Spec-Zone.ru › Ansible 2.8

Фильтры

  • Фильтры для форматирования данных
  • Принудительное определение переменных
  • Установление значения по умолчанию для неопределённых переменных
  • Исключение параметров
  • Фильтры для списков
  • Фильтры теории множеств
  • Фильтр для словарей
  • Фильтр items2dict
  • Фильтры zip и zip_longest
  • Фильтр subelements
  • Фильтр случайного MAC-адреса
  • Фильтр случайного числа
  • Фильтр перемешивания
  • Математика
  • Фильтр JSON-запроса
  • Фильтр IP-адреса
  • Фильтры сетевого CLI
  • Фильтры сетевого XML
  • Фильтры хэширования
  • Объединение хэшей/словаря
  • Извлечение значений из контейнеров
  • Фильтр комментариев
  • Фильтр разделения URL
  • Фильтры регулярных выражений
  • Фильтры Kubernetes
  • Другие полезные фильтры
  • Фильтры комбинирования
  • Фильтры продукции
  • Фильтры отладки
  • Утверждения теории вычислений
  • Для чтения человеком
  • Человеко-читаемый в байты

Фильтры в Ansible взяты из Jinja2 и используются для преобразования данных внутри выражения шаблона. Jinja2 поставляется со многими фильтрами. См. встроенные фильтры в официальной документации шаблонов Jinja2.

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

Помимо предоставленных Jinja2, Ansible поставляется со своими собственными и позволяет пользователям добавлять свои собственные пользовательские фильтры.

Фильтры для форматирования данных

Следующие фильтры примут структуру данных в шаблоне и отобразят её в немного другом формате. Эти фильтры иногда полезны для отладки:

{{ some_variable | to_json }}
{{ some_variable | to_yaml }}

Для вывода в формате, читаемом человеком, можно использовать:

{{ some_variable | to_nice_json }}
{{ some_variable | to_nice_yaml }}

Также можно изменить отступы обоих (ново в версии 2.2):

{{ some_variable | to_nice_json(indent=2) }}
{{ some_variable | to_nice_yaml(indent=8) }}

to_yaml и to_nice_yaml фильтры используют библиотеку PyYAML, которая имеет предельную длину строки в 80 символов по умолчанию. Это приводит к неожиданному переносу строки после 80-го символа (если после 80-го символа есть пробел). Чтобы избежать такого поведения и генерировать длинные строки, можно использовать width параметр:

{{ some_variable | to_yaml(indent=8, width=1337) }}
{{ some_variable | to_nice_yaml(indent=8, width=1337) }}

Хотя было бы лучше использовать конструкцию вроде float("inf"), а не жёстко заданное число, к сожалению, этот фильтр не поддерживает проксирование функций Python. Обратите внимание, что он также поддерживает передачу других параметров YAML. Полный список можно найти в документации PyYAML.

В качестве альтернативы, вы можете читать уже отформатированные данные:

{{ some_variable | from_json }}
{{ some_variable | from_yaml }}

например:

tasks:
  - shell: cat /some/path/to/file.json
    register: result

  - set_fact:
      myvar: "{{ result.stdout | from_json }}"

Новое в версии 2.7.

Для разбора многодокументных строк YAML предоставляется фильтр from_yaml_all. Фильтр from_yaml_all вернёт генератор обработанных документов YAML.

например:

tasks:
  - shell: cat /some/path/to/multidoc-file.yaml
    register: result
  - debug:
      msg: '{{ item }}'
    loop: '{{ result.stdout | from_yaml_all | list }}'

Принудительное определение переменных

По умолчанию Ansible и ansible.cfg вызывают ошибку, если переменные не определены, но вы можете это отключить.

Это позволяет выполнить явную проверку с выключенным этим параметром:

{{ variable | mandatory }}

Значение переменной будет использовано как есть, но оценка шаблона вызовет ошибку, если она не определена.

Установление значения по умолчанию для неопределённых переменных

Jinja2 предоставляет полезный фильтр «default», который часто является лучшим подходом к обработке случаев, когда переменная не определена:

{{ some_variable | default(5) }}

В приведенном выше примере, если переменная «some_variable» не определена, будет использовано значение 5, а не вызов ошибки.

Если вам нужно использовать значение по умолчанию, когда переменные имеют ложное значение или пустую строку, нужно установить второй параметр в true:

{{ lookup('env', 'MY_USER') | default('admin', true) }}

Исключение параметров

С Ansible 1.8, можно использовать фильтр по умолчанию для исключения параметров модуля с использованием специальной переменной omit:

- name: touch files with an optional mode
  file: dest={{ item.path }} state=touch mode={{ item.mode | default(omit) }}
  loop:
    - path: /tmp/foo
    - path: /tmp/bar
    - path: /tmp/baz
      mode: "0444"

