How to nest variable in ansible with for - for-loop

I am working with Ansible and I need to display a list of the hosts' network interfaces. In a Jinja2 format template I need the following values: Name, IP, Mask and Network for each of the interfaces. To have this information I use the ansible_facts but I have a problem when making the for.
I get the network interfaces from here:
"ansible_interfaces": [
"eth1",
"eth0",
"lo"
],
So far so good, I make a for and it shows me all three. My problem is that the information I need from each interface is separated in jason:
"ansible_eth0": {
"active": true,
"device": "eth0",
"hw_timestamp_filters": [],
"ipv4": {
"address": "x.x.x.x",
"broadcast": "x.x.x.x",
"netmask": "255.255.192.0",
"network": "x.x.x.x"
},
"ipv4_secondaries": [
{
"address": "x.x.x.x",
"broadcast": "x.x.x.x",
"netmask": "255.255.0.0",
"network": "x.x.x.x"
}
],
"ipv6": [
{
"address": "",
"prefix": "64",
"scope": "link"
}
],
"macaddress": "",
"module": "virtio_net",
"mtu": 1500,
"pciid": "virtio0",
"promisc": false,
"speed": -1,
"timestamping": [
"tx_software",
"rx_software",
"software"
],
"type": "ether"
},
"ansible_eth1": {
"active": true,
"device": "eth1",
"hw_timestamp_filters": [],
"ipv4": {
"address": "x.x.x.x",
"broadcast": "x.x.x.x",
"netmask": "255.255.240.0",
"network": "x.x.x.x"
},
"ipv6": [
{
"address": "",
"prefix": "64",
"scope": "link"
}
],
"macaddress": "",
"module": "virtio_net",
"mtu": 1500,
"pciid": "virtio1",
"promisc": false,
"speed": -1,
"timestamping": [
"tx_software",
"rx_software",
"software"
],
"type": "ether"
},
To get this information I try it in the following way:
{{% for interfaz in ansible_interfaces %}}
{{% for item in ansible_['interfaz'] %}}
Name: {{ item.device }}
IP: {{ item.ipv4.address }}
Netmask: {{ item.ipv4.metmask }}
Red: {{ item.ipv4.network }}
{{% endfor %}}
{{% endfor %}}
I've tried it in different ways and can't figure out how to do it. In my opinion, what the for returns me is a string. And I tried with the iteritems option but I can't either. If someone can help me with the problem I would appreciate it.

Use lookup plugin vars. See the details by running in shell ansible-doc -t lookup vars. For example
- debug:
msg: |
{% for i in ansible_interfaces %}
{% set dev = lookup('vars', 'ansible_' ~ i) %}
Name: {{ dev.device }}
IP: {{ dev.ipv4.address|default(None) }}
Netmask: {{ dev.ipv4.netmask|default(None) }}
Red: {{ dev.ipv4.network|default(None) }}
{% endfor %}
gives in my laptop
msg: |-
Name: lo
IP: 127.0.0.1
Netmask: 255.0.0.0
Red: 127.0.0.0
Name: wlan0
IP:
Netmask:
Red:
Name: eth0
IP: 10.1.0.27
Netmask: 255.255.255.0
Red: 10.1.0.0
The attribute ipv4 might be missing. Fit the default values to your needs.

Related

ansible Jinja template loop

