Ansible列表过滤报错:生成器不可迭代及列表不可哈希问题排查
解决Ansible中VMware VM列表过滤的reject报错问题
问题分析
你遇到的两个错误本质是过滤逻辑的写法不符合Ansible过滤器的要求:
- "generator object is not iterable":
reject返回的是生成器,直接赋值给列表变量时,部分场景下Ansible无法直接迭代生成器; - "unhashable type: 'list'":大概率是你在
reject的判断条件里,把未处理的嵌套VM列表直接用来做成员判断,比如item in {{ existing_vms }},但如果existing_vms是嵌套结构而非一维字符串列表,就会触发这个错误。
正确实现步骤
1. 先收集所有存在的VM名称(生成扁平列表)
先批量验证待退役列表中的VM,提取存在的VM名称为一维字符串列表(关键:必须是扁平结构,不能嵌套):
- name: 验证待退役VM的存在性 vmware_guest_info: hostname: "{{ vcenter_host }}" username: "{{ vcenter_user }}" password: "{{ vcenter_pass }}" validate_certs: false name: "{{ item }}" loop: "{{ test_decom_list }}" register: vm_check_results ignore_errors: true # 不存在的VM会报错,忽略错误继续执行 - name: 提取存在的VM名称到扁平列表 set_fact: existing_vms: "{{ vm_check_results.results | selectattr('failed', 'false') | map(attribute='instance.hw_name') | list }}"
这里通过selectattr过滤出执行成功的结果(即VM存在的条目),再用map提取VM名称,最终得到的existing_vms是类似["vm1", "vm2"]的一维字符串列表。
2. 用过滤器生成目标列表
方法一:用reject过滤不存在的VM
- name: 过滤得到仅存在的VM列表 set_fact: new_vm: "{{ test_decom_list | reject('not in', existing_vms) | list }}"
注意reject的参数写法:'not in'是过滤器测试规则,后面跟目标列表existing_vms,最后必须加|list把生成器转成可迭代的列表。
方法二:用select直接保留存在的VM(推荐)
逻辑更直观,避免条件搞反:
- name: 过滤得到仅存在的VM列表 set_fact: new_vm: "{{ test_decom_list | select('in', existing_vms) | list }}"
错误原因复盘
- 不加
|list时报错,是因为Ansible无法直接将生成器类型识别为可迭代列表; - 加
|list后仍报错,是因为你的existing_vms是嵌套列表而非扁平字符串列表,导致item in existing_vms判断时,列表被当作哈希表键处理,而列表属于不可哈希类型。
内容的提问来源于stack exchange,提问作者dfs
相关产品推荐
相关产品推荐

