ansible: how to split string with multiple delimiters - regex

Here is my output.
"result.containers": [
{
"Image": "cna.docker.dev/webproxy:1.0.0",
},
{
"Image": "cna-docker-dev-local.docker.dev/lega-customer:1.0.1",
}
]
Here is my code
- name: adding it to groups using images
add_host:
name: "{{ inventory_hostname }}"
groups: '{{ (item.Image.split("/")[1:] | regex_replace("^/", "")).split(":")[0] }}'
with_items: "{{ result.containers }}"
I'm getting the below output:
"add_host": {
"groups": [
"['webproxy"
],
"host_name": "vm4.nodekite.com",
"host_vars": {
}
I would like to filter webproxy from cna.docker.dev/webproxy:1.0.0.
But I'm getting "['webproxy" instead of "webproxy.
Could someone please help!! I even tried this code which fails
(item.Image.split("/")[1:]).split(":")[0]

- debug:
msg: "{{ item.Image | regex_replace('.*?/(.*?):.*', '\\1') }}"
loop: "{{ result.containers | flatten(1) }}"
Example regex is non greedy, adjust as needed.
Gives
ok: [localhost] => (item={'Image': 'cna.docker.dev/webproxy:1.0.0'}) => {
"msg": "webproxy"
}
ok: [localhost] => (item={'Image': 'cna-docker-dev-local.docker.dev/lega-customer:1.0.1'}) => {
"msg": "lega-customer"
}

Related

Ansible filter item in list using variables+wildcard

I have the below lists stored in variable results_one.msg
[
{
"IP": [
"192.168.1.100",
"192.168.1.101"
],
"Pool": "lan_pool_sftp",
"Members": [
"sftpnode01:5425",
"sftpnode02:5425"
]
},
{
"IP": [
"192.168.1.103",
"192.168.1.104"
],
"Pool": "icmp-net-pool",
"Members": [
"icmpnet01:8443",
"icmpnet02:8443"
]
}
]
I have another variable node_name
I would like to get the Pool and Members information from above output, by querying one of the members name.
For example, if I assign the variable node_name: icmpnet02
I want to get the output stored as in respective variable names as below.
pool_name: icmp-net-pool
pool_members: [ icmpnet01:8443,icmpnet02:8443 ]
I tried as below and I'm unable to get it
- set_fact:
pool_name: "{{ item.Pool }}"
pool_members: "{{ item.Members }}"
with_items: "{{results_one.msg }}"
when: 'item.Members.0 is defined and "node_name:*" in item.Members'
Create a list of lists of members with their names only:
_members_hostnames: "{{ results_one.msg | map(attribute='Members')
| map('map', 'regex_replace', '^(.*):.*$', '\\1') }}"
Gives:
"_members_hostnames": [
[
"sftpnode01",
"sftpnode02"
],
[
"icmpnet01",
"icmpnet02"
]
]
select the matching entry from your relevant variable, i.e.
create a list of tuples associating each original element with its counterpart calculated members hostnames
retain only element where hostname is present in the list
keep only the first element of tupple (i.e. the orginal entry)
keep only the first element from list
_matching_entry: "{{ results_one.msg | zip(_members_hostnames)
| selectattr(1, 'contains', node_name) | map(attribute=0) | first }}"
gives
"_matching_entry": {
"IP": [
"192.168.1.103",
"192.168.1.104"
],
"Members": [
"icmpnet01:8443",
"icmpnet02:8443"
],
"Pool": "icmp-net-pool"
}
use the matching entry to extract whatever variable you need:
pool_name: "{{ _matching_entry.Pool }}"
pool_members: "{{ _matching_entry.Members }}"
Putting it all together in a test playbook:
---
- hosts: localhost
gather_facts: false
vars:
# Your orig data on a single line for legibility
results_one: {"msg":[{"IP":["192.168.1.100","192.168.1.101"],"Pool":"lan_pool_sftp","Members":["sftpnode01:5425","sftpnode02:5425"]},{"IP":["192.168.1.103","192.168.1.104"],"Pool":"icmp-net-pool","Members":["icmpnet01:8443","icmpnet02:8443"]}]}
node_name: icmpnet02
_members_hostnames: "{{ results_one.msg | map(attribute='Members')
| map('map', 'regex_replace', '^(.*):.*$', '\\1') }}"
_matching_entry: "{{ results_one.msg | zip(_members_hostnames)
| selectattr(1, 'contains', node_name) | map(attribute=0) | first }}"
pool_name: "{{ _matching_entry.Pool }}"
pool_members: "{{ _matching_entry.Members }}"
tasks:
- debug:
msg:
- Pool name is {{ pool_name }}
- Pool members are {{ pool_members }}
Which gives:
PLAY [localhost] ***********************************************************************************************************************************************************************************************************************
TASK [debug] ***************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"Pool name is icmp-net-pool",
"Pool members are ['icmpnet01:8443', 'icmpnet02:8443']"
]
}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Ansible returns 'AnibleUnicode' instead of JSON, unable to filter

