1
$ 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 -在不同的订阅中

该剧应接受 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个问题:

  1. 在这里,我如何在ansible playbook中找出source_image或target_image属于哪个env(dev,uat或prod),基于env,我想选择订阅ID。因此,从上面的示例中,我想创建两个名为 source_subscription 和 target_subscription 的变量,并将它们分别分配给 dev、uat 订阅。

  2. 在 YAML 中,是否可以根据键访问字典列表中的变量,例如 envs[dev] 之类的变量?

谢谢

4

1 回答 1

0

首先 - 如果可能的话 - 当你只有三个阶段时,不要在envs. 我假设它们已经命名,所以使用:

envs:
  dev:
    acr-names:
      - ...
    subscription-id: xxx
  uat:
    acr-names:
      - ...
    subscription-id: yyy
  prod:
    acr-names:
      - ...
    subscription-id: zzz

这将使通过envs.devorenvs.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以找到您的系统。这更复杂,因为您遍历一个列表并迭代该列表中的项目。我认为,这仅靠一项任务是不可能的。但是对于给定的结构,问题是 - 字符串 insource_target不完全是 in 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.key anditem.value.acr_names anditem.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 }}"

对于源和目标,所有这些都必须执行两次。

于 2021-04-29T13:16:54.680 回答