Variables not expended inside ansible.builtin.include_vars - ansible

I have this following file var/Hendrix.yml
last: Hendrix
fullname: "Jimi {{ last }}"
And the following playbook
- name:
hosts: localhost
tasks:
- name: include
include_vars: "{{ choice }}.yml"
- name: debug
debug:
msg: "include_vars {{ choice }}, {{ fullname }}"
tags: simpleinc
- name:
hosts: localhost
tags: builtininc
tasks:
- name: include
ansible.builtin.include_vars:
file: "{{ choice }}.yml"
- name: debug
debug:
msg: "ansible.builtin.include_vars {{ choice }}, {{ fullname }}"
running with tags simpleinc or builtininc does not show the same result
ansible-playbook test.yml --extra-vars "choice=Hendrix" --tags simpleinc
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "include_vars Hendrix, Jimi Hendrix"
}
ansible-playbook test.yml --extra-vars "choice=Hendrix" --tags builtininc
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "ansible.builtin.include_vars Hendrix, Jimi {{ last }}"
}
I read that using full name of task is a good practice, but here it puzzeld me a bit, maybe this is due to file parameter, but I don't see any template

Related

ansible Iterate var only if var is not empty

I m trying to iterate over some variables in an ansible role. However, I want to ignore if the var is empty ex:ns3 from below code? I m trying when item length is greater than 0 but it seems not working? any ideas on how to do it?
---
- hosts: localhost
gather_facts: no
vars:
ns1: adm_analytics
ns2: adm_snap
ns3: ""
ns4: adm_eck
tasks:
- name: print namespace loop
with_items:
- "{{ ns1 }}"
- "{{ ns2 }}"
- "{{ ns3 }}"
- "{{ ns4 }}"
include_role:
name: verify_pod_status
vars:
NAMESPACE: "{{ item }}"
when: "{{ item | lenght > 0 }}"
You may have a look into the documentation about Conditionals.
There are some typos in your when clause.
---
- hosts: localhost
gather_facts: false
vars:
ns1: adm_analytics
ns2: adm_snap
ns3: ""
ns4: adm_eck
tasks:
- name: Print namespace loop
debug:
msg: "{{ item }}"
when: item | length > 0
with_items:
- "{{ ns1 }}"
- "{{ ns2 }}"
- "{{ ns3 }}"
- "{{ ns4 }}"
result into an output of
TASK [Print namespace loop] **************
ok: [localhost] => (item=adm_analytics) =>
msg: adm_analytics
ok: [localhost] => (item=adm_snap) =>
msg: adm_snap
ok: [localhost] => (item=adm_eck) =>
msg: adm_eck
when: condition is expanded by default. Fix the syntax
when: item|length > 0
Make your life easier and put the ns* variables into a dictionary. Then you can simply reference the values in the loop instead of listing the variables again. For example, the playbook
shell> cat playbook.yml
- hosts: localhost
gather_facts: no
vars:
ns:
ns1: adm_analytics
ns2: adm_snap
ns3: ""
ns4: adm_eck
tasks:
- name: print namespace loop
include_role:
name: verify_pod_status
loop: "{{ ns.values()|list }}"
vars:
NAMESPACE: "{{ item }}"
when: item|length > 0
and the role
shell> cat roles/verify_pod_status/tasks/main.yml
- debug:
var: NAMESPACE
give (abridged)
TASK [verify_pod_status : debug] ***********************************
skipping: [localhost] => (item=)
TASK [verify_pod_status : debug] ***********************************
ok: [localhost] =>
NAMESPACE: adm_analytics
TASK [verify_pod_status : debug] ***********************************
ok: [localhost] =>
NAMESPACE: adm_snap
TASK [verify_pod_status : debug] ***********************************
ok: [localhost] =>
NAMESPACE: adm_eck

ansible flipping inventory still reads in the same order

