ansible Jinja template loop - ansible

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 %}

Related

Output of Ansibble task

I am using command hcloud to create cloud server in Hetzner. I get an output like this:
changed: [localhost] => (item={'name': 'TEST-VARIABLES', 'server_type': 'cx11', 'os_image': 'ubuntu-20.04', 'server_labels': 'Name=test-server', 'server_location': 'hel1'}) => {
"ansible_loop_var": "item",
"changed": true,
"hcloud_server": {
"backup_window": "None",
"datacenter": "hel1-dc2",
"delete_protection": false,
"id": "19461514",
"image": "ubuntu-20.04",
"ipv4_address": "11.111.111.111",
"ipv6": "1a71:7f9:c011:0b09::/64",
"labels": {
"Name": "test-server"
},
"location": "hel1",
"name": "TEST-VARIABLES",
"placement_group": null,
"rebuild_protection": false,
"rescue_enabled": false,
"server_type": "cx11",
"status": "running"
},
"invocation": {
"module_args": {
"allow_deprecated_image": false,
"api_token": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"backups": null,
"datacenter": null,
"delete_protection": null,
"endpoint": "https://api.SERVER.cloud/v1",
"firewalls": null,
"force": false,
"force_upgrade": false,
"id": null,
"image": "ubuntu-20.04",
"labels": {
"Name": "test-server"
},
"location": "hel1",
"name": "TEST-VARIABLES",
"placement_group": null,
"rebuild_protection": null,
"rescue_mode": null,
"server_type": "cx11",
"ssh_keys": null,
"state": "present",
"upgrade_disk": false,
"user_data": null,
"volumes": null
}
},
"item": {
"name": "TEST-VARIABLES",
"os_image": "ubuntu-20.04",
"server_labels": "Name=test-server",
"server_location": "hel1",
"server_type": "cx11"
},
"root_password": "DFLDJFLDFDLFKJDLFKJ"
}
I try to get line with "ipv4_address": "11.111.111.111", and "root_password": "DFLDJFLDFDLFKJDLFKJ", but when I use task:
---
- name: Create a basic server
hcloud_server:
api_token: "{{ token }}"
name: "{{ item.name }}"
server_type: "{{ item.server_type }}"
image: "{{ item.os_image }}"
labels: "{{ item.server_labels }}"
location: "{{ item.server_location }}"
state: present
register: server_info
with_items: "{{ server }}"
- name: Here IP
debug:
var: server_info.root_password
I got error:
TASK [/etc/ansible/roles/CREATE-server : Here IP.] *********************************************************************************************************
ok: [localhost] => {
"server_info.root_password": "VARIABLE IS NOT DEFINED!"
}
Could you please help, how I can get IP line and password line, to use them in the next task (for example to send via email). Thank you!
you register the content of loop, so your result is a list (results):
- name: display
debug:
msg: "ip: {{ item.hcloud_server.ipv4_address }} has password: {{ item.root_password }}"
loop: "{{ server_info.results }}"
result: here you have just one server declared, so just one item in the list results
"msg": "ip: 11.111.111.111 has password: DFDFDFDFDFDFDFDF"
if you want to limit the output of record, you could add loop_control parameter to loop with argument label:
loop: "{{ server_info.results }}"
loop_control:
label: "{{ item.hcloud_server.ipv4_address }}"
you could put another comment if you want with label or even empty string:
loop: "{{ server_info.results }}"
loop_control:
label: "result"

Anlible. How do I add a condition to a loop operation?

How can I get from this data only the value ("subclientName": "test") where "count" = 1
"subclientName": "start9pm" should not be in the selection
{
"countbackupsetName": {
"results": [
{
"actions": {
"xpath": "//subClientProperties[subClientEntity[#subclientName=\"test\"]]/vmContent/children",
"namespaces": {},
"state": "present"
},
"changed": false,
"count": 2,
"msg": "found 2 nodes",
"invocation": {
"module_args": {
"path": "/var/lib/awx/projects/commv/parse/get_subclient2.xml",
"xpath": "//subClientProperties[subClientEntity[#subclientName=\"test\"]]/vmContent/children",
"count": true,
"namespaces": {},
"state": "present",
"print_match": false,
"pretty_print": false,
"input_type": "yaml",
"backup": false,
"strip_cdata_tags": false,
"insertbefore": false,
"insertafter": false,
"xmlstring": null,
"value": null,
"attribute": null,
"add_children": null,
"set_children": null,
"content": null
}
},
"failed": false,
"item": {
"appName": "Virtual Server",
"backupsetName": "backupset-test",
"clientName": "name05-vcagent",
"displayName": "name05-VCAgent",
"instanceName": "VC01",
"subclientName": "test"
},
"ansible_loop_var": "item"
},
{
"actions": {
"xpath": "//subClientProperties[subClientEntity[#subclientName=\"start9pm\"]]/vmContent/children",
"namespaces": {},
"state": "present"
},
"changed": false,
"count": 2,
"msg": "found 2 nodes",
"invocation": {
"module_args": {
"path": "/var/lib/awx/projects/commv/parse/get_subclient2.xml",
"xpath": "//subClientProperties[subClientEntity[#subclientName=\"start9pm\"]]/vmContent/children",
"count": true,
"namespaces": {},
"state": "present",
"print_match": false,
"pretty_print": false,
"input_type": "yaml",
"backup": false,
"strip_cdata_tags": false,
"insertbefore": false,
"insertafter": false,
"xmlstring": null,
"value": null,
"attribute": null,
"add_children": null,
"set_children": null,
"content": null
}
},
"failed": false,
"item": {
"appName": "Virtual Server",
"backupsetName": "Test01",
"clientName": "name05-vcagent",
"displayName": "name05-VCAgent",
"instanceName": "VC01",
"subclientName": "start9pm"
},
"ansible_loop_var": "item"
}
],
"msg": "All items completed",
"changed": false
},
"_ansible_verbose_always": true,
"_ansible_no_log": false,
"changed": false
}
This is how I managed to select everything, without the condition operation:
- debug:
msg: "{{ item.subclientName }}"
loop: "{{ countbackupsetName.results|map(attribute='item')|list }}"
result:
{
"msg": "test",
"_ansible_verbose_always": true,
"_ansible_no_log": false,
"changed": false,
"item": {
"appName": "Virtual Server",
"backupsetName": "backupset-test",
"clientName": "name05-vcagent",
"displayName": "name05-VCAgent",
"instanceName": "VC01",
"subclientName": "test"
},
"ansible_loop_var": "item",
"_ansible_item_label": {
"appName": "Virtual Server",
"backupsetName": "backupset-test",
"clientName": "name05-vcagent",
"displayName": "name05-VCAgent",
"instanceName": "VC01",
"subclientName": "test"
}
}
This is how I get to the data I need, but the number of lines is always different.
I also don't need lines where count ":" 2 "
code:
- name: Show value in countbackupsetName.results.0.count
debug:
var: countbackupsetName.results.0.count
- debug:
var: countbackupsetName.results.0.item.subclientName
- name: Show value in countbackupsetName.results.1.count
debug:
var: countbackupsetName.results.1.count
- debug:
var: countbackupsetName.results.1.item.subclientName
result:
TASK [Show value in countbackupsetName.results.0.count] ************************
ok: [localhost] => {
"countbackupsetName.results.0.count": "1"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"countbackupsetName.results.0.item.subclientName": "test"
}
TASK [Show value in countbackupsetName.results.1.count] ************************
ok: [localhost] => {
"countbackupsetName.results.1.count": "2"
}
code:
- name: debug jinja
debug:
msg: |
[
{% for p in countbackupsetName.results %}
{% for o in countbackupsetName.results[p].item %}
{
"count": "{{ countbackupsetName.results[p].count }}",
"key": "{{ o }}",
"value": "{{ countbackupsetName.results[p].item[o] }}"
},
{% endfor %}
{% endfor %}
]
result:
line 112, column 9, but may\nbe elsewhere in the file depending on the exact syntax problem.
Not sure I've got properly what is desired output. But idea should be the same regardless: loop through results checking for condition and printing matching items. Here you go:
- hosts: localhost
become: false
tasks:
- set_fact:
data: {
"countbackupsetName": {
"results": [
{
"actions": {
"xpath": "//subClientProperties[subClientEntity[#subclientName=\"test\"]]/vmContent/children",
"namespaces": {},
"state": "present"
},
"changed": false,
"count": 2,
"msg": "found 2 nodes",
"invocation": {
"module_args": {
"path": "/var/lib/awx/projects/commv/parse/get_subclient2.xml",
"xpath": "//subClientProperties[subClientEntity[#subclientName=\"test\"]]/vmContent/children",
"count": true,
"namespaces": {},
"state": "present",
"print_match": false,
"pretty_print": false,
"input_type": "yaml",
"backup": false,
"strip_cdata_tags": false,
"insertbefore": false,
"insertafter": false,
"xmlstring": null,
"value": null,
"attribute": null,
"add_children": null,
"set_children": null,
"content": null
}
},
"failed": false,
"item": {
"appName": "Virtual Server",
"backupsetName": "backupset-test",
"clientName": "name05-vcagent",
"displayName": "name05-VCAgent",
"instanceName": "VC01",
"subclientName": "test"
},
"ansible_loop_var": "item"
},
{
"actions": {
"xpath": "//subClientProperties[subClientEntity[#subclientName=\"start9pm\"]]/vmContent/children",
"namespaces": {},
"state": "present"
},
"changed": false,
"count": 2,
"msg": "found 2 nodes",
"invocation": {
"module_args": {
"path": "/var/lib/awx/projects/commv/parse/get_subclient2.xml",
"xpath": "//subClientProperties[subClientEntity[#subclientName=\"start9pm\"]]/vmContent/children",
"count": true,
"namespaces": {},
"state": "present",
"print_match": false,
"pretty_print": false,
"input_type": "yaml",
"backup": false,
"strip_cdata_tags": false,
"insertbefore": false,
"insertafter": false,
"xmlstring": null,
"value": null,
"attribute": null,
"add_children": null,
"set_children": null,
"content": null
}
},
"failed": false,
"item": {
"appName": "Virtual Server",
"backupsetName": "Test01",
"clientName": "name05-vcagent",
"displayName": "name05-VCAgent",
"instanceName": "VC01",
"subclientName": "start9pm"
},
"ansible_loop_var": "item"
}
],
"msg": "All items completed",
"changed": false
},
"_ansible_verbose_always": true,
"_ansible_no_log": false,
"changed": false
}
- debug:
var: result
# check for condition in result
when: result['item']['subclientName'] == "test"
# iterate over result list
loop: "{{ data['countbackupsetName']['results'] }}"
# set loop_var to not confuse ansible's "item" var with "item" key in data
loop_control:
loop_var: result
Was able to solve the problem using json_query!
code:
- set_fact:
add_filter: "{{ countbackupsetName|json_query(query2) }}"
vars:
query2: "results[?count==`1`].item.subclientName"
- name: debug json_query(query2)
debug:
var: add_filter
result:
TASK [debug json_query(query2)] ************************************************
ok: [localhost] => {
"add_filter": [
"test"
]
}
code:
- set_fact:
add_filter: "{{ count_add_hostname.results|json_query(_query) }}"
vars:
_query: "[].{subclientName: '[?count==`1`]'.item.subclientName,
backupsetName: '[?count==`1`]'.item.backupsetName}"
- name: debug json_query(add_filter)
debug:
var: add_filter
I try to execute in a loop
result:
TASK [debug json_query(add_filter) var=add_filter] *****************************
ok: [localhost] => {
"add_filter": [
{
"backupsetName": null,
"subclientName": null
},
{
"backupsetName": null,
"subclientName": null
},
{
"backupsetName": null,
"subclientName": null
}
]
}
is the empty result related to a conflict in the loop item and the dictionary name item ...

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.

Fetch the values of the variables in ansible

I am trying to list the names whose matches have been found.
- name: search for files containing string
find:
paths: /root/ansible-dir
patterns: "file3.yml"
contains: "{{ item }}"
with_items: "{{ names_list }}"
register: file_match
- name: print file
debug:
msg: "{{ file_match }}"
After the above code is run, the below code gets generated :
"msg": {
"changed": false,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": false,
"examined": 14,
"failed": false,
"files": [],
"invocation": {
"module_args": {
"age": null,
"age_stamp": "mtime",
"contains": "node_mem",
"depth": null,
"excludes": null,
"file_type": "file",
"follow": false,
"get_checksum": false,
"hidden": false,
"paths": [
"/root/ansible-dir"
],
"patterns": [
"file3.yml"
],
"recurse": false,
"size": null,
"use_regex": false
}
},
"item": "node_mem",
"matched": 0,
"msg": ""
},
How to fetch the name of the item where the matched attribute is >=1?
Use subelements. The debug below gives you a hint how to iterate the results and fetch files that contain the items
- debug:
msg: "Fetch {{ item.1 }}"
with_subelements:
- "{{ file_match.results }}"
- files
It is not necessary to test the number of files is >=1. If the list of files is empty the iteration will be skipped anyway.

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