Ansible adding items to nested list - ansible

starting data:
ok: [test#test.com] => {
"msg": {
"testdb1": {
"dbe_user_not_in_db": [
"test_user1",
"test_user2"
],
}
}
}
I currently have the following in ansible:
- name: Create dbe_pass_pairs
set_fact:
ora_sid_home_map: "{{ora_sid_home_map|combine({ item[0].key: {'dbe_pass_pairs': {item[1]: password} }}, recursive=True)}}"
loop: "{{ ora_sid_home_map | dict2items | subelements('value.dbe_user_not_in_db') }}"
vars:
password: "{{ lookup('password', '/dev/null length=10 chars=ascii_letters,digits') }}"
Which yields:
ok: [test#test.com] => {
"msg": {
"testdb1": {
"dbe_pass_pairs": {
"test_user1": "4SS2kJ7p0z",
"test_user2": "VLIzNfoaxf"
},
"dbe_user_not_in_db": [
"test_user1",
"test_user2"
],
}
}
}
Instead of dbe_pass_pairs containing dictionary items I'd like them to be a list of strings like such with a semicolon as:
ok: [test#test.com] => {
"msg": {
"testdb1": {
"dbe_pass_pairs": [
"test_user1;4SS2kJ7p0z",
"test_user2;VLIzNfoaxf"
],
"dbe_user_not_in_db": [
"test_user1",
"test_user2"
],
}
}
}
Doing something like the following just overwrite the list instead of appending:
- name: Create dbe_pass_pairs
set_fact:
ora_sid_home_map: "{{ora_sid_home_map|combine({ item[0].key: {'dbe_pass_pairs': [item[1] + ';' + password] }}, recursive=True)}}"
loop: "{{ ora_sid_home_map | dict2items | subelements('value.dbe_user_not_in_db') }}"
vars:
password: "{{ lookup('password', '/dev/null length=10 chars=ascii_letters,digits') }}"
"dbe_pass_pairs": [
"test_user2;AxL6ayeZIH"
],
Any idea how to get what I'm looking for data wise?

a solution using jinja2:
- name: Reproduce issue
hosts: localhost
gather_facts: yes
vars:
ora_sid_home_map:
testdb1:
dbe_user_not_in_db: ["test_user1", "test_user2"]
tasks:
- name: Create paswords
set_fact:
ora_sid_home_map: >-
{%- set ns=namespace(result=[], ident="", final={}) -%}
{%- set ns.ident = ora_sid_home_map |first -%}
{%- for user in ora_sid_home_map[ns.ident].dbe_user_not_in_db -%}
{%- set password = lookup('password', '/dev/null length=10 chars=ascii_letters,digits') -%}
{%- if ns.result.append(user ~ ';' ~ password) -%}{%- endif -%}
{%- endfor -%}
{{ {ns.ident: ora_sid_home_map[ns.ident] | combine({'dbe_pass_pairs': ns.result})} }}
- debug:
msg: "{{ ora_sid_home_map }}"
result:
ok: [localhost] => {
"msg": {
"testdb1": {
"dbe_pass_pairs": [
"test_user1;tPOSfCzLLq",
"test_user2;e0A92Dkuac"
],
"dbe_user_not_in_db": [
"test_user1",
"test_user2"
]
}
}
}
without jinja2:
- name: Reproduce issue
hosts: localhost
gather_facts: yes
vars:
ora_sid_home_map:
testdb1:
dbe_user_not_in_db: ["test_user1", "test_user2"]
tasks:
- name: Create paswords
set_fact:
passwords: "{{ passwords | d([]) + [data] }}"
loop: "{{ ora_sid_home_map[ident].dbe_user_not_in_db }}"
vars:
password: "{{ lookup('password', '/dev/null length=10 chars=ascii_letters,digits') }}"
data: "{{ item ~ ';' ~ password }}"
ident: "{{ ora_sid_home_map|first }}"
- name: result
set_fact:
ora_sid_home_map: "{{ {ident: data} }}"
vars:
ident: "{{ ora_sid_home_map|first }}"
data: "{{ ora_sid_home_map[ident]| combine({'dbe_pass_pairs': passwords}) }}"
- debug:
msg: "{{ ora_sid_home_map }}"

Related

To collect backing_datastore from the vmware_guest_disk_info module output

