How to Club multiple ansible condition into one based on the set_facts - azure

While going through one of the SO post for Ansible, was interested an usage of set_fact with different conditional checks.
However, I answered on the post based on my approach, but, I still see there can be an improvement to club multiple conditions for similar task like determine the location resource group and vnet.
Below is the playbook and variables file azure_vars.yml
Playbook:
---
- name: create azure vm
hosts: localhost
connection: local
tasks:
- include_vars: azure_vars.yml
- set_fact:
host: "{{ azure_vm_name.split('.') }}"
- set_fact:
domain: "{{ host.1 }}.{{ host.2 }}"
- name: Domain
debug:
msg: "{{ domain }}"
- set_fact:
location: "{{ azure_location[0] }}"
when: 'domain == azure_domain[0]'
- set_fact:
location: "{{ azure_location[1] }}"
when: 'domain == azure_domain[1]'
- set_fact:
location: "{{ azure_location[2] }}"
when: 'domain == azure_domain[2]'
- name: Location
debug:
msg: "{{ location }}"
- set_fact:
res_group: "{{ azure_res_group[0] }}"
when: 'domain == azure_domain[0]'
- set_fact:
res_group: "{{ azure_res_group[1] }}"
when: 'domain == azure_domain[1]'
- set_fact:
res_group: "{{ azure_res_group[2] }}"
when: 'domain == azure_domain[2]'
- name: Resource Group
debug:
msg: "{{ res_group }}"
- set_fact:
vnet: "{{ azure_nprod_vnet }}"
when: 'domain == azure_domain[0]'
- set_fact:
vnet: "{{ azure_prod03_vnet }}"
when: 'domain == azure_domain[2]'
- set_fact:
vnet: "{{ azure_prod02_vnet }}"
when: 'domain == azure_domain[1]'
- name: Vnet
debug:
msg: "{{ vnet }}"
Variable files: this file contains all the variable which will be a part of playbook and imported as include_vars under task section.
azure_vars.yml
---
azure_nprod_vnet: "/subscriptions/XXXXXXXX-XXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg001/providers/Microsoft.Network/virtualNetworks/vnet"
azure_prod02_vnet: "/subscriptions/XXXXXXXX-XXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg003/providers/Microsoft.Network/virtualNetworks/vnet"
azure_prod03_vnet: "/subscriptions/XXXXXXXX-XXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg002/providers/Microsoft.Network/virtualNetworks/vnet"
# Azure domain
azure_domains:
- us-sea01
- us-azrc2
- eu-azrc1
# Resource group
azure_res_group:
- rg001
- rg002
- rg003
# Azure locations
azure_location:
- westus2
- southcentralus
- westeurope
Expected would be to club below three into one condition:
- set_fact:
location: "{{ azure_location[0] }}"
when: 'domain == azure_domain[0]'
- set_fact:
location: "{{ azure_location[1] }}"
when: 'domain == azure_domain[1]'
- set_fact:
location: "{{ azure_location[2] }}"
when: 'domain == azure_domain[2]'
May be something like:
- set_fact:
location:
- azure_location[0]
- azure_location[1]
- azure_location[2]
when:
- 'domain == azure_domain[0]
- 'domain == azure_domain[1]
- 'domain == azure_domain[2]

