web-dev-qa-db-ja.com

Ansibleでこの辞書をループする方法は?

この辞書があります

war_files:
  server1:
  - file1.war
  - file2.war
  server2:
  - file1.war
  - file2.war
  - file3.war

ここでは、各アイテム(キー)をループし、次にキーの各アイテム(値)をループしたいだけです。これは私がしました

- name: Loop over the dictionary
  debug: msg="Key={{ item.key }} value={{ item.value }}"
  with_dict: "{{ war_files }}"

そして、私はこれを取得します。それはもちろん正しいですが、私が望むものではありません。

ok: [localhost] => (item={'value': [u'file1.war', u'file2.war'], 'key': u'server1'}) => {
    "item": {
        "key": "server1", 
        "value": [
            "file1.war", 
            "file2.war"
        ]
    }, 
    "msg": "Server=server1, WAR=[u'file1.war', u'file2.war']"
}
ok: [localhost] => (item={'value': [u'file1.war', u'file2.war', u'file3.war'], 'key': u'server2'}) => {
    "item": {
        "key": "server2", 
        "value": [
            "file1.war", 
            "file2.war", 
            "file3.war"
        ]
    }, 
    "msg": "Server=server2, WAR=[u'file1.war', u'file2.war', u'file3.war']"
}

という出力を取得したい

"msg": "Server=server1, WAR=file1.war"
"msg": "Server=server1, WAR=file2.war"
"msg": "Server=server2, WAR=file1.war"
"msg": "Server=server2, WAR=file2.war"
"msg": "Server=server2, WAR=file3.war"

IOW、辞書を反復処理するタスクを作成して、各キー、各キー内のアイテムを処理するにはどうすればよいですか?本質的に、ネストされた配列があり、それを反復処理したいですか?

15
Chris F

