Spec-Zone.ru › Ansible 2.9

ipaddr фильтр

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

ipaddr() — это фильтр Jinja2, предназначенный для предоставления интерфейса к пакету Python netaddr внутри Ansible. Он может работать со строками или списками элементов, проверять различные данные на предмет того, являются ли они допустимыми IP-адресами, и изменять входные данные для извлечения запрошенной информации. ipaddr() работает с адресами IPv4 и IPv6 в различных форматах. Также доступны дополнительные функции для работы с IP-подсетями и MAC-адресами.

Для использования этого фильтра в Ansible необходимо установить библиотеку Python netaddr на компьютере, на котором вы используете Ansible (она не требуется на удалённых хостах). Обычно её можно установить с помощью менеджера пакетов вашей системы или с помощью pip:

pip install netaddr
  • Основные тесты
  • Фильтрация списков
  • Оборачивание адресов IPv6 в скобки [ ]
  • Основные запросы
  • Получение информации о хостах и сетях
  • Получение информации из значений хост/префикс
  • Преобразование масок подсети в CIDR-нотацию
  • Получение информации о сети в CIDR-нотации
  • Преобразование IP-адресов
  • Преобразование IPv4-адреса в адрес 6to4
  • Поиск IP-адресов в заданном диапазоне
  • Вычисления с IP-адресами
  • Работа с подсетями
  • Объединение подсетей
  • Фильтр MAC-адресов

Основные тесты

ipaddr() предназначен для возврата входного значения, если запрос верен, и False, если запрос ложен. Таким образом, он может легко использоваться в цепочке фильтров. Для использования фильтра передайте строку:

{{ '192.0.2.0' | ipaddr }}

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

{{ myvar | ipaddr }}

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

# These values are valid IP addresses or network ranges
'192.168.0.1'       -> 192.168.0.1
'192.168.32.0/24'   -> 192.168.32.0/24
'fe80::100/10'      -> fe80::100/10
45443646733         -> ::a:94a7:50d
'523454/24'         -> 0.7.252.190/24

# Values that are not valid IP addresses or network ranges
'localhost'         -> False
True                -> False
'space bar'         -> False
False               -> False
''                  -> False
':'                 -> False
'fe80:/10'          -> False

Иногда вам нужны либо адреса IPv4, либо IPv6. Для фильтрации по определённому типу фильтр ipaddr() имеет два псевдонима, ipv4() и ipv6().

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

{{ myvar | ipv4 }}

Аналогичный пример фильтра IPv6:

{{ myvar | ipv6 }}

Вот результаты некоторых тестовых проверок для поиска адресов IPv4:

'192.168.0.1'       -> 192.168.0.1
'192.168.32.0/24'   -> 192.168.32.0/24
'fe80::100/10'      -> False
45443646733         -> False
'523454/24'         -> 0.7.252.190/24

И те же данные, отфильтрованные для адресов IPv6:

'192.168.0.1'       -> False
'192.168.32.0/24'   -> False
'fe80::100/10'      -> fe80::100/10
45443646733         -> ::a:94a7:50d
'523454/24'         -> False

Фильтрация списков

Вы можете фильтровать целые списки — ipaddr() вернёт список с значениями, которые соответствуют определённому запросу:

# Example list of values
test_list = ['192.24.2.1', 'host.fqdn', '::1', '192.168.32.0/24', 'fe80::100/10', True, '', '42540766412265424405338506004571095040/64']

# {{ test_list | ipaddr }}
['192.24.2.1', '::1', '192.168.32.0/24', 'fe80::100/10', '2001:db8:32c:faad::/64']

# {{ test_list | ipv4 }}
['192.24.2.1', '192.168.32.0/24']

# {{ test_list | ipv6 }}
['::1', 'fe80::100/10', '2001:db8:32c:faad::/64']

Оборачивание адресов IPv6 в скобки [ ]

Некоторые конфигурационные файлы требуют, чтобы адреса IPv6 были «охвачены» квадратными скобками ([ ]). Для этого можно использовать фильтр ipwrap(). Он будет оборачивать все адреса IPv6 и оставлять любые другие строки без изменений:

# {{ test_list | ipwrap }}
['192.24.2.1', 'host.fqdn', '[::1]', '192.168.32.0/24', '[fe80::100]/10', True, '', '[2001:db8:32c:faad::]/64']

Как вы видите, ipwrap() не отфильтровал значения, которые не являются IP-адресами, что обычно требуется, когда вы, например, смешиваете IP-адреса с именами хостов. Если вы всё ещё хотите отфильтровать все значения, которые не являются IP-адресами, вы можете объединить оба фильтра:

