能否在Ansible的defaults/main.yml中循环生成值列表?
问题
我有自定义的inventory数据结构和角色输入参数,想从inventory数据结构填充这些输入参数,请问能不能通过循环生成列表?
示例inventory结构如下:
--- install_disk: vtbd0: scheme: GPT target: bsdinstall partitions: 1: size: 512k type: freebsd-boot gptlabel: CSMBOOT 2: size: 55m type: efi gptlabel: EFIBOOT fslabel: efiprtn 3: size: 3g type: freebsd-ufs gptlabel: UFSBOOT fslabel: ufsprtn 4: type: freebsd-zfs gptlabel: ZFSMAIN poolname: zpool ashift: 12 swapsize: 6G mountdir: /tmp/newbsd geli: algo: AES-XTS length: 256 sector: 4096 keyfile: zpool.key keydir: geli keypath: /usr/local keycount: 3
我当前手动生成列表第一个元素的写法如下:
--- target_dsk: dev_name: "{{ install_disk.keys() | first }}" prt_scheme: "{{ install_disk.values() | first | dict2items | selectattr('key', 'equalto','scheme') | map(attribute='value') | first }}" prt_list: - index: "{{ install_disk.values() | first | dict2items | selectattr('key', 'equalto','partitions') | map(attribute='value') | first | dict2items | selectattr('key', 'equalto',1) | map(attribute='key') | first }}" type: "{{ install_disk.values() | first | dict2items | selectattr('key', 'equalto','partitions') | map(attribute='value') | first | dict2items | selectattr('key', 'equalto',1) | map(attribute='value.type') | first }}" gptlabel: "{{ install_disk.values() | first | dict2items | selectattr('key', 'equalto','partitions') | map(attribute='value') | first | dict2items | selectattr('key', 'equalto',1) | map(attribute='value.gptlabel') | first }}" size: "{{ install_disk.values() | first | dict2items | selectattr('key', 'equalto','partitions') | map(attribute='value') | first | dict2items | selectattr('key', 'equalto',1) | map(attribute='value.size') | first }}"
我觉得当前写法不够优化,想找更优的列表推导方式,同时想知道能不能通过循环生成列表元素,避免在defaults/main.yml中硬编码列表元素数量。我试过直接用字典,但不符合我的数据抽象需求。
优化方案
完全可以通过循环自动生成列表元素,无需硬编码分区数量。用Ansible的Jinja2循环语法就能实现,以下是两种优化写法:
写法一:原生YAML列表生成
直接在变量中通过Jinja2循环遍历分区,生成符合要求的列表结构:
--- target_dsk: # 简化磁盘名称获取 dev_name: "{{ install_disk.keys() | first }}" # 直接访问磁盘的scheme属性,替代冗长过滤链 prt_scheme: "{{ install_disk[dev_name].scheme }}" # 自动遍历所有分区生成列表 prt_list: {% set disk = install_disk[dev_name] %} {% set partitions = disk.partitions | dict2items | sort(attribute='key') %} {%- for part in partitions %} - index: "{{ part.key }}" type: "{{ part.value.type }}" gptlabel: "{{ part.value.gptlabel | default('') }}" size: "{{ part.value.size | default('') }}" {%- endfor %}
写法二:模板字符串转YAML(适合复杂场景)
如果分区逻辑更复杂,可以用模板字符串生成后转成YAML列表:
--- target_dsk: dev_name: "{{ install_disk.keys() | first }}" prt_scheme: "{{ install_disk[dev_name].scheme }}" prt_list: "{{ lookup('template', 'partitions.j2') | from_yaml }}"
对应的partitions.j2模板内容:
{% set disk = install_disk[install_disk.keys() | first] %} {% set partitions = disk.partitions | dict2items | sort(attribute='key') %} [ {%- for part in partitions %} { "index": "{{ part.key }}", "type": "{{ part.value.type }}", "gptlabel": "{{ part.value.gptlabel | default('') }}", "size": "{{ part.value.size | default('') }}" }{%- if not loop.last %},{% endif %} {%- endfor %} ]
优化亮点
- 简化属性访问:直接通过
install_disk[dev_name].scheme获取分区方案,可读性大幅提升。 - 自动适配分区数量:不管inventory中有多少个分区,循环都会自动生成对应列表元素,彻底避免硬编码。
- 兼容可选字段:用
default('')处理size这类可能缺失的字段,防止出现未定义错误。 - 保持数据抽象:生成的列表结构完全符合你的需求,不会像直接用字典那样破坏抽象逻辑。
内容的提问来源于stack exchange,提问作者X bl lJJ H i K
相关产品推荐
相关产品推荐

