Открытие переменных: факты и магические переменные
С помощью Ansible вы можете получить или открыть определенные переменные, содержащие информацию о ваших удаленных системах или самом Ansible. Переменные, относящиеся к удаленным системам, называются фактами. С помощью фактов вы можете использовать поведение или состояние одной системы в качестве конфигурации на других системах. Например, вы можете использовать IP-адрес одной системы в качестве значения конфигурации на другой системе. Переменные, относящиеся к Ansible, называются магическими переменными.
Факты Ansible
Факты Ansible — это данные, относящиеся к вашим удаленным системам, включая операционные системы, IP-адреса, подключенные файловые системы и многое другое. Вы можете получить доступ к этим данным в переменной ansible_facts. По умолчанию вы также можете получить доступ к некоторым фактам Ansible в качестве переменных верхнего уровня с префиксом ansible_. Вы можете отключить это поведение, используя настройку INJECT_FACTS_AS_VARS. Чтобы увидеть все доступные факты, добавьте эту задачу в запуск:
- name: Print all available facts
ansible.builtin.debug:
var: ansible_facts
Чтобы увидеть «сырую» информацию, собранную, выполните эту команду в командной строке:
ansible <hostname> -m ansible.builtin.setup
Факты включают большое количество данных переменных, которые могут выглядеть так:
{
"ansible_all_ipv4_addresses": [
"REDACTED IP ADDRESS"
],
"ansible_all_ipv6_addresses": [
"REDACTED IPV6 ADDRESS"
],
"ansible_apparmor": {
"status": "disabled"
},
"ansible_architecture": "x86_64",
"ansible_bios_date": "11/28/2013",
"ansible_bios_version": "4.1.5",
"ansible_cmdline": {
"BOOT_IMAGE": "/boot/vmlinuz-3.10.0-862.14.4.el7.x86_64",
"console": "ttyS0,115200",
"no_timer_check": true,
"nofb": true,
"nomodeset": true,
"ro": true,
"root": "LABEL=cloudimg-rootfs",
"vga": "normal"
},
"ansible_date_time": {
"date": "2018-10-25",
"day": "25",
"epoch": "1540469324",
"hour": "12",
"iso8601": "2018-10-25T12:08:44Z",
"iso8601_basic": "20181025T120844109754",
"iso8601_basic_short": "20181025T120844",
"iso8601_micro": "2018-10-25T12:08:44.109968Z",
"minute": "08",
"month": "10",
"second": "44",
"time": "12:08:44",
"tz": "UTC",
"tz_offset": "+0000",
"weekday": "Thursday",
"weekday_number": "4",
"weeknumber": "43",
"year": "2018"
},
"ansible_default_ipv4": {
"address": "REDACTED",
"alias": "eth0",
"broadcast": "REDACTED",
"gateway": "REDACTED",
"interface": "eth0",
"macaddress": "REDACTED",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "REDACTED",
"type": "ether"
},
"ansible_default_ipv6": {},
"ansible_device_links": {
"ids": {},
"labels": {
"xvda1": [
"cloudimg-rootfs"
],
"xvdd": [
"config-2"
]
},
"masters": {},
"uuids": {
"xvda1": [
"cac81d61-d0f8-4b47-84aa-b48798239164"
],
"xvdd": [
"2018-10-25-12-05-57-00"
]
}
},
"ansible_devices": {
"xvda": {
"holders": [],
"host": "",
"links": {
"ids": [],
"labels": [],
"masters": [],
"uuids": []
},
"model": null,
"partitions": {
"xvda1": {
"holders": [],
"links": {
"ids": [],
"labels": [
"cloudimg-rootfs"
],
"masters": [],
"uuids": [
"cac81d61-d0f8-4b47-84aa-b48798239164"
]
},
"sectors": "83883999",
"sectorsize": 512,
"size": "40.00 GB",
"start": "2048",
"uuid": "cac81d61-d0f8-4b47-84aa-b48798239164"
}
},
"removable": "0",
"rotational": "0",
"sas_address": null,
"sas_device_handle": null,
"scheduler_mode": "deadline",
"sectors": "83886080",
"sectorsize": "512",
"size": "40.00 GB",
"support_discard": "0",
"vendor": null,
"virtual": 1
},
"xvdd": {
"holders": [],
"host": "",
"links": {
"ids": [],
"labels": [
"config-2"
],
"masters": [],
"uuids": [
"2018-10-25-12-05-57-00"
]
},
"model": null,
"partitions": {},
"removable": "0",
"rotational": "0",
"sas_address": null,
"sas_device_handle": null,
"scheduler_mode": "deadline",
"sectors": "131072",
"sectorsize": "512",
"size": "64.00 MB",
"support_discard": "0",
"vendor": null,
"virtual": 1
},
"xvde": {
"holders": [],
"host": "",
"links": {
"ids": [],
"labels": [],
"masters": [],
"uuids": []
},
"model": null,
"partitions": {
"xvde1": {
"holders": [],
"links": {
"ids": [],
"labels": [],
"masters": [],
"uuids": []
},
"sectors": "167770112",
"sectorsize": 512,
"size": "80.00 GB",
"start": "2048",
"uuid": null
}
},
"removable": "0",
"rotational": "0",
"sas_address": null,
"sas_device_handle": null,
"scheduler_mode": "deadline",
"sectors": "167772160",
"sectorsize": "512",
"size": "80.00 GB",
"support_discard": "0",
"vendor": null,
"virtual": 1
}
},
"ansible_distribution": "CentOS",
"ansible_distribution_file_parsed": true,
"ansible_distribution_file_path": "/etc/redhat-release",
"ansible_distribution_file_variety": "RedHat",
"ansible_distribution_major_version": "7",
"ansible_distribution_release": "Core",
"ansible_distribution_version": "7.5.1804",
"ansible_dns": {
"nameservers": [
"127.0.0.1"
]
},
"ansible_domain": "",
"ansible_effective_group_id": 1000,
"ansible_effective_user_id": 1000,
"ansible_env": {
"HOME": "/home/zuul",
"LANG": "en_US.UTF-8",
"LESSOPEN": "||/usr/bin/lesspipe.sh %s",
"LOGNAME": "zuul",
"MAIL": "/var/mail/zuul",
"PATH": "/usr/local/bin:/usr/bin",
"PWD": "/home/zuul",
"SELINUX_LEVEL_REQUESTED": "",
"SELINUX_ROLE_REQUESTED": "",
"SELINUX_USE_CURRENT_RANGE": "",
"SHELL": "/bin/bash",
"SHLVL": "2",
"SSH_CLIENT": "REDACTED 55672 22",
"SSH_CONNECTION": "REDACTED 55672 REDACTED 22",
"USER": "zuul",
"XDG_RUNTIME_DIR": "/run/user/1000",
"XDG_SESSION_ID": "1",
"_": "/usr/bin/python2"
},
"ansible_eth0": {
"active": true,
"device": "eth0",
"ipv4": {
"address": "REDACTED",
"broadcast": "REDACTED",
"netmask": "255.255.255.0",
"network": "REDACTED"
},
"ipv6": [
{
"address": "REDACTED",
"prefix": "64",
"scope": "link"
}
],
"macaddress": "REDACTED",
"module": "xen_netfront",
"mtu": 1500,
"pciid": "vif-0",
"promisc": false,
"type": "ether"
},
"ansible_eth1": {
"active": true,
"device": "eth1",
"ipv4": {
"address": "REDACTED",
"broadcast": "REDACTED",
"netmask": "255.255.224.0",
"network": "REDACTED"
},
"ipv6": [
{
"address": "REDACTED",
"prefix": "64",
"scope": "link"
}
],
"macaddress": "REDACTED",
"module": "xen_netfront",
"mtu": 1500,
"pciid": "vif-1",
"promisc": false,
"type": "ether"
},
"ansible_fips": false,
"ansible_form_factor": "Other",
"ansible_fqdn": "centos-7-rax-dfw-0003427354",
"ansible_hostname": "centos-7-rax-dfw-0003427354",
"ansible_interfaces": [
"lo",
"eth1",
"eth0"
],
"ansible_is_chroot": false,
"ansible_kernel": "3.10.0-862.14.4.el7.x86_64",
"ansible_lo": {
"active": true,
"device": "lo",
"ipv4": {
"address": "127.0.0.1",
"broadcast": "host",
"netmask": "255.0.0.0",
"network": "127.0.0.0"
},
"ipv6": [
{
"address": "::1",
"prefix": "128",
"scope": "host"
}
],
"mtu": 65536,
"promisc": false,
"type": "loopback"
},
"ansible_local": {},
"ansible_lsb": {
"codename": "Core",
"description": "CentOS Linux release 7.5.1804 (Core)",
"id": "CentOS",
"major_release": "7",
"release": "7.5.1804"
},
"ansible_machine": "x86_64",
"ansible_machine_id": "2db133253c984c82aef2fafcce6f2bed",
"ansible_memfree_mb": 7709,
"ansible_memory_mb": {
"nocache": {
"free": 7804,
"used": 173
},
"real": {
"free": 7709,
"total": 7977,
"used": 268
},
"swap": {
"cached": 0,
"free": 0,
"total": 0,
"used": 0
}
},
"ansible_memtotal_mb": 7977,
"ansible_mounts": [
{
"block_available": 7220998,
"block_size": 4096,
"block_total": 9817227,
"block_used": 2596229,
"device": "/dev/xvda1",
"fstype": "ext4",
"inode_available": 10052341,
"inode_total": 10419200,
"inode_used": 366859,
"mount": "/",
"options": "rw,seclabel,relatime,data=ordered",
"size_available": 29577207808,
"size_total": 40211361792,
"uuid": "cac81d61-d0f8-4b47-84aa-b48798239164"
},
{
"block_available": 0,
"block_size": 2048,
"block_total": 252,
"block_used": 252,
"device": "/dev/xvdd",
"fstype": "iso9660",
"inode_available": 0,
"inode_total": 0,
"inode_used": 0,
"mount": "/mnt/config",
"options": "ro,relatime,mode=0700",
"size_available": 0,
"size_total": 516096,
"uuid": "2018-10-25-12-05-57-00"
}
],
"ansible_nodename": "centos-7-rax-dfw-0003427354",
"ansible_os_family": "RedHat",
"ansible_pkg_mgr": "yum",
"ansible_processor": [
"0",
"GenuineIntel",
"Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz",
"1",
"GenuineIntel",
"Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz",
"2",
"GenuineIntel",
"Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz",
"3",
"GenuineIntel",
"Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz",
"4",
"GenuineIntel",
"Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz",
"5",
"GenuineIntel",
"Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz",
"6",
"GenuineIntel",
"Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz",
"7",
"GenuineIntel",
"Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz"
],
"ansible_processor_cores": 8,
"ansible_processor_count": 8,
"ansible_processor_nproc": 8,
"ansible_processor_threads_per_core": 1,
"ansible_processor_vcpus": 8,
"ansible_product_name": "HVM domU",
"ansible_product_serial": "REDACTED",
"ansible_product_uuid": "REDACTED",
"ansible_product_version": "4.1.5",
"ansible_python": {
"executable": "/usr/bin/python2",
"has_sslcontext": true,
"type": "CPython",
"version": {
"major": 2,
"micro": 5,
"minor": 7,
"releaselevel": "final",
"serial": 0
},
"version_info": [
2,
7,
5,
"final",
0
]
},
"ansible_python_version": "2.7.5",
"ansible_real_group_id": 1000,
"ansible_real_user_id": 1000,
"ansible_selinux": {
"config_mode": "enforcing",
"mode": "enforcing",
"policyvers": 31,
"status": "enabled",
"type": "targeted"
},
"ansible_selinux_python_present": true,
"ansible_service_mgr": "systemd",
"ansible_ssh_host_key_ecdsa_public": "REDACTED KEY VALUE",
"ansible_ssh_host_key_ed25519_public": "REDACTED KEY VALUE",
"ansible_ssh_host_key_rsa_public": "REDACTED KEY VALUE",
"ansible_swapfree_mb": 0,
"ansible_swaptotal_mb": 0,
"ansible_system": "Linux",
"ansible_system_capabilities": [
""
],
"ansible_system_capabilities_enforced": "True",
"ansible_system_vendor": "Xen",
"ansible_uptime_seconds": 151,
"ansible_user_dir": "/home/zuul",
"ansible_user_gecos": "",
"ansible_user_gid": 1000,
"ansible_user_id": "zuul",
"ansible_user_shell": "/bin/bash",
"ansible_user_uid": 1000,
"ansible_userspace_architecture": "x86_64",
"ansible_userspace_bits": "64",
"ansible_virtualization_role": "guest",
"ansible_virtualization_type": "xen",
"gather_subset": [
"all"
],
"module_setup": true
}
Вы можете сослаться на модель первого диска в показанных выше фактах в шаблоне или книге задач как:
{{ ansible_facts['devices']['xvda']['model'] }}
Чтобы сослаться на имя хоста системы:
{{ ansible_facts['nodename'] }}
Вы можете использовать факты в условных операторах (см. Условные операторы) и также в шаблонах. Вы также можете использовать факты для создания динамических групп хостов, которые соответствуют определенным критериям, см. документацию модуля group_by module для получения подробностей.
Примечание
Поскольку ansible_date_time создается и кэшируется, когда Ansible собирает факты перед каждым запуском книги задач, он может устаревать при выполнении долгосрочных книг задач. Если ваша книга задач выполняется долго, используйте фильтр pipe (например, lookup('pipe', 'date +%Y-%m-%d.%H:%M:%S')) или now() с шаблоном Jinja 2 вместо ansible_date_time.
Требования к пакетам для сбора фактов
На некоторых дистрибутивах вы можете увидеть отсутствующие значения фактов или установленные фактами значения по умолчанию, потому что пакеты, поддерживающие сбор этих фактов, не установлены по умолчанию. Вы можете установить необходимые пакеты на ваших удаленных хостах, используя менеджер пакетов ОС. Известные зависимости включают:
- Сбор фактов сети Linux — зависит от двоичного файла
ip, обычно включенного в пакетiproute2.
Кэширование фактов
Как и зарегистрированные переменные, факты по умолчанию хранятся в памяти. Однако, в отличие от зарегистрированных переменных, факты могут собираться независимо и кэшироваться для повторного использования. С кэшированными фактами вы можете ссылаться на факты одной системы при конфигурации второй системы, даже если Ansible выполняет текущую книгу задач на второй системе первой. Например:
{{ hostvars['asdf.example.com']['ansible_facts']['os_family'] }}
Кэширование контролируется плагинами кэша. По умолчанию Ansible использует плагин кэша памяти, который хранит факты в памяти на период выполнения текущей книги задач. Чтобы сохранить факты Ansible для повторного использования, выберите другой плагин кэша. Подробнее см. Плагины кэша.
Кэширование фактов может улучшить производительность. Если вы управляете тысячами хостов, вы можете настроить кэширование фактов для выполнения в ночное время, а затем периодически управлять конфигурацией на меньшем наборе серверов в течение дня. С кэшированными фактами вы можете получить доступ к переменным и информации обо всех хостах, даже когда вы управляете только небольшим числом серверов.
Отключение фактов
По умолчанию Ansible собирает факты в начале каждого запуска. Если вам не нужно собирать факты (например, если вы знаете все о своих системах централизованно), вы можете отключить сбор фактов на уровне запуска, чтобы повысить масштабируемость. Отключение фактов может особенно улучшить производительность в режиме отправки с очень большим количеством систем или если вы используете Ansible на экспериментальных платформах. Чтобы отключить сбор фактов:
- hosts: whatever gather_facts: false
Добавление пользовательских фактов
Модуль setup в Ansible автоматически обнаруживает стандартный набор фактов о каждом хосте. Если вы хотите добавить пользовательские значения в свои факты, вы можете написать пользовательский модуль фактов, установить временные факты с помощью задачи ansible.builtin.set_fact или предоставить постоянные пользовательские факты, используя каталог facts.d.
facts.d или локальные факты
Введено в версии 1.3.
Вы можете добавить статические пользовательские факты, добавив статические файлы в facts.d, или добавить динамические факты, добавив исполняемые скрипты в facts.d. Например, вы можете добавить список всех пользователей на хосте в свои факты, создав и запустив скрипт в facts.d.
Чтобы использовать facts.d, создайте каталог /etc/ansible/facts.d на удаленном хосте или хостах. Если вы предпочитаете другой каталог, создайте его и укажите его с помощью ключевого слова fact_path для запуска. Добавьте файлы в каталог для предоставления пользовательских фактов. Все имена файлов должны оканчиваться на .fact. Файлы могут быть в формате JSON, INI или исполняемыми файлами, возвращающими JSON.
Чтобы добавить статические факты, просто добавьте файл с расширением .fact. Например, создайте /etc/ansible/facts.d/preferences.fact с этим содержимым:
[general] asdf=1 bar=2
Примечание
Убедитесь, что файл не исполняемый, так как это сломает модуль ansible.builtin.setup.
При следующем сборе фактов ваши факты будут содержать переменную хэш-фактов, названную general с asdf и bar в качестве членов. Для проверки этого выполните следующее:
ansible <hostname> -m ansible.builtin.setup -a "filter=ansible_local"
И вы увидите добавленный пользовательский факт:
{
"ansible_local": {
"preferences": {
"general": {
"asdf" : "1",
"bar" : "2"
}
}
}
}
Пространство имен ansible_local отделяет пользовательские факты, созданные в facts.d, от системных фактов или переменных, определенных в другом месте в книге задач, поэтому переменные не будут перекрывать друг друга. Вы можете получить доступ к этому пользовательскому факту в шаблоне или книге задач как:
{{ 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, и по умолчанию этот метод преобразует имена опций в нижний регистр.
Вы также можете использовать facts.d для выполнения скрипта на удаленном хосте, генерируя динамические пользовательские факты в пространство имен ansible_local. Например, вы можете сгенерировать список всех пользователей, которые существуют на удаленном хосте, как факт об этом хосте. Чтобы сгенерировать динамические пользовательские факты, используя facts.d:
- Напишите и протестируйте скрипт для генерации данных JSON, которые вы хотите.
- Сохраните скрипт в вашем каталоге facts.d.
- Убедитесь, что ваш скрипт имеет расширение
.fact. - Убедитесь, что ваш скрипт исполняем пользователем подключения Ansible.
- Соберите факты для выполнения скрипта и добавьте выход JSON в ansible_local.
По умолчанию сбор фактов выполняется один раз в начале каждого запуска. Если вы создаете пользовательский факт, используя facts.d в книге задач, он будет доступен в следующем запуске, который собирает факты. Если вы хотите использовать его в той же книге задач, где вы его создали, вы должны явно повторно запустить модуль setup. Например:
- hosts: webservers
tasks:
- name: Create directory for ansible custom facts
ansible.builtin.file:
state: directory
recurse: true
path: /etc/ansible/facts.d
- name: Install custom ipmi fact
ansible.builtin.copy:
src: ipmi.fact
dest: /etc/ansible/facts.d
- name: Re-read facts after adding custom fact
ansible.builtin.setup:
filter: ansible_local
Если вы часто используете эту схему, пользовательский модуль фактов будет более эффективным, чем facts.d.
Информация об Ansible: магические переменные
Вы можете получить доступ к информации об операциях Ansible, включая используемую версию Python, хосты и группы в инвентаре, а также директории для playbooks и ролей, используя «магические» переменные. Как и переменные подключения, магические переменные являются Специальными переменными. Имена магических переменных зарезервированы — не устанавливайте переменные с такими именами. Переменная environment также зарезервирована.
Наиболее часто используемые магические переменные — hostvars, groups, group_names, и inventory_hostname. С помощью hostvars, вы можете получить доступ к переменным, определённым для любого хоста в play, в любой точке playbook. Вы также можете получить доступ к фактам Ansible, используя переменную hostvars, но только после того, как вы собрали (или кэшировали) факты. Обратите внимание, что переменные, определенные в объектах play, не определены для конкретных хостов и, следовательно, не отображаются в hostvars.
Если вы хотите настроить свой сервер базы данных, используя значение «факта» с другого узла или значение переменной инвентаря, назначенной другому узлу, вы можете использовать hostvars в шаблоне или в строке действия:
{{ hostvars['test.example.com']['ansible_facts']['distribution'] }}
С помощью groups, списка всех групп (и хостов) в инвентаре, вы можете перечислить все хосты внутри группы. Например:
{% for host in groups['app_servers'] %}
# something that applies to all app servers.
{% endfor %}
Вы можете использовать groups и hostvars вместе, чтобы найти все IP-адреса в группе.
{% for host in groups['app_servers'] %}
{{ hostvars[host]['ansible_facts']['eth0']['ipv4']['address'] }}
{% endfor %}
Вы можете использовать этот подход для указания сервера прокси-сервера frontend на все хосты в вашей группе серверов приложений, для настройки правильных правил брандмауэра между серверами и так далее. Вам необходимо кэшировать или собирать факты для этих хостов перед задачей, которая заполняет шаблон.
С помощью group_names, списка (массива) всех групп, в которых находится текущий хост, вы можете создавать шаблонизированные файлы, которые различаются в зависимости от принадлежности хоста к группе (или роли):
{% if 'webserver' in group_names %}
# some part of a configuration file that only applies to webservers
{% endif %}
Вы можете использовать магическую переменную inventory_hostname, имя хоста, как оно настроено в вашем инвентаре, в качестве альтернативы ansible_hostname, когда сбор фактов отключен. Если у вас длинный FQDN, вы можете использовать inventory_hostname_short, который содержит часть до первой точки, без остальной части домена.
Другие полезные магические переменные относятся к текущему play или playbook. Эти переменные могут быть полезны для заполнения шаблонов несколькими именами хостов или для вставки списка в правила для балансировщика нагрузки.
ansible_play_hosts — список всех хостов, которые по-прежнему активны в текущем play.
ansible_play_batch — список имён хостов, которые находятся в области действия текущей «пачки» play.
Размер пачки определяется serial, если он не задан, он эквивалентен всему play (что делает его таким же, как ansible_play_hosts).
ansible_playbook_python — путь к исполняемому файлу Python, используемому для вызова командной строки Ansible.
inventory_dir — путь к каталогу, содержащему файл инвентаря хостов Ansible.
inventory_file — путь и имя файла, указывающие на файл инвентаря хостов Ansible.
playbook_dir содержит базовый каталог playbook.
role_path содержит путь к текущей роли и работает только внутри роли.
ansible_check_mode — булево значение, установленное в True, если вы запускаете Ansible с --check.
Версия Ansible
Новая в версии 1.8.
Для адаптации поведения playbook к различным версиям Ansible вы можете использовать переменную ansible_version, которая имеет следующую структуру:
{
"ansible_version": {
"full": "2.10.1",
"major": 2,
"minor": 10,
"revision": 1,
"string": "2.10.1"
}
}
© 2012–2018 Michael DeHaan
© 2018–2024 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_vars_facts.html