SUM value from 2 lists - ansible

I have the following outputs:
{
"vmoff": [
{
"CONT2": [
"vm1",
"vm2",
"vm5"
]
},
{
"CONT1": [
"vm3",
"vm4",
"vm6"
]
}
]
}
AND
{
"vmprof2": [
{
"proc": {
"vm1": "0.5",
"vm2": "0.7",
"vm3": "1.0",
"vm4": "0.5",
"vm5": "0.5",
"vm6": "0.5"
},
"sec_sys": "CONT1"
},
{
"proc": {
"vm1": "1.0",
"vm2": "0.7",
"vm3": "1.0",
"vm4": "0.7",
"vm5": "0.5",
"vm6": "0.7"
},
"sec_sys": "CONT2"
}
]
}
I want to sum the value of proc of each vm in vmoff, for example:
proc_steal:
- sec_sys: CONT1
proc: 2.0
- sec_sys: CONT2
proc: 2.2
Obtain the proc of the not activated vm, I'm getting confused on the output, don't know to use list or dict.

I suggest you to use a custom filter:
Create a folder filter_plugins at the same level as your playbook.
I created a file myfilter.py with a filter named extractfilter
.
├── filter_plugins
│ └── myfilter.py
└── playbook.yml
whith the following content:
#!/usr/bin/python
class FilterModule(object):
def filters(self):
return {
'extractfilter': self.extractfilter
}
def extractfilter(self, l1, l2):
result = []
ky = {}
for k in l1:
ky.update(k)
for k in l2:
s = k['sec_sys']
l = ky[s]
if s in ky:
total = 0.0
proc = k['proc']
for p in proc:
if p in l:
total = total + float(proc[p])
result.append({'sec_sys': s, 'proc': total})
return result
Then the playbook which uses the custom filter:
- name: testplaybook jinja2
hosts: localhost
gather_facts: no
vars:
vmoff:
- CONT2:
- vm1
- vm2
- vm5
- CONT1:
- vm3
- vm4
- vm6
vmprof2:
- proc:
vm1: '0.5'
vm2: '0.7'
vm3: '1.0'
vm4: '0.5'
vm5: '0.5'
vm6: '0.5'
sec_sys: CONT1
- proc:
vm1: '1.0'
vm2: '0.7'
vm3: '1.0'
vm4: '0.7'
vm5: '0.5'
vm6: '0.7'
sec_sys: CONT2
tasks:
- name: DEFINE VARIABLE SPINE
set_fact:
proc_steal: "{{ vmoff | extractfilter(vmprof2) }}"
- debug: msg="{{ proc_steal }}"
result:
{
"msg": [
{
"proc": 2.0,
"sec_sys": "CONT1"
},
{
"proc": 2.2,
"sec_sys": "CONT2"
}
]
}
If you have a problem with the custom filter you could use jinja:
- name: "make this working"
hosts: localhost
vars:
vmoff:
- CONT2:
- vm1
- vm2
- vm5
- CONT1:
- vm3
- vm4
- vm6
vmprof2:
- proc:
vm1: '0.5'
vm2: '0.7'
vm3: '1.0'
vm4: '0.5'
vm5: '0.5'
vm6: '0.5'
sec_sys: CONT1
- proc:
vm1: '1.0'
vm2: '0.7'
vm3: '1.0'
vm4: '0.7'
vm5: '0.5'
vm6: '0.7'
sec_sys: CONT2
tasks:
- name: list to dict
set_fact:
ky: "{{ ky | d({}) | combine( item ) }}"
loop: "{{ vmoff }}"
- name: list to dict
set_fact:
result: "{{ result| d([]) + [{'sec_sys': s, 'proc': total}] }}"
loop: "{{ vmprof2 }}"
vars:
s: "{{ item['sec_sys'] }}"
l: "{{ ky[s] }}"
total: >-
{%- set st = namespace(tt=0.0) -%}
{%- for p in item['proc'] if p in l -%}
{%- set st.tt = st.tt + (item['proc'][p] | float) -%}
{%- endfor -%}
{{ st.tt | float }}
when: s in ky
- name: list to dict
debug:
msg: "{{ result }}"

Related

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

Ansible adding items to nested list

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

Ansible merge listed dictionaries

