Get Volume group attributes to be used in condition using Ansible - ansible

I would like to be able to get list of volume groups available and then use the attributes of the volume group to conditionally create the filesystem on volume which meets the Criteria
Criteria
1: Volume must not have name root in it
2: Volume must be at-least 2 GB
I have this logic
- name: list volume groups
debug: msg="echo volume groups is {{ item }}"
with_items: "{{ ansible_lvm.vgs }}
But am struggling to get that attribute of the vgs.
Here is snippet of ansible_lvm
"ansible_lvm": {
"lvs": {
"lvud01": {
"size_g": "0.50",
"vg": "vgud01"
},
"root": {
"size_g": "79.01",
"vg": "precise32"
},
"swap_1": {
"size_g": "0.75",
"vg": "precise32"
}
},
"vgs": {
"precise32": {
"free_g": "0",
"num_lvs": "2",
"num_pvs": "1",
"size_g": "79.76"
},
"vgud01": {
"free_g": "0.50",
"num_lvs": "1",
"num_pvs": "1",
"size_g": "1.00"
}
}

Just for everyones benefit and thanks #fishi
- name: list volume groups
debug: msg="echo volume groups is {{ item.key }} has {{ item.value.free_g }}"
with_dict: "{{ ansible_lvm.vgs }}"
when: not item.key == "root"

For those like me taken here by Google and wondering where this ansible_lvm dict comes from :
it is part of the facts gathered by the setup module
it is collected only when executed with super-user privileges
In other words, to get ansible_lvm :
with an ad-hoc command (the ✨magic✨ lies in the -b) :
ansible myManagedNode -m setup -kK -b
within a playbook :
- hosts: myManagedNode
become: yes
tasks:
- debug:
var: ansible_lvm

Related

Ansible nested loop

Is it possible for Ansible to do a nested loop as I want to do a filtering and set fact.
The first fact that I have is
"username_and_role": [
{
"Name": "Jack",
"Role": "Admin User"
},
{
"Name": "Tom",
"Role": "Buyer"
},
{
"Name": "Jill",
"Role": "Seller"
}
]
The second fact that I have is
"username_and_status": [
{
"isLockedOut": "no",
"Name": "Jack"
},
{
"isLockedOut": "no",
"Name": "Tom"
},
{
"isLockedOut": "no",
"Name": "Jill"
},
{
"isLockedOut": "no",
"Name": "Brody"
},
{
"isLockedOut": "no",
"Name": "Steve"
}
]
My objective is that I want to retrieve isLockedOut from second data. If name in username_and_role is equal to name in username_and_status, retrieve the isLockedOut from username and status. and set a fact that show name, role and isLockedOut.
I've tried a few methods and it doesn't work as it didn't do the checking.
set_fact:
my_new_list: "{{[username_and_role, {'status': nameIsMatch}] }}"
cacheable: yes
with_items: "{{username_and_role}}"
vars:
nameIsMatch: "{% if item.Name == username%}item.isLockedOut{% else %}Name Does not Match{%endif %}"
loop: "{{username_and_status}}"
This is code has no error but it just did not do the checking between username_and_role & username_and_status
Convert the lists to dictionaries, e.g.
- set_fact:
username_and_role: "{{ username_and_role|
items2dict(key_name='Name',
value_name='Role') }}"
gives
username_and_role:
Jack: Admin User
Jill: Seller
Tom: Buyer
- set_fact:
username_and_status: "{{ username_and_status|
items2dict(key_name='Name',
value_name='isLockedOut') }}"
gives
username_and_status:
Brody: 'no'
Jack: 'no'
Jill: 'no'
Steve: 'no'
Tom: 'no'
Now you can retrieve the status by using the dictionary, e.g.
- debug:
msg: >
name: {{ item }}
role: {{ username_and_role[item]|d('NA') }}
status: {{ username_and_status[item]|d('NA') }}
loop: "{{ username_and_status.keys()|list }}"
gives
msg: |-
name: Jack role: Admin User status: no
msg: |-
name: Tom role: Buyer status: no
msg: |-
name: Jill role: Seller status: no
msg: |-
name: Brody role: NA status: no
msg: |-
name: Steve role: NA status: no
just to precise the nice answer of #vladimir-botka, if you just want the persons which are in both variables,
you could add a condition when
- debug:
msg: >
name: {{ item }}
role: {{ username_and_role[item] }}
status: {{ username_and_status[item] }}
when: username_and_role[item] is defined and username_and_status[item] is defined
loop: "{{ username_and_status.keys()|list }}"
- debug:
var: username_and_role | to_nice_json
result:
ok: [localhost] =>
username_and_role | to_nice_json: |-
{
"Jack": "Admin User",
"Jill": "Seller",
"Tom": "Buyer"
}

