文字列として保持しているYAMLやJSON形式のデータを構造化データとして扱うにはフィルタで変換するのが簡単です。
PowerShellのConvertFrom-Json
とかと同じやつです。
YAML形式の文字列をオブジェクトに変換
apiVersion: apps/v1 kind: Deployment metadata: labels: app: sample-http name: sample-http spec: replicas: 2 selector: matchLabels: app: sample-http template: metadata: labels: app: sample-http spec: containers: - image: httpd name: httpd
こんな感じのよく見かけるYAML形式のデータがありこれをstring型(plain/text)で変数に持っている場合に、構造化データとして処理するにはfrom_yaml
フィルタを使うと簡単に処理できます。
以下はcat
で読み込んで__result
にセットしたYAML形式の文字列データをfrom_yaml
フィルタでdata
変数にセット、あとは普通にdata
変数を構造化データとして扱って辞書型やリスト参照しています。
- hosts: localhost gather_facts: no tasks: - name: get yaml file command: cat yamlfile.yml register: __result - name: get yaml value from text vars: data: "{{ __result.stdout | from_yaml }}" debug: msg: '{{ data.spec.template.spec.containers[0].image }}'
このPlaybookでansible-playbook
を実行すると以下の通り。
TASK [get yaml value from text] *********************************************** ok: [localhost] => msg: httpd
JSON形式の文字列をオブジェクトに変換
JSON形式の場合も同様にfrom_json
を使えば同じように処理できます。
{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": { "labels": { "app": "sample-http" }, "name": "sample-http", "namespace": "default" }, "spec": { "replicas": 2, "selector": { "matchLabels": { "app": "sample-http" } }, "template": { "metadata": { "labels": { "app": "sample-http" } }, "spec": { "containers": [ { "image": "httpd", "name": "httpd" } ] } } } }
- name: get json file #command: curl https://ifconfig.io/all.json command: cat jsonfile.json register: __result - name: get json value from text vars: data: "{{ __result.stdout | from_json }}" debug: msg: "{{ data.spec.template.spec.containers[0].image }}"
この内容のPlaybookを実行すると以下の通り。
TASK [get json value from text] *********************************************** ok: [localhost] => msg: httpd
フィルターの結果の辞書やリストから直接値を取り出す
{{ result | from_json['spec'] }}
とかは出来ないので、指定要素を取り出すフィルタが無いか探したけど処理が単純すぎるのか逆に見当たらず。。
結局カッコ使ってこんな感じに。。うまいやり方は他にあるのかな。。
debug: msg: "{{ (__result.stdout | from_json).spec.template.spec.containers[0].image }}"
追記: attr()
使えないかと思ったけどダメみたい。現状カッコしかないかなー
フィルタで辞書の値を取り出すためにattr()が使えないかと試してみたけど動作せず。。検索するとattr()で指定できるのはattributeであって辞書のキーとは別物らしい(多分)
— z a k i (@zaki_hmkc) 2021年1月7日
Jinja2 attr() filter not working in ansible · Issue #24065 · ansible/ansiblehttps://t.co/aolTfjbxv7
まとめ
cat
で読み込んだりしただけだと、結果のJSONやYAML形式のデータは、書式はYAMLですが単なる複数行文字列データなので__result.stdout.data.spec ...
のように構造化データとして処理は出来ません。
from_yaml
フィルタなどを使うことで構造化データになるので、特定要素へのアクセスが簡単に処理できるようになります。
また、構造化データであればjson_query()
のようなフィルタを使った処理も可能になります。
確認した環境は以下の通り。
$ ansible --version ansible 2.10.3 config file = /home/zaki/src/ansible-sample/yaml-pickup/ansible.cfg configured module search path = ['/home/zaki/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /home/zaki/src/esxi-ansible/venv/2.10/lib64/python3.6/site-packages/ansible executable location = /home/zaki/src/esxi-ansible/venv/2.10/bin/ansible python version = 3.6.8 (default, Nov 16 2020, 16:55:22) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]