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