Описание
Существует три окружения\группы - dev
, stg
и prd
. В group_vars
которых есть переменная my_var
, значение переменной разное в каждом из окружений. Так же есть группа monitoring
. Хосты из группы monitoring
не входят в любые другие группы. Роль role_name
применяется для хостов группы monitoring
, в темплейте должна подставляться переменная my_var
из каждого окружения. Нет простого способа определить эти переменные для хоста вне группы. Ниже представлен работающий метод для получения переменной из group_vars для хоста не входящего в эту группу в Ansible.
Дано
Для лучшего понимания приведу исходные данные. Структура рабочего каталога ansible (убрано все лишнее, не влияющее на реализацию задачи):
. ├── group_vars │ ├── dev │ ├── stg │ ├── prd │ └── monitoring ├── roles │ └── role_name │ ├── tasks │ │ └── main.yml │ └── templates │ └── template.j2 └── role_name.yml
Плейбук role_name.yml
:
--- - name: Deploy my_role hosts: monitoring gather_facts: True roles: - role_name
Темплейт roles/role_name/templates/template.j2
:
dev: {{ my_var from dev environment }} stg: {{ my_var from stg environment }} prd: {{ my_var from prd environment }}
Решение
В общем случае следует пользоваться таким правилом:
{{ hostvars[groups.my_group_name.0]['my_var'] }} Или так, разный синтаксис, но команды равнозначные {{ hostvars[groups['my_group_name'][0]['my_var'] }}
Но оно не будет работать, поскольку хост для которого применяется плейбук не входит в группу из которой надо взять переменную. Для запуска сбора переменных из других групп надо вставив в плейбук, перед вызовом роли, следующие строки (что в последствии необходимо сделать для каждого окружения из которого нужна переменная):
- hosts: dev name: Gather vars from DEV environment tasks: [ ]
0
из groups.my_group_name.0
говорит анзиблю брать первый элемент в массиве. В данном случае это хост внутри группы для которого определена искомая переменная. Если его убрать, то анзибл отдаст массив из списка хостов группы и сругнется примерно так:
failed: [monitoring-host] (item=template.j2) => {"changed": false, "item": "template.j2", "msg": "AnsibleUndefinedVariable: ansible.vars.hostvars.HostVars object has no element [u'dev-host-00', u'dev-host-01', u'dev-host-02', u'dev-host-03']"}
Итог
В поставленной задаче плейбук role_name.yml
должен выглядеть так:
--- - hosts: "{{ groups.dev | random }}" name: Gather vars from DEV environment tasks: [ ] - hosts: "{{ groups.stg | random }}" name: Gather vars from STG environment tasks: [ ] - hosts: "{{ groups.prd | random }}" name: Gather vars from PRD environment tasks: [ ] - name: Deploy my_role hosts: monitoring gather_facts: True roles: - role_name
где
tasks: [ ]
означает, что ни какие таски выполняться не будут, но Ansible все-равно будет собирать данные о хостах, в том числе и нужные переменные.
groups.<env> | random
сделано для ускорения собирания фактов. Данная конструкция выбирает рандомный хост из группы и собирает с него факты. Если же сделать отдельное окружение <env>
или all
, то факты будут собираться со всех хостов, входящих в эту группу или вообще со всех, соответственно, что избыточно и затратно по времени.
Специально разделил на три блока для наглядности, при желании можно использовать один с перечислением групп: - hosts: "{{ groups.dev | random }},{{ groups.stg | random }},{{ groups.prd | random }}"
В темплейте roles/role_name/templates/template.j2
заменить переменные:
dev: {{ hostvars[groups.dev.0]['my_var'] }} stg: {{ hostvars[groups.stg.0]['my_var'] }} prd: {{ hostvars[groups.prd.0]['my_var'] }}
По мотивам этого вопроса.