ansible compare DNS list from F5 - ansible

I would like to create a playbook which logs into a big-ip device, downloads a list of certificates and compares it with a list of existing certificates to find matches.
My current playbook is:
---
- name: App Collection f5_modules
hosts: localhost
connection: local
gather_facts: false
vars:
from_ex_var: ["test1.com","test.com","httpsN-dep.san-dc.yu.com"]
from_F5: [
{
"createDateTime": "2022-11-27T09:23:39.000Z",
"expirationDate": 1681379023,
"expirationDateTime": "2023-04-13T09:43:40.000Z",
"subject": "CN=test.com,O=chicago,L=los,ST=Nord,C=PE",
"subjectAlternativeName": "DNS:httpsN-dep.san-dc.yu.com, DNS:test1.com, DNS:test.com",
},
{
"createDateTime": "2023-11-27T09:23:39.000Z",
"expirationDate": 1781379023,
"expirationDateTime": "2023-04-13T09:43:40.000Z",
"subject": "CN=test.com,O=chicago,L=los,ST=Nord,C=PE",
"subjectAlternativeName": "DNS:test.com, DNS:test1.com, DNS:httpsN-dep.san-dc.yu.com",
}
]
tasks:
- name: debug 0
set_fact:
alt_name: "{{ from_ex_var | map('regex_replace', '^(.*)$', 'DNS:\\1') | list | sort }}"
- name: works
debug:
msg: "{{ item.subjectAlternativeName.split(',') | map('regex_replace', '.*DNS:(.*)', 'DNS:\\1') | list | sort }}"
loop: "{{ from_F5 }}"
- name: does not work
debug:
var: item.subjectAlternativeName.split(',') | map('regex_replace', '.*DNS:(.*)', 'DNS:\\1') | list | sort
loop: "{{ from_F5 }}"
- name: checking compare two list
debug:
msg: "works"
loop: "{{ from_F5 }}"
when: item.subjectAlternativeName.split(',') | map('regex_replace', '.*DNS:(.*)', 'DNS:\\1') | list | sort == alt_name
I think the problem is that DNS:\\1 gives me a wrong value in my regex_replace expression in the last when: line as I tried to debug in the following task which gives:
TASK [does not work] *****************************************************************************************************************************************************************************************
ok: [localhost] => (item={'createDateTime': '2022-11-27T09:23:39.000Z', 'expirationDate': 1681379023, 'expirationDateTime': '2023-04-13T09:43:40.000Z', 'subject': 'CN=test.com,O=chicago,L=los,ST=Nord,C=PE', 'subjectAlternativeName': 'DNS:httpsN-dep.san-dc.yu.com, DNS:test1.com, DNS:test.com'}) => {
"ansible_loop_var": "item",
"item": {
"createDateTime": "2022-11-27T09:23:39.000Z",
"expirationDate": 1681379023,
"expirationDateTime": "2023-04-13T09:43:40.000Z",
"subject": "CN=test.com,O=chicago,L=los,ST=Nord,C=PE",
"subjectAlternativeName": "DNS:httpsN-dep.san-dc.yu.com, DNS:test1.com, DNS:test.com"
},
"item.subjectAlternativeName.split(',') | map('regex_replace', '.*DNS:(.*)', 'DNS:\\\\1') | list | sort": [
"DNS:\\1",
"DNS:\\1",
"DNS:\\1"
]
}
When I use the same expression in a debug msg it works as expected.
ok: [localhost] => (item={'createDateTime': '2023-11-27T09:23:39.000Z', 'expirationDate': 1781379023, 'expirationDateTime': '2023-04-13T09:43:40.000Z', 'subject': 'CN=test.com,O=chicago,L=los,ST=Nord,C=PE', 'subjectAlternativeName': 'DNS:test.com, DNS:test1.com, DNS:httpsN-dep.san-dc.yu.com'}) => {
"msg": [
"DNS:httpsN-dep.san-dc.yu.com",
"DNS:test.com",
"DNS:test1.com"
]
}
How can I troubleshoot this condition ?
when: item.subjectAlternativeName.split(',') | map('regex_replace', '.*DNS:(.*)', 'DNS:\\1') | list | sort == alt_name

Related

How to add port to each host in list of lists?