Для первых двух файлов в списке режим по умолчанию будет определяться маской umask системы, так как параметр mode= не будет передан модулю файла, в то время как для последнего файла будет получен параметр mode=0444.

Примечание

Если вы «цепочечно» добавляете дополнительные фильтры после фильтра default(omit) , вам следует сделать что-то вроде этого: “{{ foo | default(None) | some_filter or omit }}”. В этом примере значение по умолчанию None (пустое значение Python) приведёт к ошибке в последующих фильтрах, которая, в свою очередь, вызовет or omit часть логики. Использование omit таким образом очень специфично для последующих фильтров, так что будьте готовы к некоторым пробным и ошибкам, если вы делаете это.

Фильтры для списков

Все эти фильтры работают со списками переменных.

Новое в версии 1.8.

Чтобы получить минимальное значение из списка чисел:

{{ list1 | min }}

Чтобы получить максимальное значение из списка чисел:

{{ [3, 4, 2] | max }}

Новое в версии 2.5.

Разворачивание списка (то же самое, что и flatten lookup):

{{ [3, [4, 2] ] | flatten }}

Развернуть только первый уровень списка (аналогично items lookup):

{{ [3, [4, [2]] ] | flatten(levels=1) }}

Фильтры теории множеств

Все эти функции возвращают уникальное множество из множеств или списков.

Новое в версии 1.4.

Чтобы получить уникальное множество из списка:

{{ list1 | unique }}

Чтобы получить объединение двух списков:

{{ list1 | union(list2) }}

Чтобы получить пересечение двух списков (уникальный список всех элементов в обоих):

{{ list1 | intersect(list2) }}

Чтобы получить разность двух списков (элементы в первом, которых нет во втором):

{{ list1 | difference(list2) }}

Чтобы получить симметрическую разность двух списков (элементы, уникальные для каждого списка):

{{ list1 | symmetric_difference(list2) }}

Фильтр для словарей

Новое в версии 2.6.

Чтобы преобразовать словарь в список элементов, подходящий для циклов, используйте dict2items:

{{ dict | dict2items }}

Что преобразует:

tags:
  Application: payment
  Environment: dev

в:

- key: Application
  value: payment
- key: Environment
  value: dev

Новое в версии 2.8.

dict2items принимает 2 ключевых аргумента, key_name и value_name , которые позволяют настроить имена ключей для преобразования:

{{ files | dict2items(key_name='file', value_name='path') }}

Что преобразует:

files:
  users: /etc/passwd
  groups: /etc/group

в:

- file: users
  path: /etc/passwd
- file: groups
  path: /etc/group

Фильтр items2dict

Новое в версии 2.7.

Этот фильтр преобразует список словарей с двумя ключами в словарь, сопоставляя значения этих ключей в key: value пары:

{{ tags | items2dict }}

Что преобразует:

tags:
  - key: Application
    value: payment
  - key: Environment
    value: dev

в:

Application: payment
Environment: dev

Это обратное преобразование к фильтру dict2items.

items2dict принимает 2 ключевых аргумента, key_name и value_name , которые позволяют настроить имена ключей для преобразования:

{{ tags | items2dict(key_name='key', value_name='value') }}

Фильтры zip и zip_longest

Новое в версии 2.3.

Чтобы получить список, объединяющий элементы других списков, используйте zip:

- name: give me list combo of two lists
  debug:
   msg: "{{ [1,2,3,4,5] | zip(['a','b','c','d','e','f']) | list }}"

- name: give me shortest combo of two lists
  debug:
    msg: "{{ [1,2,3] | zip(['a','b','c','d','e','f']) | list }}"

Чтобы всегда исчерпать все списки, используйте zip_longest:

- name: give me longest combo of three lists , fill with X
  debug:
    msg: "{{ [1,2,3] | zip_longest(['a','b','c','d','e','f'], [21, 22, 23], fillvalue='X') | list }}"

Аналогично выводу фильтра items2dict , упомянутого выше, эти фильтры могут быть использованы для построения dict:

{{ dict(keys_list | zip(values_list)) }}

Что преобразует:

list_one:
  - one
  - two
list_two:
  - apple
  - orange

в:

one: apple
two: orange

Фильтр subelements

Новое в версии 2.7.

Создаёт произведение объекта и значений подэлементов этого объекта, аналогично subelements lookup:

{{ users | subelements('groups', skip_missing=True) }}

Что преобразует:

users:
- name: alice
  authorized:
  - /tmp/alice/onekey.pub
  - /tmp/alice/twokey.pub
  groups:
  - wheel
  - docker
- name: bob
  authorized:
  - /tmp/bob/id_rsa.pub
  groups:
  - docker

В:

-
  - name: alice
    groups:
    - wheel
    - docker
    authorized:
    - /tmp/alice/onekey.pub
    - /tmp/alice/twokey.pub
  - wheel
-
  - name: alice
    groups:
    - wheel
    - docker
    authorized:
    - /tmp/alice/onekey.pub
    - /tmp/alice/twokey.pub
  - docker
