using ansible variable in task conditonal - ansible

When I use an Ansible variable in the failed_when conditional, Ansible complains and fails by telling me that I cannot use Jinja2 expressions with failed_when.
Below snippet does not work:
vars:
var1: "var"
tasks:
- name: "sth"
raw: "anothersth"
register: status
failed_when: var1 in status.stdout
I want to use a regex in the above example and use variable var1 within a regex. This also fails.
I want to fail the task if var1 is repeated in the beginning and at the end of the stdout_lines. I was thinking something like this:
failed_when: regex("^{{var1}}/.*/{{var1}}$") in status.stdout
I wonder whether there is a way to achieve what I intend to do?
===============================================================
Exact play and the description:
Let me explain what I am trying to do:
run a command with "raw" module and register the stdout_lines.
iterate over a list of items, where list is a fact of current ansible host
use failed_when to search a pattern in the registered stdout and fail the task if it is not found
peers_underlay is a list defined in the host file:
peers_underlay:
- ip: "172.16.1.2"
- ip: "172.16.1.6"
This is the play:
- hosts: leaf-2, spine-1
gather_facts: no
tags: [ verify ]
vars:
bgp_underlay: "show ip bgp summary"
tasks:
- name: "underlay bgp test"
raw: "{{ bgp_underlay }}"
register: underlay_status
with_items: "{{ peers_underlay }}"
failed_when: not regex(".*/{{ item['ip'] }}/.*/Estab/.*") in underlay_status.stdout_lines

Q: "Fail the task if var1 is repeated in the beginning and at the end."
A: It's possible to test strings. For example, use regex
- hosts: localhost
vars:
my_stdout1: 'ABC dlkjfsldkfjsldkfj ABC'
my_stdout2: 'alkdjflaksdjflakdjflaksjdflaksdjflasj'
var1: 'ABC'
my_regex: '^{{ var1 }}(.*){{ var1 }}$'
tasks:
- debug:
msg: my_regex match my_stdout1
when: my_stdout1 is regex(my_regex)
- debug:
msg: my_regex match my_stdout2
when: my_stdout2 is regex(my_regex)
gives
"msg": "my_regex match my_stdout1"
The particular task sequence would be
vars:
var1: "var"
my_regex: '^{{ var1 }}(.*){{ var1 }}$'
tasks:
- name: "sth"
raw: "anothersth"
register: status
failed_when: status.stdout is regex(my_regex)

Related

Ansible: 'regex_replace' removing every character starting with "#"

I have following registered variable with stdout and I want to remove every character starting with "#".
ok: [localhost] => {
"msg": [
"wazuh#4.3.10-4311"
]
}
Example: wazuh#4.3.10-4311 should become wazuh.
remove every character after "#"
---
- hosts: localhost
gather_facts: false
vars:
my_string: wazuh#4.3.10-4311
tasks:
- debug:
msg: "{{ my_string | regex_replace('#.*', '') }}"
Provides:
wazuh
One could also look at the use case as just interested in the left part of the #
delimitered string.
---
- hosts: localhost
gather_facts: false
vars:
my_string: wazuh#4.3.10-4311
tasks:
# For Ansible v2.9 and later
- name: Use of Python string method
debug:
msg: "{{ my_string.split('#') | first }}"
So not removing the part behind but only deliver the part before.
# For Ansible v2.10 and later
- name: Show left part with filter
debug:
msg: "{{ my_string | split('#') | first }}"
Also this solution it's working:
regex_replace('#.*$','')

--tags does not skip vars_prompt in ansible

When I run ansible-playbook --tags tag2, why does not it skip vars_prompt from tag1? Anyhow it skips debug msg from tag1. Please help. This is making me write 2 different playbooks.
---
- name: variable print using var
hosts: all
gather_facts: no
tags: tag1
vars_prompt:
- name: ask_user
prompt: enter your name
private: no
tasks:
- debug:
msg: "{{ ask_user}} works in ABC company"
- hosts: all
gather_facts: no
tags: tag2
tasks:
- name: normal message
debug:
msg: "This is 2nd tag"
Q: "--tags does not skip vars_prompt in Ansible"
A: vars_prompt is not a task and therefore can't be skipped. Quoting from Tags
Using tags to execute or skip selected tasks is a two-step process:
Add tags to your tasks, either individually or with tag inheritance from a block, play, role, or import.
Select or skip tags when you run your playbook.
If you want to skip the prompting for a variable use pause instead of vars_prompt. For example, the playbook below does what you want
- hosts: localhost
gather_facts: false
tags: tag1
tasks:
- pause:
prompt: Enter your name
echo: true
register: result
- set_fact:
ask_user: "{{ result.user_input }}"
- debug:
msg: "{{ ask_user }} works in ABC company"
- hosts: localhost
gather_facts: false
tags: tag2
tasks:
- debug:
msg: This is tag2

Ansible - 'when' is not a valid attribute for a Play