You can solve this using a loop and zip filter, or in the older fashion way, with a with_together — not recommended anymore, if you want to future-proof your playbooks.
Given the playbook:
- hosts: all
vars:
azure_vm_name: foo.bar.us-sea01.whatever.example.org
tasks:
- include_vars: azure_vars.yml
- set_fact:
host: "{{ azure_vm_name.split('.') }}"
- set_fact:
domain: "{{ host.2 }}"
- name: Domain
debug:
msg: "{{ domain }}"
- set_fact:
location: "{{ item.1 }}"
loop: "{{ azure_domains | zip(azure_location) | list }}"
when: 'domain == item.0'
- name: Location
debug:
msg: "{{ location }}"
And the variable file azure_vars.yml:
azure_domains:
- us-sea01
- us-azrc2
- eu-azrc1
azure_location:
- westus2
- southcentralus
- westeurope
This yields the recap:
PLAY [all] *******************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************
ok: [localhost]
TASK [include_vars] **********************************************************************************************
ok: [localhost]
TASK [set_fact] **************************************************************************************************
ok: [localhost]
TASK [set_fact] **************************************************************************************************
ok: [localhost]
TASK [Domain] ****************************************************************************************************
ok: [localhost] => {
"msg": "us-sea01"
}
TASK [set_fact] **************************************************************************************************
ok: [localhost] => (item=['us-sea01', 'westus2'])
skipping: [localhost] => (item=['us-azrc2', 'southcentralus'])
skipping: [localhost] => (item=['eu-azrc1', 'westeurope'])
TASK [Location] **************************************************************************************************
ok: [localhost] => {
"msg": "westus2"
}
PLAY RECAP *******************************************************************************************************
localhost : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
This said there is another possibility, using Python's capacities of Ansible. You could use the index() method of a list to target the element of azure_location being at the same position as domain in azure_domains.
e.g. if the domain is at position 2 of azure_domains, you'll get the element of position 2 in azure_location.
Given the playbook:
- hosts: all
vars:
azure_vm_name: foo.bar.us-sea01.whatever.example.org
tasks:
- include_vars: azure_vars.yml
- set_fact:
host: "{{ azure_vm_name.split('.') }}"
- set_fact:
domain: "{{ host.2 }}"
- name: Domain
debug:
msg: "{{ domain }}"
- set_fact:
location: "{{ azure_location[azure_domains.index(domain)] }}"
- name: Location
debug:
msg: "{{ location }}"
And the same variable file azure_vars.yml, this yields the recap:
PLAY [all] ******************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************
ok: [localhost]
TASK [include_vars] *********************************************************************************************************
ok: [localhost]
TASK [set_fact] *************************************************************************************************************
ok: [localhost]
TASK [set_fact] *************************************************************************************************************
ok: [localhost]
TASK [Domain] ***************************************************************************************************************
ok: [localhost] => {
"msg": "us-sea01"
}
TASK [set_fact] *************************************************************************************************************
ok: [localhost]
TASK [Location] *************************************************************************************************************
ok: [localhost] => {
"msg": "westus2"
}
PLAY RECAP ******************************************************************************************************************
localhost : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Which is not using a loop, so makes an easier recap.

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.

filter data From ansible_default_ipv4.macaddress

