jmespathは便利だけど(私は)直感的に書けない
アットホームな職場のアドベントカレンダー2日目です。
私の誕生日である12/02に投稿する予定だったのに、いざ書き始めると難しくて日をまたいでしまいました。
さて、今日のお題はjmespathです。
かれこれ3年くらい使っているのに、ちょっと凝ったことをやろうと思うといつも手こずります。
そんなわけで、備忘録。
対象のデータはjuniperのshow command
私は主にNW機器の設定値をansible経由でjsonで取得して、そこから扱いやすいように整形する用途でcommunity.general.json_query filter(中身はjmespath)を使用しています。
今回もjuniperのvlabsの機器でshow commandを実行した結果を使用します。
余談ですが、juniperのvlabsは無料で使えて、予めtopologyもたくさん用意してくれている素晴らしいサービスです。
juniper vlabs
そして、juniperとかaristaの機器は、json出力する機能が備わっているため、パースする必要がないところが最高です。
jmespathの公式サイトでテスト
jmespathの公式はjson dataとqueryからresultを出力してくれるので、機密情報を含まないデータをさくっと確認したいときにはとても便利です。
また、リファレンスも充実してて、整形方法が分からないときはいつもここで調べています。
注意点として、queryが間違っているときにはresultが更新されないので、そこは意識してください。
どういうことかというと、もともとこういうqueryを入れていたとして、
WAをNYに変えようかなとbackspaceで消してみても、「そのqueryは間違っている」というようなメッセージは出ないです。
なので、誤ったqueryでresultが出せていると誤認する可能性があるので気を付けてね!ということでした。
今回もここを使ってテストしています。
まずはjson dataを取得してみます
これは本題ではないのですが、イメージしやすいようにvlabsの検証環境の構成図を載せておきます。
この環境の中の左上のrouterで show route
を実行すると、こんな感じでrouting tableが得られます。
jcladmin@vMX1> show route
inet.0: 17 destinations, 17 routes (17 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
0.0.0.0/0 *[Static/5] 00:15:44
> to 100.123.0.1 via fxp0.0
10.100.12.0/24 *[Direct/0] 00:12:33
> via ge-0/0/0.0
10.100.12.1/32 *[Local/0] 00:12:33
Local via ge-0/0/0.0
10.100.13.0/24 *[Direct/0] 00:12:33
> via ge-0/0/2.0
10.100.13.1/32 *[Local/0] 00:12:33
Local via ge-0/0/2.0
10.100.14.0/24 *[OSPF/10] 00:00:10, metric 3
> to 10.100.12.2 via ge-0/0/0.0
to 10.100.13.2 via ge-0/0/2.0
10.100.14.1/32 *[Local/0] 00:00:11
Reject
10.100.23.0/24 *[OSPF/10] 00:11:22, metric 2
to 10.100.12.2 via ge-0/0/0.0
> to 10.100.13.2 via ge-0/0/2.0
10.100.24.0/24 *[OSPF/10] 00:00:10, metric 2
> to 10.100.12.2 via ge-0/0/0.0
10.100.34.0/24 *[OSPF/10] 00:00:10, metric 2
> to 10.100.13.2 via ge-0/0/2.0
10.100.100.1/32 *[Direct/0] 00:12:33
> via lo0.0
10.100.100.2/32 *[OSPF/10] 00:11:28, metric 1
> to 10.100.12.2 via ge-0/0/0.0
10.100.100.3/32 *[OSPF/10] 00:11:22, metric 1
> to 10.100.13.2 via ge-0/0/2.0
10.100.100.4/32 *[OSPF/10] 00:00:10, metric 2
to 10.100.12.2 via ge-0/0/0.0
> to 10.100.13.2 via ge-0/0/2.0
100.123.0.0/16 *[Direct/0] 00:15:44
> via fxp0.0
100.123.1.0/32 *[Local/0] 00:15:44
Local via fxp0.0
224.0.0.5/32 *[OSPF/10] 00:12:33, metric 1
MultiRecv
inet6.0: 1 destinations, 1 routes (1 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
ff02::2/128 *[INET6/0] 00:15:44
MultiRecv
今回は10.100.100.4/32宛のルートを対象にアレコレやっていきます。
構成図でいう右下のrouterのloopbackです。
左上から右下のrouterへの経路は、ge-0/0/0とge-0/0/2経由の2つがあります。
10.100.100.4/32 *[OSPF/10] 00:00:10, metric 2
to 10.100.12.2 via ge-0/0/0.0
> to 10.100.13.2 via ge-0/0/2.0
では、show routeコマンドをjsonで出力してみます。
juniper機器では command | display json
とすればjson形式の出力を得られます。
長いので折りたたみます
{
"route-information" : [
{
"attributes" : {"xmlns" : "http://xml.juniper.net/junos/21.1R0/junos-routing"},
"route-table" : [
{
"comment" : "keepalive",
"table-name" : [
{
"data" : "inet.0"
}
],
"destination-count" : [
{
"data" : "17"
}
],
"total-route-count" : [
{
"data" : "17"
}
],
"active-route-count" : [
{
"data" : "17"
}
],
"holddown-route-count" : [
{
"data" : "0"
}
],
"hidden-route-count" : [
{
"data" : "0"
}
],
"rt" : [
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "0.0.0.0/0"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "Static"
}
],
"preference" : [
{
"data" : "5"
}
],
"age" : [
{
"data" : "00:17:20",
"attributes" : {"junos:seconds" : "1040"}
}
],
"nh" : [
{
"selected-next-hop" : [
{
"data" : [null]
}
],
"to" : [
{
"data" : "100.123.0.1"
}
],
"via" : [
{
"data" : "fxp0.0"
}
]
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "10.100.12.0/24"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "Direct"
}
],
"preference" : [
{
"data" : "0"
}
],
"age" : [
{
"data" : "00:14:09",
"attributes" : {"junos:seconds" : "849"}
}
],
"nh" : [
{
"selected-next-hop" : [
{
"data" : [null]
}
],
"via" : [
{
"data" : "ge-0/0/0.0"
}
]
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "10.100.12.1/32"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "Local"
}
],
"preference" : [
{
"data" : "0"
}
],
"age" : [
{
"data" : "00:14:09",
"attributes" : {"junos:seconds" : "849"}
}
],
"nh-type" : [
{
"data" : "Local"
}
],
"nh" : [
{
"nh-local-interface" : [
{
"data" : "ge-0/0/0.0"
}
]
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "10.100.13.0/24"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "Direct"
}
],
"preference" : [
{
"data" : "0"
}
],
"age" : [
{
"data" : "00:14:09",
"attributes" : {"junos:seconds" : "849"}
}
],
"nh" : [
{
"selected-next-hop" : [
{
"data" : [null]
}
],
"via" : [
{
"data" : "ge-0/0/2.0"
}
]
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "10.100.13.1/32"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "Local"
}
],
"preference" : [
{
"data" : "0"
}
],
"age" : [
{
"data" : "00:14:09",
"attributes" : {"junos:seconds" : "849"}
}
],
"nh-type" : [
{
"data" : "Local"
}
],
"nh" : [
{
"nh-local-interface" : [
{
"data" : "ge-0/0/2.0"
}
]
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "10.100.14.0/24"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "OSPF"
}
],
"preference" : [
{
"data" : "10"
}
],
"age" : [
{
"data" : "00:01:46",
"attributes" : {"junos:seconds" : "106"}
}
],
"metric" : [
{
"data" : "3"
}
],
"nh" : [
{
"selected-next-hop" : [
{
"data" : [null]
}
],
"to" : [
{
"data" : "10.100.12.2"
}
],
"via" : [
{
"data" : "ge-0/0/0.0"
}
]
},
{
"to" : [
{
"data" : "10.100.13.2"
}
],
"via" : [
{
"data" : "ge-0/0/2.0"
}
]
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "10.100.14.1/32"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "Local"
}
],
"preference" : [
{
"data" : "0"
}
],
"age" : [
{
"data" : "00:01:47",
"attributes" : {"junos:seconds" : "107"}
}
],
"nh-type" : [
{
"data" : "Reject"
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "10.100.23.0/24"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "OSPF"
}
],
"preference" : [
{
"data" : "10"
}
],
"age" : [
{
"data" : "00:12:58",
"attributes" : {"junos:seconds" : "778"}
}
],
"metric" : [
{
"data" : "2"
}
],
"nh" : [
{
"to" : [
{
"data" : "10.100.12.2"
}
],
"via" : [
{
"data" : "ge-0/0/0.0"
}
]
},
{
"selected-next-hop" : [
{
"data" : [null]
}
],
"to" : [
{
"data" : "10.100.13.2"
}
],
"via" : [
{
"data" : "ge-0/0/2.0"
}
]
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "10.100.24.0/24"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "OSPF"
}
],
"preference" : [
{
"data" : "10"
}
],
"age" : [
{
"data" : "00:01:46",
"attributes" : {"junos:seconds" : "106"}
}
],
"metric" : [
{
"data" : "2"
}
],
"nh" : [
{
"selected-next-hop" : [
{
"data" : [null]
}
],
"to" : [
{
"data" : "10.100.12.2"
}
],
"via" : [
{
"data" : "ge-0/0/0.0"
}
]
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "10.100.34.0/24"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "OSPF"
}
],
"preference" : [
{
"data" : "10"
}
],
"age" : [
{
"data" : "00:01:46",
"attributes" : {"junos:seconds" : "106"}
}
],
"metric" : [
{
"data" : "2"
}
],
"nh" : [
{
"selected-next-hop" : [
{
"data" : [null]
}
],
"to" : [
{
"data" : "10.100.13.2"
}
],
"via" : [
{
"data" : "ge-0/0/2.0"
}
]
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "10.100.100.1/32"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "Direct"
}
],
"preference" : [
{
"data" : "0"
}
],
"age" : [
{
"data" : "00:14:09",
"attributes" : {"junos:seconds" : "849"}
}
],
"nh" : [
{
"selected-next-hop" : [
{
"data" : [null]
}
],
"via" : [
{
"data" : "lo0.0"
}
]
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "10.100.100.2/32"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "OSPF"
}
],
"preference" : [
{
"data" : "10"
}
],
"age" : [
{
"data" : "00:13:04",
"attributes" : {"junos:seconds" : "784"}
}
],
"metric" : [
{
"data" : "1"
}
],
"nh" : [
{
"selected-next-hop" : [
{
"data" : [null]
}
],
"to" : [
{
"data" : "10.100.12.2"
}
],
"via" : [
{
"data" : "ge-0/0/0.0"
}
]
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "10.100.100.3/32"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "OSPF"
}
],
"preference" : [
{
"data" : "10"
}
],
"age" : [
{
"data" : "00:12:58",
"attributes" : {"junos:seconds" : "778"}
}
],
"metric" : [
{
"data" : "1"
}
],
"nh" : [
{
"selected-next-hop" : [
{
"data" : [null]
}
],
"to" : [
{
"data" : "10.100.13.2"
}
],
"via" : [
{
"data" : "ge-0/0/2.0"
}
]
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "10.100.100.4/32"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "OSPF"
}
],
"preference" : [
{
"data" : "10"
}
],
"age" : [
{
"data" : "00:01:46",
"attributes" : {"junos:seconds" : "106"}
}
],
"metric" : [
{
"data" : "2"
}
],
"nh" : [
{
"to" : [
{
"data" : "10.100.12.2"
}
],
"via" : [
{
"data" : "ge-0/0/0.0"
}
]
},
{
"selected-next-hop" : [
{
"data" : [null]
}
],
"to" : [
{
"data" : "10.100.13.2"
}
],
"via" : [
{
"data" : "ge-0/0/2.0"
}
]
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "100.123.0.0/16"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "Direct"
}
],
"preference" : [
{
"data" : "0"
}
],
"age" : [
{
"data" : "00:17:20",
"attributes" : {"junos:seconds" : "1040"}
}
],
"nh" : [
{
"selected-next-hop" : [
{
"data" : [null]
}
],
"via" : [
{
"data" : "fxp0.0"
}
]
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "100.123.1.0/32"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "Local"
}
],
"preference" : [
{
"data" : "0"
}
],
"age" : [
{
"data" : "00:17:20",
"attributes" : {"junos:seconds" : "1040"}
}
],
"nh-type" : [
{
"data" : "Local"
}
],
"nh" : [
{
"nh-local-interface" : [
{
"data" : "fxp0.0"
}
]
}
]
}
]
},
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "224.0.0.5/32"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "OSPF"
}
],
"preference" : [
{
"data" : "10"
}
],
"age" : [
{
"data" : "00:14:09",
"attributes" : {"junos:seconds" : "849"}
}
],
"metric" : [
{
"data" : "1"
}
],
"nh-type" : [
{
"data" : "MultiRecv"
}
]
}
]
}
]
},
{
"table-name" : [
{
"data" : "inet6.0"
}
],
"destination-count" : [
{
"data" : "1"
}
],
"total-route-count" : [
{
"data" : "1"
}
],
"active-route-count" : [
{
"data" : "1"
}
],
"holddown-route-count" : [
{
"data" : "0"
}
],
"hidden-route-count" : [
{
"data" : "0"
}
],
"rt" : [
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "ff02::2/128"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "INET6"
}
],
"preference" : [
{
"data" : "0"
}
],
"age" : [
{
"data" : "00:17:20",
"attributes" : {"junos:seconds" : "1040"}
}
],
"nh-type" : [
{
"data" : "MultiRecv"
}
]
}
]
}
]
}
]
}
]
}
json query 基本形
さて、ここから 10.100.100.4/32宛のnexthopを取り出してみます。
ただし、ここではまだrt[13]
のように、rt
のlistの中でも"13番目の要素"という指定の仕方をします。
queryと結果はこうです。
"route-information"[0]."route-table"[0].rt[13]."rt-entry"[0].nh
[
{
"to": [
{
"data": "10.100.12.2"
}
],
"via": [
{
"data": "ge-0/0/0.0"
}
]
},
{
"selected-next-hop": [
{
"data": [
null
]
}
],
"to": [
{
"data": "10.100.13.2"
}
],
"via": [
{
"data": "ge-0/0/2.0"
}
]
}
]
このqueryだけでも頭が痛くなりそうですが、よく見るとただtreeを辿っているだけなんです。
keyの部分にダブルクオーテーションがあったりなかったりするのは、-
(ハイフン)を含むかどうかで変わります。
jsonでは-
が演算子なので、ダブルクオーテーションで囲ってやる必要があります。
もちろん、-
が含まれていないデータをダブルクオーテーションで囲っても問題ないので、それで統一する方が分かりやすいかもしれないですね。
ちょっとだけ応用編
では、"13番目の要素" ではなく、"10.100.100.4/32 宛のルート" というように、扱うデータのリストの順番が分かってなくても取得できるようにqueryを変更してみます。
"route-information"[0]."route-table"[0].rt[?"rt-destination"[0].data == '10.100.100.4/32']."rt-entry"[0].nh[]
[
{
"to": [
{
"data": "10.100.12.2"
}
],
"via": [
{
"data": "ge-0/0/0.0"
}
]
},
{
"selected-next-hop": [
{
"data": [
null
]
}
],
"to": [
{
"data": "10.100.13.2"
}
],
"via": [
{
"data": "ge-0/0/2.0"
}
]
}
]
肝はrt[?"rt-destination"[0].data == '10.100.100.4/32']
ですね。
無事取得できましたが、もっと頭が痛くなってきました。
ご安心ください、機器側で宛先を絞れます
実はshow route コマンドはdestinationを指定することもできます。
jcladmin@vMX1> show route 10.100.100.4/32
inet.0: 17 destinations, 17 routes (17 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
10.100.100.4/32 *[OSPF/10] 01:00:59, metric 2
to 10.100.12.2 via ge-0/0/0.0
> to 10.100.13.2 via ge-0/0/2.0
jsonでは
jcladmin@vMX1> show route 10.100.100.4/32 | display json
{
"route-information" : [
{
"attributes" : {"xmlns" : "http://xml.juniper.net/junos/21.1R0/junos-routing"},
"route-table" : [
{
"comment" : "keepalive",
"table-name" : [
{
"data" : "inet.0"
}
],
"destination-count" : [
{
"data" : "17"
}
],
"total-route-count" : [
{
"data" : "17"
}
],
"active-route-count" : [
{
"data" : "17"
}
],
"holddown-route-count" : [
{
"data" : "0"
}
],
"hidden-route-count" : [
{
"data" : "0"
}
],
"rt" : [
{
"attributes" : {"junos:style" : "brief"},
"rt-destination" : [
{
"data" : "10.100.100.4/32"
}
],
"rt-entry" : [
{
"active-tag" : [
{
"data" : "*"
}
],
"current-active" : [
{
"data" : [null]
}
],
"last-active" : [
{
"data" : [null]
}
],
"protocol-name" : [
{
"data" : "OSPF"
}
],
"preference" : [
{
"data" : "10"
}
],
"age" : [
{
"data" : "01:01:26",
"attributes" : {"junos:seconds" : "3686"}
}
],
"metric" : [
{
"data" : "2"
}
],
"nh" : [
{
"to" : [
{
"data" : "10.100.12.2"
}
],
"via" : [
{
"data" : "ge-0/0/0.0"
}
]
},
{
"selected-next-hop" : [
{
"data" : [null]
}
],
"to" : [
{
"data" : "10.100.13.2"
}
],
"via" : [
{
"data" : "ge-0/0/2.0"
}
]
}
]
}
]
}
]
}
]
}
]
}
ここからはこちらのデータを使っていきます。
応用編 中くらい
では、この中からselected pathの方を抽出してみましょう。
まずはnexthopまで辿ってみます。
"route-information"[0]."route-table"[0].rt[0]."rt-entry"[0].nh
[
{
"to": [
{
"data": "10.100.12.2"
}
],
"via": [
{
"data": "ge-0/0/0.0"
}
]
},
{
"selected-next-hop": [
{
"data": [
null
]
}
],
"to": [
{
"data": "10.100.13.2"
}
],
"via": [
{
"data": "ge-0/0/2.0"
}
]
}
]
さて、先程の例では rt[?"rt-destination"[0].data == '10.100.100.4/32']
のように、とあるkeyに対するvalueがこうだったらという方法で特定しましたが、今回はselected-next-hop
のkeyを含むだけでOKです。
これは意外と簡単で、
"route-information"[0]."route-table"[0].rt[0]."rt-entry"[0].nh[?"selected-next-hop"]
[
{
"selected-next-hop": [
{
"data": [
null
]
}
],
"to": [
{
"data": "10.100.13.2"
}
],
"via": [
{
"data": "ge-0/0/2.0"
}
]
}
]
いい感じに絞れていますね。
応用編 好みの形にしてしまおう
さて、これをもっとこの後の作業、例えば想定値と実際の比較を行うにあたって使いやすい形に整形してみましょう。
こんな形を目指します。
{
"destination": "10.100.100.4/32",
"paths": [
{
"nexthop": "10.100.12.2",
"interface": "ge-0/0/0.0",
},
{
"nexthop": "10.100.13.2",
"interface": "ge-0/0/2.0",
}
]
}
dictにするには素直に{}で囲ってそれっぽく指定すればできます。
"route-information"[0]."route-table"[0].rt[0].{destination:"rt-destination"[0], paths:"rt-entry"[0].nh[].{nexthop:to[0].data, interface:via[0].data}}
{
"destination": {
"data": "10.100.100.4/32"
},
"paths": [
{
"nexthop": "10.100.12.2",
"interface": "ge-0/0/0.0"
},
{
"nexthop": "10.100.13.2",
"interface": "ge-0/0/2.0"
}
]
}
一旦目標の形にはなりました。
けど、どちらがselected pathなのかも盛り込みたいですよね。
応用編 頭痛Max
目指したい形は以下です。
{
"destination": {
"data": "10.100.100.4/32"
},
"paths": [
{
"nexthop": "10.100.12.2",
"interface": "ge-0/0/0.0",
"selected": false
},
{
"nexthop": "10.100.13.2",
"interface": "ge-0/0/2.0",
"selected": true
}
]
}
少しずつ紐解きましょう。
まず、selected pathには"selected-next-hop"というkeyが入ります。
なので、このkeyを含むか否かを判定すれば良さそう。
では、keyをどうやって引っ張るかというと、ちゃんと公式に書いてあります。
@
でそれまでqueryした内容を引数にできるんですね。
"route-information"[0]."route-table"[0].rt[0]."rt-entry"[0].nh[].keys(@)
[
[
"to",
"via"
],
[
"selected-next-hop",
"to",
"via"
]
]
ちゃんと引っ張れてます。よしよし。
では、keyがlistに含まれればtrueとするにはどうするかというと、これも公式に書いてあります。
contains
"route-information"[0]."route-table"[0].rt[0]."rt-entry"[0].nh[].keys(@).contains(@,'selected-next-hop')
[
false,
true
]
あとは先程作ったqueryと組み合わせれば、完成!
"route-information"[0]."route-table"[0].rt[0].{destination:"rt-destination"[0], paths:"rt-entry"[0].nh[].{nexthop:to[0].data, interface:via[0].data, selected:keys(@).contains(@,'selected-next-hop')}}
{
"destination": {
"data": "10.100.100.4/32"
},
"paths": [
{
"nexthop": "10.100.12.2",
"interface": "ge-0/0/0.0",
"selected": false
},
{
"nexthop": "10.100.13.2",
"interface": "ge-0/0/2.0",
"selected": true
}
]
}
いやー難しかった。
けど、困ったときはこれを見返せば大抵のことは大丈夫そう。