building variable name (list) in Jinja - list

my pb is the following :
I have a group_vars file called dns.yml
DNS_LIST_EMEA:
- EMEA:
DNS_IPv4: IP1
- AMER:
DNS_IPv4: IP2
- APAC:
DNS_IPv4: IP3
DNS_LIST_AMER:
- AMER:
DNS_IPv4: IP3
- EMEA:
DNS_IPv4: IP1
- APAC:
DNS_IPv4: IP2
In my jijna template, to configure my router, I have in its data file the variable REGION set to EMEA
my question is how can I build the list name : "DNS_LIST_"+{{REGION}} in order to access the #IPs:
{% for DNS in DNS_LIST_{{REGION}} -%}
set system name-server {{DNS.DNS_IPv4}}
{% endfor %}
above is not working, as it sees DNS_LIST_{{REGION}} as a string and not a list
Thx

Related

Ansible jinja2 regex search fails to properly find the beginning of string

I'm using
ansible 2.9.27
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /bin/ansible
python version = 2.7.5 (default, May 27 2022, 11:27:32) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
Pursuant to my question here: Ansible set_fact list using jinja , I am trying to create a list which is derived from a list, but with an element removed: if it contains "default" at the beginning of the list element string, remove it. But why doesn't the regex work properly? The sticking point is the beginning of string operator.
Here is my list:
[ u'default via 10.13.99.1 dev bond0.99',
u'10.13.101.0/23 dev p1p1.101',
u'128.1.66.227 via 10.13.201.1 dev p1p1.201' ]
It's called found_routes. When I try to filter out the first entry, the default route, I attempt:
- name: Populate appended route list
set_fact:
found_added_routes: "{{ found_routes | select('search', ' via ') | reject('regex', '^default') | list }}"
That doesn't work. But this does:
- name: Populate appended route list
set_fact:
found_added_routes: "{{ found_routes | select('search', ' via ') | reject('regex', '^..default') | list }}"
...what are those two invisible characters that my regex is finding?
Here is how I create output:
- name: Debug found_routes
debug:
msg: "Found route list: {{ item }}"
loop: "{{ found_routes }}"
- name: Debug found_added_routes
debug:
msg: "Found: {{ item }}"
loop: "{{ found_added_routes }}"
And here's the output from the successful set_fact:
TASK [networks : Debug found_route_list] **********************************************************************************************************************
ok: [server01.example.com] => (item=default via 10.13.99.1 dev bond0.99) => {
"msg": "Found route list: default via 10.13.99.1 dev bond0.99"
}
ok: [server01.example.com] => (item=10.13.101.0/24 dev p1p1.101) => {
"msg": "Found route list: 10.13.101.0/24 dev p1p1.101"
}
ok: [server01.example.com] => (item=128.1.66.227 via 10.13.101.1 dev p1p1.101) => {
"msg": "Found route list: 128.1.66.227 via 10.13.101.1 dev p1p1.101"
}
TASK [networks : Debug found_added_routes] **********************************************************************************************************************
ok: [server01.example.com] => (item=10.13.101.0/24 dev p1p1.101) => {
"msg": "Found: 10.13.101.0/24 dev p1p1.101"
}
ok: [server01.example.com] => (item=128.1.66.227 via 10.13.101.1 dev p1p1.101) => {
"msg": "Found: 128.1.66.227 via 10.13.101.1 dev p1p1.101"
}
But as you can see, in order to get rid of that first "default" route, I needed to use ^..default instead of ^default and I'm at a loss to understand why.
OK, because of the jinja2 magic that I did in my original question, which was to do this:
- name: Populate appended route list
set_fact:
found_added_routes: |-
{%- set blah = [] %}
{%- for line in found_route_list %}
{%- set _ = blah.append(line) %}
{%- endfor %}
{{ blah }}
...the output was a string that had elements literally like this: u'default via 10.13.99.1 dev bond0.99'
So the string begins not with default... but rather with a literal 'u' and tick mark, sa: u'default...
The first two characters of the string are u and '. Not d and e as I was expecting.
My mistake!

Extract values from a list of dictionaries in Ansible

