質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
Ansible

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

Q&A

1回答

2982閲覧

多階層リスト・辞書に対する任意文字列有無の確認

退会済みユーザー

退会済みユーザー

総合スコア0

Ansible

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

0グッド

0クリップ

投稿2020/06/05 06:36

編集2020/06/07 08:40

前提・実現したいこと

Ansibleで多階層になっているリスト・辞書をあつかっています。
後述の"list1"から、"Key2"内"KeyB"の値に文字列abcが入っていない場合
(あるいは"Key2"の値が[]で空のとき)、
その要素の"Key1"の値を抜き出して、別のリスト(list2)に追加したいです。

"list1"の内容は後述しますが、この場合でしたらlist2に"Value1-2"だけ入ってきてほしいです。

発生している問題・エラーメッセージ

このような場合に、"Key2"の値に文字列abcが入っていないかどうか
どのように確認すればよいかが分からず困っております。

"Key2"の値がリストでなく単一の値であれば、後述のように
"if 'abc' not in list1[i].Key2"
で調べられるとは思うのですが…。

このまま実行すると以下のようにlist2に"Value1-1","Value1-2"どちらも入ってきてしまいます。

TASK [debug] ******************************************************************* ok: [127.0.0.1] => { "msg": [ "Value1-1", "Value1-2" ] }

該当のソースコード

yml

1# test 2--- 3- name: list test 4 hosts: localhost 5 gather_facts: no 6 vars: 7 list1: [ 8 { 9 "Key1": "Value1-1", 10 "Key2": [ 11 { 12 "KeyA": "ValueA-1", 13 "KeyB": "abc" 14 }, 15 { 16 "KeyA": "ValueA-2", 17 "KeyB": "defg" 18 } 19 ], 20 "Key3": "Value3-1", 21 }, 22 { 23 "Key1": "Value1-2", 24 "Key2": [], 25 "Key3": "Value3-2", 26 } 27 ] 28 tasks: 29 - name: create list2 30 set_fact: 31 list2: >- 32 {%- set tmplist = [] -%} 33 {%- for i in range(list1|length) -%} 34 {%- if 'abc' not in list1[i].Key2 -%} 35 {%- set _ = tmplist.append(list1[i].Key1) -%} 36 {%- endif -%} 37 {%- endfor -%} 38 {{ tmplist }} 39 - name: 'debug' 40 debug: 41 msg: '{{ list2 }}'

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

$ ansible --version ansible 2.9.7 config file = /etc/ansible/ansible.cfg configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python2.7/site-packages/ansible executable location = /usr/bin/ansible python version = 2.7.5 (default, Apr 2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] $ cat /etc/system-release CentOS Linux release 7.8.2003 (Core)

2020/06/07 追記

ご回答頂いた内容より試してみたPlaybookは以下です。

yaml

