How to filter out a particular line from ansible output - linux

I am facing an issue while running my ansible-playbook to filter out the IP address from the playbook output. Here is my code
- hosts: myhost
tasks:
- name: Gather all VMs from a specific folder
community.vmware.vmware_vm_info:
hostname: myhost.com
username: local
password: mypass
folder: "/VMFStorage/vm/"
validate_certs: False
delegate_to: localhost
register: vm_info
- debug:
var: vm_info
The output of the code
ok: [myhost] => {
"vm_info": {
"changed": false,
"failed": false,
"virtual_machines": [
{
"attributes": {},
"cluster": "Storage",
"datacenter": "VMFStorage",
"esxi_hostname": "161.92.211.24",
"folder": "/VMFStorage/vm/",
"guest_fullname": "Red Hat Enterprise Linux 8 (64-bit)",
"guest_name": "RHEL Machine",
"ip_address": "192.168.1.47",
"mac_address": [
"00:50:56:a3:b1:e9"
],
"moid": "vm-22949",
"power_state": "poweredOn",
"tags": [],
"uuid": "4223f3fa-eeae-6a96-6af5-d68dc94199f3",
"vm_network": {
"00:50:56:a3:b1:e9": {
"ipv4": [
"192.168.1.47"
],
"ipv6": [
"fe80::250:56ff:fea3:b1e9"
]
}
}
},
{
"attributes": {},
"cluster": "Storage",
"datacenter": "VMFStorage",
"esxi_hostname": "161.92.211.22",
"folder": "/VMFStorage/vm/",
"guest_fullname": "Red Hat Enterprise Linux 8 (64-bit)",
"guest_name": "Machine2",
"ip_address": "192.168.1.29",
"mac_address": [
"00:50:56:a3:b3:6d"
],
"moid": "vm-21360",
"power_state": "poweredOff",
"tags": [],
"uuid": "42239cd1-69ec-ff5d-a557-85d0bc8c9edc",
"vm_network": {
"00:50:56:a3:b3:6d": {
"ipv4": [],
"ipv6": []
}
}
},
The required output is to catch the IP address of Machine1 guest name and print that output
192.168.1.29
I tried many possibilities but couldn't find out the proper solution
Any help would be appreciated
UPDATE
- hosts: myhost
tasks:
- name: Gather all VMs from a specific folder
community.vmware.vmware_vm_info:
hostname: myhost.com
username: local
password: mypass
folder: "/VMFStorage/vm/"
validate_certs: False
delegate_to: localhost
register: vm_info
- set_fact:
ip: "{{ vm_info.virtual_machines|
selectattr('guest_name', 'eq', 'AlmaLinuxBUILD-Machine')|
map(attribute='ip_address')|first }}"
- debug:
var: ip

There are many options. For example,
Select the dictionary from the list first and extract the attribute
- debug:
var: ip
vars:
ip: "{{ vm_info.virtual_machines|
selectattr('guest_name', 'eq', 'Machine2')|
map(attribute='ip_address')|first }}"
gives
ip: 192.168.1.29
If you prefer json_query the task below gives the same result
- debug:
var: ip
vars:
ip: "{{ vm_info.virtual_machines|
json_query('[?guest_name==`Machine2`].ip_address')|first }}"
Create a dictionary first if there are many items on the list that should be referenced, e.g.
- debug:
var: name_ip
vars:
name_ip: "{{ vm_info.virtual_machines|
items2dict(key_name='guest_name',
value_name='ip_address') }}"
gives
name_ip:
Machine2: 192.168.1.29
RHEL Machine: 192.168.1.47
Then, use this dictionary to get the IP of a guest. The task below also gives the same result
- debug:
var: ip
vars:
ip: "{{ name_ip['Machine2'] }}"
Q: "How can I use the ip variable in other places in the same playbook?"
A: There are many options. For example, put it into the set_facts (precedence 19)
- set_facts:
ip: "{{ name_ip['Machine2'] }}"
- debug:
var: ip

try this.. if you only want machine1 ip_address.
- debug:
msg: "{{ vm_info.virtual_machines[1].ip_address }}"
try this.. if you only want all VMs ip_addresses.
- debug:
msg: "{{ vm_info.virtual_machines[*].ip_address }}"

Related

Conditionals against variables

