1

I would need help to filter hosts with specific previous result, to be able to use add_host module. It seems add_host is ignoring the "when" condition, so probably I need to make a loop for the required hosts.

- name: Get chrome process ansible.windows.win_powershell: script: | (get-process chrome -ErrorAction SilentlyContinue).count -gt 0 register: ps_chrome_running 

Now I would need to filter for hosts where the ps_chrome_running.output[0] is true and put those hosts into a new group.

- name: Put on skip list ansible.builtin.add_host: name: '{{ item }}' groups: 'skip_chrome_actions' loop: "{{ hostvars|dict2items| selectattr('ps_chrome_running.output[0]', '==', true)| map(attribute='key') }}" delegate_to: localhost run_once: true 

I've tried already different methods, but somehow cannot get the clue of it. Could someone help with the loop filter to get only the list of hosts where ps_chrome_running.output[0] == true?

+1: ps_chrome_running.output[0] is bool already

register looks like this:

changed: [server1] => { "changed": true, "debug": [], "error": [], "host_err": "", "host_out": "", "information": [], "invocation": { "module_args": { "arguments": null, "chdir": null, "creates": null, "depth": 2, "error_action": "continue", "executable": null, "parameters": null, "removes": null, "script": "(get-process chrome -ErrorAction SilentlyContinue).count -eq 0\n", "sensitive_parameters": null } }, "output": [ true ], "result": {}, "verbose": [], "warning": [] } 

UPDATE: This playbook:

- name: "Get Chrome processes" hosts: all gather_facts: no tasks: - name: Get chrome process ansible.windows.win_powershell: script: | (get-process chrome -ErrorAction SilentlyContinue).count -gt 0 register: ps_chrome_running # failed_when: ps_chrome_running.output[0] - name: Check vars1 ansible.builtin.debug: msg: "item : {{ item }}" loop: "{{ hostvars | dict2items | json_query('[?value.ps_chrome_running.output[0]].key') }}" delegate_to: localhost run_once: true ignore_errors: true - name: Add host candidate ansible.builtin.debug: msg: "host: {{ item }}" loop: "{{ hostvars | dict2items | json_query('[?value.ps_chrome_running.output[0]].key') }}" delegate_to: localhost run_once: true ignore_errors: true - name: Put on skip list ansible.builtin.add_host: name: '{{ item }}' groups: 'skip_chrome_update' loop: "{{ hostvars | dict2items | json_query('[?value.ps_chrome_running.output[0]].key') }}" delegate_to: localhost run_once: true - debug: var: groups.skip_chrome_actions delegate_to: localhost run_once: true - name: Update Chrome hosts: '!skip_chrome_update' gather_facts: no tasks: - name: More task ansible.builtin.debug: msg: "should run on prev success" - name: More task2 ansible.windows.win_powershell: script: | write-output $env:computername 

Has this output:

PLAY [Get Chrome processes] **************************************************** TASK [Get chrome process] ****************************************************** changed: [Windows1] => {"changed": true, "debug": [], "error": [], "host_err": "", "host_out": "", "information": [], "output": [false], "result": {}, "verbose": [], "warning": []} changed: [Windows2] => {"changed": true, "debug": [], "error": [], "host_err": "", "host_out": "", "information": [], "output": [false], "result": {}, "verbose": [], "warning": []} TASK [Check vars1] ************************************************************* skipping: [Windows1] => {"skipped_reason": "No items in the list"} TASK [Add host candidate] ****************************************************** skipping: [Windows1] => {"skipped_reason": "No items in the list"} TASK [Put on skip list] ******************************************************** skipping: [Windows1] => {"changed": false, "skipped_reason": "No items in the list"} TASK [debug] ******************************************************************* ok: [Windows1 -> localhost] => { "groups.skip_chrome_actions": "VARIABLE IS NOT DEFINED!: 'dict object' has no attribute 'skip_chrome_actions'. 'dict object' has no attribute 'skip_chrome_actions'" } [WARNING]: Could not match supplied host pattern, ignoring: skip_chrome_update PLAY [Update Chrome] *********************************************************** TASK [More task] *************************************************************** ok: [Windows1] => { "msg": "should run on prev success" } ok: [Windows2] => { "msg": "should run on prev success" } TASK [More task2] ************************************************************** changed: [Windows1] => {"changed": true, "debug": [], "error": [], "host_err": "", "host_out": "", "information": [], "output": ["SM835222"], "result": {}, "verbose": [], "warning": []} changed: [Windows2] => {"changed": true, "debug": [], "error": [], "host_err": "", "host_out": "", "information": [], "output": ["SM834069"], "result": {}, "verbose": [], "warning": []} PLAY RECAP ********************************************************************* Windows2 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Windows1 : ok=5 changed=2 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0 

