Team, I have a task that is checking for mounts. I have fail condition working but i also need to report for pass condition when mounts are present.. what am i doing wrong?
shell: "mount | grep sdd"
register: lvp_mount
ignore_errors: yes
failed_when: False
delegate_to: "{{ item }}"
with_items: "{{ groups['kube-cpu-node'] }}"
- name: "Report status of mounts"
fail:
msg: |
Mounts sdd not found
Output of `mount | grep sdd`:
{{ lvp_mount.stdout }}
{{ lvp_mount.stderr }}
when: lvp_mount is failed
- name: "Success Report status of mounts"
fail:
msg: |
Mounts sdd found
Output of `mount | grep sdd`:
{{ lvp_mount.stdout }}
{{ lvp_mount.stderr }}
when: lvp_mount is succeeded
output:
TASK [team-services-pre-install-checks : Verify LVP Mounts sdd exists on CPU Nodes for mount_device] ************************************************************************
Wednesday 27 November 2019 18:20:14 +0000 (0:00:00.097) 0:00:03.959 ****
changed: [localhost -> cpu03] => (item=compute03)
[WARNING]: Consider using the mount module rather than running 'mount'. If you need to use command because mount is insufficient you can add 'warn: false' to this command
task or set 'command_warnings=False' in ansible.cfg to get rid of this message.
TASK [team-services-pre-install-checks : Report status of mounts] ***********************************************************************************************************
Wednesday 27 November 2019 18:20:15 +0000 (0:00:01.210) 0:00:05.170 ****
skipping: [localhost]
TASK [team-services-pre-install-checks : Success Report status of mounts] ***************************************************************************************************
Wednesday 27 November 2019 18:20:15 +0000 (0:00:00.056) 0:00:05.226 ****
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout'\n\nThe error appears to be in '/k8s/baremetal/roles/teama-services-pre-install-checks/tasks/main.yml': line 120, column 9, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n when: lvp_mount is failed\n - name: \"Success Report status of mounts\"\n
Solution2 i tried: but I want it to pass
- name: "Success Report status of mounts"
fail:
msg: |
Mounts sdd found
Output of `mount | grep sdd`
when: lvp_mount is succeeded
Wednesday 27 November 2019 18:46:58 +0000 (0:00:00.056) 0:00:05.321 ****
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Mounts sdd found\nOutput of `mount | grep sdd`:\n"}
I see this solution but not sure how to fit it in mine?
Ansible Message Output based on task result
Related
In this task, I am searching for a file. If there is no file, the task will be skipped.
My question is, how do I write a custom message to output when the task is skipped?
- name: Search for files
win_find:
paths: C:\dataset\
register: data
- debug:
msg: "Data exists"
when: data | json_query('files[*].exists')
- name: set_fact
set_fact:
exists: "{{ data | json_query('files[*].exists') }}"
In a different playbook:
- name: Run if file exists
block:
- name: read content from file
win_shell: C:\day.txt
register: day
when: hostvars['10.11.18.190']['exists']
- name: print message
debug:
msg: "{{ hostvars['10.12.201.20']['day'] }}"
As there is no file, the task is skipped:
TASK [Run if file exists] *********************
skipping: [10.11.18.190] => {
"changed": false,
"skip_reason": "Conditional result was False"
}
TASK [print message] **************************************************************************************
ok: [10.11.18.190] => {
"msg": {
"changed": false,
"skip_reason": "Conditional result was False",
"skipped": true
}
}
As you can see from the output, the variable hostvars['10.12.201.20']['day'] is showing "changed": false, skip_reason, etc. But I do not want this, I want it to output a message like, "File does not exist".
How can I create a custom message for this variable hostvars['10.12.201.20']['day']?
A: Use the 'Do It Yourself' callback plugin community.general.diy. See
shell> ansible-doc -t callback community.general.diy
(or the online documentation)
For example, if the file /tmp/day.txt does not exist the playbook
shell> cat pb.yml
- hosts: localhost
tasks:
- stat:
path: /tmp/day.txt
register: stat_day
- command: cat /tmp/day.txt
register: day
when: stat_day.stat.exists
vars:
ansible_callback_diy_runner_on_skipped_msg: |
skipping: [{{ inventory_hostname }}]
msg: File does not exist.
ansible_callback_diy_runner_on_skipped_msg_color: green
will display the custom message
shell> ANSIBLE_STDOUT_CALLBACK=community.general.diy ansible-playbook pb.yml
PLAY [localhost] *****************************************************************************
TASK [stat] **********************************************************************************
ok: [localhost]
TASK [command] *******************************************************************************
skipping: [localhost]
msg: File does not exist.
PLAY RECAP ***********************************************************************************
localhost: ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
Optionally, you can use the block/rescue construct. See Handling errors with blocks.
For example, in Linux (I don't have access to Windows atm) when you try to access a nonexistent file by the module command on the localhost
- command: cat /tmp/day.txt
register: day
the command will fail
fatal: [localhost]: FAILED! => changed=true
ansible_facts:
discovered_interpreter_python: /usr/bin/python3
cmd:
- cat
- /tmp/day.txt
delta: '0:00:00.010884'
end: '2023-02-14 07:21:50.664051'
msg: non-zero return code
rc: 1
start: '2023-02-14 07:21:50.653167'
stderr: 'cat: /tmp/day.txt: No such file or directory'
stderr_lines: <omitted>
stdout: ''
stdout_lines: <omitted>
Put the command into the block and use the section rescue
- block:
- command: cat /tmp/day.txt
register: day
- debug:
var: day.stdout
rescue:
- debug:
var: ansible_failed_result
Now, if the command fails you'll see
ansible_failed_result:
ansible_facts:
discovered_interpreter_python: /usr/bin/python3
changed: true
cmd:
- cat
- /tmp/day.txt
delta: '0:00:01.007972'
end: '2023-02-14 07:24:43.791343'
failed: true
invocation:
module_args:
_raw_params: cat /tmp/day.txt
_uses_shell: false
argv: null
chdir: null
creates: null
executable: null
removes: null
stdin: null
stdin_add_newline: true
strip_empty_ends: true
msg: non-zero return code
rc: 1
start: '2023-02-14 07:24:42.783371'
stderr: 'cat: /tmp/day.txt: No such file or directory'
stderr_lines:
- 'cat: /tmp/day.txt: No such file or directory'
stdout: ''
stdout_lines: []
You can reduce the output to the standard error
rescue:
- debug:
var: ansible_failed_result.stderr
If the file exists
shell> echo 'This is the content of /tmp/day.txt' > /tmp/day.txt
The next task in the block will display the standard output of the command
day.stdout: This is the content of /tmp/day.txt
Of course, there will be differences in the error messages among the operating systems. Take a look at the data you get and fit the messages to your needs.
I see not direct solution for this problem. But you could do the following:
disable the output of skipped tasks at all, with
[defaults]
display_skipped_hosts = true
In the ansbile.cfg
For details see https://docs.ansible.com/ansible/latest/collections/ansible/builtin/default_callback.html
create a debug task with the message you want to display with an opposite when condition. So it will only run if the other task is skipped.
I am trying to extract the status (http) (Enabled/ Disabled) for each server and display it in the logs. It is able to check for http status but when I try to store it, it is giving following error.
- name: Check http status(yes or no)
shell: |
sshpass -p "{{ imc_prod_password }}" ssh -T -o StrictHostKeyChecking=no {{ imc_username }}#"{{ item.cimcNames }}" << EOL
scope http
show detail | grep Enabled
EOL
register: http_status
loop: "{{ user_list.list }}"
- debug:
msg: '{{ http_status.stdout_lines | select("Enabled") | list }}'
The command show detail gives following output
Enabled: no
Output - Line 59 points to - debug:
TASK [cimc_reip : Check http status(yes or no)] ********************************
changed: [hostname] => (item={'PreferredDNS': 'x.x.x.x', 'IPdetails': 'x.x.x.x', 'Alternate': 'x.x.x.x', 'id': '1', 'GWDetails': 'x.x.x.x', 'Subnetdetails': 'x.x.x.x', 'cimcNames': 'test-server-01-r'})
changed: [hostname] => (item={'PreferredDNS': 'x.x.x.x', 'IPdetails': 'x.x.x.x', 'Alternate': 'x.x.x.x', 'id': '2', 'GWDetails': 'x.x.x.x', 'Subnetdetails': 'x.x.x.x', 'cimcNames': 'test-server-02-r'})
TASK [cimc_reip : debug] *******************************************************
fatal: [hostname]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout_lines'\n\nThe error appears to be in '/builds/xxxxx/xxxx/playbooks/roles/cimc_reip/tasks/main.yml': line 59, column 5, 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"}
As already mentioned in the comments you are registering the result set in a loop in one variable. You will get therefore an dictionary and in your example an error
The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout_lines'
The following test shows it
---
- hosts: localhost
become: false
gather_facts: false
vars:
USERNAME: ['test'] # list
PASSWORD: 'password'
target_host: "test.example.com"
tasks:
- name: Check http status
shell: |
sshpass -p '{{ PASSWORD }}' ssh -T -o StrictHostKeyChecking=no {{ item }}#"{{ target_host }}" << EOF
sudo lsof -Pi TCP
EOF
register: http_status
loop: "{{ USERNAME }}" # list
- debug:
msg: "{{ http_status | type_debug }}"
resulting into an output of
TASK [debug] ************
ok: [test.example.com] =>
msg: dict
You can loop over the http_status.results list in the dictionary as follow
- name: Show result
debug:
msg: "{{ item.stdout_lines }}"
loop: "{{ http_status.results }}" # list
loop_control:
label: "{{ item.item }}" # with USERNAME looped over to limit the displayed output
resulting into an output of
TASK [Show result] *****************************************************************************
ok: [test.example.com] => (item=test) =>
msg:
- COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
- httpd 384 root 19u IPv4 12345678 0t0 TCP test.example.com:443 (LISTEN)
Team,
I am trying to verify if sdd exists in mount command output. so when there is any, i am fine but when there is none, my task is simply failing instead of just telling me that no mounts exists. any hint how to tackle this? I don't want my task to fail but to report what is the state.
when status code is 0 am good but when status code is 1 am just seeing failure instead of a helpful message that mounds sdd don't exist.
"mount | grep sdd"
- name: "Verify LVP Mounts sdd exists on CPU Nodes for mount_device"
shell: "mount | grep sdd"
register: lvp_mount
ignore_errors: yes
failed_when: False
delegate_to: "{{ item }}"
with_items: "{{ groups['kube-cpu-node'] }}"
- name: "Report status of mounts"
fail:
msg: |
Mounts sdd not found
Output of `mount | grep sdd`:
{{ lvp_mount.stdout }}
{{ lvp_mount.stderr }}
when: lvp_mount | failed
output:
fatal: [localhost]: FAILED! => {"msg": "The conditional check 'lvp_mount | failed' failed. The error was: template error while templating string: no filter named 'failed'. String: {% if lvp_mount | failed %} True {% else %} False {% endif %}\n\nThe error appears to be in '/k8s/baremetal/roles/maglev-services-pre-install-checks/tasks/main.yml': line 111, column 9, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n with_items: \"{{ groups['kube-cpu-node'] }}\"\n - name: \"Report status of mounts\"\n ^ here\n"}
expected output:
if lvp_mount.rc == 0
msg: mount sdd exists
if lvp_mount.rc == 1
msg: mount sdd does not exists
if lvp_mount.rc not in [0, 1]
msg: mount exec errir
The error is telling you that there is no filter named failed. To check for a failed result in a conditional, use this instead:
when: lvp_mount is failed
Alternatively, to check for a successful result, use:
when: lvp_mount is succeeded
Team, I have below task but I need to search for sdd in its output which is a list. listing the output and my assert is failing. I just want to print a message sdd found and not found on this task based on result.
#Local volume provision sdd check on CPU node
- name: "Verify LVP Mounts sdd exists on CPU Nodes for mount_device"
shell: "mount | grep sdd"
register: lvp_mount
ignore_errors: yes
failed_when: False
delegate_to: "{{ item }}"
with_items: "{{ groups['kube-cpu-node'] }}"
- set_fact:
sdd: lvp_mount.results[0].stdout_lines
when: lvp_mount is succeeded
- debug:
var: lvp_mount.results[0].stdout_lines
- debug:
msg: "Assert SDD Mounts present"
failed_when: lvp_mount.results[0].stdout_lines[0] is search('sdd')
output
debug] *****************************************************************************************************************************
Wednesday 27 November 2019 23:19:36 +0000 (0:00:00.066) 0:00:04.251 ****
ok: [localhost] => {
"lvp_mount.results[0].stdout_lines": [
"/dev/sdd1 on /local-volumes/postgres/b5b296cf-02cd-41b3-b090-4e2dc77c6867 type ext4 (rw,relatime,data=ordered)"
]
}
TASK [services-pre-install-checks : debug] *****************************************************************************************************************************
Wednesday 27 November 2019 23:19:36 +0000 (0:00:00.066) 0:00:04.317 ****
fatal: [localhost]: FAILED! => {
"msg": "Assert SDD Mounts present"
}
My bad, I was doing opposite of logic. Need to do NOT. is not search('sdd')
- name: "Verify LVP Mounts sdd exists on CPU Nodes for mount_device"
shell: "mount | grep sdd"
register: lvp_mount
ignore_errors: yes
failed_when: False
delegate_to: "{{ item }}"
with_items: "{{ groups['kube-cpu-node'] }}"
- debug:
msg: "Assert SDD Mounts present"
failed_when: lvp_mount.results[0].stdout_lines[0] is not search('sdd')
Team,
I am writing a validation task that is supposed to just check if a mount exists or not and report its state from output. so my task is below but it fails and am not sure how to handle it. any hint what adjustments do i need to make?
- name: "Verify LVP Mounts on CPU Nodes for mount_device"
shell: "mount | grep sdd"
register: lvp_mount
delegate_to: "{{ item }}"
with_items: "{{ groups['kube-cpu-node'] }}"
#failed_when: lvp_mount.rc != 0
#ignore_errors: yes
# - debug:
# var: lvp_mount
- name: "Report status of mounts"
fail:
msg: |
Mounts sdd not found
Output of `mount | grep sdd`:
{{ lvp_mount.stdout }}
{{ lvp_mount.stderr }}
when: lvp_mount | failed
changed: [localhost -> ] => (item=hostA)
[WARNING]: Consider using the mount module rather than running 'mount'. If you
need to use command because mount is insufficient you can add 'warn: false' to
this command task or set 'command_warnings=False' in ansible.cfg to get rid of
this message.
failed: [localhost -> hostA.test.net] (item=hostA) => {"ansible_loop_var": "item", "changed": true, "cmd": "mount | grep sdd", "delta": "0:00:00.009284", "end": "2019-11-06 18:22:56.138007", "failed_when_result": true, "item": "hostA", "msg": "non-zero return code", "rc": 1, "start": "2019-11-06 18:22:56.128723", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring
TASK [services-pre-install-checks : Report status of mounts] ************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout'\n\nThe error appears to be in '/home/run_ansible_playbook/k8s/baremetal/roles/services-pre-install-checks/tasks/main.yml': line 265, column 9, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: \"Report status of mounts\"\n ^ here\n"}
Your task "Verify LVP Mounts on CPU Nodes for mount_device" is a loop so the register behavior is modified as specified in the documentation.
You can access the various outputs with lvp_mount.results.X.stdout where X is the index.
There is a cleaner way to write your script however. More specifically using:
delegate_to: "{{ item }}"
with_items: "{{ groups['kube-cpu-node'] }}"
is bad practice. You can accomplish your desired outcome at the play level.
For example:
- hosts: kube-cpu-node # allows you to iterate over all hosts in kube-cpu-node group
tasks:
- name: "Verify LVP Mounts on CPU Nodes for mount_device"
shell: "mount | grep sdd"
register: lvp_mount
ignore_errors: yes
# notice there is no loop here
- name: "Report status of mounts"
fail:
msg: |
Mounts sdd not found
Output of `mount | grep sdd`:
{{ lvp_mount.stdout }} # no loop so you can use lvp_mount.stdout
{{ lvp_mount.stderr }} # no loop so you can use lvp_mount.stderr
when: lvp_mount | failed