python - 使用多个子元素最有效的方法是什么?
问题描述
我正在使用 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 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 并期望将用户从不再关联的主机中删除。
我已经尝试subelements
使用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
andtests
组中的成员身份。
一旦你有了这个列表,创建和删除用户就很简单了:
- 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 - Python中“set”和“if item in array”的时间复杂度是多少?
- python - Python,PyTest 是否可以同时添加长参数和短参数?
- vb.net - 处理 WaitForSingleObject - 响应式 UI
- database - 在 PostgreSQL 中存储唯一和非唯一视图/使用统计信息的最佳方式
- reactjs - 使用 react native paper 和 react native navigation v5 将道具从堆栈导航器下的屏幕传递到共享应用栏
- assembly - NASM。如何使用在有效地址上不断变化的变量?
- javascript - 使用树结构 React JS 中的数据在下拉菜单中搜索
- ios - Xcode 重构“转换为 Switch”
- php - htaccess 重写 url 和 php GET 方法
- wordpress - 如何恢复不可用的 WordPress 网站?