2 Answers 2

1

add_host respects a when condition. ansible-doc add_host lists it as ignore_conditional none, which is a weird double negative way to say when works.

Possibly your expression is a string type, that would need to be parsed into a boolean type. As a non-empty string is a true value, which is not what was intended if the string is "False". In Ansible Jinja, the bool filter will be true if the value (lower case) is in: True, 'yes', 'on', '1', 'true', 1. And false otherwise.

- name: Get chrome process ansible.windows.win_powershell: script: | (get-process chrome -ErrorAction SilentlyContinue).count -gt 0 register: ps_chrome_running - name: Put on skip list when: "{{ ps_chrome_running.output[0] | bool | default(False) }}" ansible.builtin.add_host: name: "{{ inventory_hostname }}" groups: "skip_chrome_actions" 

In addition I have added a default of false for the when, in case the expression is ever not defined. Could be considered optional, certainly not every Ansible expression needs to be guarded this way.

After your unmodified get-process task, the add_host can be done in the host loop. As we are adding this host, the magic variable inventory_hostname is its name. (add_host is an action plugin with no module code, those always run on localhost)

Using this in-memory group, the easiest to understand is to start a new play targeting skip_chrome_actions with a pattern.

As usual with inventory, you can also get a little clever. inventory_hostnames lookup will return a list of host matching some pattern. Or could make us of the magic variable groups, and if a hostname is in groups.skip_chrome_actions.

3
  • Hi John, I've checked the output[0] already and ansible interprets it as a BOOL. Commented Feb 19 at 8:52
  • If I set the WHEN:false, the add_host will still run, so it ignores the when parameter Commented Feb 19 at 9:03
  • add_host with when: false is skipped, and no such host is added to the group. I tested on ansible-core 2.16.11. As I mentioned in my answer, be careful about the distinction between an expression returning a string False (from the command output), and an actual boolean value (such as parsing YAML). ansible-doc -t filter type_debug for a filter that will tell you the Python type of the input. Commented Feb 23 at 18:15
1

This selection is wrong

loop: "{{ hostvars | dict2items | selectattr('ps_chrome_running.output[0]', '==', true) | map(attribute='key') }}" 

Because of the dict2items filter, you have to reference value.ps_chrome_running

loop: "{{ hostvars | dict2items | selectattr('value.ps_chrome_running.output[0]', '==', true) | map(attribute='key') }}" 

You can simplify the selection. If the variable is boolean the comparison isn't needed

loop: "{{ hostvars | dict2items | selectattr('value.ps_chrome_running.output[0]') | map(attribute='key') }}" 

Use json_query instead of selectattr. The filter selectattr will crash if the variable ps_chrome_running is undefined. This might be the case when localhost is in the hostvars. The filter json_query silently ignores missing variables. The below loop is the best option

loop: "{{ hostvars | dict2items | json_query('[?value.ps_chrome_running.output[0]].key') }}" 

Example of a complete playbook for testing

shell> cat pb.yml - hosts: all tasks: - debug: var: ps_chrome_running.output.0 - add_host: name: "{{ item }}" groups: skip_chrome_actions loop: "{{ hostvars | dict2items | json_query('[?value.ps_chrome_running.output[0]].key') }}" run_once: true - debug: var: groups.skip_chrome_actions run_once: true 

gives

shell> ansible-playbook pb.yml -i hosts PLAY [all] ********************************************************************************************************** TASK [debug] ******************************************************************************************************** ok: [test_01] => ps_chrome_running.output.0: true ok: [test_02] => ps_chrome_running.output.0: true ok: [test_03] => ps_chrome_running.output.0: false TASK [add_host] ***************************************************************************************************** changed: [test_01] => (item=test_01) changed: [test_01] => (item=test_02) TASK [debug] ******************************************************************************************************** ok: [test_01] => groups.skip_chrome_actions: - test_01 - test_02 PLAY RECAP ********************************************************************************************************** test_01: ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 test_02: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 test_03: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 

Given the tree

shell> tree . . ├── ansible.cfg ├── hosts ├── host_vars │   ├── test_01.yml │   ├── test_02.yml │   └── test_03.yml └── pb.yml 
shell> cat ansible.cfg [defaults] gathering = explicit inventory = $PWD/hosts callback_result_format = yaml [connection] pipelining = true 
shell> cat hosts test_01 test_02 test_03 
shell> cat host_vars/test_01.yml ps_chrome_running: output: - true shell> cat host_vars/test_02.yml ps_chrome_running: output: - true shell> cat host_vars/test_03.yml ps_chrome_running: output: - false 
2
  • Hi Vladimir, thank you for the super description, however it seems the output is a bit different. Commented Feb 19 at 8:50
  • I added the complete mre. Commented Feb 19 at 11:18

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.