-
  - name: bob
    authorized:
    - /tmp/bob/id_rsa.pub
    groups:
    - docker
  - docker

Пример использования этого фильтра с loop:

- name: Set authorized ssh key, extracting just that data from 'users'
  authorized_key:
    user: "{{ item.0.name }}"
    key: "{{ lookup('file', item.1) }}"
  loop: "{{ users | subelements('authorized') }}"

Фильтр случайного MAC-адреса

Новое в версии 2.6.

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

Чтобы получить случайный MAC-адрес из префикса строки, начинающегося с «52:54:00»:

"{{ '52:54:00' | random_mac }}"
# => '52:54:00:ef:1c:03'

Обратите внимание, что если в строке префикса есть ошибки, фильтр выдаст ошибку.

Фильтр случайных чисел

Новое в версии 1.6.

Этот фильтр можно использовать аналогично стандартному фильтру jinja2 random (возвращающему случайный элемент из последовательности элементов), но он также может генерировать случайное число в заданном диапазоне.

Для получения случайного элемента из списка:

"{{ ['a','b','c'] | random }}"
# => 'c'

Для получения случайного числа между 0 и заданным числом:

"{{ 60 | random }} * * * * root /script/from/cron"
# => '21 * * * * root /script/from/cron'

Получение случайного числа от 0 до 100 с шагом 10:

{{ 101 | random(step=10) }}
# => 70

Получение случайного числа от 1 до 100 с шагом 10:

{{ 101 | random(1, 10) }}
# => 31
{{ 101 | random(start=1, step=10) }}
# => 51

Начиная с Ansible версии 2.3, также можно инициализировать генератор случайных чисел из заданного значения. Таким образом, можно создавать случайные, но идемпотентные числа:

"{{ 60 | random(seed=inventory_hostname) }} * * * * root /script/from/cron"

Фильтр перемешивания

Новое в версии 1.8.

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

Для получения случайного списка из существующего списка:

{{ ['a','b','c'] | shuffle }}
# => ['c','a','b']
{{ ['a','b','c'] | shuffle }}
# => ['b','c','a']

Начиная с Ansible версии 2.3, также можно выполнить перемешивание списка идемпотентно. Всё, что вам нужно, это seed.:

{{ ['a','b','c'] | shuffle(seed=inventory_hostname) }}
# => ['b','a','c']

Обратите внимание, что при использовании с элементом, не являющимся списком, он ничего не делает, в противном случае всегда возвращает список

Математические операции

Новое в версии 1.9.

Получение логарифма (по умолчанию по основанию e):

{{ myvar | log }}

Получение логарифма по основанию 10:

{{ myvar | log(10) }}

Возведение в степень 2! (или 5):

{{ myvar | pow(2) }}
{{ myvar | pow(5) }}

Квадратный корень или 5-й корень:

{{ myvar | root }}
{{ myvar | root(5) }}

Обратите внимание, что jinja2 уже предоставляет некоторые функции, такие как abs() и round().

Фильтр запроса JSON

Новое в версии 2.2.

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

Примечание

Этот фильтр построен на основе jmespath, и вы можете использовать тот же синтаксис. Примеры см. на странице jmespath examples.

Теперь давайте рассмотрим следующую структуру данных:

domain_definition:
    domain:
        cluster:
            - name: "cluster1"
            - name: "cluster2"
        server:
            - name: "server11"
              cluster: "cluster1"
              port: "8080"
            - name: "server12"
              cluster: "cluster1"
              port: "8090"
            - name: "server21"
              cluster: "cluster2"
              port: "9080"
            - name: "server22"
              cluster: "cluster2"
              port: "9090"
        library:
            - name: "lib1"
              target: "cluster1"
            - name: "lib2"
              target: "cluster2"

Для извлечения всех кластеров из этой структуры можно использовать следующий запрос:

- name: "Display all cluster names"
  debug:
    var: item
  loop: "{{ domain_definition | json_query('domain.cluster[*].name') }}"

То же самое для всех имён серверов:

- name: "Display all server names"
  debug:
    var: item
  loop: "{{ domain_definition | json_query('domain.server[*].name') }}"

Этот пример показывает порты из кластера cluster1:

- name: "Display all ports from cluster1"
  debug:
    var: item
  loop: "{{ domain_definition | json_query(server_name_cluster1_query) }}"
  vars:
    server_name_cluster1_query: "domain.server[?cluster=='cluster1'].port"

Примечание

Можно использовать переменную, чтобы сделать запрос более читаемым.

Или, как альтернативу, вывести порты в строке, разделённой запятыми:

- name: "Display all ports from cluster1 as a string"
  debug:
    msg: "{{ domain_definition | json_query('domain.server[?cluster==`cluster1`].port') | join(', ') }}"

Примечание

Здесь использование обратных кавычек для литералов предотвращает экранирование кавычек и сохраняет читабельность.

