Spec-Zone.ru › Ansible

Использование фильтров для обработки данных

Фильтры позволяют преобразовать данные JSON в YAML, разбить URL для извлечения имени хоста, получить SHA1-хеш строки, сложить или перемножить целые числа и многое другое. Вы можете использовать специфичные для Ansible фильтры, описанные здесь, или любые стандартные фильтры, поставляемые с Jinja2 — см. список встроенных фильтров в официальной документации по шаблонам Jinja2. Также вы можете использовать методы Python для преобразования данных. Вы можете создавать пользовательские фильтры Ansible как плагины, хотя мы обычно приветствуем новые фильтры в репозитории ansible-core, чтобы все могли их использовать.

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

  • Обработка неопределенных переменных

    • Указание значений по умолчанию
    • Делаем переменные необязательными
    • Определение обязательных значений
  • Определение различных значений для true/false/null (тернарный)
  • Управление типами данных

    • Определение типа данных
    • Преобразование строк в списки
    • Преобразование словарей в списки
    • Преобразование списков в словари
    • Принудительное назначение типа данных
  • Форматирование данных: YAML и JSON

    • Фильтр to_json и поддержка Unicode
  • Комбинирование и выбор данных

    • Комбинирование элементов из нескольких списков: zip и zip_longest
    • Комбинирование объектов и подэлементов
    • Комбинирование хэшей/словаря
    • Выбор значений из массивов или хэштаблиц
    • Комбинирование списков

      • перестановки
      • комбинации
      • произведения
    • Выбор данных JSON: запросы JSON
  • Случайные данные

    • Случайные MAC-адреса
    • Случайные элементы или числа
    • Перемешивание списка
  • Управление переменными-списками
  • Выбор из множеств или списков (теория множеств)
  • Вычисления с числами (математика)
  • Управление сетевыми взаимодействиями

    • Фильтры IP-адресов
    • Фильтры командной строки сети
    • Фильтры XML сети
    • Фильтры VLAN сети
  • Хеширование и шифрование строк и паролей
  • Обработка текста

    • Добавление комментариев к файлам
    • Кодирование переменных в URL
    • Разделение URL-адресов
    • Поиск строк с помощью регулярных выражений
    • Управление именами файлов и путями
  • Обработка строк
  • Управление UUID
  • Работа с датами и временем
  • Получение имён ресурсов Kubernetes

Обработка неопределенных переменных

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

Указание значений по умолчанию

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

{{ some_variable | default(5) }}

В приведенном выше примере, если переменная «some_variable» не определена, Ansible использует значение по умолчанию 5, вместо того, чтобы генерировать ошибку «неопределенная переменная» и завершиться сбоем. Если вы работаете в рамках роли, вы также можете добавить значения по умолчанию для роли, чтобы определить значения по умолчанию для переменных в вашей роли. Чтобы узнать больше о значениях по умолчанию для ролей, см. Структуру каталога ролей.

Начиная с версии 2.8, попытка доступа к атрибуту неопределенного значения в Jinja вернет другое неопределенное значение, а не выбросит ошибку немедленно. Это означает, что теперь вы можете просто использовать значение по умолчанию с данными вложенной структуры данных (иными словами, {{ foo.bar.baz | default('DEFAULT') }}), когда вы не знаете, определены ли промежуточные значения.

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

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

Делаем переменные необязательными

По умолчанию Ansible требует значений для всех переменных в шаблонизированном выражении. Однако вы можете сделать определенные переменные модуля необязательными. Например, вы можете использовать системное значение по умолчанию для некоторых элементов и контролировать значение для других. Чтобы сделать переменную модуля необязательной, установите значение по умолчанию для специальной переменной omit:

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

В этом примере режим по умолчанию для файлов /tmp/foo и /tmp/bar определяется системной маской. Ansible не отправляет значение для mode. Только третий файл, /tmp/baz, получает параметр mode=0444.

Примечание

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

Определение обязательных значений

Если вы настроите Ansible на игнорирование неопределенных переменных, вы можете захотеть определить некоторые значения как обязательные. По умолчанию Ansible завершается ошибкой, если переменная в вашем плейбуке или команде неопределена. Вы можете настроить Ansible на разрешение неопределенных переменных, установив DEFAULT_UNDEFINED_VAR_BEHAVIOR на false. В этом случае вы можете потребовать определения некоторых переменных. Вы можете сделать это с помощью:

{{ variable | mandatory }}

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

Удобный способ потребовать переопределения переменной — присвоить ей неопределенное значение с помощью функции undef().

