В Ansible, как объединить переменные из отдельных файлов в один массив?

В Ansible, в роли, у меня есть файлы vars:

vars/
    app1.yml
    app2.yml

Каждый файл содержит vars, специфичные для приложения/веб-сайта, например:

name: app1
git_repo: https://github.com/philgyford/app1.git
# ...

В идеальном случае, не зная заранее, какие приложения имеют переменные файлы, я бы хотел получить массив под названием apps:

apps:
  - name: app1
    git_repo: https://github.com/philgyford/app1.git
    # ...
  - name: app2
    git_repo: https://github.com/philgyford/app2.git
    # ...

т.е. объединяет переменные из файлов в один.

Я знаю, что могу загрузить все переменные файлы следующим образом:

- name: Load var files
  with_fileglob:
    - ../vars/*.yml
  include_vars: '{{ item }}'

Но, учитывая, что каждый файл имеет идентичные имена переменных, он перезаписывает каждый предыдущий набор переменных. Я не вижу способ загрузить переменные и поместить их в массив apps.

Я открыт, чтобы немного изменить порядок, если это единственный способ сделать что-то подобное.

Ответ 1

Тебе этого не сделать. Переменные всегда будут переопределять переменные с одинаковыми именами. Единственное, что вы можете сделать с этой точной настройкой, это написать свой собственный плагин vars, который читает эти файлы и объединяет их в массив.

Если вы готовы изменить структуру определения своих приложений, вы можете использовать хэш и установить свой hash_behavior=merge. В каждом файле Vars у вас будет такое определение:

apps:
  app1:
    git_repo: https://github.com/philgyford/app1.git

apps:
  app2:
    git_repo: https://github.com/philgyford/app2.git

Когда Ansible загрузит оба файла, он автоматически объединит их в:

apps:
  app1:
    git_repo: https://github.com/philgyford/app1.git
  app2:
    git_repo: https://github.com/philgyford/app2.git</pre>

Но hash_behavior=merge что hash_behavior=merge фундаментально меняет поведение Ansible по умолчанию на глобальном уровне. Убедитесь, что все ваши роли не имеют проблем с этим параметром. В документации упоминается:

Как правило, мы рекомендуем не использовать этот параметр, если вы не считаете, что он вам абсолютно необходим

Если вы все еще используете Ansible 1, вы можете использовать вместо этого один из моих старых плагинов: include_vars_merged. По сути, это добавляет поведение hash_behavior=merge только к одной задаче.

Я еще не рассматривал возможность перехода на Ansible 2, хотя в настоящее время мне кажется, что он мне больше не нужен.

Ответ 2

Начиная с Ansible v2.0 вы можете сделать это:

- name: merging hash_a and hash_b into hash_c
  set_fact: hash_c="{{ hash_a|combine(hash_b) }}"

Проверьте больше в Ansible filters - Объединение хэшей/словарей (из Jinja2)

Ответ 3

Ну, вы не можете напрямую построить массив, но вы можете добиться того же усилия с помощью диктата.

Предположим, вы хотите построить массив:

[{
    name: 'bob',
    age: 30
}, {
    name: 'alice',
    age: 35 
}]

Вы можете поместить каждый элемент в файл как:

bob.yml

bob:
  name: bob
  age: 30

alice.yml

alice:
  name: alice
  age: 35

Поместите эти файлы в один и тот же каталог (например, user), затем используйте include_vars для загрузки всего каталога:

- name: Include vars
  include_vars:
    name: users
    dir: user

Это даст вам возможность users:

users:
  alice:
    name: alice
    age: 35
  bob:
    name: bob
    age: 30

dict2items фильтр dict2items в ansible, вы получите dict2items массив

Ответ 4

Начиная с Ansible 2.2, модуль include_vars (ссылка) был значительно расширен.

Теперь можно сделать что-то вроде:

- include_vars:
    name: 'apps'
    dir: '../vars'
    extensions:
      - 'yaml'
      - 'yml'

name - это ключ. Со страницы модуля:

Имя переменной, в которую назначаются включенные переменные. Если опущен (ноль), они будут сделаны переменными верхнего уровня.

Это позволяет вам конвертировать:

vars/
    app1.yml
    app2.yml
    ...

app1.yml:

name: app1
git_repo: https://github.com/philgyford/app1.git
# ...

app2.yml:

name: app2
git_repo: https://github.com/philgyford/app2.git
# ...

Into...

apps:
  - name: app1
    git_repo: https://github.com/philgyford/app1.git
    # ...
  - name: app2
    git_repo: https://github.com/philgyford/app2.git
    # ...

Ответ 5

Хотел опубликовать возможное альтернативное решение, получив список переменных, которые соответствуют шаблону, затем вы можете просто обработать все эти переменные, сортировка вручную.

В следующем блоке кода приведен пример извлечения всех переменных, которые соответствуют определенному шаблону, и зацикливания. Вы можете установить новый факт с их объединением или просто обработать их все индивидуально.

- name: "debug2"   debug:
    msg: "value is: {{ lookup('vars', item) }} "   
  loop: "{{ hostvars[inventory_hostname] | select('match', '^linux_hosts_entries') |list  }}"

см. следующую запись для получения дополнительной информации.

Ответ 6

Если вы не хотите изменять поведение хэша по умолчанию. Я предлагаю вам мое решение. Я определяю несколько переменных (с одним и тем же регулярным выражением), когда Ineed объединяет их, я фильтрую их из hostvars. Например:

- name: Combine variables with prefix enabled_services
  debug:
    msg: "{{ hostvars[inventory_hostname].keys() | map('regex_search', 'enabled_services.*') | select('string') | list }}"