Используя Ansible в качестве инструмента автоматизации, часто приходится сталкиваться с задачей обработки и фильтрации структурированных данных. Как правило, это набор фактов, полученных с управляемых серверов, или ответ на запрос к внешним API, которые возвращают данные в виде стандартного json. Многие неопытные инженеры, используя Ansible в таких случаях, начинают прибегать к помощи привычных консольных команд и начинают городить то, что среди специалистов получило название bashsible. В общем, вспоминается известный мем: В этой статье мы покажем, как легко и просто можно обрабатывать данные прямо в Ansible, используя его собственные мощные возможности. Речь идет о фильтрах Jinja2, которые представляют собой мощный, но в то же время интуитивно понятный инструмент для трансформации данных. Эти фильтры позволяют эффективно сортировать, выбирать и преобразовывать данные, устраняя необходимость в сложных внешних командах и скриптах.  В обычных языках программирования задача обработки данных обычно решается с помощью циклов (for, while, for_each и т. п.) и различных функций преобразования типов объектов (массивы, коллекции, замыкания и т. п.) Ansible использует упрощенную модель данных, используя по сути лишь два варианта объекта с данными, список (list) и словарь (dictionary). Если вы не очень хорошо понимаете, что это такое и чем они отличаются, рекомендую для начала прочесть вот эту короткую статью.  Начнем с базовых примеров использования фильтров для работы со списками и словарями. Это позволит вам видеть, насколько мощными и гибкими могут быть эти инструменты в правильных руках.  На практике часто приходится иметь дело с фактами или результатом выполнения определенных модулей, которые представляют собой структуру в виде json/yaml. Например, давайте возьмем такой факт, как ansible_mounts и попробуем с ним поработать. Попробуйте запустить у себя следующий плейбук, выводящий значения ansible_mounts: В выводе получится что-то вроде такого: Давайте попробуем отфильтровать из этого длинного списка только те значения, для которых значение ключа device содержит /dev/sda. Это можно сделать с помощью фильтра selectattr и теста match: Получим примерно такое: Теперь давайте предположим, что нам из всего набора ключей каждого словаря нужно только значение ключа mount. Как выбрать из полученного списка лишь значения определенного ключа? Тут нам на помощь придет фильтр map. Это довольно мощный фильтр, суть которого сводится к тому, что он применяет фильтр с аргументами, которые сами переданы ему в качестве аргументов, к каждому элементу списка словарей, которые приходят на вход. В простейшем случае, если нам нужно просто получить значение конкретного ключа из каждого элемента списка словарей, использование данного фильтра будет очень простым. Нужно просто указать значение нужного имени ключа в виде атрибута фильтра с соответствующей командой. В нашем случае это будет map(attribute='mount'). В результате получим следующий код: В выводе получим следующее: Как видим, получить нужный нам набор данных оказывается весьма просто даже без использования программирования и циклов. Давайте усложним задачу. Скажем, нам нужно получить в выводе значения не только ключа mount, но также значения ключей size_available и size_total. Идущие в комплекте фильтры так не умеют. Фильтры Ansible умеют фильтровать списки и списки словарей, но не сами ключи словаря. Выход прост: нужно превратить словарь в список и уже его отфильтровать имеющимися инструментами. К счастью, в Ansible есть подходящие фильтры для такой задачи. С их помощью можно превращать словари в списки, а списки — обратно в словари. Называются эти фильтры, соответственно, dict2items и items2dict.  Например, у нас есть следующий словарь: И мы хотим отфильтровать только те элементы словаря, где есть ключ version. Сделать это мы сможем так. Сначала превращаем словать в список с помощью фильтра dict2items: Получим: Теперь отфильтруем только те элементы списка, которые содержат дочерний ключ version: Получим: Теперь превратим обратно список в словарь исходного вида. Для этого добавим в конец конвейера фильтр items2dict. Получаем: Теперь давайте вспомним про нашу исходную задачу со списком словарей ansible_mounts из которого мы хотим извлечь только некоторые ключи. Сам список мы уже отфильтровали по нужному нам условию, теперь нам нужно выбрать только определенные ключи из списка. Получается, что к каждому элементу списка словарей нужно применить фильтр dict2items, потом отфильтровать этот список по списку ключей, а потом обратно превратить каждый дочерний список обратно в словарь. Сложно? На самом деле не очень. Как работать со словарем, мы уже видели на примере выше. Теперь нам нужно проделать то же самое со списком словарей. Тут нам как раз поможет упоминавшийся выше фильтр map, только уже в более продвинутом варианте применения. Покажем сразу итоговый результат. Код: И результат: Из чего состоит код в данном примере: Выборка разделов диска: ansible_mounts | selectattr('device', 'match', '/dev/sda') Здесь используется фильтр selectattr для выбора тех элементов из списка ansible_mounts, у которых атрибут device соответствует регулярному выражению /dev/sda. Это позволяет выбрать информацию о монтировании только для определенного устройства. Преобразование словарей в списки элементов: | map('dict2items') Фильтр dict2items применяется к каждому элементу списка (каждому словарю), преобразуя его в список пар ключ-значение. Выборка определенных ключей: | map('selectattr', 'key', 'in', ['mount', 'size_available', 'size_total']) Далее, для каждого списка пар ключ-значение используется map совместно с selectattr, чтобы выбрать только те пары, ключи которых включают 'mount', 'size_available' или 'size_total'. Преобразование обратно в словари: | map('items2dict') Наконец, после фильтрации нужных ключей, каждый список пар ключ-значение преобразуется обратно в словарь с помощью map и фильтра items2dict. Мы познакомились с наглядными примерами использования фильтров Ansible, и, надеюсь, теперь они кажутся вам не такими уж сложными. Ведь часто всё кажется сложным, пока не попробуешь. С фильтрами Ansible точно так же: попробуйте, поэкспериментируйте, и вы увидите, как они могут упростить вашу жизнь. А еще напишите в комментариях, хотели бы вы увидеть продолжение статьи с другими интересными примерами фильтров? Если тема будет интересна, то в следующих статьях попробую в том числе раскрыть тему написания своих собственных кастомных фильтров.