How do I work with Ansible list of dicts?

I'm so confused with this. If I have a file containing:
users:
- name: jconnor
first: john
last: connor
uid: 3003
- name: sconnor
first: sarah
last: connor
uid: 3001
How do I get the details of each user? With this simple playbook:
- name: create users
hosts: localhost
gather_facts: false
tasks:
- name: Include vars
include_vars:
file: user_list.yml
name: users
- name: debug
debug:
msg: "{{ item }}"
with_dict: "{{ users }}"
I get the following which I can't use:
ok: [localhost] => (item={'value': [{u'last': u'connor', u'uid': 3003, u'name': u'jconnor', u'first': u'john'}, {u'last': u'connor', u'uid': 3001, u'name': u'sconnor', u'first': u'sarah'}], 'key': u'users'}) => {
"msg": {
"key": "users",
"value": [
{
"first": "john",
"last": "connor",
"name": "jconnor",
"uid": 3003
},
{
"first": "sarah",
"last": "connor",
"name": "sconnor",
"uid": 3001
}
]
}
}
I want to create user accounts with this but I simply don't understand how to use this structure.
Note that this is part of a larger structure and I can't change it.
Thanks
Since the users variable is a list of dicts, you should loop with loop or with_items. Then we can access the key of each dict with item.key. E.g.: item.name, item.uid, etc.
Note that you are importing the variables from the file with the name users. So this variable now contains the users hash of that file. If you skip name: users in include_var, then you can directly access the users dict while looping.
tasks:
- include_vars:
file: user_list.yml
name: users
- debug:
msg: "Username is {{ item.name }}, full name is {{ item.first }} {{ item.last }}, userid is {{ item.uid }}"
with_items: "{{ users.users }}"
This outputs message (showing 1 item):
ok: [localhost] => (item={u'last': u'connor', u'uid': 3003, u'name': u'jconnor', u'first': u'john'}) => {
"msg": "Username is jconnor, full name is john connor, userid is 3003"
}

How to pull deeply nested data from a dictionary in ansible

I am trying to print nested data from an ansible dictionary. However, I cannot figure out how to pull the nested values. Specifically, in the data below, I am trying to print the two values returned under "ipv4". Currently, the output of item.value.ipv4 is the portion in brackets below:
"msg": "GigabitEthernet0/0/0,[{'address': '192.168.3.1', 'subnet': '28'}]"
I would like to just use the value like so:
"msg": "GigabitEthernet0/0/0, 192.168.3.1, 28"
I cannot figure out how to pull this nested data out of to do this. To put it simply, it would be nice if something like this worked: item.value.ipv4['address']. How is this done?
tasks:
- name: get config for Cisco IOS
ios_facts:
gather_subset: all
gather_network_resources: interfaces
- name: create dictionary with ansible_net_interfaces
set_fact:
foo_value: "{{ query('dict', ansible_net_interfaces) }}"
- name: display the results of foo_value
debug:
msg: "{{ foo_value }}"
- name: display certain detalys values from foo_value
debug:
msg: "{{ item.key }},{{ item.value.ipv4 }}"
with_items: "{{ foo_value }}"
These tasks produce the following:
TASK [display the results of foo] **********************************************************************************************************************
ok: [192.168.3.1] => {
"msg": [
{
"key": "GigabitEthernet0/0/0",
"value": {
"bandwidth": 1000000,
"description": "This is an interface description",
"duplex": "Full",
"ipv4": [
{
"address": "192.168.3.1",
"subnet": "28"
}
],
"lineprotocol": "up",
"macaddress": "50f7.123c.b0c0",
"mediatype": "RJ45",
"mtu": 1500,
"operstatus": "up",
"type": "ISR4331-3x1GE"
}
},
{
"key": "GigabitEthernet0/0/1",
"value": {
"bandwidth": 1000000,
"description": "This is another interface description",
"duplex": "Full",
"ipv4": [
{
"address": "192.168.3.33",
"subnet": "30"
}
],
"lineprotocol": "up",
"macaddress": "50f7.123c.b0c0",
"mediatype": "RJ45",
"mtu": 1500,
"operstatus": "up",
"type": "ISR4331-3x1GE"
}
},
]
}
ipv4 is a list of dictionaries. Assuming you need only the first dictionary,
- name: display certain detalys values from foo_value
debug:
msg: "{{ item.key }},{{ item.value.ipv4[0].address }},{{ item.value.ipv4[0].subnet }}"
when: item.value.ipv4 is defined and item.value.ipv4[0].subnet is defined and item.value.ipv4[0].address is defined
with_items: "{{ foo_value }}"