I'm trying to figure out how to "remove" the warning message [WARNING]: Could not match supplied host pattern, ignoring: ps_nodes, by fixing the root cause. The root cause for me is that when we do Linux machine creation we will have the ps_nodes hosts empty. So, I was trying to add the block: + when: (os_type|capitalize) == "Windows", to assure that Play to only execute when os_type is a Windows creation.
How can I achieve that? Because, what I'm trying is to use the when condiction, but looks like it's not possible, and I'm not sure what to search anymore.
Code example:
- name: "Start handling of vm specific delete scripts for Windows machines"
block:
hosts: ps_nodes
any_errors_fatal: false
gather_facts: false
vars:
private_ip_1: "{{ hostvars['localhost']['_private_ip_1']|default('') }}"
scripts: "{{ hostvars['localhost']['scripts'] }}"
sh_script_dir: "{{ hostvars['localhost']['sh_script_dir'] }}"
cred_base_hst: "{{ hostvars['localhost']['cred_base_hst'] }}"
cred_base_gst: "{{ hostvars['localhost']['cred_base_gst'] }}"
newline: "\n"
tasks:
- import_tasks: roles/script/tasks/callWindowsScripts.yml
when: action == 'delete'
when: (os_type|capitalize) == "Windows"
Error using 'when' for a Play:
ERROR! 'when' is not a valid attribute for a Play
The error appears to be in '/opt/projectX/playbooks/create_vm.yml': line 265, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
##############################################################################
- name: \"Start handling of vm specific delete scripts for Windows machines\"
^ here
I think the problem is the indentation. Use 'and':
- name: "Start handling of vm specific delete scripts for Windows machines"
block:
hosts: ps_nodes
any_errors_fatal: false
gather_facts: false
vars:
private_ip_1: "{{ hostvars['localhost']['_private_ip_1']|default('') }}"
scripts: "{{ hostvars['localhost']['scripts'] }}"
sh_script_dir: "{{ hostvars['localhost']['sh_script_dir'] }}"
cred_base_hst: "{{ hostvars['localhost']['cred_base_hst'] }}"
cred_base_gst: "{{ hostvars['localhost']['cred_base_gst'] }}"
newline: "\n"
tasks:
- import_tasks: roles/script/tasks/callWindowsScripts.yml
when: action == 'delete' and (os_type|capitalize) == "Windows"
Got it,
What if you use a host that exists, like localhost, check the number of hosts in ps_nodes and delegate_to them?
Something like this:
hosts: localhost
vars:
tasks:
- import_tasks: roles/script/tasks/callWindowsScripts.yml
delegate_to: ps_nodes
when: {{ ps_nodes | length > 0}}
Same issue and fixed by "indent":
- hosts: test
roles:
- role: test
vars:
k: 1
when: "'dbg' in ansible_run_tags"

set path when file exists in Ansible yml code

I'm trying to set a var only when a file exists, here is one of my attempts
---
- hosts: all
tasks:
- stat:
path: '{{ srch_path_new }}/bin/run'
register: result
- vars: srch_path="{{ srch_path_new }}"
when: result.stat.exists
This also didn't work
- vars: srch_path:"{{ srch_path_new }}"
The task you are looking for is called set_fact: and is the mechanism ansible uses to declare arbitrary "host variables", sometimes called "hostvars", or (also confusingly) "facts"
The syntax would be:
- set_fact:
srch_path: "{{ srch_path_new }}"
when: result.stat.exists
Also, while vars: is a legal keyword on a Task, its syntax is the same as set_fact: (or the vars: on the playbook): a yaml dictionary, not a key:value pair as you had. For example:
- debug:
msg: hello, {{ friend }}
vars:
friend: Jane Doe
and be aware that vars: on a task exist only for that task

iteration using with_items and register

Looking for help with a problem I've been struggling with for a few hours. I want to iterate over a list, run a command, register the output for each command and then iterate with debug over each unique registers {{ someregister }}.stdout
For example, the following code will spit out "msg": "1" and "msg": "2"
---
- hosts: localhost
gather_facts: false
vars:
numbers:
- name: "first"
int: "1"
- name: "second"
int: "2"
tasks:
- name: Register output
command: "/bin/echo {{ item.int }}"
register: result
with_items: "{{ numbers }}"
- debug: msg={{ item.stdout }}
with_items: "{{ result.results }}"
If however, I try and capture the output of a command in a register variable that is named using with_list, I am having trouble accessing the list or the elements within it. For example, altering the code slightly to:
---
- hosts: localhost
gather_facts: false
vars:
numbers:
- name: "first"
int: "1"
- name: "second"
int: "2"
tasks:
- name: Register output
command: "/bin/echo {{ item.int }}"
register: "{{ item.name }}"
with_items: "{{ numbers }}"
- debug: var={{ item.name.stdout }}
with_items: "{{ numbers }}"
Gives me:
TASK [debug]
> ******************************************************************* fatal: [localhost]: FAILED! => {"failed": true, "msg": "'unicode
> object' has no attribute 'stdout'"}
Is it not possible to dynamically name the register the output of a command which can then be called later on in the play? I would like each iteration of the command and its subsequent register name to be accessed uniquely, e.g, given the last example I would expect there to be variables registered called "first" and "second" but there aren't.
Taking away the with_items from the debug stanza, and just explicitly defining the var or message using first.stdout returns "undefined".
Ansible version is 2.0.2.0 on Centos 7_2.
Thanks in advance.
OK so I found a post on stackoverflow that helped me better understand what is going on here and how to access the elements in result.results.
The resultant code I ended up with was:
---
- hosts: localhost
gather_facts: false
vars:
numbers:
- name: "first"
int: "1"
- name: "second"
int: "2"
tasks:
- name: Register output
command: "/bin/echo {{ item.int }}"
register: echo_out
with_items: "{{ numbers }}"
- debug: msg="item.item={{item.item.name}}, item.stdout={{item.stdout}}"
with_items: "{{ echo_out.results }}"
Which gave me the desired result:
"msg": "item.item=first, item.stdout=1"
"msg": "item.item=second, item.stdout=2"
I am not sure if I understand the question correctly, but maybe this can help:
- debug: msg="{{ item.stdout }}"
with_items: echo_out.results
Please note that Ansible will print each item and the msg both - so you need to look carefully for a line that looks like "msg": "2".

Resources