I have this playbook and I need to find a way to display the values of the list of dictionaries under prerequisite knowing that we have different key names. how can I display theses values keeping the same syntax of my playbook?
Expected output:
"linux/mysql/8.0.19/prerequis/mysql-community-common-8.0.19-1.el7.x86_64.rpm"
"mysql-community-common-8.0.19-1.el7.x86_64"
"linux/mysql/8.0.19/prerequis/mysql-community-libs-8.0.19-1.el7.x86_64.rpm"
"mysql-community-libs-8.0.19-1.el7.x86_64"
"linux/mysql/8.0.19/prerequis/mysql-community-client-8.0.11-1.el7.x86_64.rpm"
"mysql-community-client-8.0.11-1.el7.x86_64"
"linux/mysql/8.0.19/prerequis/mysql-shell-8.0.19-1.el7.x86_64.rpm"
"mysql-shell-8.0.19-1.el7.x86_64"
- name: "extract values from a list of dictionaries"
hosts: localhost
tasks:
- name: "adding variables"
set_fact:
products:
mysql_8_0_19:
CentOS_7:
signature: "mysql-community-server-8.0.19-1.el7.x86_64"
url: "linux/mysql/8.0.19/mysql-community-server-8.0.19-1.el7.x86_64.rpm"
pymysql_url: "linux/mysql/8.0.19/prerequis/PyMySQL-0.9.3.tar.gz"
prerequisite:
- mysql_c_common_url: "linux/mysql/8.0.19/prerequis/mysql-community-common-8.0.19-1.el7.x86_64.rpm"
mysql_c_common_signature: "mysql-community-common-8.0.19-1.el7.x86_64"
- mysql_c_libs_url: "linux/mysql/8.0.19/prerequis/mysql-community-libs-8.0.19-1.el7.x86_64.rpm"
mysql_c_libs_signature: "mysql-community-libs-8.0.19-1.el7.x86_64"
- mysql_c_client_url: "linux/mysql/8.0.19/prerequis/mysql-community-client-8.0.11-1.el7.x86_64.rpm"
mysql_c_client_signature: "mysql-community-client-8.0.11-1.el7.x86_64"
- mysql_shell_url: "linux/mysql/8.0.19/prerequis/mysql-shell-8.0.19-1.el7.x86_64.rpm"
mysql_shell_signature: "mysql-shell-8.0.19-1.el7.x86_64"
- name: " display "
debug:
msg: "{{ item }}"
with_items: "{{ products.mysql_8_0_19.prerequisite }}"'
Getting the values of a dictionary in Ansible with an "unknown" set of keys usually call for the usage of dict2items.
Your use case does fit the bill, you just have to map this filter on all elements of the prerequisite list, then flatten it and finally extract the values with another map filter.
So, you can achieve what you need with the task:
- debug:
msg: "{{ item }}"
loop: >-
{{
products.mysql_8_0_19.prerequisite
| map('dict2items')
| flatten
| map(attribute='value')
}}
You might want to add a | list filter at the end if you are on an old version of Ansible and get an error like <generator object do_map at 0x7f3xxxxx>
Given the task:
- debug:
var: >-
products.mysql_8_0_19.prerequisite
| map('dict2items')
| flatten
| map(attribute='value')
vars:
products:
mysql_8_0_19:
prerequisite: "{{ prerequisite }}"
prerequisite:
- mysql_c_common_url: >-
linux/mysql/8.0.19/prerequis{#- allows line wrap -#}
/mysql-community-common-8.0.19-1.el7.x86_64.rpm
mysql_c_common_signature: >-
mysql-community-common-8.0.19-1.el7.x86_64
- mysql_c_libs_url: >-
linux/mysql/8.0.19/prerequis{#- allows line wrap -#}
/mysql-community-libs-8.0.19-1.el7.x86_64.rpm
mysql_c_libs_signature: >-
mysql-community-libs-8.0.19-1.el7.x86_64
- mysql_c_client_url: >-
linux/mysql/8.0.19/prerequis{#- allows line wrap -#}
/mysql-community-client-8.0.11-1.el7.x86_64.rpm
mysql_c_client_signature: >-
mysql-community-client-8.0.11-1.el7.x86_64
- mysql_shell_url: >-
linux/mysql/8.0.19/prerequis{#- allows line wrap -#}
/mysql-shell-8.0.19-1.el7.x86_64.rpm
mysql_shell_signature: >-
mysql-shell-8.0.19-1.el7.x86_64
This yields:
- linux/mysql/8.0.19/prerequis/mysql-community-common-8.0.19-1.el7.x86_64.rpm
- mysql-community-common-8.0.19-1.el7.x86_64
- linux/mysql/8.0.19/prerequis/mysql-community-libs-8.0.19-1.el7.x86_64.rpm
- mysql-community-libs-8.0.19-1.el7.x86_64
- linux/mysql/8.0.19/prerequis/mysql-community-client-8.0.11-1.el7.x86_64.rpm
- mysql-community-client-8.0.11-1.el7.x86_64
- linux/mysql/8.0.19/prerequis/mysql-shell-8.0.19-1.el7.x86_64.rpm
- mysql-shell-8.0.19-1.el7.x86_64

Ansible List Variable and Select Filter to ignore matched items

I have a variable dir_lst_raw in an ansible playbook whose value is a list as shown below:
"dir_lst_raw": [
"/path1/dir1/user",
"/path2/dir2/admin",
"/path3/dir3/user.ansible_backup_2020-03-16",
"/path1/dir1/config.ansible_backup_2020-03-16",
"/path2/dir2/dir3/somefile"
]
I need to remove all the lines containing .ansible_backup_ and save to another variable as a list.
I've googled for regex and tried to not match the pattern with the select filter as below:
- set_fact:
dir_lst: "{{ dir_lst_flt_r | select('match','(^.ansible_backup_)+') | list }}"
but the new variable dir_lst turned out as an empty list. I am expecting dir_lst as below:
"dir_lst_raw": [
"/path1/dir1/user",
"/path2/dir2/admin",
"/path2/dir2/dir3/somefile"
]
Could somebody please suggest how can I get it done?
Q: "Remove all the lines containing .ansible_backup_"
A: The task below does the job
- set_fact:
dir_lst: "{{ dir_lst_raw|reject('match', my_regex)|list }}"
vars:
my_regex: '^(.*)\.ansible_backup_(.*)$'
- debug:
var: dir_lst
gives
dir_lst:
- /path1/dir1/user
- /path2/dir2/admin
- /path2/dir2/dir3/somefile

Ansible consume AD command output

i got a problem how to consume the following command output in Ansible
basically im trying to get the list of Active Directory OUs and loop over that list to search for specific name. My script works well when multiple OUs exists but i have an issue when only single OU exists. Explained below
tasks:
- name: PS - Pull System OUs from AD
win_command: powershell -
args:
stdin: "Get-ADOrganizationalUnit -LDAPFilter '(name=*)' -SearchScope 1 -SearchBase 'OU=SYSTEMS,DC=domain,DC=int' -Server domain.int | select-object name | ConvertTo-json"
become: yes
register: ou_reg_out
- name: Select Systems OU
block:
- name: Set list of standardized OUs as facts
set_fact:
ou_reg_list: "{{ ou_reg_out.stdout }}"
- name: Set System OU for system
set_fact:
ou_name: "OU={{item.name}}"
loop: "{{ ou_reg_list }}"
when: (item.name|upper) == (srv_type|upper)
when: ou_reg_out.stdout|length != 0
basically i need to be able to loop over the ou_reg_out.stdout.
It works when command returns multiple OUs as ou_reg_out.stdout returns list:
ou_reg_out.stdout:
- { name: OU1 }
- { name: OU2 }
issue is when only single OU exists , command doesnt return the list
ou_reg_out.stdout:
{ name: OU1 }
Any idea how to workaround this problem ?
Test the type of the variable and branch the code.
json_query filter helps to select the items from the list. Then ternary helps to conditionally select the value. The value of the first item that matches the condition is used. Defaults to 'NOTFOUND'.
For example the play bellow for both versions of ou_reg_list
- hosts: localhost
vars:
ou_reg_list:
- { name: OU1 }
- { name: OU2 }
# ou_reg_list:
# { name: OU1 }
srv_type: 'ou1'
tasks:
- set_fact:
ou_name: "OU={{ (ou_reg_list.name == srv_type|upper)|
ternary( ou_reg_list.name, 'NOTFOUND') }}"
when: ou_reg_list is mapping
- block:
- set_fact:
ou_names: "{{ ou_reg_list|json_query(query) }}"
vars:
query: "[?name=='{{ srv_type|upper }}'].name"
- set_fact:
ou_name: "OU={{ (ou_names|length > 0)|
ternary( ou_names.0, 'NOTFOUND') }}"
when: ou_reg_list is not mapping
- debug:
var: ou_name
gives
"ou_name": "OU=OU1"