Или, используя YAML escape:

- name: "Display all ports from cluster1"
  debug:
    var: item
  loop: "{{ domain_definition | json_query('domain.server[?cluster==''cluster1''].port') }}"

Примечание

Экранирование одинарных кавычек внутри одинарных кавычек в YAML выполняется путем удвоения одинарной кавычки.

В этом примере мы получаем хэш-таблицу со всеми портами и именами кластера:

- name: "Display all server ports and names from cluster1"
  debug:
    var: item
  loop: "{{ domain_definition | json_query(server_name_cluster1_query) }}"
  vars:
    server_name_cluster1_query: "domain.server[?cluster=='cluster2'].{name: name, port: port}"

Фильтр IP-адресов

Новое в версии 1.9.

Для проверки, является ли строка допустимым IP-адресом:

{{ myvar | ipaddr }}

Также можно потребовать определенную версию протокола IP:

{{ myvar | ipv4 }}
{{ myvar | ipv6 }}

Фильтр IP-адресов также можно использовать для извлечения определенной информации из IP-адреса. Например, чтобы получить сам IP-адрес из CIDR, можно использовать:

{{ '192.0.2.1/24' | ipaddr('address') }}

Дополнительную информацию о фильтре ipaddr и полное руководство по использованию можно найти в фильтре ipaddr.

Сетевые фильтры командной строки

Новое в версии 2.4.

Для преобразования вывода команды сетевого устройства CLI в структурированный вывод JSON используйте фильтр parse_cli:

{{ output | parse_cli('path/to/spec') }}

Фильтр parse_cli загрузит файл спецификаций и передаст вывод команды через него, возвращая вывод JSON. Файл спецификаций YAML определяет, как анализировать вывод CLI.

Файл спецификаций должен быть валидным файлом YAML. Он определяет, как анализировать вывод CLI и возвращать данные JSON. Ниже приведен пример валидного файла спецификаций, который будет анализировать вывод команды show vlan.

---
vars:
  vlan:
    vlan_id: "{{ item.vlan_id }}"
    name: "{{ item.name }}"
    enabled: "{{ item.state != 'act/lshut' }}"
    state: "{{ item.state }}"

keys:
  vlans:
    value: "{{ vlan }}"
    items: "^(?P<vlan_id>\\d+)\\s+(?P<name>\\w+)\\s+(?P<state>active|act/lshut|suspended)"
  state_static:
    value: present

Файл спецификаций выше вернёт структуру данных JSON, представляющую собой список хэшей с проанализированной информацией VLAN.

Ту же команду можно проанализировать в хэш, используя директивы key и values. Вот пример того, как анализировать вывод в хэш-значение, используя ту же команду show vlan.

---
vars:
  vlan:
    key: "{{ item.vlan_id }}"
    values:
      vlan_id: "{{ item.vlan_id }}"
      name: "{{ item.name }}"
      enabled: "{{ item.state != 'act/lshut' }}"
      state: "{{ item.state }}"

keys:
  vlans:
    value: "{{ vlan }}"
    items: "^(?P<vlan_id>\\d+)\\s+(?P<name>\\w+)\\s+(?P<state>active|act/lshut|suspended)"
  state_static:
    value: present

Другой распространенный случай использования для анализа команд CLI — разбить большую команду на блоки, которые можно проанализировать. Это можно сделать, используя директивы start_block и end_block для разделения команды на блоки, которые можно проанализировать.

---
vars:
  interface:
    name: "{{ item[0].match[0] }}"
    state: "{{ item[1].state }}"
    mode: "{{ item[2].match[0] }}"

keys:
  interfaces:
    value: "{{ interface }}"
    start_block: "^Ethernet.*$"
    end_block: "^$"
    items:
      - "^(?P<name>Ethernet\\d\\/\\d*)"
      - "admin state is (?P<state>.+),"
      - "Port mode is (.+)"

Приведённый выше пример проанализирует вывод команды show interface в список хэшей.

Сетевые фильтры также поддерживают парсинг вывода команды CLI с помощью библиотеки TextFSM. Для парсинга вывода CLI с TextFSM используйте следующий фильтр:

{{ output.stdout[0] | parse_cli_textfsm('path/to/fsm') }}

Для использования фильтра TextFSM требуется установка библиотеки TextFSM.

Сетевые XML-фильтры

Новое в версии 2.5.

Для преобразования XML-вывода команды сетевого устройства в структурированный вывод JSON используйте фильтр parse_xml:

{{ output | parse_xml('path/to/spec') }}

Фильтр parse_xml загрузит файл спецификаций и передаст вывод команды, отформатированный как JSON.

Файл спецификаций должен быть валидным файлом YAML. Он определяет, как анализировать XML-вывод и возвращать данные JSON.

Ниже приведен пример валидного файла спецификаций, который будет анализировать вывод команды show vlan | display xml.