Dear community i ask for your help please.
I would create a playbook that will take a macaddress given in input and it should respect the Unix format. Then, if the address given respects the required format, another task will check if the given macaddress match an existed one in the hosts, **if it exists it will show the interface related to that macaddress if not the task will fail with an error message "No interfaces found with mac address '$MACADDRESS'. Fatal error."
here is what was done by me, i don't what should be done to achieve the goal:
- hosts: all
gather_facts: no
vars_prompt:
- name: "MACADDRESS"
prompt: "mac address?(please use Unix format ex- 1a:2b:3c:4d:5e:6f )"
private: no
tasks:
- name: check macaddresssyntax
debug:
msg: "{{ MACADDRESS | ansible.utils.hwaddr('unix') }}"
register: mac_syntax
failed_when: mac_syntax failed
- name: check local mac
debug:
var: mac_syntax |intersect (ansible_facts['default_ipv4']|selectattr('macaddress') | map(attribute='interface')|list)
You don't normally register the result of a debug task (because it's not useful). If you want to fail when someone enters an invalid MAC address, use the fail task:
- name: check mac address syntax
fail:
msg: "Invalid mac address syntax"
when: not MACADDRESS|ansible.utils.hwaddr('unix')
You have gather_facts set to false, but with fact gathering
disabled Ansible won't provide you with any facts. You need to
enable fact gathering if you want Ansible to provide you with
information about host interfaces.
I'm not entirely sure what you're trying to do in your check local mac task, but this seems to accomplish what you were asking about:
- hosts: localhost
gather_facts: true
vars_prompt:
- name: "MACADDRESS"
prompt: "mac address?(please use Unix format ex- 1a:2b:3c:4d:5e:6f )"
private: no
tasks:
- name: check macaddresssyntax
fail:
msg: "Invalid mac address syntax"
when: not MACADDRESS | ansible.utils.hwaddr('unix')
# In this task, we loop over `ansible_interfaces`, which is
# a list of interface names. We set the `matched_interface`
# variable to the current interface name if it has a
# matching MAC address.
- name: check local mac
set_fact:
matched_interface: "{{ ifname }}"
when: >-
lookup('vars', 'ansible_{}'.format(ifname)).macaddress|default(false) == MACADDRESS
vars:
# For whatever reason, ansible replaces `-` in interface
# names with `_`.
ifname: "{{ item.replace('-', '_') }}"
loop: "{{ ansible_interfaces }}"
- debug:
msg: "the interface related to {{ MACADDRESS }} is {{ matched_interface }}"
when: matched_interface|default(false)
- fail:
msg: "no interfaces found with mac address {{ MACADDRESS }}"
when: not matched_interface|default(false)
Running the above playbook on my system, which has an interface with address a2:29:ab:4e:e7:74, looks like this:
$ ansible-playbook playbook.yaml -e MACADDRESS='a2:29:ab:4e:e7:74
PLAY [localhost] ***************************************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [check macaddresssyntax] **************************************************
skipping: [localhost]
TASK [check local mac] *********************************************************
skipping: [localhost] => (item=veth92b9a89f)
...
ok: [localhost] => (item=example)
skipping: [localhost] => (item=lo)
...
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "the interface related to a2:29:ab:4e:e7:74 is example"
}
TASK [fail] ********************************************************************
skipping: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
If I run it with a MAC address that doesn't exist on my system, I get:
TASK [check local mac] *********************************************************
skipping: [localhost] => (item=veth168ad56c)
...
TASK [debug] *******************************************************************
skipping: [localhost]
TASK [fail] ********************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "msg": "no interfaces found with mac address a2:29:ab:4e:e7:77"}
PLAY RECAP *********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=1 skipped=3 rescued=0 ignored=0
Collect the network's facts and get the list of interfaces. For example,
- setup:
gather_subset: network
- debug:
var: ansible_facts.interfaces
gives
ansible_facts.interfaces:
- lo0
- lo1
- pflog0
- wlan0
Put the declaration below as appropriate
_ifcs: "{{ ansible_facts.interfaces|map('extract', ansible_facts)|list }}"
_macs: "{{ _ifcs|json_query('[].macaddress') }}"
_devs: "{{ _ifcs|json_query('[].device') }}"
_macs_valid: "{{ _macs|map('ansible.utils.hwaddr', 'bool')|
map('ternary', true, false)|list }}"
_dev_mac_valid: "{{ _devs|zip(_macs)|zip(_macs_valid)|
map('flatten')|
selectattr(2) }}"
dev_mac_valid: "{{ _dev_mac_valid|map('zip', ['dev', 'mac', 'valid'])|
map('map', 'reverse')|
map('community.general.dict') }}"
dev_mac: "{{ dev_mac_valid|items2dict(key_name='dev', value_name='mac') }}"
mac_dev: "{{ dev_mac_valid|items2dict(key_name='mac', value_name='dev') }}"
For example, these evaluate to
_macs: [unknown, unknown, unknown, '00:12:00:34:56:78']
_macs_valid: [false, false, false, true]
_devs: [lo0, lo1, pflog0, wlan0]
_dev_mac_valid:
- [wlan0, '00:12:00:34:56:78', true]
dev_mac_valid:
- dev: wlan0
mac: 00:12:00:34:56:78
valid: true
dev_mac:
wlan0: 00:12:00:34:56:78
mac_dev:
00:12:00:34:56:78: wlan0
Q: "Check if the given macaddress match an existing one in the hosts"
A: Use the dictionary mac_dev. For example,
- pause:
prompt: "Enter MAC address"
register: result
- set_fact:
macaddress: "{{ result.user_input }}"
- assert:
that: macaddress|ansible.utils.hwaddr('bool')
fail_msg: Wrong MAC address
- assert:
that: macaddress in mac_dev.keys()|list
fail_msg: "No interfaces found with mac address {{ macaddress }}"
success_msg: "Interfaces {{ mac_dev[macaddress] }} found
with mac address {{ macaddress }}"
If there are more hosts declare a dictionary of all hosts
mac_dev_hosts: "{{ dict(ansible_play_hosts|
zip(ansible_play_hosts|
map('extract', hostvars, 'mac_dev'))) }}"
Then, putting it all together, for example, the playbook
- hosts: test_11,test_12,test_13
gather_facts: false
vars:
_ifcs: "{{ ansible_facts.interfaces|map('extract', ansible_facts)|list }}"
_macs: "{{ _ifcs|json_query('[].macaddress') }}"
_devs: "{{ _ifcs|json_query('[].device') }}"
_macs_valid: "{{ _macs|map('ansible.utils.hwaddr', 'bool')|
map('ternary', true, false)|list }}"
_dev_mac_valid: "{{ _devs|zip(_macs)|zip(_macs_valid)|
map('flatten')|
selectattr(2) }}"
dev_mac_valid: "{{ _dev_mac_valid|map('zip', ['dev', 'mac', 'valid'])|
map('map', 'reverse')|
map('community.general.dict') }}"
dev_mac: "{{ dev_mac_valid|items2dict(key_name='dev', value_name='mac') }}"
mac_dev: "{{ dev_mac_valid|items2dict(key_name='mac', value_name='dev') }}"
mac_dev_hosts: "{{ dict(ansible_play_hosts|
zip(ansible_play_hosts|
map('extract', hostvars, 'mac_dev'))) }}"
tasks:
- setup:
gather_subset: network
- set_fact:
mac_dev: "{{ mac_dev }}"
- block:
- debug:
var: mac_dev_hosts|to_nice_yaml
- pause:
prompt: "Enter MAC address"
register: result
- set_fact:
macaddress: "{{ result.user_input }}"
- assert:
that: macaddress|ansible.utils.hwaddr('bool')
fail_msg: Wrong MAC address
- assert:
that: macaddress in mac_dev_hosts|json_query('*.keys(#)')|flatten
fail_msg: "No interface found with mac address {{ macaddress }}"
- debug:
msg: "Interface {{ dev }} found with mac address {{ macaddress }}
at {{ hst }}"
vars:
itm: "{{ mac_dev_hosts|dict2items|
selectattr('value', 'contains', macaddress)|first }}"
hst: "{{ itm.key }}"
dev: "{{ itm.value[macaddress] }}"
run_once: true
gives
PLAY [test_11,test_12,test_13] ***************************************************************
TASK [setup] *********************************************************************************
ok: [test_13]
ok: [test_12]
ok: [test_11]
TASK [set_fact] ******************************************************************************
ok: [test_13]
ok: [test_11]
ok: [test_12]
TASK [debug] *********************************************************************************
ok: [test_11] =>
mac_dev_hosts|to_nice_yaml: |-
test_11:
00:12:00:34:56:AA: wlan0
test_12:
00:12:00:34:56:BB: wlan0
test_13:
00:12:00:34:56:CC: wlan0
TASK [pause] *********************************************************************************
[pause]
Enter MAC address:
00:12:00:34:56:CC^Mok: [test_11]
TASK [set_fact] ******************************************************************************
ok: [test_11]
TASK [assert] ********************************************************************************
ok: [test_11] => changed=false
msg: All assertions passed
TASK [assert] ********************************************************************************
ok: [test_11] => changed=false
msg: All assertions passed
TASK [debug] *********************************************************************************
ok: [test_11] =>
msg: Interface wlan0 found with mac address 00:12:00:34:56:CC at test_13
PLAY RECAP ***********************************************************************************
test_11: ok=8 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_12: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_13: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
If the MAC is missing the play will fail, for example
TASK [assert] ********************************************************************************
fatal: [test_11]: FAILED! => changed=false
assertion: macaddress in mac_dev_hosts|json_query('*.keys(#)')|flatten
evaluated_to: false
msg: No interface found with mac address 00:12:00:34:56:FF