I'm attempting to loop through a registered variable in a Jinja template via an Ansible playbook. Here is my task:
- name: Check if ports are open | inventory ports
wait_for:
host: "{{ item.name }}"
port: "{{ item.port }}"
state: started
delay: 0
timeout: 5
ignore_errors: true
loop: "{{ server_facts.server_port|default (server_port) }}"
register: server_port_check
Then here is the output:
"server_port_check.results": [
{
"state": "started",
"port": 636,
"search_regex": null,
"match_groups": [],
"match_groupdict": {},
"path": null,
"elapsed": 0,
"invocation": {
"module_args": {
"host": "dc.domain.com",
"port": 636,
"state": "started",
"delay": 0,
"timeout": 5,
"connect_timeout": 5,
"active_connection_states": [
"ESTABLISHED",
"FIN_WAIT1",
"FIN_WAIT2",
"SYN_RECV",
"SYN_SENT",
"TIME_WAIT"
],
"sleep": 1,
"path": null,
"search_regex": null,
"exclude_hosts": null,
"msg": null
}
},
"failed": false,
"changed": false,
"item": {
"name": "dc.domain.com",
"port": 636
},
"ansible_loop_var": "item"
},
{
"state": "started",
"port": 4505,
"search_regex": null,
"match_groups": [],
"match_groupdict": {},
"path": null,
"elapsed": 0,
"invocation": {
"module_args": {
"host": "server01",
"port": 4505,
"state": "started",
"delay": 0,
"timeout": 5,
"connect_timeout": 5,
"active_connection_states": [
"ESTABLISHED",
"FIN_WAIT1",
"FIN_WAIT2",
"SYN_RECV",
"SYN_SENT",
"TIME_WAIT"
],
"sleep": 1,
"path": null,
"search_regex": null,
"exclude_hosts": null,
"msg": null
}
},
"failed": false,
"changed": false,
"item": {
"name": "server01",
"port": 4505
},
"ansible_loop_var": "item"
}
],
"_ansible_verbose_always": true,
"_ansible_no_log": false,
"changed": false
}
When I'm able to grab what I want with the following task:
- name: debugging
debug:
msg:
- "{{ server_port_check.results.0.item.name }}"
- "{{ server_port_check.results.0.port }}"
- "{{ server_port_check.results.0.state }}"
How do I loop over this in a template. I've been doing the following (or different variations):
{% for results in server_port_check.results %}
Host: {{ item.name }}
Port: {{ port }}
Status: {{ state }}
{% endfor %}
The playbook fails with
The task includes an option with an undefined variable
The item of your for loop, is the .0 of your debug task.
So:
{% for result in server_port_check.results %}
Host: {{ result.item.name }}
Port: {{ result.port }}
Status: {{ result.state }}
{% endfor %}

ansible jinja2 seperate certain interfaces from list

I'm new to jinja and ansible, and am still trying to wrap my head around how to work with them.
In my case, I'm trying to get a sublist of interface names, where I can execute a certain action on if the description key contains a certain value.
I tried things with an if map construction, but that did seem to work out.
Any suggestion how to do this?
I have the following
- hosts: Router1
gather_facts: false
connection: network_cli
tasks:
- name: get interfaces
arista.eos.eos_interfaces:
state: gathered
register: all_interfaces
- name: check debug
debug:
msg: "{{ all_interfaces.gathered }}"
- name: only configured by Ansible ports
set_fact:
interface: >
{% if 'Configured by Ansible' in all_interfaces.gathered|map(attribute='description')%}
{% endif %}
- name: check debug
debug:
msg: "{{ interface }}"
The list printed out (and which I try to use)
[
{
"description": "Router2",
"enabled": true,
"mode": "layer3",
"name": "Port-Channel1000"
},
{
"description": "Router2",
"enabled": true,
"name": "Ethernet1"
},
{
"description": "",
"enabled": true,
"name": "Ethernet2"
},
{
"description": "",
"enabled": true,
"name": "Ethernet3"
},
{
"description": "",
"enabled": true,
"name": "Ethernet4"
},
{
"description": "Configured by Ansible",
"enabled": false,
"name": "Ethernet5"
},
{
"description": "Configured by Ansible",
"enabled": false,
"name": "Ethernet6"
},
{
"enabled": true,
"name": "Ethernet7"
},
{
"enabled": true,
"name": "Ethernet8"
},
{
"enabled": true,
"name": "Loopback0"
},
{
"enabled": true,
"name": "Management0"
},
{
"enabled": true,
"name": "Management1"
}
]

Correct way to join a new Windows guest to a domain when deployed form a template