1- name: Append List 2 hosts: localhost 3 connection: local 4 gather_facts: False 5 vars: 6 list1: [ 7 { 8 "Key1": "Value1-1", 9 "Key2": [ 10 { 11 "KeyA": "ValueA-1", 12 "KeyB": "abc" 13 }, 14 { 15 "KeyA": "ValueA-2", 16 "KeyB": "defg" 17 } 18 ], 19 "Key3": "Value3-1", 20 }, 21 { 22 "Key1": "Value1-2", 23 "Key2": [], 24 "Key3": "Value3-2", 25 }, 26 { 27 "Key1": "Value1-3", 28 "Key2": [ 29 { 30 "KeyA": "ValueA-2", 31 "KeyB": "defg" 32 } 33 ], 34 "Key3": "Value3-3", 35 } 36 ] 37 tasks: 38 - name: create list2 39 set_fact: 40 list2: >- 41 {%- set tmplist = [] -%} 42 {%- for item in list1 -%} 43 {#- Key2が空の場合はそのままリストに追加 -#} 44 {%- if (item.Key2 | length) <= 0 -%} 45 {%- set dummy = tmplist.append(item.Key1) -%} 46 {%- elif (item.Key2 | json_query('[?KeyB==`abc`]') | length > 0) == False -%} 47 {#- Key2が空ではない場合はabcの文字列がなければリストに追加する -#} 48 {%- set dummy = tmplist.append(item.Key1) -%} 49 {%- endif -%} 50 {%- endfor -%} 51 {{ tmplist }} 52 53 - name: 'debug' 54 debug: 55 msg: '{{ list2 }}'

yaml

1# 切り分けのためifの分岐を減らす 2- name: Append List 3 hosts: localhost 4 connection: local 5 gather_facts: False 6 vars: 7 list1: [ 8 { 9 "Key1": "Value1-1", 10 "Key2": [ 11 { 12 "KeyA": "ValueA-1", 13 "KeyB": "abc" 14 }, 15 { 16 "KeyA": "ValueA-2", 17 "KeyB": "defg" 18 } 19 ], 20 "Key3": "Value3-1", 21 }, 22 { 23 "Key1": "Value1-2", 24 "Key2": [], 25 "Key3": "Value3-2", 26 }, 27 { 28 "Key1": "Value1-3", 29 "Key2": [ 30 { 31 "KeyA": "ValueA-2", 32 "KeyB": "defg" 33 } 34 ], 35 "Key3": "Value3-3", 36 } 37 ] 38 tasks: 39 - name: create list2 40 set_fact: 41 list2: >- 42 {%- set tmplist = [] -%} 43 {%- for item in list1 -%} 44 {%- if (item.Key2 | json_query('[?KeyB==`abc`]') | length > 0) == False -%} 45 {#- Key2が空ではない場合はabcの文字列がなければリストに追加する -#} 46 {%- set dummy = tmplist.append(item.Key1) -%} 47 {%- endif -%} 48 {%- endfor -%} 49 {{ tmplist }} 50 51 - name: 'debug' 52 debug: 53 msg: '{{ list2 }}'
TASK [debug] ******************************************************************************************** ok: [localhost] => { "msg": [ "Value1-1" ] }

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

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

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

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

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

guest

回答1

0

こんな感じでどうでしょう。
テスト用に変数を追加しました。

ポイント

  • forでrangeを使わずにそのまま要素を取得する(コード量が減る)
  • json_queryフィルタを使うことで特定の用語が含まれているのか?を検出することができる

 今回はjson_queryでabcが含まれている要素を取得できなければ、list2へ追加するようにしました
https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html

yaml

1 2- name: Append List 3 hosts: localhost 4 connection: local 5 gather_facts: False 6 vars: 7 list1: [ 8 { 9 "Key1": "Value1-1", 10 "Key2": [ 11 { 12 "KeyA": "ValueA-1", 13 "KeyB": "abc" 14 }, 15 { 16 "KeyA": "ValueA-2", 17 "KeyB": "defg" 18 } 19 ], 20 "Key3": "Value3-1", 21 }, 22 { 23 "Key1": "Value1-1", 24 "Key2": [ 25 { 26 "KeyA": "ValueA-1", 27 "KeyB": "adc" 28 }, 29 { 30 "KeyA": "ValueA-2", 31 "KeyB": "defg" 32 } 33 ], 34 "Key3": "Value3-1", 35 }, 36 { 37 "Key1": "Value1-2", 38 "Key2": [], 39 "Key3": "Value3-2", 40 } 41 ] 42 tasks: 43 - name: create list2 44 set_fact: 45 list2: >- 46 {%- set tmplist = [] -%} 47 {%- for item in list1 -%} 48 {#- key2が空の場合はそのままリストに追加 -#} 49 {%- if (item.Key2 | length) <= 0 -%} 50 {%- set dummy = tmplist.append(item) -%} 51 {%- elif (item.Key2 | json_query('[?KeyB==`abc`]') | length > 0) == False -%} 52 {#- key2が空ではない場合はabcの文字列がなければリストに追加する -#} 53 {%- set dummy = tmplist.append(item) -%} 54 {%- endif -%} 55 {%- endfor -%} 56 {{ tmplist }} 57 58 - name: 'debug' 59 debug: 60 msg: '{{ list2 }}'

投稿2020/06/05 08:39

編集2020/06/05 08:42
comefigo

総合スコア1045

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

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

退会済みユーザー

退会済みユーザー

2020/06/07 08:39 編集

ご回答ありがとうございます。 テスト用にlist1を少し変更し、tmplist.append(item.Key1)に変更しました。 # コメントではMarkdown利用不可のようですので、Playbookの中身を質問内容に追記いたしました。 これでlist2が[ "Value1-2", "Value1-3"]になってくれれば成功なのですが、なぜか[ "Value1-1", "Value1-3"]になってしまいます…。 切り分けのためifの分岐を減らしてみたところ、"Value1-1"のみlist2に入ってきました。 さらに"if (item.Key2 | json_query('[?KeyB!=`abc`]') | length > 0) == True"にしてみると、list2は空になりました。 結果からlist2[2]以降に対してifの条件式で判定されていない?ような気がするのですが ” for item in list1”でループさせていますので、何を直せばよいか分からず…。 すみませんが改めてご確認いただけると幸いです。
comefigo

2020/06/07 12:18

> これでlist2が[ "Value1-2", "Value1-3"]になってくれれば成功なのですが、なぜか[ "Value1-1", "Value1-3"]になってしまいます… 私のコードをベースに検証したのであれば、"Value1-1", "Value1-3"で問題ないです。 紛らわしいですが、テストデータがそうなっています。 > さらに"if (item.Key2 | json_query('[?KeyB!=`abc`]') | length > 0) == True"にしてみると、list2は空になりました。 それはおかしいですね。。。 このif条件と同じように私の手元のコードで検証したところ、list2は空になりませんでした。 > 結果からlist2[2]以降に対してifの条件式で判定されていない?ような気がするのですが > ” for item in list1”でループさせていますので、何を直せばよいか分からず…。 「結果から」とは上記のlist2が空のことを指しているのでしょうか?
退会済みユーザー

退会済みユーザー

2020/06/08 04:28

ご確認ありがとうございます。 > 私のコードをベースに検証したのであれば、"Value1-1", "Value1-3"で問題ないです。 説明が不足しておりすみません。 "Value1-1"が2つ存在していたため、「2020/06/07 追記」に記載した ひとつめのコードの通り片方を"Value1-2"に変更しております。 また、json_queryが上手く動いていない可能性を考えて jmespathを最新(0.10.0)にしてみましたが結果は変わりませんでした。 >> 結果からlist2[2]以降に対してifの条件式で判定されていない?ような気がするのですが > 「結果から」とは上記のlist2が空のことを指しているのでしょうか? すみません、こちらは私の勘違いでした…
comefigo

2020/06/08 05:46

「2020/06/07 追記」のコードを実行してみましたが、記載されている結果("Value1-1")とは異なるようですね。 私の手元ですと「 "Value1-2", "Value1-3"」と正しい結果が出ています。
comefigo

2020/06/08 05:51 編集

ansibleのバージョンは私の手元と同じのようなので、基本的に同じ結果になると思いますが、念のためansible.cfgの中身を出力して頂けませんか? 「ansible-config view」で出力されます。(重要な情報はマスキングして頂いてOKです)
退会済みユーザー

退会済みユーザー

2020/06/08 09:09

ご確認ありがとうございます。 環境によって結果が違うのですね… 私の環境では以下の設定がされており、その他は全てコメントアウトされています。 -------------------------------------------------- [defaults] inventory = /etc/ansible/hosts sudo_user = root [ssh_connection] ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no --------------------------------------------------
comefigo

2020/06/08 12:47

ありがとうございます。 ansible configの設定値を確認したところ結果に影響を及ぼすようなパラメータは設定されていないようですね。。。
退会済みユーザー

退会済みユーザー

2020/06/10 07:44

ご確認ありがとうございます。 新しくvenvを作成してそちらでもう一度試してみたいと思います。 大変お手数なのですが、参考までにご利用のansibleやjmespathのバージョンを教えて頂くことは可能でしょうか?
comefigo

2020/06/10 08:16

[Ansibleのバージョン] ansible 2.9.6 config file = /root/.ansible.cfg configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python2.7/site-packages/ansible executable location = /usr/bin/ansible python version = 2.7.16 (default, Dec 12 2019, 23:58:22) [GCC 7.3.1 20180712 (Red Hat 7.3.1-6)] -------------------------- [jmespath] jmespath==0.10.0 ですね。
退会済みユーザー

退会済みユーザー

2020/06/10 08:41

ありがとうございます! 試してみます
comefigo

2020/06/10 09:10

基本的に同じなので、結果はぶれない気がします・・・
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問