---
vars:
  vlan:
    vlan_id: "{{ item.vlan_id }}"
    name: "{{ item.name }}"
    desc: "{{ item.desc }}"
    enabled: "{{ item.state.get('inactive') != 'inactive' }}"
    state: "{% if item.state.get('inactive') == 'inactive'%} inactive {% else %} active {% endif %}"

keys:
  vlans:
    value: "{{ vlan }}"
    top: configuration/vlans/vlan
    items:
      vlan_id: vlan-id
      name: name
      desc: description
      state: ".[@inactive='inactive']"

Файл спецификаций выше вернёт структуру данных JSON, представляющую собой список хэшей с проанализированной информацией VLAN.

Ту же команду можно проанализировать в хэш, используя директивы key и values. Вот пример того, как анализировать вывод в хэш-значение, используя ту же команду show vlan | display xml.

---
vars:
  vlan:
    key: "{{ item.vlan_id }}"
    values:
        vlan_id: "{{ item.vlan_id }}"
        name: "{{ item.name }}"
        desc: "{{ item.desc }}"
        enabled: "{{ item.state.get('inactive') != 'inactive' }}"
        state: "{% if item.state.get('inactive') == 'inactive'%} inactive {% else %} active {% endif %}"

keys:
  vlans:
    value: "{{ vlan }}"
    top: configuration/vlans/vlan
    items:
      vlan_id: vlan-id
      name: name
      desc: description
      state: ".[@inactive='inactive']"

Значение top — это XPath относительно корневого узла XML. В примере XML-вывода, приведённом ниже, значение top равно configuration/vlans/vlan, что является выражением XPath относительно корневого узла (<rpc-reply>). configuration в значении top — это самый внешний контейнерный узел, а vlan — самый внутренний.

items — это словарь пар «ключ-значение», который сопоставляет пользовательские имена с выражениями XPath, выбирающими элементы. Выражение XPath относительно значения XPath, содержащегося в top. Например, vlan_id в файле спецификаций — это пользовательское имя, а его значение vlan-id — это относительное значение XPath в top.

Атрибуты XML-тегов можно извлекать с помощью выражений XPath. Значение state в спецификации — это выражение XPath, используемое для получения атрибутов тега vlan в выходном XML.

<rpc-reply>
  <configuration>
    <vlans>
      <vlan inactive="inactive">
       <name>vlan-1</name>
       <vlan-id>200</vlan-id>
       <description>This is vlan-1</description>
      </vlan>
    </vlans>
  </configuration>
</rpc-reply>

Примечание

Дополнительную информацию об поддерживаемых выражениях XPath см. на странице https://docs.python.org/2/library/xml.etree.elementtree.html#xpath-support.

Хеш-фильтры

Новое в версии 1.9.

Для получения sha1 хеша строки:

{{ 'test1' | hash('sha1') }}

Для получения md5 хеша строки:

{{ 'test1' | hash('md5') }}

Получение контрольной суммы строки:

{{ 'test2' | checksum }}

Другие хеши (зависит от платформы):

{{ 'test2' | hash('blowfish') }}

Для получения хеша пароля sha512 (случайная соль):

{{ 'passwordsaresecret' | password_hash('sha512') }}

Для получения хеша пароля sha256 с указанной солью:

{{ 'secretpassword' | password_hash('sha256', 'mysecretsalt') }}

Идемпотентный метод генерации уникальных хешей на каждой системе — использовать соль, которая остается неизменной между запусками:

{{ 'secretpassword' | password_hash('sha512', 65534 | random(seed=inventory_hostname) | string) }}