Ansible - set fact for key of dict based on sub-key value

Pfoef, describing my issue at hand is quite difficult. Please bear with me.
I have this dict:
my_dict:
FIRST:
some_key: first_value
SECOND:
some_key: second_value
My Ansible task is:
- shell: "echo {{ item.value['some_key'] }}"
register: exec_output
loop: "{{ my_dict | dict2items }}"
# This is something where I do not know what to do
- set_fact:
desired_output: ???
when: <some_key_contains_a_value>
When Ansible executes, it will execute the shell command twice, because there are 2 items in the dict.
Q: How can I configure Ansible so that: Ansible will set a fact and add the key (FIRST or SECOND) if the value of some_key is e.g. 'second_value'. In this example case, the fact will contain "SECOND".
You can find back the whole item that was part of a loop when register'ing its output via the item.item property.
So, in your case, you will find, in the items under exec_output.results:
item:
key: FIRST
value:
some_key: first_value
item:
key: SECOND
value:
some_key: second_value
So, based on that you could have a playbook like:
- hosts: localhost
gather_facts: no
tasks:
- shell: "echo {{ item.value.some_key }}"
register: exec_output
loop: "{{ my_dict | dict2items }}"
vars:
my_dict:
FIRST:
some_key: first_value
SECOND:
some_key: second_value
- set_fact:
desired_output: "{{ item.item.key }}"
when: some_key in item.stdout
loop: "{{ exec_output.results }}"
vars:
some_key: second
loop_control:
label: "{{ item.stdout }}"
- debug:
var: desired_output
That would give you the expected result:
PLAY [localhost] *******************************************************************************************************************
TASK [shell] ***********************************************************************************************************************
changed: [localhost] => (item={'key': 'FIRST', 'value': {'some_key': 'first_value'}})
changed: [localhost] => (item={'key': 'SECOND', 'value': {'some_key': 'second_value'}})
TASK [set_fact] ********************************************************************************************************************
skipping: [localhost] => (item=first_value)
ok: [localhost] => (item=second_value)
TASK [debug] ***********************************************************************************************************************
ok: [localhost] =>
desired_output: SECOND
PLAY RECAP *************************************************************************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Extend Volume Group using Ansible

