I have a file similar to below.
SITE "A" (id:1,bindings:http/*:80:,net.tcp/808:*,net.pipe/*,state:Stopped)
SITE "B" (id:2,bindings:https/*:344:,net.tcp/325:*,net.pipe/*,state:Started)
SITE "C" (id:3,bindings:http/:80:xyz.domain.com,http/*:80:xyz,http/*:80:seiging,http/*:80:seiging.domain.com,state:Started)
SITE "D" (id:4,bindings:http/:901:,http/*:80:actdaov,state:Started)
SITE "E" (id:5,bindings:https/:443:idu.domain.com,http/*:80:idu.domain.com,state:Started)
I want to extract the below content.
"A,id:1,",
"B,id:2,",
"C,id:3,http/:80:seiging.domain.com",
"D,id:4,",
"E,id:5,http/:80:idu.domain.com",
The third field - If domain.com is present I need to extract that, if not it should be blank. If more than one domain.com exists then I need to take the last one.
I tried as below:
set_fact: inv_op="{{ item | regex_replace('SITE \\\"(.*)\\\" \((.*)\,bindings(.*)\,state.*', '\\1,\\2,\\3') }}"
Output as below:
"A,id:1,:http/:80:,net.tcp/808:,net.pipe/",
"B,id:2,:https/:344:,net.tcp/325:,net.pipe/",
"C,id:3,:http/:80:xyz.domain.com,http/:80:xyz,http/:80:seiging,http/:80:seiging.domain.com",
"D,id:4,:http/:901:,http/:80:actdaov",
"E,id:5,:https/:443:idu.domain.com,http/*:80:idu.domain.com",
Please advice
It's possible to create a dictionary first. For example the tasks
- set_fact:
my_lines: "{{ lookup('file', 'data.csv').splitlines() }}"
- set_fact:
my_lists: "{{ my_lists|default([]) + [item.split(' ')] }}"
loop: "{{ my_lines }}"
- set_fact:
my_dict: "{{ my_dict|default({})|
combine({item.1.1: {'id': item.2.split(',')[0].split(':')[1],
'state': item.2.split(',')[-1].split(':')[1][:-1],
'bindings': item.2.split(',')[1:-1]|
map('regex_replace', 'bindings:', '')|list}})
}}"
loop: "{{ my_lists }}"
give
"my_dict": {
"A": {
"bindings": [
"http/*:80:",
"net.tcp/808:*",
"net.pipe/*"
],
"id": "1",
"state": "Stopped"
},
"B": {
"bindings": [
"https/*:344:",
"net.tcp/325:*",
"net.pipe/*"
],
"id": "2",
"state": "Started"
},
"C": {
"bindings": [
"http/:80:xyz.domain.com",
"http/*:80:xyz",
"http/*:80:seiging",
"http/*:80:seiging.domain.com"
],
"id": "3",
"state": "Started"
},
"D": {
"bindings": [
"http/:901:",
"http/*:80:actdaov"
],
"id": "4",
"state": "Started"
},
"E": {
"bindings": [
"https/:443:idu.domain.com",
"http/*:80:idu.domain.com"
],
"id": "5",
"state": "Started"
}
}
Then print the data. For example the task
"The third field - If domain.com is present I need to extract that, if not it should be blank. If more than one domain.com exists then I need to take the last one."
- debug:
msg: |
{{ item.key }},id:{{ item.value.id }},
{%- if item.value.bindings|select('search', 'domain\.com')|list %}
{{ item.value.bindings|select('search', 'domain\.com')|reverse|list|first }},
{% endif %}
loop: "{{ my_dict|dict2items }}"
gives
"msg": "A,id:1,\n"
"msg": "C,id:3,http/*:80:seiging.domain.com,\n"
"msg": "B,id:2,\n"
"msg": "E,id:5,http/*:80:idu.domain.com,\n"
"msg": "D,id:4,\n"
Related
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
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
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"
}
I am relatively new to working with Ansible Core / Tower and I am at a complete loss what is causing the following issues. I have spent the past two days reading everything I could find on the topic and I am still stuck, looking for help.
Here is what I currently have setup (among other Ansible playbooks, roles, and tasks to create brand new VPC).
Below are the tasks that I am using to create a set of new subnets, one per availability zone, and get the results back from what is created. These tasks all works perfectly as verified through the AWS Console.
### Create the Internet-facing DMZ subnets ###
- name: Create Subnet(s) in VPC - DMZ
ec2_vpc_subnet:
state: present
vpc_id: "{{ new_vpc_info['vpcs'][0]['id'] }}"
region: "{{ vpc_region }}"
az: "{{ item.az }}"
cidr: "{{ item.subnet }}"
resource_tags:
Name: "{{ item.name }}"
Role: "{{ role_tag }}"
Team: "{{ team_tag }}"
Product Area: "{{ product_area_tag }}"
Portfolio: "{{ portfolio_tag }}"
with_items: "{{ dmz_subnet_az }}"
- name: Get Sunbet Info - DMZ
ec2_vpc_subnet_facts:
region: "{{ vpc_region }}"
filters:
"tag:Name": "{{ item.name }}"
with_items: "{{ dmz_subnet_az }}"
register: new_dmz_subnets
- debug:
var=new_dmz_subnets
The output of the "debug" command is provided below, truncated to remove the rest of the subnets and redacted so I do not get yelled at, which matches up to what is in the AWS Console.
{
"changed": false,
"_ansible_verbose_always": true,
"new_dmz_subnets": {
"msg": "All items completed",
"changed": false,
"results": [
{
"_ansible_parsed": true,
"subnets": [
{
"tags": {
"Product Area": "Engineering Tools",
"Portfolio": "Shared Platform and Operations",
"Role": "splunk-proof-of-concept",
"Name": "DMZ_Subnet_A",
"Team": "Engineering Tools"
},
"subnet_id": "subnet-XXXX",
"assign_ipv6_address_on_creation": false,
"default_for_az": false,
"state": "available",
"ipv6_cidr_block_association_set": [],
"availability_zone": "us-east-1a",
"vpc_id": "vpc-XXXX",
"cidr_block": "x.x.x.x/24",
"available_ip_address_count": 251,
"id": "subnet-XXXX",
"map_public_ip_on_launch": false
}
],
"changed": false,
"_ansible_item_label": {
"subnet": "x.x.x.x/24",
"az": "us-east-1a",
"name": "DMZ_Subnet_A"
},
"item": {
"subnet": "x.x.x.x/24",
"az": "us-east-1a",
"name": "DMZ_Subnet_A"
},
"_ansible_item_result": true,
"failed": false,
"invocation": {
"module_args": {
"profile": null,
"aws_secret_key": null,
"aws_access_key": null,
"security_token": null,
"region": "us-east-1",
"filters": {
"tag:Name": "DMZ_Subnet_A"
},
"ec2_url": null,
"subnet_ids": [],
"validate_certs": true
}
},
"_ansible_ignore_errors": null,
"_ansible_no_log": false
},
{
"_ansible_parsed": true,
"subnets": [
{
"tags": {
"Product Area": "Engineering Tools",
"Portfolio": "Shared Platform and Operations",
"Role": "splunk-proof-of-concept",
"Name": "DMZ_Subnet_B",
"Team": "Engineering Tools"
},
"subnet_id": "subnet-XXXX",
"assign_ipv6_address_on_creation": false,
"default_for_az": false,
"state": "available",
"ipv6_cidr_block_association_set": [],
"availability_zone": "us-east-1b",
"vpc_id": "vpc-XXXX",
"cidr_block": "x.x.x.x/24",
"available_ip_address_count": 251,
"id": "subnet-XXXX",
"map_public_ip_on_launch": false
}
],
"changed": false,
"_ansible_item_label": {
"subnet": "x.x.x.x/24",
"az": "us-east-1b",
"name": "DMZ_Subnet_B"
},
"item": {
"subnet": "x.x.x.x/24",
"az": "us-east-1b",
"name": "DMZ_Subnet_B"
},
"_ansible_item_result": true,
"failed": false,
"invocation": {
"module_args": {
"profile": null,
"aws_secret_key": null,
"aws_access_key": null,
"security_token": null,
"region": "us-east-1",
"filters": {
"tag:Name": "DMZ_Subnet_B"
},
"ec2_url": null,
"subnet_ids": [],
"validate_certs": true
}
},
"_ansible_ignore_errors": null,
"_ansible_no_log": false
},
......
}
]
},
"_ansible_no_log": false
}
Now onto the tasks that I am having issues getting working, below is my most recent attempt, which may be completely in left field due to me trying everything I found to get it working. I am attempting to get a list of the "subnet_id" from the registered "new_dmz_subnets" variable, then concatenating it with a "name" that is set in a vars file, and finally using that information to create a NAT Gateway within each of the subnets.
### Create the NAT Gateway in VPC ###
- name: Set DMZ Subnet facts
set_fact:
subnet_id_items:
subnet_id: '{{ item.subnets | map(attribute="subnet_id") | list }}'
with_items: "{{ new_dmz_subnets }}"
register: subnet_id_list
- name: Set Name and DMZ Subnet loop facts
set_fact:
name_subnet_items:
name: "{{ nat_gateway.name }}"
subnet_id: "{{ item.subnet_id }}"
loop: "{{ subnet_id_list }}"
register: name_subnet_list
- debug:
var=name_subnet_list
- name: Create NAT Gateway, allocate new EIP, in VPC
ec2_vpc_nat_gateway:
state: present
subnet_id: "{{ item.subnet_id }}"
region: "{{ vpc_region }}"
wait: yes
if_exist_do_not_create: true
tags:
Name: "{{ item.name }}"
Role: "{{ role_tag }}"
Team: "{{ team_tag }}"
Product Area: "{{ product_area_tag }}"
Portfolio: "{{ portfolio_tag }}"
with_items: "{{ name_subnet_list }}"
register: new_nat_gateway
- debug:
var=new_nat_gateway
When I ran this setup, I got the following fatal error message, which is pretty much the same across every variation I have attempted.
12:55:15
fatal: [localhost]: FAILED! => {
"msg": "The task includes an option with an undefined variable. The error was: 'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'subnets'\n\nThe error appears to have been in '/var/lib/awx/projects/_6__erik_andresen_git/ansible/splunk_poc_playbook/roles/create_networking_role/tasks/create_gateways_task.yml': line 21, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n### Starting working on this Task ###\n- name: Set DMZ Subnet facts\n ^ here\n"
}
Please let me know if I can provide any additional details and thanks in advance for the help!!!
-- Erik
I came across a setup that actually works! It may not be the best way to do it and I am still open to suggestions, but it at least works.
Here is code of the "ec2_vpc_subnet" module and collecting the Subnet IDs for later use in the playbook.
### Create the Internet-facing DMZ subnets ###
- name: Create Subnet(s) in VPC - DMZ
ec2_vpc_subnet:
state: present
vpc_id: "{{ vpc_id }}"
region: "{{ vpc_region }}"
az: "{{ item.az }}"
cidr: "{{ item.subnet }}"
resource_tags:
Name: "{{ item.name }}"
Role: "{{ role_tag }}"
Team: "{{ team_tag }}"
Product Area: "{{ product_area_tag }}"
Portfolio: "{{ portfolio_tag }}"
Created By: "{{ created_by }}"
with_items: "{{ dmz_subnet_az }}"
register: new_dmz_subnets
- name: Set facts for Subnet - DMZ
set_fact:
subnet_dmz_id: "{{ subnet_dmz_id | default({}) | combine({ item.subnet.tags.Name: item.subnet.id }) }}"
loop: "{{ new_dmz_subnets.results }}"
- debug:
var=subnet_dmz_id
And here is the use of the Subnet IDs in the "ec2_vpc_nat_gateway" module to create a NAT Gateway within each Availability Zone.
### Create the NAT Gateway in VPC ###
- name: Create NAT Gateway, allocate new EIP, in VPC
ec2_vpc_nat_gateway:
state: present
# NAT Gateways being deployed in DMZ subnets
subnet_id: "{{ subnet_dmz_id[item.subnet_name] }}"
region: "{{ vpc_region }}"
wait: yes
if_exist_do_not_create: true
# Tags not supported in the "ec2_vpc_nat_gateway" module
# https://github.com/ansible/ansible/issues/44339
#tags:
# Name: "{{ item.name }}"
# Role: "{{ role_tag }}"
# Team: "{{ team_tag }}"
# Product Area: "{{ product_area_tag }}"
# Portfolio: "{{ portfolio_tag }}"
# Created By: "{{ created_by }}"
with_items: "{{ nat_gateway }}"
register: new_nat_gateway
- debug:
var=new_nat_gateway
I'm trying to find all the up interfaces on a switch, by looking at the results of some output from nxos_facts:
- name: get nxos facts via nxapi
nxos_facts:
provider: "{{ provider['nxapi'] }}"
gather_subset:
- "interfaces"
register: nxfacts_nxapi
- debug:
msg: "{{ nxfacts_nxapi.ansible_facts.ansible_net_interfaces | to_nice_json}} "
And I can successfully print out the debug to show the structure of the dictionary:
"ansible_net_interfaces": {
"Ethernet1/1": {
"bandwidth": 1000000,
"duplex": "full",
"ipv4": {
"address": "10.0.1.2",
"masklen": 24
},
"macaddress": "0800.276d.ee15",
"mtu": "1500",
"speed": "1000 Mb/s",
"state": "up",
"type": "100/1000/10000 Ethernet"
},
"Ethernet1/10": {
"bandwidth": 10000000,
"duplex": "auto",
"macaddress": "0800.276c.eecc",
"mode": "access",
"mtu": "1500",
"speed": "auto-speed",
"state": "down",
"type": "100/1000/10000 Ethernet"
},
But I'm struggling with the syntax to dereference the dictionary to only print when the "state" is "up"?
I'm running with the following version:
ansible 2.3.1.0
Any help is much appreciated.
You can iterate over the dictionary of interfaces and print only those elements for which the condition is true. Example:
- name: mytask
debug:
msg: "{{ item }}"
when: "item.value.state == 'up'"
with_dict: "{{ nxfacts_nxapi.ansible_facts.ansible_net_interfaces }}"