Ansible как найти словарь из списка словарей

$ 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

Я хочу написать нестандартную игру для копирования изображения между реестрами в Azure https://docs.microsoft.com/en-us/azure/container-registry/container-registry-import-images#import-изреестравдругойподписке

Игра должна принимать 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. Вот как я могу узнать, к какому env (dev, uat или prod) принадлежит source_image или target_image в ansible playbook, на основе env я хочу выбрать идентификатор подписки. Итак, в приведенном выше примере я хочу создать 2 переменные с именами source_subscription и target_subscription и назначить их подпискам dev и uat соответственно.

  2. В YAML можно ли получить доступ к переменной в списке словарей на основе ключа, например, что-то вроде envs[dev]?

Спасибо


person Yogendramummaneni Prasad    schedule 27.04.2021    source источник
comment
Привет Йогендрамумманени, добро пожаловать в SO. Вы захотите отредактировать свой вопрос и включить код для своей попытки, так как ваш текущий вопрос звучит как список требования, чтобы кто-то другой написал код для вас. Пожалуйста, прочитайте страницу как спросить и обратите особое внимание на MCVE. Удачи!   -  person mdaniel    schedule 27.04.2021


Ответы (1)


Во-первых, если возможно, когда у вас есть только три этапа, не используйте список элементов словаря в envs. Я предполагаю, что они уже названы, поэтому используйте:

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.keyanditem.value.acr_namesanditem.value.subscription_id` для доступа к значениям внутри dict. Я бы не рекомендовал это.

- 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 }}"

Все это нужно сделать дважды для источника и цели.

person TRW    schedule 29.04.2021