ansible when condition failing - ansible

Can someone help me to understand why this when condition is failing.
Below is my Playbook:
- name: restart pkgd once finally for RHEL6 and RHEL7 systems
service:
name: pkgd
enabled: yes
state: restarted
when: ansible_os_family == 'RedHat' and ansible_distribution_major_version|int >= 7
Error:
TASK [restart pkgd once finally for RHEL6 and RHEL7 systems] ******************************************************************************************************
task path: /home/user/tr_vdi.yml:250
fatal: [myhost]: FAILED! => {}
MSG:
The conditional check 'ansible_os_family == 'RedHat' and ansible_distribution_major_version|int >= 7' failed. The error was: error while evaluating conditional (ansible_os_family == 'RedHat' and ansible_distribution_major_version|int >= 7): 'ansible_os_family' is undefined
Ansible Ad hoc:
devSanbox$ ansible myhost -m setup -a "filter=ansible_distribution_*"
/usr/lib/python2.7/site-packages/ansible/parsing/vault/__init__.py:44: CryptographyDeprecationWarning: Python 2 is no longer supported by the Python core team. Support for it is now deprecated in cryptography, and will be removed in a future release.
from cryptography.exceptions import InvalidSignature
myhost | SUCCESS => {
"ansible_facts": {
"ansible_distribution_file_parsed": true,
"ansible_distribution_file_path": "/etc/redhat-release",
"ansible_distribution_file_search_string": "Red Hat",
"ansible_distribution_file_variety": "RedHat",
"ansible_distribution_major_version": "7",
"ansible_distribution_release": "Maipo",
"ansible_distribution_version": "7.8",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
devSanbox$ ansible myhost -m setup -a "filter=ansible_os_family*"
from cryptography.exceptions import InvalidSignature
myhost | SUCCESS => {
"ansible_facts": {
"ansible_os_family": "RedHat",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
ansible version: 2.9

I do not see any problem in your play section if you have gather_facts: true there.
However, I see many newbie guys overwriting this while disabling it in the ansible.cfg file.
Please check below in your ansible.cfg file, it should be the reason.
gathering = False

Related

How do I find which register attribute to use in Ansible?

I am testing out the results of the register commands and it yields different attribute for various tasks: failures, msg, stderr, err..etc
- yum:
name: packagenotfound
state: present
ignore_errors: yes
register: command_result
- debug:
msg: "{{ command_result }}"
ok: [ansible] => {
"msg": {
"changed": false,
"failed": true,
"failures": [
"No package packagenotfound available."
],
"msg": "Failed to install some of the specified packages",
"rc": 1,
"results": []
}}
And
- lvg:
pvs: /dev/sddnotfound
vg: vgdata
ignore_errors: yes
register: command_result
- debug:
msg: "{{ command_result }}"
ok: [ansible] => {
"msg": {
"changed": false,
"failed": true,
"msg": "Device /dev/sddnotfound not found."
}
And
- shell: thiscommandwontwork
ignore_errors: yes
register: command_result
- debug:
msg: "{{ command_result }}"
ok: [ansible] => {
"msg": {
"changed": true,
"cmd": "thiscommandwontwork",
"delta": "0:00:00.002560",
"end": "2020-02-05 04:24:35.297556",
"failed": true,
"msg": "non-zero return code",
"rc": 127,
"start": "2020-02-05 04:24:35.294996",
"stderr": "/bin/sh: thiscommandwontwork: command not found",
"stderr_lines": [
"/bin/sh: thiscommandwontwork: command not found"
],
"stdout": "",
"stdout_lines": []
}
And
- lvol:
lv: lvdata
vg: vgroup
size: 2000M
ignore_errors: yes
register: command_result
- debug:
msg: "{{ command_result }}"
ok: [ansible] => {
"msg": {
"changed": false,
"err": " Volume group \"vgroup\" not found\n Cannot process volume group vgroup\n",
"failed": true,
"msg": "Volume group vgroup does not exist.",
"rc": 5
}
Now if I tried to use when: '"xxx" in command_result.err' with yum task for example, it will result in dict_object not found error.
Is there a way to find out which attribute to use without testing?
Testing is definitely the easiest and fastest way to have a look at the content of your registered var in several situation and to take decisions on how to use it in your playbook.
Meanwhile, there are ways to have a global knowledge of what is returned in your registered var from the documenations:
There is a page on Common modules return values
Modules returning specific values usually document them on each relevant doc page. Here is an example for the stat module
You should also be aware that the global register structure is changed when using a loop by addind a top level results list, as explained in registering variables
Knowing what could be in your register does not mean it will be. Your example mentions the (undocumented...) err attribute for the lvol module, which will only be available for an lvol task in error. You can work around such cases by using tests (like my_register is failed) or defaulting values with the default filter.

Ansible suddenly uses svr4pkg as a backend of yum

Declared YUM task as below:
---
- hosts: all
vars:
tasks:
- name: install package
yum:
name: ntp
state: present
Ran following command:
ansible-playbook test.yml -i localhost, --connection=local -vvvv
Receiving error message:
TASK [install package] ***************************************************************************************************************************************************
task path: /home/osuser/dod/test.yml:6
Using module file /usr/lib/python2.7/site-packages/ansible/modules/system/setup.py
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: osuser
<localhost> EXEC /bin/sh -c '/usr/bin/python && sleep 0'
Running svr4pkg as the backend for the yum action plugin
Using module file /usr/lib/python2.7/site-packages/ansible/modules/packaging/os/svr4pkg.py
<localhost> EXEC /bin/sh -c '/usr/bin/python && sleep 0'
fatal: [localhost]: FAILED! => {
"ansible_facts": {
"pkg_mgr": "svr4pkg"
},
"changed": false,
"invocation": {
"module_args": {
"category": false,
"name": "ntp",
"proxy": null,
"response_file": null,
"src": null,
"state": "present",
"zone": "all"
}
},
"msg": "src is required when state=present",
"name": "ntp"
Note the following message in debug:
Running svr4pkg as the backend for the yum action plugin
Ansible decided to use "srv4pkg" module (which requires src parameter) as backend of yum.
Workaround:
Set use_backend: yum parameter on yum module... if possible ! (I cannot modify the yaml file in my real usage).
Running Ansible 2.7.15 on CentOS 7.6.. with yum installed so there is absolutely no reason svr4pkg as a back-end (which is not supported/documented by yum module).
However, as it seems to be defined as an ansible_fact, I have done following test (result is filtered):
ansible -i localhost, all -m setup -k
SUCCESS => {
"ansible_facts": {
"ansible_distribution": "CentOS",
"ansible_distribution_file_parsed": true,
"ansible_distribution_file_path": "/etc/redhat-release",
"ansible_distribution_file_variety": "RedHat",
"ansible_distribution_major_version": "7",
"ansible_distribution_release": "Core",
"ansible_distribution_version": "7.6.1810",
"ansible_os_family": "RedHat",
"ansible_pkg_mgr": "svr4pkg",
"ansible_python_version": "2.7.5",
"module_setup": true
},
"changed": false
}
Any clue of the reason and how to enforce ansible_pkg_mgr ?
It seems that this distribution is shipped with yum and svr4pkg as we can see below:
$ ll /usr/bin/yum
-rwxr-xr-x. 1 root root 801 Nov 5 2018 /usr/bin/yum
$ ll /usr/sbin/pkgadd
-rwxr-xr-x. 1 root root 207342 Jul 2 16:12 /usr/sbin/pkgadd
So the last available package manager resolved is kept and take precedence /usr/lib/python2.7/site-packages/ansible/module_utils/facts/system/pkg_mgr.py
# A list of dicts. If there is a platform with more than one
# package manager, put the preferred one last. If there is an
# ansible module, use that as the value for the 'name' key.
PKG_MGRS = [{'path': '/usr/bin/yum', 'name': 'yum'},
{'path': '/usr/bin/dnf', 'name': 'dnf'},
{'path': '/usr/bin/apt-get', 'name': 'apt'},
{'path': '/usr/sbin/pkgadd', 'name': 'svr4pkg'},
[...]
def collect(self, module=None, collected_facts=None):
facts_dict = {}
collected_facts = collected_facts or {}
pkg_mgr_name = 'unknown'
for pkg in PKG_MGRS:
if os.path.exists(pkg['path']):
pkg_mgr_name = pkg['name']
# Handle distro family defaults when more than one package manager is
# installed, the ansible_fact entry should be the default package
# manager provided by the distro.
if collected_facts['ansible_os_family'] == "RedHat":
if pkg_mgr_name not in ('yum', 'dnf'):
pkg_mgr_name = self._check_rh_versions(pkg_mgr_name, collected_facts)
[...]
facts_dict['pkg_mgr'] = pkg_mgr_name
return facts_dict
So it seems to be an unmanaged case on ansible.
However, I still have no idea on how to enforce the right value !
Fixed by upgrading to Ansible 2.8+.
See https://github.com/ansible/ansible/issues/49184 when multiple package managers are available on system.

Unable to stop and disable firewalld using Ansible

This is my playbook to stop and disable firewalld :
---
- hosts : openstack
connection : ssh
remote_user : ec2-user
become_method : sudo
become : yes
gather_facts : no
tasks :
- command: "{{ item }}"
with_items:
- systemctl stop firewalld
- systemctl disable firewalld
Error :
failed: [ec2-52-87-240-155.compute-1.amazonaws.com] (item=systemctl stop firewalld) => {"changed": true, "cmd": ["systemctl", "stop", "firewalld"], "delta": "0:00:00.009282", "end": "2016-10-27 13:37:20.620051", "failed": true, "item": "systemctl stop firewalld", "rc": 5, "start": "2016-10-27 13:37:20.610769", "stderr": "Failed to stop firewalld.service: Unit firewalld.service not loaded.", "stdout": "", "stdout_lines": [], "warnings": []}
failed: [ec2-52-87-240-155.compute-1.amazonaws.com] (item=systemctl disable firewalld) => {"changed": true, "cmd": ["systemctl", "disable", "firewalld"], "delta": "0:00:00.004876", "end": "2016-10-27 13:37:20.816710", "failed": true, "item": "systemctl disable firewalld", "rc": 1, "start": "2016-10-27 13:37:20.811834", "stderr": "Failed to execute operation: Access denied", "stdout": "", "stdout_lines": [], "warnings": []}
Could anyone help me out with this?
There a few things wrong with this playbook:
don't set a space character between parameter and :
use service module instead of command module
This should work:
---
- hosts: openstack
connection: ssh
remote_user: ec2-user
become: True
gather_facts: False
tasks:
- name: Stop and disable firewalld.
service:
name: firewalld
state: stopped
enabled: False
if firewalld not installed/not running you can simply ignore error message using "failed_when:"
To avoid Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg
- name: 'Disable firewalld Services'
service:
name: "{{item}}"
state: stopped
enabled: no
loop:
- firewalld
register: firewalld_service_disable
failed_when: "firewalld_service_disable|failed and ('Could not find the requested service' not in firewalld_service_disable.msg)"
ignore_errors: yes
tags: test
Below is the anisble playbook execution output
# ansible-playbook main.yml --tags test
PLAY [all] **********************************************************
TASK [Gathering Facts] **********************************************
ok: [ANSIBLECLIENTNODE]
TASK [hardening : Disable firewalld Services] ***********************
changed: [ANSIBLECLIENTNODE] => (item=firewalld)
PLAY RECAP **********************************************************
ANSIBLECLIENTNODE : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
If your ansible version 2.9 and later , follow below "service_facts" method
- name: 'Populate service facts'
service_facts:
- name: 'Disable firewalld Services'
service:
name: "{{item}}"
state: stopped
enabled: no
loop:
- firewalld
when: ansible_facts.services[item] is defined
ignore_errors: yes

Ansible condition when string not matching

I am trying to write an Ansible playbook that only compiles Nginx if it's not already present and at the current version. However it compiles every time which is undesirable.
This is what I have:
- shell: /usr/local/nginx/sbin/nginx -v 2>&1
register: nginxVersion
- debug:
var=nginxVersion
- name: install nginx
shell: /var/local/ansible/nginx/makenginx.sh
when: "not nginxVersion == 'nginx version: nginx/1.8.0'"
become: yes
The script all works apart from the fact that it runs the shell script every time to compile Nginx. The debug output for nginxVersion is:
ok: [server] => {
"var": {
"nginxVersion": {
"changed": true,
"cmd": "/usr/local/nginx/sbin/nginx -v 2>&1",
"delta": "0:00:00.003752",
"end": "2015-09-25 16:45:26.500409",
"invocation": {
"module_args": "/usr/local/nginx/sbin/nginx -v 2>&1",
"module_name": "shell"
},
"rc": 0,
"start": "2015-09-25 16:45:26.496657",
"stderr": "",
"stdout": "nginx version: nginx/1.8.0",
"stdout_lines": [
"nginx version: nginx/1.8.0"
],
"warnings": []
}
}
}
According to the documentation I am on the right lines, what simple trick am I missing?
Try:
when: nginxVersion.stdout != 'nginx version: nginx/1.8.0'
or
when: '"nginx version: nginx/1.8.0" not in nginxVersion.stdout'
Since var is a json string you can parse it to json and access it's keys.
set_fact:
var_json: "{{ var.stdout|from_json }}"
Then access the json and get the value you want.
when: var_json.nginxVersion.stdout == 'nginx version: nginx/1.8.0'
checkout this link: https://gist.github.com/justinhennessy/28e82c2ec05f9081786a

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