I have a list of lists of hosts:
[['host-0', 'host-1'], ['host-2', 'host-3'], ['host-4', 'host-5', 'host-6']]
How can I add a port number, e.g., 8000, to each host using ansible/ jinja2 to get:
[['host-0:8000', 'host-1:8000'], ['host-2:8000', 'host-3:8000'], ['host-4:8000', 'host-5:8000', 'host-6:8000']]
this task shall do it:
- name: convert items in list
set_fact:
my_new_list: "{{ my_new_list | default([])+ [ my_var ] }}"
vars:
my_var: "{{ item | map('regex_replace', '$', ':8000') | list }}"
with_items:
- "{{ my_list }}"
full playbook to run as demo:
---
- hosts: localhost
gather_facts: false
vars:
my_list:
- ['host-0', 'host-1']
- ['host-2', 'host-3']
- ['host-4', 'host-5', 'host-6']
tasks:
- name: print original variable
debug:
var: my_list
- name: convert items in list
set_fact:
my_new_list: "{{ my_new_list | default([])+ [ my_var ] }}"
vars:
my_var: "{{ item | map('regex_replace', '$', ':8000') | list }}"
with_items:
- "{{ my_list }}"
- name: print new variable
debug:
var: my_new_list
result:
TASK [print new variable] **********************************************************************************************************************************************************************************************
ok: [localhost] => {
"my_new_list": [
[
"host-0:8000",
"host-1:8000"
],
[
"host-2:8000",
"host-3:8000"
],
[
"host-4:8000",
"host-5:8000",
"host-6:8000"
]
]
}
PLAY RECAP
Use map + regex_replace.
- debug:
msg: "{{ foo | map('map', 'regex_replace', '$', ':8000') }}"
vars:
foo: [['host-0', 'host-1'], ['host-2', 'host-3'], ['host-4', 'host-5', 'host-6']]
"msg": [
[
"host-0:8000",
"host-1:8000"
],
[
"host-2:8000",
"host-3:8000"
],
[
"host-4:8000",
"host-5:8000",
"host-6:8000"
]
]

how to use json_query filter to extract all items equals to a value

Here is my json output:
{
"kind": [
{
"inventory": "",
"inventory_sources": "",
"job_templates": "",
"workflow_job_templates": "104"
},
{
"inventory": "",
"inventory_sources": "",
"job_templates": "114",
"workflow_job_templates": ""
},
{
"inventory": "24",
"inventory_sources": "",
"job_templates": "",
"workflow_job_templates": ""
},
{
"inventory": "",
"inventory_sources": "108",
"job_templates": "",
"workflow_job_templates": ""
}
]
}
I'd like to display all items name that contain a specific value. For example, for a search value of 104 I want to get the key name workflow_job_templates
I tested some syntaxes without any success:
- debug:
msg: "104 is {{kind|json_query(query)}}"
vars:
query: "[?*==`104`].workflow_job_templates"
I know it is wrong but can someone tell me how he'd do for himself?
json_query could be part of the equation for your solution but is really not needed here.
Explanation of the below piece of code:
Apply the dict2items filter to each element of your list. This transforms each mapping to a list of {key: "key", value: "value"} pairs
Flatten the given list so we get all those elements to a single top level
Select elements having a value of '104' only
Extract the key attribute of each element in a list
Make that list unique and sort it.
- name: Display all element having a value of 104
debug:
msg: "{{ kind | map('dict2items') | flatten
| selectattr('value', '==', '104')
| map(attribute='key') | unique | sort }}"
Please note that this solution will give you a result if the same key name has different values but one of them is `104. With your above data the result is:
TASK [Display all element having a value of 104] ***************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"workflow_job_templates"
]
}
(Update)
The task below
- debug:
msg: "{{ item }} {{ kind|
map('dict2items')|
map('json_query', query)|
flatten }}"
loop: [104, 114, 108, 24]
vars:
query: "[?to_string(value) == to_string('{{ item }}')].key"
gives
msg: 104 ['workflow_job_templates']
msg: 114 ['job_templates']
msg: 108 ['inventory_sources']
msg: 24 ['inventory']
(For the record. Brute-force approach)
Create a unique list of the keys
- set_fact:
my_keys: "{{ my_keys|default([]) + item.keys()|list }}"
loop: "{{ kind }}"
- set_fact:
my_keys: "{{ my_keys|unique }}"
gives
my_keys:
- inventory
- inventory_sources
- job_templates
- workflow_job_templates
Create a dictionary with all values
- set_fact:
my_dict: "{{ my_dict|default({})|combine({item: values}) }}"
loop: "{{ my_keys }}"
vars:
query: "[].{{ item }}"
values: "{{ kind|json_query(query) }}"
gives
my_dict:
inventory:
- ''
- ''
- '24'
- ''
inventory_sources:
- ''
- ''
- ''
- '108'
job_templates:
- ''
- '114'
- ''
- ''
workflow_job_templates:
- '104'
- ''
- ''
- ''
Then search the dictionary. For example
- debug:
msg: "{{ item }} {{ my_dict|dict2items|json_query(query) }}"
loop: [104, 114, 108, 24]
vars:
query: "[?value[?contains(#, '{{ item }}')]].key"
gives
msg: 104 ['workflow_job_templates']
msg: 114 ['job_templates']
msg: 108 ['inventory_sources']
msg: 24 ['inventory']
The correct alternative of selectattr with json_query is:
- debug:
msg: "{{ kind | map('dict2items') | flatten | json_query(query)}}"
vars:
- query: "[?value == `\"104\"`].key"
If you really just want to use json_query()
---
- name: PLAYBOOK Filtering
hosts: localhost # run locally
tasks:
- name: Create json
set_fact:
kind: '{{ lookup("file", "kind.json") }}'
- name: check the var was created properly
debug:
var: kind
- name: output the element that matches 104
debug:
msg: "{{ kind | json_query(\"kind[?workflow_job_templates=='104'].workflow_job_templates\") }}"
- name:
set_fact:
output: "{{ kind | json_query(\"kind[?workflow_job_templates=='104'].workflow_job_templates\") }}"
Output
TASK [output the element that matches 104] *************************************************************************************************************
ok: [localhost] => {
"msg": [
"104"
]
}

