我正在使用python进行用户管理。我有一个“ user_groups”映射数组,其中每个元素都包含一个具有映射名称的键,该值是应在其中配置组的主机的数组。
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剧本已在所有主机上运行,并且仅当用户通过组或按每个用户定义的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 }} ))
这一直很好,但是现在我有一个要求,以确保没有与之关联的所有主机上都不存在该用户。这里的主要用例是经历了组/用户的用户。主机更改,但它们仍将存在于不再关联的服务器上。
如果我尝试上面发布的相同代码块,但是将when
的条件取反并将state
更改为absent
,由于循环的性质,它将无法正常工作。在特定主机上运行任务时,我们会循环浏览分组列出的每个服务器。并非每个迭代都会匹配inventory_hostname
,因此ansible将抢先删除用户,即使该关联将在以后的迭代中匹配。
我想只有在循环的所有迭代都符合条件的情况下,我才试图找出如何运行任务的方法。或者也许有一种更优雅的方式来解决问题。
预期结果:
将用户映射到两个组。运行ansible,以在组中包含的主机上配置用户。
从用户中删除一组。运行ansible,并希望将用户从不再与之关联的主机中删除。
我尝试使用subelements
jinja过滤器product
嵌套unions
,但似乎无法弄清楚这一点。
感谢您的帮助。
答案 0 :(得分:2)
阅读您的评论后,我会更好地了解您要做什么。这是另一种方法:构建用户应在其上存在的主机的统一列表。
让我们从这个示例数据开始(这次我使用了两个现有变量的字典):
---
- 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
在列表中的每个项目周围添加引号。