Ansible: 次playの接続先や接続方法を動的に設定するにはadd_hostモジュールが使用可能


タイトル通りですが備忘として。

add_hostモジュールは、同じプレイブックのその後のプレイで使用するために、インメモリーのインベントリーに新しいホストとグループを作成する。

より正確には、add_hostを使用しなくとも、インベントリーに含まれるhostやgroupは、接続先として指定可能。
しかし、例えば、現playでデプロイする為、接続先、接続方法、インスタンス数などがまだ未定のvmに、次playで接続したいと言った様な場合には、インベントリーへの動的な追加が必要となる。


## 例1 メモリー内のインベントリーにホストを追加して、次playで指定

### playbook

```yaml:sample1.yml
- name: play01
  hosts: localhost
  gather_facts: false
  tasks:

    - name: groups befor add_host
      debug:
        var: groups


    - name: !unsafe 'add_host: { name: new_host, ansible_host: p8126a, ansible_python_interpreter: /usr/bin/python }'
      add_host:　　　　　　　　　　　　　# インベントリーにnew_hostを追加　
        name: new_host
        ansible_host: p8126a
        ansible_python_interpreter: /usr/bin/python
      register: r


    - name: result of add_host
      debug:
        var: r

    - name: groups after add_host
      debug:
        var: groups

    - debug:
        var: hostvars['new_host'].ansible_host

    - debug:
        var: hostvars['new_host'].ansible_python_interpreter


- name: play02
  hosts: new_host                 　　# <= インベントリーに追加したnew_host
  gather_facts: false
  tasks:
    - debug:
        var: inventory_hostname
    - name: '"shell": "cat /etc/motd"'
      shell: cat /etc/motd
      register: r
    - debug:
        var: r.stdout_lines
```

### 実行

```
$ ansible-playbook -i localhost, sample1.yml

PLAY [play01] ****************************************************************************************************

TASK [groups befor add_host] *************************************************************************************
ok: [localhost] => {
    "groups": {
        "all": [
            "localhost"
        ],
        "ungrouped": [
            "localhost"
        ]
    }
}

TASK [add_host: { name: new_host, ansible_host: p8126a, ansible_python_interpreter: /usr/bin/python }] ***********
changed: [localhost]

TASK [result of add_host] ****************************************************************************************
ok: [localhost] => {
    "r": {
        "add_host": {
            "groups": [],
            "host_name": "new_host",
            "host_vars": {
                "ansible_host": "p8126a",
                "ansible_python_interpreter": "/usr/bin/python"
            }
        },
        "changed": true,
        "failed": false
    }
}

TASK [groups after add_host] *************************************************************************************
ok: [localhost] => {
    "groups": {
        "all": [
            "new_host",         # <= 追加
            "localhost"
        ],
        "ungrouped": [
            "localhost",
            "new_host"　　　　　　# <= 追加
        ]
    }
}

TASK [debug] *****************************************************************************************************
ok: [localhost] => {
    "hostvars['new_host'].ansible_host": "p8126a"
}

TASK [debug] *****************************************************************************************************
ok: [localhost] => {
    "hostvars['new_host'].ansible_python_interpreter": "/usr/bin/python"
}

# <= 以下から別playとなる

PLAY [play02] ****************************************************************************************************

TASK [debug] *****************************************************************************************************
ok: [new_host] => {
    "inventory_hostname": "new_host"         # <= 接続先がnew_hostとなっている
}

TASK ["shell": "cat /etc/motd"] **********************************************************************************
changed: [new_host]

TASK [debug] *****************************************************************************************************
ok: [new_host] => {
    "r.stdout_lines": [
        "*******************************************************************************",
        "*                                                                             *",
        "*                                                                             *",
        "*  Welcome to AIX Version 7.2!                                                *",
        "*                                                                             *",
        "*                                                                             *",
        "*  Please see the README file in /usr/lpp/bos for information pertinent to    *",
        "*  this release of the AIX Operating System.                                  *",
        "*                                                                             *",
        "*                                                                             *",
        "*******************************************************************************"
    ]
}

PLAY RECAP *******************************************************************************************************
localhost                  : ok=6    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
new_host                   : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
```

## 例2 メモリー内のインベントリーにホストグループを追加して、次playで指定

### playbook

