Ansibleのregisterから任意のディクショナリやリストを生成する

#はじめに
Ansibleでタスクの実行結果をregisterに保存しておくと後続タスクで利用することができますが、階層が深かったりするので、結果から任意の値でディクショナリやリストを作れれば色々と便利ですよね。

今回はregisterから任意のディクショナリやリストを生成して、後続タスクで利用してみたいと思います。


#sample

ターゲットホストの下記ユーザのUIDを取得し、それらをディクショナリやリストにして、後続タスクで参照します。

- test1(UID:501)
- test2(UID:502)

##UIDを取得してresisterに保存


```YAML:playbook
- name: UID取得
  command: "id -u {{ item }}"
  with_items:
    - test1
    - test2
  register: uid

- debug: var=uid.results
```

idコマンドでuidを取得し、registerに結果を保存します。

##結果

```YAML:結果
TASK [sample : UID取得 _raw_params=id -u {{ item }}] *****************************
changed: [targethost] => (item=test1)
changed: [targethost] => (item=test2)

TASK [sample : debug var=uid.results] ****************************************
ok: [targethost] => {
    "uid.results": [
        {
            "_ansible_item_result": true,
            "_ansible_no_log": false,
            "_ansible_parsed": true,
            "changed": true,
            "cmd": [
                "id",
                "-u",
                "test1"
            ],
            "delta": "0:00:00.002434",
            "end": "2017-03-24 17:29:35.322215",
            "invocation": {
                "module_args": {
                    "_raw_params": "id -u test1",
                    "_uses_shell": false,
                    "chdir": null,
                    "creates": null,
                    "executable": null,
                    "removes": null,
                    "warn": true
                },
                "module_name": "command"
            },
            "item": "test1",
            "rc": 0,
            "start": "2017-03-24 17:29:35.319781",
            "stderr": "",
            "stdout": "501",
            "stdout_lines": [
                "501"
            ],
            "warnings": []
        },
        {
            "_ansible_item_result": true,
            "_ansible_no_log": false,
            "_ansible_parsed": true,
            "changed": true,
            "cmd": [
                "id",
                "-u",
                "test2"
            ],
            "delta": "0:00:00.002320",
            "end": "2017-03-24 17:29:35.535008",
            "invocation": {
                "module_args": {
                    "_raw_params": "id -u test2",
                    "_uses_shell": false,
                    "chdir": null,
                    "creates": null,
                    "executable": null,
                    "removes": null,
                    "warn": true
                },
                "module_name": "command"
            },
            "item": "test2",
            "rc": 0,
            "start": "2017-03-24 17:29:35.532688",
            "stderr": "",
            "stdout": "502",
            "stdout_lines": [
                "502"
            ],
            "warnings": []
        }
    ]
}
```
ちょっと長いですが、今回は`with_items`で2回ループさせているので、uid.resultsというリストに結果が格納されています。

それぞれの`item`と`stdout`（今回はuid）からディクショナリを作成します。

##ディクショナリ作成

```YAML:playbook
- name: dict作成
  set_fact:
    uid_dict: >-
      {%- set tmpdict = {} -%}
      {%- for i in range(uid.results|length) -%}
      {%-   set _ = tmpdict.update({uid.results[i].item: uid.results[i].stdout}) -%}
      {%- endfor -%}
      {{ tmpdict }}

- debug: var=uid_dict
```

##結果
```YAML:結果
TASK [sample : dict作成 uid_dict={%- set tmpdict = {} -%} {%- for i in range(uid.results|length) -%} {%-   set _ = tmpdict.update({uid.results[i].item: uid.results[i].stdout}) -%} {%- endfor -%} {{ tmpdict }}] ***
ok: [targethost]

TASK [sample : debug var=uid_dict] *******************************************
ok: [targethost] => {
    "uid_dict": {
        "test1": "501",
        "test2": "502"
    }
}
```
uid_dictという、key:ユーザ名,value:UIDのディクショナリができました。

