🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Ansible

Ansibleは、Python で書かれたサーバーの設定を管理するための 構成管理ツールです。

Q&A

解決済

2回答

2850閲覧

ansible の yaml で要素を読み込んだ順序で出力したい

mit0223

総合スコア3401

Ansible

Ansibleは、Python で書かれたサーバーの設定を管理するための 構成管理ツールです。

0グッド

1クリップ

投稿2021/02/11 02:20

編集2021/02/11 02:26

前提・実現したいこと

ansible の yaml で辞書の要素を読み込んだ順序で出力したい。
Order my dicts のプルリクエストをみると、ansible ではデフォルトで要素の順序を保存するように修正されているように見えるのですが、まだリリースされていないのでしょうか?

発生している問題

辞書オブジェクトの要素の順序が読み込んだ順ではなく abc 順で出力されてしまいます。
たとえば、以下の playbook では、辞書オブジェクトの要素を d, bの順序で定義しているのに b,d の順になってしまいます。 python の OrderedDict のように要素の順序を保存してほしいです。

$ ansible-playbook book.yml [WARNING]: No inventory was parsed, only implicit localhost is available [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' PLAY [localhost] ***************************************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************************************** ok: [localhost] TASK [debug] ********************************************************************************************************************************* ok: [localhost] => { "test": { "b": 3, "d": 1 } } PLAY RECAP *********************************************************************************************************************************** localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

該当のソースコード

ansible

1- hosts: localhost 2 vars: 3 test: 4 d: 1 5 b: 3 6 tasks: 7 - debug: var=test

試したこと

パース側

ファイルから読み込んで from_json などでパースしても同じでした。

lookup('file', 'test.json') | from_json
lookup('file', 'test.yml') | from_yaml

出力側

ansible.cfg に以下を追加して yaml で出力しても要素の順序は同じでした。

[defaults] stdout_callback=yaml

補足情報(FW/ツールのバージョンなど)

OS: MacOS Big Sur 11.2.1

$ ansible --version ansible 2.10.5 config file = None configured module search path = ['/Users/mitsuru/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /Users/mitsuru/.pyenv/versions/3.7.3/envs/ansible/lib/python3.7/site-packages/ansible executable location = /Users/mitsuru/.pyenv/versions/ansible/bin/ansible python version = 3.7.3 (default, Jun 7 2019, 11:23:14) [Clang 10.0.1 (clang-1001.0.46.4)]

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

自己解決

Python のコードをいろいろと調べてみましたが、結論としては読み込んだときは順序を保存しているが、出力するときにソートしてしまっているという状況でした。
debug モジュールなど task の結果を印刷するときに sort_keys=False を渡せば保存された結果が印刷されましたが、ここはハードコーディングされているので、カスタマイズはできそうにありませんでした。
具体的には、
https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/callback/default.py#L146
の _dump_results に sort_keys=False を指定すると、属性順序が保存されて出力されました。
さらに調べた結果、 to_nice_yaml フィルタは sort_keys=False を受け付けてくれることがわかり、以下の playbook で解決できました。 to_json は sort_keys=False がデフォルトでした。

playbook

yaml

1- hosts: localhost 2 vars: 3 test: 4 d: 1 5 b: 3 6 test_yaml: "{{ test | to_nice_yaml(sort_keys=False) }}" 7 test_yaml_default: "{{ test | to_nice_yaml() }}" 8 test_json: " {{ test | to_json(sort_keys=True) }}" 9 test_json_default: " {{ test | to_json() }}" 10 tasks: 11 - debug: var=test 12 - debug: var=test_yaml 13 - debug: var=test_yaml_default 14 - debug: var=test_json 15 - debug: var=test_json_default

結果:

$ ansible-playbook book.yml [WARNING]: No inventory was parsed, only implicit localhost is available [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' PLAY [localhost] ****************************************************************************************************************************************************************************************** TASK [Gathering Facts] ************************************************************************************************************************************************************************************ ok: [localhost] TASK [debug] ********************************************************************************************************************************************************************************************** ok: [localhost] => { "test": { "b": 3, "d": 1 } } TASK [debug] ********************************************************************************************************************************************************************************************** ok: [localhost] => { "test_yaml": "d: 1\nb: 3\n" } TASK [debug] ********************************************************************************************************************************************************************************************** ok: [localhost] => { "test_yaml_default": "b: 3\nd: 1\n" } TASK [debug] ********************************************************************************************************************************************************************************************** ok: [localhost] => { "test_json": " {\"b\": 3, \"d\": 1}" } TASK [debug] ********************************************************************************************************************************************************************************************** ok: [localhost] => { "test_json_default": " {\"d\": 1, \"b\": 3}" } PLAY RECAP ************************************************************************************************************************************************************************************************ localhost : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

投稿2021/02/24 10:43

編集2021/02/24 10:56
mit0223

総合スコア3401

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

結論から言うと、私にもわかりませんでした。。
他の方の回答を待ちたいところですが、Pythonわからない人なりに少しだけ調べた範囲を書きます。


■環境

yml

1$ ansible --version 2ansible 2.10.4 3 config file = None 4 configured module search path = ['/home/stopendy/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] 5 ansible python module location = /home/stopendy/venv/ansible/lib64/python3.9/site-packages/ansible 6 executable location = /home/stopendy/venv/ansible/bin/ansible 7 python version = 3.9.1 (default, Dec 8 2020, 00:00:00) [GCC 10.2.1 20201125 (Red Hat 10.2.1-9)]

■確かに動かない
頂いたサンプル以外にもいくつか試したのですが、確かに動きません。

↓test.yml

yml

1- hosts: localhost 2 vars: 3 test: 4 d: 1 5 b: 3 6 test1: 7 c: 99 8 test2: 9 a: 1 10 11 tasks: 12 - debug: var=test 13 - debug: var="test1 | combine(test2)" 14 - debug: var="test2 | combine(test1)" 15

↓出力 (ansible-playbook)

yml

1TASK [debug] ******************************************************************************** 2ok: [localhost] => { 3 "test": { 4 "b": 3, 5 "d": 1 6 } 7} 8 9TASK [debug] ******************************************************************************** 10ok: [localhost] => { 11 "test1 | combine(test2)": { 12 "a": 1, 13 "c": 99 14 } 15} 16 17TASK [debug] ******************************************************************************** 18ok: [localhost] => { 19 "test2 | combine(test1)": { 20 "a": 1, 21 "c": 99 22 } 23}

■対象のコミットは反映されているように見える
git logは見ていませんが、v2.10のブランチでキーワード検索したら、それっぽい文字列が見つかりました。

https://github.com/ansible/ansible/blob/stable-2.10/lib/ansible/parsing/yaml/objects.py#L62

また、手元のAnsibleでもその行は見つかりました。

sh

1$ egrep -i "odict|orderddict" lib/python3.9/site-packages/ansible/parsing/yaml/objects.py 2# try to always use orderddict with yaml, after py3.6 the dict type already does this 3odict = dict 4 from collections import OrderedDict as odict 5class AnsibleMapping(AnsibleBaseYAMLObject, odict):

投稿2021/02/11 03:56

stopendy0122

総合スコア170

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mit0223

2021/02/11 07:21

うーん、#58000のプルリクエストは私が期待したものとは別なのでしょうか。どういうときに ordereddict になるのでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問