'dict object' has no attribute 'stdout' in Ansible - ansible

Could you please help me with identifying the error
'dict object' has no attribute 'stdout'
which I am getting while running an Ansible playbook. Please see the error below:
{"msg": "The conditional check '(result.stdout == 1) and (ansible_distribution == 'CentOS' or ansible_distribution == 'RedHat')' failed. The error was: error while evaluating conditional ((result.stdout == 1) and (ansible_distribution == 'CentOS' or ansible_distribution == 'RedHat')): 'dict object' has no attribute 'stdout'\n\nThe error appears to be in '/etc/ansible/playbooks/dev_patching_security_upgrade_version2.yml': line 47, 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 - name: Reboot CentOS Server if Necessary\n ^ here\n"}
I am pasting the relevant part of the code below:
- name: check to see if we need a reboot in Centos
shell:
"needs-restarting; echo $?"
register: result
ignore_errors: yes
when: ansible_distribution == 'CentOS' or ansible_distribution == 'RedHat'
- name: display result
debug:
var: result.stdout
when: ansible_distribution == 'CentOS' or ansible_distribution == 'RedHat'
- name: Reboot CentOS Server if Necessary
command: shutdown -r now "Ansible Updates Triggered reboot"
become: true
async: 30
poll: 0
when: (result.stdout == 1) and (ansible_distribution == 'CentOS' or ansible_distribution == 'RedHat')
Thanks in advance

This is because the result set might not have a dictionary key stdout. To debug a result set you may use
- name: Show result
debug:
var: result
Since the shell module already provides the return code within the Return Values, reboot checks are simple as
- name: Check if reboot_required
shell:
cmd: "needs-restarting -r"
changed_when: false
failed_when: reboot_required.rc != 0 and reboot_required.rc != 1
check_mode: false
register: reboot_required
- name: Report reboot_required
debug:
msg: "{{ reboot_required.rc | bool }} "
changed_when: reboot_required.rc == 1
check_mode: false
and resulting into an output of in example
TASK [Report reboot_required] **************************************************
ok: [test1.example.com] => {
"msg": "True "
}
ok: [test2.example.com] => {
"msg": "False "
}
You could dense down the tasks to one by using one
needs-restarting -r || /usr/sbin/shutdown -r now "Ansible Updates Triggered reboot"
Further Q&A
How to determine if system needs a reboot?
Ansible - How to reboot the server based on condition?

Related

Ansible how to setup a block with multiple when conditionals

How best to setup an Ansible block and run the block if a command does not exist or have specific output?
If the command does not exist then stdout would not be available.
- name: Check if mybin exists
stat:
path: /usr/sbin/mybin
register: mybin
- name: Get mybin status
command: mybin status
register: status
when: mybin.stat.exists
changed_when: false
- name: This node is not yet configured so run this block
block:
- name: Install req packages
....
when:
- mybin.stat.exists == False
- status.stdout.find('successfully setup') == False
The conditional check 'status.stdout.find('successfully setup') == False' failed. The error was: error while evaluating conditional (status.stdout.find('successfully setup') == False): 'dict object' has no attribute 'stdout'
As the play is written, those two conditions can never both be true at the same time. You have written the conditions as and-ed together. You need or:
when: mybin.stat.exists == False or status.stdout.find('successfully setup') == False

Use skip_reason as a condition in a task

Is it possible to use the skip_reason as condition to another task?
Here is the task:
- name: PSP Validation
script: roles/OS_minor_upgrade/files/PSP_validation.sh
ignore_errors: true.
register: PSP_VAL
when: >
not 'VMware' in HWMODEL.stdout
Which output:
TASK [OS_minor_upgrade : PSP Postwork] ******************************************************************************************************************************************************
task path: /home/ansible/linuxpatching_OS_Upgrade/roles/OS_minor_upgrade/tasks/upgrade.yml:264
skipping: [server123] => {
"changed": false,
"skip_reason": "Conditional result was False"
}
Now I want to use the above as condition to execute another task, I tried with the task below but it seem like it is not working.
- name: OSupgrade done
shell: echo {{ inventory_hostname }} "OS Upgrade Done" > OUTGOING-OSUPGRADE-PATCHCOMPLETION/inventory_{{ inventory_hostname }}_{{ '%y%m%d%H%M%S' | strftime }}_Offlineoutput
delegate_to: localhost
when: >
fs_check.rc == 0 and val_etrust.rc == 0 and 'PSP Installation is successfully completed' in PSP_VAL.stdout or 'Conditional result was False' in PSP_VAL.skip_reason
How can this be achieved?
Technically, you can use 'skip_reason' as any other variable, but I STRONGLY suggest you not to.
The reason is that person, reading your code (you, 1 week later) would be in a total loss over such decision.
If you have important information about your host, you can use set_fact module to update your host information. Further tasks can use this to make decisions.
- name: Update vmware info
set_fact:
vmware_flag: ('VMware' in HWMODEL.stdout)
- name: PSP Validation
script: roles/OS_minor_upgrade/files/PSP_validation.sh
failed_when: false
register: PSP_VAL
when: not vmware_flag
- name: OSupgrade done
delegate_to: localhost
copy:
dest: OUTGOING-OSUPGRADE-PATCHCOMPLETION/inventory_{{ inventory_hostname }}_{{ '%y%m%d%H%M%S' | strftime }}_Offlineoutput
content: '{{ inventory_hostname }} "OS Upgrade Done"'
when: (some other conditions) or vmware_flag
There are specific ansible tests to verify the registered result of a task
In your specific case:
when: <...all other conditions...> or PSP_VAL is skipped