[〜#〜] edit [〜#〜]:この回答を書いている時点では、Ansible 2.6はリリースされていませんでした。 @tmoschouが提供する回答を読んでください。


まあ、私はそれを行う非常に簡単な方法を見つけることができませんでしたが、少しのjinja2で、この種の何かを達成することができます:

/tmp ❯❯❯ cat example.yml
---
- hosts: 127.0.0.1
  vars:
    war_files:
      server1:
      - file1.war
      - file2.war
      server2:
      - file1.war
      - file2.war
      - file3.war
  tasks:
  - set_fact:
      war_files_list_of_dicts: |
          {% set res = [] -%}
          {% for key in war_files.keys() -%}
             {% for value in war_files[key] -%}
              {% set ignored = res.extend([{'Server': key, 'WAR':value}]) -%}
             {%- endfor %}
          {%- endfor %}
          {{ res }}

  - name: let's debug the crap out of this
    debug: var=war_files_list_of_dicts

  - name: Servers and their WARs!!!
    debug:
       msg: "Server={{ item.Server }}, WAR={{ item.WAR }}"
    with_items: "{{ war_files_list_of_dicts }}"

そして、プレイブックが実行されると:

/tmp ❯❯❯ ansible-playbook example.yml
 [WARNING]: provided hosts list is empty, only localhost is available


PLAY [127.0.0.1] ***************************************************************

TASK [setup] *******************************************************************
ok: [127.0.0.1]

TASK [set_fact] ****************************************************************
ok: [127.0.0.1]

TASK [let's debug the crap out of this] ****************************************
ok: [127.0.0.1] => {
    "war_files_list_of_dicts": [
        {
            "Server": "server1", 
            "WAR": "file1.war"
        }, 
        {
            "Server": "server1", 
            "WAR": "file2.war"
        }, 
        {
            "Server": "server2", 
            "WAR": "file1.war"
        }, 
        {
            "Server": "server2", 
            "WAR": "file2.war"
        }, 
        {
            "Server": "server2", 
            "WAR": "file3.war"
        }
    ]
}

TASK [Servers and their WARs!!!] ***********************************************
ok: [127.0.0.1] => (item={'WAR': u'file1.war', 'Server': u'server1'}) => {
    "item": {
        "Server": "server1", 
        "WAR": "file1.war"
    }, 
    "msg": "Server=server1, WAR=file1.war"
}
ok: [127.0.0.1] => (item={'WAR': u'file2.war', 'Server': u'server1'}) => {
    "item": {
        "Server": "server1", 
        "WAR": "file2.war"
    }, 
    "msg": "Server=server1, WAR=file2.war"
}
ok: [127.0.0.1] => (item={'WAR': u'file1.war', 'Server': u'server2'}) => {
    "item": {
        "Server": "server2", 
        "WAR": "file1.war"
    }, 
    "msg": "Server=server2, WAR=file1.war"
}
ok: [127.0.0.1] => (item={'WAR': u'file2.war', 'Server': u'server2'}) => {
    "item": {
        "Server": "server2", 
        "WAR": "file2.war"
    }, 
    "msg": "Server=server2, WAR=file2.war"
}
ok: [127.0.0.1] => (item={'WAR': u'file3.war', 'Server': u'server2'}) => {
    "item": {
        "Server": "server2", 
        "WAR": "file3.war"
    }, 
    "msg": "Server=server2, WAR=file3.war"
}

PLAY RECAP *********************************************************************
127.0.0.1                  : ok=4    changed=0    unreachable=0    failed=0   
6
Nehal J Wani

これはどう

- hosts: localhost
  vars:
    war_files:
      server1:
      - file1.war
      - file2.war
      server2:
      - file1.war
      - file2.war
      - file3.war
  tasks:
    - name: Loop over subelements of the dictionary
      debug:
        msg: "Key={{ item.0.key }} value={{ item.1 }}"
      loop: "{{ war_files | dict2items | subelements('value') }}"

dict2itemssubelementsフィルターはAnsible 2.6で導入されます。

参考までに、目的のフィルターが存在しない場合は、jinja2ハックに頼らずにpythonで独自のフィルターを作成できます。Ansibleは簡単に拡張可能です。filter_plugins/*.pyのフィルターはプレイ/ロールに隣接してデフォルトで検索され、自動的に含まれます-詳細については Developing Plugins を参照してください。

15
tmoschou

これでAnsibleはこれを許可します

- name: add several users
  user:
    name: "{{ item.name }}"
    state: present
    groups: "{{ item.groups }}"
  with_items:
    - { name: 'testuser1', groups: 'wheel' }
    - { name: 'testuser2', groups: 'root' }
12

辞書をループするための好ましい方法は次のとおりです。

input_data.ymlには次が含まれます。

----
input_data:
  item_1:
    id: 1
    info: "Info field number 1"
  item_2:
    id: 2
    info: "Info field number 2"

次に、keys()関数を使用したプレイで上記のようなデータ構造を使用し、with_itemsを使用してデータを反復処理します。

---
- hosts: localhost
  gather_facts: false
  connection: local
  tasks:
    - name: Include dictionary data
      include_vars:
        file: data.yml

    - name: Show info field from data.yml
      debug:
        msg: "Id: {{ input_data[item]['id'] }} - info: {{ input_data[item]['info'] }}"
      with_items: "{{ input_data.keys() }}"

上記のプレイブックは、次の出力を生成します。

PLAY [localhost] ***********************************************************

TASK [Include dictionary data] *********************************************
ok: [localhost]

TASK [Show info field from data.yml] ***************************************
ok: [localhost] => (item=item_2) => {
    "msg": "Id: 2 - info: Info field item 2"
}
ok: [localhost] => (item=item_3) => {
    "msg": "Id: 3 - info: Info field item 3"
}
ok: [localhost] => (item=item_1) => {
    "msg": "Id: 1 - info: Info field item 1"
}

PLAY RECAP *****************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0
2
M_dk

dict2items

異種のキーのセットとそれらに関連付けられた値を繰り返し処理し、タスクでキーと値のペアを使用したいと考えました。 dict2itemsフィルタは、私が見つけた最も簡単な方法です。 Ansible 2.6で dict2items を見つけることができます

ディクテーションの例

systemsetup:
  remotelogin: "On"
  timezone: "Europe/Oslo"
  usingnetworktime: "On"
  sleep: 0
  computersleep: 0
  displaysleep: 0
  harddisksleep: 0
  allowpowerbuttontosleepcomputer: "Off"
  wakeonnetworkaccess: "On"
  restartfreeze: "On"
  restartpowerfailure: "On"

タスク例

---
- debug:
    msg: "KEY: {{ item.key }}, VALUE: {{ item.value }}"
  loop: "{{ systemsetup | dict2items }}"