Ansibleのplaybookで`with_items`等でループ処理したすべての実行結果を`register`してdebugで取り出す方法

# はじめに
本記事は、Ansibleのplaybookで`with_items`等でループ処理した時の実行結果を`register`した後に、`debug`モジュールを利用して、標準出力結果をループ数分取り出す方法を試行錯誤した結果です。ループしなければ簡単なのですが、地味にはまりました。
なお、デバッグオプション(-v)をつけてplaybookを実行すれば、`register`と`debug`モジュールでこんなことをしなくても画面に出力されますが、改行されず見づらい等もあるので、自分用の備忘メモもかねて。

## アジェンダ
ENV. 実行環境
Sample Playbook サンプルプレイブック
Results サンプルプレイブック実行結果
解説

## Env.
```
# cat /etc/redhat-release
CentOS release 6.7 (Final)
#ansible --version
ansible 2.1.0 (devel d358a22542) last updated 2016/04/04 23:43:05 (GMT +900)
  lib/ansible/modules/core: (detached HEAD a38bdfc720) last updated 2016/04/04 23:43:15 (GMT +900)
  lib/ansible/modules/extras: (detached HEAD 7c3999a92a) last updated 2016/04/04 23:43:22 (GMT +900)
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
```

## Sample playbook

``` reg_ret_with_items.yml
- hosts: localhost
  gather_facts: no
  vars:
    TEST_CMD:
      - cmd: echo "# LOOP01 *** THIS IS LOOP01 STDOUT ***"
      - cmd: echo "# LOOP02 *** THIS IS LOOP02 STDOUT ***"
      - cmd: echo "# LOOP03 *** THIS IS LOOP03 STDOUT ***"

  tasks:
   - raw: echo "# NOLOOP *** THIS IS NOLOOP STDOUT ***"
     register: RESULT
   - name: "DEBUG0: Output RESULT.stdout_lines"
     debug: var=RESULT.stdout_lines

   - raw:  "{{ item.cmd }}"
     register: CMD_RESULT
     with_items: '{{ TEST_CMD }}'

   - name: "DEBUG1: Output CMD_RESULT.stdout_lines"
     debug: var=CMD_RESULT.stdout_lines

   - name: "DEBUG2: Output CMD_RESULT.results"
     debug: var=CMD_RESULT.results

   - name: "DEBUG3: Output CMD_RESULT.results.stdout_lines by using with_items loop"
     debug: var=item.stdout_lines
     with_items: '{{ CMD_RESULT.results }}'

   - name: "DEBUG4: Output CMD_RESULT.results.stdout_lines by using jinjya2 fileter"
     debug:
      msg: |
        {% for r in CMD_RESULT.results %}
          {{ r.stdout_lines | to_nice_json }}
        {% endfor %}
```

## Results

