Обращения к внешним источникам данных
Плагины обращений к внешним источникам данных позволяют получить данные из внешних источников в Ansible. Как и все плагины шаблонизации, эти плагины обрабатываются на управляющей машине Ansible и могут включать чтение файловой системы, а также обращение к внешним хранилищам данных и сервисам. Эти значения затем становятся доступными с помощью стандартной системы шаблонизации Ansible и обычно используются для загрузки переменных или шаблонов с информацией из этих систем.
Примечание
Эта функция считается продвинутой, и многие пользователи, вероятно, ею не воспользуются.
Примечание
Обращения к внешним источникам данных происходят на локальном компьютере, а не на удалённом.
Примечание
Обращения к внешним источникам данных выполняются с cwd, относительным к роли или задаче, в отличие от локальных задач, которые выполняются с cwd исполняемого скрипта.
Примечание
С версии 1.9 можно передавать wantlist=True в обращения к внешним источникам данных для использования в циклах «for» шаблона Jinja2.
Предупреждение
Некоторые обращения к внешним источникам данных передают аргументы в оболочку. При использовании переменных из удалённого/ненадёжного источника используйте фильтр |quote, чтобы обеспечить безопасное использование.
Введение в обращения: Получение содержимого файла
Плагин для работы с файлами — это самый базовый тип обращения.
Содержимое можно прочитать из файловой системы следующим образом:
---
- hosts: all
vars:
contents: "{{ lookup('file', '/etc/foo.txt') }}"
tasks:
- debug: msg="the value of foo.txt is {{ contents }}"
Плагин для работы с паролями
Примечание
Отличной альтернативой плагину для работы с паролями, если вам не нужно генерировать случайные пароли для каждого хоста, будет использование Использование Vault в playbooks. Ознакомьтесь с документацией и рассмотрите возможность использования этого метода в первую очередь, он будет более желателен для большинства приложений.
password генерирует случайный текстовый пароль и сохраняет его в файл по заданному пути.
(Документация о режимах шифрования сохранения ожидается)
Если файл существует ранее, он получит его содержимое, ведя себя точно так же, как с with_file. Использование переменных, таких как «{{ inventory_hostname }}», в пути к файлу может быть использовано для настройки случайных паролей для каждого хоста (что упрощает управление паролями в переменных «host_vars»).
Особый случай — использование /dev/null в качестве пути. Плагин для работы с паролями сгенерирует новый случайный пароль каждый раз, но не запишет его в /dev/null. Это можно использовать, когда вам нужен пароль без его сохранения на контроллере.
Сгенерированные пароли содержат случайную смесь заглавных и строчных букв ASCII, цифр от 0 до 9 и знаков препинания (". , : - _"). Длина сгенерированного пароля по умолчанию составляет 20 символов. Эту длину можно изменить, передав дополнительный параметр:
---
- hosts: all
tasks:
- name: create a mysql user with a random password
mysql_user:
name: "{{ client }}"
password: "{{ lookup('password', 'credentials/' + client + '/' + tier + '/' + role + '/mysqlpassword length=15') }}"
priv: "{{ client }}_{{ tier }}_{{ role }}.*:ALL"
# (...)
Примечание
Если файл уже существует, данные в него не будут записаны. Если файл содержит данные, эти данные будут считаны как пароль. Пустые файлы приводят к тому, что пароль возвращается как пустая строка.
Предупреждение: так как это выполняется на хосте Ansible пользователем, выполняющим playbook, и «become» не применяется, целевой файл должен быть доступен для чтения пользователем playbook, или, если он не существует, у пользователя playbook должны быть достаточные привилегии для его создания. (Например, попытки записи в такие области, как /etc, завершатся ошибкой, если весь playbook не выполняется от имени root).
Начиная с версии 1.4, password принимает параметр «chars» для определения набора символов в сгенерированных паролях. Он принимает список, разделённый запятыми, имён, которые являются либо атрибутами модуля string (ascii_letters, digits и т. д.), либо используются буквально:
---
- hosts: all
tasks:
- name: create a mysql user with a random password using only ascii letters
mysql_user: name={{ client }} password="{{ lookup('password', '/tmp/passwordfile chars=ascii_letters') }}" priv={{ client }}_{{ tier }}_{{ role }}.*:ALL
- name: create a mysql user with a random password using only digits
mysql_user:
name: "{{ client }}"
password: "{{ lookup('password', '/tmp/passwordfile chars=digits') }}"
priv: "{{ client }}_{{ tier }}_{{ role }}.*:ALL"
- name: create a mysql user with a random password using many different char sets
mysql_user:
name: "{{ client }}"
password" "{{ lookup('password', '/tmp/passwordfile chars=ascii_letters,digits,hexdigits,punctuation') }}"
priv: "{{ client }}_{{ tier }}_{{ role }}.*:ALL"
# (...)
Для ввода запятой используйте две запятые «,,» где-нибудь — желательно в конце. Цитаты и двойные кавычки не поддерживаются.
Плагин для работы с хранилищем паролей
Новое в версии 2.3.
Плагин passwordstore позволяет Ansible получать, создавать или обновлять пароли из passwordstore.org pass утилиты. Он также получает ключи в формате YAML, хранящиеся в виде многострочных строк в файле паролей.
Примеры
Базовое обращение. Возникает ошибка, если example/test не существует:
password="{{ lookup('passwordstore', 'example/test')}}"
Создать пароль со случайным паролем из 16 символов. Если пароль существует, просто верните пароль:
password="{{ lookup('passwordstore', 'example/test create=true')}}"
Пароль разной длины:
password="{{ lookup('passwordstore', 'example/test create=true length=42')}}"
Создать пароль и перезаписать пароль, если он существует. Кроме того, этот модуль включает старый пароль внутри файла пароля:
password="{{ lookup('passwordstore', 'example/test create=true overwrite=true')}}"
Вернуть значение для пользователя в паре ключ-значение пользователь: имя_пользователя:
password="{{ lookup('passwordstore', 'example/test subkey=user')}}"
Вернуть всё содержимое файла пароля:
password="{{ lookup('passwordstore', 'example/test returnall=true')}}"
- Расположение каталога password-store можно указать следующими способами:
-
- По умолчанию ~/.password-store
- Можно переопределить переменной среды PASSWORD_STORE_DIR
- Можно переопределить настройкой Ansible «passwordstore: путь/к/.password-store»
- Можно переопределить аргументом «directory=путь» в вызове обращения
Плагин для работы с файлами CSV
Новое в версии 1.5.
Плагин csvfile читает содержимое файла в формате CSV (значения, разделённые запятыми). Плагин ищет строку, где первый столбец соответствует keyname, и возвращает значение во втором столбце, если не указан другой столбец.
В примере ниже показано содержимое файла CSV с именем elements.csv с информацией о периодической таблице элементов:
Symbol,Atomic Number,Atomic Mass H,1,1.008 He,2,4.0026 Li,3,6.94 Be,4,9.012 B,5,10.81
Мы можем использовать плагин csvfile для поиска атомного номера или атомного Lithium по его символу:
- debug: msg="The atomic number of Lithium is {{ lookup('csvfile', 'Li file=elements.csv delimiter=,') }}"
- debug: msg="The atomic mass of Lithium is {{ lookup('csvfile', 'Li file=elements.csv delimiter=, col=2') }}"
Плагин csvfile поддерживает несколько аргументов. Формат передачи аргументов:
lookup('csvfile', 'key arg1=val1 arg2=val2 ...')
Первое значение в аргументе — это key, которое должно быть элементом, который появляется ровно один раз в столбце 0 (первый столбец, индексированный с 0) таблицы. Все остальные аргументы необязательны.
| Поле | Значение по умолчанию | Описание |
| файл | ansible.csv | Имя загружаемого файла |
| столбец | 1 | Столбец для вывода, индексируется с 0 |
| разделитель | TAB | Разделитель, используемый в файле CSV. В качестве специального случая, табуляцию можно указать как TAB или t. |
| значение по умолчанию | пустая строка | Значение по умолчанию, если ключ отсутствует в файле CSV |
| кодировка | utf-8 | Кодировка (кодовая страница) используемого файла CSV (добавлена в версии 2.1) |
Примечание
Значение по умолчанию для разделителя — TAB, а не запятая.
Плагин для работы с файлами INI
Новое в версии 2.0.
Плагин ini читает содержимое файла в формате INI (key1=value1). Этот плагин получает значение справа от знака равенства (‘=’) в заданном разделе ([section]). Вы также можете читать файл свойств, который в этом случае не содержит раздел.
Вот простой пример файла INI с конфигурацией пользователя/пароля:
[production] # My production information user=robert pass=somerandompassword [integration] # My integration information user=gertrude pass=anotherpassword
Мы можем использовать плагин ini для поиска конфигурации пользователя:
- debug: msg="User in integration is {{ lookup('ini', 'user section=integration file=users.ini') }}"
- debug: msg="User in production is {{ lookup('ini', 'user section=production file=users.ini') }}"
Другой пример использования этого плагина — поиск значения в файле Java-свойств. Вот пример файла свойств, который мы будем использовать:
user.name=robert user.pass=somerandompassword
Вы можете получить user.name поле с помощью следующего обращения:
- debug: msg="user.name is {{ lookup('ini', 'user.name type=properties file=user.properties') }}"
Плагин ini поддерживает несколько аргументов, как и плагин для работы с файлами CSV. Формат передачи аргументов:
lookup('ini', 'key [type=<properties|ini>] [section=section] [file=file.ini] [re=true] [default=<defaultvalue>]')
Первое значение в аргументе — это key, которое должно быть элементом, который появляется ровно один раз в качестве ключа. Все остальные аргументы необязательны.
| Поле | Значение по умолчанию | Описание |
| тип | ini | Тип файла. Может быть ini или properties (для файлов свойств Java). |
| файл | ansible.ini | Имя загружаемого файла |
| раздел | global | Раздел по умолчанию, где искать ключ. |
| re | False | Ключ — это регулярное выражение. |
| кодировка | utf-8 | Кодировка текста. |
| значение по умолчанию | пустая строка | Возвращаемое значение, если ключ отсутствует в файле ini |
Примечание
В файлах свойств Java нет необходимости указывать раздел.
Плагин для работы с Credstash
Новое в версии 2.0.
Credstash — это небольшая утилита для управления секретами с помощью KMS и DynamoDB AWS: https://github.com/fugue/credstash
Сначала вам нужно сохранить секреты с помощью credstash:
credstash put my-github-password secure123 # my-github-password has been stored
Пример использования:
---
- name: "Test credstash lookup plugin -- get my github password"
debug: msg="Credstash lookup! {{ lookup('credstash', 'my-github-password') }}"
Можно указать регионы или таблицы для извлечения секретов:
---
- name: "Test credstash lookup plugin -- get my other password from us-west-1"
debug: msg="Credstash lookup! {{ lookup('credstash', 'my-other-password', region='us-west-1') }}"
- name: "Test credstash lookup plugin -- get the company's github password"
debug: msg="Credstash lookup! {{ lookup('credstash', 'company-github-password', table='company-passwords') }}"
Если вы используете функцию контекста при размещении секрета, вы можете получить его, передав словарь в параметр контекста, например так:
---
- name: test
hosts: localhost
vars:
context:
app: my_app
environment: production
tasks:
- name: "Test credstash lookup plugin -- get the password with a context passed as a variable"
debug: msg="{{ lookup('credstash', 'some-password', context=context) }}"
- name: "Test credstash lookup plugin -- get the password with a context defined here"
debug: msg="{{ lookup('credstash', 'some-password', context=dict(app='my_app', environment='production')) }}"
Если вы ещё не используете версию 2.0, вы можете сделать что-то подобное с помощью инструмента credstash и плагина для работы с конвейерами (см. ниже):
debug: msg="Poor man's credstash lookup! {{ lookup('pipe', 'credstash -r us-west-1 get my-other-password') }}"
Обращение к DNS (dig)
Новая версия 1.9.0.
Предупреждение
Этот поиск зависит от библиотеки dnspython.
Поиск dig выполняет запросы к DNS-серверам для получения записей DNS для определённого имени (FQDN — полностью квалифицированное доменное имя). Таким образом можно получить любые записи DNS.
Существует несколько различных синтаксисов для указания, какая запись должна быть получена и для какого имени. Также можно явно указать DNS-сервер(ы), которые следует использовать для поиска.
В самом простом виде плагин поиска dig может использоваться для получения IP-адреса IPv4 (запись DNS A ) для FQDN:
Примечание
Если вам нужно получить запись AAAA (IP-адрес IPv6), необходимо явно указать тип записи. Синтаксис для указания типа записи описан ниже.
Примечание
Конечная точка в большинстве приведённых примеров является необязательной, но указана для полноты и правильности.
- debug: msg="The IPv4 address for example.com. is {{ lookup('dig', 'example.com.')}}"
Помимо (по умолчанию) A записи, также можно указать другой тип записи, который должен быть запрошен. Это можно сделать, передав дополнительный параметр формата qtype=TYPE в поиск dig, или добавив /TYPE к запрашиваемому FQDN. Например:
- debug: msg="The TXT record for example.org. is {{ lookup('dig', 'example.org.', 'qtype=TXT') }}"
- debug: msg="The TXT record for example.org. is {{ lookup('dig', 'example.org./TXT') }}"
Если с запрошенной записью связаны несколько значений, результаты будут возвращены в виде списка, разделённого запятыми. В таких случаях вы можете передать параметр wantlist=True плагину, что приведет к возвращению значений записи в виде списка, по которому вы сможете итерироваться позже:
- debug: msg="One of the MX records for gmail.com. is {{ item }}"
with_items: "{{ lookup('dig', 'gmail.com./MX', wantlist=True) }}"
В случае обратного поиска DNS (PTR записи) вы также можете использовать удобный синтаксис формата IP_ADDRESS/PTR. Следующие три строки дадут тот же результат:
- debug: msg="Reverse DNS for 192.0.2.5 is {{ lookup('dig', '192.0.2.5/PTR') }}"
- debug: msg="Reverse DNS for 192.0.2.5 is {{ lookup('dig', '5.2.0.192.in-addr.arpa./PTR') }}"
- debug: msg="Reverse DNS for 192.0.2.5 is {{ lookup('dig', '5.2.0.192.in-addr.arpa.', 'qtype=PTR') }}"
По умолчанию поиск будет полагаться на настроенные в системе DNS-серверы для выполнения запроса. Также возможно явно указать DNS-серверы для запроса с помощью обозначения @DNS_SERVER_1,DNS_SERVER_2,...,DNS_SERVER_N. Это необходимо передать как дополнительный параметр поиску. Например:
- debug: msg="Querying 198.51.100.23 for IPv4 address for example.com. produces {{ lookup('dig', 'example.com', '@198.51.100.23') }}"
В некоторых случаях записи DNS могут содержать более сложную структуру данных, или может быть полезно получить результаты в виде словаря для дальнейшей обработки. Поиск dig поддерживает разбор ряда таких записей, возвращая результат в виде словаря. Таким образом, можно легко получить доступ к таким вложенным данным. Этот формат возврата можно запросить, передав опцию flat=0 поиску. Например:
- debug: msg="XMPP service for gmail.com. is available at {{ item.target }} on port {{ item.port }}"
with_items: "{{ lookup('dig', '_xmpp-server._tcp.gmail.com./SRV', 'flat=0', wantlist=True) }}"
Обратите внимание, что из-за работы поисков Ansible, вы должны передать аргумент wantlist=True поиску, иначе Ansible сообщит об ошибках.
В настоящее время поддержка словарей результатов доступна для следующих записей:
Примечание
ALL — это не запись сама по себе, а всего лишь перечисленные поля доступны для любых результатов записи, которые вы получаете в виде словаря.
| Запись | Поля |
| ALL | owner, ttl, type |
| A | address |
| AAAA | address |
| CNAME | target |
| DNAME | target |
| DLV | algorithm, digest_type, key_tag, digest |
| DNSKEY | flags, algorithm, protocol, key |
| DS | algorithm, digest_type, key_tag, digest |
| HINFO | cpu, os |
| LOC | latitude, longitude, altitude, size, horizontal_precision, vertical_precision |
| MX | preference, exchange |
| NAPTR | order, preference, flags, service, regexp, replacement |
| NS | target |
| NSEC3PARAM | algorithm, flags, iterations, salt |
| PTR | target |
| RP | mbox, txt |
| SOA | mname, rname, serial, refresh, retry, expire, minimum |
| SPF | strings |
| SRV | priority, weight, port, target |
| SSHFP | algorithm, fp_type, fingerprint |
| TLSA | usage, selector, mtype, cert |
| TXT | strings |
Поиск MongoDB
Новая версия 2.3.
Предупреждение
Этот поиск зависит от библиотеки pymongo 2.4+.
Поиск MongoDB выполняет команду find() для заданной коллекции на заданном сервере MongoDB.
Результат — список jsons, поэтому немного отличается от того, что возвращает PyMongo. В частности, временные метки преобразуются в целые числа эпохи.
В настоящее время поддерживаются следующие параметры.
| Параметр | Обязательный | Тип | Значение по умолчанию | Комментарий |
| connection_string | нет | строка | mongodb://localhost/ | Может быть любой допустимый строка подключения к MongoDB, поддерживающий аутентификацию, репликации и т.д. Более подробная информация по адресу https://docs.mongodb.org/manual/reference/connection-string/ |
| extra_connection_parameters | нет | словарь | {} | Словарь с дополнительными параметрами, такими как ssl, ssl_keyfile, maxPoolSize и т.д... Полный список см. здесь: https://api.mongodb.org/python/current/api/pymongo/mongo_client.html#pymongo.mongo_client.MongoClient |
| database | да | строка | Имя базы данных, для которой будет выполнен запрос | |
| collection | да | строка | Имя коллекции, для которой будет выполнен запрос | |
| filter | нет | словарь | [pymongo по умолчанию] | Критерии выходных данных Пример: { “hostname”: “batman” } |
| projection | нет | словарь | [pymongo по умолчанию] | Поля, которые вы хотите получить. Пример: { “pid”: True , “_id” : False , “hostname” : True } |
| skip | нет | целое число | [pymongo по умолчанию] | Сколько результатов следует пропустить |
| limit | нет | целое число | [pymongo по умолчанию] | Сколько результатов следует отобразить |
| sort | нет | список | [pymongo по умолчанию] | Правила сортировки. Обратите внимание, что константы заменены строками. [ [ “startTime” , “ASCENDING” ] , [ “age”, “DESCENDING” ] ] |
| [любой параметр find()] | нет | [любой] | [pymongo по умолчанию] | Все параметры, за исключением connection_string, database и collection, передаются pymongo напрямую. |
Для получения дополнительной информации см. https://api.mongodb.org/python/current/api/pymongo/collection.html?highlight=find#pymongo.collection.Collection.find.
Поскольку для этого метода поиска слишком много параметров, ниже приведён пример playbook, демонстрирующий его использование и хороший способ подачи параметров:
---
- hosts: all
gather_facts: false
vars:
mongodb_parameters:
#optional parameter, default = "mongodb://localhost/"
# connection_string: "mongodb://localhost/"
# extra_connection_parameters: { "ssl" : True , "ssl_certfile": /etc/self_signed_certificate.pem" }
#mandatory parameters
database: 'local'
collection: "startup_log"
#optional query parameters
#we accept any parameter from the normal mongodb query.
# the official documentation is here
# https://api.mongodb.org/python/current/api/pymongo/collection.html?highlight=find#pymongo.collection.Collection.find
# filter: { "hostname": "batman" }
projection: { "pid": True , "_id" : False , "hostname" : True }
# skip: 0
limit: 1
# sort: [ [ "startTime" , "ASCENDING" ] , [ "age", "DESCENDING" ] ]
tasks:
- debug: msg="Mongo has already started with the following PID [{{ item.pid }}]"
with_mongodb: "{{mongodb_parameters}}"
Пример выходных данных:
mdiez@batman:~/ansible$ ansible-playbook m.yml -i localhost.ini
PLAY [all] *********************************************************************
TASK [debug] *******************************************************************
Sunday 20 March 2016 22:40:39 +0200 (0:00:00.023) 0:00:00.023 **********
ok: [localhost] => (item={u'hostname': u'batman', u'pid': 60639L}) => {
"item": {
"hostname": "batman",
"pid": 60639
},
"msg": "Mongo has already started with the following PID [60639]"
}
PLAY RECAP *********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0
Sunday 20 March 2016 22:40:39 +0200 (0:00:00.067) 0:00:00.091 **********
===============================================================================
debug ------------------------------------------------------------------- 0.07s
mdiez@batman:~/ansible$
Дополнительные поиски
Различные плагины поиска позволяют дополнительные способы итерации по данным. В Циклы вы узнаете, как использовать их для обхода коллекций различных типов. Однако их также можно использовать для извлечения данных из удалённых источников, таких как команды оболочки или даже хранилища значений. В этом разделе будут рассмотрены плагины поиска в этом качестве.
Вот несколько примеров:
---
- hosts: all
tasks:
- debug: msg="{{ lookup('env','HOME') }} is an environment variable"
- name: lines will iterate over each line from stdout of a command
debug: msg="{{ item }} is a line from the result of this command"
with_lines: cat /etc/motd
- debug: msg="{{ lookup('pipe','date') }} is the raw result of running this command"
- name: Always use quote filter to make sure your variables are safe to use with shell
debug: msg="{{ lookup('pipe','getent ' + myuser|quote ) }}"
- name: Quote variables with_lines also as it executes shell
debug: msg="{{ item }} is a line from myfile"
with_lines: "cat {{myfile|quote}}"
- name: redis_kv lookup requires the Python redis package
debug: msg="{{ lookup('redis_kv', 'redis://localhost:6379,somekey') }} is value in Redis for somekey"
- name: dnstxt lookup requires the Python dnspython package
debug: msg="{{ lookup('dnstxt', 'example.com') }} is a DNS TXT record for example.com"
- debug: msg="{{ lookup('template', './some_template.j2') }} is a value from evaluation of this template"
# Since 2.4, you can pass in variables during evaluation
- debug: msg="{{ lookup('template', './some_template.j2', template_vars=dict(x=42)) }} is evaluated with x=42"
- name: loading a json file from a template as a string
debug: msg="{{ lookup('template', './some_json.json.j2', convert_data=False) }} is a value from evaluation of this template"
- debug: msg="{{ lookup('etcd', 'foo') }} is a value from a locally running etcd"
# shelvefile lookup retrieves a string value corresponding to a key inside a Python shelve file
- debug: msg="{{ lookup('shelvefile', 'file=path_to_some_shelve_file.db key=key_to_retrieve') }}
# The following lookups were added in 1.9
# url lookup splits lines by default, an option to disable this was added in 2.4
- debug: msg="{{item}}"
with_url:
- 'https://github.com/gremlin.keys'
# outputs the cartesian product of the supplied lists
- debug: msg="{{item}}"
with_cartesian:
- "{{list1}}"
- "{{list2}}"
- [1,2,3,4,5,6]
- name: Added in 2.3 allows using the system's keyring
debug: msg={{lookup('keyring','myservice myuser')}}
В качестве альтернативы вы также можете назначить плагины поиска переменным или использовать их в другом месте. Эти макросы оцениваются каждый раз, когда они используются в задаче (или шаблоне):
vars:
motd_value: "{{ lookup('file', '/etc/motd') }}"
tasks:
- debug: msg="motd value is {{ motd_value }}"
См. также
- Playbooks
- Введение в playbooks
- Условные операторы
- Условные операторы в playbooks
- Переменные
- Все о переменных
- Циклы
- Итерации в playbooks
- Список рассылки пользователей
- У вас есть вопросы? Зайдите на страницу группы 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.4/playbooks_lookups.html