Переменные
- Что делает имя переменной допустимым
- Переменные, определённые в инвентаре
- Переменные, определённые в плейбуке
- Переменные, определённые из включённых файлов и ролей
- Использование переменных: информация о Jinja2
- Фильтры Jinja2
- Подождите, проблема с YAML
- Информация, полученная от систем: факты
- Отключение фактов
- Локальные факты (Facts.d)
- Версия Ansible
- Кэширование фактов
- Зарегистрированные переменные
- Доступ к сложным данным переменных
- Магические переменные и как получить информацию об других хостах
- Разделение файлов переменных
- Передача переменных через командную строку
- Приоритет переменных: куда поместить переменную?
- Области видимости переменных
- Примеры переменных
- Расширенный синтаксис
Хотя автоматизация упрощает повторяемость задач, все системы не идентичны; некоторые могут потребовать немного отличающейся конфигурации. В некоторых случаях наблюдаемое поведение или состояние одной системы может повлиять на конфигурацию других систем. Например, вам может потребоваться узнать IP-адрес системы и использовать его как значение конфигурации на другой системе.
Ansible использует переменные для решения проблем с различиями между системами.
Для понимания переменных также следует ознакомиться с Условными операторами и Циклами. Полезные вещи, такие как модуль group_by и условный оператор when, также могут использоваться с переменными и помогают управлять различиями между системами.
Репозиторий github ansible-examples содержит множество примеров использования переменных в Ansible.
За советом по наилучшим практикам обратитесь к разделу Переменные и хранилища в главе Лучшие практики.
Что делает имя переменной допустимым
Прежде чем начать использовать переменные, важно знать, какие имена переменных являются допустимыми.
Имена переменных должны содержать буквы, цифры и символы подчеркивания. Переменные всегда должны начинаться с буквы.
foo_port — это отличное имя переменной. foo5 тоже подходит.
foo-port, foo port, foo.port и 12 — это недопустимые имена переменных.
YAML также поддерживает словари, которые сопоставляют ключи со значениями. Например:
foo: field1: one field2: two
Затем вы можете обратиться к определенному полю в словаре, используя либо обозначение с квадратными скобками, либо с точкой:
foo['field1'] foo.field1
Оба способа обратятся к одному и тому же значению («one»). Однако, если вы используете обозначение с точкой, имейте в виду, что некоторые ключи могут вызвать проблемы из-за конфликта с атрибутами и методами словарей Python. Вместо обозначения с точкой следует использовать обозначение с квадратными скобками, если вы используете ключи, начинающиеся и заканчивающиеся двумя символами подчеркивания (они зарезервированы для специальных значений в Python) или являются известными общедоступными атрибутами:
add, append, as_integer_ratio, bit_length, capitalize, center, clear, conjugate, copy, count, decode, denominator, difference, difference_update, discard, encode, endswith, expandtabs, extend, find, format, fromhex, fromkeys, get, has_key, hex, imag, index, insert, intersection, intersection_update, isalnum, isalpha, isdecimal, isdigit, isdisjoint, is_integer, islower, isnumeric, isspace, issubset, issuperset, istitle, isupper, items, iteritems, iterkeys, itervalues, join, keys, ljust, lower, lstrip, numerator, partition, pop, popitem, real, remove, replace, reverse, rfind, rindex, rjust, rpartition, rsplit, rstrip, setdefault, sort, split, splitlines, startswith, strip, swapcase, symmetric_difference, symmetric_difference_update, title, translate, union, update, upper, values, viewitems, viewkeys, viewvalues, zfill.
Переменные, определённые в инвентаре
На самом деле мы уже много говорили о переменных в другом разделе, поэтому это должно быть не слишком ново, но немного освежителя.
Часто вам потребуется задать переменные, основанные на группах машин. Например, машины в Бостоне могут использовать «boston.ntp.example.com» в качестве сервера NTP.
См. документ Работа с инвентарём для нескольких способов определения переменных в инвентаре.
Переменные, определённые в плейбуке
В плейбуке можно определять переменные непосредственно в строке, например:
- hosts: webservers
vars:
http_port: 80
Это может быть удобно, так как всё это находится прямо там, когда вы читаете плейбук.
Переменные, определённые из включённых файлов и ролей
Оказывается, мы уже говорили о переменных и в другом месте.
Как описано в Ролях, переменные также могут быть включены в плейбук с помощью файлов include, которые могут или не могут быть частью «Роли Ansible». Использование ролей предпочтительно, так как это обеспечивает хорошую систему организации.
Использование переменных: информация о Jinja2
Приятно знать, как определять переменные, но как их использовать?
Ansible позволяет ссылаться на переменные в ваших плейбуках, используя систему шаблонов Jinja2. Хотя вы можете делать много сложных вещей в Jinja, сначала вам нужно изучить только основы.
Например, в простом шаблоне можно сделать что-то вроде:
My amp goes to {{ max_amp_value }}
И это предоставит наиболее базовый вид подстановки переменных.
Это также допустимо непосредственно в плейбуках, и иногда вам захочется сделать что-то вроде:
template: src=foo.cfg.j2 dest={{ remote_install_path }}/foo.cfg
В приведённом выше примере мы использовали переменную, чтобы помочь определить местоположение файла.
Внутри шаблона вы автоматически имеете доступ ко всем переменным, которые находятся в области видимости для хоста. На самом деле это больше, чем просто это – вы также можете читать переменные об других хостах. Мы покажем, как это сделать чуть позже.
Примечание
ansible допускает циклы и условные операторы Jinja2 в шаблонах, но в плейбуках мы их не используем. Плейбуки Ansible — это чистый, разборный YAML. Это довольно важная функция, поскольку она позволяет генерировать фрагменты файлов или использовать другие инструменты экосистемы для чтения файлов Ansible. Не все это понадобится, но это может открыть новые возможности.
См. также
- Шаблоны (Jinja2)
- Дополнительная информация о шаблонах Jinja2
Фильтры Jinja2
Примечание
Эти функции используются редко. Используйте их, если они соответствуют вашему случаю использования, но это необязательные знания.
Фильтры в Jinja2 — это способ преобразования выражений шаблонов из одного типа данных в другой. Jinja2 поставляется со многими из них. См. встроенные фильтры в официальной документации по шаблонам Jinja2.
В дополнение к этим, Ansible предоставляет ещё много других. См. документ Фильтры для списка доступных фильтров и руководства по их использованию.
Подождите, проблема с YAML
Синтаксис YAML требует, что если вы начинаете значение с {{ foo }} вы должны заключить всю строку в кавычки, поскольку он хочет быть уверенным, что вы не пытаетесь начать словарь YAML. Это описано в документации Синтаксис YAML.
Это не сработает:
- hosts: app_servers
vars:
app_path: {{ base_path }}/22
Сделайте так, и всё будет в порядке:
- hosts: app_servers
vars:
app_path: "{{ base_path }}/22"
Информация, полученная от систем: Факты
Существуют и другие источники переменных, но эти являются открытыми переменными, а не задаваемыми пользователем.
Факты — это информация, полученная в результате общения с удалёнными системами.
Пример — это IP-адрес удалённого узла или операционная система.
Чтобы увидеть доступную информацию, попробуйте следующее:
ansible hostname -m setup
Это вернёт большой объём данных переменных, которые могут выглядеть следующим образом, как полученные из Ansible 1.4, работающего на системе Ubuntu 12.04
{
"ansible_all_ipv4_addresses": [
"REDACTED IP ADDRESS"
],
"ansible_all_ipv6_addresses": [
"REDACTED IPV6 ADDRESS"
],
"ansible_architecture": "x86_64",
"ansible_bios_date": "09/20/2012",
"ansible_bios_version": "6.00",
"ansible_cmdline": {
"BOOT_IMAGE": "/boot/vmlinuz-3.5.0-23-generic",
"quiet": true,
"ro": true,
"root": "UUID=4195bff4-e157-4e41-8701-e93f0aec9e22",
"splash": true
},
"ansible_date_time": {
"date": "2013-10-02",
"day": "02",
"epoch": "1380756810",
"hour": "19",
"iso8601": "2013-10-02T23:33:30Z",
"iso8601_micro": "2013-10-02T23:33:30.036070Z",
"minute": "33",
"month": "10",
"second": "30",
"time": "19:33:30",
"tz": "EDT",
"year": "2013"
},
"ansible_default_ipv4": {
"address": "REDACTED",
"alias": "eth0",
"gateway": "REDACTED",
"interface": "eth0",
"macaddress": "REDACTED",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "REDACTED",
"type": "ether"
},
"ansible_default_ipv6": {},
"ansible_devices": {
"fd0": {
"holders": [],
"host": "",
"model": null,
"partitions": {},
"removable": "1",
"rotational": "1",
"scheduler_mode": "deadline",
"sectors": "0",
"sectorsize": "512",
"size": "0.00 Bytes",
"support_discard": "0",
"vendor": null
},
"sda": {
"holders": [],
"host": "SCSI storage controller: LSI Logic / Symbios Logic 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI (rev 01)",
"model": "VMware Virtual S",
"partitions": {
"sda1": {
"sectors": "39843840",
"sectorsize": 512,
"size": "19.00 GB",
"start": "2048"
},
"sda2": {
"sectors": "2",
"sectorsize": 512,
"size": "1.00 KB",
"start": "39847934"
},
"sda5": {
"sectors": "2093056",
"sectorsize": 512,
"size": "1022.00 MB",
"start": "39847936"
}
},
"removable": "0",
"rotational": "1",
"scheduler_mode": "deadline",
"sectors": "41943040",
"sectorsize": "512",
"size": "20.00 GB",
"support_discard": "0",
"vendor": "VMware,"
},
"sr0": {
"holders": [],
"host": "IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01)",
"model": "VMware IDE CDR10",
"partitions": {},
"removable": "1",
"rotational": "1",
"scheduler_mode": "deadline",
"sectors": "2097151",
"sectorsize": "512",
"size": "1024.00 MB",
"support_discard": "0",
"vendor": "NECVMWar"
}
},
"ansible_distribution": "Ubuntu",
"ansible_distribution_release": "precise",
"ansible_distribution_version": "12.04",
"ansible_domain": "",
"ansible_env": {
"COLORTERM": "gnome-terminal",
"DISPLAY": ":0",
"HOME": "/home/mdehaan",
"LANG": "C",
"LESSCLOSE": "/usr/bin/lesspipe %s %s",
"LESSOPEN": "| /usr/bin/lesspipe %s",
"LOGNAME": "root",
"LS_COLORS": "rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:",
"MAIL": "/var/mail/root",
"OLDPWD": "/root/ansible/docsite",
"PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"PWD": "/root/ansible",
"SHELL": "/bin/bash",
"SHLVL": "1",
"SUDO_COMMAND": "/bin/bash",
"SUDO_GID": "1000",
"SUDO_UID": "1000",
"SUDO_USER": "mdehaan",
"TERM": "xterm",
"USER": "root",
"USERNAME": "root",
"XAUTHORITY": "/home/mdehaan/.Xauthority",
"_": "/usr/local/bin/ansible"
},
"ansible_eth0": {
"active": true,
"device": "eth0",
"ipv4": {
"address": "REDACTED",
"netmask": "255.255.255.0",
"network": "REDACTED"
},
"ipv6": [
{
"address": "REDACTED",
"prefix": "64",
"scope": "link"
}
],
"macaddress": "REDACTED",
"module": "e1000",
"mtu": 1500,
"type": "ether"
},
"ansible_form_factor": "Other",
"ansible_fqdn": "ubuntu2.example.com",
"ansible_hostname": "ubuntu2",
"ansible_interfaces": [
"lo",
"eth0"
],
"ansible_kernel": "3.5.0-23-generic",
"ansible_lo": {
"active": true,
"device": "lo",
"ipv4": {
"address": "127.0.0.1",
"netmask": "255.0.0.0",
"network": "127.0.0.0"
},
"ipv6": [
{
"address": "::1",
"prefix": "128",
"scope": "host"
}
],
"mtu": 16436,
"type": "loopback"
},
"ansible_lsb": {
"codename": "precise",
"description": "Ubuntu 12.04.2 LTS",
"id": "Ubuntu",
"major_release": "12",
"release": "12.04"
},
"ansible_machine": "x86_64",
"ansible_memfree_mb": 74,
"ansible_memtotal_mb": 991,
"ansible_mounts": [
{
"device": "/dev/sda1",
"fstype": "ext4",
"mount": "/",
"options": "rw,errors=remount-ro",
"size_available": 15032406016,
"size_total": 20079898624
}
],
"ansible_nodename": "ubuntu2.example.com",
"ansible_os_family": "Debian",
"ansible_pkg_mgr": "apt",
"ansible_processor": [
"Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz"
],
"ansible_processor_cores": 1,
"ansible_processor_count": 1,
"ansible_processor_threads_per_core": 1,
"ansible_processor_vcpus": 1,
"ansible_product_name": "VMware Virtual Platform",
"ansible_product_serial": "REDACTED",
"ansible_product_uuid": "REDACTED",
"ansible_product_version": "None",
"ansible_python_version": "2.7.3",
"ansible_selinux": false,
"ansible_ssh_host_key_dsa_public": "REDACTED KEY VALUE",
"ansible_ssh_host_key_ecdsa_public": "REDACTED KEY VALUE",
"ansible_ssh_host_key_rsa_public": "REDACTED KEY VALUE",
"ansible_swapfree_mb": 665,
"ansible_swaptotal_mb": 1021,
"ansible_system": "Linux",
"ansible_system_vendor": "VMware, Inc.",
"ansible_user_id": "root",
"ansible_userspace_architecture": "x86_64",
"ansible_userspace_bits": "64",
"ansible_virtualization_role": "guest",
"ansible_virtualization_type": "VMware"
}
В приведённом выше примере модель первого жёсткого диска может быть указана в шаблоне или книге задач как:
{{ ansible_devices.sda.model }}
Аналогично, имя хоста, как его сообщает система, это:
{{ ansible_nodename }}
и неполное имя хоста отображает строку перед первой точкой (.) :
{{ ansible_hostname }}
Факты часто используются в условных операторах (см. Условные операторы) и также в шаблонах.
Факты также могут использоваться для создания динамических групп узлов, соответствующих определённым критериям. Смотрите документацию по работе с модулями по group_by для получения подробностей, а также в обобщённых условных операторах, как описано в главе Условные операторы.
Отключение фактов
Если вам не нужны данные о фактах о ваших узлах и вы знаете всё о ваших системах централизованно, вы можете отключить сбор фактов. Это имеет преимущества при масштабировании Ansible в режиме push с очень большим количеством систем, или если вы используете Ansible на экспериментальных платформах. В любой книге задач просто сделайте следующее:
- hosts: whatever gather_facts: no
Локальные факты (Facts.d)
Новое в версии 1.3.
Как обсуждалось в главе о книгах задач, Ansible факты — это способ получения данных об удалённых системах для использования в переменных книги задач.
Обычно они обнаруживаются автоматически модулем setup в Ansible. Пользователи также могут писать пользовательские модули фактов, как описано в руководстве по API. Однако что, если вы хотите иметь простой способ предоставления данных, предоставляемых системой или пользователем, для использования в переменных Ansible, не создавая модуль фактов?
«Facts.d» — это один из механизмов, позволяющий пользователям контролировать некоторые аспекты управления своими системами.
Примечание
Возможно, «локальные факты» — это не совсем точное название, это означает «локально заданные значения пользователя», в отличие от «центрально заданных значений пользователя», или то, что представляют собой факты — «локально динамически определяемые значения».
Если у удалённо управляемой системы есть каталог /etc/ansible/facts.d, любые файлы в этом каталоге, заканчивающиеся на .fact, могут быть файлами JSON, INI или исполняемыми файлами, возвращающими JSON, и они могут предоставлять локальные факты в Ansible. Альтернативный каталог может быть указан с использованием ключевого слова книги задач fact_path.
Например, предположим, что /etc/ansible/facts.d/preferences.fact содержит:
[general] asdf=1 bar=2
Это создаст переменную хэш-факта с именем general с asdf и bar в качестве элементов. Для проверки выполните следующее:
ansible <hostname> -m setup -a "filter=ansible_local"
И вы увидите добавление следующего факта:
"ansible_local": {
"preferences": {
"general": {
"asdf" : "1",
"bar" : "2"
}
}
}
И к этим данным можно получить доступ в template/playbook как:
{{ ansible_local.preferences.general.asdf }}
Локальное пространство имён предотвращает переопределение фактов, заданных пользователем, фактами системы или переменными, определёнными где-либо ещё в книге задач.
Примечание
Ключевая часть в парах ключ=значение будет преобразована в нижний регистр внутри переменной ansible_local. Используя пример выше, если файл ini содержал XYZ=3 в разделе [general], то вы должны ожидать доступа к нему как: {{ ansible_local.preferences.general.xyz }} и не как {{ ansible_local.preferences.general.XYZ }}. Это связано с тем, что Ansible использует ConfigParser из Python, который пропускает все имена опций через метод optionxform, а стандартная реализация этого метода преобразует имена опций в нижний регистр.
Если у вас есть книга задач, копирующая пользовательский факт, а затем выполняющая его, явное обращение для повторного запуска модуля настройки может позволить использовать этот факт во время этой конкретной книги задач. В противном случае он будет доступен в следующей книге задач, собирающей информацию о фактах. Вот пример того, как это может выглядеть:
- hosts: webservers
tasks:
- name: create directory for ansible custom facts
file: state=directory recurse=yes path=/etc/ansible/facts.d
- name: install custom ipmi fact
copy: src=ipmi.fact dest=/etc/ansible/facts.d
- name: re-read facts after adding custom fact
setup: filter=ansible_local
В этой схеме, однако, вы также можете написать модуль фактов и можете рассмотреть этот вариант.
Версия Ansible
Новое в версии 1.8.
Для адаптации поведения книги задач к определённой версии Ansible доступна переменная ansible_version со следующей структурой:
"ansible_version": {
"full": "2.0.0.2",
"major": 2,
"minor": 0,
"revision": 0,
"string": "2.0.0.2"
}
Кэширование фактов
Новое в версии 1.8.
Как показано в других разделах документации, один сервер может ссылаться на переменные другого, например:
{{ hostvars['asdf.example.com']['ansible_os_family'] }}
Если кэширование фактов отключено, для этого Ansible должен был уже связаться с ‘asdf.example.com’ в текущей книге задач или другой книге задач выше в книге задач. Это стандартная конфигурация Ansible.
Чтобы этого избежать, Ansible 1.8 позволяет сохранять факты между запусками книг задач, но эту функцию необходимо вручную включить. Зачем это может быть полезно?
В очень большой инфраструктуре с тысячами узлов кэширование фактов можно настроить на ежедневный запуск. Конфигурация небольшой группы серверов может выполняться в режиме ad-hoc или периодически в течение дня. При включенном кэшировании фактов не будет необходимости обращаться ко всем серверам для ссылки на переменные и информацию о них.
При включенном кэшировании фактов машина в одной группе может ссылаться на переменные машин в другой группе, несмотря на то, что с ними не общались во время текущего выполнения /usr/bin/ansible-playbook.
Чтобы воспользоваться кэшированными фактами, вам необходимо изменить значение gathering на smart или explicit или установить gather_facts на False в большинстве книг задач.
В настоящее время Ansible поставляется с двумя плагинами постоянного кэша: redis и jsonfile.
Чтобы настроить кэширование фактов с помощью redis, включите его в ansible.cfg следующим образом:
[defaults] gathering = smart fact_caching = redis fact_caching_timeout = 86400 # seconds
Чтобы запустить redis, выполните эквивалентные системные команды:
yum install redis service redis start pip install redis
Обратите внимание, что библиотека Python redis должна быть установлена из pip, версия, входящая в EPEL, слишком устаревшая для использования Ansible.
В настоящее время эта функция находится на стадии бета-тестирования, и плагин Redis не поддерживает конфигурацию порта или пароля, но это ожидается в ближайшем будущем.
Чтобы настроить кэширование фактов с помощью jsonfile, включите его в ansible.cfg следующим образом:
[defaults] gathering = smart fact_caching = jsonfile fact_caching_connection = /path/to/cachedir fact_caching_timeout = 86400 # seconds
fact_caching_connection — это локальный путь к файловой системе к каталогу с правами записи (ansible попытается создать каталог, если он не существует).
fact_caching_timeout — это количество секунд для кэширования записанных фактов.
Зарегистрированные переменные
Ещё одно важное применение переменных — это выполнение команды и использование результата этой команды для сохранения результата в переменной. Результаты будут различаться в зависимости от модуля. Использование -v при выполнении книг задач покажет возможные значения результатов.
Значение выполняемой задачи в ansible можно сохранить в переменной и использовать позднее. Смотрите некоторые примеры в главе Условные операторы.
Хотя это упоминается и в другом месте в этом документе, вот быстрый пример синтаксиса:
- hosts: web_servers
tasks:
- shell: /usr/bin/foo
register: foo_result
ignore_errors: True
- shell: /usr/bin/bar
when: foo_result.rc == 5
Зарегистрированные переменные действительны на узле до конца выполнения книги задач, что соответствует жизненному циклу «фактов» в Ansible. По сути, зарегистрированные переменные такие же, как и факты.
При использовании register с циклом структура данных, помещённая в переменную во время цикла, будет содержать атрибут results, который представляет собой список всех ответов модуля. Более подробный пример того, как это работает, см. в разделе Циклы по использованию register с циклом.
Примечание
Если задача завершается сбоем или пропускается, переменная всё равно регистрируется со статусом ошибки или пропуска. Единственный способ избежать регистрации переменной — использование тегов.
Доступ к сложным данным переменных
Мы уже немного описали факты выше в документации.
Некоторые предоставленные факты, например, сетевая информация, доступны в виде вложенных структур данных. Для доступа к ним простого {{ foo }} недостаточно, но это всё равно легко сделать. Вот как мы получаем IP-адрес:
{{ ansible_eth0["ipv4"]["address"] }}
или альтернативно:
{{ ansible_eth0.ipv4.address }}
Аналогично, вот как мы получаем первый элемент массива:
{{ foo[0] }}
Магические переменные и как получить информацию об других узлах
Ansible автоматически предоставляет несколько переменных, даже если вы их не определяли. Самые важные из них — hostvars, group_names, и groups. Пользователям не следует использовать эти имена, так как они зарезервированы. environment также зарезервировано.
hostvars позволяет запрашивать переменные другого узла, включая факты, собранные об этом узле. Если вы ещё не общались с этим узлом ни в одной книге задач в книге задач или наборе книг задач, вы всё равно можете получить переменные, но не сможете увидеть факты.
Если вашему серверу базы данных нужно использовать значение «факта» с другого узла или переменную инвентаризации, присвоенную другому узлу, это легко сделать в шаблоне или даже строке действия:
{{ hostvars['test.example.com']['ansible_distribution'] }}
Кроме того, group_names — это список (массив) всех групп, к которым принадлежит текущий узел. Это можно использовать в шаблонах с синтаксисом Jinja2 для создания файлов шаблонов, которые различаются в зависимости от членства в группе (или роли) узла
{% if 'webserver' in group_names %}
# some part of a configuration file that only applies to webservers
{% endif %}
groups — это список всех групп (и узлов) в инвентаризации. Это можно использовать для перечисления всех узлов в группе. Например:
{% for host in groups['app_servers'] %}
# something that applies to all app servers.
{% endfor %}
Часто используется выражение для поиска всех IP-адресов в группе
{% for host in groups['app_servers'] %}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}
{% endfor %}
Примером может быть указание переднего прокси-сервера на все серверы приложения, настройка правильных правил брандмауэра между серверами и т. д. Однако необходимо убедиться, что данные о фактах этих хостов были заполнены, например, путем запуска игры против них, если факты не были кэшированы недавно (кэширование фактов было добавлено в Ansible 1.8).
Кроме того, inventory_hostname — это имя хоста, как оно настроено в файле инвентаризации хостов Ansible. Это может быть полезно, когда вы не хотите полагаться на обнаруженное имя хоста ansible_hostname или по другим непонятным причинам. Если у вас длинное полное доменное имя (FQDN), inventory_hostname_short также содержит часть до первого периода, без остальной части домена.
play_hosts устарел в версии 2.2, он был таким же, как новая переменная ansible_play_batch.
Новое в версии 2.2.
ansible_play_hosts — это полный список всех хостов, по-прежнему активных в текущей игре.
Новое в версии 2.2.
ansible_play_batch доступен в виде списка имен хостов, которые находятся в области действия текущей «пачки» игры. Размер пачки определяется значением serial, а если оно не установлено, он эквивалентен всей игре (что делает его таким же, как ansible_play_hosts).
Новое в версии 2.3.
ansible_playbook_python — это путь к исполняемому файлу Python, используемому для вызова командной строки Ansible.
Эти переменные могут быть полезны для заполнения шаблонов несколькими именами хостов или для вставки списка в правила балансировщика нагрузки.
Не беспокойтесь об этом, если не считаете нужным. Вы узнаете, когда вам это понадобится.
Также доступны inventory_dir — путь к каталогу, содержащему файл инвентаризации хостов Ansible, а inventory_file — путь и имя файла, указывающие на файл инвентаризации хостов Ansible.
playbook_dir содержит базовый каталог playbook.
Затем у нас есть role_path, которая вернёт текущий путь к роли (с версии 1.8). Это будет работать только внутри роли.
И, наконец, ansible_check_mode (добавлено в версии 2.1), магическая булевовая переменная, которая будет установлена в True, если вы запустите Ansible с --check.
Подробности разделения файлов переменных
Отличной идеей является размещение playbooks под управлением системы контроля версий, но вы можете сделать исходный код playbook общедоступным, сохранив при этом некоторые важные переменные конфиденциальными. Аналогично, иногда вы просто хотите сохранить определённую информацию в разных файлах, отдельно от основного playbook.
Вы можете сделать это, используя внешний файл или файлы переменных, как показано ниже:
---
- hosts: all
remote_user: root
vars:
favcolor: blue
vars_files:
- /vars/external_vars.yml
tasks:
- name: this is just a placeholder
command: /bin/echo foo
Это устраняет риск совместного использования конфиденциальных данных с другими, когда вы предоставляете им исходный код playbook.
Содержимое каждого файла переменных — это простой словарь YAML, например:
--- # in the above example, this would be vars/external_vars.yml somevar: somevalue password: magic
Примечание
Также можно хранить переменные на хост и на группу в очень похожих файлах, это рассматривается в Разделение данных, специфичных для хостов и групп.
Передача переменных в командной строке
В дополнение к vars_prompt и vars_files, можно задать переменные в командной строке, используя аргумент --extra-vars (или -e). Переменные можно определить с использованием строковой переменной в одинарных кавычках (содержащей одну или несколько переменных) с использованием одного из приведенных ниже форматов.
Формат ключевое слово=значение:
ansible-playbook release.yml --extra-vars "version=1.23.45 other_variable=foo"
Примечание
Значения, переданные с помощью синтаксиса key=value, интерпретируются как строки. Используйте формат JSON, если вам нужно передать что-либо, кроме строки (булевы значения, целые числа, числа с плавающей точкой, списки и т. д.).
Новое в версии 1.2.
Формат JSON-строки:
ansible-playbook release.yml --extra-vars '{"version":"1.23.45","other_variable":"foo"}'
ansible-playbook arcade.yml --extra-vars '{"pacman":"mrs","ghosts":["inky","pinky","clyde","sue"]}'
Новое в версии 1.3.
Формат YAML-строки:
ansible-playbook release.yml --extra-vars ' version: "1.23.45" other_variable: foo' ansible-playbook arcade.yml --extra-vars ' pacman: mrs ghosts: - inky - pinky - clyde - sue'
Новое в версии 1.3.
Переменные из файла JSON или YAML:
ansible-playbook release.yml --extra-vars "@some_file.json"
Это полезно, среди прочего, для установки группы хостов или пользователя для playbook.
Экранирование кавычек и других специальных символов:
Новое в версии 1.2.
Убедитесь, что вы правильно экранируете кавычки как в разметке (например, JSON), так и в оболочке, в которой вы работаете.:
ansible-playbook arcade.yml --extra-vars "{\"name\":\"Conan O\'Brien\"}"
ansible-playbook arcade.yml --extra-vars '{"name":"Conan O'\\\''Brien"}'
ansible-playbook script.yml --extra-vars "{\"dialog\":\"He said \\\"I just can\'t get enough of those single and double-quotes"\!"\\\"\"}"
Новое в версии 1.3.
В этих случаях, вероятно, лучше использовать файл JSON или YAML, содержащий определения переменных.
Порядок приоритета переменных Ansible
Многие задают вопрос о том, как переменные переопределяют другие. В конечном счёте, философия Ansible заключается в том, что лучше знать, куда поместить переменную, а затем вам придётся об этом думать гораздо меньше.
Избегайте определения переменной «x» в 47 местах, а затем задавайте вопрос «какая x используется». Почему? Потому что это не философия Ansible, которая заключается в том, чтобы делать всё просто.
Существует только одно здание Empire State Building. Одна Моны Лизы и т.д. Определите, куда поместить переменную, и не усложняйте.
Тем не менее, давайте рассмотрим вопрос о приоритете! Он существует. Это реальная вещь, и вам может потребоваться знать об этом.
Если несколько переменных с одинаковым именем определены в разных местах, они перезаписываются в определённом порядке.
Вот порядок приоритета от наименьшего к наибольшему (переменные, указанные последними, имеют приоритет):
- значения в командной строке (например, «-u user»)
- значения по умолчанию для роли [1]
- переменные группы из файла инвентаризации или скрипта [2]
- переменные группы group_vars/all из файла инвентаризации [3]
- переменные группы group_vars/all из playbook [3]
- переменные группы group_vars/* из файла инвентаризации [3]
- переменные группы group_vars/* из playbook [3]
- переменные хоста из файла инвентаризации или скрипта [2]
- переменные хоста host_vars/* из файла инвентаризации [3]
- переменные хоста host_vars/* из playbook [3]
- факты хоста / кэшированные установленные факты [4]
- переменные игры
- переменные игры vars_prompt
- переменные игры vars_files
- переменные роли (определённые в role/vars/main.yml)
- переменные блока (только для задач в блоке)
- переменные задачи (только для задачи)
- include_vars
- установленные факты / зарегистрированные переменные
- параметры роли (и include_role)
- параметры include
- дополнительные переменные (всегда имеют приоритет)
В принципе, всё, что попадает в «значения по умолчанию роли» (каталог defaults внутри роли), является наиболее изменчивым и легко переопределяемым. Всё в каталоге vars роли переопределяет предыдущие версии этой переменной в пространстве имён. Здесь нужно следовать идее, что чем яснее вы зададите область действия, тем больше приоритет она получает в командной строке -e дополнительные переменные всегда имеют наивысший приоритет. Переменные хоста и/или инвентаризации могут переопределять значения по умолчанию для роли, но не явные включения, такие как каталог vars или задача include_vars.
Примечания
| [1] | Задачи в каждой роли будут видеть значения по умолчанию для своей роли. Задачи, определённые вне роли, будут видеть значения по умолчанию для последней роли. |
| [2] | (1, 2) Переменные, определённые в файле инвентаризации или предоставленные динамической инвентаризацией. |
| [3] | (1, 2, 3, 4, 5, 6) Включает переменные, добавленные «плагинами переменных», а также host_vars и group_vars, которые добавляются плагином переменных по умолчанию, поставляемым с Ansible. |
| [4] | При создании с опцией кэширования set_facts переменные будут иметь высокий приоритет в игре, но будут такими же, как приоритет фактов хоста, когда они взяты из кэша. |
Примечание
В любом разделе повторное определение переменной перепишет предыдущий экземпляр. Если у нескольких групп одинаковая переменная, последняя загруженная группа побеждает. Если вы дважды определите переменную в разделе vars: игры, то вторая переменная победит.
Примечание
Предыдущее описание — это конфигурация по умолчанию hash_behaviour=replace, переключитесь на merge, чтобы частично переписать.
Примечание
Загрузка группы следует отношениям «родитель/дочерний» уровень. Группы одного и того же уровня «родитель/дочерний» затем объединяются в соответствии с алфавитным порядком. Последний может быть переопределен пользователем с помощью ansible_group_priority, по умолчанию это 1 для всех групп.
Ещё один важный момент (для всех версий) заключается в том, что переменные подключения переопределяют конфигурацию, командную строку и специфичные для игры/роли/задачи параметры и ключевые слова. Например, если ваш инвентарь указывает ansible_ssh_user: ramon и вы запустите:
ansible -u lola myhost
Это всё равно подключится как ramon, потому что значение переменной имеет приоритет (в данном случае переменная была взята из инвентаризации, но то же самое будет справедливо независимо от того, где переменная была определена).
Для игр/задач это также верно для remote_user. Предполагая ту же конфигурацию инвентаризации, следующая игра:
- hosts: myhost
tasks:
- command: I'll connect as ramon still
remote_user: lola
будет иметь значение remote_user переопределено значением ansible_ssh_user в инвентаре.
Это делается для того, чтобы настройки, специфичные для хоста, могли переопределять общие настройки. Эти переменные обычно определяются на хост или группу в инвентаре, но они ведут себя как и другие переменные.
Если вы хотите переопределить удалённого пользователя глобально (даже над инвентарем), вы можете использовать дополнительные переменные. Например, если вы запустите:
ansible... -e "ansible_user=maria" -u lola
значение lola всё ещё игнорируется, но ansible_user=maria имеет приоритет над всеми другими местами, где ansible_user (или ansible_ssh_user, или remote_user) может быть установлено.
Вы также можете переопределить как обычную переменную в пьесе:
- hosts: all
vars:
ansible_user: lola
tasks:
- command: I'll connect as lola!
Области действия переменных
Ansible имеет три основные области действия:
- Глобальная: задаётся конфигурацией, переменными среды и командной строкой
- Пьеса: каждая пьеса и вложенные структуры, записи vars (vars; vars_files; vars_prompt), значения по умолчанию роли и vars.
- Хост: переменные, непосредственно связанные с хостом, такие как инвентарь, include_vars, факты или результаты зарегистрированных задач
Примеры переменных
Давайте рассмотрим некоторые примеры и то, где следует поместить переменную, основываясь на желаемом уровне контроля над значениями.Прежде всего, групповые переменные мощные.
Общие значения по умолчанию для всего сайта должны быть определены как group_vars/all настройка. Групповые переменные обычно размещаются рядом с файлом инвентаризации. Их также можно вернуть с помощью динамического скрипта инвентаризации (см. Работа с динамическим инвентарём) или определить в таких инструментах, как Ansible Tower из пользовательского интерфейса или API:
--- # file: /etc/ansible/group_vars/all # this is the site wide default ntp_server: default-time.example.com
Региональная информация может быть определена в group_vars/region переменной. Если эта группа является дочерней группой all группы (что она и есть, так как все группы таковы), она переопределит группу, расположенную выше и имеющую более общий характер:
--- # file: /etc/ansible/group_vars/boston ntp_server: boston-time.example.com
Если по какой-то причине мы захотим указать конкретному хосту использовать определённый сервер NTP, он переопределит групповую переменную!:
--- # file: /etc/ansible/host_vars/xyz.boston.example.com ntp_server: override.example.com
Таким образом, мы рассмотрели инвентарь и то, что обычно устанавливается там. Это отличное место для вещей, связанных с географией или поведением. Поскольку группы часто являются сущностью, на которую назначаются роли на хосты, иногда бывает удобно задавать переменные в группе вместо их определения в роли. Вы можете поступить так или иначе.
Запомните: дочерние группы переопределяют родительские группы, а хосты всегда переопределяют свои группы.
Далее: изучение порядка приоритета переменных роли.
Мы предположим, что вы в настоящее время используете роли. Вы определённо должны использовать роли. Роли отличные. Вы используете роли, не так ли? Намек, намек.
Если вы пишете перераспределяемую роль с разумными значениями по умолчанию, поместите их в roles/x/defaults/main.yml файл. Это означает, что роль принесёт значение по умолчанию, но ЛЮБОЕ значение в Ansible переопределит его. См. Роли для получения дополнительной информации об этом:
--- # file: roles/x/defaults/main.yml # if not overridden in inventory or as a parameter, this is the value that will be used http_port: 80
Если вы пишете роль и хотите гарантировать, что значение в роли будет абсолютно использоваться в этой роли и не будет переопределено инвентарём, вы должны поместить его в roles/x/vars/main.yml следующим образом, и значения инвентаря не смогут его переопределить. -e однако, всё ещё может:
--- # file: roles/x/vars/main.yml # this will absolutely be used in this role http_port: 80
Это один из способов включения констант о роли, которые всегда верны. Если вы не делитесь своей ролью с другими, поведение, специфичное для приложения, например, порты, можно разместить здесь. Но если вы делитесь ролями с другими, размещение переменных здесь может быть неудачным. Никто не сможет их переопределить с помощью инвентаря, но они всё ещё могут, передав параметр роли.
Параметризованные роли полезны.
Если вы используете роль и хотите переопределить значение по умолчанию, передайте его как параметр роли следующим образом:
roles:
- role: apache
vars:
http_port: 8080
Это делает понятным для читателя книги задач, что вы сознательно выбрали переопределение некоторого значения по умолчанию в роли или передали некоторую конфигурацию, которую роль не может предположить сама. Это также позволяет вам передать что-то специфичное для сайта, что не является частью роли, которой вы делитесь с другими.
Это часто используется для вещей, которые могут применяться к нескольким хостам многократно. Например:
roles:
- role: app_user
vars:
myname: Ian
- role: app_user
vars:
myname: Terry
- role: app_user
vars:
myname: Graham
- role: app_user
vars:
myname: John
В этом примере роль вызывалась несколько раз. Вероятно, значение по умолчанию для name вообще не было предоставлено. Ansible может предупредить вас, когда переменные не определены — это, по сути, стандартное поведение.
Существуют и другие аспекты работы с ролями.
Как правило, переменные, установленные в одной роли, доступны другим. Это означает, что если у вас есть roles/common/vars/main.yml , вы можете установить переменные там и использовать их в других ролях и в других частях книги задач:
roles:
- role: common_settings
- role: something
vars:
foo: 12
- role: something_else
Примечание
Существуют определённые средства защиты, чтобы избежать необходимости именования переменных. В приведенном выше примере, переменные, определённые в common_settings, однозначно доступны задачам «something» и «something_else», но если гарантировано, что у «something» установлено значение foo как 12, даже если где-то глубоко в common settings оно установлено как 20.
Итак, это порядок приоритета, объяснённый более прямо. Не беспокойтесь о порядке приоритета, просто подумайте, определяет ли ваша роль переменную, которая является значением по умолчанию, или «живой» переменной, которую вы однозначно хотите использовать. Инвентарь занимает место в порядке приоритета прямо посередине, а если вы хотите принудительно переопределить что-то, используйте -e.
Если вам показалось это немного сложно понять, взгляните на репозиторий ansible-examples на нашем GitHub, чтобы получить дополнительную информацию о том, как всё это может работать вместе.
Расширенный синтаксис
Дополнительную информацию о расширенном синтаксисе YAML, используемом для объявления переменных и более точного управления данными, помещаемыми в файлы YAML, используемые Ansible, см. в разделе Расширенный синтаксис.
См. также
- Работа с книгами задач
- Введение в книги задач
- Условные операторы
- Условные операторы в книгах задач
- Фильтры
- Фильтры Jinja2 и их применение
- Циклы
- Циклы в книгах задач
- Роли
- Организация книги задач по ролям
- Рекомендации по наилучшей практике
- Рекомендации по наилучшей практике в книгах задач
- Список рассылки пользователей
- У вас есть вопросы? Загляните в группу Google!
- irc.freenode.net
- #ansible IRC чат-канал
© 2012–2018 Michael DeHaan
© 2018–2019 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/ansible/2.6/user_guide/playbooks_variables.html