Ansible如何从字典列表中找出字典
Posted
技术标签:
【中文标题】Ansible如何从字典列表中找出字典【英文标题】:Ansible how to find out dictionary out of list of dictionaries 【发布时间】:2021-07-20 10:35:37 【问题描述】:$ more defaults/mail.yaml
---
envs:
- dev:
acr-names:
- intake.azurecr.io
- dit.azurecr.io
- dev.azurecr.io
subscription-id: xxx
- uat:
acr-names:
- stagreg.azurecr.io
subscription-id: yyy
- prod:
acr-names:
- prodreg.azurecr.io
subscription-id: zzz
我想写一个 ansible play 来复制 azure https://docs.microsoft.com/en-us/azure/container-registry/container-registry-import-images#import-from-a-registry-in-a-different-subscription 注册表之间的图像
play 应该接受 2 个参数。 source_image 和 target_image,所以播放会将图像从源导入到目标
例如:
ansible-playbook sync-docker-image.yml -e source_image=dit.azurecr.io/repo1:v1.0.0.0 -e target_image=stagreg.azurecr.io/stage-repo:latest
2 个问题:
这里我如何在ansible playbook中找出source_image或target_image属于哪个env(dev,uat或prod),基于env,我想选择订阅ID。所以从上面的例子中,我想创建 2 个变量,分别叫 source_subscription 和 target_subscription 并将它们分别分配给 dev、uat 订阅。
在 YAML 中,是否可以根据键访问字典列表中的变量,例如 envs[dev] 之类的变量?
谢谢
【问题讨论】:
嗨,Yogendramummaneni,欢迎来到 SO。您需要edit your question 并包含到目前为止您尝试的代码,因为您当前的问题听起来像是其他人为您编写代码的要求列表。请阅读how to ask 页面,并特别注意MCVE 部分。祝你好运! 【参考方案1】:首先 - 如果可能的话 - 当你只有三个阶段时,不要使用 envs
中的 dict 项目列表。我假设它们已经被命名,所以使用:
envs:
dev:
acr-names:
- ...
subscription-id: xxx
uat:
acr-names:
- ...
subscription-id: yyy
prod:
acr-names:
- ...
subscription-id: zzz
这将使通过envs.dev
或envs.uat
等访问阶段变得更容易。因此您只需要遍历envs.dev.acr-names
(可以使用_ 而不是-,否则以后会遇到麻烦)。在迭代中,您可以使用 when 条件来检查您的来源:
- name: "Facts"
set_fact:
envs:
dev:
acr_names:
- intake.azurecr.io
- dit.azurecr.io
- dev.azurecr.io
subscription_id: xxx
uat:
acr_names:
- stagreg.azurecr.io
subscription_id: yyy
prod:
acr_names:
- prodreg.azurecr.io
subscription_id: zzz
source_image: "dit.azurecr.io/repo1:v1.0.0.0"
target_image: "stagreg.azurecr.io/stage-repo:latest"
- name: "Identify source subscription"
set_fact:
source_subscription: " envs.dev.subscription_id "
when:
- "item in source_image"
- "source_subscription is undefined"
loop: " envs.dev.acr_names "
如果无法更改 dict(因为您有“很多”),则需要遍历 envs
中的项目。如果可能,不要创建“随机”键,而是使用“名称”项。所以这样的结构会更好
envs:
- name: dev
acr_names:
- ...
subscription_id: xxx
- name: uat
acr_names:
- ...
subscription_id: yyy
...
因此,您遍历 envs
中的项目,然后遍历 item.acr_names
以找到您的系统。这更复杂,因为您遍历一个列表并迭代该列表中的项目。我认为,这仅靠一项任务是不可能的。但是对于给定的结构,问题是-source_target
中的字符串与acr_names
中的字符串不完全相同。因此,删除斜线后的任何内容,然后您可以使用不同的方法在列表中搜索字符串。
- name: "Identify source subscription"
set_fact:
source_subscription: " env.subscription_id "
when:
- "source_image.split('/')[0] in env.acr_names"
- "source_subscription is undefined"
loop: " envs "
loop_control:
loop_var: env
您还可以在第一个示例中使用 split
过滤器,而无需循环 envs.dev
等。
- name: "Show result"
set_fact:
source_subscription: " envs.dev.subscription_id "
when:
- "source_image.split('/')[0] in envs.dev.acr_names"
如果你真的需要使用你给定的结构,那么你需要遍历envs
。它将带有随机键的字典作为根元素。这使得它非常复杂。在这种情况下,您需要遍历它,包含一个带有include_tasks
的单独任务文件,并且在该任务列表中,您需要过滤器lookup('dict',env) to get a special dict and you can access
item.keyand
item.value.acr_namesand
item.value。 subscription_id` 来访问字典中的值。我不建议这样做。
- name: "Identify source subscription"
include_tasks: find_env.yml
loop: " envs "
loop_control:
loop_var: env
而find_env.yml
包含:
- name: "Show result"
set_fact:
source_subscription: " env[item.key].subscription_id "
when:
- "source_image.split('/')[0] in env[item.key].acr_names"
- "source_subscription is undefined"
loop: " env | dict2items "
所有这些都必须针对源和目标执行两次。
【讨论】:
以上是关于Ansible如何从字典列表中找出字典的主要内容,如果未能解决你的问题,请参考以下文章