I'm unable to filter the following output with json_query, even though it works on a jmespath validator website.
Let me explain in detail with the code.
type_debug returns AnsibleUnicode for members value, so when I tried to use json_query to filter output it returned null. I need to get value from key ip, but I don't know how to do it in a good way.
---
- hosts: localhost
gather_facts: false
vars:
- RPN:
stdout: >-
"members": [
{
"id": 0,
"ip": "x.x.x.x",
"owner": "buzut",
"private_ip": "10.91.154.39",
"speed": 100,
"status": "active"
}
]
tasks:
- debug:
msg: "{{ RPN.stdout | type_debug }}"
From your question I understand that you like to gather all member with a json_query. To do so I've corrected the JSON slightly.
---
- hosts: localhost
become: false
gather_facts: false
vars:
RPN:
stdout: >-
{
"members": [{
"id": 0,
"ip": "x.x.x.x",
"owner": "buzut",
"private_ip": "10.91.154.39",
"speed": 100,
"status": "active"
}]
}
tasks:
- name: Show type(s)
debug:
msg:
- "{{ RPN.stdout | type_debug }}"
- "{{ RPN.stdout | from_json | type_debug }}"
- "{{ RPN.stdout | to_json | type_debug }}"
- name: Show members
debug:
msg: "{{ RPN.stdout | from_json | json_query('members') }}"
resulting into an output of
TASK [Show type(s)] *********
ok: [localhost] =>
msg:
- AnsibleUnicode
- dict
- str
TASK [Show members] *********
ok: [localhost] =>
msg:
- id: 0
ip: x.x.x.x
owner: buzut
private_ip: 10.91.154.39
speed: 100
status: active
I need to get value from key ip
- name: Show value of key 'ip'
debug:
msg: "{{ RPN.stdout | from_json | json_query('members[*].ip') }}"
resulting into an output of
TASK [Show value of key 'ip'] *********
ok: [localhost] =>
msg:
- x.x.x.x
Further Documentation
Selecting JSON data: JSON queries

Ansible - remove empty elements from the list

I have an ansible output from which I want to remove all empty (none) elements for a specific attribute. Here is the example list:
"resources": [
{
"id": "9c40900909",
"name": "some_name1"
},
{
"id": "pc4b09090"
},
{
"id": "8lknkkn45"
},
{
"id": "9df40900909",
"name": "some_name2"
}
]
Here is how I reduced the list to be just "resources" with attribute "name":
- set_fact:
resources_names: "{{ output.resources | map(attribute='name') }}"
Problem with that is that I get the elements that does not have any value for the name. These are "AnsibleUndefined" in the following output:
- debug:
msg: resources_names list is "{{ resources_names }}"
ok: [localhost] => {
"msg": "resources_names list is \"['some_name1', AnsibleUndefined, AnsibleUndefined, 'some_name2']\""
}
I tried to remove it with reject and regexp but that's not working.
- set_fact:
list2: "{{ resources_names | reject('match', '^$') | list }}"
Same with this one:
- set_fact:
resources_names: "{{ output.resources | map(attribute='name') | rejectattr('name', 'none') }}"
Any idea?
Thanks.
In a nutshell:
---
- hosts: localhost
gather_facts: false
vars:
resources: [
{
"id": "9c40900909",
"name": "some_name1"
},
{
"id": "pc4b09090"
},
{
"id": "8lknkkn45"
},
{
"id": "9df40900909",
"name": "some_name2"
}
]
tasks:
- debug:
msg: "{{ resources | selectattr('name', 'defined') | map(attribute='name') }}"
which gives:
$ ansible-playbook /tmp/play.yml
[WARNING]: No inventory was parsed, only implicit localhost is available
PLAY [localhost] *******************************************************************************************************************************************************************************
TASK [debug] ***********************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"some_name1",
"some_name2"
]
}
PLAY RECAP *************************************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Note for your next question: please make sure you double check your examples and paste valid json/yaml data in your question. Thanks
Use the filter json_query. This filter ignores missing attributes
resources_names: "{{ output.resources|json_query('[].name') }}"
gives
resources_names:
- some_name1
- some_name2

Ansible - create list out of with_items

How can I create a list out of with_items? I tried the following but it records only the last group ID instead of creating a list.
- name: "Generate list"
set_fact:
my_new_list: "{{ [ item.group_id ] }}"
with_items:
- "{{ec2_info.instances[0].security_groups}}"
ec2_info.instances[0].security_groups has multiple group_id's.
"security_groups": [
{
"group_id": "sg-0500c5b20f7c152b4",
"group_name": "ManageIQ"
},
{
"group_id": "sg-062178ea5fabaf350",
"group_name": "launch-wizard-1"
}
],
this playbook traps all the list:
- name: "Generate list"
set_fact:
my_new_list: "{{ my_new_list|d([]) + [ item.group_id ] }}"
with_items:
- "{{ec2_info.instances[0].security_groups}}"

ansible join list

I run into a problem joining a list in ansible. Please look at the following playbook excerpt:
- name: determine how much time we have left
set_fact:
time_left1: "{{ cmd_output.stdout | regex_search(time_left_regex1, '\\1', '\\2') }}"
time_left2: "{{ cmd_output.stdout | regex_findall(time_left_regex2, '\\1') }}"
vars:
time_left_regex1: 'Remaining Time: ([0-9]+ Minutes) and ([0-9]+ Seconds)'
time_left_regex2: 'Remaining Time: (?:([0-9]+ Minutes) and )?([0-9]+ Seconds)'
- debug:
msg: "{{ time_left1 }}"
- debug:
msg: "{{ time_left1 | join(' ') }}"
- debug:
msg: "{{ time_left2 }}"
- debug:
msg: "{{ time_left2 | join(' ') }}"
When I run this playbook I get:
ok: [localhost] => {
"msg": [
"11 Minutes",
"48 Seconds"
] }
ok: [localhost] => {
"msg": "11 Minutes 48 Seconds" }
ok: [localhost] => {
"msg": [
[
"11 Minutes",
"48 Seconds"
]
] }
ok: [localhost] => {
"msg": [
"11 Minutes",
"48 Seconds"
] }
To me it seems that the regex_search returned I list that I can join to a simple string, and that regex_findall creates a nested list. Is this correct? And if so, how can convert the output to a string similar to the way regex_search works?
PS: for more information about the contents of cmd_output please take a look at my previous question
flatten the nested list. For example
- debug:
msg: "{{ time_left2|flatten|join(' ') }}"