Ansible 基于PID字典匹配part_id替换Manufacturer并保留字典结构
核心问题定位
现有实现存在两处逻辑缺陷,直接导致输出格式异常:
- 结构化类型丢失:通过字符串拼接方式给
new_merged_list赋值,会将列表、字典这类结构化对象强制渲染为纯文本,且被Ansible默认标记为AnsibleUnsafeText,后续无法做键值访问、元素过滤等操作 - 字段值类型不匹配:
json_query的查询结果固定为数组格式,未提取单值就直接赋值给Manufacturer字段,导致字段值为['Cisco']这类单元素数组,不符合预期的纯字符串厂商名要求
修正方案
最小改动适配原有逻辑
- 循环开始前先初始化
new_merged_list为空列表,规避未定义变量报错 - 改用列表加法的方式追加元素,全程保持列表类型
- 对匹配到的厂商结果用
first过滤器提取单值,无匹配时返回默认空字符串
# 初始化空结果列表 - name: 初始化结果存储变量 set_fact: new_merged_list: [] - name: 遍历条目匹配PID厂商映射 set_fact: new_merged_list: "{{ new_merged_list + [updated_item] }}" loop: "{{ merged_list | flatten(levels=1) }}" vars: # 提取匹配到的厂商单值,无匹配返回空字符串 matched_vendor: >- {{ PID | dict2items | json_query(query) | first | default('') }} query: "[?contains(value, '{{ item.part_id }}')].key" # 合并更新当前条目的Manufacturer字段 updated_item: "{{ item | combine({'Manufacturer': matched_vendor}) }}" - debug: msg: "{{ new_merged_list }}"
批量优化实现方案
不需要逐轮循环调用set_fact拼接列表,直接通过Jinja过滤器一次性完成整个列表的转换,执行效率更高,代码更简洁:
- name: 批量匹配PID映射生成结构化结果 set_fact: new_merged_list: >- {{ merged_list | flatten(levels=1) | map('match_vendor') | list }} vars: # 单条目匹配逻辑:为每个条目标注对应厂商 match_vendor: | {{ item | combine({ 'Manufacturer': ( PID | dict2items | selectattr('value', 'contains', item.part_id) | map(attribute='key') | first | default('') ) }) }}
修正后效果
- 输出的
new_merged_list为标准列表类型,元素为字典结构,可直接进行后续键值操作、过滤、取值等逻辑,不会出现AnsibleUnsafeText类型问题 - 条目的Manufacturer字段为纯字符串格式(如
Cisco),不存在数组嵌套问题 - 未匹配到PID映射的条目,Manufacturer字段会自动填充为默认空值,与原有逻辑保持一致
说明:使用
selectattr替代硬编码json_query查询字符串的方式,可避免复杂的转义问题,逻辑可读性更强
内容的提问来源于stack exchange,提问作者smenk
相关产品推荐
相关产品推荐