# {{ test_list | ipaddr | ipwrap }}
['192.24.2.1', '[::1]', '192.168.32.0/24', '[fe80::100]/10', '[2001:db8:32c:faad::]/64']

Основные запросы

Вы можете передать единственный аргумент каждому фильтру ipaddr(). Затем фильтр будет обрабатывать его как запрос и возвращать значения, изменённые этим запросом. Списки будут содержать только те значения, которые вы запрашиваете.

Типы запросов включают:

  • запрос по имени: ipaddr('address'), ipv4('network');
  • запрос по диапазону CIDR: ipaddr('192.168.0.0/24'), ipv6('2001:db8::/32');
  • запрос по номеру индекса: ipaddr('1'), ipaddr('-1');

Если тип запроса не распознаётся, Ansible выведет ошибку.

Получение информации о хостах и сетях

Вот наш тестовый список ещё раз:

# Example list of values
test_list = ['192.24.2.1', 'host.fqdn', '::1', '192.168.32.0/24', 'fe80::100/10', True, '', '42540766412265424405338506004571095040/64']

Давайте возьмём список выше и получим только те элементы, которые являются IP-адресами хостов, а не диапазонами сетей:

# {{ test_list | ipaddr('address') }}
['192.24.2.1', '::1', 'fe80::100']

Как вы можете видеть, даже если некоторые значения содержали адрес хоста с префиксом CIDR, они были отброшены фильтром. Если вы хотите IP-адреса хостов с их правильными префиксами CIDR (как это обычно делается с адресацией IPv6), вы можете использовать фильтр ipaddr('host'):

# {{ test_list | ipaddr('host') }}
['192.24.2.1/32', '::1/128', 'fe80::100/10']

Фильтрация по типу IP-адреса также работает:

# {{ test_list | ipv4('address') }}
['192.24.2.1']

# {{ test_list | ipv6('address') }}
['::1', 'fe80::100']

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

# {{ test_list | ipaddr('public') }}
['192.24.2.1', '2001:db8:32c:faad::/64']

# {{ test_list | ipaddr('private') }}
['192.168.32.0/24', 'fe80::100/10']

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

# {{ test_list | ipaddr('net') }}
['192.168.32.0/24', '2001:db8:32c:faad::/64']

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

# {{ test_list | ipaddr('net') | ipaddr('size') }}
[256, 18446744073709551616L]

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

# {{ test_list | ipaddr('192.0.0.0/8') }}
['192.24.2.1', '192.168.32.0/24']

Если вы укажете положительное или отрицательное целое число в качестве запроса, ipaddr() будет обрабатывать его как индекс и возвращать конкретный IP-адрес из диапазона сети в формате «хост/префикс»:

# First IP address (network address)
# {{ test_list | ipaddr('net') | ipaddr('0') }}
['192.168.32.0/24', '2001:db8:32c:faad::/64']

# Second IP address (usually the gateway host)
# {{ test_list | ipaddr('net') | ipaddr('1') }}
['192.168.32.1/24', '2001:db8:32c:faad::1/64']

# Last IP address (the broadcast address in IPv4 networks)
# {{ test_list | ipaddr('net') | ipaddr('-1') }}
['192.168.32.255/24', '2001:db8:32c:faad:ffff:ffff:ffff:ffff/64']

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

# Returns from the start of the range
# {{ test_list | ipaddr('net') | ipaddr('200') }}
['192.168.32.200/24', '2001:db8:32c:faad::c8/64']

# Returns from the end of the range
# {{ test_list | ipaddr('net') | ipaddr('-200') }}
['192.168.32.56/24', '2001:db8:32c:faad:ffff:ffff:ffff:ff38/64']

# {{ test_list | ipaddr('net') | ipaddr('400') }}
['2001:db8:32c:faad::190/64']

Получение информации из значений хост/префикс

Вы часто используете комбинацию IP-адресов и префиксов подсети («CIDR»), это ещё более распространено при использовании IPv6. Фильтр ipaddr() может извлечь полезные данные из этих префиксов.

Вот пример набора из двух префиксов хоста (с некоторыми «контрольными» значениями):

host_prefix = ['2001:db8:deaf:be11::ef3/64', '192.0.2.48/24', '127.0.0.1', '192.168.0.0/16']

Сначала убедимся, что мы работаем только с правильными значениями хост/префикс, а не просто с подсетями или одиночными IP-адресами:

# {{ host_prefix | ipaddr('host/prefix') }}
['2001:db8:deaf:be11::ef3/64', '192.0.2.48/24']

В системах на основе Debian конфигурация сети, хранящаяся в файле /etc/network/interfaces, использует комбинацию IP-адреса, сетевого адреса, маски подсети и широковещательного адреса для настройки сетевого интерфейса IPv4. Мы можем получить эти значения из одного сочетания «хост/префикс»:

# Jinja2 template
{% set ipv4_host = host_prefix | unique | ipv4('host/prefix') | first %}
iface eth0 inet static
    address   {{ ipv4_host | ipaddr('address') }}
    network   {{ ipv4_host | ipaddr('network') }}
    netmask   {{ ipv4_host | ipaddr('netmask') }}
    broadcast {{ ipv4_host | ipaddr('broadcast') }}

# Generated configuration file
iface eth0 inet static
    address   192.0.2.48
    network   192.0.2.0
    netmask   255.255.255.0
    broadcast 192.0.2.255

В приведённом выше примере нам нужно было учесть тот факт, что значения хранились в списке, что необычно для сетей IPv4, где на интерфейсе можно установить только один IP-адрес. Однако в сетях IPv6 на интерфейсе можно установить несколько IP-адресов:

.. code-block:: jinja

  # Jinja2 template
  iface eth0 inet6 static
    {% set ipv6_list = host_prefix | unique | ipv6('host/prefix') %}
    address {{ ipv6_list[0] }}
    {% if ipv6_list | length > 1 %}
    {% for subnet in ipv6_list[1:] %}
    up   /sbin/ip address add {{ subnet }} dev eth0
    down /sbin/ip address del {{ subnet }} dev eth0
    {% endfor %}
    {% endif %}

  # Generated configuration file
  iface eth0 inet6 static
    address 2001:db8:deaf:be11::ef3/64

При необходимости можно извлечь информацию о подсети и префиксе из значения «хост/префикс»:

# {{ host_prefix | ipaddr('host/prefix') | ipaddr('subnet') }}
['2001:db8:deaf:be11::/64', '192.0.2.0/24']

# {{ host_prefix | ipaddr('host/prefix') | ipaddr('prefix') }}
[64, 24]

Преобразование масок подсети в CIDR-нотацию

Учитывая подсеть в форме сетевого адреса и маски подсети, фильтр ipaddr() может преобразовать её в CIDR-нотацию. Это может быть полезно для преобразования фактов Ansible, собранных о сетевой конфигурации, из масок подсети в формат CIDR:

ansible_default_ipv4: {
    address: "192.168.0.11",
    alias: "eth0",
    broadcast: "192.168.0.255",
    gateway: "192.168.0.1",
    interface: "eth0",
    macaddress: "fa:16:3e:c4:bd:89",
    mtu: 1500,
    netmask: "255.255.255.0",
    network: "192.168.0.0",
    type: "ether"
}

Сначала объединим сетевой адрес и маску подсети:

net_mask = "{{ ansible_default_ipv4.network }}/{{ ansible_default_ipv4.netmask }}"
'192.168.0.0/255.255.255.0'

Этот результат можно преобразовать в каноническую форму с помощью ipaddr() для получения подсети в формате CIDR:

# {{ net_mask | ipaddr('prefix') }}
'24'

# {{ net_mask | ipaddr('net') }}
'192.168.0.0/24'

Получение информации о сети в CIDR-нотации

Учитывая IP-адрес, фильтр ipaddr() может вывести сетевой адрес в CIDR-нотации. Это может быть полезно, когда вам нужно получить сетевой адрес из IP-адреса в формате CIDR.

Вот пример IP-адреса:

ip_address = "{{ ansible_default_ipv4.address }}/{{ ansible_default_ipv4.netmask }}"
'192.168.0.11/255.255.255.0'

Это можно использовать для получения сетевого адреса в формате CIDR:

# {{ ip_address | ipaddr('network/prefix') }}
'192.168.0.0/24'

Преобразование IP-адресов

Вот наш тестовый список ещё раз:

# Example list of values
test_list = ['192.24.2.1', 'host.fqdn', '::1', '192.168.32.0/24', 'fe80::100/10', True, '', '42540766412265424405338506004571095040/64']

Вы можете преобразовать IPv4-адреса в IPv6-адреса:

# {{ test_list | ipv4('ipv6') }}
['::ffff:192.24.2.1/128', '::ffff:192.168.32.0/120']