galaxy_url: "https://galaxy.ansible.com"
galaxy_api_key: "{{ undef(hint='You must specify your Galaxy API key') }}"

Определение различных значений для true/false/null (тернарный)

Вы можете создать проверку, затем определить одно значение для использования, когда проверка возвращает true, и другое — когда она возвращает false (новое в версии 1.9):

{{ (status == 'needs_restart') | ternary('restart', 'continue') }}

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

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

Управление типами данных

Возможно, вам потребуется узнать, изменить или установить тип данных переменной. Например, зарегистрированная переменная может содержать словарь, а вашей следующей задаче может потребоваться список, или пользовательский запрос может вернуть строку, когда вашему плейбуку требуется булево значение. Используйте фильтры ansible.builtin.type_debug, ansible.builtin.dict2items и ansible.builtin.items2dict для управления типами данных. Вы также можете использовать сам тип данных для преобразования значения в определённый тип данных.

Определение типа данных

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

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

{{ myvar | type_debug }}

Следует отметить, что, хотя этот фильтр может показаться полезным для проверки того, что у вас есть нужный тип данных в переменной, вы часто предпочитаете тесты типа, которые позволят вам проверить конкретные типы данных.

Преобразование строк в списки

Используйте фильтр ansible.builtin.split для преобразования строки, разделитель которой является символом или строкой, в список элементов, подходящий для циклов. Например, если вы хотите разбить строковую переменную fruits по запятым, вы можете использовать:

{{ fruits | split(',') }}

Данные строки (до применения фильтра ansible.builtin.split):

fruits: apple,banana,orange

Данные списка (после применения фильтра ansible.builtin.split):

- apple
- banana
- orange

Преобразование словарей в списки

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

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

{{ dict | dict2items }}

Данные словаря (до применения фильтра ansible.builtin.dict2items):

tags:
  Application: payment
  Environment: dev

Данные списка (после применения фильтра ansible.builtin.dict2items):

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

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

Фильтр ansible.builtin.dict2items является обратным фильтру ansible.builtin.items2dict.

Если вы хотите настроить имена ключей, фильтр ansible.builtin.dict2items принимает 2 ключевых аргумента. Передайте аргументы key_name и value_name для настройки имён ключей в выходном списке:

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

Данные словаря (до применения фильтра ansible.builtin.dict2items):

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

Данные списка (после применения фильтра ansible.builtin.dict2items):

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

Преобразование списков в словари

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

Используйте фильтр ansible.builtin.items2dict для преобразования списка в словарь, отображая содержимое в key: value пары:

{{ tags | items2dict }}

Данные списка (до применения фильтра ansible.builtin.items2dict):

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

Данные словаря (после применения фильтра ansible.builtin.items2dict):

Application: payment
Environment: dev

Фильтр ansible.builtin.items2dict является обратным фильтру ansible.builtin.dict2items.

Не все списки используют key для обозначения ключей и value для обозначения значений. Например:

fruits:
  - fruit: apple
    color: red
  - fruit: pear
    color: yellow
  - fruit: grapefruit
    color: yellow

В этом примере необходимо передать аргументы key_name и value_name для настройки преобразования. Например:

{{ fruits | items2dict(key_name='fruit', value_name='color') }}

Если вы не передадите эти аргументы или не передадите правильные значения для вашего списка, вы увидите KeyError: key или KeyError: my_typo.

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

Вы можете преобразовывать значения в определенные типы. Например, если вы ожидаете ввод «True» от vars_prompt и хотите, чтобы Ansible распознал его как булево значение, а не строку:

- ansible.builtin.debug:
     msg: test
  when: some_string_value | bool

Если вы хотите выполнить математическое сравнение с фактом и хотите, чтобы Ansible распознал его как целое число, а не строку:

- shell: echo "only on Red Hat 6, derivatives, and later"
  when: ansible_facts['os_family'] == "RedHat" and ansible_facts['lsb']['major_release'] | int >= 6

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

Форматирование данных: YAML и JSON

Вы можете переключить структуру данных в шаблоне на формат JSON или YAML с опциями форматирования, отступов и загрузки данных. Базовые фильтры иногда полезны для отладки:

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

См. ansible.builtin.to_json и ansible.builtin.to_yaml для документации по этим фильтрам.

Для удобочитаемого вывода вы можете использовать:

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

См. ansible.builtin.to_nice_json и ansible.builtin.to_nice_yaml для документации по этим фильтрам.

Вы можете изменить отступы любого из форматов:

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

