I have a problem in my playbook, actually I want to do a ping test on some Windows hosts and I want to send the result via Slack. I have done all of this now the problem is the message that I want to send is just the list of what is ok and what's not.
This is the role of the ping :
---
- name: get powershell version
ignore_unreachable: true
raw: $PSVersionTable
- name: ping
ignore_unreachable: true
win_ping:
register: ping_results
just to have a vision this is the ping_results output :
ok: [frsv000003.local.cloud.com] => {
"msg": {
"changed": false,
"failed": false,
"ping": "pong"
}
}
ok: [frsv000023.local.cloud.com] => {
"msg": {
"changed": false,
"failed": false,
"ping": "pong"
}
}
ok: [besv000075.local.cloud.com] => {
"msg": {
"changed": false,
"msg": "psrp connection failure during runspace open: Received a broken RunspacePoolState message: Requested registry access is not allowed.",
"skip_reason": "Host besv000075.local.cloud.com is unreachable",
"unreachable": true
}
}
ok: [frsv000007.local.cloud.com] => {
"msg": {
"changed": false,
"msg": "psrp connection failure during runspace open: Received a WSManFault message. (Code: 2150858811, Machine: 172.9.1.xxx, Reason: The WS-Management service cannot process the request. The resource URI (http://schemas.microsoft.com/powershell/Microsoft.PowerShell) was not found in the WS-Management catalog. The catalog contains the metadata that describes resources, or logical endpoints.)",
"skip_reason": "Host frsv000007.local.cloud.com is unreachable",
"unreachable": true
}
}
Now for the message to send for slack, I have created a condition to put hosts that are ok and non ok in two different lists
- name: set fact
set_fact:
ok_list: []
- name: set fact2
set_fact:
ok_list: "{{ ok_list + [item.value] }}"
when: item.value is match('pong')
with_dict: "{{ ping_results }}"
- name: set fact
set_fact:
nok_list: []
- name: set fact2
set_fact:
nok_list: "{{ nok_list + [item.value] }}"
when:
- item.value is not match('pong')
with_items: "{{ ping_results | dict2items }}"
The problem I got is this :
TASK [Hello-windows : Print variable ok] ***************************************
ok: [frsv000003.local.cloud.com] => {
"msg": [
"pong"
]
}
ok: [frsv000023.local.cloud.com] => {
"msg": [
"pong"
]
}
ok: [besv000075.local.cloud.com] => {
"msg": []
}
ok: [frsv000007.local.cloud.com] => {
"msg": []
}
I need to get only hostname to print it in Slack the problem is how to get these hosts from one list and without the empty values. Thanks.
Edited Part :
#larsks i will put this as a answer the inventory is based on ansible tower contains a lot of hosts like the first example :
frsv000003.local.cloud.com
frsv000004.local.cloud.com
frsv000005.local.cloud.com
frsv000006.local.cloud.com
frsv000007.local.cloud.com
frsv000008.local.cloud.com
frsv000009.local.cloud.com
frsv000010.local.cloud.com
...
For the playbook i use a role so the main file for the role is the same as you
- name: set ok_list
set_fact:
ok_list: "{{ ok_list + [item] }}"
when: hostvars[item].ping_results.ping|default('') == "pong"
loop: "{{ groups.all }}"
- name: set nok_list
set_fact:
nok_list: "{{ nok_list + [item] }}"
when: hostvars[item].ping_results.ping|default('') != "pong"
loop: "{{ groups.all }}"
- debug:
msg:
- "ok_list: {{ ok_list }}"
- "nok_list: {{ nok_list }}"
and also for the main file (not the role) i have this :
- name: Test windows Connectivity
hosts: all
gather_facts: no
vars:
ping_results:
slack_msg:
ok_list: []
nok_list: []
roles:
- Hello-windows
So when i run the job using jobtemplate with 5 hosts the problem is that i got a list like this means that the nok list contains all hosts :
TASK [Hello-windows : debug] ***************************************************
ok: [frsv000003.local.cloud.com] => {
"msg": [
"ok_list: [u'frsv000003.local.cloud.com', u'frsv000023.local.cloud.com']",
"nok_list: [u'frsv005207.local.cloud.com', u'frsv005336.local.cloud.com', u'uksv000232.local.cloud.com', u'frsv001871.local.cloud.com', u'frsv005090.local.cloud.com', u'frsv005333.local.cloud.com', u'frsv002043.local.cloud.com', u'frsv001811.local.cloud.com', u'frsv005150.local.cloud.com', u'frsv000928.local.cloud.com', u'frsv005529.local.cloud.com', u'frsv001606.local.cloud.com', u'frsv000236.local.cloud.com', u'frsv000929.local.cloud.com', u'frsv000363.local.cloud.com', u'frsv000539.local.cloud.com', u'frsv000653.local.cloud.com', u'frsv000508.local.cloud.com', u'frsv000654.local.cloud.com', u'frsv000205.local.cloud.com', u'frsv000632.local.cloud.com', u'frsv000516.local.cloud.com', u'frsv000427.local.cloud.com', u'frsv000137.local.cloud.com', u'frsv000466.local.cloud.com', u'frsv000324.local.cloud.com', u'frsv000974.local.cloud.com', u'frsv001451.local.cloud.com', u'frsv005432.local.cloud.com', u'besv005627.local.cloud.com',
]
}
ok: [frsv000023.local.cloud.com] => {
"msg": [
"ok_list: [u'frsv000003.local.cloud.com', u'frsv000023.local.cloud.com']",
"nok_list: [u'frsv005207.local.cloud.com', u'frsv005336.local.cloud.com', u'uksv000232.local.cloud.com', u'frsv001871.local.cloud.com', u'frsv005090.local.cloud.com', u'frsv005333.local.cloud.com', u'frsv002043.local.cloud.com', u'frsv001811.local.cloud.com', u'frsv005150.local.cloud.com', u'frsv000928.local.cloud.com', u'frsv005529.local.cloud.com', u'frsv001606.local.cloud.com', u'frsv000236.local.cloud.com', u'frsv000929.local.cloud.com', u'frsv000363.local.cloud.com', u'frsv000539.local.cloud.com', u'frsv000653.local.cloud.com', u'frsv000508.local.cloud.com', u'frsv000654.local.cloud.com', u'frsv000205.local.cloud.com', u'frsv000632.local.cloud.com', u'frsv000516.local.cloud.com', u'frsv000427.local.cloud.com', u'frsv000137.local.cloud.com', u'frsv000466.local.cloud.com', u'frsv000324.local.cloud.com', u'frsv000974.local.cloud.com', u'frsv001451.local.cloud.com', u'frsv005432.local.cloud.com', u'besv005627.local.cloud.com',
]
}
ok: [besv000075.local.cloud.com] => {
"msg": [
"ok_list: [u'frsv000003.local.cloud.com', u'frsv000023.local.cloud.com']",
"nok_list: [u'frsv005207.local.cloud.com', u'frsv005336.local.cloud.com', u'uksv000232.local.cloud.com', u'frsv001871.local.cloud.com', u'frsv005090.local.cloud.com', u'frsv005333.local.cloud.com', u'frsv002043.local.cloud.com', u'frsv001811.local.cloud.com', u'frsv005150.local.cloud.com', u'frsv000928.local.cloud.com', u'frsv005529.local.cloud.com', u'frsv001606.local.cloud.com', u'frsv000236.local.cloud.com', u'frsv000929.local.cloud.com', u'frsv000363.local.cloud.com', u'frsv000539.local.cloud.com', u'frsv000653.local.cloud.com', u'frsv000508.local.cloud.com', u'frsv000654.local.cloud.com', u'frsv000205.local.cloud.com', u'frsv000632.local.cloud.com', u'frsv000516.local.cloud.com', u'frsv000427.local.cloud.com', u'frsv000137.local.cloud.com', u'frsv000466.local.cloud.com', u'frsv000324.local.cloud.com', u'frsv000974.local.cloud.com', u'frsv001451.local.cloud.com', u'frsv005432.local.cloud.com', u'besv005627.local.cloud.com',
]
}
ok: [frsv000007.local.cloud.com] => {
"msg": [
"ok_list: [u'frsv000003.local.cloud.com', u'frsv000023.local.cloud.com']",
"nok_list: [u'frsv005207.local.cloud.com', u'frsv005336.local.cloud.com', u'uksv000232.local.cloud.com', u'frsv001871.local.cloud.com', u'frsv005090.local.cloud.com', u'frsv005333.local.cloud.com', u'frsv002043.local.cloud.com', u'frsv001811.local.cloud.com', u'frsv005150.local.cloud.com', u'frsv000928.local.cloud.com', u'frsv005529.local.cloud.com', u'frsv001606.local.cloud.com', u'frsv000236.local.cloud.com', u'frsv000929.local.cloud.com', u'frsv000363.local.cloud.com', u'frsv000539.local.cloud.com', u'frsv000653.local.cloud.com', u'frsv000508.local.cloud.com', u'frsv000654.local.cloud.com', u'frsv000205.local.cloud.com', u'frsv000632.local.cloud.com', u'frsv000516.local.cloud.com', u'frsv000427.local.cloud.com', u'frsv000137.local.cloud.com', u'frsv000466.local.cloud.com', u'frsv000324.local.cloud.com', u'frsv000974.local.cloud.com', u'frsv001451.local.cloud.com', u'frsv005432.local.cloud.com', u'besv005627.local.cloud.com',
]
}
PLAY RECAP *********************************************************************
besv000075.local.cloud.com : ok=3 changed=0 unreachable=1 failed=0 skipped=1 rescued=0 ignored=0
frsv000003.local.cloud.com : ok=10 changed=1 unreachable=0 failed=0 skipped=10 rescued=0 ignored=0
frsv000007.local.cloud.com : ok=3 changed=0 unreachable=1 failed=0 skipped=1 rescued=0 ignored=0
frsv000023.local.cloud.com : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Your problem is that ping_results isn't a list of results; it's a single result for a single host. When you run:
- name: ping
ignore_unreachable: true
win_ping:
register: ping_results
This runs once on each host, and registers a variable named
ping_results for that host. You can see that in your debug output.
To get two lists, one of hosts that were reachable and one of hosts
that were not, you would need a play that runs on a single host (e.g.,
localhost) and loops over all the target hosts to look up the
ping_results variable. For example:
- hosts: localhost
gather_facts: false
tasks:
- name: set ok_list
set_fact:
ok_list: "{{ ok_list + [item] }}"
when: hostvars[item].ping_results.ping|default('') == "pong"
vars:
ok_list: []
loop: "{{ groups.all }}"
- name: set nok_list
set_fact:
nok_list: "{{ nok_list + [item] }}"
when: hostvars[item].ping_results.ping|default('') != "pong"
vars:
nok_list: []
loop: "{{ groups.all }}"
- debug:
msg:
- "ok_list: {{ ok_list }}"
- "nok_list: {{ nok_list }}"
Running this with your sample data produces the following out:
PLAY [localhost] ***************************************************************
TASK [set ok_list] *************************************************************
ok: [localhost] => (item=frsv000003.local.cloud.com)
ok: [localhost] => (item=frsv000023.local.cloud.com)
skipping: [localhost] => (item=besv000075.local.cloud.com)
skipping: [localhost] => (item=frsv000007.local.cloud.com)
TASK [set nok_list] ************************************************************
skipping: [localhost] => (item=frsv000003.local.cloud.com)
skipping: [localhost] => (item=frsv000023.local.cloud.com)
ok: [localhost] => (item=besv000075.local.cloud.com)
ok: [localhost] => (item=frsv000007.local.cloud.com)
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": [
"ok_list: ['frsv000003.local.cloud.com', 'frsv000023.local.cloud.com']",
"nok_list: ['besv000075.local.cloud.com', 'frsv000007.local.cloud.com']"
]
}
PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
And I think that's what you're looking for.
NB: I tested the above playbook using this inventory file in
hosts.yml:
all:
hosts:
frsv000003.local.cloud.com:
ansible_host: localhost
ping_results:
changed: false
failed: false
ping: pong
frsv000023.local.cloud.com:
ansible_host: localhost
ping_results:
changed: false
failed: false
ping: pong
besv000075.local.cloud.com:
ansible_host: localhost
ping_results:
changed: false
msg: "psrp connection failure during runspace open: Received a broken RunspacePoolState message: Requested registry access is not allowed."
skip_reason: "Host besv000075.local.cloud.com is unreachable"
unreachable: true
frsv000007.local.cloud.com:
ansible_host: localhost
ping_results:
changed: false
msg: "psrp connection failure during runspace open: Received a WSManFault message. (Code: 2150858811, Machine: 172.9.1.xxx, Reason: The WS-Management service cannot process the request. The resource URI (http://schemas.microsoft.com/powershell/Microsoft.PowerShell) was not found in the WS-Management catalog. The catalog contains the metadata that describes resources, or logical endpoints.)"
skip_reason: "Host frsv000007.local.cloud.com is unreachable"
unreachable: true
Running it like this:
ansible-playbook -i hosts.yml playbook.yml
How to print debug message for success and failure having information of destination host on which the task failed in Ansible wait_for module to test a firewall?
- name: Check Firewall Connectivity
wait_for:
host: 10.200.12.2
port: 2041
state: started
delay: 0
timeout: 3
ignore_errors: yes
TL;DR;
Here is the debug you are looking for:
- debug:
msg: "{{ 'Failed with message: ' ~ wait_result.msg if wait_result.failed else 'Success connecting to Firewall' }}"
You can always register the result of a task in Ansible.
Then based on this result, you can actually act, or print something.
Here is how I would have approached it: I don't know from the top of my head what a task will give me as a result, but I know for a fact that I can register it and debug it.
So I made this playbook:
- hosts: local
gather_facts: no
tasks:
- name: Check Firewall Connectivity
wait_for:
host: 10.200.12.2
port: 2041
state: started
delay: 0
timeout: 3
ignore_errors: yes
register: wait_result
- debug:
msg: "{{ wait_result }}"
It resulted in this recap:
PLAY [local] *******************************************************************
TASK [Check Firewall Connectivity] *********************************************
fatal: [local]: FAILED! => {"changed": false, "elapsed": 3, "msg": "Timeout when waiting for 127.0.0.1:22"}
...ignoring
TASK [debug] *******************************************************************
ok: [local] => {
"msg": {
"changed": false,
"elapsed": 3,
"failed": true,
"msg": "Timeout when waiting for 127.0.0.1:22"
}
}
PLAY RECAP *********************************************************************
local : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
So based on this recap, I know that my result have a property failed this is going to be true if the wait_for task fails.
And I even get a msg of failure for it.
So now, with the help of the inline if expression of Jinja, I can create this task:
- debug:
msg: "{{ 'Failed with message: ' ~ wait_result.msg if wait_result.failed else 'Success connecting to Firewall' }}"
This will result in either the recap:
TASK [debug] *******************************************************************
ok: [local] => {
"msg": "Success connecting to Firewall"
}
or the recap:
TASK [debug] *******************************************************************
ok: [local] => {
"msg": "Failed with message: Timeout when waiting for 10.200.12.2:2041"
}
i am trying ansible playbook to prompt for a user input and if condition is not satisfied it should fail & exit.
my playbook is as below.
[ansible#localhost ~]$ cat dummy.yml
---
- name: testing failed_when
hosts: localhost
gather_facts: no
tasks:
- pause:
prompt: "\nPlease ente 1:\n"
register: given
failed_when: given.user_input != 1
- set_fact:
SER: "{{ given.user_input }}"
- fail:
msg: "unacceptable"
when: SER is undefined
and when i execute this, it's getting failed even though i give input as 1..
[ansible#localhost ~]$ ansible-playbook dummy.yml
PLAY [testing failed_when] *********************************************************************************************************************
TASK [pause] ***********************************************************************************************************************************
[pause]
Please ente 1:
:1
fatal: [localhost]: FAILED! => {"changed": false, "delta": 1, "echo": true, "failed_when_result": true, "rc": 0, "start": "2020-05-29 02:52:27.318633", "stderr": "", "stdout": "Paused for 0.02 minutes", "stop": "2020-05-29 02:52:28.556987", "user_input": "1"}
NO MORE HOSTS LEFT *****************************************************************************************************************************
PLAY RECAP *************************************************************************************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
[ansible#localhost ~]$
and i have tried using "fail" as shown below, it's not working too.
tasks:
- pause:
prompt: "\nPlease ente 1:\n"
register: given
- set_fact:
SER: "{{ given.user_input }}"
- fail:
msg: "unacceptable"
when: SER != 1
result:
[ansible#localhost ~]$ ansible-playbook dummy.yml
PLAY [testing failed_when] *********************************************************************************************************************
TASK [pause] ***********************************************************************************************************************************
[pause]
Please ente 1:
:1
ok: [localhost]
TASK [set_fact] ********************************************************************************************************************************
ok: [localhost]
TASK [fail] ************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "msg": "unacceptable"}
PLAY RECAP *************************************************************************************************************************************
localhost
in both of above cases, i have entered "1" as user input & it's still failing.. Not sure what mistake i did.
please help.
thanks in advance.
The condition when expands by default the variable to string. Either compare SER to string
when: SER != "1"
or convert SER to integer
when: SER|int != 1
I wrote below yml file which will install the SSM and cloudwatch agent but I want to rollback the installation in case of any failures during the installation. I tried use FAIL but not working..Please advise..
---
# tasks file for SSMAgnetInstall
- name: status check
command: systemctl status amazon-ssm-agent
register: s_status
- debug:
msg: "{{ s_status }}"
- name: Get CPU architecture
command: getconf LONG_BIT
register: cpu_arch
changed_when: False
check_mode: no
when: s_status.stdout == ""
ignore_errors: true
- name: Install rpm file for Redhat Family (Amazon Linux, RHEL, and CentOS) 32/64-bit
yum:
name: "https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_386/amazon-ssm-agent.rpm"
state: present
when: s_status.stdout == ""
become: yes
ignore_errors: true
- name: cloud status check
command: systemctl status amazon-cloudwatch-agent
register: cld_status
become: yes
- debug:
msg: "{{ cld_status }}"
- name: Register to cloud watch service
become: yes
become_user: root
service:
name: amazon-ssm-agent
enabled: yes
state: started
- name: copy the output to a local file
copy:
content: "{{ myshell_output.stdout }}"
dest: "/home/ansible/rama/output.txt"
delegate_to: localhost
You should have a look at the the documentation on blocks, more specifically the error handling part. This is the general idea with an oversimplified example, you will have to adapt to your specific case.
The test.yml playbook
---
- hosts: localhost
gather_facts: false
tasks:
- block:
- name: I am a task that can fail
debug:
msg: "I {{ gen_fail | default(false) | bool | ternary('failed', 'succeeded') }}"
failed_when: gen_fail | default(false) | bool
- name: I am a task that will never fail
debug:
msg: I succeeded
rescue:
- name: I am a task in a block played when a failure happens
debug:
msg: rescue task
always:
- name: I am a task always played whatever happens
debug:
msg: always task
Played normally (no fail)
$ ansible-playbook test.yml
PLAY [localhost] ************************************************************************
TASK [I am a task that can fail] ********************************************************
ok: [localhost] => {
"msg": "I succeeded"
}
TASK [I am a task that will never fail] *************************************************
ok: [localhost] => {
"msg": "I succeeded"
}
TASK [I am a task always played whatever happens] ***************************************
ok: [localhost] => {
"msg": "always task"
}
PLAY RECAP ******************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Played forcing a fail
$ ansible-playbook test.yml -e gen_fail=true
PLAY [localhost] ************************************************************************
TASK [I am a task that can fail] ********************************************************
fatal: [localhost]: FAILED! => {
"msg": "I failed"
}
TASK [I am a task in a block played when a failure happens] *****************************
ok: [localhost] => {
"msg": "rescue task"
}
TASK [I am a task always played whatever happens] ***************************************
ok: [localhost] => {
"msg": "always task"
}
PLAY RECAP ******************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0
In ansible what i require is to check for a file is available on two hosts. But if the file is available on even one host i need to cancel the task on other host and move onto the next task. The reason why i require this is because a the next task can only be done if that particular file is available and that file can be randomly written to any of the hosts.
The following play does exactly what you want:
---
- hosts:
- server1
- server2
gather_facts: False
vars:
file_name: 'foo.bar'
tasks:
- name: wait for file
wait_for:
path: '{{ file_name }}'
state: present
timeout: 30
ignore_errors: True
- name: stat
stat:
path: '{{ file_name }}'
register: result
- name: next
debug:
msg: "File {{ file_name }} available on {{ ansible_host }}"
when: result.stat.isreg is defined and result.stat.isreg
The output is:
PLAY [server1,server2] *********************************************************
TASK [wait for file] ***********************************************************
ok: [server1]
fatal: [server2]: FAILED! => {"changed": false, "elapsed": 3, "msg": "Timeout when waiting for file foo.bar"}
...ignoring
TASK [stat] ********************************************************************
ok: [server1]
ok: [server2]
TASK [next] ********************************************************************
skipping: [server2]
ok: [server1] => {
"msg": "File foo.bar available on server1"
}
PLAY RECAP *********************************************************************
server1 : ok=3 changed=0 unreachable=0 failed=0
server2 : ok=0 changed=0 unreachable=0 failed=0
You can use the stat module to check the status like below and for also you can add the serial:1 below hosts: in your playbook
stat:
path: /path/to/something
register: p
debug:
msg: "Path exists and is a directory"
when: p.stat.isdir is defined and p.stat.isdir
https://docs.ansible.com/ansible/latest/modules/stat_module.html for more details