Преобразование из IPv6 в IPv4 работает очень редко:

# {{ test_list | ipv6('ipv4') }}
['0.0.0.1/32']

Но мы можем выполнить двойное преобразование при необходимости:

# {{ test_list | ipaddr('ipv6') | ipaddr('ipv4') }}
['192.24.2.1/32', '0.0.0.1/32', '192.168.32.0/24']

Вы можете преобразовать IP-адреса в целые числа, так же как вы можете преобразовать целые числа в IP-адреса:

# {{ test_list | ipaddr('address') | ipaddr('int') }}
[3222798849, 1, '3232243712/24', '338288524927261089654018896841347694848/10', '42540766412265424405338506004571095040/64']

Вы можете преобразовать IPv4-адрес в шестнадцатеричную нотацию с необязательным разделителем:

# {{ '192.168.1.5' | ip4_hex }}
c0a80105
# {{ '192.168.1.5' | ip4_hex(':') }}
c0:a8:01:05

Вы можете преобразовать IP-адреса в записи PTR:

# {% for address in test_list | ipaddr %}
# {{ address | ipaddr('revdns') }}
# {% endfor %}
1.2.24.192.in-addr.arpa.
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.
0.32.168.192.in-addr.arpa.
0.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa.
0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.a.a.f.c.2.3.0.8.b.d.0.1.0.0.2.ip6.arpa.

Преобразование IPv4-адреса в адрес 6to4

Тунель 6to4 — это способ доступа к интернету IPv6 из сети только с IPv4. Если у вас есть публичный IPv4-адрес, вы можете автоматически настроить его эквивалент IPv6 в диапазоне сети 2002::/16. После преобразования вы получите доступ к подсети 2002:xxxx:xxxx::/48, которая может быть разделена на 65535 /64 подсетей при необходимости.

Для преобразования вашего IPv4-адреса просто отправьте его через фильтр '6to4'. Он будет автоматически преобразован в адрес маршрутизатора (с адресом хоста ::1/48):

# {{ '193.0.2.0' | ipaddr('6to4') }}
2002:c100:0200::1/48

Поиск IP-адресов в заданном диапазоне

Для поиска доступных IP-адресов в диапазоне IP-адресов попробуйте эти фильтры ipaddr:

Для поиска следующего доступного IP-адреса в диапазоне используйте next_usable

# {{ '192.168.122.1/24' | ipaddr('next_usable') }}
192.168.122.2

Для поиска последнего доступного IP-адреса из диапазона используйте last_usable:

# {{ '192.168.122.1/24' | ipaddr('last_usable') }}
192.168.122.254

Для поиска доступного диапазона IP-адресов из заданного сетевого адреса используйте range_usable:

# {{ '192.168.122.1/24' | ipaddr('range_usable') }}
192.168.122.1-192.168.122.254

Для поиска n-го доступного IP-адреса в диапазоне используйте next_nth_usable:

# {{ '192.168.122.1/24' | next_nth_usable(2) }}
192.168.122.3

В этом примере next_nth_usable возвращает второй доступный IP-адрес для заданного диапазона IP-адресов.

Вычисления с IP-адресами

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

Фильтр ipmath() можно использовать для выполнения простых вычислений/арифметических операций с IP-адресами.

Вот несколько простых примеров:

# {{ '192.168.1.5' | ipmath(5) }}
192.168.1.10

# {{ '192.168.0.5' | ipmath(-10) }}
192.167.255.251

# {{ '192.168.1.1/24' | ipmath(5) }}
192.168.1.6

# {{ '192.168.1.6/24' | ipmath(-5) }}
192.168.1.1

# {{ '192.168.2.6/24' | ipmath(-10) }}
192.168.1.252

# {{ '2001::1' | ipmath(10) }}
2001::b

# {{ '2001::5' | ipmath(-10) }}
2000:ffff:ffff:ffff:ffff:ffff:ffff:fffb

Работа с подсетями

Фильтр ipsubnet() может использоваться для манипулирования подсетями сетей несколькими способами.

Вот пример IP-адреса и подсети:

address = '192.168.144.5'
subnet  = '192.168.0.0/16'

Чтобы проверить, является ли заданная строка подсетью, передайте её через фильтр без каких-либо аргументов. Если заданная строка представляет IP-адрес, она будет преобразована в подсеть:

# {{ address | ipsubnet }}
192.168.144.5/32

# {{ subnet | ipsubnet }}
192.168.0.0/16