Ansible undefined variables in check mode

Consider this playbook:
---
- name: test
hosts: localhost
gather_facts: no
tasks:
- name: foo
shell: echo foo # skipped when running in check mode
register: result
- debug: msg="foo"
when: (result is defined)
and (result.stdout == 'foo')
I thought the is defined would result in short circuit evaluation as in other languages, but it doesn't.
If this is run in check mode, I get:
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout'
I know I can ignore the error with ignore_errors: "{{ansible_check_mode}}", but I want to learn how to fix this problem.
How do I rewrite the when clause to prevent referencing undefined variables?
Actually, if you debug the var without a condition, you will see it is defined. It simply does not contain a stdout key since the task was skipped. The correct ways to work arround this (non exhaustive list):
- debug: msg="{{ result.stdout | default('no value') }}
when: result.stdout | default('') == 'foo'
- debug: msg="foo"
when:
- result is not skipped
- result.stdout == 'foo'
Note that since your above shell example is not changing anything on the remote target you can also decide to play it even when running in check mode:
- name: foo
shell: echo foo
check_mode: false
changed_when: false
register: result
- debug: msg="foo"
when: result.stdout == 'foo'

Ansible Exit code fail

Guys I have code like:
- name: Running ccache for {{ SOMETHING }}
shell: "{{ item }}"
loop:
- command1
- command2
- command3
when: stat_result.stat.exists
failed_when: >
(rc != 0) or
(rc != 8)
I tried to get the following logic work:
"If command's exit code is not 0 or 8 , then success."
However only thing I get from this is:
[0;31mfatal: [someIPhere]: FAILED! => {"msg": "The conditional check '(rc != 0) or (rc != 8)' failed. The error was: error while evaluating conditional ((rc != 0) or (rc != 8)): 'rc' is undefined"}[0m
Any advices?
You need to register a variable to contain the results of the commands. This variable will contain values for each item in the loop, including rc.
https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#registering-variables
- name: Running ccache for {{ TENANT }}
shell: "{{ item }}"
loop:
- touch /tmp/test
- touch /tmp/test
- touch /tmp/test
when: stat_result.stat.exists
register: command_result
failed_when: command_result.rc not in [ 0, 68 ]

Ansible ignoring conditional

I am working on a ansible playbook for my servers (mix of ubuntu and centos) and when trying to transfer some config files for monit if a program is installed I am running into an issue. It works perfectly on my centos machines but the ubuntu one's it transfers the template no matter what completely ignoring the conditional.
---
- name: Check for Sendmail (Ubuntu)
shell: dpkg-query -W -f='${Status} ${Version}\n' sendmail
register: ubuntu_installed
when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
changed_when: False
failed_when: "'FAILED' in ubuntu_installed.stderr"
- debug: var=ubuntu_installed
- name: Check for Sendmail (CentOs)
shell: rpm -qa | grep sendmail
register: cent_installed
when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux'
changed_when: False
failed_when: "'FAILED' in cent_installed.stderr"
- name: Transfer Monit config files for Sendmail (Ubuntu)
template: src=monit/templates/sendmail.j2 dest=/etc/monit/conf.d/sendmail owner=root group=root mode=644
when: ubuntu_installed.skipped is not defined and ubuntu_installed.stdout != "" and ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
- name: Transfer Monit config files for Sendmail (CentOs)
template: src=monit/templates/sendmail.j2 dest=/etc/monit.d/sendmail owner=root group=root mode=644
when: cent_installed.skipped is not defined and cent_installed.stdout != "" and ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux'
I have the debug in there to check to make sure the variable is right. When I run the playbook I get...
TASK: [monit | debug var=ubuntu_installed] ************************************
ok: [server1] => {
"item": "",
"ubuntu_installed": {
"changed": false,
"cmd": "dpkg-query -W -f='${Status} ${Version}\\n' sendmail ",
"delta": "0:00:00.012985",
"end": "2014-07-11 16:56:12.688509",
"failed": false,
"failed_when_result": false,
"invocation": {
"module_args": "dpkg-query -W -f='${Status} ${Version}\\n' sendmail",
"module_name": "shell"
},
"item": "",
"rc": 1,
"start": "2014-07-11 16:56:12.675524",
"stderr": "dpkg-query: no packages found matching sendmail",
"stdout": "",
"stdout_lines": []
}
}
It is completely ignoring the conditional ubuntu_installed.stdout != ""
Here's your conditional:
- when: ubuntu_installed.skipped is not defined and ubuntu_installed.stdout != "" and ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
Your precedence is incorrect: A and B and C or D means is (A and B and C) or D, which is not what you want. (note Ansible conditionals use Jinja2 expressions, which reflect Python conditionals, so here are the precedence rules).
Lazy programmers add parenthesis for clarity; here's the revised conditional:
- when: (ubuntu_installed.skipped is not defined and ubuntu_installed.stdout != "") and (ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu')
PS- you showed the output to one command, debug, but it's helpful to give alllll the output. That's ansible-playbook -vvv.

Resources