Spec-Zone.ru › Ansible 2.5

Переменные

  • Что делает имя переменной допустимым
  • Переменные, определённые в инвентаре
  • Переменные, определённые в плейбуке
  • Переменные, определённые из включённых файлов и ролей
  • Использование переменных: о Jinja2
  • Фильтры Jinja2
  • Подождите, проблема с YAML
  • Информация, полученная от систем: Факты
  • Отключение Фактов
  • Локальные Факты (Facts.d)
  • Версия Ansible
  • Кэширование Фактов
  • Зарегистрированные переменные
  • Доступ к сложным данным переменных
  • Магические переменные и как получить информацию об других хостах
  • Разделение файлов переменных
  • Передача переменных в командной строке
  • Приоритет переменных: Куда поместить переменную?
  • Области переменных
  • Примеры переменных
  • Расширенный синтаксис

Хотя автоматизация упрощает повторяемость действий, все ваши системы, скорее всего, не идентичны.

В некоторых системах вы можете захотеть установить немного отличающееся поведение или конфигурацию.

Кроме того, некоторые наблюдаемые поведение или состояние удалённых систем могут потребоваться для влияния на конфигурацию этих систем. (Например, вам может потребоваться узнать IP-адрес системы и даже использовать его в качестве значения конфигурации на другой системе).

Возможно, у вас есть шаблоны для файлов конфигурации, которые в основном одинаковы, но немного различаются в зависимости от этих переменных.

Переменные в Ansible – это способ решения проблем различий между системами.

Для понимания переменных также необходимо изучить Условные операторы и Циклы. Такие полезные инструменты, как модуль group_by и условный оператор when, также могут быть использованы с переменными, чтобы помочь управлять различиями между системами.

Высоко рекомендуется ознакомиться с репозиторием ansible-examples на GitHub, чтобы увидеть множество примеров использования переменных.

Для получения рекомендаций по лучшим практикам обратитесь к разделу Переменные и хранилища в главе Лучшие практики.

Что делает имя переменной допустимым

Прежде чем начать использовать переменные, важно знать, какие имена переменных являются допустимыми.

Имена переменных должны содержать буквы, цифры и символы подчеркивания. Переменные всегда должны начинаться с буквы.

foo_port – отличная переменная. foo5 – тоже хорошо.

foo-port, foo port, foo.port и 12 – недопустимые имена переменных.

YAML также поддерживает словари, которые сопоставляют ключи со значениями. Например:

foo:
  field1: one
  field2: two

Затем вы можете обратиться к определённому полю в словаре, используя либо квадратную нотацию, либо точечную нотацию:

foo['field1']
foo.field1

Эти записи ссылаются на одно и то же значение («один»). Однако, если вы решите использовать точечную нотацию, имейте в виду, что некоторые ключи могут создавать проблемы, поскольку они конфликтуют с атрибутами и методами словарей 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

Это может быть удобно, так как переменные находятся прямо там, где вы читаете плейбук.

Переменные, определённые из включённых файлов и ролей

Оказывается, мы уже говорили о переменных и в другом месте.

Как описано в Ролях, переменные также могут быть включены в плейбук через файлы включения, которые могут или не могут быть частью «Роли Ansible». Использование ролей предпочтительнее, так как оно обеспечивает хорошую организацию.

Использование переменных: о Jinja2

Приятно знать, как определять переменные, но как их использовать?

Ansible позволяет ссылаться на переменные в ваших плейбуках, используя систему шаблонизации Jinja2. Хотя вы можете сделать много сложных вещей в Jinja2, на начальном этапе достаточно освоить основы.

Например, в простом шаблоне вы можете сделать что-то вроде:

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 использует модуль Python ConfigParser, который обрабатывает все имена параметров через метод optionxform, а по умолчанию этот метод преобразует имена параметров в нижний регистр.

Если в вашей книге задач копируется пользовательский факт, а затем выполняется его запуск, явное повторное выполнение модуля setup может позволить использовать этот факт во время этой конкретной книги задач. В противном случае он будет доступен в следующей книге задач, собирающей информацию о фактах. Вот пример того, как это может выглядеть:

- hosts: webservers
  tasks:
    - name: create directory for ansible custom facts
      file: state=directory recurse=yes path=/etc/ansible/facts.d
    - name: install custom impi 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 позволяет сохранять факты между запусками книги задач, но эту функцию необходимо включить вручную. Зачем это может быть полезно?