Если вы укажете размер подсети в качестве первого параметра фильтра ipsubnet(), а размер подсети меньше текущего, вы получите количество подсетей, на которые можно разделить данную подсеть:

# {{ subnet | ipsubnet(20) }}
16

Вторым аргументом фильтра ipsubnet() является индекс; указав его, вы можете получить новую подсеть с указанным размером:

# First subnet
# {{ subnet | ipsubnet(20, 0) }}
192.168.0.0/20

# Last subnet
# {{ subnet | ipsubnet(20, -1) }}
192.168.240.0/20

# Fifth subnet
# {{ subnet | ipsubnet(20, 5) }}
192.168.80.0/20

# Fifth to last subnet
# {{ subnet | ipsubnet(20, -5) }}
192.168.176.0/20

Если вы укажете IP-адрес вместо подсети и размер подсети в качестве первого аргумента, фильтр ipsubnet() вернёт наибольшую подсеть, содержащую этот IP-адрес:

# {{ address | ipsubnet(20) }}
192.168.144.0/20

Указав индекс в качестве второго аргумента, вы можете выбирать всё более мелкие подсети:

# First subnet
# {{ address | ipsubnet(18, 0) }}
192.168.128.0/18

# Last subnet
# {{ address | ipsubnet(18, -1) }}
192.168.144.4/31

# Fifth subnet
# {{ address | ipsubnet(18, 5) }}
192.168.144.0/23

# Fifth to last subnet
# {{ address | ipsubnet(18, -5) }}
192.168.144.0/27

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

# The rank of the IP in the subnet (the IP is the 36870nth /32 of the subnet)
# {{ address | ipsubnet(subnet) }}
36870

# The rank in the /24 that contain the address
# {{ address | ipsubnet('192.168.144.0/24') }}
6

# An IP with the subnet in the first /30 in a /24
# {{ '192.168.144.1/30' | ipsubnet('192.168.144.0/24') }}
1

# The fifth subnet /30 in a /24
# {{ '192.168.144.16/30' | ipsubnet('192.168.144.0/24') }}
5

Если вторая подсеть не включает первую подсеть, фильтр ipsubnet() генерирует ошибку.

Вы можете использовать фильтр ipsubnet() вместе с фильтром ipaddr() для, например, разделения заданного префикса /48 на более мелкие подсети /64:

# {{ '193.0.2.0' | ipaddr('6to4') | ipsubnet(64, 58820) | ipaddr('1') }}
2002:c100:200:e5c4::1/64

Из-за размера подсетей IPv6 итерация по всем подсетям для поиска нужной может занять некоторое время на более медленных компьютерах, в зависимости от разницы в размерах подсетей.

Объединение подсетей

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

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

{{ ['192.168.0.0/17', '192.168.128.0/17', '192.168.128.1' ] | cidr_merge }}
# => ['192.168.0.0/16']

{{ ['192.168.0.0/24', '192.168.1.0/24', '192.168.3.0/24'] | cidr_merge }}
# => ['192.168.0.0/23', '192.168.3.0/24']

Изменение действия с «объединение» на «объединение в диапазон» вернёт наименьшую подсеть, которая содержит все входы:

{{ ['192.168.0.0/24', '192.168.3.0/24'] | cidr_merge('span') }}
# => '192.168.0.0/22'

{{ ['192.168.1.42', '192.168.42.1'] | cidr_merge('span') }}
# => '192.168.0.0/18'

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

Вы можете использовать фильтр hwaddr() для проверки, является ли заданная строка MAC-адресом, или преобразовать её между различными форматами. Примеры:

# Example MAC address
macaddress = '1a:2b:3c:4d:5e:6f'

# Check if given string is a MAC address
# {{ macaddress | hwaddr }}
1a:2b:3c:4d:5e:6f

# Convert MAC address to PostgreSQL format
# {{ macaddress | hwaddr('pgsql') }}
1a2b3c:4d5e6f

# Convert MAC address to Cisco format
# {{ macaddress | hwaddr('cisco') }}
1a2b.3c4d.5e6f

Поддерживаемые форматы приводят к следующим преобразованиям для MAC-адреса 1a:2b:3c:4d:5e:6f:

bare: 1A2B3C4D5E6F
bool: True
int: 28772997619311
cisco: 1a2b.3c4d.5e6f
eui48 or win: 1A-2B-3C-4D-5E-6F
linux or unix: 1a:2b:3c:4d:5e:6f:
pgsql, postgresql, or psql: 1a2b3c:4d5e6f

См. также

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

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

Spec-Zone.ru

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