Фильтры ansible.builtin.to_yaml и ansible.builtin.to_nice_yaml используют библиотеку PyYAML, которая имеет стандартное ограничение длины строки в 80 символов. Это приводит к неожиданному разрыву строки после 80-го символа (если после 80-го символа есть пробел). Чтобы избежать такого поведения и сгенерировать длинные строки, используйте опцию width. Вы должны использовать жёстко заданное число для определения ширины, а не конструкцию типа float("inf"), потому что фильтр не поддерживает проксирование функций Python. Например:

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

Фильтр поддерживает передачу других параметров YAML. Полный список см. в документации PyYAML для dump().

Если вы читаете уже отформатированные данные:

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

например:

tasks:
  - name: Register JSON output as a variable
    ansible.builtin.shell: cat /some/path/to/file.json
    register: result

  - name: Set a variable
    ansible.builtin.set_fact:
      myvar: "{{ result.stdout | from_json }}"

Фильтр to_json и поддержка Unicode

По умолчанию ansible.builtin.to_json и ansible.builtin.to_nice_json преобразуют полученные данные в ASCII, поэтому:

{{ 'München'| to_json }}

вернёт:

'M\u00fcnchen'

Чтобы сохранить символы Unicode, передайте параметр ensure_ascii=False в фильтр:

{{ 'München'| to_json(ensure_ascii=False) }}

'München'

Добавлена в версии 2.7.

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

например:

tasks:
  - name: Register a file content as a variable
    ansible.builtin.shell: cat /some/path/to/multidoc-file.yaml
    register: result

  - name: Print the transformed variable
    ansible.builtin.debug:
      msg: '{{ item }}'
    loop: '{{ result.stdout | from_yaml_all | list }}'

Объединение и выбор данных

Вы можете объединять данные из нескольких источников и типов, а также выбирать значения из больших структур данных, что даёт вам точный контроль над сложными данными.

Объединение элементов из нескольких списков: zip и zip_longest

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

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

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

# => [[1, "a"], [2, "b"], [3, "c"], [4, "d"], [5, "e"], [6, "f"]]

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

# => [[1, "a"], [2, "b"], [3, "c"]]

Для гарантированного исчерпания всех списков используйте ansible.builtin.zip_longest:

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

# => [[1, "a", 21], [2, "b", 22], [3, "c", 23], ["X", "d", "X"], ["X", "e", "X"], ["X", "f", "X"]]

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

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

Данные списка (до применения фильтра ansible.builtin.zip):

keys_list:
  - one
  - two
values_list:
  - apple
  - orange

Данные словаря (после применения фильтра ansible.builtin.zip):

one: apple
two: orange

Объединение объектов и подэлементов

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

Фильтр ansible.builtin.subelements производит произведение объекта и значений подэлементов этого объекта, аналогично поиску ansible.builtin.subelements. Это позволяет указать отдельные подэлементы для использования в шаблоне. Например, это выражение:

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

Данные до применения фильтра ansible.builtin.subelements:

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

Данные после применения фильтра ansible.builtin.subelements:

-
  - 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'
  ansible.posix.authorized_key:
    user: "{{ item.0.name }}"
    key: "{{ lookup('file', item.1) }}"
  loop: "{{ users | subelements('authorized') }}"

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

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

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

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

Получившийся хеш будет:

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

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

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

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

Фильтр также принимает два необязательных параметра: recursive и list_merge.

recursive

Это булево значение, по умолчанию равное False. Необходимо ли фильтру ansible.builtin.combine рекурсивно объединять вложенные хеши. Примечание: Это не зависит от значения параметра hash_behaviour в ansible.cfg.

list_merge

Это строка, возможные значения которой replace (по умолчанию), keep, append, prepend, append_rp или prepend_rp. Он изменяет поведение фильтра ansible.builtin.combine при объединении хешей, содержащих массивы/списки.

default:
  a:
    x: default
    y: default
  b: default
  c: default
patch:
  a:
    y: patch
    z: patch
  b: patch

Если recursive=False (по умолчанию), вложенные хеши не объединяются:

{{ default | combine(patch) }}

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

a:
  y: patch
  z: patch
b: patch
c: default

Если recursive=True, происходит рекурсивное объединение ключей вложенных хешей:

{{ default | combine(patch, recursive=True) }}

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

a:
  x: default
  y: patch
  z: patch
b: patch
c: default

Если list_merge='replace' (по умолчанию), массивы из правого хеша «заменят» массивы в левом хеше:

default:
  a:
    - default
patch:
  a:
    - patch
{{ default | combine(patch) }}

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

a:
  - patch

Если list_merge='keep', массивы из левого хеша сохранятся:

{{ default | combine(patch, list_merge='keep') }}

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

a:
  - default

Если list_merge='append', массивы из правого хеша будут добавлены к массивам из левого хеша:

{{ default | combine(patch, list_merge='append') }}

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

a:
  - default
  - patch

Если list_merge='prepend', массивы из правого хеша будут добавлены в начало массивов из левого хеша:

{{ default | combine(patch, list_merge='prepend') }}

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

a:
  - patch
  - default

Если list_merge='append_rp', массивы из правого хеша будут добавлены к массивам из левого хеша. Элементы массивов в левом хеше, которые также присутствуют в соответствующем массиве правого хеша, будут удалены («rp» означает «удалить присутствующий»). Повторяющиеся элементы, которые не присутствуют в обоих хешах, сохраняются:

default:
  a:
    - 1
    - 1
    - 2
    - 3
patch:
  a:
    - 3
    - 4
    - 5
    - 5
{{ default | combine(patch, list_merge='append_rp') }}

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

a:
  - 1
  - 1
  - 2
  - 3
  - 4
  - 5
  - 5

Если list_merge='prepend_rp', поведение аналогично предыдущему, но элементы массивов из правого хеша добавляются в начало:

{{ default | combine(patch, list_merge='prepend_rp') }}

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

a:
  - 3
  - 4
  - 5
  - 5
  - 1
  - 1
  - 2

recursive и list_merge могут быть использованы вместе:

default:
  a:
    a':
      x: default_value
      y: default_value
      list:
        - default_value
  b:
    - 1
    - 1
    - 2
    - 3
patch:
  a:
    a':
      y: patch_value
      z: patch_value
      list:
        - patch_value
  b:
    - 3
    - 4
    - 4
    - key: value
{{ default | combine(patch, recursive=True, list_merge='append_rp') }}

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

a:
  a':
    x: default_value
    y: patch_value
    z: patch_value
    list:
      - default_value
      - patch_value
b:
  - 1
  - 1
  - 2
  - 3
  - 4
  - 4
  - key: value

Выбор значений из массивов или хеш-таблиц

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

Объединение списков

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

Перестановки

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

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

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

Комбинации

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

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

Также смотрите zip_filter

Декартово произведение

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

Например:

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

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

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

Выбор данных JSON: запросы JSON

Для выбора одного элемента или подмножества данных из сложной структуры данных в формате JSON (например, фактов Ansible) используйте фильтр community.general.json_query. Фильтр community.general.json_query позволяет вам запросить сложную структуру JSON и перебирать её с помощью цикла.

Примечание

Этот фильтр переместился в коллекцию community.general. Следуйте инструкциям по установке, чтобы установить эту коллекцию.

Примечание

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

Рассмотрим эту структуру данных:

{
    "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
  ansible.builtin.debug:
    var: item
  loop: "{{ domain_definition | community.general.json_query('domain.cluster[*].name') }}"

Чтобы извлечь все имена серверов:

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

Чтобы извлечь порты из кластера cluster1:

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

Примечание

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

Чтобы вывести порты из cluster1 в виде строки, разделенной запятыми:

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

Примечание

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

Вы можете использовать YAML экранирование одиночных кавычек:

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

Примечание

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

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

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

Чтобы извлечь порты из всех кластеров, имена которых начинаются с «server1»:

- name: Display ports from all clusters with the name starting with 'server1'
  ansible.builtin.debug:
    msg: "{{ domain_definition | to_json | from_json | community.general.json_query(server_name_query) }}"
  vars:
    server_name_query: "domain.server[?starts_with(name,'server1')].port"

Чтобы извлечь порты из всех кластеров, имена которых содержат «server1»:

- name: Display ports from all clusters with the name containing 'server1'
  ansible.builtin.debug:
    msg: "{{ domain_definition | to_json | from_json | community.general.json_query(server_name_query) }}"
  vars:
    server_name_query: "domain.server[?contains(name,'server1')].port"

Примечание

при использовании starts_with и contains, необходимо использовать фильтр `` to_json | from_json `` для правильной обработки структуры данных.

Генерация случайных данных

Когда вам нужен случайный генерируемый параметр, используйте один из этих фильтров.

Случайные MAC-адреса

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

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

Примечание

Этот фильтр переместился в коллекцию community.general. Следуйте инструкциям по установке, чтобы установить эту коллекцию.

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

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

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

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

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

"{{ '52:54:00' | community.general.random_mac(seed=inventory_hostname) }}"

Случайные элементы или числа

Фильтр ansible.builtin.random в Ansible является расширением стандартного фильтра 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

Вы можете инициализировать генератор случайных чисел из семян, чтобы создавать случайные, но идемпотентные числа:

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

Перемешивание списка

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

Чтобы получить случайный список из существующего списка:

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

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

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

Фильтр shuffle возвращает список, когда это возможно. Если вы используете его с элементом, не являющимся «списком», фильтр ничего не делает.

Управление переменными списков

Вы можете искать минимальное или максимальное значение в списке или сплющивать многоуровневый список.

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

{{ list1 | min }}

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

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

{{ [{'val': 1}, {'val': 2}] | min(attribute='val') }}

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

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

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

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

{{ [{'val': 1}, {'val': 2}] | max(attribute='val') }}

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

Сплющить список (то же самое, что и делает lookup flatten):

{{ [3, [4, 2] ] | flatten }}
# => [3, 4, 2]

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

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

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

Сохранить null в списке, по умолчанию flatten их удаляет.:

{{ [3, None, [4, [2]] ] | flatten(levels=1, skip_nulls=False) }}
# => [3, None, 4, [2]]

Выбор из множеств или списков (теория множеств)

Вы можете выбирать или комбинировать элементы из множеств или списков.

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

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

# list1: [1, 2, 5, 1, 3, 4, 10]
{{ list1 | unique }}
# => [1, 2, 5, 3, 4, 10]

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

# list1: [1, 2, 5, 1, 3, 4, 10]
# list2: [1, 2, 3, 4, 5, 11, 99]
{{ list1 | union(list2) }}
# => [1, 2, 5, 1, 3, 4, 10, 11, 99]

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

# list1: [1, 2, 5, 3, 4, 10]
# list2: [1, 2, 3, 4, 5, 11, 99]
{{ list1 | intersect(list2) }}
# => [1, 2, 5, 3, 4]

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

# list1: [1, 2, 5, 1, 3, 4, 10]
# list2: [1, 2, 3, 4, 5, 11, 99]
{{ list1 | difference(list2) }}
# => [10]

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

# list1: [1, 2, 5, 1, 3, 4, 10]
# list2: [1, 2, 3, 4, 5, 11, 99]
{{ list1 | symmetric_difference(list2) }}
# => [10, 11, 99]

Вычисления чисел (математика)

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

Вы можете вычислять логарифмы, степени и корни чисел с помощью фильтров Ansible. Jinja2 предоставляет другие математические функции, такие как abs() и round().

Получить логарифм (по умолчанию e):

{{ 8 | log }}
# => 2.0794415416798357

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

{{ 8 | log(10) }}
# => 0.9030899869919435

Дайте мне степень 2! (или 5):

{{ 8 | pow(5) }}
# => 32768.0

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

{{ 8 | root }}
# => 2.8284271247461903

{{ 8 | root(5) }}
# => 1.5157165665103982

Управление сетевыми взаимодействиями

Эти фильтры помогают вам с общими сетевыми задачами.

Примечание

Эти фильтры перенесены в коллекцию ansible.utils. Следуйте инструкциям по установке, чтобы установить эту коллекцию.

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

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

Чтобы проверить, является ли строка валидным IP-адресом:

{{ myvar | ansible.utils.ipaddr }}

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

{{ myvar | ansible.utils.ipv4 }}
{{ myvar | ansible.utils.ipv6 }}

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

{{ '192.0.2.1/24' | ansible.utils.ipaddr('address') }}
# => 192.0.2.1

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

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

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

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

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

Фильтр ansible.netcommon.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

Ещё один распространённый случай использования для анализа команд 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. Чтобы проанализировать вывод командной строки с помощью TextFSM, используйте следующий фильтр:

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

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

Фильтры сетевого XML

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

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

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

Фильтр ansible.netcommon.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 см. в XPath Support.

Фильтры сетевой VLAN

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

Используйте фильтр ansible.netcommon.vlan_parser, чтобы преобразовать несортированный список целочисленных значений VLAN в отсортированный строковый список целых чисел в соответствии с правилами списков VLAN в стиле IOS. Этот список имеет следующие свойства:

  • VLANs перечислены в порядке возрастания.
  • Три и более последовательных VLAN перечисляются с дефисом.
  • Первая строка списка может быть длиной first_line_len символов.
  • Последующие строки списка могут иметь длину other_line_len символов.

Чтобы отсортировать список VLAN:

{{ [3003, 3004, 3005, 100, 1688, 3002, 3999] | ansible.netcommon.vlan_parser }}

Этот пример отображает следующий отсортированный список:

['100,1688,3002-3005,3999']

Ещё один пример шаблона Jinja:

{% set parsed_vlans = vlans | ansible.netcommon.vlan_parser %}
switchport trunk allowed vlan {{ parsed_vlans[0] }}
{% for i in range (1, parsed_vlans | count) %}
switchport trunk allowed vlan add {{ parsed_vlans[i] }}
{% endfor %}

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

Хэширование и шифрование строк и паролей

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

Чтобы получить sha1 хэш строки:

{{ 'test1' | hash('sha1') }}
# => "b444ac06613fc8d63795be9ad0beaf55011936ac"

Чтобы получить md5 хэш строки:

{{ 'test1' | hash('md5') }}
# => "5a105e8b9d40e1329780d62ea2265d8a"

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

{{ 'test2' | checksum }}
# => "109f4b3c50d7b0df729d299bc6f8e9ef9066971f"

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

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

Чтобы получить хэш пароля sha512 (случайный соль):

{{ 'passwordsaresecret' | password_hash('sha512') }}
# => "$6$UIv3676O/ilZzWEE$ktEfFF19NQPF2zyxqxGkAceTnbEgpEKuGBtk6MlU4v2ZorWaVQUMyurgmHCh2Fr4wpmQ/Y.AlXMJkRnIS4RfH/"

Чтобы получить хэш пароля sha256 с заданной солью:

{{ 'secretpassword' | password_hash('sha256', 'mysecretsalt') }}
# => "$5$mysecretsalt$ReKNyDYjkKNqRVwouShhsEqZ3VOE8eoVO4exihOfvG4"

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

{{ 'secretpassword' | password_hash('sha512', 65534 | random(seed=inventory_hostname) | string) }}
# => "$6$43927$lQxPKz2M2X.NWO.gK.t7phLwOKQMcSq72XxDZQ0XzYV6DlL1OD72h417aj16OnHTGxNzhftXJQBcjbunLEepM0"

Доступные типы хэшей зависят от управляющей системы, в которой выполняется Ansible, ansible.builtin.hash зависит от hashlib, ansible.builtin.password_hash зависит от passlib. crypt используется в качестве резервного варианта, если passlib не установлен.

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

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

{{ 'secretpassword' | password_hash('sha256', 'mysecretsalt', rounds=10000) }}
# => "$5$rounds=10000$mysecretsalt$Tkm80llAxD4YHll6AgNIztKn0vzAACsuuEfYeGP7tm7"

Фильтр password_hash даёт разные результаты в зависимости от того, установлен ли у вас passlib или нет.

Для обеспечения идемпотентности укажите rounds, чтобы он не был ни по умолчанию crypt, ни по умолчанию passlib, который равен 5000 для crypt и переменной величине (535000 для sha256, 656000 для sha512) для passlib:

{{ 'secretpassword' | password_hash('sha256', 'mysecretsalt', rounds=5001) }}
# => "$5$rounds=5001$mysecretsalt$wXcTWWXbfcR8er5IVf7NuquLvnUA6s8/qdtOhAZ.xN."

Тип хэша «blowfish» (BCrypt) предоставляет возможность указать версию алгоритма BCrypt.

{{ 'secretpassword' | password_hash('blowfish', '1234567890123456789012', ident='2b') }}
# => "$2b$12$123456789012345678901uuJ4qFdej6xnWjOQT.FStqfdoY8dYUPC"

Примечание

Параметр доступен только для blowfish (BCrypt). Другие типы хэшей просто проигнорируют этот параметр. Допустимые значения для этого параметра: [‘2’, ‘2a’, ‘2y’, ‘2b’]

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

Вы также можете использовать Ansible-фильтр ansible.builtin.vault для шифрования данных:

# simply encrypt my key in a vault
vars:
  myvaultedkey: "{{ keyrawdata|vault(passphrase) }}"

- name: save templated vaulted data
  template: src=dump_template_data.j2 dest=/some/key/vault.txt
  vars:
    mysalt: '{{ 2**256|random(seed=inventory_hostname) }}'
    template_data: '{{ secretdata|vault(vaultsecret, salt=mysalt) }}'

А затем расшифровать его с помощью фильтра unvault:

# simply decrypt my key from a vault
vars:
  mykey: "{{ myvaultedkey|unvault(passphrase) }}"

- name: save templated unvaulted data
  template: src=dump_template_data.j2 dest=/some/key/clear.txt
  vars:
    template_data: '{{ secretdata|unvault(vaultsecret) }}'

Обработка текста

Несколько фильтров работают с текстом, включая URL, имена файлов и имена путей.

Добавление комментариев к файлам

Фильтр ansible.builtin.comment позволяет создавать комментарии в файле из текста в шаблоне с различными стилями комментариев. По умолчанию Ansible использует # для начала строки комментария и добавляет пустую строку комментария сверху и снизу текста комментария. Например:

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

производит этот вывод:

#
# Plain style (default)
#

Ansible предлагает стили комментариев для 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

Фильтр urlencode кодирует данные для использования в пути URL или запросе с использованием UTF-8:

{{ 'Trollhättan' | urlencode }}
# => 'Trollh%C3%A4ttan'

Разделение URL

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

Фильтр ansible.builtin.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"
#   }

Поиск в строках с использованием регулярных выражений

Для поиска в строке или извлечения частей строки с помощью регулярного выражения используйте фильтр ansible.builtin.regex_search:

# Extracts the database name from a string
{{ 'server1/database42' | regex_search('database[0-9]+') }}
# => 'database42'

# Example for a case insensitive search in multiline mode
{{ 'foo\nBAR' | regex_search('^bar', multiline=True, ignorecase=True) }}
# => 'BAR'

# Example for a case insensitive search in multiline mode using inline regex flags
{{ 'foo\nBAR' | regex_search('(?im)^bar') }}
# => 'BAR'

# Extracts server and database id from a string
{{ 'server1/database42' | regex_search('server([0-9]+)/database([0-9]+)', '\\1', '\\2') }}
# => ['1', '42']

# Extracts dividend and divisor from a division
{{ '21/42' | regex_search('(?P<dividend>[0-9]+)/(?P<divisor>[0-9]+)', '\\g<dividend>', '\\g<divisor>') }}
# => ['21', '42']

Фильтр ansible.builtin.regex_search возвращает пустую строку, если не найдено совпадение:

{{ 'ansible' | regex_search('foobar') }}
# => ''

Примечание

Фильтр ansible.builtin.regex_search возвращает None при использовании в выражении Jinja (например, в сочетании с операторами, другими фильтрами и т. д.). См. два примера ниже.

{{ 'ansible' | regex_search('foobar') == '' }}
# => False
{{ 'ansible' | regex_search('foobar') is none }}
# => True

Это связано с историческим поведением и пользовательской реализацией некоторых внутренних компонентов Jinja в Ansible. Включите настройку jinja2_native, если хотите, чтобы фильтр ansible.builtin.regex_search всегда возвращал None, если совпадение не найдено. См. Почему фильтр regex_search возвращает None вместо пустой строки? для получения подробной информации.

Для извлечения всех совпадений регулярных выражений в строке используйте фильтр ansible.builtin.regex_findall:

# Returns 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') }}
# => ['8.8.8.8', '8.8.4.4']

# Returns all lines that end with "ar"
{{ 'CAR\ntar\nfoo\nbar\n' | regex_findall('^.ar$', multiline=True, ignorecase=True) }}
# => ['CAR', 'tar', 'bar']

# Returns all lines that end with "ar" using inline regex flags for multiline and ignorecase
{{ 'CAR\ntar\nfoo\nbar\n' | regex_findall('(?im)^.ar$') }}
# => ['CAR', 'tar', 'bar']

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

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

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

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

# Convert "localhost:80" to "localhost"
{{ 'localhost:80' | regex_replace(':80') }}
# => 'localhost'

# Comment all lines that end with "ar"
{{ 'CAR\ntar\nfoo\nbar\n' | regex_replace('^(.ar)$', '#\\1', multiline=True, ignorecase=True) }}
# => '#CAR\n#tar\nfoo\n#bar\n'

# Comment all lines that end with "ar" using inline regex flags for multiline and ignorecase
{{ 'CAR\ntar\nfoo\nbar\n' | regex_replace('(?im)^(.ar)$', '#\\1') }}
# => '#CAR\n#tar\nfoo\n#bar\n'

Примечание

Если вы хотите сопоставить всю строку и используете *, убедитесь, что всегда оборачиваете своё регулярное выражение якорями начала/конца. Например, ^(.*)$ всегда будет сопоставлять только один результат, в то время как (.*) на некоторых версиях Python будет сопоставлять всю строку и пустую строку в конце, что означает, что он произведёт две замены:

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

BAD:
{{ hosts | map('regex_replace', '(.*)', 'https://\\1') | list }}

# append ':80' to each item in a list
GOOD:
{{ hosts | map('regex_replace', '^(.*)$', '\\1:80') | list }}
{{ hosts | map('regex_replace', '(.+)', '\\1:80') | list }}
{{ hosts | map('regex_replace', '$', ':80') | list }}

BAD:
{{ hosts | map('regex_replace', '(.*)', '\\1:80') | list }}

Примечание

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

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

Для экранирования специальных символов в стандартном регулярном выражении Python используйте фильтр ansible.builtin.regex_escape (используя необязательный параметр re_type='python'):

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

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

Для экранирования специальных символов в регулярном выражении POSIX basic используйте фильтр ansible.builtin.regex_escape с опцией re_type='posix_basic':

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

Управление именами файлов и именами путей

Для получения последнего имени файла пути, например, ‘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 }}

