Ansible条件判断中如何遍历列表匹配节点类型创建用户
问题背景
现有两台主机,分别对应生产环境、测试环境。节点类型标识test、prod配置在目标主机的本地事实文件中,对应ini配置分两类:
生产节点配置:
[node] type= prod
测试节点配置:
[node] type= test
预先定义的用户配置变量如下:
users: - username: A password: password_A update_password: always home: /home/A state: present nodes: ['test', 'prod'] - username: B password: passwd_B update_password: always home: /home/B state: present nodes: ['test']
需求为:用户A需要在生产、测试主机上均完成创建,用户B仅在测试主机创建。
原有编写的角色任务在nodes字段为单值时可正常运行,原任务代码:
- name: create users ansible.builtin.user: name: "{{ item.username }}" password: "{{ item.password }}" uid: "{{ item.uid }}" home: "{{ item.home }}" create_home: yes group : "{{ item.group }}" shell: /bin/bash state: present expires: -1 with_items: - "{{ users }}" when: item.nodes == ansible_local['myfact']['node"']['type']
现存问题:原有判断逻辑仅支持nodes为单值的匹配场景,无法适配nodes为多值列表的比对需求,后续还会新增除prod、test之外的其他主机类型,曾尝试使用subelements实现该逻辑但未成功。
解决方案
无需遍历item.nodes列表做逐值比对,直接使用Ansible内置的in测试判断当前节点类型是否在用户的允许节点列表中即可,逻辑简洁且后续新增节点类型无需调整任务代码。
首先修正原有代码的两处问题:
- 原
when条件中事实取值存在笔误:ansible_local['myfact']['node"']['type']多了冗余双引号,正确取值为ansible_local['myfact']['node']['type'] - 等值判断替换为成员判断,无需额外嵌套循环或复杂插件调用。
修正后的可直接运行的任务代码:
- name: create users ansible.builtin.user: name: "{{ item.username }}" password: "{{ item.password }}" uid: "{{ item.uid | default(omit) }}" home: "{{ item.home }}" create_home: yes group : "{{ item.group | default(omit) }}" shell: /bin/bash state: present expires: -1 update_password: "{{ item.update_password }}" loop: "{{ users }}" when: ansible_local['myfact']['node']['type'] in item.nodes
逻辑说明
- 任务执行时会先获取当前主机的节点类型,直接判断该类型是否存在于当前遍历用户的
nodes允许列表中,存在则执行用户创建操作,不存在则跳过,天然支持多节点类型的匹配需求 - 代码中补充了
default(omit)配置:原有用户变量中未定义uid、group字段,直接引用会触发变量未定义报错,添加该配置后如果对应字段未传值,将自动使用模块默认值 - 补充了原任务遗漏的
update_password参数,和预定义的变量配置对齐,保证密码更新逻辑生效
如果需要使用subelements实现(适配后续更复杂的列表嵌套场景),可参考如下写法,效果与上述方案完全一致:
- name: create users (subelements实现版本) ansible.builtin.user: name: "{{ item.0.username }}" password: "{{ item.0.password }}" uid: "{{ item.0.uid | default(omit) }}" home: "{{ item.0.home }}" create_home: yes group : "{{ item.0.group | default(omit) }}" shell: /bin/bash state: present expires: -1 update_password: "{{ item.0.update_password }}" loop: "{{ users | subelements('nodes') }}" when: item.1 == ansible_local['myfact']['node']['type']
注意:
subelements写法会将每个用户按nodes列表拆分为多条循环项,例如用户A会被拆为(A, test)、(A, prod)两个循环项,仅当循环项的第二个元素和当前节点类型匹配时才会执行操作。该写法循环次数更多,当前场景下直接使用in做成员判断是最优方案。
内容的提问来源于stack exchange,提问作者Philippe
相关产品推荐
相关产品推荐

