Ansible nested variable - filter

I have a variable like this:
unicast_ip_group: "{{ groups['elasticsearch-demo'] | map('extract', hostvars, ['ansible_host']) | join(':9300,') }}:9300"
I want to make the static value elasticsearch-demo a variable. I have tried this but this looks like is not supported in Ansible:
unicast_ip_group: "{{ groups['{{ my_variable }}'] | map('extract', hostvars, ['ansible_host']) | join(':9300,') }}:9300"

The following should work:
unicast_ip_group: "{{ groups[my_variable] | map('extract', hostvars, ['ansible_host']) | join(':9300,') }}:9300"
You already opened a Jinja2 expression with {{, so you can use variables just by referring their names.

Related

how to set default value if key is not available in dict in ansible play

I am setting fact as dict using host names like below,
set_fact:
processed_hosts: "{{ processed_hosts | default([]) + [dict(host_name=item, result=hostvars[item]['_OS_upgraded'])] }}"
with_items:
- "{{ groups['reachable_a_hosts'] }}"
Its working good when all the host has "_OS_upgraded".
But when task failed in any of the host then "_OS_upgraded" is not set, on that scenario i am getting error when i call this hostvars[item]['_OS_upgraded']
so want to set it false by default if that item is not in hostvars,
Can some one let me know how to do that?
It worked after adding | default(False)
set_fact:
processed_hosts: "{{ processed_hosts | default([]) + [dict(host_name=item, result=hostvars[item]['_OS_upgraded']|default(False))] }}"
with_items:
- "{{ groups['reachable_a_hosts'] }}"

How do I filter a list by existance of an attribute in ansible/jinja2?

G'day everyone.
I have two ansible tasks like this, running over the 'workernodes' group in the inventory file:
- name: count remote files
find:
paths: "{{ data_path }}"
register: exported_files
- name: sum up number of remote files
set_fact:
sum_of_exported_files: "{{ groups[ workernodes ] | map('extract', hostvars, 'exported_files') | map(attribute='matched') | sum }}"
run_once: yes
This works fine as long as all are nodes available. But if the find-Task count not run on any of the workernodes i get in error in the sum-up task. There is no exported_files variable on for this node, so the mapping to the attribute fails.
How can i filter for the existance of the exported_files attribute in the extarcted hostvars list?
Please EnlightMe
Thanks.
How about adding this when: clause:
when: groups[ workernodes ] | map('extract', hostvars, 'exported_files')|list|first|length > 0"
G'day everyone,
finally i found the (really simple) answer by myself:
sum_of_exported_files: "{{ groups[ workernodes ] | map('extract', hostvars, 'exported_files') | select("defined") | map(attribute='matched') | select("number") | sum }}"
Thanks isabellema for your thought that helped me to think it over.

How to filter a dictionary using regex on value

I need to filter a dictionary in ansible based on regex matching it's values.
mydict:
some_value: /my/path
another_value: 2345
anotherpath: /my/other/path
What I tried is:
set_fact:
newvar: "{{ mydict | dict2items | selectattr('value', 'match', '^/my/.+$') | list }}"
But what i get is:
expected string or buffer
How can I filter all values based on part of their string for using them later in with_items?
The issue you currently have is that the regex match cannot handle integers. This will solve your issue, though it's slightly more verbose:
- set_fact:
file_list: []
- set_fact:
file_list: "{{ file_list + [item.value] }}"
when: item.value|string | match('^/my/.+$')
loop: "{{ mydict | dict2items }}"
If you can ensure that all values will always be strings, then you could use:
- set_fact:
newvar: "{{ mydict | dict2items | selectattr('value', 'match', '^/my/.+$') | map(attribute='value') | list }}"
Thanks #matt-p for clarifying :-) I didn't know this was actually caused by the match function itself. Is this more like an issue I should report to the Ansible community?
BTW I changed your code a little bit to fit the actual Ansible standard (the when condition is using deprecated syntax):
- set_fact:
file_list: []
- set_fact:
file_list: "{{ file_list + [item.value] }}"
when:
- item.value is string
- item.value is match('^/my/.+$')
with_items: "{{ mydict | dict2items }}"

Multiple facts retrieved in set_fact task causes playbook run to issue error

Multiple facts retrieved using set_fact in playbook, causes error
I have tried separate set_fact tasks, 1 per fact retrieved. Also got error.
Seems to occur when I have 3 facts defined under set_fact i.e when I include mountsize_tmp. No error when I have the first 2 facts only.
Does a variable name used in set_fact need to be defined in the var variables section?
Error is:
The offending line appears to be: set_fact: ^ here exception type: exception: No first item, sequence was empty.
- set_fact:
alto_seal: "{{ ansible_local.alto_bootstrap.seal }}" # local fact
mountsize: "{{ ansible_mounts | selectattr('mount', 'equalto', '/abc') | map(attribute='size_total') | first }}" # ansible fact
mountsize_tmp: "{{ ansible_mounts | selectattr('mount', 'equalto', '/tmp') | map(attribute='size_total') | first }}"
- debug:
msg: "{{ 'Alto start mountsize ' ~ mountsize }}"
- debug:
msg: "{{'Seal ' ~ alto_seal }}"
Expect values of a file mount a size and a fact from a custom fact file to be displayed in 2 rows
To avoid your exception you can manage that by:
Defining default values:
- set_fact:
alto_seal: "{{ ansible_local.alto_bootstrap.seal }}" # local fact
- set_fact:
mountsize: "<DEFAULT_VALUE_OF_YOUR_CHOICE>"
mountsize_tmp: "<DEFAULT_VALUE_OF_YOUR_CHOICE>"
- set_fact:
mountsize: "{{ ansible_mounts | selectattr('mount', 'equalto', '/abc') | map(attribute='size_total') | first }}" # ansible fact
when: ansible_mounts | selectattr('mount', 'equalto', '/abc') | map(attribute='size_total') | list != []
- set_fact:
mountsize_tmp: "{{ ansible_mounts | selectattr('mount', 'equalto', '/tmp') | map(attribute='size_total') | first }}"
when: ansible_mounts | selectattr('mount', 'equalto', '/tmp') | map(attribute='size_total') | list != []
or
Sending a specific message:
- set_fact:
alto_seal: "{{ ansible_local.alto_bootstrap.seal }}" # local fact
- set_fact:
mountsize: "{{ ansible_mounts | selectattr('mount', 'equalto', '/abc') | map(attribute='size_total') | first }}" # ansible fact
msg: "{{ 'Alto start mountsize ' ~ mountsize }}"
when: ansible_mounts | selectattr('mount', 'equalto', '/abc') | map(attribute='size_total') | list != []
- set_fact:
msg: "Alto start mountsize cannot be calculated"
when: ansible_mounts | selectattr('mount', 'equalto', '/abc') | map(attribute='size_total') | list == []
- debug:
msg: "{{ msg }}"

How to pick only those keys of a map, where values satisfy a condition?

Suppose, I have a map of PIPs:
pips:
dispy: "4.9.1"
psutil: "latest"
pyodbc: "latest"
foo: "absent"
and wish to use the Ansible pip-module to install/upgrade/remove them.
How do I filter only those of names from the pips, where the value is set to latest?
Update: using the recipe by #techraf I was able to come up with the following:
- name: Install PIPs by explicit versions
pip:
name: "{{ item }}"
executable: "{{ pip }}"
version: "{{ pips[item] }}"
loop: >-
{{ pips | dictsort | rejectattr(1, 'in', '["latest", "absent"]') | map('first') | list }}
- name: Upgrade or remove other PIPs as prescribed
pip:
name: "{{ item }}"
executable: "{{ pip }}"
state: "{{ pips[item] }}"
loop: >-
{{ pips | dictsort | selectattr(1, 'in', '["latest", "absent"]') | map('first') | list }}
Which works, but is unsatisfying -- because the original pips-map is turned into another object using dictsort and then again into a list. And each instance of the task still needs to look up the value (to set either the version or the state clause) to execute anyway...
There is got to be a better way...
For example:
{{ pips | dictsort | selectattr(1, 'equalto', 'latest') | map('first') | list }}
yields a list:
[
"psutil",
"pyodbc"
]

Resources