Ansible extract sub-string from a matched element of a List variable - ansible

I have a variable, which is a list as below:
"test_list": [
"some text here",
"server1",
"command1 parameter1",
"path/to/command2 parameter2 server1_202012",
"some more text",
"New backup file is server1_202019"
]
I am trying to extract the substring server1_202019 which is at the end of the line that starts with New backup file.... There is only one line like this and I've tried below option to get the substring.
- set_fact:
test_name: "{{ test_list | select('^New backup file is (.+)$','\\1') }}"
and the output I've received is:
"test_name": "<generator object _select_or_reject at 0x3fe5b40>"
I've tried below code also, but failed.
- set_fact:
test_name: "{{ test_list | regex_search('^New backup file is (.+)$','\\1') }}"
The error is:
"msg": "Unexpected templating type error occurred on ({{ test_list | regex_search('^New backup file is (.+)$','\\\\1') }}): ..... expected string or buffer"
Could somebody please suggest how I can get the output as below:
"test_name": "server1_202019"
The ansible version I'm using is 2.9
Thanks

Select the item from the list and then use regex_replace. For example
- set_fact:
test_name: "{{ test_list|
select('regex', my_regex)|
first|
regex_replace(my_regex, my_replace) }}"
vars:
my_regex: '^New backup file is (.*)$'
my_replace: '\1'
- debug:
var: test_name
give
"test_name": "server1_202019"

Since test_list is a list, you need to loop through the items to be matched using regex. Something like below can be done.
- set_fact:
matched: "{{ item | regex_search('^New backup file is (.+)$','\\1') }}"
loop: "{{ test_list }}"
register: matching_items
- debug:
var: item.ansible_facts.matched
with_items: "{{ matching_items.results }}"
when: item.ansible_facts.matched != ""
Should output like below for debug:
TASK [debug] *******************************************************************************************************************************
skipping: [localhost] => (item={'changed': False, 'ansible_facts': {'matched': ''}, 'failed': False, 'item': 'some text here', 'ansible_loop_var': 'item'})
skipping: [localhost] => (item={'changed': False, 'ansible_facts': {'matched': ''}, 'failed': False, 'item': 'server1', 'ansible_loop_var': 'item'})
skipping: [localhost] => (item={'changed': False, 'ansible_facts': {'matched': ''}, 'failed': False, 'item': 'command1 parameter1', 'ansible_loop_var': 'item'})
skipping: [localhost] => (item={'changed': False, 'ansible_facts': {'matched': ''}, 'failed': False, 'item': 'path/to/command2 parameter2 server1_202012', 'ansible_loop_var': 'item'})
ok: [localhost] => (item={'changed': False, 'ansible_facts': {'matched': ['server1_202019']}, 'failed': False, 'item': 'New backup file is server1_202019', 'ansible_loop_var': 'item'}) => {
"ansible_loop_var": "item",
"item": {
"ansible_facts": {
"matched": [
"server1_202019"
]
},
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"item": "New backup file is server1_202019"
},
"item.ansible_facts.matched": [
"server1_202019"
]
}
skipping: [localhost] => (item={'changed': False, 'ansible_facts': {'matched': ''}, 'failed': False, 'item': 'some more text', 'ansible_loop_var': 'item'})

Related

ansible: "variable is not defined" even with ignore_erros: True & failed_when: 0 > 1 | How to define variable when task is failed/ignored/skipped?