Фильтр ansible.builtin.splitext всегда возвращает пару строк. Отдельные компоненты можно получить с помощью фильтров first и last:

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

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

Для объединения одного или нескольких компонентов пути:

{{ ('/etc', path, 'subdir', file) | path_join }}

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

Обработка строк

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

- name: Run a shell command
  ansible.builtin.shell: echo {{ string_value | quote }}

(Документация: ansible.builtin.quote)

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

{{ list | join(" ") }}

Для разделения строки на список:

{{ csv_string | split(",") }}

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

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

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

(Документация: ansible.builtin.b64encode)

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

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

(Документация: ansible.builtin.b64decode)

Примечание

Фильтр string необходим только для Python 2 и гарантирует, что текст для кодирования — строка Unicode. Без этого фильтра перед b64encode будет закодировано неправильное значение.

Примечание

Возвращаемое значение фильтра b64decode — строка. Если вы декодируете двоичный блок с использованием b64decode, а затем пытаетесь использовать его (например, с помощью copy для записи его в файл), вы, скорее всего, обнаружите, что ваш двоичный блок повреждён. Если вам нужно взять двоичный блок, закодированный в Base64, и записать его на диск, лучше всего использовать системную команду base64 с модулем shell, передавая закодированные данные с помощью параметра stdin. Например: shell: cmd="base64 --decode > myfile.bin" stdin="{{ encoded }}"

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