```yaml:sample2.yml

- name: play01
  hosts: localhost
  gather_facts: false
  vars:
    add_host:                  # <= play varsに定義
      - name: new_host01
        groups: new_group　　　# <= group名を合わせる
        ansible_host: p8126a
        ansible_python_interpreter: /usr/bin/python
      - name: new_host02
        groups: new_group　　　# <= group名を合わせる
        ansible_host: p8127a
        ansible_python_interpreter: /usr/bin/python
  tasks:


    - name: 'add_host'
      loop: '{{ add_host }}'
      add_host:                # <= インベントリーにgroups指定でhost追加
        name: '{{ item.name }}'
        ansible_connection: '{{ item.ansible_connection | default(omit) }}'
        ansible_host: '{{ item.ansible_host | default(omit) }}'
        ansible_python_interpreter: '{{ item.ansible_python_interpreter | default(omit)
          }}'
        ansible_user: '{{ item.ansible_user | default(omit) }}'
        ansible_port: '{{ item.ansible_port | default(omit) }}'
        ansible_ssh_private_key_file: '{{ item.ansible_ssh_private_key_file | default(omit)
          }}'
        groups: '{{ item.groups | default(omit) }}'

    - name: groups after add_host
      debug:
        var: groups


- name: play02
  hosts: new_group　　　　　　　　# <= インベントリーに追加したnew_group
  gather_facts: false
  tasks:
    - debug:
        var: inventory_hostname
    - name: '"shell": "cat /etc/motd"'
      shell: cat /etc/motd
      register: r
    - debug:
        var: r.stdout_lines
```

```
$ ansible-playbook -i localhost, sample2.yml 

PLAY [play01] ****************************************************************************************************

TASK [add_host] ************************************************************************************
changed: [localhost] => (item={'name': 'new_host01', 'ansible_host': 'p8126a', 'ansible_python_interpreter': '/usr/bin/python', 'groups': 'new_group'})
changed: [localhost] => (item={'name': 'new_host02', 'ansible_host': 'p8127a', 'ansible_python_interpreter': '/usr/bin/python', 'groups': 'new_group'})

TASK [groups after add_host] *************************************************************************************
ok: [localhost] => {
    "groups": {
        "all": [               # <= もし以降のplayでhosts: allを指定すると現対象hostも含まれる
            "new_host01",
            "new_host02",
            "localhost"
        ],
        "new_group": [　　　　　# <= 追加ホストで指定したgroup
            "new_host01",
            "new_host02"
        ],
        "ungrouped": [
            "localhost"
        ]
    }
}

# <= 以下から別playとなる

PLAY [play02] 　　　　　　　　　　＃〈＝ 表示名を明示指定しない場合、hosts:に渡される名前(この例ではnew_group)が使用される。--limit SUBSET相当。
****************************************************************************************************

TASK [debug] *****************************************************************************************************
ok: [new_host01] => {
    "inventory_hostname": "new_host01"
}
ok: [new_host02] => {
    "inventory_hostname": "new_host02"
}

TASK ["shell": "cat /etc/motd"] **********************************************************************************
changed: [new_host01]
changed: [new_host02]

TASK [debug] *****************************************************************************************************
ok: [new_host01] => {
    "r.stdout_lines": [
        "*******************************************************************************",
        "*                                                                             *",
        "*                                                                             *",
        "*  Welcome to AIX Version 7.2!                                                *",
        "*                                                                             *",
        "*                                                                             *",
        "*  Please see the README file in /usr/lpp/bos for information pertinent to    *",
        "*  this release of the AIX Operating System.                                  *",
        "*                                                                             *",
        "*                                                                             *",
        "*******************************************************************************"
    ]
}
ok: [new_host02] => {
    "r.stdout_lines": [
        "*******************************************************************************",
        "*                                                                             *",
        "*                                                                             *",
        "*  Welcome to AIX Version 7.2!                                                *",
        "*                                                                             *",
        "*                                                                             *",
        "*  Please see the README file in /usr/lpp/bos for information pertinent to    *",
        "*  this release of the AIX Operating System.                                  *",
        "*                                                                             *",
        "*                                                                             *",
        "*******************************************************************************"
    ]
}

PLAY RECAP *******************************************************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
new_host01                 : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
new_host02                 : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
```


## 不明

- play varsは、インベントリーに書かなくてもplayに直接書けば良いので、重要度は低い。
- group varsをどう書くかは未調査。書ける？

## 参考
https://stackoverflow.com/questions/47681937/ansible-specify-inventory-file-inside-playbook
https://stackoverflow.com/a/47682837/13819312

https://docs.ansible.com/ansible/latest/modules/add_host_module.html