I am working on a project aimed at populating the IP's of some routers based on East/West locations. The first host will always be the primary and the second will always be the secondary.
Based on the location passed, I flip the inventory. I see the inventory being flipped, but Ansible get the value from the list in the same order.
It doesn't matter what order the inventory list is read. I need for the first host to read the first element e.g. 20.21.22.23 and then the second host to read the second element 28.29.30.31.
Right now, ATL is always the first element and LAX the second.
ok: [ATL_isr_lab] => {
"msg": [
"20.21.22.23",
"24.25.26.27",
"24.25.26.28"
]
}
ok: [LAX_isr_lab] => {
"msg": [
"28.29.30.31",
"32.33.34.35",
"32.33.34.36"
]
}
------------------ Inventory Flipped -------------------------------
ok: [LAX_isr_lab] => {
"msg": [
"28.29.30.31",
"32.33.34.35",
"32.33.34.36"
]
}
ok: [ATL_isr_lab] => {
"msg": [
"20.21.22.23",
"24.25.26.27",
"24.25.26.28"
]
}
---
- hosts: test_hosts
vars:
region: east
_Hub_IP: [ 20.21.22.23, 28.29.30.31]
_Transit_IP: [ 24.25.26.27, 32.33.34.35]
_Neighbor_IP: [24.25.26.28, 32.33.34.36]
_idx: "{{ groups.all.index(inventory_hostname) }}"
#flips inventory if west
order: "{{ (region == 'east')|ternary('reverse_inventory', 'inventory') }}"
become: yes
ignore_unreachable: true
gather_facts: false
tasks:
- name: "Configure Router"
debug:
msg:
- "{{ _Hub_IP[_idx|int] }}"
- "{{ _Transit_IP[_idx|int] }}"
- "{{ _Neighbor_IP[_idx|int] }}"
Well, the issue is not coming with the reverse_inventory and inventory value of the order parameter like you seems to think it is.
The issue is to think that groups.all is indeed reversed when you do use the reverse_inventory value.
Here is an example of this, with the playbook:
- hosts: localhost
gather_facts: no
order: "{{ (region == 'east')|ternary('reverse_inventory', 'inventory') }}"
tasks:
- debug:
var: groups.all
Running it with, with the region as an extra-vars:
ansible-playbook play.yml --inventory inventory.yml --extra-vars "region=east"
Will yield:
ok: [localhost] =>
groups.all:
- LAX_isr_lab
- ATL_isr_lab
ansible-playbook play.yml --inventory inventory.yml --extra-vars "region=west"
Will yield:
ok: [localhost] =>
groups.all:
- LAX_isr_lab
- ATL_isr_lab
Still the sorting works, see:
- hosts: all
gather_facts: no
order: "{{ (region == 'east')|ternary('reverse_inventory', 'inventory') }}"
tasks:
- debug:
Run with:
ansible-playbook play.yml --inventory inventory.yml --extra-vars "region=east"
Will yield
ok: [ATL_isr_lab] =>
msg: Hello world!
ok: [LAX_isr_lab] =>
msg: Hello world!
ansible-playbook play.yml --inventory inventory.yml --extra-vars "region=west"
Will yield
ok: [LAX_isr_lab] =>
msg: Hello world!
ok: [ATL_isr_lab] =>
msg: Hello world!
So, what ends up being wrong is your _idx value.
To fix this, you could use the reverse filter of jinja with the same ternary as you are using in the order parameter, like this:
_idx: "{{ ((region == 'east')|ternary(groups.all|reverse, groups.all)).index(inventory_hostname) }}"
Working playbook:
- hosts: all
gather_facts: no
order: "{{ (region == 'east')|ternary('reverse_inventory', 'inventory') }}"
vars:
_Hub_IP: [20.21.22.23, 28.29.30.31]
_Transit_IP: [24.25.26.27, 32.33.34.35]
_Neighbor_IP: [24.25.26.28, 32.33.34.36]
_idx: "{{ ((region == 'east')|ternary(groups.all|reverse, groups.all)).index(inventory_hostname) }}"
tasks:
- debug:
msg:
- "{{ _Hub_IP[_idx|int] }}"
- "{{ _Transit_IP[_idx|int] }}"
- "{{ _Neighbor_IP[_idx|int] }}"
Running examples:
ansible-playbook play.yml --inventory inventory.yml --extra-vars "region=east"
Will yield:
ok: [ATL_isr_lab] =>
msg:
- 20.21.22.23
- 24.25.26.27
- 24.25.26.28
ok: [LAX_isr_lab] =>
msg:
- 28.29.30.31
- 32.33.34.35
- 32.33.34.36
ansible-playbook play.yml --inventory inventory.yml --extra-vars "region=west"
Will yield:
ok: [LAX_isr_lab] =>
msg:
- 20.21.22.23
- 24.25.26.27
- 24.25.26.28
ok: [ATL_isr_lab] =>
msg:
- 28.29.30.31
- 32.33.34.35
- 32.33.34.36
Got it working as posted originally. I had to upgrade to ansible version 2.11.6. I'm running Debian 10 and apt-get update/apt-get upgrade did not find a newer version.
My solution involved deleting the version and installing it again through pip. After that, I ran the code and it worked flawlessly.