I am building a snapshot management playbook and that checks for an existing snap before taking a snap. I am having trouble testing a conditional when the playbook finds an existing snap. Here is a sample code:
---
- name: Test Snapshot
hosts: axwayT
gather_facts: false
vars_files:
- vault/creds.yml
vars:
mail_body_file: "/tmp/ansible_mail"
pre_tasks:
- name: Delete mail body file
file:
state: absent
path: "{{ mail_body_file }}"
delegate_to: localhost
run_once: true
- name: Create mail body file
file:
state: touch
path: "{{ mail_body_file }}"
delegate_to: localhost
run_once: true
tasks:
- name: find guest's folder using name
vmware_guest_find:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
validate_certs: no
name: "{{ vcenter_hostgroup_name }}"
datacenter: "{{ datacenter_name }}"
register: vm_folder
delegate_to: localhost
- name: Check for existing snapshots
vmware_guest:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
validate_certs: no
name: "{{ vcenter_hostgroup_name }}"
datacenter: "{{ datacenter_name }}"
folder: "{{vm_folder.folders[0]}}"
name: "{{ vcenter_hostgroup_name }}"
state: present
register: vm_state
delegate_to: localhost
- name: debug
debug:
var: vm_state.instance.current_snapshot
- name: Test
shell: echo "Found!"
when: vm_state.instance.current_snapshot !=""
I am working with an inventory of two servers for testing, nothing special. Here is the ouput I want to use a conditional against:
TASK [debug] ********************************************************************************************************************************************************************************************************************************
ok: [swipe901.test.com] => {
"vm_state.instance.current_snapshot": ""
}
ok: [swipe902.test.com] => {
"vm_state.instance.current_snapshot": {
"creation_time": "2023-02-07T21:14:06.812901+00:00",
"description": "",
"id": 13,
"name": "VM Snapshot 2%2f7%2f2023, 3:14:05 PM",
"state": "poweredOn"
}
}
I tried two when statements:
when: vm_state.instance.current_snapshot =""
when: vm_state.instance.current_snapshot is defined
My logic is way off and I am seeing my own limitations with programing logic, which I plan to fix soon.
My plan for the logic is to, skip a step, in my playbook if vm_state.instance.current_snapshot is "". How would this be handled?
Q: "I would like the condition to evaluate false if there is anything populated in current_snapshot."
A: For example, the playbook
shell> cat pb.yml
- name: Evaluate false if there is anything populated in current_snapshot
hosts: localhost
tasks:
- debug:
msg: The variable current_snapshot is either empty or does not exist.
when: current_snapshot|d('', true)|length == 0
gives
shell> ansible-playbook pb.yml
PLAY [Evaluate false if there is anything populated in current_snapshot] *************************************************************
TASK [debug] *************************************************************************************************************************
ok: [localhost] =>
msg: The variable current_snapshot is either empty or does not exist.
PLAY RECAP ***************************************************************************************************************************
localhost: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
shell> ansible-playbook pb.yml -e current_snapshot=''
PLAY [Evaluate false if there is anything populated in current_snapshot] *************************************************************
TASK [debug] *************************************************************************************************************************
ok: [localhost] =>
msg: The variable current_snapshot is either empty or does not exist.
PLAY RECAP ***************************************************************************************************************************
localhost: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
shell> ansible-playbook pb.yml -e current_snapshot='anything'
PLAY [Evaluate false if there is anything populated in current_snapshot] *************************************************************
TASK [debug] *************************************************************************************************************************
skipping: [localhost]
PLAY RECAP ***************************************************************************************************************************
localhost: ok=0 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
You can also use assert. For example,
shell> cat pb.yml
- name: Evaluate false if there is anything populated in current_snapshot
hosts: localhost
tasks:
- assert:
that: current_snapshot|d('', true)|length == 0
success_msg: The variable current_snapshot is either empty or does not exist.
fail_msg: The variable current_snapshot is populated.

