tech memo

調べたこと、試したことの覚書です

Ansible で 動的リストをつかって 一部の処理をループ実行する

この記事の概要

Ansible の playbook を使って、

① 対象サーバからリスト(インターフェース一覧など)を取得する
② そのリストの項目毎に一部の処理をループ実行する

ということを、1回のplaybook実行でできる記述方法を模索していたところ、とあるアプローチに至ったので、その手法を書き留めておきます。

変数に定義するのはつらいリスト(流動的 or 膨大な量)に対して処理を実行したいときに使えそうな方法なのではないかと思っています。

 

実行バージョンによる留意事項

私が試した Ansible バージョンは 2.6.2です。

記事内の記述は、バージョン 2.4 以降の Action である import_tasksinclude_tasks をつかって記述しています。

バージョン 2.6.2だとまだ include でも記述可能ですが、下記のような include は 2.8で無くなる という旨の警告が出力されます。

[DEPRECATION WARNING]: 'include' for playbook includes. You should use 'import_playbook' instead. This
feature will be removed in version 2.8. Deprecation warnings can be disabled by setting
deprecation_warnings=False in ansible.cfg. 

バージョン 2.1以降~2.4未満で記述する場合は、逆に include を使わないとsyntax errorになる はずですので、

下記に記述する手法の import_tasksinclude_tasksinclude に置き換えて頂くと、同様の動作をすると思われます。

 

playbook の記述例と解説

さて、本題です。playbook の記述例 です。

<階層>

ansible.cfg
hosts
playbook.yml
roles
L test
L tasks
L main.yml
  L install.yml
  L config.yml
L setup.yml ← こちらがループ対象の処理

※ ansible.cfg、hosts、install.yml については今回の説明に内容の例示が不要ですので割愛させていただきます。

 

<playbook.yml>

---
- hosts: all
remote_user: root
roles:
- role: test

 

<main.yml>

---
- import_tasks: install.yml
tags:
- test
- test_install

- import_tasks: config.yml
tags:
- test
- test_config

 

<config.yml>

- name: config
command: echo "test config"

## ここで何かしらのリストを取得します
- name: get target interface name
shell: |
/sbin/ip -o link | awk -F': ' '{print $2}' | grep -v lo
register: interface_list
check_mode: no
changed_when: false

- include_tasks: setup.yml
with_items: "{{ interface_list.stdout_lines }}"

 わたしが例で示したリスト取得コマンドの実行結果の例はこのような内容です。

$ /sbin/ip -o link | awk -F': ' '{print $2}' | grep -v lo
eth0
eth1

これを、with_items: <レジスタ名>.stdout_lines で呼ぶと リストの各行を 1 item として setup.yml をループ実行させることができます。

 

<setup.yml>

- name: setup test
command: echo "{{ item }}"

 今回は、分かりやすいようにechoするだけにしてみます。

 

playbook の実行結果

さて、このplaybookを実行してみます。

ansible-playbook playbook.yml -v -D -t test

PLAY [all] **********************************************************************

(略)

TASK [test : install] ***********************************************************
changed: [(アドレス)] => {"changed": true, "cmd": ["echo", "install"], "delta": "0:00:00.002680", "end": "2019-02-22 23:58:21.466355", "rc": 0, "start": "2019-02-22 23:58:21.463675", "stderr": "", "stderr_lines": [], "stdout": "install", "stdout_lines": ["install"]}

TASK [test : config] ************************************************************
changed: [(アドレス)] => {"changed": true, "cmd": ["echo", "config"], "delta": "0:00:00.002671", "end": "2019-02-22 23:58:22.044150", "rc": 0, "start": "2019-02-22 23:58:22.041479", "stderr": "", "stderr_lines": [], "stdout": "config", "stdout_lines": ["config"]}

TASK [test : get target interface name] *****************************************
ok: [(アドレス)] => {"changed": false, "cmd": "/sbin/ip -o link | awk -F': ' '{print $2}'", "delta": "0:00:00.004626", "end": "2019-02-22 23:58:22.631947", "rc": 0, "start": "2019-02-22 23:58:22.627321", "stderr": "", "stderr_lines": [], "stdout": "eth0\neth1", "stdout_lines": ["eth0", "eth1"]}

TASK [test : include_tasks] *****************************************************
included: /home/nozomi/work/test-loop/roles/test/tasks/setup.yml for (アドレス)
included: /home/nozomi/work/test-loop/roles/test/tasks/setup.yml for (アドレス)

TASK [test : setup test] ********************************************************
changed: [(アドレス)] => {"changed": true, "cmd": ["echo", "lo"], "delta": "0:00:00.002642", "end": "2019-02-22 23:58:23.403662", "rc": 0, "start": "2019-02-22 23:58:23.401020", "stderr": "", "stderr_lines": [], "stdout": "eth0", "stdout_lines": ["eth0"]}

TASK [test : setup test] ********************************************************
changed: [(アドレス)] => {"changed": true, "cmd": ["echo", "eth0"], "delta": "0:00:00.002678", "end": "2019-02-22 23:58:24.035418", "rc": 0, "start": "2019-02-22 23:58:24.032740", "stderr": "", "stderr_lines": [], "stdout": "eth1", "stdout_lines": ["eth1"]}

PLAY RECAP **********************************************************************

(略)

 実行処理の順序は下記のようになりました。

main.yml
→ install.yml
task: install
→ config.yml
task: config
task: include_tasks
→ setup.yml
task: setup test (1回目/item=eth0)
task: setup test (2回目/item=eth1)

 このように 動的リストをつかって 一部の処理をループ実行させることができました。