はじめに
Ansible では、結果が JSON になるタスクを実行すると、(少なくとも表示上は)エスケープされた JSON が返ってくることがあります。
この場合、構造化データのように見えて文字列なので、ディクショナリ(構造化データ)として正しく扱えません。
from_json
フィルターをかけると、うまくいきます。
この記事では簡単なサンプルをもとに説明します。
■ エスケープされた JSON とは?
以下は、nclu
モジュールを利用して、Cumulus Linux に対して、show bgp summary json
コマンドを実行した結果を、debug
モジュールで表示した結果です。
msg
内に \
によるエスケープが入っています。JSON のように見えてただの文字列です。
TASK [debug show bgp summary] *************************************************************************
ok: [leaf01] => {
"msg": {
"changed": false,
"failed": false,
"msg": "{\n \"ipv4 unicast\": {\n \"as\": 65011, \n \"bestPath\": {\n \"multiPathRelax\": \"true\"\n }, \n \"dynamicPeers\": 0, \n \"peerCount\": 2, \n \"peerGroupCount\": 1, \n \"peerGroupMemory\": 64, \n \"peerMemory\": 42352,
...(略)...
}
}
このままでは、result.msg['ipv4 unicast']
のように、内部のキーを指定しても、'dict object' has no attribute 'ipv4 unicast'
のような、キーの参照エラーになってしまいます。
ちょっとハマりやすいのは、上記例でいうと result.msg
を参照したときは、以下のように、いかにも正しい JSON っぽく表示される点です。
TASK [debug show bgp summary] *************************************************************************
ok: [leaf01] => {
"msg": {
"ipv4 unicast": {
"as": 65011,
"bestPath": {
"multiPathRelax": "true"
},
"dynamicPeers": 0,
"peerCount": 2,
...(略)...
どう見てもディクショナリとして扱えそうですが、{{ result.msg | type_debug }}
の結果は AnsibleUnsafeText
です。どうして・・。
from_json
フィルターでディクショナリに変換
正しくディクショナリとして扱うために、from_json
フィルターをかけます。
"{{ result_bgp_summary_raw | from_json }}"
こでれで、JSON、ディクショナリになります。
TASK [debug show bgp summary] *************************************************************************
ok: [leaf01] => {
"msg": {
"ipv4 unicast": {
"as": 65011,
"bestPath": {
"multiPathRelax": "true"
},
"dynamicPeers": 0,
"peerCount": 2,
...(略)...
"{{ result_bgp_summary_raw.msg | from_json | type_debug }}"
の結果は dict
です。
ここまでくれば、通常のディクショナリと同じく、特定のキーを参照したりするだけです。
タスク例
- name: debug show bgp summary
debug:
msg: "{{ bgp_summary['ipv4 unicast']['peerCount'] }}"
vars:
bgp_summary: "{{ result_bgp_summary_raw.msg | from_json }}"
(キーの指定を .ipv4 unicast
ではなく ['ipv4 unicast']
としているのは、今回対象のデータに、たまたまスペース入りのキー名があったためです)
実行例
TASK [debug show bgp summary] *************************************************************************
ok: [leaf01] => {
"msg": "2"
}
■ おわりに
エスケープされた JSON に、from_json
フィルターをかけて、ディクショナリにする方法をご紹介しました。
私だけかもしれませんが、Ansible で構造化データの扱いで悩むことが結構あります。
あるはずのキーが has no attribute
となってハマったときは、エスケープされてないか、type_debug
の結果はどうなるか、などを確認するのがよさそうです。