Trying to get a variable defined when the task is partially failed/ignored. When a VM is not found in Vsphere it throws an error: "msg": "Unable to gather information for non-existing VM vm2"
I tried with and without ignore_errors: True and failed_when: 0 > 1 but no change.
I need the variable vm_fact to be defined even when a non-existing VM is in the decom_list. The plan is to change the list after i have identified which VM's are non-existing.
Please note: this task does work when all vm's are present in the system. When one is missing the task fails. I need the task not to fail so that i can clean the decom_list and then run it again.
- name: check/power(on/off) hosts on vsphere
hosts: localhost
ignore_errors: True
vars:
decom_list:
- vm1
- vm2
- vm3
tasks:
- name: check hosts on vsphere
vmware_guest_info:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
name: "{{ item }}"
schema: vsphere
datacenter: DC1
loop: "{{ decom_list }}"
register: vm_fact
ignore_errors: True
failed_when: 0 > 1
Whatever i try does not work because my vm_fact is not defined.
- debug:
var: "{{ vm_fact }}"
error:
TASK [debug] **************************************************************************************************************************
ok: [localhost] => {
"<class 'dict'>": "VARIABLE IS NOT DEFINED!"
}
Just to confirm i did try all i know.
When i try it with a loop:
- debug:
var: "{{ item['item'] }}"
loop: "{{ vm_fact['results'] }}"
when: '"Unable to gather information for non-existing VM" in item.msg'
I get error:
ok: [localhost] => (item={'failed': False, 'msg': 'Unable to gather information for non-existing VM vm2', 'invocation': {'module_args': {'hostname': 'hostname.domain', 'username': 'username', 'password': 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER', 'name': 'vm2', 'schema': 'vsphere', 'datacenter': 'DC1', 'port': 443, 'validate_certs': True, 'name_match': 'first', 'use_instance_uuid': False, 'tags': False, 'tag_details': False, 'proxy_host': None, 'proxy_port': None, 'uuid': None, 'moid': None, 'folder': None, 'properties': None}}, 'changed': False, 'failed_when_result': False, 'item': 'vm2', 'ansible_loop_var': 'item'}) => {
"ansible_loop_var": "item",
"item": {
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"failed_when_result": false,
"invocation": {
"module_args": {
"datacenter": "DC1",
"folder": null,
"hostname": "hostname.domain",
"moid": null,
"name": "vm2",
"name_match": "first",
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"port": 443,
"properties": null,
"proxy_host": null,
"proxy_port": null,
"schema": "vsphere",
"tag_details": false,
"tags": false,
"use_instance_uuid": false,
"username": "username",
"uuid": null,
"validate_certs": true
}
},
"item": "vm2",
"msg": "Unable to gather information for non-existing VM vm2"
},
"vm2": "VARIABLE IS NOT DEFINED!"
}
ok: [localhost] => (item={'failed': False, 'msg': 'Unable to gather information for non-existing VM vm3', 'invocation': {'module_args': {'hostname': 'hostname.domain', 'username': 'username', 'password': 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER', 'name': 'vm3', 'schema': 'vsphere', 'datacenter': 'DC1', 'port': 443, 'validate_certs': True, 'name_match': 'first', 'use_instance_uuid': False, 'tags': False, 'tag_details': False, 'proxy_host': None, 'proxy_port': None, 'uuid': None, 'moid': None, 'folder': None, 'properties': None}}, 'changed': False, 'failed_when_result': False, 'item': 'vm3', 'ansible_loop_var': 'item'}) => {
"ansible_loop_var": "item",
"item": {
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"failed_when_result": false,
"invocation": {
"module_args": {
"datacenter": "DC1",
"folder": null,
"hostname": "hostname.domain",
"moid": null,
"name": "vm3",
"name_match": "first",
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"port": 443,
"properties": null,
"proxy_host": null,
"proxy_port": null,
"schema": "vsphere",
"tag_details": false,
"tags": false,
"use_instance_uuid": false,
"username": "username",
"uuid": null,
"validate_certs": true
}
},
"item": "vm3",
"msg": "Unable to gather information for non-existing VM vm3"
},
"vm3": "VARIABLE IS NOT DEFINED!"
}
fatal: [localhost]: FAILED! => {"msg": "The conditional check '\"Unable to gather information for non-existing VM\" in item.msg' failed. The error was: error while evaluating conditional (\"Unable to gather information for non-existing VM\" in item.msg): 'dict object' has no attribute 'msg'\n\nThe error appears to be in 'location': line 33, column 24, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n # - debug: var=vm_fact\n ^ here\n\nThere appears to be both 'k=v' shorthand syntax and YAML in this task. Only one syntax may be used.\n"}
Tried:
- debug:
msg: "{{ vm_fact['results']|json_query('msg') }}"
- debug:
msg: "{{ vm_fact['results']|to_json|from_json|map(attribute='msg') }}"
- debug:
msg: "{{ vm_fact['results']|map(attribute='msg') }}"
- debug:
msg: "{{ vm_fact['results']|dict2items|map(attribute='msg') }}"
- debug:
msg: "{{ vm_fact['results']|flatten|map(attribute='msg') }}"
error:
TASK [debug] **************************************************************************************************************************
ok: [localhost] => {
"msg": ""
}
TASK [debug] **************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'msg'\n\nThe error appears to be in 'location': line 42, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - debug:\n ^ here\n"}
...ignoring
TASK [debug] **************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'msg'\n\nThe error appears to be in 'location': line 45, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - debug:\n ^ here\n"}
...ignoring
TASK [debug] **************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "Unexpected templating type error occurred on ({{ vm_fact['results']|dict2items|map(attribute='msg') }}): dict2items requires a dictionary, got <class 'list'> instead."}
...ignoring
TASK [debug] **************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'msg'\n\nThe error appears to be in 'lcoation': line 51, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - debug:\n ^ here\n"}
...ignoring
You are, frankly, making things very difficult for yourself. Ansible loops through hosts, use it.
decom.inv:
[decom]
vm1
vm2
vm3
decom.yml:
- name: check/power(on/off) hosts on vsphere
hosts: decom
gather_facts: no
tasks:
- name: check hosts on vsphere
vmware_guest_info:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
name: "{{ ansible_hostname }}"
schema: vsphere
datacenter: DC1
register: vm_fact
ignore_errors: True
failed_when: false
delegate_to: localhost
- name: Show results
debug:
var: vm_fact

ansible with_sequence result message hide

I want to hide the result message of with_sequence:
My task playbook :
- name: Alarm check
debug: msg="Alarm check"
when: '"{{ item }} alarms currently active" in HOST_MGMT1.stdout'
register: result_alarm
with_sequence: start=0 end=10
result output message:
##########_QFX10K_##########
Current time: 2020-03-13 11:34:58 KST
{All items completed', 'changed': False, 'results': [{'item': u'0', 'skipped': True, 'ansible_loop_var': u'item', 'changed': False, 'skip_reason': u'Conditional result was False'}, {'item': u'1', 'skipped': True, 'ansible_loop_var': u'item', 'changed': False, 'skip_reason': u'Conditional result was False'}, {'item': u'2', 'skipped': True, 'ansible_loop_var': u'item', 'changed': False, 'skip_reason': u'Conditional result was False'}, {Alarm check', 'item': u'3', 'ansible_loop_var': u'item', 'changed': False, 'failed': False}, {'item': u'4', 'skipped': True, 'ansible_loop_var': u'item', 'changed': False, 'skip_reason': u'Conditional result was False'}, {'item': u'5', 'skipped': True, 'ansible_loop_var': u'item', 'changed': False, 'skip_reason': u'Conditional result was False'}, {'item': u'6', 'skipped': True, 'ansible_loop_var': u'item', 'changed': False, 'skip_reason': u'Conditional result was False'}, {'item': u'7', 'skipped': True, 'ansible_loop_var': u'item', 'changed': False, 'skip_reason': u'Conditional result was False'}, {'item': u'8', 'skipped': True, 'ansible_loop_var': u'item', 'changed': False, 'skip_reason': u'Conditional result was False'}, {'item': u'9', 'skipped': True, 'ansible_loop_var': u'item', 'changed': False, 'skip_reason': u'Conditional result was False'}, {'item': u'10', 'skipped': True, 'ansible_loop_var': u'item', 'changed': False, 'skip_reason': u'Conditional result was False'}]}
Try skippy callback plugin. For example the playbook
shell> cat playbook.yml
- hosts: localhost
vars:
HOST_MGMT1:
stdout: "3 alarms currently active"
tasks:
- name: Alarm check
debug: msg="Alarm check"
when: "my_item in HOST_MGMT1.stdout"
register: result_alarm
with_sequence: start=0 end=10
vars:
my_item: "{{ item }} alarms currently active"
gives (abbridged)
shell> export ANSIBLE_STDOUT_CALLBACK=skippy
shell> ansible-playbook playbook.yml
PLAY [localhost] ***
TASK [Alarm check] ***
ok: [localhost] => (item=3) => {
"msg": "Alarm check"
}
PLAY RECAP ***
localhost: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

could not find job trying to async and poll tasks

I try to do :
Get a list of docker containers
Shutdown this list (with async values to go to next task without waiting for the end).
Waiting for shutdown
I did this :
- name: "get containers"
become: yes
shell: docker ps -a | grep -v NAMES | awk '{print $NF}'
register: efluidnet_tp_containers_list
delegate_to: myserver
- name: "shutdown containers"
async: 3600
poll: 0
become: yes
docker_container:
name: "{{ item }}"
state: stopped
with_items:
- "{{ efluidnet_tp_containers_list.stdout_lines }}"
register: restart_aelnet
delegate_to: myserver
- debug:
msg: "{{ item['ansible_job_id'] }}"
with_items: "{{ restart_aelnet['results'] }}"
- name: 'waiting for shutdown'
async_status:
jid: "{{ item['ansible_job_id'] }}"
register: job_result
until: job_result.finished
retries: 30
with_items: "{{ restart_aelnet['results'] }}"
delegate_to: myserver
But my waiting task is unable to find the ansible_jod id :
TASK [get containers] *******************************************************************************************************************************************
Thursday 05 December 2019 08:17:55 +0100 (0:00:00.285) 0:00:00.366 *****
changed: [localhost -> None]
TASK [shutdown containers] **************************************************************************************************************************************
Thursday 05 December 2019 08:17:56 +0100 (0:00:00.937) 0:00:01.303 *****
changed: [localhost -> None] => (item=ael-13.20.200-PREPRO-AMN_V13)
changed: [localhost -> None] => (item=ael-13.20.200-PREPRO-SCH_V13)
changed: [localhost -> None] => (item=ael-13.20.200-PREPRO-SAR_V13)
changed: [localhost -> None] => (item=ael-13.20.200-PREPRO-ROM_V13)
changed: [localhost -> None] => (item=ael-13.20.200-PREPRO-SAL_V13)
TASK [debug] *****************************************************************************************************************************************************
Thursday 05 December 2019 08:18:00 +0100 (0:00:03.320) 0:00:04.624 *****
ok: [localhost] => (item={'ansible_loop_var': u'item', u'ansible_job_id': u'264488569945.120415', 'failed': False, u'started': 1, 'changed': True, 'item': u'ael-13.20.200-PREPRO-AMN_V13', u'finished': 0, u'results_file': u'/root/.ansible_async/264488569945.120415'}) => {
"msg": "264488569945.120415"
}
ok: [localhost] => (item={'ansible_loop_var': u'item', u'ansible_job_id': u'828045810515.120527', 'failed': False, u'started': 1, 'changed': True, 'item': u'ael-13.20.200-PREPRO-SCH_V13', u'finished': 0, u'results_file': u'/root/.ansible_async/828045810515.120527'}) => {
"msg": "828045810515.120527"
}
ok: [localhost] => (item={'ansible_loop_var': u'item', u'ansible_job_id': u'406259878781.120644', 'failed': False, u'started': 1, 'changed': True, 'item': u'ael-13.20.200-PREPRO-SAR_V13', u'finished': 0, u'results_file': u'/root/.ansible_async/406259878781.120644'}) => {
"msg": "406259878781.120644"
}
ok: [localhost] => (item={'ansible_loop_var': u'item', u'ansible_job_id': u'803234566504.120755', 'failed': False, u'started': 1, 'changed': True, 'item': u'ael-13.20.200-PREPRO-ROM_V13', u'finished': 0, u'results_file': u'/root/.ansible_async/803234566504.120755'}) => {
"msg": "803234566504.120755"
}
ok: [localhost] => (item={'ansible_loop_var': u'item', u'ansible_job_id': u'966123972732.120860', 'failed': False, u'started': 1, 'changed': True, 'item': u'ael-13.20.200-PREPRO-SAL_V13', u'finished': 0, u'results_file': u'/root/.ansible_async/966123972732.120860'}) => {
"msg": "966123972732.120860"
}
TASK [waiting for shutdown] **************************************************************************************************************************************
Thursday 05 December 2019 08:18:00 +0100 (0:00:00.085) 0:00:04.710 *****
failed: [localhost -> None] (item={'ansible_loop_var': u'item', u'ansible_job_id': u'264488569945.120415', 'failed': False, u'started': 1, 'changed': True, 'item': u'ael-13.20.200-PREPRO-AMN_V13', u'finished': 0, u'results_file': u'/root/.ansible_async/264488569945.120415'}) => {"ansible_job_id": "264488569945.120415", "ansible_loop_var": "item", "attempts": 1, "changed": false, "finished": 1, "item": {"ansible_job_id": "264488569945.120415", "ansible_loop_var": "item", "changed": true, "failed": false, "finished": 0, "item": "ael-13.20.200-PREPRO-AMN_V13", "results_file": "/root/.ansible_async/264488569945.120415", "started": 1}, "msg": "could not find job", "started": 1}
failed: [localhost -> None] (item={'ansible_loop_var': u'item', u'ansible_job_id': u'828045810515.120527', 'failed': False, u'started': 1, 'changed': True, 'item': u'ael-13.20.200-PREPRO-SCH_V13', u'finished': 0, u'results_file': u'/root/.ansible_async/828045810515.120527'}) => {"ansible_job_id": "828045810515.120527", "ansible_loop_var": "item", "attempts": 1, "changed": false, "finished": 1, "item": {"ansible_job_id": "828045810515.120527", "ansible_loop_var": "item", "changed": true, "failed": false, "finished": 0, "item": "ael-13.20.200-PREPRO-SCH_V13", "results_file": "/root/.ansible_async/828045810515.120527", "started": 1}, "msg": "could not find job", "started": 1}
failed: [localhost -> None] (item={'ansible_loop_var': u'item', u'ansible_job_id': u'406259878781.120644', 'failed': False, u'started': 1, 'changed': True, 'item': u'ael-13.20.200-PREPRO-SAR_V13', u'finished': 0, u'results_file': u'/root/.ansible_async/406259878781.120644'}) => {"ansible_job_id": "406259878781.120644", "ansible_loop_var": "item", "attempts": 1, "changed": false, "finished": 1, "item": {"ansible_job_id": "406259878781.120644", "ansible_loop_var": "item", "changed": true, "failed": false, "finished": 0, "item": "ael-13.20.200-PREPRO-SAR_V13", "results_file": "/root/.ansible_async/406259878781.120644", "started": 1}, "msg": "could not find job", "started": 1}
failed: [localhost -> None] (item={'ansible_loop_var': u'item', u'ansible_job_id': u'803234566504.120755', 'failed': False, u'started': 1, 'changed': True, 'item': u'ael-13.20.200-PREPRO-ROM_V13', u'finished': 0, u'results_file': u'/root/.ansible_async/803234566504.120755'}) => {"ansible_job_id": "803234566504.120755", "ansible_loop_var": "item", "attempts": 1, "changed": false, "finished": 1, "item": {"ansible_job_id": "803234566504.120755", "ansible_loop_var": "item", "changed": true, "failed": false, "finished": 0, "item": "ael-13.20.200-PREPRO-ROM_V13", "results_file": "/root/.ansible_async/803234566504.120755", "started": 1}, "msg": "could not find job", "started": 1}
failed: [localhost -> None] (item={'ansible_loop_var': u'item', u'ansible_job_id': u'966123972732.120860', 'failed': False, u'started': 1, 'changed': True, 'item': u'ael-13.20.200-PREPRO-SAL_V13', u'finished': 0, u'results_file': u'/root/.ansible_async/966123972732.120860'}) => {"ansible_job_id": "966123972732.120860", "ansible_loop_var": "item", "attempts": 1, "changed": false, "finished": 1, "item": {"ansible_job_id": "966123972732.120860", "ansible_loop_var": "item", "changed": true, "failed": false, "finished": 0, "item": "ael-13.20.200-PREPRO-SAL_V13", "results_file": "/root/.ansible_async/966123972732.120860", "started": 1}, "msg": "could not find job", "started": 1}
PLAY RECAP *******************************************************************************************************************************************************
localhost : ok=4 changed=2 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
I managed to run this mechanism with a simple example like this:
- name: 'waiting for a long tasks'
shell: /bin/sleep 15
async: 1000
poll: 0
register: yum_sleeper
delegate_to: myserver
- debug:
msg: "{{ yum_sleeper }}"
delegate_to: myserver
- name: 'get results'
async_status:
jid: "{{ yum_sleeper.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 30
delegate_to: myserver
But in my real use case i have a "results" properties that can be problematic ...
Can somebody help me ?
Thanks you
I think the issue is on become. To check the async_status the user needs to be the same as the one who ran the async job.
- name: 'waiting for shutdown'
become: yes
async_status:
jid: "{{ item['ansible_job_id'] }}"
register: job_result
until: job_result.finished
retries: 30
with_items: "{{ restart_aelnet['results'] }}"
delegate_to: myserver

ansible output multiple variables to same line

I'm collecting the SQL version and edition found in registry using win_reg_stat, registering these into a variable, and writing them to a file.
Is it possible to write the values to the same line instead of separate lines?
- name: get sql version
win_reg_stat:
path: HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\{{ item }}\Setup
name: Version
with_items: "{{ sql_versions }}"
register: sql_version
- name: get sql edition
win_reg_stat:
path: HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\{{ item }}\Setup
name: Edition
with_items: "{{ sql_versions }}"
register: sql_edition
- lineinfile:
dest: /tmp/sql
line: "{{ inventory_hostname }};{{ item.value }}"
when: item.exists
with_items:
- "{{ sql_version.results }}"
delegate_to: localhost
- lineinfile:
dest: /tmp/sql
line: "{{ inventory_hostname }};{{ item.value }}"
when: item.exists
with_items:
- "{{ sql_edition.results }}"
delegate_to: localhost
The sql_versions variable contains multiple items:
sql_versions:
- MSSQL15.MSSQLSERVER
- MSSQL14.MSSQLSERVER
- MSSQL13.MSSQLSERVER
- MSSQL12.MSSQLSERVER
- MSSQL11.MSSQLSERVER
- MSSQL10_50.MSSQLSERVER
- MSSQL10.MSSQLSERVER
- MSSQL.1
Output example:
TASK [licensing : register sql version] *****************************************************************************************************************************************************************************************************
skipping: [win2019] => (item={'changed': False, 'exists': False, 'failed': False, 'item': 'MSSQL15.MSSQLSERVER', 'ansible_loop_var': 'item'})
skipping: [win2019] => (item={'changed': False, 'exists': False, 'failed': False, 'item': 'MSSQL14.MSSQLSERVER', 'ansible_loop_var': 'item'})
ok: [win2019] => (item={'changed': False, 'type': 'REG_SZ', 'raw_value': '13.2.5026.0', 'value': '13.2.5026.0', 'exists': True, 'failed': False, 'item': 'MSSQL13.MSSQLSERVER', 'ansible_loop_var': 'item'}) => {
"msg": "13.2.5026.0"
}
skipping: [win2019] => (item={'changed': False, 'exists': False, 'failed': False, 'item': 'MSSQL12.MSSQLSERVER', 'ansible_loop_var': 'item'})
skipping: [win2019] => (item={'changed': False, 'exists': False, 'failed': False, 'item': 'MSSQL11.MSSQLSERVER', 'ansible_loop_var': 'item'})
skipping: [win2019] => (item={'changed': False, 'exists': False, 'failed': False, 'item': 'MSSQL10_50.MSSQLSERVER', 'ansible_loop_var': 'item'})
skipping: [win2019] => (item={'changed': False, 'exists': False, 'failed': False, 'item': 'MSSQL10.MSSQLSERVER', 'ansible_loop_var': 'item'})
skipping: [win2019] => (item={'changed': False, 'exists': False, 'failed': False, 'item': 'MSSQL.1', 'ansible_loop_var': 'item'})
TASK [licensing : register sql edition] *****************************************************************************************************************************************************************************************************
skipping: [win2019] => (item={'changed': False, 'exists': False, 'failed': False, 'item': 'MSSQL15.MSSQLSERVER', 'ansible_loop_var': 'item'})
skipping: [win2019] => (item={'changed': False, 'exists': False, 'failed': False, 'item': 'MSSQL14.MSSQLSERVER', 'ansible_loop_var': 'item'})
ok: [win2019] => (item={'changed': False, 'type': 'REG_SZ', 'raw_value': 'Web Edition', 'value': 'Web Edition', 'exists': True, 'failed': False, 'item': 'MSSQL13.MSSQLSERVER', 'ansible_loop_var': 'item'}) => {
"msg": "Web Edition"
}
skipping: [win2019] => (item={'changed': False, 'exists': False, 'failed': False, 'item': 'MSSQL12.MSSQLSERVER', 'ansible_loop_var': 'item'})
skipping: [win2019] => (item={'changed': False, 'exists': False, 'failed': False, 'item': 'MSSQL11.MSSQLSERVER', 'ansible_loop_var': 'item'})
skipping: [win2019] => (item={'changed': False, 'exists': False, 'failed': False, 'item': 'MSSQL10_50.MSSQLSERVER', 'ansible_loop_var': 'item'})
skipping: [win2019] => (item={'changed': False, 'exists': False, 'failed': False, 'item': 'MSSQL10.MSSQLSERVER', 'ansible_loop_var': 'item'})
skipping: [win2019] => (item={'changed': False, 'exists': False, 'failed': False, 'item': 'MSSQL.1', 'ansible_loop_var': 'item'})
did you tried this..
- lineinfile:
dest: /tmp/sql
line: "{{ inventory_hostname }};{{ item.value }}"
when: item.exists
with_items:
- "{{ sql_version.results }}"
- "{{ sql_edition.results }}"
delegate_to: localhost
Please try as below (not tested)
- lineinfile:
dest: /tmp/sql
line: "{{ inventory_hostname }};{{ item.version.value }};{{ item.edition.value }}"
when: item.exists
with_items:
- "{ version: {{sql_version.results}}, edition: {{sql_edition.results}} }"
delegate_to: localhost

Ansible playbook to handle both Linux and Windows hosts

Trying to write one playbook that checks whether a set of files exist on a set of servers (both Linux and Windows hosts), and if they do, then to replace the files.
Here is what i have so far:
---
- hosts: "{{hosts}}"
vars:
scripts:
- check_blackout.pl
- check_empty.pl
tasks:
- name: windows stat
with_items: "{{scripts}}"
win_stat: path=D:\scripts\{{item}}
register: windows_stat
when: "'windows' in group_names"
- name: other stat
with_items: "{{scripts}}"
stat: path=/usr/local/bin/{{item}}
register: other_stat
remote_user: "{{script_owner | default(ansible_user)}}"
when: "'windows' not in group_names"
- name: windows debug
with_items: "{{windows_stat.results}}"
debug: var={{item.item}}
when: "{{item.stat.exists}}"
- name: other debug
with_items: "{{other_stat.results}}"
debug: var={{item.item}}
when: "{{item.stat.exists}}"
...
When I run this against a Windows and Linux host for testing, I get the following:
[ansible#vmhklftpscdv1 ~]$ ansible-playbook test.yml -e "hosts=vmhkge1jasdev01,jdeesbkup" --ask-vault-pass
Vault password:
PLAY [vmhkge1jasdev01,jdeesbkup] ************************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************************************
ok: [vmhkge1jasdev01]
ok: [jdeesbkup]
TASK [windows stat] *************************************************************************************************************************************************************
skipping: [jdeesbkup] => (item=check_blackout.pl)
skipping: [jdeesbkup] => (item=check_empty.pl)
ok: [vmhkge1jasdev01] => (item=check_blackout.pl)
ok: [vmhkge1jasdev01] => (item=check_empty.pl)
TASK [other stat] ***************************************************************************************************************************************************************
skipping: [vmhkge1jasdev01] => (item=check_empty.pl)
skipping: [vmhkge1jasdev01] => (item=check_blackout.pl)
ok: [jdeesbkup] => (item=check_blackout.pl)
ok: [jdeesbkup] => (item=check_empty.pl)
TASK [windows debug] ************************************************************************************************************************************************************
skipping: [vmhkge1jasdev01] => (item={'_ansible_parsed': True, u'stat': {u'exists': False}, '_ansible_item_result': True, '_ansible_no_log': False, u'changed': False, 'item': u'check_empty.pl', 'invocation': {'module_name': u'win_stat'}})
skipping: [vmhkge1jasdev01] => (item={'_ansible_parsed': True, u'stat': {u'exists': False}, '_ansible_item_result': True, '_ansible_no_log': False, u'changed': False, 'item': u'check_blackout.pl', 'invocation': {'module_name': u'win_stat'}})
fatal: [jdeesbkup]: FAILED! => {"failed": true, "msg": "The conditional check '{{item.stat.exists}}' failed. The error was: error while evaluating conditional ({{item.stat.exists}}): 'dict object' has no attribute 'stat'\n\nThe error appears to have been in '/home/ansible/test.yml': line 19, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n when: \"'windows' not in group_names\"\n - name: windows debug\n ^ here\n"}
TASK [other debug] **************************************************************************************************************************************************************
fatal: [vmhkge1jasdev01]: FAILED! => {"failed": true, "msg": "The conditional check '{{item.stat.exists}}' failed. The error was: error while evaluating conditional ({{item.stat.exists}}): 'dict object' has no attribute 'stat'\n\nThe error appears to have been in '/home/ansible/test.yml': line 23, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n when: \"{{item.stat.exists}}\"\n - name: other debug\n ^ here\n"}
to retry, use: --limit #/home/ansible/test.retry
PLAY RECAP **********************************************************************************************************************************************************************
jdeesbkup : ok=2 changed=0 unreachable=0 failed=1
vmhkge1jasdev01 : ok=2 changed=0 unreachable=0 failed=1
[ansible#vmhklftpscdv1 ~]$
Any ideas how I can get this working?
I've tried various combinations including checking the group membership before checking the results:
when: "'windows' in group_names and {{item.stat.exists}}"
However Ansible still seems to check the item.stat field even when the first part of the condition is false.
Or is my fundamental approach wrong, should I be splitting these tasks up into different playbooks?
Yes, you are right. with_items is evaluated before when. You can add a default empty list to avoid the error:
- name: other debug
with_items: "{{other_stat.results | default([]) }}"
debug: var={{item}}
when: "{{item.stat.exists | default(false)}}"
Got it working, here is successful playbook and output:
---
- hosts: "{{hosts}}"
vars:
scripts:
- run.pl
tasks:
- name: win_stat
with_items: scripts
win_stat: path="D:\scripts\{{item}}"
register: "win_result"
when: "'windows' in group_names"
- name: other_stat
with_items: scripts
stat: path="/usr/local/bin/{{item}}"
register: "other_result"
when: "'windows' not in group_names"
- debug: var=win_result
- debug: var=other_result
- with_items: "{{ win_result.results }}"
debug: msg="{{item.item}}"
when: "not (item.skipped | default(false))"
- with_items: "{{ other_result.results}}"
debug: msg="{{item.item}}"
when: "not (item.skipped | default(false))"
...
[ansible#vmhklftpscdv1 ~]$ ansible-playbook debug.yml -e "hosts=jdeesbkup,vmhkge1jasdev01" --ask-vault-pass
Vault password:
PLAY [jdeesbkup,vmhkge1jasdev01] **************************************************************************************************************************
TASK [Gathering Facts] ************************************************************************************************************************************
ok: [jdeesbkup]
ok: [vmhkge1jasdev01]
TASK [win_stat] *******************************************************************************************************************************************
skipping: [jdeesbkup] => (item=scripts)
ok: [vmhkge1jasdev01] => (item=scripts)
TASK [other_stat] *****************************************************************************************************************************************
skipping: [vmhkge1jasdev01] => (item=scripts)
ok: [jdeesbkup] => (item=scripts)
TASK [debug] **********************************************************************************************************************************************
ok: [jdeesbkup] => {
"win_result": {
"changed": false,
"msg": "All items completed",
"results": [
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"changed": false,
"item": "scripts",
"skip_reason": "Conditional check failed",
"skipped": true
}
]
}
}
ok: [vmhkge1jasdev01] => {
"win_result": {
"changed": false,
"msg": "All items completed",
"results": [
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": false,
"invocation": {
"module_name": "win_stat"
},
"item": "scripts",
"stat": {
"exists": false
}
}
]
}
}
TASK [debug] **********************************************************************************************************************************************
ok: [jdeesbkup] => {
"other_result": {
"changed": false,
"msg": "All items completed",
"results": [
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": false,
"invocation": {
"module_args": {
"checksum_algorithm": "sha1",
"follow": false,
"get_attributes": true,
"get_checksum": true,
"get_md5": true,
"get_mime": true,
"path": "/usr/local/bin/scripts"
},
"module_name": "stat"
},
"item": "scripts",
"stat": {
"exists": false
}
}
]
}
}
ok: [vmhkge1jasdev01] => {
"other_result": {
"changed": false,
"msg": "All items completed",
"results": [
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"changed": false,
"item": "scripts",
"skip_reason": "Conditional check failed",
"skipped": true
}
]
}
}
TASK [debug] **********************************************************************************************************************************************
skipping: [jdeesbkup] => (item={'skipped': True, '_ansible_no_log': False, 'skip_reason': u'Conditional check failed', '_ansible_item_result': True, 'item': u'scripts', 'changed': False})
ok: [vmhkge1jasdev01] => (item={'_ansible_parsed': True, u'stat': {u'exists': False}, '_ansible_item_result': True, '_ansible_no_log': False, u'changed': False, 'item': u'scripts', 'invocation': {'module_name': u'win_stat'}}) => {
"item": {
"changed": false,
"invocation": {
"module_name": "win_stat"
},
"item": "scripts",
"stat": {
"exists": false
}
},
"msg": "scripts"
}
TASK [debug] **********************************************************************************************************************************************
---
- hosts: "{{hosts}}"
vars:
scripts:
- run.pl
tasks:
- name: win_stat
with_items: scripts
win_stat: path="D:\scripts\{{item}}"
register: "win_result"
when: "'windows' in group_names"
- name: other_stat
with_items: scripts
stat: path="/usr/local/bin/{{item}}"
register: "other_result"
when: "'windows' not in group_names"
- debug: var=win_result
- debug: var=other_result
- with_items: "{{ win_result.results }}"
debug: msg="{{item.item}}"
when: "not (item.skipped | default(false))"
- with_items: "{{ other_result.results}}"
debug: msg="{{item.item}}"
when: "not (item.skipped | default(false))"
# when: "'windows' in group_names and {{item.stat.exists}}"
# - name: win_test
# with_items: {{win_result.results}}
# debug: var="{{item}}"
# when: "'windows' in group_names and {{item.stat.exists}}"
~
~
~
skipping: [vmhkge1jasdev01] => (item={'skipped': True, '_ansible_no_log': False, 'skip_reason': u'Conditional check failed', '_ansible_item_result': True, 'item': u'scripts', 'changed': False})
ok: [jdeesbkup] => (item={'_ansible_parsed': True, u'stat': {u'exists': False}, '_ansible_item_result': True, '_ansible_no_log': False, u'changed': False, 'item': u'scripts', 'invocation': {'module_name': u'stat', u'module_args': {u'checksum_algorithm': u'sha1', u'get_checksum': True, u'follow': False, u'path': u'/usr/local/bin/scripts', u'get_md5': True, u'get_mime': True, u'get_attributes': True}}}) => {
"item": {
"changed": false,
"invocation": {
"module_args": {
"checksum_algorithm": "sha1",
"follow": false,
"get_attributes": true,
"get_checksum": true,
"get_md5": true,
"get_mime": true,
"path": "/usr/local/bin/scripts"
},
"module_name": "stat"
},
"item": "scripts",
"stat": {
"exists": false
}
},
"msg": "scripts"
}
PLAY RECAP ************************************************************************************************************************************************
jdeesbkup : ok=5 changed=0 unreachable=0 failed=0
vmhkge1jasdev01 : ok=5 changed=0 unreachable=0 failed=0

Resources