てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] グループAとBの両方に所属しているホストを対象にする方法

■ はじめに

Ansible では、管理対象のホストをグループ化してインベントリファイルに定義できます。Playbook 内にグループを指定すると、指定したグループに所属するホストのみが対象になります。

では「グループAとBに両方に所属しているホスト」を対象にしたい場合はどのようにしたらよいでしょうか。 例えば以下のようなインベントリファイルがある場合、host02host03 を対象にしたい、というケースです。

[group_a]
host01
host02
host03

[group_b]
host02
host03
host04

この記事では、両方に所属しているホストを対象にする2つの方法を、簡単な例とともにご紹介します。

  • 動作確認環境: Ansible 2.3.0, 2.7.9


■ 方法1: play の hosts ディレクティブにグループを and 条件で指定する

Pkabbook内(のplay)の hosts ディレクティブには、複数の対象を and 条件で指定できます。この機能を利用する方法です。

参考: https://docs.ansible.com/ansible/latest/user_guide/intro_patterns.html

  • playbook
- hosts: group_a:&group_b
  gather_facts: no

  tasks:
    - name: debug test
      debug:
        msg: "I am {{ inventory_hostname }}."

上記のように group_a:&group_b と指定することで、group_a に所属、かつ group_b にも所属、という指定になります。

  • 実行例
$ ansible-playbook -i inventory test.yml

PLAY [group_a:&group_b] ****************************************************************

TASK [debug test] **********************************************************************
ok: [host02] => {
    "msg": "I am host02."
}
ok: [host03] => {
    "msg": "I am host03."
}

PLAY RECAP ******************************************************************************
host02                     : ok=1    changed=0    unreachable=0    failed=0    skipped=0
host03                     : ok=1    changed=0    unreachable=0    failed=0    skipped=0

両グループに所属している、host02host03 が対象となりました。

なお、--list-hosts オプションを付けると実処理をせずに対象ホストを確認できます。

$ ansible-playbook -i inventory test.yml --list-hosts

playbook: test.yml

  play #1 (group_a:&group_b): group_a:&group_b  TAGS: []
    pattern: [u'group_a:&group_b']
    hosts (2):
      host02
      host03


■ 方法2: -l オプションと組み合わせる

ansible-playbook コマンドには、対象ホストを絞り込む -l または --limit オプションがあります。この機能と、hosts ディレクティブを併用する方法です。

参考: https://docs.ansible.com/ansible/latest/cli/ansible-playbook.html#cmdoption-ansible-playbook-l

  • playbook
- hosts: group_a
  gather_facts: no

  tasks:
    - name: debug test
      debug:
        msg: "I am {{ inventory_hostname }}."

Playbook としては group_a を対象としています。

  • 実行例
$ ansible-playbook -i inventory test.yml -l group_b

PLAY [group_a] ***************************************************************************

TASK [debug test] ************************************************************************
ok: [host02] => {
    "msg": "I am host02."
}
ok: [host03] => {
    "msg": "I am host03."
}

PLAY RECAP *******************************************************************************
host02                     : ok=1    changed=0    unreachable=0    failed=0    skipped=0
host03                     : ok=1    changed=0    unreachable=0    failed=0    skipped=0

-l group_b で絞ることによって、結果的に両グループに所属している host02host03 が対象となりました。

--list-hosts オプションでも確認してみます。

$ ansible-playbook -i inventory test.yml -l group_b --list-hosts

playbook: test.yml

  play #1 (group_a): group_a    TAGS: []
    pattern: [u'group_a']
    hosts (2):
      host02
      host03


■ 方法3: when で group_names で判断する [2019/10/16 追記]

Play 単位ではなく、when が効く ロールや block 、タスクなどで使える方法です。

- hosts: all
  roles:
    - role: test
      when: "'group_a' in group_names and 'group_b' in group_names"
  tasks:
    - debug:
msg: In group_a and group_b
      when: "'group_a' in group_names and 'group_b' in group_names"

@satoh_fumiyasu さんにアイディアいただきました。ありがとうございます。


■ まとめ

複数のグループに所属しているホストを対象にする方法を2つご紹介しました。 ただ、インベントリとして新たにグループを定義したほうが、メンテナンス性が良いケースもあるかもしれません。必要に応じて使い分けるのが良いと思います。