Представьте, например, очень большую инфраструктуру с тысячами хостов. Кэширование фактов можно настроить на еженощное выполнение, а конфигурацию небольшого набора серверов можно выполнять в любое время или периодически в течение дня. При включённом кэшировании фактов не нужно будет обращаться ко всем серверам для ссылки на переменные и информацию о них.

При включённом кэшировании фактов машина в одной группе может ссылаться на переменные машин в другой группе, несмотря на то, что с ними не было установлено соединение во время текущего выполнения /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 содержит базовый каталог сценария воспроизведения.

Затем у нас есть role_path, который вернёт текущий путь к роли (с версии 1.8). Это будет работать только внутри роли.

И, наконец, ansible_check_mode, магическая булеву переменная (добавленная в версии 2.1), которая будет установлена в значение True, если вы запустите Ansible с --check.

Подробности разделения переменных

Это отличная идея — хранить ваши сценарии воспроизведения под управлением системы контроля версий, но вы можете захотеть сделать исходный код сценария воспроизведения общедоступным, сохранив при этом некоторые важные переменные конфиденциальными. Аналогично, иногда вы просто хотите хранить определённую информацию в разных файлах, отдельно от основного сценария воспроизведения.

Вы можете сделать это, используя внешний файл или файлы переменных, как это:

---

- 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

Это снижает риск совместного использования конфиденциальных данных с другими при совместном использовании исходного кода сценария воспроизведения с ними.

Содержимое каждого файла переменных — это простой словарь YAML, например:

---
# in the above example, this would be vars/external_vars.yml
somevar: somevalue
password: magic

Примечание

Также возможно хранение переменных на хост-уровне и группе в очень похожих файлах, это описано в Разделение данных, относящихся к хосту и группе.

Передача переменных в командной строке

В дополнение к vars_prompt и vars_files, можно задавать переменные в командной строке, используя аргумент --extra-vars (или -e). Переменные можно определять с помощью строки в одинарных кавычках (содержащей одну или несколько переменных) с помощью одного из следующих форматов.

Формат key=value:

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"

Это полезно для, среди прочего, задания группы хостов или пользователя для сценария воспроизведения.

Экранирование кавычек и других специальных символов:

Новое в версии 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 в отношении совершения дел.

Существует только одно здание Эмпайр-стейт. Одна Мона Лиза и т. д. Определите, куда поместить переменную, и не усложняйте.

Однако давайте разберемся с приоритетом! Он существует. Это реальная вещь, и вам может потребоваться для этого решение.

Если несколько переменных с одинаковым именем определены в разных местах, они перезаписываются в определенном порядке.

В версии 1.x порядок приоритетов следующий (приоритет получает последняя перечисленная переменная):

  • «Значения по умолчанию роли», которые уступают приоритет всему и наиболее легко перезаписываются
  • переменные, определённые в инвентаризации
  • факты, обнаруженные о системе
  • «почти всё остальное» (переключатели командной строки, переменные в воспроизведении, включенные переменные, переменные роли и т. д.)
  • переменные подключения (ansible_user, и т. д.)
  • дополнительные переменные (-e в командной строке) всегда имеют преимущество