I am attempting to automate the deployment of a Windows guest in a VMware environment and I have been quite able to do so as long as I am happy with having to manually add it to the domain, which I am not. I have tried using the vmware_client customization and it does not appear to even be applied.
Ansible 2.9
Red Hat 8
YML
---
- hosts: all
gather_facts: false
vars_files:
- group_vars/all
- build_info/vars
tasks:
- debug:
var: "{{ dusername }}"
- name: Clone a virtual machine from Windows template and customize
vmware_guest:
annotation: "This machine was built from a template through a process triggered by an ansible playbook"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
validate_certs: "{{ validate_certs }}"
datacenter: "{{ datacenter }}"
cluster: "{{ cluster }}"
folder: "{{ folder }}"
name: "{{ bname }}"
template: "{{ template }}"
datastore: "{{ datastore}}"
state: poweredon
networks:
- name: "{{ bnetworks.netname }}"
ip: "{{ bnetworks.ip }}"
netmask: "{{ bnetworks.netmask }}"
gateway: "{{ bnetworks.gateway }}"
domain: "{{ bnetworks.domain }}"
start_connected: yes
dns_servers: "{{bnetworks.dns_servers}}"
dns_suffix: "{{bnetworks.dns_suffix}}"
customization:
hostname: "{{ bname }}"
domainadmin: "{{ dusername }}"
domainadminpassword: "{{ dpassword }}"
joindomain: "{{ bnetworks.domain }}"
fullname: "{{ ladminname }}"
wait_for_ip_address: yes
wait_for_customization: yes
with_dict: "{{ bnetworks }}"
delegate_to: localhost'
The result
{
"changed": true,
"instance": {
"module_hw": true,
"hw_name": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"hw_power_status": "poweredOn",
"hw_guest_full_name": "Microsoft Windows Server 2016 or later (64-bit)",
"hw_guest_id": "windows9Server64Guest",
"hw_product_uuid": "4227f81c-1b25-13fd-45f2-d9399408a5f6",
"hw_processor_count": 2,
"hw_cores_per_socket": 1,
"hw_memtotal_mb": 8192,
"hw_interfaces": [
"eth0"
],
"hw_datastores": [
"na2-tntr02-dat"
],
"hw_files": [
"[na2-tntr02-dat] ********/********.vmx",
"[na2-tntr02-dat] ********/********.nvram",
"[na2-tntr02-dat] ********/********.vmsd",
"[na2-tntr02-dat] ********/********.vmxf",
"[na2-tntr02-dat] ********/********.vmdk"
],
"hw_esxi_host": "na2-devesx01.********",
"hw_guest_ha_state": true,
"hw_is_template": false,
"hw_folder": "/NA2/vm/GLOBAL OPERATIONS/Storage",
"hw_version": "vmx-13",
"instance_uuid": "5027d0ef-7a89-73a6-1da9-6e15df083592",
"guest_tools_status": "guestToolsRunning",
"guest_tools_version": "11269",
"guest_question": null,
"guest_consolidation_needed": false,
"ipv4": "10.6.6.10",
"ipv6": null,
"annotation": "This machine was built from a template through a process triggered by an ansible playbook",
"customvalues": {},
"snapshots": [],
"current_snapshot": null,
"vnc": {},
"moid": "vm-21984",
"vimref": "vim.VirtualMachine:vm-21984",
"hw_cluster": "NA2-NonPROD",
"hw_eth0": {
"addresstype": "assigned",
"label": "Network adapter 1",
"macaddress": "00:50:56:a7:fc:87",
"ipaddresses": [
"fe80::4835:d689:f1a7:6dd4",
"10.6.6.10"
],
"macaddress_dash": "00-50-56-a7-fc-87",
"summary": "DVSwitch: 50 27 7a 36 e1 9e ae 1a-29 5a 4a 79 8d 2b 6f a3",
"portgroup_portkey": "191",
"portgroup_key": "dvportgroup-71"
}
},
"invocation": {
"module_args": {
"annotation": "This machine was built from a template through a process triggered by an ansible playbook",
"hostname": "na2-pdvcva01.********",
"username": "RP4VM#vsphere.local",
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"validate_certs": false,
"datacenter": "NA2",
"cluster": "NA2-NonPROD",
"folder": "/GLOBAL OPERATIONS/Storage",
"name": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"template": "NA2_ZWindows2016STD",
"datastore": "na2-tntr02-dat",
"state": "poweredon",
"networks": [
{
"name": "FIRM_NA|PROD_ap|STORAGE_epg",
"ip": "10.6.6.10",
"netmask": "255.255.255.0",
"gateway": "10.6.6.1",
"domain": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"start_connected": true,
"dns_servers": [
"10.6.2.16",
"10.2.2.17"
],
"dns_suffix": [
"VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"asia.global-legal.com",
"emea.global-legal.com"
],
"type": "static"
}
],
"customization": {
"hostname": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"domainadmin": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"domainadminpassword": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"joindomain": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"fullname": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
},
"wait_for_ip_address": true,
"wait_for_customization": true,
"port": 443,
"is_template": false,
"customvalues": [],
"name_match": "first",
"use_instance_uuid": false,
"disk": [],
"cdrom": [],
"hardware": {},
"force": false,
"state_change_timeout": 0,
"linked_clone": false,
"vapp_properties": [],
"proxy_host": null,
"proxy_port": null,
"uuid": null,
"guest_id": null,
"esxi_hostname": null,
"snapshot_src": null,
"resource_pool": null,
"customization_spec": null,
"convert": null
}
},
"_ansible_no_log": false,
"item": {
"key": "netname",
"value": "FIRM_NA|PROD_ap|STORAGE_epg"
},
"ansible_loop_var": "item",
"_ansible_item_label": {
"key": "netname",
"value": "FIRM_NA|PROD_ap|STORAGE_epg"
},
"_ansible_delegated_vars": {}
}
However the machine does not join the domain. I fully expect a fail because the domain credentials supplied do not have the authority to add the machine to the domain.