次はUIDだけのリストを作成してみます。


##リスト作成
```YAML:playbook
- name: list作成
  set_fact:
    uid_list: >-
      {%- set tmplist = [] -%}
      {%- for i in range(uid.results|length) -%}
      {%-   set _ = tmplist.append(uid.results[i].stdout) -%}
      {%- endfor -%}
      {{ tmplist }}

- debug: var=uid_list
```

##結果
```
TASK [sample : list作成 uid_list={%- set tmplist = [] -%} {%- for i in range(uid.results|length) -%} {%-   set _ = tmplist.append(uid.results[i].stdout) -%} {%- endfor -%} {{ tmplist }}] ***
ok: [targethost]

TASK [sample : debug var=uid_list] *******************************************
ok: [targethost] => {
    "uid_list": [
        "501",
        "502"
    ]
}
```
作成できました。

それでは、後続タスクでこれらを参照してみます。

まず、uid_dictのtest1のvalue(=501)をrawモジュールに渡して/etc/passwdをuidでgrepしてみます。

##ディクショナリを使う
```YAML:playbook
- name: uid_dictを使う
  raw: "cat /etc/passwd | grep {{ uid_dict.test1 }}"
  register: use_uid_dict

- debug: var=use_uid_dict.stdout
```


##結果
```YAML:結果
TASK [sample : uid_dictを使う _raw_params=cat /etc/passwd | grep {{ uid_dict.test1 }}] ***
changed: [targethost]

TASK [set_dict : debug var=use_uid_dict.stdout] ********************************
ok: [targethost] => {
    "use_uid_dict.stdout": "test1:x:501:501::/home/test1:/bin/bash\r\n"
}
```
うまくいきました。

次はuid_listを使ってwith_itemsでループさせてみます。
uid_listにはUIDが格納されているので、同じく/etc/passwdをgrepしてみます。

##リストを使う
```YAML:playbook
- name: uid_listを使う
  raw: "cat /etc/passwd | grep {{ item }}"
  with_items: "{{ uid_list }}"
  register: use_uid_list

- debug: var=use_uid_list.results
```

##結果
```YAML:結果
TASK [sample : uid_listを使う _raw_params=cat /etc/passwd | grep {{ item }}] ******
changed: [targethost] => (item=501)
changed: [targethost] => (item=502)

TASK [sample : debug var=use_uid_list.results] *******************************
ok: [targethost] => {
    "use_uid_list.results": [
        {
            "_ansible_item_result": true,
            "_ansible_no_log": false,
            "changed": true,
            "invocation": {
                "module_args": {
                    "_raw_params": "cat /etc/passwd | grep 501"
                },
                "module_name": "raw"
            },
            "item": "501",
            "rc": 0,
            "stderr": "Shared connection to xxx.xxx.xxx.xxx closed.\r\n",
            "stdout": "test1:x:501:501::/home/test1:/bin/bash\r\n",
            "stdout_lines": [
                "test1:x:501:501::/home/test1:/bin/bash"
            ]
        },
        {
            "_ansible_item_result": true,
            "_ansible_no_log": false,
            "changed": true,
            "invocation": {
                "module_args": {
                    "_raw_params": "cat /etc/passwd | grep 502"
                },
                "module_name": "raw"
            },
            "item": "502",
            "rc": 0,
            "stderr": "Shared connection to xxx.xxx.xxx.xxx closed.\r\n",
            "stdout": "test2:x:502:502::/home/test2:/bin/bash\r\n",
            "stdout_lines": [
                "test2:x:502:502::/home/test2:/bin/bash"
            ]
        }
    ]
}
```
ちょっと長いですが、各resultsのstdoutを見ると、うまくいっているのが分かります。

#まとめ
今回のサンプルはあまりいい例ではありませんが、このように任意のディクショナリやリストを作成すると何かと便利に使えると思います。