Keywords: Ansible | with_items | conditionals
Abstract: This article delves into the challenges of dynamic variable registration when using Ansible's with_items loops combined with when conditionals in automation configurations. Through a practical case study—formatting physical drives on multiple servers while excluding the system disk and ensuring no data loss—it identifies common error patterns in variable handling during iterations. The core solution leverages the results list structure from loop-registered variables, avoiding dynamic variable name concatenation and incorporating is not skipped conditions to filter excluded items. It explains the device_stat.results data structure, item.item access methods, and proper conditional logic combination, providing clear technical guidance for similar automation tasks.
In Ansible automation configuration management, combining loops with conditionals is a common requirement, but improper handling can lead to difficult-to-debug errors. This article explores how to correctly use with_items and when conditionals to avoid pitfalls in dynamic variable registration through a specific case study.
Problem Scenario Analysis
Assume we have multiple servers, each with four physical drives: /dev/sda, sdb, sdc, and sdd. The sda drive has the operating system installed, and we need to format the other drives, provided they contain no existing data. The initial implementation attempted the following steps:
- Retrieve all physical disk lists and store them in the
disk_varvariable. - Check if each disk (excluding
sda) is partitioned by using thestatmodule to detect the existence of the/dev/{{item}}1path. - If a disk is not partitioned, use the
partedcommand to create a GPT partition table.
The key issue arises in variable passing between steps two and three. The initial code tried to register separate variable names for each loop item, such as base_secondary_partition_{{item}}, and then reference these dynamic variables in conditionals. However, Ansible's Jinja2 template engine does not support direct variable value access via string concatenation, leading to conditional evaluation failures with errors like: error while evaluating conditional: base_secondary_partition_sdd.stat.exists == false.
Solution: Leveraging Loop Registration Result Structure
When Ansible processes loop tasks, it collects all iteration results into a registered variable containing a results list. Each list element corresponds to one loop iteration, including the original item (accessible via the item attribute), task execution status (e.g., skipped, changed), and module return data (e.g., stat.exists).
The corrected code example is as follows:
- name: Check if the disk is partitioned and also ignore sda
stat: path=/dev/{{item}}1
with_items: "{{ disk_var }}"
when: item != 'sda'
register: device_stat
- name: Create GPT partition table
command: /sbin/parted -s /dev/{{ item.item }} mklabel gpt
with_items: "{{ device_stat.results }}"
when:
- item is not skipped
- item.stat.exists == false
In the first task, the device_stat registered variable includes a results list, with each element corresponding to an item from disk_var (including sda, which is skipped by when: item != 'sda'). In the second task, we loop over device_stat.results and access the original disk identifier (e.g., sdb) via item.item. The conditional check has two parts: item is not skipped ensures excluded items (i.e., sda) are not processed, and item.stat.exists == false verifies that the disk is not partitioned.
Technical Details and Best Practices
This approach avoids the complexity of dynamic variable names by directly utilizing Ansible's built-in data structures. Key points to note include:
- The order of elements in
device_stat.resultsmatches the originaldisk_varlist but includes all items, even those skipped by conditions. Thus, filtering withitem is not skippedis essential. - When accessing the original item, use
item.iteminstead ofitem, asitemin this context represents the entire result object. - Conditionals can combine multiple expressions to enhance logic clarity and maintainability.
For more complex scenarios, consider using loop (Ansible 2.5+) as an alternative to with_items, though the core principles remain similar. It is always advisable to use the debug module during development to output registered variable structures, for example:
- debug:
var: device_stat
This helps understand data formats and prevent common erroneous assumptions.
Conclusion
Through this case study, we have learned how to properly handle the interaction between loops and conditionals in Ansible. Key takeaways include avoiding dynamic variable name concatenation, leveraging the results list structure, and appropriately using is not skipped for filtering. These techniques are not only applicable to disk formatting tasks but also widely useful in other automation scenarios requiring iterative checks, improving Playbook reliability and readability.