I have trying to extend the VG via ansible passing the pvname by variable, however I really don't understand why is not working.
Below you can see my code.
Variable file:
new_disk:
- diskname: /dev/sdc
pvname: /dev/sdb1, dev/sdc1
vgname: datavg
lvm_settings:
- lv_name: datalv
lv_size: +100%FREE
fs_name: ansible_fs_test
lvpath: /dev/mapper/datavg-datalv
filesystem_type: ext4
tasks file:
include_vars: "{{ vm_name }}.yml"
- name: First disk partition settings
block:
- name: Create a new primary partition
community.general.parted:
device: "{{ item.diskname }}"
number: 1
state: present
with_items: "{{ new_disk }}"
register: partition_status
rescue:
- name: Debug messages to check the error
debug:
msg: "{{ partition_status }}"
- name: Extending the Volume Group
community.general.lvg:
vg: "{{ vgname }}"
pvs: "{{ pvname }}"
pvresize: yes
Below, you can see the error message:
TASK [resize_fs_linux : Extending the Volume Group] **********************************************************************************************************************************************************fatal: [10.1.33.225]: FAILED! => {"changed": false, "msg": "Device /home/icc-admin/ dev/sdc1 not found."}
Do you know have any idea why is not working?
I really appreciate your help and time
Best Regards,
For it works that way:
Variable file
diskname:
- /dev/sdb
- /dev/sdc
disks_settings:
- vgname: datavg
pvname:
- /dev/sdb1
- /dev/sdc1
lvm_settings:
- vgname: datavg
lv_name: datalv
lv_size: +100%FREE
fs_name: ansible_fs_test
lvpath: /dev/mapper/datavg-datalv
filesystem_type: ext4
Tasks file:
---
# tasks file for resize_fs_linux
- include_vars: "{{ vm_name }}.yml"
- name: First disk partition settings
block:
- name: Create a new primary partition
community.general.parted:
device: "{{ item }}"
number: 1
state: present
with_items: "{{ diskname }}"
register: partition_status
run_once: true
rescue:
- name: Debug messages to check the error
debug:
msg: "{{ partition_status }}"
- name: Extending the Volume Group
community.general.lvg:
vg: "{{ item.vgname }}"
pvs: "{{ item.pvname }}"
pvresize: yes
with_items: "{{ disks_settings }}"
- name: Increasing the filesystems
community.general.lvol:
vg: "{{ vgname }}"
lv: "{{ item.lv_name }}"
size: "{{ item.lv_size }}"
resizefs: true
with_items: "{{ lvm_settings }}"

Ansible to execute a task only when multiple files exist

I want to execute a task only when multiple files exist . if only single file is exist i need to ignore this task. How can i achieve this.
Am unable to achieve with the below playbook
---
- name: Standardize
hosts: test
gather_facts: false
vars:
file_vars:
- {id: 1, name: /etc/h_cm}
- {id: 2, name: /etc/H_CM}
tasks:
- block:
- name: Check if both exists
stat:
path: "{{ item.name }}"
with_items: "{{ file_vars }}"
register: cm_result
- name: Move both files
shell: mv "{{ item.item }}" /tmp/merged
with_items: "{{ cm_result.results }}"
when: item.stat.exists
After check if both exist task, you can add a set fact task like this one:
- name: set facts
set_fact:
files_exist: "{{ (files_exist | default([])) + [item.stat.exists] }}"
with_items: "{{ cm_result.results }}"
And you change your move files task to:
- name: Move both files
debug:
msg: "{{ item.stat.exists }}"
with_items: "{{ cm_result.results }}"
when: false not in files_exist
You have to specify shell: mv "{{ item.item.name }}" /tmp/merged insted of shell: mv "{{ item.item }}" /tmp/merged
Check the below works?:
- name: Standardize
hosts: test
gather_facts: false
become: yes ## If needed
vars:
file_vars:
- {id: 1, name: /etc/h_cm}
- {id: 2, name: /etc/H_CM}
tasks:
- block:
- name: Check if both file exists
stat:
path: "{{ item.name }}"
with_items: "{{ file_vars }}"
register: cm_result
- debug:
var: item.stat.exists
loop: "{{ cm_result.results }}"
- name: Crate a dummy list
set_fact:
file_state: []
- name: Add true to list if file exists
set_fact:
file_state: "{{ file_state }} + ['{{ item.stat.exists }}']"
loop: "{{ cm_result.results }}"
when: item.stat.exists == true
- name: Move both files
shell: mv "{{ item.item.name }}" /tmp/merged
loop: "{{ cm_result.results }}"
when: file_state|length > 1

Resources