Ansible: How to modify a list of dicts

I want to modify dicts in a list within hostvars with a new entry for the IP address I get from the IPAM.
{
"vm_guest_networks": [
{
"device_type": "vmxnet3",
"state": "present",
"subnet": "10.91.1.0/24"
},
{
"device_type": "vmxnet3",
"state": "present",
"subnet": "10.91.0.0/24"
}
]
}
Within a loop I have the subnet to identify the right dict and the IP address I want to add with the ipv4_address key so the result should look like:
{
"vm_guest_networks": [
{
"device_type": "vmxnet3",
"state": "present",
"subnet": "10.91.1.0/24",
"ipv4_address": "10.91.1.216"
},
{
"device_type": "vmxnet3",
"state": "present",
"subnet": "10.91.0.0/24",
"ipv4_address": "10.91.0.21"
}
]
}
The current WIP ansible code is at https://pastebin.com/bFc1Ww2K
Let's assume the list of IPs is available. For example
ip4: [10.91.1.216, 10.91.0.21]
Let's use combine filter and Extended loop variables to create a new list where each dictionary will be updated. For example
- set_fact:
mydata: "{{ mydata|default([]) +
[item|combine({'ipv4_address': ip4[ansible_loop.index0]})] }}"
loop: "{{ vm_guest_networks }}"
loop_control:
extended: yes
- set_fact:
vm_guest_networks: "{{ mydata }}"
- debug:
var: vm_guest_networks
give
"vm_guest_networks": [
{
"device_type": "vmxnet3",
"ipv4_address": "10.91.1.216",
"state": "present",
"subnet": "10.91.1.0/24"
},
{
"device_type": "vmxnet3",
"ipv4_address": "10.91.0.21",
"state": "present",
"subnet": "10.91.0.0/24"
}
]

Different instance tag on EC2 provisioning with Ansible

I want to provision with Ansible more than one EC2 instance but don't really know how can I correctly assign a different instance tag name.
I tried with:
---
....
instance_tags:
Name: tag-{{ item }}
register: ec2
with_items:
- 1
- 2
But then when I want to check if ssh is open:
- name: Check ssh port to be open
wait_for:
host: "{{ item.public_ip }}"
port: 22
delay: 60
timeout: 240
with_items: "{{ ec2.instances }}"
I receive this error:
'dict object' has no attribute 'instances'
Is there a possibility to resolve this issue?
I use Ansible version 2.4.
Please learn how output is registered when running module in a loop: Using register with a loop.
ec2 in your example is a list, not a dictionary, so ec2.instances does not exist.
Use debug module to display actual variable values, pay attention to [ ] and { }, and fix your code appropriately.
if you're using the ec2 module from ansible then you will see that ec2.instances does exist but it's an array of dictionaries. With each entry being the instances that you provisioned so you have to access the members from them.
ok: [localhost] => {
"ec2": {
"changed": true,
"failed": false,
"instance_ids": [
"i-020dfd4ea1872f"
],
"instances": [
{
"ami_launch_index": "0",
"architecture": "x86_64",
"block_device_mapping": {
"/dev/xvda": {
"delete_on_termination": true,
"status": "attached",
"volume_id": "vol-00415be2e41d58564"
}
},
"dns_name": "",
"ebs_optimized": false,
"groups": {
"sg-fcef86": "default"
},
"hypervisor": "xen",
"id": "i-020dfd4ea182f",
"image_id": "ami-e6899e",
"instance_type": "t2.micro",
"kernel": null,
"key_name": "st",
"launch_time": "2017-10-23T21:28:06.000Z",
"placement": "us-west-2b",
"private_dns_name": "ip-10-",
"private_ip": "10.212",
"public_dns_name": "",
"public_ip": null,
"ramdisk": null,
"region": "us-west-2",
"root_device_name": "/dev/xvda",
"root_device_type": "ebs",
"state": "running",
"state_code": 16,
"tags": {},
"tenancy": "default",
"virtualization_type": "hvm"
}
],
"tagged_instances": []
}
}
Your with_items would work:
instance_tags:
Name: "{{ item }}"
with_items:
- Machine1
- Machine2
But going back to why your ec2.instances doens't exist it's because of what I responded to up top
make sure to do a:
- debug: var=ec2
To view your variable

Resources