使用Ansible Jinja2列表特性调用hostvars返回结果不符合预期
问题:Ansible筛选NVMe磁盘时的变量解析错误
问题场景
我尝试用Ansible的hostvars筛选以nvme开头的磁盘,编写了如下任务:
- name: Output disk information debug: var: hostvars[inventory_hostname].ansible_devices.keys() | map('regex_search', 'nvme.*') | select('string') | list
实际输出
执行后返回的结果包含完整的查询语句作为键,而非直接返回列表:
ok: [cm42.ag6hq.net] => { "hostvars[inventory_hostname].ansible_devices.keys() | map('regex_search', 'nvme.*') | select('string') | list": [ "nvme0n1" ] } ok: [cm43.ag6hq.net] => { "hostvars[inventory_hostname].ansible_devices.keys() | map('regex_search', 'nvme.*') | select('string') | list": [] }
预期输出
我期望直接得到列表内容:
ok: [cm42.ag6hq.net] => { [ "nvme0n1" ] } ok: [cm43.ag6hq.net] => { [] }
后续报错
当我把这个查询用在with_items:中时,Ansible没有解析表达式,而是把整个字符串当作item值,导致设备找不到的错误:
failed: [cm42.ag6hq.net] (item=hostvars[inventory_hostname].ansible_devices.keys() | map('regex_search', 'nvme.*') | select('string') | list) => {"ansible_loop_var": "item", "changed": false, "item": "hostvars[inventory_hostname].ansible_devices.keys() | map('regex_search', 'nvme.*') | select('string') | list", "msg": "Device /dev/hostvars[inventory_hostname].ansible_devices.keys() | map('regex_search', 'nvme.*') | select('string') | list not found."}
错误原因与解决方法
错误原因
你犯了两个核心错误:
debug模块var参数的特性:var接收的是变量名字符串,直接写带管道的表达式时,Ansible不会解析表达式,而是把整个字符串当作变量名,所以输出会以该字符串为键,对应值才是表达式的计算结果。with_items的变量解析问题:旧版with_items(现在推荐用loop)如果直接写复杂表达式,必须用{{ }}包裹触发Jinja2解析,否则会被当作纯字符串处理。
解决方法
方法1:调整debug输出,直接显示计算结果
把var换成msg,并用{{ }}包裹表达式,让Jinja2解析后输出结果:
- name: Output disk information debug: msg: "{{ hostvars[inventory_hostname].ansible_devices.keys() | map('regex_search', 'nvme.*') | select('string') | list }}"
方法2:先存变量再使用(更规范)
通过set_fact把筛选后的磁盘列表存为变量,后续任务直接引用:
- name: Get NVME disks list set_fact: nvme_disks: "{{ hostvars[inventory_hostname].ansible_devices.keys() | map('regex_search', 'nvme.*') | select('string') | list }}" - name: Output disk information debug: var: nvme_disks - name: Process each NVME disk loop: "{{ nvme_disks }}" debug: msg: "Processing device /dev/{{ item }}"
额外优化:简化筛选表达式
可以用select结合match简化逻辑,效果一致:
nvme_disks: "{{ ansible_devices.keys() | select('match', 'nvme.*') | list }}"
(注:当前任务运行在目标主机上,直接用ansible_devices即可,无需通过hostvars[inventory_hostname]引用)
内容的提问来源于stack exchange,提问作者AG6HQ
相关产品推荐
相关产品推荐