Ansible sum register value

How to get the sum of two hosts with Jinja2 filtering ansible
host1 and host 2
---
- name: Count Check
hosts: MYGROUP
gather_facts: true
user: sv_admin
tasks:
- name: count check
shell: cat /etc/hosts | wc -l
register: command_result
- debug:
var: command_result.stdout
- set_fact:
total_result: "{{ command_result.stdout | map('int') | sum(start=0) }}"
- debug:
msg: "Total count: {{ total_result }}"
Playbook Output
TASK [debug] *****************************************************************
ok: [Host-01] => {
"msg": "Total count: 134"
}
ok: [Host-02] => {
"msg": "Total count: 133"
}
Use extract and sum. For example, the playbook below
shell> cat playbook.yml
- hosts: test_01:test_03
gather_facts: false
tasks:
- shell: cat /etc/hosts | wc -l
register: command_result
- debug:
var: command_result.stdout
- set_fact:
total_result: "{{ ansible_play_hosts_all|
map('extract', hostvars, ['command_result', 'stdout'])|
map('int')|
sum }}"
run_once: true
- debug:
var: total_result
gives (abridged)
shell> ansible-playbook playbook.yml
PLAY [test_01:test_03] ****
TASK [shell] ****
changed: [test_01]
changed: [test_03]
TASK [debug] ****
ok: [test_01] => {
"command_result.stdout": " 62"
}
ok: [test_03] => {
"command_result.stdout": " 31"
}
TASK [set_fact] ****
ok: [test_01]
TASK [debug] ****
ok: [test_03] => {
"total_result": "93"
}
ok: [test_01] => {
"total_result": "93"
}
See serial
See the difference between ansible_play_hosts and ansible_play_hosts_all
You can use custom stats to do that: https://docs.ansible.com/ansible/latest/modules/set_stats_module.html
So for your case it would look like
---
- name: Count Check
hosts: MYGROUP
gather_facts: true
user: sv_admin
tasks:
- name: count check
shell: cat /etc/hosts | wc -l
register: command_result
- debug:
var: command_result.stdout
- set_fact:
host_result: "{{ command_result.stdout }}"
- debug:
msg: "Count for this host: {{ host_result }}"
- set_stats:
data: "{{ { 'total_count': host_result | int } }}"
Then if you run it with ANSIBLE_SHOW_CUSTOM_STATS=yes it will show you the result at the end:
$ ANSIBLE_SHOW_CUSTOM_STATS=yes ansible-playbook -i inventory pb.yml
... (usual output)
CUSTOM STATS: *************************************************************
RUN: { "total_count": 267}
The set_stats task adds results together from all the hosts by default, which is what you are looking for. You need to make sure the values are integers though, because if they are strings it will just concatenate them and you will end up with something like RUN: { "total_count": "134133"}. That's why I have put the data: bit the way I have - if you try to create the dictionary in regular yaml, like
data:
total_count: "{{ host_result | int }}"
you will see that the value is still a string (due to the way yaml/jinja works) and it won't work properly.

How do i count task success/failure in ansible?