jinja2 Ansible filter dictionary

I've been doing ansible for a while, but have recently started doing some more advanced things such as pulling data to drive actions from outside sources. This has resulted in me having to dig a little deeper into how ansible allows logic and parsing of variables, requiring me to dig a little into jinja2.
In my playbook I am attempting to pull data in from etcd, allowing me to construct authorized sudo spec files, which I then pass onto a role to add to the appropriate systems.
My datasource, in addition to storing data that is needed to construct the specs has metadata used for auditing and logging purposes.
A key aspect of my datasource is that no metadata, i.e. that user XYZ had password less sudo for a period of 10 days, should be deleted when access is removed. So many aspects have a state field that may be active, inactive or in the case of sudo specs grant or revoke.
I have successfully constructed a lookup that pulls back a dictionary similar to below - which I then parse using the subsequent ansible statements. I am able to succcessfully process and extract all data except for groups/users that have their specs in a grant state.
When specs are in a "grant" state, I need to extract the linuxName field, to be passed onto the role that configures sudo.
I have tried a number of variations of filters, most of which end in me getting a reject or similar message, or a NULL value instead of the list of values that I want.
Anyone have an idea on how to accomplish this?
Thanks in advance.
Sample Data
ok: [serverName] => {
"sudoInfraSpecs": [
{
"infra_admins": {
"addedBy": "someUser",
"commands": "FULL_SUDO",
"comment": "platform support admins",
"dateAdded": "20180720",
"defaults": "!requiretty",
"hosts": "SERVERS",
"name": "infra_admins",
"operators": "ROOT",
"state": "active",
"tags": "PASSWD",
"users": {
"admingroup1": {
"addedBy": "someUser",
"dateAdded": "20180719",
"linuxName": "%admingroup1",
"name": "admingroup1",
"state": "grant"
},
"admingroup2": {
"addedBy": "someUser",
"dateAdded": "20180719",
"linuxName": "%admingroup2",
"name": "admingroup2",
"state": "grant"
}
}
},
"ucp_service_account": {
"addedBy": "someUser",
"commands": "FULL_SUDO",
"comment": "platform service account",
"dateAdded": "20180720",
"defaults": "!requiretty",
"hosts": "SERVERS",
"name": "platform_service_account",
"operators": "ROOT",
"state": "active",
"tags": "NOPASSWD,LOG_OUTPUT",
"users": {
"platformUser": {
"addedBy": "someUser",
"dateAdded": "20180719",
"linuxName": "platformUser",
"name": "platformUser",
"state": "grant"
}
}
}
}
]
}
Ansible snippet
- name: Translate infraAdmins sudoers specs from etcd into a list for processing [1]
set_fact:
tempInfraSpecs:
name: "{{ item.value.name}}"
comment: "{{ item.value.comment }}"
users: "{{ item.value.users | list }}"
hosts: "{{ item.value.hosts.split(',') }}"
operators: "{{ item.value.operators.split(',') }}"
tags: "{{ item.value.tags.split(',') }}"
commands: "{{ item.value.commands.split(',') }}"
defaults: "{{ item.value.defaults.split(',') }}"
with_dict: "{{ sudoInfraSpecs }}"
when: item.value.state == 'active'
register: tempsudoInfraSpecs
- name: Translate infraAdmins sudoers specs from etcd into a list for processing [2]
set_fact:
sudoInfraSpecs_fact: "{{ tempsudoInfraSpecs.results | selectattr('ansible_facts','defined')| map(attribute='ansible_facts.tempInfraSpecs') | list }}"
Rough Desired output dictionary:
sudoInfraSpecs:
- infra_admins:
addedBy: someUser
commands: FULL_SUDO
comment: platform support admins
dateAdded: '20180720'
defaults: "!requiretty"
hosts: SERVERS
name: infra_admins
operators: ROOT
state: active
tags: PASSWD
users:
"%admingroup1"
"%admingroup2"
- ucp_service_account:
addedBy: someUser
commands: FULL_SUDO
comment: platform service account
dateAdded: '20180720'
defaults: "!requiretty"
hosts: SERVERS
name: platform_service_account
operators: ROOT
state: active
tags: NOPASSWD,LOG_OUTPUT
users:
"platformUser"
I ended up doing this by creating a custom filter for use in my playbook that parsed the nested dictionary that makes up users:
#!/usr/bin/python
def getSpecActiveMembers(my_dict):
thisSpecActiveMembers = []
for i, value in my_dict.iteritems():
if value['state'] == 'grant':
thisSpecActiveMembers.append(value['linuxName'])
return thisSpecActiveMembers
class FilterModule(object):
def filters(self):
return {
'getSpecActiveMembers': getSpecActiveMembers
}
This ends up flattening the users from the source listed above, to the desired output.

