
Описание
Существует три окружения\группы - 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'] }}
По мотивам этого вопроса.