How to be make ansible regularly probing for a fact value and only proceed if the value changes? - ansible

I have a the following snippet where I install OS on a virtual machine using ansible, and after it finishes it stops the VM so I can continue the rest of the tasks, I am collecting facts from the red hat virtualization manager regarding the state the vm, and I want to keep waiting until the status of the VM changes from up to down so I can proceed, how can I code this?:
# I am kickstarting the VM
- name: Installing OS
ovirt_vms:
state: running
name: "{{ vm_name }}"
initrd_path: iso://initrd.img
kernel_path: iso://vmlinuz
kernel_params: initrd=initrd.img inst.stage2=cdrom inst.ks=ftp://10.0.1.2/pub/ks.cfg net.ifnames=0 biosdevname=0 BOOT_IMAGE=vmlinuz
# Getting facts about the VM
- name: Gather VM Status
ovirt_vms_facts:
pattern: name={{ vm_name}}
- name: Register VM Status
debug:
msg: "{{ ovirt_vms[0].status }}"
register: vm_status
#Should Keep probing the value of vm_status until it changes from up to down.
????????????? --> What should I do here?
#When Status change continue the work book
I tried to parse the ovirt_vms I gathered from ovirt_vms_facts, and I got the following:
{
"_ansible_parsed": true,
"invocation": {
"module_args": {
"all_content": false,
"pattern": "name=as-vm-type1",
"nested_attributes": [],
"case_sensitive": true,
"fetch_nested": false,
"max": null
}
},
"changed": false,
"_ansible_no_log": false,
"ansible_facts": {
"ovirt_vms": [
{
"disk_attachments": [],
"origin": "ovirt",
"sso": {
"methods": []
},
"affinity_labels": [],
"placement_policy": {
"affinity": "migratable"
},
"watchdogs": [],
"creation_time": "2018-07-15 13:54:10.565000+02:00",
"snapshots": [],
"graphics_consoles": [],
"cluster": {
"href": "/ovirt-engine/api/clusters/a5272863-38a8-469d-998e-c1e1f26f4f5a",
"id": "a5272863-38a8-469d-998e-c1e1f26f4f5a"
},
"href": "/ovirt-engine/api/vms/08406dad-5173-4241-8d42-904ddf3d096a",
"migration": {
"auto_converge": "inherit",
"compressed": "inherit"
},
"io": {
"threads": 0
},
"migration_downtime": -1,
"id": "08406dad-5173-4241-8d42-904ddf3d096a",
"high_availability": {
"priority": 0,
"enabled": false
},
"cdroms": [],
"statistics": [],
"usb": {
"enabled": false
},
"display": {
"allow_override": false,
"disconnect_action": "LOCK_SCREEN",
"file_transfer_enabled": true,
"copy_paste_enabled": true,
"secure_port": 5900,
"smartcard_enabled": false,
"single_qxl_pci": false,
"type": "spice",
"monitors": 1,
"address": "10.254.148.74"
},
"nics": [],
"tags": [],
"name": "as-vm-type1",
"bios": {
"boot_menu": {
"enabled": false
}
},
"stop_time": "2018-07-15 13:54:10.569000+02:00",
"template": {
"href": "/ovirt-engine/api/templates/00000000-0000-0000-0000-000000000000",
"id": "00000000-0000-0000-0000-000000000000"
},
"memory": 42949672960,
"type": "server",
"katello_errata": [],
"numa_tune_mode": "interleave",
"status": "up",
"next_run_configuration_exists": false,
"delete_protected": false,
"sessions": [],
"start_time": "2018-07-15 13:54:14.079000+02:00",
"quota": {
"id": "ad014a63-fd76-42da-8369-57dae2dd5979"
},
"applications": [],
"host": {
"href": "/ovirt-engine/api/hosts/56a65d3b-1c0a-4b2a-9c6c-aa96262d9502",
"id": "56a65d3b-1c0a-4b2a-9c6c-aa96262d9502"
},
"memory_policy": {
"max": 171798691840,
"guaranteed": 42949672960
},
"numa_nodes": [],
"permissions": [],
"stateless": false,
"reported_devices": [],
"large_icon": {
"href": "/ovirt-engine/api/icons/2971ddbe-1dbf-4af8-b86a-078cbbe66419",
"id": "2971ddbe-1dbf-4af8-b86a-078cbbe66419"
},
"storage_error_resume_behaviour": "auto_resume",
"cpu_profile": {
"href": "/ovirt-engine/api/cpuprofiles/34000c79-d669-41ef-8d2a-d37d7f925c3c",
"id": "34000c79-d669-41ef-8d2a-d37d7f925c3c"
},
"time_zone": {
"name": "Etc/GMT"
},
"run_once": true,
"original_template": {
"href": "/ovirt-engine/api/templates/00000000-0000-0000-0000-000000000000",
"id": "00000000-0000-0000-0000-000000000000"
},
"start_paused": false,
"host_devices": [],
"small_icon": {
"href": "/ovirt-engine/api/icons/28054380-4723-42db-a8e5-fed8a3778199",
"id": "28054380-4723-42db-a8e5-fed8a3778199"
},
"os": {
"boot": {
"devices": [
"hd",
"cdrom"
]
},
"type": "rhel_7x64"
},
"cpu": {
"architecture": "x86_64",
"topology": {
"cores": 1,
"threads": 1,
"sockets": 8
}
},
"cpu_shares": 1024
}
]
}
}