Ansible: Using ansible facts, how can I get a disk device based on the storage controller value and then set the device as a variable

Context: I have a system that has a combination of disks from different storage controllers, so each type of disk has different purpose. I'm new to ansible and learning as I go. Writing a playbook that gets the disk from each type of controller so I can set them up.
Ex. Below is sample output from #'filter=ansible_devices*' ... sdz device is from SATA controller. On my other hosts it might not always be sdz.. so I want to get the device name and store in a variable if in the facts the device has "host": "SATA controller". I'm thinking maybe I need to traverse through ansible_devices dictionaries, find the key that matches ("host": "SATA controller") and then get the parent dict for it which would be the device. Is there a way to do that.. or easier way? :)
"sdz": {
"holders": [
"mpathz"
],
"host": "SATA controller: Intel Corporation C610/X99 series chipset 6-Port SATA Controller [AHCI mode] (rev 05)",
"links": {
"ids": [
"ata-SAMSUNG_MZ7GE960HMHP-00003_S1Y2NYAFC02269",
"wwn-0x50025388003aeb2a"
],
"labels": [],
"masters": [
"dm-19"
],
"uuids": []
},
"model": "SAMSUNG MZ7GE960",
"partitions": {},
"removable": "0",
"rotational": "0",
"sas_address": null,
"sas_device_handle": null,
"scheduler_mode": "cfq",
"sectors": "1875385008",
"sectorsize": "512",
"serial": "S1Y2NYAFC02269",
"size": "894.25 GB",
"support_discard": "512",
"vendor": "ATA",
"virtual": 1,
"wwn": "0x50025388003aeb2a"
This tasks fragment in a playbook should do it, assuming ansible_devices is already set as a variable
tasks:
- name: get device name
set_fact:
device_name: "{{ item.key }}"
no_log: True
with_dict: "{{ ansible_devices }}"
when: "item.value.host.startswith('SATA')"
- name: show all values for selected device name
debug: var=ansible_devices[device_name]
- name: show only device name
debug: var=device_name
The set_fact will get your device name. The two debug statements will dump all of the device values and just the device name, respectively.
Assuming ansible.builtin.setup has finished, you can get all storage devices using this code:
- name: initialize empty list for devices
set_fact:
storage_devices: []
no_log: true
- name: get SATA and NVMe devices
set_fact:
storage_devices: "{{ storage_devices + [item.key] }}"
no_log: true
with_dict: "{{ ansible_devices }}"
when: "item.value.host.startswith('SATA controller:') or
item.value.host.startswith('Non-Volatile memory controller:')"
- name: show all values for selected devices
debug: msg="{{ ansible_devices[item] }}"
loop: "{{ storage_devices }}"
- name: show devices names
debug: var=storage_devices
- name: show first SATA or NVMe device in the list
debug: var=storage_devices[0]

Resources