Ansible/Jinja2 - Map nested key in list - filter

When map'ing a attribute in a list of nested variables, I am not able to retrieve its key.
I want to retrieve the key of "tls_cert_file" from followingemphasized text variables:
vault_config_listener:
- tcp:
- address: "0.0.0.0:8200"
- tls_cert_file: "/etc/ssl/wildcard.crt"
- tls_key_file: "/etc/ssl/private/wildcard.key"
- tls_require_and_verify_client_cert: "false"
- tcp:
- address: "127.0.0.1:8200"
- tls_disable: true
The debug task:
- debug:
msg: "{{ (vault_config_listener | selectattr('tcp', 'defined') | map(attribute='tcp')) | selectattr('tls_cert_file','defined') | map(attribute='tls_cert_file') | join('') | dirname }}"
The output:
ok: [test] => {
"msg": ""
}
I got the map'ing working until "tcp", but no further... What is wrong at the logic?

To get a list of tls_cert_file you can use
vault_config_listener | selectattr('tcp', 'defined') | map(attribute='tcp') | sum(start=[]) | selectattr('tls_cert_file','defined') | map(attribute='tls_cert_file') | list
note sum(start=[]) – it is used to flatten list of lists.
P.S. Why do you join possible(?) multiple paths into string?
P.P.S Your data structure seems rather weird. Why do you define tcp properties like list, and not just:
tcp:
address: 0.0.0.0:8200
tls_cert_file: /etc/ssl/wildcard.crt
tls_key_file: /etc/ssl/private/wildcard.key
tls_require_and_verify_client_cert: false

Related

Return IP addresses from a list in quotes - Ansible

Hoping someone can assist. I'm trying to extract IP addresses from a list so that they may be used in a URI call in Ansible, so the basic code I have is
Vars:
servers:
- name: Backups
ipaddr:
- "192.168.10.10"
- "192.168.20.10"
- "192.168.30.10"
Then I run this code
- name: list vars
debug:
msg: "{{ item.ipaddr | flatten | join (',')}}"
loop: "{{servers}}"
But the output is
"msg": "192.168.40.10,192.168.50.10,192.168.60.10"
Whereas I need this returned with the quotes
"msg": "192.168.40.10","192.168.50.10","192.168.60.10"
Sure I am missing something obvious but any help would be gratefully received
Thanks to Jinja_dude but managed to fix this with
{{ item.ipaddr | to_json | join() }}
Which produced the result
"msg": [
"192.168.40.10",
"192.168.50.10",
"192.168.60.10"
]
And this was accepted in my URI call
Hello steve I think a way of achieving something similar is using this :
"{{ item.ipaddr | map('quote') | flatten | join(', ') }}"
Otherwise there is also this already implemented filter in ansible that will help you have each ip between quotes :
"{{ item.ipaddr | map("regex_replace","(.+)","\'\\1\'") | flatten | join(',')}}"

Filter a dictionary based on key

I have a dict like this
{"product_1": [
"account1",
"account2"
],
"product_2": [
"account1",
"account2"
],
...
"product_10": [
"account1",
"account2"
]}
How to filter this dict based on the key?
There are specific jinja2 filters for that: selectattr and rejectattr.
But those work on a list of dicts, not on a dict itself. You will have to use dict2items and items2dict to work around that.
Here are some example usage:
# Values are dicts, select only items with specific attribute defined.
result: "{{ my_dict | dict2items | selectattr('value.my_attribute', 'defined')
| list | items2dict }}"
# Values are lists (as in your example), check for an existing item value.
result: "{{ my_dict | dict2items | selectattr('value', 'contains', 'some item')
| list | items2dict }}"
# Values are dict. Reject elements when attributes has a specific value.
result: "{{ my_dict | dict2items | rejectattr('value.my_attribute', '==', 'Does not apply')
| list | items2dict }}"
Check the above documentations and the rest of the filters for an exhaustive view of all the possibilities.
you could use dict2items to reformat the elements to have the names you are searching for as keys, then pass it to map filter to get those keys:
---
- hosts: localhost
gather_facts: false
vars:
myvar:
product_1:
- account1
- account2
product_2:
- account1
- account2
product_10:
- account1
- account2
tasks:
- name: extract the list of keys
debug:
msg: '{{ myvar | dict2items | map(attribute="key") | list }}'
cheers

