Spec-Zone.ru › Ansible 2.6

Фильтры

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

Фильтры в 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) }}

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

{{ 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 }}"

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

По умолчанию в 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 можно использовать фильтр default для пропуска модульных параметров, используя специальную 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 null) приведёт к сбою последующих фильтров, что запустит часть логики 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) }}

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

{{ list1 | intersect(list2) }}

Для получения разности 2 списков (элементы в 1, которых нет во 2):

{{ list1 | difference(list2) }}

Для получения симметрической разности 2 списков (элементы, уникальные для каждого списка):

{{ list1 | symmetric_difference(list2) }}

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

Введено в версии 2.6.

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

{{ dict | dict2items }}

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

tags:
  Application: payment
  Environment: dev

в:

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

Фильтр 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
  - wheel
-
  - name: alice
    groups:
      - wheel
      - docker
    authorized:
      - /tmp/alice/onekey.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') }}"

Фильтр случайного числа

Введено в версии 1.6.

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

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

"{{ ['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 также можно инициализировать генератор случайных чисел из seed. Таким образом, вы можете создавать случайные, но идемпотентные числа:

"{{ 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']

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

Математика

Введено в версии 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.

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

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 экранирование одинарной кавычки:

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

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

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

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

Файл спецификаций должен быть валидным файлом YAML. Он определяет, как разобрать вывод командной строки и вернуть данные в формате 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

Другой распространённый случай использования для разбора команд командной строки — разбивка большой команды на блоки, которые можно разобрать. Это можно сделать, используя директивы 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 на список хешей.

Фильтры сетевых команд также поддерживают разбор вывода команды командной строки с помощью библиотеки TextFSM. Для разбора вывода командной строки с помощью 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 (http://passlib.readthedocs.io/en/stable/lib/passlib.hash.html).

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

Новое в версии 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') }}

Примечание

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

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

Для экранирования специальных символов в регулярном выражении используйте фильтр «regex_escape»:

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

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

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

- shell: echo {{ string_value | quote }}

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

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

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

{{ 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.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:

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

Новая в версии 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.

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

{{ myvar | type_debug }}

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

См. также

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

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

Spec-Zone.ru

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