```
# ansible-playbook reg_ret_with_items.yml

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

TASK [raw] *********************************************************************
ok: [localhost]

TASK [DEBUG0: Output RESULT.stdout_lines] **************************************
ok: [localhost] => {
    "RESULT.stdout_lines": [
        "# NOLOOP *** THIS IS NOLOOP STDOUT ***"
    ]
}

TASK [raw] *********************************************************************
ok: [localhost] => (item={u'cmd': u'echo "# LOOP01 *** THIS IS LOOP01 STDOUT ***"'})
ok: [localhost] => (item={u'cmd': u'echo "# LOOP02 *** THIS IS LOOP02 STDOUT ***"'})
ok: [localhost] => (item={u'cmd': u'echo "# LOOP03 *** THIS IS LOOP03 STDOUT ***"'})

TASK [DEBUG1: Output CMD_RESULT.stdout_lines] **********************************
ok: [localhost] => {
    "CMD_RESULT.stdout_lines": "VARIABLE IS NOT DEFINED!"
}

TASK [DEBUG2: Output CMD_RESULT.results] ***************************************
ok: [localhost] => {
    "CMD_RESULT.results": [
        {
            "_ansible_item_result": true,
            "_ansible_no_log": false,
            "invocation": {
                "module_args": {
                    "_raw_params": "echo \"# LOOP01 *** THIS IS LOOP01 STDOUT ***\""
                },
                "module_name": "raw"
            },
            "item": {
                "cmd": "echo \"# LOOP01 *** THIS IS LOOP01 STDOUT ***\""
            },
            "rc": 0,
            "stderr": "",
            "stdout": "# LOOP01 *** THIS IS LOOP01 STDOUT ***\n",
            "stdout_lines": [
                "# LOOP01 *** THIS IS LOOP01 STDOUT ***"
            ]
        },
        {
            "_ansible_item_result": true,
            "_ansible_no_log": false,
            "invocation": {
                "module_args": {
                    "_raw_params": "echo \"# LOOP02 *** THIS IS LOOP02 STDOUT ***\""
                },
                "module_name": "raw"
            },
            "item": {
                "cmd": "echo \"# LOOP02 *** THIS IS LOOP02 STDOUT ***\""
            },
            "rc": 0,
            "stderr": "",
            "stdout": "# LOOP02 *** THIS IS LOOP02 STDOUT ***\n",
            "stdout_lines": [
                "# LOOP02 *** THIS IS LOOP02 STDOUT ***"
            ]
        },
        {
            "_ansible_item_result": true,
            "_ansible_no_log": false,
            "invocation": {
                "module_args": {
                    "_raw_params": "echo \"# LOOP03 *** THIS IS LOOP03 STDOUT ***\""
                },
                "module_name": "raw"
            },
            "item": {
                "cmd": "echo \"# LOOP03 *** THIS IS LOOP03 STDOUT ***\""
            },
            "rc": 0,
            "stderr": "",
            "stdout": "# LOOP03 *** THIS IS LOOP03 STDOUT ***\n",
            "stdout_lines": [
                "# LOOP03 *** THIS IS LOOP03 STDOUT ***"
            ]
        }
    ]
}

TASK [DEBUG3: Output CMD_RESULT.results.stdout_lines by using with_items loop] *
ok: [localhost] => (item={'_ansible_no_log': False, 'stdout': u'# LOOP01 *** THIS IS LOOP01 STDOUT ***\n', '_ansible_item_result': True, 'item': {u'cmd': u'echo "# LOOP01 *** THIS IS LOOP01 STDOUT ***"'}, 'stderr': u'', 'rc': 0, 'invocation': {'module_name': u'raw', 'module_args': {u'_raw_params': u'echo "# LOOP01 *** THIS IS LOOP01 STDOUT ***"'}}, 'stdout_lines': [u'# LOOP01 *** THIS IS LOOP01 STDOUT ***']}) => {
    "item": {
        "invocation": {
            "module_args": {
                "_raw_params": "echo \"# LOOP01 *** THIS IS LOOP01 STDOUT ***\""
            },
            "module_name": "raw"
        },
        "item": {
            "cmd": "echo \"# LOOP01 *** THIS IS LOOP01 STDOUT ***\""
        },
        "rc": 0,
        "stderr": "",
        "stdout": "# LOOP01 *** THIS IS LOOP01 STDOUT ***\n",
        "stdout_lines": [
            "# LOOP01 *** THIS IS LOOP01 STDOUT ***"
        ]
    },
    "item.stdout_lines": [
        "# LOOP01 *** THIS IS LOOP01 STDOUT ***"
    ]
}
ok: [localhost] => (item={'_ansible_no_log': False, 'stdout': u'# LOOP02 *** THIS IS LOOP02 STDOUT ***\n', '_ansible_item_result': True, 'item': {u'cmd': u'echo "# LOOP02 *** THIS IS LOOP02 STDOUT ***"'}, 'stderr': u'', 'rc': 0, 'invocation': {'module_name': u'raw', 'module_args': {u'_raw_params': u'echo "# LOOP02 *** THIS IS LOOP02 STDOUT ***"'}}, 'stdout_lines': [u'# LOOP02 *** THIS IS LOOP02 STDOUT ***']}) => {
    "item": {
        "invocation": {
            "module_args": {
                "_raw_params": "echo \"# LOOP02 *** THIS IS LOOP02 STDOUT ***\""
            },
            "module_name": "raw"
        },
        "item": {
            "cmd": "echo \"# LOOP02 *** THIS IS LOOP02 STDOUT ***\""
        },
        "rc": 0,
        "stderr": "",
        "stdout": "# LOOP02 *** THIS IS LOOP02 STDOUT ***\n",
        "stdout_lines": [
            "# LOOP02 *** THIS IS LOOP02 STDOUT ***"
        ]
    },
    "item.stdout_lines": [
        "# LOOP02 *** THIS IS LOOP02 STDOUT ***"
    ]
}
ok: [localhost] => (item={'_ansible_no_log': False, 'stdout': u'# LOOP03 *** THIS IS LOOP03 STDOUT ***\n', '_ansible_item_result': True, 'item': {u'cmd': u'echo "# LOOP03 *** THIS IS LOOP03 STDOUT ***"'}, 'stderr': u'', 'rc': 0, 'invocation': {'module_name': u'raw', 'module_args': {u'_raw_params': u'echo "# LOOP03 *** THIS IS LOOP03 STDOUT ***"'}}, 'stdout_lines': [u'# LOOP03 *** THIS IS LOOP03 STDOUT ***']}) => {
    "item": {
        "invocation": {
            "module_args": {
                "_raw_params": "echo \"# LOOP03 *** THIS IS LOOP03 STDOUT ***\""
            },
            "module_name": "raw"
        },
        "item": {
            "cmd": "echo \"# LOOP03 *** THIS IS LOOP03 STDOUT ***\""
        },
        "rc": 0,
        "stderr": "",
        "stdout": "# LOOP03 *** THIS IS LOOP03 STDOUT ***\n",
        "stdout_lines": [
            "# LOOP03 *** THIS IS LOOP03 STDOUT ***"
        ]
    },
    "item.stdout_lines": [
        "# LOOP03 *** THIS IS LOOP03 STDOUT ***"
    ]
}

TASK [DEBUG4: Output CMD_RESULT.results.stdout_lines by using jinjya2 fileter] *
ok: [localhost] => {
    "msg": "  [\n    \"# LOOP01 *** THIS IS LOOP01 STDOUT ***\"\n]\n  [\n    \"# LOOP02 *** THIS IS LOOP02 STDOUT ***\"\n]\n  [\n    \"# LOOP03 *** THIS IS LOOP03 STDOUT ***\"\n]\n"
}

PLAY RECAP *********************************************************************
localhost                  : ok=7    changed=0    unreachable=0    failed=0

#
```

## 解説
### ループ処理がない場合
ループ処理がない場合、*DEBUG0*のように標準出力の結果を画面表示できますが、
`with_items`等でループ処理をした場合は、少し工夫が必要です。

### ループ処理がある場合
ループ処理がある場合、`register`した結果は、`変数名.results`の下に配列として格納されているようなので、ループ処理がない時と同じようにしてもうまくいきません。

+ *DEBUG1*では、ループ処理が無いときと同じように書いているため、"VARIABLE IS NOT DEFINED!"として出力に失敗した例です。
+ *DEBUG2*では、`変数名.results`の配列をまるごと出力した例です。
+ *DEBUG3*では、`変数名.results.stdout_lines`を`with_itmes`として`変数名.results`を指定した例です。`item`の中身も出力されるので少し見ずらいです。
+ *DEBUG4*では、`変数名.results.stdout_lines`をjinjya2 filterを使ってstdout_linesのみを出力した例ですが、jinjya2 filterの理解不足のためか改行処理がうまくいっていません。。。

## おわりに
もっと上手い書き方があると思いますので、こんな風にすれば良い等、ありましたら是非コメント頂ければと思います。