Ansible remove quote from ansbile fact value - ansible

I have below task to setup IPv6 not disable settings. when I used ansible_default_ipv4.interface values its including to quote value. how to remove the quote from ansible fact value for below task?
- name: Ensure IPv6 not disabled with sysctl
sysctl:
name: "{{ item }}"
value: '0'
state: present
sysctl_file: /etc/sysctl.conf
reload: yes
with_items:
- "net.ipv6.conf.{{ ansible_default_ipv4.interface }}.disable_ipv6"
ignore_errors: yes
This gives below message
cannot stat /proc/sys/net/ipv6/conf/\"ens192\"/disable_ipv6: No such file or directory\
Here is the fact value:
"ansible_default_ipv4": {
"alias": "ens192",
"interface": "ens192",
"mtu": 1500,
"type": "ether"
},
Thanks
SR

Works for me in Ansible 2.9.6. For example
- sysctl:
name: "{{ item }}"
value: "1"
register: result
with_items:
- "net.ipv4.conf.{{ ansible_default_ipv4.interface }}.forwarding"
- debug:
var: result
gives
TASK [sysctl] ****
ok: [localhost] => (item=net.ipv4.conf.eth0.forwarding)
TASK [debug] ****
ok: [localhost] =>
result:
changed: false
msg: All items completed
results:
- ansible_loop_var: item
changed: false
failed: false
invocation:
module_args:
ignoreerrors: false
name: net.ipv4.conf.eth0.forwarding
reload: true
state: present
sysctl_file: /etc/sysctl.conf
sysctl_set: false
value: '1'
item: net.ipv4.conf.eth0.forwarding

Related

Multiple 'and' operators in Ansible 'when' condition