filtering the ansible playbook output [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have output of an ansible playbook for which i need to apply fileters in such a way to proceed with next tasks. Please find the below output.
ok: [localhost] => {
"results": [
{
"actions": {
"namespaces": {},
"state": "present",
"xpath": "/Storage/SSL/KeyStorePath"
},
"ansible_loop_var": "item",
"changed": false,
"pod": 1,
"failed": false,
"invocation": {
"module_args": {
"mount": true,
"input_type": "yaml",
}
},
"item": "100.108.22.102",
"msg": "found 1 nodes"
},
{
"actions": {
"namespaces": {},
"state": "present",
"xpath": "/Storage/SSL/KeyStorePath"
},
"ansible_loop_var": "item",
"changed": false,
"pod": 0,
"failed": false,
"invocation": {
"module_args": {
"mount": true,
"input_type": "yaml",
}
},
"item": "100.108.22.103",
"msg": "found 0 nodes"
}
]
}
Here, i want the next task to be executed when the node respective pod value is 1 if the pod value of the node is 0 then the next task should not run on the respective node ip.
Please assist ..
Q: "Execute next task when the node's respective pod value is 1"
A: There are many ways how to proceed with the next task. For example, given the variable results
Use delegate_to and loop selected items
- hosts: localhost
tasks:
- debug:
msg: 'Task is running on {{ item.item }}'
loop: "{{ results|selectattr('pod', 'eq', 1)|list }}"
loop_control:
label: "{{ item.item }}"
delegate_to: "{{ item.item }}"
gives (abridged)
TASK [debug] ****
ok: [localhost -> 100.108.22.102] => (item=100.108.22.102) =>
msg: Task is running on 100.108.22.102
Create a list of selected hosts and test the host is in the list
- hosts: 100.108.22.102,100.108.22.103
tasks:
- debug:
msg: "Task is running on {{ inventory_hostname }}"
when: inventory_hostname in pods
vars:
pods: "{{ results|
selectattr('pod', 'eq', 1)|
map(attribute='item')|
list }}"
gives (abridged)
TASK [debug] ****
ok: [100.108.22.102] =>
msg: Task is running on 100.108.22.102
skipping: [100.108.22.103]
Use add_host to create an inventory group in the first play and use it in the second one
- hosts: localhost
tasks:
- add_host:
name: '{{ item }}'
groups: pods_enabled
loop: "{{ results|
selectattr('pod', 'eq', 1)|
map(attribute='item')|
list }}"
- hosts: pods_enabled
tasks:
- debug:
msg: "Task is running on {{ inventory_hostname }}"
gives (abridged)
PLAY [localhost] ****
TASK [add_host] ****
changed: [localhost] => (item=100.108.22.102)
PLAY [pods_enabled] ****
TASK [debug] ****
ok: [100.108.22.102] =>
msg: Task is running on 100.108.22.102
PLAY RECAP ****
100.108.22.102: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
localhost: ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You could use with_items and when in your next task as below
- name: validate pod value
debug:
msg: "The pod value is 1"
with_items: "{{ your_var.results }}"
when: item.pod == "1"

Print json output in Ansible and store in a list?

Ansible playbook:
---
- task:-
- code goes here
- name: Trying to get instance Private IP from ASG
ec2_instance_facts:
instance_ids:
- "{{ item }}"
with_items: "{{ INSTANCE_IDS_FROM_ASG }}"
register: instance_ids_result
- set_fact:
msg: "{{ instance_ids_result | json_query('results[*].instances[*].network_interfaces[*].private_ip_address') }} "
- debug: var=msg
I have the output as follows:
ok: [localhost] => {
"msg": [
[
"172.31.144.74"
],
[
"172.31.147.69"
]
]
}
But, I would need the output in a list as ["172.31.144.74", "172.31.147.69"] or "172.31.147.69" "172.31.147.69".
What is the best way to print it that way?
You could flatten your list using the filter
- set_fact:
msg: "{{ instance_ids_result | json_query('results[*].instances[*].network_interfaces[*].private_ip_address') | flatten }} "

Ansible to create users and assign them to a particular group based on vars

Gurus, I'm learning ansible and trying to understand how the variables can be used, i have come across writing below playbook but i'm not understanding How to assign a particular group to particular users based on the Variables i have defined in the play for both Users and Groups under vars
I have below play where i want to create Users anika and rigved and want to assign them to a docker group while ayush and eshant should have the test group assigned.
I'm not getting the idea to achieve this so far. However as of now while running it creates users and assigns both group to all users.
$ cat nested_playbook-1.yml
---
- name: testing nested play
hosts: localhost
vars:
users:
- anika
- rigved
- ayush
- eshant
grps:
- docker
- test
tasks:
- name: make users members of groups
user:
name: "{{ item[0] }}"
state: present
groups: "{{ item[0] }}"
with_nested:
- "{{ users }}"
- "{{ grps }}"
The way you've structured your data doesn't show any relationship between users and groups. One option would be to structure it like this:
grps:
- name: docker
users:
- anika
- rigved
- name: test
users:
- ayush
- eshant
With this structure, you can loop over grps using the subelements filter, like this:
---
- name: testing nested play
gather_facts: false
hosts: localhost
vars:
grps:
- name: docker
users:
- anika
- rigved
- name: test
users:
- ayush
- eshant
tasks:
- debug:
msg:
user:
name: "{{ item.1 }}"
state: present
groups: "{{ item.0.name }}"
loop: "{{ grps|subelements('users') }}"
loop_control:
label: "{{ item.1 }}"
The subelements filter is a way of creating a "nested loop": it iterates over each member of the 'users' key for each group in grps. During each loop iteration, item is a 2-tuple in which the first item is the corresponding element from grps and the second item iterates over the users key for that element. In other words, you end up iterating over this list:
[{'name': 'docker', 'users': ['anika', 'rigved']}, anika}
[{'name': 'docker', 'users': ['anika', 'rigved']}, rigved}
[{'name': 'test', 'users': ['ayush', 'eshant']}, ayush}
[{'name': 'test', 'users': ['ayush', 'eshant']}, eshant}
So within the loop, item.0 refers to the group entry itself (and thus item.0.name is the group name), and item.1 refers to the user.
PLAY [testing nested play] *******************************************************************
TASK [debug] *********************************************************************************
ok: [localhost] => (item=anika) => {
"msg": {
"user": {
"groups": "docker",
"name": "anika",
"state": "present"
}
}
}
ok: [localhost] => (item=rigved) => {
"msg": {
"user": {
"groups": "docker",
"name": "rigved",
"state": "present"
}
}
}
ok: [localhost] => (item=ayush) => {
"msg": {
"user": {
"groups": "test",
"name": "ayush",
"state": "present"
}
}
}
ok: [localhost] => (item=eshant) => {
"msg": {
"user": {
"groups": "test",
"name": "eshant",
"state": "present"
}
}
}
PLAY RECAP ***********************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Alternately, you could structure your data like this:
users:
- name: anika
group: docker
- name: rigved
group: docker
- name: ayush
group: docker
- name: eshant
group: docker
You can just use a simple loop to process this structure:
---
- name: testing nested play
gather_facts: false
hosts: localhost
vars:
users:
- name: anika
group: docker
- name: rigved
group: docker
- name: ayush
group: docker
- name: eshant
group: docker
tasks:
- debug:
msg:
user:
name: "{{ item.name }}"
state: present
groups: "{{ item.group }}"
loop: "{{ users }}"
loop_control:
label: "{{ item.name }}"
Note that in both the above examples I'm using loop_control on the tasks just to set the loop label and make the output look nicer. You could remove loop_control from the above tasks with no impact on how they operate.