You can do it as follows:
- name: Wait for VMs to be down
ovirt_vms_facts:
auth: "{{ ovirt_auth }}"
pattern: "name={{ vm_name }}"
until: "ovirt_vms[0].status == 'down'"
retries: 5
delay: 10

You can do it as below::
- name: Register VM Status
debug:
msg: "{{ ovirt_vms[0].status }}"
register: vm_status
until: vm_status.stdout.find("down") != -1
retries: 10
delay: 5
Here it is retrying for 10 times with a delay of 5 seconds.

Related

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"
}
]

Getting a value out of registered variable in Ansible

So, I'm provisioning an EC2 instance using the ec2 module. At the end I'm using register: ec2info, so, I can later reference values inside, such as instance ID and Public DNS.
- name: Print the results
debug:
var: ec2info
Gets me
TASK [Print the results] ***********************************************************************************************************************
ok: [localhost] => {
"ec2info": {
"changed": true,
"deprecations": [
{
"collection_name": "amazon.aws",
"msg": "The 'ec2' module has been deprecated and replaced by the 'ec2_instance' module'",
"version": "4.0.0"
}
],
"failed": false,
"instance_ids": [
"i-0e9de15eb82eda3ad"
],
"instances": [
{
"ami_launch_index": "0",
"architecture": "x86_64",
"block_device_mapping": {
"/dev/sda1": {
"delete_on_termination": true,
"status": "attached",
"volume_id": "vol-066bb2dd4d14bdcac"
}
},
"dns_name": "ec2-35-173-126-60.compute-1.amazonaws.com",
"ebs_optimized": false,
"groups": {
"sg-0a732c6cbeb3f1025": "launch-wizard-39"
},
"hypervisor": "xen",
"id": "i-0e9de15eb82eda3ad",
"image_id": "ami-06644055bed38ebd9",
"instance_type": "t2.micro",
"kernel": null,
"key_name": "daro.io",
"launch_time": "2022-02-01T02:05:22.000Z",
"placement": "us-east-1c",
"private_dns_name": "ip-172-31-90-87.ec2.internal",
"private_ip": "172.31.90.87",
"public_dns_name": "ec2-35-173-126-60.compute-1.amazonaws.com",
"public_ip": "35.173.126.60",
"ramdisk": null,
"region": "us-east-1",
"root_device_name": "/dev/sda1",
"root_device_type": "ebs",
"state": "running",
"state_code": 16,
"tags": {
"Name": "new_demo_template"
},
"tenancy": "default",
"virtualization_type": "hvm"
}
],
"tagged_instances": []
}
}
I would like to get the value of Public DNS I have tried
- name: Print the results
debug:
var: ec2info.instances.public_dns_name
## AND
var: ec2info.instances['public_dns_name']
## AND
var: '{{ec2info.instances.public_dns_name}}'
If you could also point out to the part of the documentation that covers this?
So, I figured it out
var: ec2info.instances[0].public_dns_name

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 ...

