Ansible conditional template variable substitution - ansible

I am trying to create configuration files from a template with include variables based on the fourth character of {{ ansible_hostname }}.
What works:
playbook:
---
- hosts: spock
roles:
- templaterole
role:
---
- name: testing autofs template on spock
template:
src=autofs
dest=/tmp/autofs
with_items:
- "{{ var_a }}"
when: ('{{ ansible_hostname }}' == "spock")
vars/main.yml:
var_a:
-
var_1: 'this is var_a1'
var_2: 'this is var_a2'
var_b:
-
var_1: 'this is var_b1'
var_2: 'this is var_b2'
template:
{{ item.var_1 }}
#
{{ item.var_2 }}
#
This works as expected and the output produces a /tmp/autofs file on the spock host that looks like:
this is var_a1
#
this is var_a2
#
Now, if I try to write the file based on trying to pull out the 4th character of the {{ ansible_hostname }}, the play does not get a match on the conditional and does not write the file. I'm trying this conditional in my role:
---
- name: testing autofs template on spock
template:
src=autofs
dest=/tmp/autofs
with_items:
- "{{ var_a }}"
when: ('{{ ansible_hostname }} | cut -c4' == "c") or
('{{ ansible_hostname }} | cut -c4' == "k")
the play skips this task due to not matching on the conditional. Ultimately i want to be able to pull any 4th character of our hostnames as this will always be predictable (can only be one of 4 known characters which defines my environment and lets me define the correct template variables based on these diff production environments.)
Can anyone help me to redefine my when statement such that i can do or conditionals and pull characters out of defined ansible variables like ansible_hostname?

Don't use curly brackets inside when statement, it's already a Jinja2 statement.
And in Jinja2 statements you use | to apply filter, but there is no cut filter available.
Your statement should be as simple as:
when: ansible_hostname[3] in 'ck'

Related

How to fix Ansible Lint warning: no-jinja-when

I just got warning raised by Ansible Lint.
This is the issue:
[no-jinja-when] [HIGH] No Jinja2 in when
You can skip specific rules or tags by adding them to your configuration file:
# .ansible-lint
warn_list: # or 'skip_list' to silence them completely
- no-jinja-when # No Jinja2 in when
This is my task:
- name: remove unecessary batch
file:
path: "{{ item.path }}"
state: absent
when: var_service == "service2" and item.path | regex_replace(cron_regex_for_s2_deletion, '\\1') not in batches_{{ var_fuction | regex_replace('^service2-batch-', '') }}
with_items: "{{ result.files }}"
I'm not sure how to fix the when condition to fulfil Ansible lint recommendations.
when conditions are always templated:
The when clause is a raw Jinja2 expression without double curly braces
Source: https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_conditionals.html#basic-conditionals-with-when
So, you cannot have any expression block {{ ... }} or statement block {% ... %} in it.
In order to get a variable from a dynamic name you should use the vars lookup, so:
lookup(
'vars',
'batches_' ~ var_fuction | regex_replace('^service2-batch-', '')
)
You can also make that when more readable by switching your and for a list:
You can use logical operators to combine conditions. When you have multiple conditions that all need to be true (that is, a logical and), you can specify them as a list
Source: https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_conditionals.html#conditionals-based-on-ansible-facts
Some extra YAML multiline trickery could also help you keep the expression on a line, as that could also be a warning Ansible lint could raise.
You end up with this condition:
when:
- var_service == 'service2'
- >-
item.path | regex_replace(cron_regex_for_s2_deletion, '\1')
not in lookup(
'vars',
'batches_' ~ var_fuction | regex_replace('^service2-batch-', '')
)

Not picking up variable in expression correctly - Ansible

I'm trying the following -
---
- name: Test
hosts: "{{ hosts }}"
vars:
before: "groups.{{ hosts[0] }}_group_name"
after: "{{ before }}" # This equals {{ groups.test_group_name }}
roles:
- test-check
Just an explanation: I'm feeding hosts in when executing the playbook as a 'var'. In this case, var = test. The expected var string for before would be groups.test_group_name which is a group that contains multiple hosts in my inventory. However, when I execute this, after remains as groups.test_group_name instead of the expected array of hosts.
Does anybody know how I can remedy this? If I hard-code the host_name (test) into the after var, it picks it up, but if I don't, it doesn't. Thanks.
It appears you are trying to do pseudocode: {{ eval(before) }} but that is not how ansible, or jinja2, work. Thankfully, groups is a normal python dict and thus is subject to the __getitem__ syntax [] to dynamically look up keys
Thus, you likely want:
- hosts: "{{ hosts }}"
vars:
after: "{{ groups[ hosts[0]+'_group_name' ] }}"
tasks:
- debug: var=after