how to get vlan id from vcenter using ansible

I am trying to use below ansible module to get vlan_id information.
- name: Get all portgroups in dvswitch vDS
vmware_dvs_portgroup_find:
hostname: "{{ vsphere_host }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_password }}"
dvswitch: 'test-123' --- dvswitch
validate_certs: no
with_items: "{{ dvswitch_list }}"
register: test
- debug: msg="{{ test }}"
I am getting out in below format.
"results": [
{
"ansible_loop_var": "item",
"changed": false,
"dvs_portgroups": [
{
"dvswitch": "test-123",
"name": "DPortGroup2",
"pvlan": false,
"trunk": false,
"vlan_id": "220"
},
{
"dvswitch": "test-123",
"name": "PP1",
"pvlan": false,
"trunk": false,
"vlan_id": "465"
},
{
"dvswitch": "test-123",
"name": "PP2",
"pvlan": false,
"trunk": false,
"vlan_id": "685"
},
I am using below debug msg to get vlan_id but some how it does not work.
- debug: msg="{{ item.vlan_id }}"
with_items: "{{ test.results.dvs_portgroups }}"
ASK [role_vmware_datastore_size : debug] ********************************************************************************
fatal: [192.168.90.00]: FAILED! => {"msg": "'list object' has no attribute 'dvs_portgroups'"}
test.results is the list of results for each item of the with_items of the vmware_dvs_portgroup_find task. Therefore you have to iterate over this list before accessing a field of each element.
If you want to iterate over all the dvs_portgroups of all the results, you can do that:
- debug: msg="{{ item.vlan_id }}"
with_items: "{{ test.results | map(attribute='dvs_portgroups') | flatten | list }}"
map(attribute='dvs_portgroups') is transforming the list of results into a list of the dvs_portgroups of each result
| flatten is transforming the list of lists (the dvs_portgroups) into a list of all elements of each lists
| list is transforming an iterator back to a list that can be interpreted by with_items
above debug code is working fine. I am getting list of vlan_id. Just to add more details. I have 4 dvswich and getting vlan_id from all dvswtich. I want to make it format like each dvswitch name with there vlan_id.
test-123 -- dvswith name
220
221
222
test-456 -- dvswtich name
300
301
302
I am trying below way but its giving only one vlan_id from each dvswitch.
- name: Final VLAN Details
set_fact:
vlan_details: "{{ vlan_details | default([]) + [dict(name=item[0], size=item[1])] }}"
loop: "{{ dvswitch | zip(vlan_id) | list }}"
loop_control:
label: " "

Extracting nested object in Jinja2

I need to extract IPv4 addresses for specific interface from hostvars in Ansible Jinja2 template without loops using.
Trying to extract 'ansible_eth1' object from hostvars is successful and Ansible provides me all info about `eth1' interface:
- debug:
msg: "{{ groups['my_hosts'] | map('extract', hostvars, 'ansible_eth1') | join(', ') }}"
TASK [my_task : debug] *****************************************************************************************************************************************************************************************************
ok: [server1] => {
"msg": [
{
"active": true,
"device": "eth1",
...
"ipv4": {
"address": "192.168.56.15",
"broadcast": "192.168.56.255",
"netmask": "255.255.255.0",
"network": "192.168.56.0"
},
...
But if I try to extract nested object - 'ipv4.address' - it returns empty list:
- debug:
msg: "{{ groups['my_hosts'] | map('extract', hostvars, 'ansible_eth1.ipv4.address') | join(', ') }}"
TASK [my_task : debug] *****************************************************************************************************************************************************************************************************
ok: [server1] => {
"msg": ", "
}
ok: [server2] => {
"msg": ", "
}
Is it possible?
The behavior you are after is specified by the final line in the extract section, where it says "The third argument to the filter can also be a list, for a recursive lookup inside the container"
Thus, in your case:
msg: "{{ groups['my_hosts']
| map('extract', hostvars, ['ansible_eth1', 'ipv4', 'address'])
| join(', ') }}"

ansible-playbook with_flattened migration to loop

I am trying to migrate my old playbooks that uses with_flattened to loop.
I tried to follow ansible user guide but failed to do so.
This is my host_var:
- hosts: example.com
vars:
- configureddisks:
- xvdb
- xvdc
- btrfsdisks:
- xvdf
- xvdg
My original task and its output is as follow:
# Task
- debug:
msg: "{{ item }}"
with_flattened:
- "{{ configureddisks | select('defined') | list }}"
- "{{ btrfsdisks | select('defined') | list }}"
# ansible-playbook output
TASK [devices : debug] **********************************************************************************************************************************************************************************************************************
ok: [example.com] => (item=xvdb) => {
"msg": "xvdb"
}
ok: [example.com] => (item=xvdc) => {
"msg": "xvdc"
}
ok: [example.com] => (item=xvdf) => {
"msg": "xvdf"
}
ok: [example.com] => (item=xvdg) => {
"msg": "xvdg"
}
My new task and its output is as follow:
# Task
- debug:
msg: "{{ item }}"
loop:
- "{{ configureddisks | select('defined') | list | flatten }}"
- "{{ btrfsdisks | select('defined') | list | flatten }}"
# ansible-playbook output
ok: [example.com] => (item=[u'xvdb', u'xvdc']) => {
"msg": [
"xvdb",
"xvdc"
]
}
ok: [example.com] => (item=[u'xvdf', u'xvdg']) => {
"msg": [
"xvdf",
"xvdg"
]
}
How should I write the new task using loop so that it has the same outputs as the old task?
You are misuing the flatten filter. When you write this:
loop:
- "{{ configureddisks | select('defined') | list | flatten }}"
- "{{ btrfsdisks | select('defined') | list | flatten }}"
The flatten filter has no effect: you are providing as input (twice) a list that is already flattened. You would need to apply the filter to the generated list, but rather than doing that, you can rewrite your expression so that no flattening is necessary:
- debug:
msg: "{{ item }}"
loop: "{{ (configureddisks + btrfsdisks) | select('defined') | list }}"
If you really wanted to go the "build a list of lists and flatten it" route, that might look something like:
- debug:
msg: "{{ item }}"
loop: >-
{{
(
(configureddisks | select('defined') | list) +
(btrfsdisks | select('defined') | list)
)|flatten
}}
Note that I've spread that across multiple lines for legibility, but you could just as easily write it all on one line:
loop: "{{ ((configureddisks | select('defined') | list) + (btrfsdisks | select('defined') | list))|flatten }}"

Resources