Способ получить переменную из group_vars для хоста не входящего в эту группу в Ansible

Автор: Admin | 02.09.2018

Описание

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

По мотивам этого вопроса.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *