Spec-Zone.ru › Ansible 2.4

Обращения к внешним источникам данных

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

Примечание

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

Примечание

Обращения к внешним источникам данных происходят на локальном компьютере, а не на удалённом.

Примечание

Обращения к внешним источникам данных выполняются с cwd, относительным к роли или задаче, в отличие от локальных задач, которые выполняются с cwd исполняемого скрипта.

Примечание

С версии 1.9 можно передавать wantlist=True в обращения к внешним источникам данных для использования в циклах «for» шаблона Jinja2.

Предупреждение

Некоторые обращения к внешним источникам данных передают аргументы в оболочку. При использовании переменных из удалённого/ненадёжного источника используйте фильтр |quote, чтобы обеспечить безопасное использование.

  • Обращения к внешним источникам данных
    • Введение в обращения: Получение содержимого файла
    • Плагин для работы с паролями
    • Плагин для работы с хранилищем паролей
  • Примеры
    • Плагин для работы с файлами CSV
    • Плагин для работы с файлами INI
    • Плагин для работы с Credstash
    • Плагин для работы с DNS (dig)
    • Плагин для работы с MongoDB
    • Дополнительные плагины обращений

Введение в обращения: Получение содержимого файла

Плагин для работы с файлами — это самый базовый тип обращения.

Содержимое можно прочитать из файловой системы следующим образом:

---
- 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

Spec-Zone.ru

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