ANSIBLE - how to concatenate a string with a list

I am trying to concatenate a string which is referenced as variable with a nested list
I looked into the options of using the set_fact and join but to no avail.
#config.yml
- name: concatenate
module_name:Test
state: present
port: {{ env_dc }}{{item.ports}}
with_items:
- "{{ my_list }}"
#group_vars\all.yml
env_dc: uk
my_list:
- {name: switch1, ports: [p1, p2, p3, p4]}
I am expecting the following output:
ukp1
ukp2
ukp3
ukp4
But I am getting;
"item": {
"ports": [
"p1",
"p2",
"p3",
"p4"
]
Actual Playbook:
Error message:
If you write this:
port: {{ env_dc }}{{item.ports}}
You are not producing a new list formated by concatenating the value in env_dc with each item in item.ports; you are simply creating a new string that has the contents of env_dc followed by the string representation of item.ports. That is, in your example, that would evaluate to something like:
uk['p1', 'p2', 'p3', 'p4']
You can solve this using the map filter (which can apply a filter to all items in a list) and the regex_replace filter, like this:
---
- hosts: localhost
gather_facts: false
vars:
env_dc: uk
my_list:
- name: switch1
ports:
- p1
- p2
- p3
- p4
tasks:
- debug:
msg: "ports: {{ item.ports|map('regex_replace', '^', env_dc)|list }}"
with_items: "{{ my_list }}"
Which given your example data would evaluate to:
TASK [debug] **********************************************************************************
ok: [localhost] => (item={u'name': u'switch1', u'ports': [u'p1', u'p2', u'p3', u'p4']}) => {
"msg": "ports: [u'ukp1', u'ukp2', u'ukp3', u'ukp4']"
}