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']
Как видите, даже если некоторые значения содержали IP-адрес с префиксом 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-адресами:
# {{ 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-адресов, установленных на интерфейсе:
# 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
См. также
- Работа с Playbook
- Введение в Playbook
- Фильтры
- Введение в Jinja2 фильтры и их использование
- Условные операторы
- Условные операторы в Playbook
- Переменные
- Все о переменных
- Циклы
- Использование циклов в Playbook
- Роли
- Организация Playbook по ролям
- Рекомендации
- Рекомендации по использованию Playbook
- Список рассылки пользователей
- У вас есть вопрос? Загляните в группу Google!
- irc.freenode.net
- IRC-чат-канал #ansible
© 2012–2018 Michael DeHaan
© 2018–2019 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/ansible/2.5/user_guide/playbooks_filters_ipaddr.html