В версии Ansible 2.x порядок приоритетов более конкретный (приоритет получает последняя перечисленная переменная):

  • значения по умолчанию роли [1]
  • переменные файла или сценария инвентаризации, переменные группы [2]
  • переменные группы инвентаризации/все [3]
  • переменные группы сценария воспроизведения/все [3]
  • переменные группы инвентаризации/* [3]
  • переменные группы сценария воспроизведения/* [3]
  • переменные файла или сценария инвентаризации, переменные хоста [2]
  • переменные хоста инвентаризации/*
  • переменные хоста сценария воспроизведения/*
  • факты хоста / кэшированные установленные факты [4]
  • переменные хоста инвентаризации/* [3]
  • переменные хоста сценария воспроизведения/* [3]
  • факты хоста
  • переменные воспроизведения
  • переменные воспроизведения_prompt
  • переменные воспроизведения_files
  • переменные роли (определены в role/vars/main.yml)
  • переменные блока (только для задач в блоке)
  • переменные задачи (только для задачи)
  • include_vars
  • set_facts / зарегистрированные переменные
  • параметры роли (и 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_behavior=replace, переключитесь на «merge», чтобы только частично перезаписать.

Примечание

Загрузка групп следует отношениям родитель/дочерний. Затем группы на одном уровне «родитель/дочерний» объединяются в алфавитном порядке. Этот последний может быть перекрыт пользователем с помощью ansible_group_priority, который по умолчанию установлен в значение 1 для всех групп.

Ещё один важный момент (для всех версий) заключается в том, что переменные подключения переопределяют конфигурацию, командную строку и специфичные для воспроизведения/роли/задачи параметры и директивы. Например:

ansible -u lola myhost

Подключение всё равно будет как ramon, так как ansible_ssh_user установлено в значение ramon в инвентаризации для myhost. Для воспроизведений/задач это также верно для remote_user:

- hosts: myhost
  tasks:
   - command: i'll connect as ramon still
     remote_user: lola

Это делается для того, чтобы настройки, специфичные для хоста, могли переопределять общие настройки. Эти переменные обычно определяются на хост или группу в инвентаре, но они ведут себя как и другие переменные. Если вы хотите переопределить удалённого пользователя глобально (даже над инвентарём), вы можете использовать дополнительные переменные:

ansible... -e "ansible_user=<user>"

Вы также можете переопределить как обычную переменную в плейбуке:

- hosts: all
  vars:
    ansible_user: lola
  tasks:
    - command: i'll connect as lola!

Области действия переменных

Ansible имеет три основные области действия:

  • Глобальная: настраивается конфигурацией, переменными среды и командной строкой
  • Плейбук: каждый плейбук и содержащие его структуры, записи переменных (vars; vars_files; vars_prompt), значения по умолчанию ролей и переменные.
  • Хост: переменные, напрямую связанные с хостом, такие как инвентарь, 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, http_port: 8080 }

Это ясно показывает читателю плейбука, что вы сознательно выбрали переопределение некоторых значений по умолчанию в роли или передачу некоторой конфигурации, которую роль не может предположить сама. Это также позволяет передать что-то специфичное для сайта, что не является частью роли, которую вы делитесь с другими.

Это часто используется для вещей, которые могут применяться к некоторым хостам многократно. Например:

roles:
   - { role: app_user, name: Ian    }
   - { role: app_user, name: Terry  }
   - { role: app_user, name: Graham }
   - { role: app_user, name: John   }

В этом примере одна и та же роль вызывалась несколько раз. Весьма вероятно, что значение по умолчанию для «имени» вообще не было предоставлено. Ansible может предупредить вас, когда переменные не определены — это фактически поведение по умолчанию.

Есть ещё несколько моментов, связанных с ролями.

Как правило, переменные, установленные в одной роли, доступны и другим. Это означает, что если у вас есть roles/common/vars/main.yml вы можете установить переменные в нём и использовать их в других ролях и в других частях вашего плейбука:

roles:
   - { role: common_settings }
   - { role: something, foo: 12 }
   - { role: something_else }

Примечание

Существуют некоторые средства защиты, которые предотвращают необходимость именования переменных. В примере выше, переменные, определённые в common_settings, безусловно, доступны для задач «something» и «something_else», но если для «something» гарантированно установлено foo равным 12, даже если где-то глубоко в common_settings установлено foo равным 20.

Итак, это порядок приоритетов, объяснённый более прямо. Не беспокойтесь о порядке приоритетов, просто подумайте, определяет ли ваша роль переменную, которая является значением по умолчанию, или «живой» переменной, которую вы обязательно хотите использовать. Инвентарь находится в порядке приоритетов прямо посередине, а если вы хотите насильственно переопределить что-либо, используйте -e.

Если вам показалось это немного сложным для понимания, взгляните на репозиторий ansible-examples на нашем GitHub, чтобы узнать больше о том, как всё это может работать вместе.

Расширенный синтаксис

Дополнительную информацию об расширенном синтаксисе YAML, используемом для объявления переменных и более тонкого управления данными, размещаемыми в YAML-файлах, используемых Ansible, см. в Расширенном синтаксисе.

См. также

Работа с плейбуками
Введение в плейбуки
Условные операторы
Условные операторы в плейбуках
Фильтры
Фильтры Jinja2 и их применение
Циклы
Циклы в плейбуках
Роли
Организация плейбуков с помощью ролей
Рекомендации по наилучшей практике
Рекомендации по наилучшей практике в плейбуках
Список рассылки пользователей
Есть вопрос? Загляните в группу Google!
irc.freenode.net
Канал IRC чата #ansible

© 2012–2018 Michael DeHaan
© 2018–2019 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/ansible/2.5/user_guide/playbooks_variables.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API