I'm using the below tasks in the playbook to find the backing datastore in the vmware but I tried various options, which is not helping to gather the backing_datastore name, kindly suggest how to fetch:
- name: Take Snapshot
hosts: patching
serial: 1
vars_files:
- 1credentials.yml
tasks:
- name: Gather data of the registered virtual machines
community.vmware.vmware_vm_info:
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
password: '{{ vcenter_password }}'
vm_type: vm
validate_certs: no
delegate_to: localhost
register: vminfo
- debug:
msg: "{{ item.datacenter }}"
loop: "{{ vminfo.virtual_machines}}"
when: item.ip_address == inventory_hostname
- name: Gather Disk facts for the server - {{ inventory_hostname }}
vmware_guest_disk_info:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
datacenter: "{{ item.datacenter }}"
uuid: "{{ item.uuid }}"
validate_certs: False
delegate_to: localhost
register: disk_fact
loop: "{{ vminfo.virtual_machines }}"
when: item.ip_address == inventory_hostname
- debug:
msg: "{{ item.backing_datastore }}"
loop: "{{ disk_fact }}"
The raw output of the registered variable disk_fact is mentioned below:
ok: [172.17.92.62] => {
"msg": {
"changed": false,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": false,
"item": {
"allocated": {},
"attributes": {},
"cluster": "Training",
"datacenter": "opendc-rookie",
"datastore_url": [
{
"name": "Rookie-Core",
"url": "/vmfs/volumes/60ebc5fb-2e22fef3-ec42-1402ec6fadc8"
},
{
"name": "ENV08",
"url": "/vmfs/volumes/60ebd414-4e6253d6-7e29-1402ec6fadc8"
}
],
"esxi_hostname": "172.17.138.13",
"folder": "/opendc-rookie/vm/ENV08",
"guest_fullname": "Microsoft Windows 8.x (64-bit)",
"guest_name": "win1",
"ip_address": "172.17.92.43",
"mac_address": [
"00:50:56:81:2e:64"
],
"moid": "vm-968",
"power_state": "poweredOn",
"tags": [],
"uuid": "4201e3dd-0cf5-1027-7eaf-d2b8804761d9",
"vm_network": {
"00:50:56:81:2e:64": {
"ipv4": [
"172.17.92.43"
],
"ipv6": []
}
}
},
"skip_reason": "Conditional result was False",
"skipped": true
},
{
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"guest_disk_info": {
"0": {
"backing_datastore": "ENV04",
"backing_disk_mode": "persistent",
"backing_diskmode": "persistent",
"backing_eagerlyscrub": false,
"backing_filename": "[ENV04] ansible_automation_platofrm_RHEL8/ansible_automation_platofrm_RHEL8-000005.vmdk",
"backing_thinprovisioned": false,
"backing_type": "FlatVer2",
"backing_uuid": "6000C294-c77a-56fa-180c-d17ac9693433",
"backing_writethrough": false,
"capacity_in_bytes": 25769803776,
"capacity_in_kb": 25165824,
"controller_bus_number": 0,
"controller_key": 1000,
"controller_type": "paravirtual",
"key": 2000,
"label": "Hard disk 1",
"summary": "25,165,824 KB",
"unit_number": 0
}
},
"invocation": {
"module_args": {
"datacenter": "opendc-rookie",
"folder": null,
"hostname": "172.17.168.212",
"moid": null,
"name": null,
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"port": 443,
"proxy_host": null,
"proxy_port": null,
"use_instance_uuid": false,
"username": "Administrator#vsphere.local",
"uuid": "42013f12-5142-2b83-1ce7-6c334958afd5",
"validate_certs": false
}
},
"item": {
"allocated": {},
"attributes": {},
"cluster": "Training",
"datacenter": "opendc-rookie",
"datastore_url": [
{
"name": "Rookie-Core",
"url": "/vmfs/volumes/60ebc5fb-2e22fef3-ec42-1402ec6fadc8"
},
{
"name": "ENV04",
"url": "/vmfs/volumes/60ebd318-7c586ef0-5838-1402ec6fadc8"
}
],
"esxi_hostname": "172.17.138.13",
"folder": "/opendc-rookie/vm/Pugaz",
"guest_fullname": "Red Hat Enterprise Linux 8 (64-bit)",
"guest_name": "ansible_automation_platofrm_RHEL8",
"ip_address": "172.17.92.62",
"mac_address": [
"00:50:56:81:c6:e3"
],
"moid": "vm-836",
"power_state": "poweredOn",
"tags": [],
"uuid": "42013f12-5142-2b83-1ce7-6c334958afd5",
"vm_network": {
"00:50:56:81:c6:e3": {
"ipv4": [
"172.17.92.62"
],
"ipv6": [
"fe80::250:56ff:fe81:c6e3"
]
}
}
}
}
Kindly suggest how can I fetch the backing_datastore from the above mentioned output.
The result is a list because there might be more items with the attribute backing_datastore. For example,
backing_datastores: "{{ disk_fact.results|json_query(_query) }}"
_query: '[].guest_disk_info[].*.backing_datastore'
gives
backing_datastores:
- - ENV04
If you want the first one
backing_datastore: "{{ backing_datastores|flatten|first }}"
gives
backing_datastore: ENV04
If you want to iterate results
- debug:
msg: "{{ item.guest_disk_info['0'].backing_datastore }}"
loop: "{{ disk_fact.results }}"
loop_control:
label: "{{ item.item.ip_address }}"
when: not item.skipped|d(false)
gives the attribute backing_datastore of the disk "0"
TASK [debug] **************************************************
skipping: [localhost] => (item=172.17.92.43)
ok: [localhost] => (item=172.17.92.62) =>
msg: ENV04
If you want to get the list of attributes backing_datastore of all disks use json_query in the loop
- debug:
msg: "{{ item.guest_disk_info|json_query('*.backing_datastore') }}"
loop: "{{ disk_fact.results }}"
loop_control:
label: "{{ item.item.ip_address }}"
when: not item.skipped|d(false)
gives
TASK [debug] **************************************************
skipping: [localhost] => (item=172.17.92.43)
ok: [localhost] => (item=172.17.92.62) =>
msg:
- ENV04
Example of a complete playbook for testing
- hosts: localhost
vars_files:
- disk_fact.json
vars:
backing_datastores: "{{ disk_fact.results|json_query(_query) }}"
_query: '[].guest_disk_info[].*.backing_datastore'
backing_datastore: "{{ backing_datastores|flatten|first }}"
tasks:
- debug:
var: backing_datastores
- debug:
var: backing_datastore
- debug:
msg: "{{ item.guest_disk_info['0'].backing_datastore }}"
loop: "{{ disk_fact.results }}"
loop_control:
label: "{{ item.item.ip_address }}"
when: not item.skipped|d(false)

Parsing dictionary from VMware module

I'm using ansible community.vmware.vmware_datacenter_info.I only want to get the name of my several datacenter in vCenter.
Here is my play:
---
- hosts: localhost
gather_facts: False
tasks:
- name: Gather information about all datacenters
community.vmware.vmware_datacenter_info:
hostname: "{{ vCenter }}"
username: "{{ vCenter_username }}"
password: "{{ vCenter_password }}"
validate_certs: False
delegate_to: localhost
register: result
Here is the output of my variable result:
TASK [Print the gateway for each host when defined] ********************************
ok: [localhost] => {
"msg": {
"changed": false,
"datacenter_info": [
{
"config_status": "gray",
"moid": "datacenter-271",
"name": "Sample_DC_1",
"overall_status": "gray"
},
{
"config_status": "gray",
"moid": "datacenter-276",
"name": "Sample_DC_2",
"overall_status": "gray"
}
],
"failed": false
}
}
What I would like to get is only the name for both datacenter: Sample_DC_1 and Simple_DC_2 so I can use them in another play.
What I tried:
- name: Display datacenter name
debug:
msg:
- "{{ item.value.name }}"
loop: "{{ lookup('dict', result) }}"
Result:
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'bool object' has no attribute 'name
if I only try to display "Key: {{ item.key }}" & " Value: {{ item.value }}" I got this output:
"msg": [
"Key : datacenter_info Value : [{'name': 'Sample_DC_1', 'moid': 'datacenter-271', 'config_status': 'gray', 'overall_status': 'gray'}, {'name': 'Sample_DC_2', 'moid': 'datacenter-276', 'config_status': 'gray', 'overall_status': 'gray'}]"
]
How can I register my both datacenter's name in a var so I can re-use them later in the playbook?
Q: "Get the names of both datacenter."
A: Map the attribute
dc_names: "{{ result.datacenter_info|map(attribute='name')|list }}"
Example of a complete playbook for testing
- hosts: localhost
vars:
result:
changed: false
datacenter_info:
- config_status: gray
moid: datacenter-271
name: Sample_DC_1
overall_status: gray
- config_status: gray
moid: datacenter-276
name: Sample_DC_2
overall_status: gray
failed: false
dc_names: "{{ result.datacenter_info|map(attribute='name')|list }}"
tasks:
- debug:
var: dc_names
gives
dc_names:
- Sample_DC_1
- Sample_DC_2

How to iterate over variables in an ansible dictionary

I have a role that should scatter NGINX configs across different servers using Jinja2 templates, referring to the variables specified in defaults/main, please tell me how to write a loop to iterate over these variables correctly, tried it through with_items and with_nested, but nothing happens.
The defaults/main file looks like this:
allservers:
server1:
- { src: 'templates/sites-enabled/api.j2', dest: '/etc/nginx/sites-enabled/api.conf' }
- { src: 'templates/sites-enabled/citizens.j2', dest: '/etc/nginx/sites-enabled/citizens.conf' }
- { src: 'templates/sites-enabled/control.j2', dest: '/etc/nginx/sites-enabled/control.conf' }
- { src: 'templates/sites-enabled/documents.j2', dest: '/etc/nginx/sites-enabled/documents.conf' }
- { src: 'templates/sites-enabled/orders.j2', dest: '/etc/nginx/sites-enabled/orders.conf' }
- { src: 'templates/sites-enabled/logs.j2', dest: '/etc/nginx/sites-enabled/logs.conf' }
server2:
- { src: 'templates/sites-enabled/permissions.j2', dest: '/etc/nginx/sites-enabled/permissions.conf' }
- { src: 'templates/sites-enabled/documents.j2', dest: '/etc/nginx/sites-enabled/documents.conf' }
- { src: 'templates/sites-enabled/default.j2', dest: '/etc/nginx/sites-enabled/default' }
- { src: 'templates/sites-enabled/orders.j2', dest: '/etc/nginx/sites-enabled/orders.conf' }
- { src: 'templates/sites-enabled/settings.j2', dest: '/etc/nginx/sites-enabled/settings.conf' }
I assume you do not want to change your data structure, and that server1 and server2 refer to hosts in your inventory.
---
- hosts: server1:server2
remote_user: ansible
vars:
allservers:
server1:
- { src: "/tmp/file1", dest: "/tmp"}
- { src: "/tmp/file2", dest: "/tmp"}
- { src: "/tmp/file3", dest: "/tmp"}
server2:
- { src: "/tmp/file4", dest: "/tmp"}
- { src: "/tmp/file5", dest: "/tmp"}
- { src: "/tmp/file6", dest: "/tmp"}
tasks:
- name: Copy template
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
when: inventory_hostname in allservers.keys()
with_items:
- "{{ allservers[inventory_hostname] }}"
Another solutions is to include a task (copy_template.yml) which you will iterate over using with_dict: allservers.
playbook.yml
---
- hosts: server1:server2
remote_user: ansible
vars:
allservers:
server1:
- { src: "/tmp/file1", dest: "/tmp"}
- { src: "/tmp/file2", dest: "/tmp"}
- { src: "/tmp/file3", dest: "/tmp"}
server2:
- { src: "/tmp/file4", dest: "/tmp"}
- { src: "/tmp/file5", dest: "/tmp"}
- { src: "/tmp/file6", dest: "/tmp"}
tasks:
- include: copy_template.yml
vars:
server: "{{ item.key }}"
with_dict:
- "{{ allservers }}"
copy_template.yml
---
- debug:
msg: "{{ template.src }} and {{ template.dest }}"
loop: "{{ allservers[server] }}"
when: server == inventory_hostname
loop_control:
loop_var: template

Filter ansible output parameter without double quotes

I am trying to filter one parameter from the output but the value is in quotes. I need the value without quotes. I tried slicing and using some filters but it didn't work. Appreciate your help.
Attaching the output below.
[localhost] => {
"retunrn_item": {
"cache_control": "private",
"changed": false,
"connection": "close",
"content_length": "48",
"content_type": "application/json;charset=utf-8",
"cookies_string": "JSESSIONID=1007F276D92C74C40F45D1016CF17B44",
"elapsed": 1,
"failed": false,
"json": {
"_type_": 3,
"clientId": 2,
"clientName": "mydns"
},
"msg": "OK (48 bytes)"\
I am trying to filter the ClientID which has a value 2. But the value is in Quotes when i print using Debug or do a set_fact.
- debug:
msg: "{{ return_item.json.clientID }}"
this prints the below output:
msg: "2"
I have to pass this clientID in the next task. Please find below.
name: blackout uri:
url: http:*******
method: POST
body_format: json
headers:
Authtoken: "{{ login.json.token }}"
Accept: application/json
Content-Type: application/json
body:
operationWindow:
endDate: "{{ operationWindow_enddate }}"
name: "{{ operationWindow_name }}"
startDate: "{{ operationWindow_startdate }}"
operations: "[{{ operationWindow_opreations }}]"
dayTime:
- startTime: "{{ operationWindow_daytime_starttime }}"
endTime: "{{ operationWindow_daytime_endtime }}"
dayOfWeek: "[{{ operationWindow_daytime_dayofweek }}]"
entity:
clientGroupId: "{{ groupid_value }}" #"{{ entity_clientgroupid }}"
#clientId: "{{ clientid2.json.clientId }}" #"{{ entity_clientid }}"
clientId: "{{ clientid2.json.clientId }}"
validate_certs: false
retries: 5
delay: 6

Create an AMI using ansible ec2_ami module and grab snapshot_id(s) from registered variable

I have the following playbook:
- hosts: localhost
connection: local
gather_facts: False
tasks:
- name: Read Variables
include_vars:
file: variables.yml
- name: Create AMI
ec2_ami:
aws_access_key: "{{ ACCESS_KEY }}"
aws_secret_key: "{{ SECRET_KEY }}"
region: "{{ AWS_REGION }}"
delete_snapshot: yes
instance_id: "{{ ID_INSTANCE }}"
name: "{{ SUFFIX_BACKUP }}-{{ NAME_BACKUP }}"
wait: yes
description: "{{ DESCR }}"
tags:
project: project1
register: ami_data
Example content of "ami_data" variable:
"msg": {
"architecture": "x86_64",
"block_device_mapping": {
"/dev/sda1": {
"delete_on_termination": true,
"encrypted": false,
"size": 30,
"snapshot_id": "snap-0e95eac98734af1d1",
"volume_type": "gp2"
}
},
"changed": false,
"creationDate": "2017-12-13T17:02:47.000Z",
"description": "descripition",
"failed": false,
"hypervisor": "xen",
"image_id": "ami-XXXXXX",
"is_public": false,
"launch_permissions": {},
"location": "457841571138/MYAMINAME",
"msg": "AMI not updated",
"name": "MYAMINAME",
"ownerId": "XXXXXXXXXX",
"platform": null,
"root_device_name": "/dev/sda1",
"root_device_type": "ebs",
"state": "available",
"tags": {
"project": "project1",
},
"virtualization_type": "hvm"
}
}
And now I want to grab the "snapshot_id" that was registered on "ami_data" variable for every disk on it. I have tried the following debug tasks using "msg" to show the value(s) of "snapshot_id" but non of them worked. What I'm doing wrong?
- name: Show data
debug:
msg: "{{ ami_data.block_device_mapping[*].snapshot_id }}"
- name: Show data
debug:
msg: "{{ ami_data.block_device_mapping[/dev/sda1].snapshot_id }}"
- name: Show data
debug:
msg: "{{ ami_data.block_device_mapping./dev/sda1.snapshot_id }}"
- name: Show data
debug:
msg: "{{ ami_data.block_device_mapping.[*].snapshot_id }}"
This one works:
- name: Show data
debug:
msg: "{{ ami_data.block_device_mapping }}"
And give me the following:
ok: [localhost] => {
"msg": {
"/dev/sda1": {
"delete_on_termination": true,
"encrypted": false,
"size": 30,
"snapshot_id": "snap-0ea846d9aca82b51f",
"volume_type": "gp2"
}
}
}
Firstly, with the ami_data.block_device_mapping you have to iterate with the list and after search under the map with the key name of the element (snapshot_id in this case):
- debug:
msg: {{ item }}
with_items: "{{ ami_data.block_device_mapping|map(attribute='snapshot_id')|list}}"
You were really close. Use square brackets but use quotes to specify literals:
- name: Show data
debug:
msg: "{{ ami_data.block_device_mapping['/dev/sda1'].snapshot_id }}"
or using variables:
- name: Show data
debug:
msg: "{{ ami_data.block_device_mapping[item].snapshot_id }}"
with_items: "{{ ami_data.block_device_mapping }}"

Resources