Доступные типы хешей зависят от системного мастера Ansible, ‘hash’ зависит от hashlib, password_hash зависит от passlib (https://passlib.readthedocs.io/en/stable/lib/passlib.hash.html).

Новое в версии 2.7.

Некоторые типы хешей позволяют указать параметр rounds:

{{ 'secretpassword' | password_hash('sha256', 'mysecretsalt', rounds=10000) }}

Объединение хешей/словарей

Новое в версии 2.0.

Фильтр combine позволяет объединять хеши. Например, следующее переопределяет ключи в одном хеше:

{{ {'a':1, 'b':2} | combine({'b':3}) }}

Результирующий хеш будет таким:

{'a':1, 'b':3}

Фильтр также принимает необязательный параметр recursive=True для не только переопределения ключей в первом хеше, но и рекурсивного перехода во вложенные хеши и объединения их ключей тоже

{{ {'a':{'foo':1, 'bar':2}, 'b':2} | combine({'a':{'bar':3, 'baz':4}}, recursive=True) }}

Это приведет к:

{'a':{'foo':1, 'bar':3, 'baz':4}, 'b':2}

Фильтр также может принимать несколько аргументов для объединения:

{{ a | combine(b, c, d) }}

В этом случае ключи в d переопределят ключи в c, которые переопределят ключи в b, и так далее.

Это поведение не зависит от значения параметра hash_behaviour в ansible.cfg.

Извлечение значений из контейнеров

Новое в версии 2.1.

Фильтр extract используется для отображения списка индексов в список значений из контейнера (хеш или массив):

{{ [0,2] | map('extract', ['x','y','z']) | list }}
{{ ['x','y'] | map('extract', {'x': 42, 'y': 31}) | list }}

Результаты вышеуказанных выражений будут следующими:

['x', 'z']
[42, 31]

Фильтр может принять ещё один аргумент:

{{ groups['x'] | map('extract', hostvars, 'ec2_ip_address') | list }}

Это берет список хостов в группе ‘x’, ищет их в hostvars, а затем ищет ec2_ip_address результата. Конечный результат — список IP-адресов хостов в группе ‘x’.

Третий аргумент фильтра также может быть списком для рекурсивного поиска внутри контейнера:

{{ ['a'] | map('extract', b, ['x','y']) | list }}

Это вернёт список, содержащий значение b[‘a’][‘x’][‘y’].

Фильтр комментариев

Новый в версии 2.0.

Фильтр comment позволяет форматировать текст выбранным стилем комментариев. Например, следующее:

{{ "Plain style (default)" | comment }}

выведет такой результат:

#
# Plain style (default)
#

Аналогичным образом можно применить стили для C (//...), блока C (/*...*/), Erlang (%...) и XML (<!--...-->):

{{ "C style" | comment('c') }}
{{ "C block style" | comment('cblock') }}
{{ "Erlang style" | comment('erlang') }}
{{ "XML style" | comment('xml') }}

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

{{ "My Special Case" | comment(decoration="! ") }}

что даст:

!
! My Special Case
!

Также возможно полностью настроить стиль комментария:

{{ "Custom style" | comment('plain', prefix='#######\n#', postfix='#\n#######\n   ###\n    #') }}

Что создаст следующий вывод:

#######
#
# Custom style
#
#######
   ###
    #

Фильтр также может применяться к любым переменным Ansible. Например, чтобы сделать вывод переменной ansible_managed более читабельным, мы можем изменить её определение в файле ansible.cfg на следующее:

[defaults]

ansible_managed = This file is managed by Ansible.%n
  template: {file}
  date: %Y-%m-%d %H:%M:%S
  user: {uid}
  host: {host}

а затем использовать переменную с фильтром comment:

{{ ansible_managed | comment }}

что выведет такой результат:

#
# This file is managed by Ansible.
#
# template: /home/ansible/env/dev/ansible_managed/roles/role1/templates/test.j2
# date: 2015-09-10 11:02:58
# user: ansible
# host: myhost
#

Фильтр разбиения URL

Новый в версии 2.4.

Фильтр urlsplit извлекает фрагмент, имя хоста, netloc, пароль, путь, порт, запрос, схему и имя пользователя из URL. Без аргументов возвращает словарь всех полей:

{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('hostname') }}
# => 'www.acme.com'

{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('netloc') }}
# => 'user:password@www.acme.com:9000'

{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('username') }}
# => 'user'

{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('password') }}
# => 'password'

{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('path') }}
# => '/dir/index.html'

{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('port') }}
# => '9000'

{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('scheme') }}
# => 'http'

{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('query') }}
# => 'query=term'

{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('fragment') }}
# => 'fragment'

{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit }}
# =>
#   {
#       "fragment": "fragment",
#       "hostname": "www.acme.com",
#       "netloc": "user:password@www.acme.com:9000",
#       "password": "password",
#       "path": "/dir/index.html",
#       "port": 9000,
#       "query": "query=term",
#       "scheme": "http",
#       "username": "user"
#   }

Фильтры регулярных выражений

Для поиска строки с использованием регулярного выражения используйте фильтр “regex_search”:

# search for "foo" in "foobar"
{{ 'foobar' | regex_search('(foo)') }}

# will return empty if it cannot find a match
{{ 'ansible' | regex_search('(foobar)') }}

# case insensitive search in multiline mode
{{ 'foo\nBAR' | regex_search("^bar", multiline=True, ignorecase=True) }}

Для поиска всех вхождений совпадений с регулярным выражением используйте фильтр “regex_findall”:

# Return a list of all IPv4 addresses in the string
{{ 'Some DNS servers are 8.8.8.8 and 8.8.4.4' | regex_findall('\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}\\b') }}

Для замены текста в строке с помощью регулярного выражения используйте фильтр “regex_replace”:

# convert "ansible" to "able"
{{ 'ansible' | regex_replace('^a.*i(.*)$', 'a\\1') }}

# convert "foobar" to "bar"
{{ 'foobar' | regex_replace('^f.*o(.*)$', '\\1') }}

# convert "localhost:80" to "localhost, 80" using named groups
{{ 'localhost:80' | regex_replace('^(?P<host>.+):(?P<port>\\d+)$', '\\g<host>, \\g<port>') }}

