我正在使用 python 进行用户管理。我有一个“user_groups” map 数组,其中每个元素都包含一个具有 map 名称的键,值是应配置该组的主机数组。
user_groups:
robots: "test_server1,test_server2"
developers: "test_server3,test_server4"
tests: "test_server5"
我还有一个 user_names
数组,其中每个元素都包含一个映射,其中包含诸如该人的用户名、该人应关联的组以及该人的任何其他主机等详细信息。用户应与关联。
user_names:
- username: mohamed
group:
- robots
- tests
hosts:
user:
- test_server4
到目前为止,我们的 ansible playbook 已在所有主机上运行,并且仅当用户通过组或通过每个用户定义的hosts.user 与主机关联时才将用户添加到主机。子元素循环促进了这一点。举个例子:
- name: If user is not associated with this host via groups or item.hosts.user, then ensure user is absent from host and remove user's home directory.
become: true
user:
state: present
name: "{{ item.0.username }}"
with_subelements:
- "{{ user_names }}"
- group
- flags:
skip_missing: true
when: (item.0.hosts is defined and item.0.hosts.user is defined and inventory_hostname in item.0.hosts.user) or (inventory_hostname in user_groups.{{ item.1 }} ))
这一直工作得很好,但现在我需要确保用户不在其不关联的所有主机上。这里的主要用例是经历 groups/user.hosts 更改的用户,但它们仍然存在于不再关联的服务器上。
如果我尝试上面发布的相同代码块,但反转 when
条件并将 state
更改为 absent
,它不会由于循环的性质而工作;当在特定主机上运行任务时,我们循环遍历组中列出的每个服务器。并非每次迭代都会匹配 inventory_hostname,因此 ansible 会先发制人地删除用户,即使该关联在以后的迭代中会匹配。
我想我正在尝试找出仅当循环的所有迭代都匹配条件时如何运行任务。或者也许有一种更优雅的方法来解决问题。
预期结果:
将用户映射到两个组。运行 ansible 以在组中包含的主机上配置用户。
从用户中删除一组。运行 ansible 并期望将用户从不再与其关联的主机中删除。
我尝试过嵌套子元素
,使用product
jinja过滤器,unions
,但似乎无法弄清楚这一点。
感谢您的帮助。
最佳答案
阅读您的评论,我更好地理解您想要做什么。这是一种不同的方法:构建用户应存在的主机的统一列表。
让我们从这个示例数据开始(这次我使用了两个现有变量的字典):
---
- hosts: all
gather_facts: false
vars:
user_groups:
robots: [host0, host2]
developers: [host0]
tests: [host2]
user_names:
bob:
group:
- robots
- tests
hosts:
- host0
alice:
group:
- developers
hosts:
- host1
现在,对于每个用户,我们将为其定义一个统一的主机列表:
---
# Just set a default value for user_hosts to avoid a bunch of
# calls to the |default filter in the following expression.
- set_fact:
user_hosts: {}
- set_fact:
user_hosts: >-
{{ user_hosts|combine({
item.key:
(
item.value.hosts|default([])
+ user_groups|json_query('[{}][]'.format(','.join(item.value.group)))
)|unique
}) }}
loop: "{{ user_names|dict2items }}"
- debug:
var: user_hosts
这将产生:
ok: [host0] => {
"user_hosts": {
"alice": [
"host1",
"host0"
],
"bob": [
"host0",
"host1",
"host2"
]
}
}
alice
是在 host1
上定义的,因为它是在 user_names
中显式声明的。她在 host0
上定义,因为她是 developers
组的成员。
bob
最终在本示例中的所有三个主机上定义:host0
,因为它是在 user_names
和 host1 中显式声明的
和 host2
因为他是 robots
和 tests
组的成员。
获得此列表后,创建和删除用户就很简单:
- name: create users
debug:
msg: "create user {{ item.key }}"
when: inventory_hostname in item.value
loop: "{{ user_hosts|dict2items }}"
loop_control:
label: "{{ item.key }}"
- name: delete users
debug:
msg: "delete user {{ item.key }}"
when: inventory_hostname not in item.value
loop: "{{ user_hosts|dict2items }}"
loop_control:
label: "{{ item.key }}"
更新
如果您的组名称不是有效的标识符(例如,它们有空格或 -
等),则需要在 jmespath 表达式中引用它们:
- set_fact:
user_hosts: >-
{{ user_hosts|combine({
item.key:
(
item.value.hosts|default([])
+ user_groups|json_query('[{}][]'.format(
','.join(item.value.group|map('regex_replace', '(.*)', '"\1"'))
))
)|unique
}) }}
loop: "{{ user_names|dict2items }}"
此处,我们使用 regex_replace
过滤器和 map
在列表中的每个项目周围添加引号。
关于python - 处理多个子元素的最有效方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55938051/