I'm currently building a Ansible playbook which provides me with below two variables. I need to merge these into one variable where the ipAddresses match as showed in the example below.
---
- hosts: localhost
gather_facts: no
vars:
sites:
- siteGroupId: 123
siteName: name123
siteDevices:
- ipAddress: 1.1.1.1
- ipAddress: 2.2.2.2
- siteGroupId: 456
siteName: name456
siteDevices:
- ipAddress: 3.3.3.3
- ipAddress: 4.4.4.4
devices:
- ipAddress: 1.1.1.1
deviceName: name123-a.tld
- ipAddress: 2.2.2.2
deviceName: name123-b.tld
- ipAddress: 3.3.3.3
deviceName: name456-a.tld
- ipAddress: 4.4.4.4
deviceName: name456-b.tld
Expected output:
sites:
- siteGroupId: 123
siteName: name123
siteDevices:
- ipAddress: 1.1.1.1
deviceName: name123-a.tld
- ipAddress: 2.2.2.2
deviceName: name123-b.tld
- siteGroupId: 456
siteName: name456
siteDevices:
- ipAddress: 3.3.3.3
deviceName: name456-a.tld
- ipAddress: 4.4.4.4
deviceName: name456-b.tld
What I have succeed so far with the below code is that I get the name added to the site but get 4 sites (duplicated siteGroupID as output).
---
- hosts: localhost
gather_facts: no
vars:
sites:
- siteGroupId: 123
siteName: name123
siteDevices:
- ipAddress: 1.1.1.1
- ipAddress: 2.2.2.2
- siteGroupId: 456
siteName: name456
siteDevices:
- ipAddress: 3.3.3.3
- ipAddress: 4.4.4.4
devices:
- ipAddress: 1.1.1.1
deviceName: name123-a.tld
- ipAddress: 2.2.2.2
deviceName: name123-b.tld
- ipAddress: 3.3.3.3
deviceName: name456-a.tld
- ipAddress: 4.4.4.4
deviceName: name456-b.tld
tasks:
- set_fact:
tmpVar1: "{{ item.0 | combine({'siteDevices': [ item.1 | combine(devices | selectattr('ipAddress','equalto',item.1.ipAddress) | first) ] }) }}"
loop: "{{lookup('subelements', sites, 'siteDevices', {'skip_missing': True})}}"
register: tmpVar2
- name: tmpVar1
debug:
msg: "{{ tmpVar1 }}"
- name: tmpVar2
debug:
msg: "{{ tmpVar2 }}"
- set_fact:
sites: "{{ tmpVar2.results | map(attribute='ansible_facts.tmpVar1') | list }}"
- name: SITES
debug:
msg: "{{ sites }}"
OUTPUT:
{
"siteDevices": [
{
"deviceName": "name123-a.tld",
"ipAddress": "1.1.1.1"
}
],
"siteGroupId": 123,
"siteName": "name123"
},
{
"siteDevices": [
{
"deviceName": "name123-b.tld",
"ipAddress": "2.2.2.2"
}
],
"siteGroupId": 123,
"siteName": "name123"
},
{
"siteDevices": [
{
"deviceName": "name456-a.tld",
"ipAddress": "3.3.3.3"
}
],
"siteGroupId": 456,
"siteName": "name456"
},
{
"siteDevices": [
{
"deviceName": "name456-b.tld",
"ipAddress": "4.4.4.4"
}
],
"siteGroupId": 456,
"siteName": "name456"
}
The tasks
- set_fact:
devices_dict: "{{ devices|
items2dict(key_name='ipAddress',
value_name='deviceName') }}"
- set_fact:
sites2: "{{ sites2|default([]) + [
item|
combine({'siteDevices':
dict(my_ipAddress|
zip(my_ipAddress|
map('extract', devices_dict)))|
dict2items(key_name='ipAddress',
value_name='deviceName')})] }}"
vars:
my_ipAddress: "{{ item.siteDevices|json_query('[].ipAddress') }}"
loop: "{{ sites }}"
- debug:
var: sites2
give
"sites2": [
{
"siteDevices": [
{
"deviceName": "name123-a.tld",
"ipAddress": "1.1.1.1"
},
{
"deviceName": "name123-b.tld",
"ipAddress": "2.2.2.2"
}
],
"siteGroupId": 123,
"siteName": "name123"
},
{
"siteDevices": [
{
"deviceName": "name456-a.tld",
"ipAddress": "3.3.3.3"
},
{
"deviceName": "name456-b.tld",
"ipAddress": "4.4.4.4"
}
],
"siteGroupId": 456,
"siteName": "name456"
}
]

Setting multiple values in sysctl with Ansible

I have a playbook with several tasks setting values to sysctl. Instead of having a task for each setting, how can I set all the values with one task, using the sysctl module?
Playbook snippet:
- name: Set tcp_keepalive_probes in sysctl
become: yes
sysctl:
name: net.ipv4.tcp_keepalive_probes
value: 3
state: present
reload: yes
- name: Set tcp_keepalive_intvl in sysctl
become: yes
sysctl:
name: net.ipv4.tcp_keepalive_intvl
value: 10
state: present
reload: yes
- name: Set rmem_default in sysctl
become: yes
sysctl:
name: net.core.rmem_default
value: 16777216
state: present
reload: yes
define all the variables in a var file:
e.g.
sysctl:
- name: test
value: test
...
...
playbook:
- hosts: "{{ }}"
tasks:
- name: update sysctl param
sysctl:
name: "{{ item.name }}"
value: "{{ item.value }}"
state: present
reload: yes
with_items:
- "{{ hosts }}"
Simple solution: define variable as a dict
Example playbook:
---
- hosts: all
gather_facts: false
become: true
vars:
ansible_python_interpreter: /usr/bin/python3
sysctl_config:
net.ipv4.ip_forward: 1
net.ipv4.conf.all.forwarding: 1
net.ipv6.conf.all.forwarding: 1
tasks:
- name: Change various sysctl-settings
sysctl:
name: '{{ item.key }}'
value: '{{ item.value }}'
sysctl_set: yes
state: present
reload: yes
ignoreerrors: yes
with_dict: '{{ sysctl_config }}'
Output:
TASK [Change various sysctl-settings] **********************************************************************************************************************************************************************
changed: [10.10.10.10] => (item={'key': 'net.ipv4.ip_forward', 'value': 1}) => {
"ansible_loop_var": "item",
"changed": true,
"item": {
"key": "net.ipv4.ip_forward",
"value": 1
}
}
changed: [10.10.10.10] => (item={'key': 'net.ipv4.conf.all.forwarding', 'value': 1}) => {
"ansible_loop_var": "item",
"changed": true,
"item": {
"key": "net.ipv4.conf.all.forwarding",
"value": 1
}
}
changed: [10.10.10.10] => (item={'key': 'net.ipv6.conf.all.forwarding', 'value': 1}) => {
"ansible_loop_var": "item",
"changed": true,
"item": {
"key": "net.ipv6.conf.all.forwarding",
"value": 1
}
}

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