I am using ansible to set up a distributed application. i'm installing nodes, and then creating virtual interfaces, and cannot have more virtual interfaces than nodes. therefore, if i install on X nodes, and Y nodes fail, I need to check there are no more that (X-Y) virtual interfaces.
Is there a way to get, for a specific task, a numerical value of how many nodes succeeded/failed, so i can later use it to check the number of virtual interfaces?
Use ansible-runner. See Runner Artifact Job Events and "stats" in particular. For example ansible-runner and the playbook
shell> cat private3/project/test.yml
- hosts: test_01:test_02
gather_facts: false
tasks:
- debug:
var: inventory_hostname
- fail:
msg: Fail test_02
when: inventory_hostname == 'test_02'
shell> ansible-runner -p test.yml -i ID01 run private3
...
ASK [fail] ********************************************************************
skipping: [test_01]
fatal: [test_02]: FAILED! => {"changed": false, "msg": "Fail test_02"}
...
created records in the directory private3/artifacts/ID01/job_events/. I'm not aware of any publicly available tool to analyze the events. I've created a playbook that displays failed tasks
shell> cat pb.yml
- hosts: localhost
gather_facts: false
vars:
events_dir: private3/artifacts/ID01/job_events
tasks:
- find:
paths: "{{ events_dir }}"
register: result
- include_vars:
file: "{{ item }}"
name: "{{ 'my_var_' ~ my_idx }}"
loop: "{{ result.files|json_query('[].path') }}"
loop_control:
index_var: my_idx
label: "{{ my_idx }}"
- set_fact:
my_events: "{{ my_events|default({})|
combine({my_key: lookup('vars', my_key)}) }}"
loop: "{{ range(0, result.matched)|list }}"
loop_control:
index_var: my_idx
vars:
my_key: "{{ 'my_var_' ~ my_idx }}"
- set_fact:
my_list: "{{ my_events|json_query('*.{counter: counter,
event: event,
task: event_data.task_action,
host: event_data.host}') }}"
- debug:
var: item
loop: "{{ my_list|sort(attribute='counter') }}"
loop_control:
label: "{{ item.counter }}"
when: item.event == 'runner_on_failed'
gives
shell> ansible-playbook pb.yml
...
skipping: [localhost] => (item=11)
ok: [localhost] => (item=12) => {
"ansible_loop_var": "item",
"item": {
"counter": 12,
"event": "runner_on_failed",
"host": "test_02",
"task": "fail"
}
}
skipping: [localhost] => (item=13)
...
Feel free to fit the playbook to your needs.

Ansible : error in calling the groups through restapi

I am trying fetch to distinct groups in the inventory through a variable.this is the command am trying to run in the playbook to add hosts to the Nagios XI. Am trying to do this using Rest API through CURL command. Am getting error as Incorrect pattern. Can some one please advise about the issue. or help me out with how we can call two groups from the inventory in the same command.
- name: add host to nagios XI.
shell: curl -XPOST "http://16.231.22.60/nagiosxi/api/v1/config/host?apikey=qfOQpKFORCNo7HPunDUsSjW7f2rNNmrdVv3kvYpmQcNdSS2grV2jeXKsgbv3QgfL&pretty=1" -d "host_name={{ item.hostname }}&address={{ item.address }}&use=xiwizard_ncpa_host&max_check_attempts=5&check_period=xi_timeperiod_24x7&notification_interval=60&notification_period=xi_timeperiod_24x7&notifications_enabled=0&contacts=nagiosadmin&contact_groups=Candle Admins,Candle-L1-L2-Internal&applyconfig=1"
with_items:
- { hostname: "{{ groups['grp1'] }}", address: "{{ groups['grp2'] }}"}
EDIT: code formatting
Understanding that your hostname and address from each group match each other you can do the following:
Inventory:
[grp1]
host1
host2
host3
[grp2]
10.100.10.1
10.100.10.2
10.100.10.3
Play:
---
- name: Debug Together
hosts: localhost
gather_facts: False
tasks:
- name: Add host to nagios XI
shell: shell: curl -XPOST "http://16.231.22.60/nagiosxi/api/v1/config/host?apikey=qfOQpKFORCNo7HPunDUsSjW7f2rNNmrdVv3kvYpmQcNdSS2grV2jeXKsgbv3QgfL&pretty=1" -d "host_name={{ item.0 }}&address={{ item.1 }}&use=xiwizard_ncpa_host&max_check_attempts=5&check_period=xi_timeperiod_24x7&notification_interval=60&notification_period=xi_timeperiod_24x7&notifications_enabled=0&contacts=nagiosadmin&contact_groups=Candle Admins,Candle-L1-L2-Internal&applyconfig=1"
with_together:
- "{{ groups['grp1'] }}"
- "{{ groups['grp2'] }}"
You will get something like:
TASK [debug] ******************************************************************************************************************
ok: [localhost] => (item=None) => {
"item.0, item.1": "(u'host1', u'10.100.10.1')"
}
ok: [localhost] => (item=None) => {
"item.0, item.1": "(u'host2', u'10.100.10.2')"
}
ok: [localhost] => (item=None) => {
"item.0, item.1": "(u'host3', u'10.100.10.3')"
}
Comming from my test:
- name:
debug:
var: item.0, item.1
with_together:
- "{{ groups['grp1'] }}"
- "{{ groups['grp2'] }}"

Resources