Ansible - как вы ссылаетесь на элемент, который в данный момент зациклен в другом цикле - PullRequest
1 голос
/ 27 марта 2019

У меня есть переменная, которая выглядит (реальность намного длиннее):

deploy_dirs:
  conf:
    base: '/etc/projects/'
    subs:
      apache: '/httpd'
      modsec: '/modsec'
      php: '/php'
      haproxy: '/haproxy'
      varnish: '/varnish'
  logs:
    base: '/var/log/projects/'
    subs:
      apache: '/httpd'
      modsec: '/modsec'
      php: '/php'
      haproxy: '/haproxy'
      varnish: '/varnish'

Тогда у меня есть задача, которая выглядит следующим образом:

- debug:
    msg: '{{ item.0.value.base }}SOME-OTHER-VAR{{ item.1 }}'
  loop: '{{ deploy_dirs | dict2items | subelements("value.subs") }}'

Который я бы хотелна вывод:

/etc/projects/SOME-OTHER-VAR/httpd
/etc/projects/SOME-OTHER-VAR/modsec
/etc/projects/SOME-OTHER-VAR/php
/etc/projects/SOME-OTHER-VAR/haproxy
/etc/projects/SOME-OTHER-VAR/varnish

/var/log/projects/SOME-OTHER-VAR/httpd
/var/log/projects/SOME-OTHER-VAR/modsec
/var/log/projects/SOME-OTHER-VAR/php
/var/log/projects/SOME-OTHER-VAR/haproxy
/var/log/projects/SOME-OTHER-VAR/varnish

Эти переменные повторно используются в разных местах по всем моим книгам, и структура имеет смысл для меня и кажется достаточно простой.

Я пробовализменение фильтра subelements() на фильтр product() (эквивалент with_nested), но, похоже, он не может ссылаться на переменную из более раннего цикла так же, как фильтр subelements().

Очевидно, проблема с вышесказанным в том, что subelements() нужен список, а не словарь.Я не могу преобразовать аргумент "value.subs" в список, так как не могу найти способ для вложения таких фильтров ..?

У кого-нибудь есть идеи, как заставить это работать?

Спасибо!

ОБНОВЛЕНИЕ : Если у меня также есть:

www:
    base: '/srv/www/projects/'
    subs: {}

И я просто хочу вывести:

/srv/www/projects/SOME-OTHER-VAR

Знаете ли вы, как я могу развернуть бит subs, чтобы он работал и генерировал ожидаемый результат?На данный момент это просто пропускает.т.е. для www.

петли не возникают

1 Ответ

1 голос
/ 27 марта 2019

Вы можете преобразовать ваш subs дикт в список с помощью json_query перед использованием фильтра субэлементов.

- debug:
    msg: "{{ item.0.base }}SOME-OTHER-VAR{{ item.1 }}"
  loop: >-
    {{
      deploy_dirs
      | json_query('*[].{base: base, subs: subs.*}')
      | subelements('subs')
    }}

Посмотрите на документацию jmespath для синтаксиса. json_query действительно удобен, когда ваша структура данных становится сложной.

Это решение не будет зацикливаться на элементах с пустым элементом subs, таким как запись карты 'www' в вашем примере, и у меня нет «чистого и простого» способа сделать это в одной задаче. Вы можете легко получить вторую задачу, зацикливаясь на элементах с пустыми подпрограммами => deploy_dirs | json_query("* | [?!subs]")

Полагаю, ваша конечная цель - не записывать сообщения отладки на экран. Если вам действительно нужна единая структура для выполнения вашей конечной задачи (например, создания каталогов) за один шаг, вы можете заполнить переменную с помощью set_fact и описанных выше методов, а затем использовать ее для достижения вашей реальной задачи

- name: Get all elements with subs to loop over
  set_fact:
    my_var: >-
      {{
        deploy_dirs
        | json_query('*[].{base: base, subs: subs.*}')
        | subelements('subs')
      }}

- name: Add entries with empty item1 for elements with empty subs
  set_fact:
    my_var: >-
      {{
        my_var
        +
        [[item, '']]
      }}
  loop: >-
    {{ deploy_dirs | json_query("* | [?!subs]") }}

- name: This will be replaced with a real task
  debug:
    msg: "{{ item.0.base }}SOME-OTHER-VAR{{ item.1 }}"
  loop: "{{ my_var }}"
...