Управление UUID

Для создания UUIDv5 в пространстве имён:

{{ string | to_uuid(namespace='11111111-2222-3333-4444-555555555555') }}

Новая версия с 2.10.

Для создания UUIDv5 в пространстве имён по умолчанию ‘361E6D51-FAEC-444A-9079-341386DA8E2E’:

{{ string | to_uuid }}

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

Чтобы использовать один атрибут из каждого элемента списка сложных переменных, используйте фильтр Jinja2 map filter:

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

Обработка дат и времени

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

# Get the 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, and so on 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 the 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  }}

Примечание

Полный список кодов формата для работы со строками формата даты Python см. в документации по дате и времени Python.

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

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

# Display year-month-day
{{ '%Y-%m-%d' | strftime }}
# => "2021-03-19"

# Display hour:min:sec
{{ '%H:%M:%S' | strftime }}
# => "21:51:04"

# Use ansible_date_time.epoch fact
{{ '%Y-%m-%d %H:%M:%S' | strftime(ansible_date_time.epoch) }}
# => "2021-03-19 21:54:09"

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

Новая версия с 2.13.

strftime принимает необязательный аргумент utc, по умолчанию False, что означает, что время указано в часовом поясе по умолчанию:

{{ '%H:%M:%S' | strftime }}           # time now in local timezone
{{ '%H:%M:%S' | strftime(utc=True) }} # time now in UTC

Примечание

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

Получение имён ресурсов Kubernetes

Примечание

Эти фильтры переехали в коллекцию kubernetes.core. Следуйте инструкциям по установке, чтобы установить эту коллекцию.

Используйте фильтр «k8s_config_resource_name», чтобы получить имя Kubernetes ConfigMap или Secret, включая его хеш:

{{ configmap_resource_definition | kubernetes.core.k8s_config_resource_name }}

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

my_secret:
  kind: Secret
  metadata:
    name: my_secret_name

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

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

См. также

Ansible playbook

Вступление к Ansible playbooks

Условные выражения

Условные операторы в playbooks

Использование переменных

Все о переменных

Циклы

Использование циклов в playbooks

Роли

Организация playbooks по ролям

Общие советы

Советы и рекомендации по playbooks

Связь

Есть вопросы? Нужна помощь? Хотите поделиться своими идеями? Посетите руководство по общению в Ansible

Операции с регулярными выражениями Python 3

Как использовать встроенные флаги регулярных выражений

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

Spec-Zone.ru

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