This is the code that I am trying to run
- name: Read and Register Contents of .bash_profile
shell: grep -E 'AB_AG_HOME|AB_AG_LOCAL_ROOT|AB_AG_LOCAL_DIR|AB_AG_CONFIG_DIR|AB_AG_LOG_DIR' /home/username/.bash_profile
register: output
- debug:
msg: "{{ output.stdout_lines }}"
- name: Append AG environment variables in .bash_profile
shell: cat /home/{{ admin_user }}/tmp_bash.profile >> /home/{{ admin_user }}/.bash_profile
when: "'AB_AG_HOME' and 'AB_AG_LOCAL_ROOT' and 'AB_AG_LOCAL_DIR' and 'AB_AG_CONFIG_DIR' and 'AB_AG_LOG_DIR' not in item"
with_items: "{{ output.stdout_lines }}"
- name: Delete the temporary tmp_bash.profile"
file:
path: /home/{{ abinitio_admin_user }}/tmp_bash.profile
state: absent
when I run this code, all the values are repeated 4 times.
Is there anything that is missing?
By looping over the stdout_lines via
with_items: "{{ output.stdout_lines }}"`
the condition
when: "'AB_AG_HOME' and 'AB_AG_LOCAL_ROOT' and 'AB_AG_LOCAL_DIR' and 'AB_AG_CONFIG_DIR' and 'AB_AG_LOG_DIR' not in item"
would only be true if all strings are in one line (item) together.
You may have a look into the following minimal example
---
- hosts: localhost
become: false
gather_facts: false
vars:
result:
stdout_lines:
- "A1"
- "A2"
- "A3"
- "A4"
- "A5"
tasks:
- name: Debug one-line conditional
debug:
msg: "Not in stdout_lines"
when: "'A1' and 'A2' and 'A3' and 'A4' and 'A5' not in result.stdout_lines"
Whereby the first given example get skipped because of the condition, the second example
- name: Debug loop conditional
debug:
msg: "Not in {{ result.stdout_lines[ansible_loop.index0] }}"
when: "'A1' and 'A2' and 'A3' and 'A4' and 'A5' not in item"
loop: "{{ result.stdout_lines }}"
loop_control:
extended: true
will result into an output of
TASK [Debug loop conditional] ******
ok: [localhost] => (item=A1) =>
msg: Not in A1
ok: [localhost] => (item=A2) =>
msg: Not in A2
ok: [localhost] => (item=A3) =>
msg: Not in A3
ok: [localhost] => (item=A4) =>
msg: Not in A4
For further debugging you could also use the assert module – Asserts given expressions are true.

Complex with_subelements construct

I have the list:
final_list:
- result:
name: "val1"
status: true
- result:
name: "val2"
status: true
- skipped:
path: "path1"
- result:
results:
- result:
name: "val4"
status: true
- result:
name: "val5"
status: true
- skipped:
path: "path2"
I would like check if any status in my list is false.
I started with:
- set_fact:
any_false: true
when: (item.0.result is defined and item.0.result.status == false) or (item.1.result is defined and item.1.result.status == false)
with_subelements:
- "{{ final_list }}"
- result.results"
- skip_missing: True
but this task ommit elements from finally_list without results in result.
I would expect iterate by all elements which contain status variable.
I tried also:
with_subelements:
- "{{ final_list }}"
- result.results | default([])
but get error:
msg: msg: the key result should point to a dictionary, got 'None'
I suggest to do this a bit differently: get all individual result elements in a single flattened list, extract the status and check that all elements are true (or not).
The following playbook should be self explanatory (run with -v to see intermediate debug)
---
- hosts: localhost
gather_facts: false
vars:
final_list:
- result:
name: "val1"
status: true
- result:
results:
- result:
name: "valA"
status: false
- result:
name: "valB"
status: true
- skipped:
path: "path2"
- result:
name: "val2"
status: true
- skipped:
path: "path1"
- result:
results:
- result:
name: "val4"
status: true
- result:
name: "val5"
status: true
- skipped:
path: "path2"
# List of all top level elements without nested elements
single_results: "{{ final_list | rejectattr('result.results', 'defined') }}"
# Flattened list of all nested result elements.
# Will work with several nested elements (as you can see from my example data)
nested_results: "{{ final_list | selectattr('result.results', 'defined') | map(attribute='result.results') | flatten }}"
# Single list containing top level + nested result elements
all_results: "{{ single_results + nested_results }}"
# List of all existing status values in the list of result elements
all_status: "{{ all_results | selectattr('result.status', 'defined') | map(attribute='result.status') }}"
tasks:
- name: Show entire list
debug:
var: all_results
verbosity: 1
- name: Show list of status
debug:
var: all_status
verbosity: 1
- name: Make sure all exsiting status are true
assert:
that:
- all_status is all
fail_msg: "At least one status is false"
success_msg: "All status are true"
which gives:
PLAY [localhost] ***********************************************************************************************************************************************************************************************************************
TASK [Show entire list] ****************************************************************************************************************************************************************************************************************
skipping: [localhost]
TASK [Show list of status] *************************************************************************************************************************************************************************************************************
skipping: [localhost]
TASK [Make sure all exsiting status are true] ******************************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {
"assertion": "all_status is all",
"changed": false,
"evaluated_to": false,
"msg": "At least one status is false"
}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=2 rescued=0 ignored=0
And if you modify the data to all true (only pasting the last task...)
TASK [Make sure all exsiting status are true] ******************************************************************************************************************************************************************************************
ok: [localhost] => {
"changed": false,
"msg": "All status are true"
}
Q: "Check if any status is false."
A: Simple brute force
- set_fact:
status: "{{ status|d([]) + [item.split(':')|last|trim|bool] }}"
loop: "{{ (final_list|to_nice_yaml).splitlines() }}"
when: item is match('^.*\\s+status:\\s+.*$')
gives the list of the statuses
status:
- true
- true
- true
- true
See Testing if a list value is True, e.g.
- debug:
msg: No status is False.
when: status is all

Processing embedded lists inside dict variables in Ansible

I got the example code in Ansible:
- name: testing
hosts: localhost
vars:
svc:
https: ['tcp/443']
app_svc: ['tcp/5543', 'udp/5543', 'tcp/3100']
tasks:
- name: print
debug:
msg: port={{item.key}} value={{item.value}}
with_dict:
- "{{svc}}"
And this outputs to:
ok: [127.0.0.1] => (item=None) => {
"msg": "port=app_svc value=[u'tcp/5543', u'udp/5543', u'tcp/3100']"
}
ok: [127.0.0.1] => (item=None) => {
"msg": "port=https value=[u'tcp/443']"
}
What I would like to achieve is, when there is more than one element in list of values it would split like this:
- name=https, prot=tcp, port=443
- name=app_svc, prot=tcp, port=5543
- name=app_svc, prot=udp, port=5543
- name=app_svc, prot=tcp, port=3100
with_dict stanza only displays me a whole list and I couldn't find a way do do it differently. Is it possible to do it like that without reorganizing the var section? Thanks in advance for input.
To see the syntax errors run
# ansible-lint <YOUR-PLAYBOOK>
Correct syntax should be
- hosts: localhost
gather_facts: no
vars:
svc:
https: ['tcp/443']
app_svc: ['tcp/5543', 'udp/5543', 'tcp/3100']
tasks:
- name: print
debug:
msg: "port={{ item.key }} value={{ item.value }}"
with_dict: "{{ svc }}"
gives
"msg": "port=app_svc value=[u'tcp/5543', u'udp/5543', u'tcp/3100']"
"msg": "port=https value=[u'tcp/443']"
Change the loop
- name: print
debug:
msg: "name={{ item.0.key }},
prot={{ item.1.split('/')[0] }},
port={{ item.1.split('/')[1] }}"
loop: "{{ lookup('subelements', svc|dict2items, 'value') }}"
to get the format
"msg": "name=app_svc, prot=tcp, port=5543"
"msg": "name=app_svc, prot=udp, port=5543"
"msg": "name=app_svc, prot=tcp, port=3100"
"msg": "name=https, prot=tcp, port=443"
dict2items is available since version 2.6 . Without "dict2items" transform the data first. See below (not tested).
https:
- {key: 'https', value: ['tcp/443']}
- {key: 'app_svc', value: ['tcp/5543', 'udp/5543', 'tcp/3100']}

What causes Ansible to evaluate 'false and true' as 'true'? [duplicate]

I have the following tasks in a playbook I'm writing (results listed next to the debug statement in <>):
- debug: var=nrpe_installed.stat.exists <true>
- debug: var=force_install <true>
- debug: var=plugins_installed.stat.exists <true>
- name: Run the prep
include: prep.yml
when: (nrpe_installed.stat.exists == false or plugins_installed.stat.exists == true or force_install == true)
tags: ['prep']
- debug: var=nrpe_installed.stat.exists <true>
- debug: var=force_install <true>
- debug: var=force_nrpe_install <false>
- name: Install NRPE
include: install-nrpe.yml
when: (nrpe_installed.stat.exists == false or force_install == true or force_nrpe_install == true)
tags: ['install_nrpe']
vars:
nrpe_url: 'http://url.goes.here'
nrpe_md5: 3921ddc598312983f604541784b35a50
nrpe_version: 2.15
nrpe_artifact: nrpe-{{ nrpe_version }}.tar.gz
nagios_ip: {{ nagios_ip }}
config_dir: /home/ansible/config/
And I'm running it with the following command:
ansible-playbook install.yml -i $invFile --extra-vars="hosts=webservers force_install=True"
The first include runs, but the second skips with this output:
skipping: [server1] => {"changed": false, "skip_reason": "Conditional check failed", "skipped": true}
I'm under the impression that the conditional check should pass for all of them as force_install == true evaluates to true which should make the whole when evaluate to true (since it's a series of 'OR's).
How do I get the when to run when the variables are set appropriately?
Edit:
Changing the second when for the Install NRPE include to the following works, but doesn't explain why the other one, Run the prep runs appropriately:
Working:
when: (not nrpe_installed.stat.exists or force_install or force_nrpe_install)
Also working:
when: (nrpe_installed.stat.exists == false or plugins_installed.stat.exists == true or force_install == true)
Not working:
when: (nrpe_installed.stat.exists == false or force_install == true or force_nrpe_install == true)
The truncated (duplicates removed) output of that particular section of the play is:
TASK [debug] *******************************************************************
ok: [server2] => {
"nrpe_installed.stat.exists": true
}
TASK [debug] *******************************************************************
ok: [server2] => {
"plugins_installed.stat.exists": true
}
TASK [debug] *******************************************************************
ok: [server2] => {
"force_install": true
}
TASK [Run the prep] ************************************************************
included: /tasks/nrpe-install/prep.yml for server2, server3, server4, server5, server6, server7
TASK [Prep and configure for installation | Install yum packages] **************
ok: [server6] => (item=[u'gcc', u'glibc', u'glibc-common', u'gd', u'gd-devel', u'make', u'net-snmp', u'openssl-devel', u'unzip', u'tar', u'gzip', u'xinetd']) => {"changed": false, "item": ["gcc", "glibc", "glibc-common", "gd", "gd-devel", "make", "net-snmp", "openssl-devel", "unzip", "tar", "gzip", "xinetd"], "msg": "", "rc": 0, "results": ["gcc-4.1.2-55.el5.x86_64 providing gcc is already installed", "glibc-2.5-123.el5_11.3.i686 providing glibc is already installed", "glibc-common-2.5-123.el5_11.3.x86_64 providing glibc-common is already installed", "gd-2.0.33-9.4.el5_4.2.x86_64 providing gd is already installed", "gd-devel-2.0.33-9.4.el5_4.2.i386 providing gd-devel is already installed", "make-3.81-3.el5.x86_64 providing make is already installed", "net-snmp-5.3.2.2-20.el5.x86_64 providing net-snmp is already installed", "openssl-devel-0.9.8e-40.el5_11.x86_64 providing openssl-devel is already installed", "unzip-5.52-3.el5.x86_64 providing unzip is already installed", "tar-1.15.1-32.el5_8.x86_64 providing tar is already installed", "gzip-1.3.5-13.el5.centos.x86_64 providing gzip is already installed", "xinetd-2.3.14-20.el5_10.x86_64 providing xinetd is already installed"]}
TASK [Prep and configure for installation | Make nagios group] *****************
ok: [server2] => {"changed": false, "gid": 20002, "name": "nagios", "state": "present", "system": false}
TASK [Prep and configure for installation | Make nagios user] ******************
ok: [server6] => {"append": false, "changed": false, "comment": "User for Nagios NRPE", "group": 20002, "home": "/home/nagios", "move_home": false, "name": "nagios", "shell": "/bin/bash", "state": "present", "uid": 20002}
TASK [debug] *******************************************************************
ok: [server2] => {
"nrpe_installed.stat.exists": true
}
TASK [debug] *******************************************************************
ok: [server2] => {
"force_install": true
}
TASK [debug] *******************************************************************
ok: [server2] => {
"force_nrpe_install": false
}
TASK [Install NRPE] ************************************************************
skipping: [server2] => {"changed": false, "skip_reason": "Conditional check failed", "skipped": true}
You need to convert the variable to a boolean:
force_install|bool == true
I don't claim I understand the logic behind it. In python any non-empty string should be truthy. But when directly used in a condition it evaluates to false.
The bool filter then again interprets the strings 'yes', 'on', '1', 'true' (case-insensitive) and 1 as true (see source). Any other string is false.
You might want to also set a default value in case force_install is not defined, since it would result in an undefined variable error:
force_install|default(false)|bool == true
Yeah... certainly requires testing. I recommend
| bool is good unless you expect undefined vars
var is defined and (var | bool) if you expect undefined vars
default(False) is OK as long and you are happy that these are true if the input is not parsed from YAML. I.e. variables defined through --extra_vars CLI parameter are strings.
"false"
"null"
"defined string"
Hope this helps:
#!/usr/bin/env ansible-playbook
---
- name: Test truthiness
hosts: localhost
gather_facts: False
vars:
truthy_vars:
# TRUE
- True
- 1
- "true"
# FALSE
- "false"
- null
- False
- 0
# ERROR (invalid sytax error stops the loop of the first of these)
- "null"
- "defined string"
# ERROR
# truthy_var_undefined
# FALSE
truthy_var_defined:
tasks:
- name: Test truthy
debug:
msg: "is truthy"
ignore_errors: True # beware, the loo
when: item
loop: "{{ truthy_vars }}"
loop_control:
label: Test {{ item }}
- name: truthy_var_undefined
debug:
when: truthy_var_undefined
ignore_errors: true
- name: truthy_var_defined
debug:
when: truthy_var_defined
- name: Test | default(False)
hosts: localhost
gather_facts: False
vars:
default_pipe_vars:
# TRUE
- True
- 1
- "true"
# beware these:
- "false"
- "null"
- "defined string"
# FALSE
- null
- False
- 0
# FALSE
# default_pipe_undefined
# FALSE
default_pipe_defined:
tasks:
- name: Test | default(False)
debug:
msg: "is not | default(False)"
when: item | default(False)
loop: "{{ default_pipe_vars }}"
loop_control:
label: Test {{ item }}
- name: default_pipe_undefined | default(False)
debug:
when: default_pipe_undefined | default(False)
- name: default_pipe_defined | default(False)
debug:
when: default_pipe_defined | default(False)
- name: Test | bool
hosts: localhost
gather_facts: False
vars:
bool_vars:
# TRUE
- True
- 1
- "true"
# FALSE
- "defined string"
- "null"
- "false"
- null
- False
- 0
# ERROR
# bool_undefined
# FALSE
bool_defined:
tasks:
- name: Test bool parsing
debug:
msg: "parsed as true booleans"
when: item | bool
loop: "{{ bool_vars }}"
loop_control:
label: Test {{ item }}
- name: bool_undefined | bool
debug:
when: bool_undefined | bool
ignore_errors: true
- name: bool_defined var | bool
debug:
when: bool_defined | bool
- name: Test is defined and | bool
hosts: localhost
gather_facts: False
vars:
defined_bool_vars:
# TRUE
- True
- 1
- "true"
# FALSE
- "defined string"
- "null"
- "false"
- null
- False
- 0
# FALSE
# defined_bool_undefined
# FALSE
defined_bool_defined:
tasks:
- name: Test bool parsing
debug:
msg: "parsed as true booleans"
when:
- item is defined
- item | bool
loop: "{{ defined_bool_vars }}"
loop_control:
label: Test {{ item }}
- name: defined_bool_undefined | bool
debug:
when:
- defined_bool_undefined is defined
- defined_bool_undefined | bool
ignore_errors: true
- name: defined_bool_defined var | bool
debug:
when:
- defined_bool_defined is defined
- defined_bool_defined | bool
https://gist.github.com/kcd83/4ea23d201c271b58f1c4ef7844408657

Test value of all members in hash variable in Ansible playbook

I need to run a task only if one or more files from a pre-defined list of files are missing. I tried the following (and some variants):
touch a
cat test.yml
- hosts: localhost
vars:
filelist:
- a
- b
tasks:
- stat:
path: "{{ item }}"
with_items: "{{ filelist }}"
register: all_files
- debug:
var: all_files
- debug:
msg: "Some file(s) missing"
when: "false in all_files['results'][*]['stat']['exists']"
ansible-playbook test.yml
...
TASK [debug] ********************************************************************
ok: [localhost] => {
"all_files": {
...
"item": "a",
"stat": {
...
"exists": true,
...
"item": "b",
"stat": {
"exists": false
...
TASK [debug] ********************************************************************
fatal: [localhost]: FAILED! => {"failed": true, "msg": "The conditional check 'false in all_files['results'][*]['stat']['exists']' failed. The error was: template error while templating string: unexpected '*'. String: {% if false in all_files['results'][*]['stat']['exists'] %} True {% else %} False {% endif %}\n\nThe error appears to have been in 'test.yml': line 16, 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"}
...
What is the correct syntax to use in the 'when:' clause? Or is this the wrong way altogether?
- hosts: localhost
gather_facts: false
vars:
file_vars:
- {name: file1}
- {name: file2}
tasks:
- name: Checking existing file name
stat:
path: ./{{ item.name }}
with_items: "{{ file_vars }}"
register: check_file_name
- debug:
msg: 'file name {{item.item.name}} not exists'
with_items: "{{ check_file_name.results }}"
when: item.stat.exists == False
- name: Create file
file:
path: "./{{item.item.name}}"
state: touch
with_items: "{{ check_file_name.results }}"
when: item.stat.exists == False

Resources