# convert "localhost:80" to "localhost"
{{ 'localhost:80' | regex_replace(':80') }}

# add "https://" prefix to each item in a list
{{ hosts | map('regex_replace', '^(.*)$', 'https://\\1') | list }}

Примечание

До версии Ansible 2.0, если фильтр “regex_replace” использовался с переменными внутри аргументов YAML (в отличие от более простых аргументов типа ‘ключ=значение’), вам нужно было экранировать обратные ссылки (например, \\1) четырьмя обратными слешами (\\\\) вместо двух (\\).

Новый в версии 2.0.

Для экранирования специальных символов внутри стандартного Python регулярного выражения используйте фильтр “regex_escape” (используя опцию re_type=’python’ по умолчанию):

# convert '^f.*o(.*)$' to '\^f\.\*o\(\.\*\)\$'
{{ '^f.*o(.*)$' | regex_escape() }}

Новый в версии 2.8.

Для экранирования специальных символов внутри POSIX базового регулярного выражения используйте фильтр “regex_escape” с опцией re_type=’posix_basic’:

# convert '^f.*o(.*)$' to '\^f\.\*o(\.\*)\$'
{{ '^f.*o(.*)$' | regex_escape('posix_basic') }}

Фильтры Kubernetes

Используйте фильтр “k8s_config_resource_name” для получения имени Kubernetes ConfigMap или Secret, включая его хэш:

{{ configmap_resource_definition | k8s_config_resource_name }}

Это можно использовать для ссылки на хэши в спецификациях Pod:

my_secret:
  kind: Secret
  name: my_secret_name

deployment_resource:
  kind: Deployment
  spec:
    template:
      spec:
        containers:
        - envFrom:
            - secretRef:
                name: {{ my_secret | k8s_config_resource_name }}

Новый в версии 2.8.

Другие полезные фильтры

Для добавления кавычек для использования в оболочке:

- shell: echo {{ string_value | quote }}

Для использования одного значения при true и другого при false (новое в версии 1.9):

{{ (name == "John") | ternary('Mr','Ms') }}

Для использования одного значения при true, одного значения при false и третьего при null (новое в версии 2.8):

{{ enabled | ternary('no shutdown', 'shutdown', omit) }}

Для конкатенации списка в строку:

{{ list | join(" ") }}

Для получения последнего имени файла, такого как ‘foo.txt’ из ‘/etc/asdf/foo.txt’:

{{ path | basename }}

Для получения последнего имени файла в пути в стиле Windows (новое в версии 2.0):

{{ path | win_basename }}

Для разделения буквы диска Windows от остальной части пути файла (новое в версии 2.0):

{{ path | win_splitdrive }}

Для получения только буквы диска Windows:

{{ path | win_splitdrive | first }}

Для получения остальной части пути без буквы диска:

{{ path | win_splitdrive | last }}

Для получения каталога из пути:

{{ path | dirname }}

Для получения каталога из пути в стиле Windows (новая версия 2.0):

{{ path | win_dirname }}

Для расширения пути, содержащего символ тильды (~) (новое в версии 1.5):

{{ path | expanduser }}

Для расширения пути, содержащего переменные среды:

{{ path | expandvars }}

Примечание

expandvars расширяет локальные переменные; использование его с удалёнными путями может привести к ошибкам.

Новый в версии 2.6.

Для получения реального пути ссылки (новое в версии 1.8):

{{ path | realpath }}

Для получения относительного пути ссылки от начальной точки (новое в версии 1.7):

{{ path | relpath('/etc') }}

Для получения корня и расширения пути или имени файла (новое в версии 2.0):

# with path == 'nginx.conf' the return would be ('nginx', '.conf')
{{ path | splitext }}

Для работы с Base64 закодированными строками:

{{ encoded | b64decode }}
{{ decoded | b64encode }}

Начиная с версии 2.6, вы можете определить тип кодирования, используемый по умолчанию utf-8:

{{ encoded | b64decode(encoding='utf-16-le') }}
{{ decoded | b64encode(encoding='utf-16-le') }}

Новый в версии 2.6.

Для создания UUID из строки (новое в версии 1.9):

{{ hostname | to_uuid }}

Для преобразования значений в определённые типы, например, когда вы вводите строку как “True” из vars_prompt, и система не понимает, что это булево значение:

- debug:
    msg: test
  when: some_string_value | bool

Новый в версии 1.6.

Для использования одного атрибута из каждого элемента в списке сложных переменных, используйте фильтр “map” (см. документацию Jinja2 map() для получения более подробной информации):

# get a comma-separated list of the mount points (e.g. "/,/mnt/stuff") on a host
{{ ansible_mounts | map(attribute='mount') | join(',') }}

Для получения объекта даты из строки используйте фильтр to_datetime (новое в версии 2.2):