Ansible condtional statement with stdout and variable

I am trying to use a condition to verify the MD5_hash value from the std output with the stored value in the host file.
- block:
- name: Install OS
nxos_install_os:
provider: "{{ creds }}"
system_image_file: "{{bin}}"
issu: no
timeout: 500
when: md5_result.stdout[0] == "{{ MD5_Hash }}"
[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found:
md5_result.stdout[0] == "{{ MD5_bin5 }}"
I found a suggestion of using [] instead of {{}}, but I am just getting the condition result is FALSE.
Please suggest.

Ansible: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}

Can someone help me in understanding and resolving it
- name: Copying file to sever2
fetch:
src: /tmp/
dest: /u0/test/
when:
"{{ inventory_hostname == 'testdb' }}"
In your case, you should use when condition without Jinja delimiters.
Example:
when: inventory_hostname == 'testdb'
Detailed explanation:
Jinja template delimiters are used when variable interpolation is required in context of text and templates. This tells Ansible to use the value of the variable instead of the variable name.
Consider everything as text unless told otherwise (with delimiters)
Example:
vars:
fav_tool: Ansible
tasks:
- debug:
msg: "I like fav_tool"
This will output:
"msg": "I like fav_tool"
This is not what I wanted, I wanted to display "I like Ansible". So then I have to "tell" ansible to use the value of fav_tool.
- debug:
msg: "I like {{ fav_tool }}"
Similarly we use Jinja template delimiters in templates. Where we want to separate the variable, and expressions from text.
Example template such as below:
if fav_tool == 'Ansible'
I like Ansible
endif
... will result in exactly the same text without evaluating:
if fav_tool == 'Ansible'
I like Ansible
endif
However, when we use Jinja delimiters:
{% if fav_tool == 'Ansible' %}
I like Ansible
{% endif %}
It will result in:
I like Ansible
When we use conditions such as when:, we don't need delimiters as the conditionals will automatically interpolate the variable to value.
Consider everything as variables and expressions unless told otherwise (with '')
Example:
The case is reversed here and whatever is not enclosed in single-quotes is automatically evaluated. Only 'Ansible' is considered as text here (not evaluated).
vars:
fav_tool: Ansible
tasks:
- debug:
msg: "Ansible rocks!"
when: fav_tool == 'Ansible'
It worked for me with
when:
(inventory_hostname in groups['testdb'])

Checking the first digit in a number in ansible playbook

I have an ansible playbook that reads in a vars_file containing usernames and uids
users:
- name: josh
uid: 1201
- name: peter
uid: 1202
- name: paul
uid: 2101
- name: ryan
uid: 2102
I have two host groups in my inventory file, db and web. I want users to be created in db if their uid starts with a 1, and web if it starts with 2.
My playbook so far looks like this
---
- name: users playbook
hosts: all
become: yes
vars_files:
- vars/user_list.yml
tasks:
- name: test debug
debug:
msg: "{{ item.username }}, {{ item.uid }}"
loop: "{{ users }}"
when: '{{ item.uid[0] }} == 1'
But my when conditional throws the error
The error was: error while evaluating conditional ({{ item.uid[0] }} == 1)
Is there a better way of doing this for both conditionals?
Several problems.
First, you are not comparing anything. In the expression '{{ item.uid[0] }} == 1' the last part (i.e. == 1) will be literally treated as a string and written as output. If used in a full jinja2 expression, the comparison must be inside the markers: {{ item.uid[0] == 1 }}
Second, when clauses should not contain any jinja2 markers to expand variables. This is also the case for failed_when and changed_when. See the conditionals doc
Lastly, getting the character with an index will only work if the input is a string and not an int. So you first need to make sure or that by casting it correctly with the string filter. The char you will then get will be itself a string. Comparing it to an integer will always return false. So you either have to write the comparison value as a string (i.e. '1') or cast the extracted car to an integer with the int filter.
This is how I would fix your task:
- name: test debug
debug:
msg: "{{ item.username }}, {{ item.uid }}"
loop: "{{ users }}"
when: (item.uid | string)[0] | int == 1

Resources