Spec-Zone.ru › Ansible 2.4

ipaddr фильтр

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

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

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

pip install netaddr
  • Базовые тесты
  • Фильтрация списков
  • Оборачивание IPv6 адресов в квадратные скобки [ ]
  • Базовые запросы
  • Получение информации о хостах и сетях
  • Получение информации из значений хост/префикс
  • Преобразование масок подсети в CIDR-нотацию
  • Преобразование IP-адресов
  • Преобразование IPv4-адреса в 6to4-адрес
  • Работа с подсетями
  • Фильтр 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 gateway host)
# {{ test_list | ipaddr('net') | ipaddr('1') }}
['192.168.32.1/24', '2001:db8:32c:faad::1/64']

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

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

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

# {{ 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-адресами:

# {{ test_list | 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-адресов:

# 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-нотацию

Учитывая подсеть в виде сетевого адреса и маски подсети, её можно преобразовать в CIDR-нотацию, используя ipaddr(). Это может быть полезно для преобразования собранных фактов 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'

Преобразование 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']

Вы можете преобразовать 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

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

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

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

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

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

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

См. также

Playbooks
Вступление к playbooks
Filters
Введение к фильтрам Jinja2 и их применению
Conditionals
Условные операторы в playbooks
Variables
Всё о переменных
Loops
Циклы в playbooks
Roles
Организация playbooks по ролям
Best Practices
Рекомендации по разработке playbooks
Список рассылки пользователей
У вас есть вопрос? Заходите на форум!
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.4/playbooks_filters_ipaddr.html

Spec-Zone.ru

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