Ansible search and query

Updated with suggestions from larsks.
With the following structure
"intf_output_ios": {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"failed": false,
"gathered": [
{
"name": "GigabitEthernet0/0"
},
{
"mode": "trunk",
"name": "GigabitEthernet0/1",
"trunk": {
"allowed_vlans": [
"10",
"20",
"30",
"99",
"100"
],
"encapsulation": "dot1q"
}
},
{
"mode": "trunk",
"name": "GigabitEthernet0/2",
"trunk": {
"allowed_vlans": [
"10",
"20",
"30",
"99",
"100"
],
"encapsulation": "dot1q"
}
},
{
"access": {
"vlan": 30
},
"mode": "access",
"name": "GigabitEthernet0/3"
},
{
"name": "GigabitEthernet1/0"
},
{
"name": "GigabitEthernet1/1"
},
{
"name": "GigabitEthernet1/2"
},
{
"name": "GigabitEthernet1/3"
},
{
"name": "GigabitEthernet2/0"
},
{
"name": "GigabitEthernet2/1"
},
{
"name": "GigabitEthernet2/2"
},
{
"name": "GigabitEthernet2/3"
},
{
"name": "GigabitEthernet3/0"
},
{
"name": "GigabitEthernet3/1"
},
{
"name": "GigabitEthernet3/2"
},
{
"access": {
"vlan": 99
},
"mode": "access",
"name": "GigabitEthernet3/3"
}
]
}
To print only the ports in VLAN 30 use the following?
- name: "P901T6: Set fact to include only access ports - IOS"
set_fact:
access_ports_ios_2: "{{ intf_output_ios | json_query(query) }}"
vars:
query: >-
gathered[?access.vlan==`30`]
- name: "P901T7: Dump list of access ports - IOS"
debug:
var=access_ports_ios_2
NOTE: It is important to use 30 (with backticks) and not '30'
I have gone through https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#managing-list-variables without really understanding how to fix this. If someone has some good link that would be very useful
With a structure like
ok: [access01] => {
"access_ports_ios": [
{
"access": {
"vlan": 30
},
"mode": "access",
"name": "GigabitEthernet0/3"
},
{
"access": {
"vlan": 99
},
"mode": "access",
"name": "GigabitEthernet3/3"
}
]
}
To get ports in vlan 30 use:
- debug:
var: access_ports_ios|json_query(query)
vars:
query: >-
[?access.vlan==`30`]
Note:
If you want to use a variable for vlan instead of hard-coding it. I had to do as follows:
- name: Debug 4
debug:
var: access_ports_ios|json_query('[?access.vlan==`{{ src_vlan | int}}`]')
You're asking for gathered.access, but gathered is a list and does not have an access attribute. You want "all items from gathered for which access.vlan is 30 (and note that the value of access.vlan is an integer, not a string):
- debug:
var: intf_output_ios|json_query(query)
vars:
query: >-
gathered[?access.vlan==`30`]
Which given you example input produces:
TASK [debug] *******************************************************************
ok: [localhost] => {
"intf_output_ios|json_query(query)": [
{
"access": {
"vlan": 30
},
"mode": "access",
"name": "GigabitEthernet0/3"
}
]
}
I'm going to reiterate advice I often give for json_query questions: use something like jpterm or the JMESPath website to test JMESPath expressions against your actual data. This makes it much easier to figure out where an expression might be going wrong.

Remove double quotes from Ansible fact

