LoginSignup
3
1

More than 5 years have passed since last update.

Ansibleでループの条件分岐したい時

Posted at

目的

現在インストール済みのパッケージを確認し、有無によって実行処理を分けたい場合があると思うので、それをやってみたいと思います
今回はasdfのプラグインの場合で確認しますが、それ以外のパッケージマネージャーでも利用できます
もちろんモジュールがあるならそれを使ったほうがいいですが、モジュールを作ろうとすると、結構よく出てくる問題です

対象環境

> ansible --version
ansible 2.7.1
  config file = None
  configured module search path = ['/Users/loveansibleman/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/Cellar/ansible/2.7.1/libexec/lib/python3.7/site-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 3.7.1 (default, Nov 11 2018, 22:35:12) [Clang 10.0.0 (clang-1000.11.45.5)]

方法

変数代入

まず、変数代入の部分ですが、基本的にwith_itemsと同じ部分に記載すれば良いです
今回はasdf pluginを確認して、条件分岐をしたいので、asdf plugin-listの結果をgrepで必要な言語をwith_items配下で指定してgrepしています
asdfの場合、.bash_profileを読み込んで実行する必要があるので、先頭に/bin/bash -lcをつけています
rbenvなどをインストールする時も同じようなことがありますが、必要に応じてつけてください

- name: Get installed plugin list
  shell: /bin/bash -lc "asdf plugin-list | grep {{ item }}"
  register: result
  with_items:
    - python
    - ruby
    - golang
    - java
  ignore_errors: yes
  changed_when: no

grepは引っかからなければエラーとなるのでignore_errors: yesとし、コマンドが実行出来ればchangeとなるのでchanged_when: noを入れています

結果が下記です

TASK [Get installed plugin list] ***************************************************************
ok: [127.0.0.1] => (item=python)
ok: [127.0.0.1] => (item=ruby)
ok: [127.0.0.1] => (item=golang)
failed: [127.0.0.1] (item=java) => {"changed": false, "cmd": "/bin/bash -lc \"asdf plugin-list | grep java\"", "delta": "0:00:00.574073", "end": "2019-01-26 10:42:38.981170", "item": "java", "msg": "non-zero return code", "rc": 1, "start": "2019-01-26 10:42:38.407097", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

python, ruby, golangは存在するのでgrepでエラーにならず、またchanged_when: noを入れているためchangeにもならず、okになっています。
javaは存在しないためエラーになっていますが、ignore_errors: yesを入れているため、ignoringとなっています

変数の中身

resultの中身をみたいので、下記Playbookを実行します

- name: View result
  debug: 
    var: result

すると結果がこちらです

TASK [View result] *****************************************************************************
ok: [127.0.0.1] => {
    "result": {
        "changed": false,
        "failed": true,
        "msg": "All items completed",
        "results": [
            {
                "_ansible_ignore_errors": true,
                "_ansible_item_label": "python",
                "_ansible_item_result": true,
                "_ansible_no_log": false,
                "_ansible_parsed": true,
                "changed": false,
                "cmd": "/bin/bash -lc \"asdf plugin-list | grep python\"",
                "delta": "0:00:00.694997",
                "end": "2019-01-26 10:42:36.372877",
                "failed": false,
                "invocation": {
                    "module_args": {
                        "_raw_params": "/bin/bash -lc \"asdf plugin-list | grep python\"",
                        "_uses_shell": true,
                        "argv": null,
                        "chdir": null,
                        "creates": null,
                        "executable": null,
                        "removes": null,
                        "stdin": null,
                        "warn": true
                    }
                },
                "item": "python",
                "rc": 0,
                "start": "2019-01-26 10:42:35.677880",
                "stderr": "",
                "stderr_lines": [],
                "stdout": "python",
                "stdout_lines": [
                    "python"
                ]
            },
            {
                "_ansible_ignore_errors": true,
                "_ansible_item_label": "ruby",
                "_ansible_item_result": true,
                "_ansible_no_log": false,
                "_ansible_parsed": true,
                "changed": false,
                "cmd": "/bin/bash -lc \"asdf plugin-list | grep ruby\"",
                "delta": "0:00:00.584345",
                "end": "2019-01-26 10:42:37.258385",
                "failed": false,
                "invocation": {
                    "module_args": {
                        "_raw_params": "/bin/bash -lc \"asdf plugin-list | grep ruby\"",
                        "_uses_shell": true,
                        "argv": null,
                        "chdir": null,
                        "creates": null,
                        "executable": null,
                        "removes": null,
                        "stdin": null,
                        "warn": true
                    }
                },
                "item": "ruby",
                "rc": 0,
                "start": "2019-01-26 10:42:36.674040",
                "stderr": "",
                "stderr_lines": [],
                "stdout": "ruby",
                "stdout_lines": [
                    "ruby"
                ]
            },
            {
                "_ansible_ignore_errors": true,
                "_ansible_item_label": "golang",
                "_ansible_item_result": true,
                "_ansible_no_log": false,
                "_ansible_parsed": true,
                "changed": false,
                "cmd": "/bin/bash -lc \"asdf plugin-list | grep golang\"",
                "delta": "0:00:00.579275",
                "end": "2019-01-26 10:42:38.121094",
                "failed": false,
                "invocation": {
                    "module_args": {
                        "_raw_params": "/bin/bash -lc \"asdf plugin-list | grep golang\"",
                        "_uses_shell": true,
                        "argv": null,
                        "chdir": null,
                        "creates": null,
                        "executable": null,
                        "removes": null,
                        "stdin": null,
                        "warn": true
                    }
                },
                "item": "golang",
                "rc": 0,
                "start": "2019-01-26 10:42:37.541819",
                "stderr": "",
                "stderr_lines": [],
                "stdout": "golang",
                "stdout_lines": [
                    "golang"
                ]
            },
            {
                "_ansible_item_label": "java",
                "_ansible_item_result": true,
                "_ansible_no_log": false,
                "_ansible_parsed": true,
                "changed": false,
                "cmd": "/bin/bash -lc \"asdf plugin-list | grep java\"",
                "delta": "0:00:00.574073",
                "end": "2019-01-26 10:42:38.981170",
                "failed": true,
                "invocation": {
                    "module_args": {
                        "_raw_params": "/bin/bash -lc \"asdf plugin-list | grep java\"",
                        "_uses_shell": true,
                        "argv": null,
                        "chdir": null,
                        "creates": null,
                        "executable": null,
                        "removes": null,
                        "stdin": null,
                        "warn": true
                    }
                },
                "item": "java",
                "msg": "non-zero return code",
                "rc": 1,
                "start": "2019-01-26 10:42:38.407097",
                "stderr": "",
                "stderr_lines": [],
                "stdout": "",
                "stdout_lines": []
            }
        ]
    }
}

これを見ると、result.resultsの中にwith_itemsのそれぞれの結果が配列として入っています
その配列の中身の中にfailed, item, cmdなどが入っています
それぞれの説明は下記の通りです

key名 valueの説明
failed 失敗したかどうかのboolean値
item with_itemsで指定した値
cmd 今回実行したコマンド

つまり、result.resultsでループを回し、その中のfailedで条件分岐が出来ることがわかりました
また、item, cmdも必要であればループ内で利用できます

条件分岐

上記の結果を元に、result.resultsをwith_itemsにいれ、whenにnot item.failedを入れると、存在した場合の条件分岐ができ、item.failedを入れると存在しない場合の条件分岐ができます
その時の設定が下記です

- name: If listed items
  debug: 
    msg: "{{ item.item }} is found"
  with_items: '{{ result.results }}'
  when: not item.failed

- name: If not listed items
  debug: 
    msg: "{{ item.item }} is not found"
  with_items: '{{ result.results }}'
  when: item.failed

結果が下記です

TASK [If listed items] *************************************************************************
ok: [127.0.0.1] => (item={'changed': False, 'end': '2019-01-26 10:42:36.372877', 'stdout': 'python', 'cmd': '/bin/bash -lc "asdf plugin-list | grep python"', 'rc': 0, 'start': '2019-01-26 10:42:35.677880', 'stderr': '', 'delta': '0:00:00.694997', 'invocation': {'module_args': {'creates': None, 'executable': None, '_uses_shell': True, '_raw_params': '/bin/bash -lc "asdf plugin-list | grep python"', 'removes': None, 'argv': None, 'warn': True, 'chdir': None, 'stdin': None}}, '_ansible_parsed': True, 'stdout_lines': ['python'], 'stderr_lines': [], '_ansible_no_log': False, 'failed': False, 'item': 'python', '_ansible_item_result': True, '_ansible_ignore_errors': True, '_ansible_item_label': 'python'}) => {
    "msg": "python is found"
}
ok: [127.0.0.1] => (item={'changed': False, 'end': '2019-01-26 10:42:37.258385', 'stdout': 'ruby', 'cmd': '/bin/bash -lc "asdf plugin-list | grep ruby"', 'rc': 0, 'start': '2019-01-26 10:42:36.674040', 'stderr': '', 'delta': '0:00:00.584345', 'invocation': {'module_args': {'creates': None, 'executable': None, '_uses_shell': True, '_raw_params': '/bin/bash -lc "asdf plugin-list | grep ruby"', 'removes': None, 'argv': None, 'warn': True, 'chdir': None, 'stdin': None}}, '_ansible_parsed': True, 'stdout_lines': ['ruby'], 'stderr_lines': [], '_ansible_no_log': False, 'failed': False, 'item': 'ruby', '_ansible_item_result': True, '_ansible_ignore_errors': True, '_ansible_item_label': 'ruby'}) => {
    "msg": "ruby is found"
}
ok: [127.0.0.1] => (item={'changed': False, 'end': '2019-01-26 10:42:38.121094', 'stdout': 'golang', 'cmd': '/bin/bash -lc "asdf plugin-list | grep golang"', 'rc': 0, 'start': '2019-01-26 10:42:37.541819', 'stderr': '', 'delta': '0:00:00.579275', 'invocation': {'module_args': {'creates': None, 'executable': None, '_uses_shell': True, '_raw_params': '/bin/bash -lc "asdf plugin-list | grep golang"', 'removes': None, 'argv': None, 'warn': True, 'chdir': None, 'stdin': None}}, '_ansible_parsed': True, 'stdout_lines': ['golang'], 'stderr_lines': [], '_ansible_no_log': False, 'failed': False, 'item': 'golang', '_ansible_item_result': True, '_ansible_ignore_errors': True, '_ansible_item_label': 'golang'}) => {
    "msg": "golang is found"
}
skipping: [127.0.0.1] => (item={'changed': False, 'end': '2019-01-26 10:42:38.981170', 'stdout': '', 'cmd': '/bin/bash -lc "asdf plugin-list | grep java"', 'failed': True, 'delta': '0:00:00.574073', 'stderr': '', 'rc': 1, 'invocation': {'module_args': {'creates': None, 'executable': None, '_uses_shell': True, '_raw_params': '/bin/bash -lc "asdf plugin-list | grep java"', 'removes': None, 'argv': None, 'warn': True, 'chdir': None, 'stdin': None}}, 'start': '2019-01-26 10:42:38.407097', 'msg': 'non-zero return code', '_ansible_parsed': True, 'stdout_lines': [], 'stderr_lines': [], '_ansible_no_log': False, 'item': 'java', '_ansible_item_result': True, '_ansible_item_label': 'java'})

TASK [If not listed items] ********************************************************************
skipping: [127.0.0.1] => (item={'changed': False, 'end': '2019-01-26 10:42:36.372877', 'stdout': 'python', 'cmd': '/bin/bash -lc "asdf plugin-list | grep python"', 'rc': 0, 'start': '2019-01-26 10:42:35.677880', 'stderr': '', 'delta': '0:00:00.694997', 'invocation': {'module_args': {'creates': None, 'executable': None, '_uses_shell': True, '_raw_params': '/bin/bash -lc "asdf plugin-list | grep python"', 'removes': None, 'argv': None, 'warn': True, 'chdir': None, 'stdin': None}}, '_ansible_parsed': True, 'stdout_lines': ['python'], 'stderr_lines': [], '_ansible_no_log': False, 'failed': False, 'item': 'python', '_ansible_item_result': True, '_ansible_ignore_errors': True, '_ansible_item_label': 'python'})
skipping: [127.0.0.1] => (item={'changed': False, 'end': '2019-01-26 10:42:37.258385', 'stdout': 'ruby', 'cmd': '/bin/bash -lc "asdf plugin-list | grep ruby"', 'rc': 0, 'start': '2019-01-26 10:42:36.674040', 'stderr': '', 'delta': '0:00:00.584345', 'invocation': {'module_args': {'creates': None, 'executable': None, '_uses_shell': True, '_raw_params': '/bin/bash -lc "asdf plugin-list | grep ruby"', 'removes': None, 'argv': None, 'warn': True, 'chdir': None, 'stdin': None}}, '_ansible_parsed': True, 'stdout_lines': ['ruby'], 'stderr_lines': [], '_ansible_no_log': False, 'failed': False, 'item': 'ruby', '_ansible_item_result': True, '_ansible_ignore_errors': True, '_ansible_item_label': 'ruby'})
skipping: [127.0.0.1] => (item={'changed': False, 'end': '2019-01-26 10:42:38.121094', 'stdout': 'golang', 'cmd': '/bin/bash -lc "asdf plugin-list | grep golang"', 'rc': 0, 'start': '2019-01-26 10:42:37.541819', 'stderr': '', 'delta': '0:00:00.579275', 'invocation': {'module_args': {'creates': None, 'executable': None, '_uses_shell': True, '_raw_params': '/bin/bash -lc "asdf plugin-list | grep golang"', 'removes': None, 'argv': None, 'warn': True, 'chdir': None, 'stdin': None}}, '_ansible_parsed': True, 'stdout_lines': ['golang'], 'stderr_lines': [], '_ansible_no_log': False, 'failed': False, 'item': 'golang', '_ansible_item_result': True, '_ansible_ignore_errors': True, '_ansible_item_label': 'golang'})
ok: [127.0.0.1] => (item={'changed': False, 'end': '2019-01-26 10:42:38.981170', 'stdout': '', 'cmd': '/bin/bash -lc "asdf plugin-list | grep java"', 'failed': True, 'delta': '0:00:00.574073', 'stderr': '', 'rc': 1, 'invocation': {'module_args': {'creates': None, 'executable': None, '_uses_shell': True, '_raw_params': '/bin/bash -lc "asdf plugin-list | grep java"', 'removes': None, 'argv': None, 'warn': True, 'chdir': None, 'stdin': None}}, 'start': '2019-01-26 10:42:38.407097', 'msg': 'non-zero return code', '_ansible_parsed': True, 'stdout_lines': [], 'stderr_lines': [], '_ansible_no_log': False, 'item': 'java', '_ansible_item_result': True, '_ansible_item_label': 'java'}) => {
    "msg": "java is not found"
}

python, ruby, golangだと1個目のplaybookで実行され、javaだと1個目はスキップし2個目で実行されていることがわかります
やったね!

まとめ

今回利用したplaybookは下記になりますので、ご利用ください

- name: Get installed plugin list
  shell: /bin/bash -lc "asdf plugin-list | grep {{ item }}"
  register: result
  with_items:
    - python
    - ruby
    - golang
    - java
  ignore_errors: yes
  changed_when: no

- name: View result
  debug: 
    var: result

- name: If listed items
  debug: 
    msg: "{{ item.item }} is found"
  with_items: '{{ result.results }}'
  when: not item.failed

- name: If not listed items
  debug: 
    msg: "{{ item.item }} is not found"
  with_items: '{{ result.results }}'
  when: item.failed

参考

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1