Filter webhook payload for modified repositories

I'm building a pipeline with Gitlab and AWX and need to filter the payload of the webhook. What I need is basically parsing only project1 and project2 (which is between two /) into a variable which I can use in other roles.
tower_webhook_payload:
after:
before:
checkout_sha:
commits:
- id:
message:
title:
timestamp:
url: >-
author:
name:
email:
added: []
modified:
- repository/project1/file1
removed: []
- id:
message:
title:
timestamp:
url: >-
author:
name:
email:
added:
modified:
- repository/project2/file2
removed: []
This was my rough idea but I don't have much experience working with lists or regex.
- debug: msg="{{ tower_webhook_payload.commits | select('match', 'modified') | list }}"
"msg": "Unexpected templating type error occurred on ({{ tower_webhook_payload.commits | select('match', 'modified') | list }}): expected string or bytes-like object"}
One way to achieve this:
extract the modified list attribute of each commits.
flatten the result so you get a single list of all gathered elements.
map the regex_replace filter to each element to extract only the project name. The below regex capture everything after the initial repository/ that does not contain a / and replaces the entire match only with that capture
apply the unique filter so you eliminate duplicates if any
---
- debug:
msg: "{{ tower_webhook_payload.commits | map(attribute='modified') | flatten
| map('regex_replace', 'repository/([^/]*)/.*', '\\1') | unique }}"
Edit: with older versions of ansible, you might have to explicitely cast to list after maping
---
- debug:
msg: "{{ tower_webhook_payload.commits | map(attribute='modified')
| list | flatten
| map('regex_replace', 'repository/([^/]*)/.*', '\\1')
| list | unique }}"
how about using json_query like:
- debug: msg="{{ tower_webhook_payload | json_query(\"commits[].modified[0]\") }}"

Ansible get first element from list

Suppose I have the following vars_file:
mappings:
- primary: 1.1.1.1
secondary: 2.2.2.2
- primary: 12.12.12.12
secondary: 11.11.11.11
and hosts file
1.1.1.1
12.12.12.12
5.5.5.5
and the following playbook task
- name: Extract secondary from list
debug:
msg: "{{ (mappings | selectattr('primary', 'search', inventory_hostname) | list | first | default({'secondary':None})).secondary }}"
The current task works and will give empty string when no match are found, but I would like to know if there is a better way/cleaner way of doing it without passing a dictionary to the default constructor.
An option would be to use json_query
- debug:
msg: "{{ mappings | json_query(\"[?primary=='\" + inventory_hostname + \"'].secondary\") }}"
, but selectattr works too
- debug:
msg: "{{ mappings | selectattr('primary', 'equalto', inventory_hostname) | map(attribute='secondary') | list }}"

In Ansible, how to filter a dictionary based on regex pattern on the keys?

I need to extract a subset of a dictionary based on a pattern on the key names.
For example, in the v below I need to extract the key->values section1*.
The code below assigns the list of values, but I still haven't found a way to preserve the key->map setting.
- set_fact:
v:
section1_1: true
section1_2: false
section2_1: true
section2_2: false
section3: true
- set_fact:
v2: "{{ v | select('match','^section1_.*') | map('extract', v) | list }}"
- debug:
var: v2
Any help, please?
Thanks.
Combine dict2items and items2dict filters:
- debug:
msg: "{{ v | dict2items | selectattr('key', 'match', '^section1') | list | items2dict }}"
fatal: [localhost]: FAILED! => {"msg": "template error while templating string: no filter named 'items2dict'. String: {{ v | dict2items | selectattr('key', 'match', '^section1_') | list | items2dict }}"}
If I look at the sources in /usr/lib/python2.7/dist-packages I see that there are references to it, but not real function definitions
ansible/plugins/filter/core.py: raise AnsibleFilterError("items2dict requires a list, got %s instead." % type(mylist))
ansible/plugins/filter/core.py: 'items2dict': list_of_dict_key_value_elements_to_dict,
I'm runing 2.5.1. Do I need a later version?

Resources