Using register with a loop in Ansible

i want to code a playbook which IF a user exists changes the pw of it.
The playbook should be able to take n User's and change the pw of those Users.
At the moment im having the issue that the when is empty due to the loop, i tried using with_items: {{ user_exists.results }} but this is somehow not working.
(http://docs.ansible.com/ansible/playbooks_loops.html#using-register-with-a-loop)
Am i doing something wrong ?
Br,
Numblesix
---
-
become: true
become_method: sudo
hosts: xetest
name: "Updates the password of given User if exists"
tasks:
-
ignore_errors: true
name: "Check if User exists"
register: user_exists
shell: "grep -q {{ item.key }} /etc/passwd &>/dev/null"
with_dict: "{{ users }}"
-
debug:
var: user_exists
-
debug:
msg: "User name is {{ item.key }} and hash is {{ item.value.passwd}} and return code is: "
with_dict: "{{ users }}"
-
debug:
var: user_exists
with_items: "{{user_exists.results }}"
-
name: "updating password for given User"
user: "name={{ item.key }} update_password=always password={{ item.value.passwd}} createhome=no"
when: user_exists.rc == 0
with_dict: "{{ users }}"
with_items: "{{ user_exists.results }}"
vars:
users:
foo:
passwd: $6$random_salt$12A.ar9eNDsgmds3leKoCDZPmq7OHLvhBtQg/Q3K2G/3yeEa/r8Ou4DxJpN6vzccewugvZt7IkfCbHFF2i.QU.
RESULTS IN ERROR!
duplicate loop in task: items
WITHOUT with_items: "{{ user_exists.results }}" im getting this error
"failed": true, "msg": "The conditional check 'user_exists.rc == 0' failed.
The error was: error while evaluating conditional (user_exists.rc == 0):
'dict object' has no attribute 'rc'
For my testing, I'm using ansible 2.1.4.0.
When running the script, you can see in the debug for user_exists.results that it contains the input value passed in along with the return code:
"results": [
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "grep -q foo /etc/passwd",
"delta": "0:00:00.009034",
"end": "2017-05-02 17:42:57.835871",
"failed": true,
"invocation": {
"module_args": {
"_raw_params": "grep -q foo /etc/passwd",
"_uses_shell": true,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"warn": true
},
"module_name": "command"
},
"item": {
"key": "foo",
"value": {
"passwd": "foobar"
}
},
"rc": 1,
"start": "2017-05-02 17:42:57.826837",
"stderr": "",
"stdout": "",
"stdout_lines": [],
"warnings": []
},
So instead doing two loops (which would have been done with with_nested and two lists), you can do everything with a single loop:
- name: "updating password for given User"
debug:
msg: "name={{ item.item.key }} update_password=always password={{ item.item.value.passwd}} createhome=no"
when: item.rc == 0
with_items: "{{ user_exists.results }}"
Note: In my testing shell: "grep -q {{ item.key }} /etc/passwd &>/dev/null" was always returning a 0 return code. I had to remove the "&>/dev/null" part to get the proper return code.

Resources