# Get total amount of seconds between two dates. Default date format is %Y-%m-%d %H:%M:%S but you can pass your own format
{{ (("2016-08-14 20:00:12" | to_datetime) - ("2015-12-25" | to_datetime('%Y-%m-%d'))).total_seconds()  }}

# Get remaining seconds after delta has been calculated. NOTE: This does NOT convert years, days, hours, etc to seconds. For that, use total_seconds()
{{ (("2016-08-14 20:00:12" | to_datetime) - ("2016-08-14 18:00:00" | to_datetime)).seconds  }}
# This expression evaluates to "12" and not "132". Delta is 2 hours, 12 seconds

# get amount of days between two dates. This returns only number of days and discards remaining hours, minutes, and seconds
{{ (("2016-08-14 20:00:12" | to_datetime) - ("2015-12-25" | to_datetime('%Y-%m-%d'))).days  }}

Новый в версии 2.4.

Для форматирования даты с помощью строки (как с командой shell date), используйте фильтр “strftime”:

# Display year-month-day
{{ '%Y-%m-%d' | strftime }}

# Display hour:min:sec
{{ '%H:%M:%S' | strftime }}

# Use ansible_date_time.epoch fact
{{ '%Y-%m-%d %H:%M:%S' | strftime(ansible_date_time.epoch) }}

# Use arbitrary epoch value
{{ '%Y-%m-%d' | strftime(0) }}          # => 1970-01-01
{{ '%Y-%m-%d' | strftime(1441357287) }} # => 2015-09-04

Примечание

Чтобы получить все варианты строк, проверьте https://docs.python.org/2/library/time.html#time.strftime

Фильтры комбинаций

Новый в версии 2.3.

Этот набор фильтров возвращает список объединённых списков. Чтобы получить перестановки списка:

- name: give me largest permutations (order matters)
  debug:
    msg: "{{ [1,2,3,4,5] | permutations | list }}"

- name: give me permutations of sets of three
  debug:
    msg: "{{ [1,2,3,4,5] | permutations(3) | list }}"

Комбинации всегда требуют установленного размера:

- name: give me combinations for sets of two
  debug:
    msg: "{{ [1,2,3,4,5] | combinations(2) | list }}"

Также см. фильтры zip и zip_longest

Фильтры произведения

Фильтр product возвращает декартово произведение входных итерируемых объектов.

Это примерно эквивалентно вложенным циклам for в выражении генератора.

Например:

- name: generate multiple hostnames
  debug:
    msg: "{{ ['foo', 'bar'] | product(['com']) | map('join', '.') | join(',') }}"

Это приведет к:

{ "msg": "foo.com,bar.com" }

Фильтры отладки

Новый в версии 2.3.

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

{{ myvar | type_debug }}

Утверждения по компьютерной теории

Функции human_readable и human_to_bytes позволяют проверить ваши playbook'и, чтобы убедиться, что вы используете правильный формат размера в своих задачах — что вы предоставляете формат байтов компьютерам и формат, понятный человеку, людям.

Читабельный формат

Определяет, является ли данная строка читаемой человеком или нет.

Например:

- name: "Human Readable"
  assert:
    that:
      - '"1.00 Bytes" == 1|human_readable'
      - '"1.00 bits" == 1|human_readable(isbits=True)'
      - '"10.00 KB" == 10240|human_readable'
      - '"97.66 MB" == 102400000|human_readable'
      - '"0.10 GB" == 102400000|human_readable(unit="G")'
      - '"0.10 Gb" == 102400000|human_readable(isbits=True, unit="G")'

Это приведет к:

{ "changed": false, "msg": "All assertions passed" }

Преобразование из читаемого формата в байты

Возвращает данную строку в формате байтов.

Например:

- name: "Human to Bytes"
  assert:
    that:
      - "{{'0'|human_to_bytes}}        == 0"
      - "{{'0.1'|human_to_bytes}}      == 0"
      - "{{'0.9'|human_to_bytes}}      == 1"
      - "{{'1'|human_to_bytes}}        == 1"
      - "{{'10.00 KB'|human_to_bytes}} == 10240"
      - "{{   '11 MB'|human_to_bytes}} == 11534336"
      - "{{  '1.1 GB'|human_to_bytes}} == 1181116006"
      - "{{'10.00 Kb'|human_to_bytes(isbits=True)}} == 10240"

Это приведет к:

{ "changed": false, "msg": "All assertions passed" }

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

См. также

Работа с Playbook
Введение в playbook'и
Условные операторы
Условные операторы в playbook'ах
Использование переменных
Всё о переменных
Циклы
Циклы в playbook'ах
Роли
Организация Playbook по ролям
Рекомендации по лучшим практикам
Рекомендации по лучшим практикам в playbook'ах
Пользовательская почтовая рассылка
Есть вопрос? Обратитесь в сообщество!
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.8/user_guide/playbooks_filters.html

Spec-Zone.ru

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