目的
現在インストール済みのパッケージを確認し、有無によって実行処理を分けたい場合があると思うので、それをやってみたいと思います
今回は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