There is a json output which I am trying to parse. I registered the output into variable named instance_ip.
Here is the json output:
{
"msg": {
"instances": [
{
"root_device_type": "ebs",
"private_dns_name": "",
"cpu_options": {
"core_count": 2,
"threads_per_core": 1
},
"security_groups": [],
"state_reason": {
"message": "Client.UserInitiatedShutdown: User initiated shutdown",
"code": "Client.UserInitiatedShutdown"
},
"monitoring": {
"state": "disabled"
},
"ebs_optimized": false,
"state": {
"code": 48,
"name": "terminated"
},
"client_token": "test-Logst-14O6L4IETB05E",
"virtualization_type": "hvm",
"architecture": "x86_64",
"tags": {
"sg:environment": "TST",
"Name": "logstash1",
"aws:cloudformation:logical-id": "Logstash1A1594E87",
"sg:owner": "Platforms#paparapa.com",
"aws:cloudformation:stack-name": "test-three-ec2-instances-elk-demo",
"elastic_role": "logstash",
"sg:function": "Storage"
},
"key_name": "AWS_key",
"image_id": "ami-09f765d333a8ebb4b",
"state_transition_reason": "User initiated (2021-01-31 09:46:23 GMT)",
"hibernation_options": {
"configured": false
},
"capacity_reservation_specification": {
"capacity_reservation_preference": "open"
},
"public_dns_name": "",
"block_device_mappings": [],
"metadata_options": {
"http_endpoint": "enabled",
"state": "pending",
"http_tokens": "optional",
"http_put_response_hop_limit": 1
},
"placement": {
"group_name": "",
"tenancy": "default",
"availability_zone": "ap-southeast-2a"
},
"enclave_options": {
"enabled": false
},
"ami_launch_index": 0,
"ena_support": true,
"network_interfaces": [],
"launch_time": "2021-01-31T09:44:51+00:00",
"instance_id": "i-0fa5dbb869833d7c6",
"instance_type": "t2.medium",
"root_device_name": "/dev/xvda",
"hypervisor": "xen",
"product_codes": []
},
{
"root_device_type": "ebs",
"private_dns_name": "ip-10-x-x-x.ap-southeast-2.compute.internal",
"cpu_options": {
"core_count": 2,
"threads_per_core": 1
},
"source_dest_check": true,
"monitoring": {
"state": "disabled"
},
"subnet_id": "subnet-0d5f856afab8f0eec",
"ebs_optimized": false,
"iam_instance_profile": {
"id": "AIPARWXXVHXJWC2FL4AI6",
"arn": "arn:aws:iam::instance-profile/test-three-ec2-instances-elk-demo-Logstash1InstanceProfileC3035819-1F2LI7JM16FVM"
},
"state": {
"code": 16,
"name": "running"
},
"security_groups": [
{
"group_id": "sg-0e5dffa834a036fab",
"group_name": "Ansible_sec_group"
}
],
"client_token": "test-Logst-8UF6RX33BH06",
"virtualization_type": "hvm",
"architecture": "x86_64",
"public_ip_address": "3.x.x.x",
"tags": {
"Name": "logstash1",
"aws:cloudformation:logical-id": "Logstash1A1594E87",
"srg:environment": "TST",
"aws:cloudformation:stack-id": "arn:aws:cloudformation:ap-southeast-2:117557247443:stack/test-three-ec2-instances-elk-demo/ca8ef2b0-63ad-11eb-805f-02630ffccc8c",
"sg:function": "Storage",
"aws:cloudformation:stack-name": "test-three-ec2-instances-elk-demo",
"elastic_role": "logstash",
"sg:owner": "Platforms#paparapa.com"
},
"key_name": "AWS_SRG_key",
"image_id": "ami-09f765d333a8ebb4b",
"ena_support": true,
"hibernation_options": {
"configured": false
},
"capacity_reservation_specification": {
"capacity_reservation_preference": "open"
},
"public_dns_name": "ec2-3-x-x-x.ap-southeast-2.compute.amazonaws.com",
"block_device_mappings": [
{
"device_name": "/dev/xvda",
"ebs": {
"status": "attached",
"delete_on_termination": true,
"attach_time": "2021-01-31T10:22:21+00:00",
"volume_id": "vol-058662934ffba3a68"
}
}
],
"metadata_options": {
"http_endpoint": "enabled",
"state": "applied",
"http_tokens": "optional",
"http_put_response_hop_limit": 1
},
"placement": {
"group_name": "",
"tenancy": "default",
"availability_zone": "ap-southeast-2a"
},
"enclave_options": {
"enabled": false
},
"ami_launch_index": 0,
"hypervisor": "xen",
"network_interfaces": [
{
"status": "in-use",
"description": "",
"subnet_id": "subnet-0d5f856afab8f0eec",
"source_dest_check": true,
"interface_type": "interface",
"ipv6_addresses": [],
"network_interface_id": "eni-09b045668ac59990c",
"private_dns_name": "ip-10-x-x-x.ap-southeast-2.compute.internal",
"attachment": {
"status": "attached",
"device_index": 0,
"attachment_id": "eni-attach-0700cd11dfb27e2dc",
"delete_on_termination": true,
"attach_time": "2021-01-31T10:22:20+00:00"
},
"private_ip_addresses": [
{
"private_ip_address": "10.x.x.x",
"private_dns_name": "ip-10-x-x-x.ap-southeast-2.compute.internal",
"association": {
"public_ip": "3.x.x.x",
"public_dns_name": "ec2-3-x-x-x.ap-southeast-2.compute.amazonaws.com",
"ip_owner_id": "amazon"
},
"primary": true
}
],
"mac_address": "02:d1:13:01:59:b2",
"private_ip_address": "10.x.x.x",
"vpc_id": "vpc-0016dcdf5abe4fef0",
"groups": [
{
"group_id": "sg-0e5dffa834a036fab",
"group_name": "Ansible_sec_group"
}
],
"association": {
"public_ip": "3.x.x.x",
"public_dns_name": "ec2-3-x-x-x.ap-southeast-2.compute.amazonaws.com",
"ip_owner_id": "amazon"
},
"owner_id": "117557247443"
}
],
"launch_time": "2021-01-31T10:22:20+00:00",
"instance_id": "i-0482bb8ca1bef6006",
"instance_type": "t2.medium",
"root_device_name": "/dev/xvda",
"state_transition_reason": "",
"private_ip_address": "10.x.x.x",
"vpc_id": "vpc-0016dcdf5abe4fef0",
"product_codes": []
}
],
"failed": false,
"changed": false
},
"_ansible_verbose_always": true,
"_ansible_no_log": false,
"changed": false
}
The goal is to get the private ip address and append the port number.
With the following task I got the list with node ip address ["10.x.x.x"]
- name: Getting EC2 instance ip address
set_fact:
instance_ip: "{{ logstash_instance | json_query('instances[*].network_interfaces[*].private_ip_address') | flatten }}"
With next task in a play I am trying to append the port number but I am keep getting
"['10.x.x.x:5044']"
- name: Get everything between quotes and append port 5044
set_fact:
logstash_hosts: "{{ instance_ip | map('regex_replace', '^(.*)$', '\\1:5044') | list }}"
Here is the template output:
# ------------------------------ Logstash Output -------------------------------
output.logstash:
hosts: "['10.x.x.x:5044']"
I need to get rid of the double quotes and pass the clean variable ['10.x.x.x:5044'] to my template file.
You can try creating a new list variable with the port number appended to each element, using this approach:
- set_fact:
logstash_hosts: "{{ logstash_hosts|default([]) + [ item ~ ':5044' ] }}"
with_items: "{{ instance_ip }}"
Then in template:
output.logstash:
hosts: {{ logstash_hosts|to_yaml }}
Also since the Logstash configuration is a YAML formatted file, you use YAML list syntax and directly use the instance_ip variable (and avoid set_fact). Then the template will look like this:
output.logstash:
hosts:
{% for ip in instance_ip %}
- {{ ip }}:5044
{% endfor %}

Resources