[docker_network] add ipv6 support (#47492)
* [docker_network] add ipv6 support * docker_network: review ipam_options * docker_network: fix requirements * docker_network: fix deprecation notice * docker_network: add minimum docker version change * docker_network: remove trailing whitespace * docker_network: revert rename of network_four #discussion_r228707101 * docker_network: refactor IPAM config comparison #discussion_r228707255, #discussion_r228707280 * docker_network: correct spelling of IPv4 and IPv6 #discussion_r228707114, #discussion_r228707138 * docker_network: manually remove networks #discussion_r228709051 * docker_network: refactor enable_ipv6 condition #discussion_r228707317 * docker_network: add mutually_exclusive #discussion_r228707185 * docker_network: fix iprange #discussion_r228709072 * docker_network: add auxiliary addresses in examples and tests * docker_network: link to docker docs #discussion_r228707018 * docker_network: remove list default #discussion_r228707060, #discussion_r228709091 * docker_network: introduce params syntax for create_network() #discussion_r228709031 * docker_network: beautify code * docker_network: resolve change requests * docker_network: add yaml header * docker_networking: fix get_ip_version * docker_network: extend CIDR test * docker_network: use backported unittest2 for python 2.6 * docker_network: migrate unittest to pytest
This commit is contained in:
parent
80ca779aa7
commit
00bab2d24d
6 changed files with 386 additions and 44 deletions
|
@ -1,4 +1,3 @@
|
||||||
---
|
---
|
||||||
minor_changes:
|
minor_changes:
|
||||||
- "docker_network - ``internal`` is now used to set the ``Internal`` property of the docker network during creation."
|
- "docker_network - ``internal`` is now used to set the ``Internal`` property of the docker network during creation."
|
||||||
- "docker_network - Minimum docker-py version increased from ``1.8.0`` to ``1.9.0``."
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
minor_changes:
|
||||||
|
- "docker_network - Add support for IPv6 networks."
|
||||||
|
deprecated_features:
|
||||||
|
- "docker_network - Deprecate ``ipam_options`` in favour of ``ipam_config``."
|
4
changelogs/fragments/docker_network-requirements.yaml
Normal file
4
changelogs/fragments/docker_network-requirements.yaml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
minor_changes:
|
||||||
|
- "docker_network - Minimum docker-py version increased from ``1.8.0`` to ``1.10.0``."
|
||||||
|
- "docker_network - Minimum docker server version increased from ``1.9.0`` to ``1.10.0``."
|
|
@ -62,6 +62,14 @@ options:
|
||||||
aliases:
|
aliases:
|
||||||
- incremental
|
- incremental
|
||||||
|
|
||||||
|
enable_ipv6:
|
||||||
|
version_added: 2.8
|
||||||
|
description:
|
||||||
|
- Enable IPv6 networking.
|
||||||
|
type: bool
|
||||||
|
default: null
|
||||||
|
required: false
|
||||||
|
|
||||||
ipam_driver:
|
ipam_driver:
|
||||||
description:
|
description:
|
||||||
- Specify an IPAM driver.
|
- Specify an IPAM driver.
|
||||||
|
@ -69,6 +77,18 @@ options:
|
||||||
ipam_options:
|
ipam_options:
|
||||||
description:
|
description:
|
||||||
- Dictionary of IPAM options.
|
- Dictionary of IPAM options.
|
||||||
|
- Deprecated in 2.8, will be removed in 2.12. Use parameter ``ipam_config`` instead. In Docker 1.10.0, IPAM
|
||||||
|
options were introduced (see L(here,https://github.com/moby/moby/pull/17316)). This module parameter addresses
|
||||||
|
the IPAM config not the newly introduced IPAM options.
|
||||||
|
|
||||||
|
ipam_config:
|
||||||
|
version_added: 2.8
|
||||||
|
description:
|
||||||
|
- List of IPAM config blocks. Consult
|
||||||
|
L(Docker docs,https://docs.docker.com/compose/compose-file/compose-file-v2/#ipam) for valid options and values.
|
||||||
|
type: list
|
||||||
|
default: null
|
||||||
|
required: false
|
||||||
|
|
||||||
state:
|
state:
|
||||||
description:
|
description:
|
||||||
|
@ -104,7 +124,7 @@ author:
|
||||||
|
|
||||||
requirements:
|
requirements:
|
||||||
- "python >= 2.6"
|
- "python >= 2.6"
|
||||||
- "docker-py >= 1.9.0"
|
- "docker-py >= 1.10.0"
|
||||||
- "Please note that the L(docker-py,https://pypi.org/project/docker-py/) Python
|
- "Please note that the L(docker-py,https://pypi.org/project/docker-py/) Python
|
||||||
module has been superseded by L(docker,https://pypi.org/project/docker/)
|
module has been superseded by L(docker,https://pypi.org/project/docker/)
|
||||||
(see L(here,https://github.com/docker/docker-py/issues/1310) for details).
|
(see L(here,https://github.com/docker/docker-py/issues/1310) for details).
|
||||||
|
@ -113,7 +133,7 @@ requirements:
|
||||||
be installed at the same time. Also note that when both modules are installed
|
be installed at the same time. Also note that when both modules are installed
|
||||||
and one of them is uninstalled, the other might no longer function and a
|
and one of them is uninstalled, the other might no longer function and a
|
||||||
reinstall of it is required."
|
reinstall of it is required."
|
||||||
- "The docker server >= 1.9.0"
|
- "The docker server >= 1.10.0"
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = '''
|
EXAMPLES = '''
|
||||||
|
@ -141,15 +161,37 @@ EXAMPLES = '''
|
||||||
- container_a
|
- container_a
|
||||||
appends: yes
|
appends: yes
|
||||||
|
|
||||||
- name: Create a network with options
|
- name: Create a network with driver options
|
||||||
docker_network:
|
docker_network:
|
||||||
name: network_two
|
name: network_two
|
||||||
driver_options:
|
driver_options:
|
||||||
com.docker.network.bridge.name: net2
|
com.docker.network.bridge.name: net2
|
||||||
ipam_options:
|
|
||||||
subnet: '172.3.26.0/16'
|
- name: Create a network with custom IPAM config
|
||||||
gateway: 172.3.26.1
|
docker_network:
|
||||||
iprange: '192.168.1.0/24'
|
name: network_three
|
||||||
|
ipam_config:
|
||||||
|
- subnet: 172.3.27.0/24
|
||||||
|
gateway: 172.3.27.2
|
||||||
|
iprange: 172.3.27.0/26
|
||||||
|
aux_addresses:
|
||||||
|
host1: 172.3.27.3
|
||||||
|
host2: 172.3.27.4
|
||||||
|
|
||||||
|
- name: Create a network with IPv6 IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: network_ipv6_one
|
||||||
|
enable_ipv6: yes
|
||||||
|
ipam_config:
|
||||||
|
- subnet: fdd1:ac8c:0557:7ce1::/64
|
||||||
|
|
||||||
|
- name: Create a network with IPv6 and custom IPv4 IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: network_ipv6_two
|
||||||
|
enable_ipv6: yes
|
||||||
|
ipam_config:
|
||||||
|
- subnet: 172.4.27.0/24
|
||||||
|
- subnet: fdd1:ac8c:0557:7ce2::/64
|
||||||
|
|
||||||
- name: Delete a network, disconnecting all containers
|
- name: Delete a network, disconnecting all containers
|
||||||
docker_network:
|
docker_network:
|
||||||
|
@ -166,6 +208,8 @@ facts:
|
||||||
sample: {}
|
sample: {}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
from ansible.module_utils.docker_common import AnsibleDockerClient, DockerBaseClass, HAS_DOCKER_PY_2, HAS_DOCKER_PY_3
|
from ansible.module_utils.docker_common import AnsibleDockerClient, DockerBaseClass, HAS_DOCKER_PY_2, HAS_DOCKER_PY_3
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -189,10 +233,12 @@ class TaskParameters(DockerBaseClass):
|
||||||
self.driver_options = None
|
self.driver_options = None
|
||||||
self.ipam_driver = None
|
self.ipam_driver = None
|
||||||
self.ipam_options = None
|
self.ipam_options = None
|
||||||
|
self.ipam_config = None
|
||||||
self.appends = None
|
self.appends = None
|
||||||
self.force = None
|
self.force = None
|
||||||
self.internal = None
|
self.internal = None
|
||||||
self.debug = None
|
self.debug = None
|
||||||
|
self.enable_ipv6 = None
|
||||||
|
|
||||||
for key, value in client.module.params.items():
|
for key, value in client.module.params.items():
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
|
@ -202,6 +248,26 @@ def container_names_in_network(network):
|
||||||
return [c['Name'] for c in network['Containers'].values()] if network['Containers'] else []
|
return [c['Name'] for c in network['Containers'].values()] if network['Containers'] else []
|
||||||
|
|
||||||
|
|
||||||
|
CIDR_IPV4 = re.compile(r'^([0-9]{1,3}\.){3}[0-9]{1,3}/([0-9]|[1-2][0-9]|3[0-2])$')
|
||||||
|
CIDR_IPV6 = re.compile(r'^[0-9a-fA-F:]+/([0-9]|[1-9][0-9]|1[0-2][0-9])$')
|
||||||
|
|
||||||
|
|
||||||
|
def get_ip_version(cidr):
|
||||||
|
"""Gets the IP version of a CIDR string
|
||||||
|
|
||||||
|
:param cidr: Valid CIDR
|
||||||
|
:type cidr: str
|
||||||
|
:return: ``ipv4`` or ``ipv6``
|
||||||
|
:rtype: str
|
||||||
|
:raises ValueError: If ``cidr`` is not a valid CIDR
|
||||||
|
"""
|
||||||
|
if CIDR_IPV4.match(cidr):
|
||||||
|
return 'ipv4'
|
||||||
|
elif CIDR_IPV6.match(cidr):
|
||||||
|
return 'ipv6'
|
||||||
|
raise ValueError('"{0}" is not a valid CIDR'.format(cidr))
|
||||||
|
|
||||||
|
|
||||||
class DockerNetworkManager(object):
|
class DockerNetworkManager(object):
|
||||||
|
|
||||||
def __init__(self, client):
|
def __init__(self, client):
|
||||||
|
@ -219,6 +285,9 @@ class DockerNetworkManager(object):
|
||||||
if not self.parameters.connected and self.existing_network:
|
if not self.parameters.connected and self.existing_network:
|
||||||
self.parameters.connected = container_names_in_network(self.existing_network)
|
self.parameters.connected = container_names_in_network(self.existing_network)
|
||||||
|
|
||||||
|
if self.parameters.ipam_options:
|
||||||
|
self.parameters.ipam_config = [self.parameters.ipam_options]
|
||||||
|
|
||||||
state = self.parameters.state
|
state = self.parameters.state
|
||||||
if state == 'present':
|
if state == 'present':
|
||||||
self.present()
|
self.present()
|
||||||
|
@ -253,29 +322,41 @@ class DockerNetworkManager(object):
|
||||||
if not (key in net['Options']) or value != net['Options'][key]:
|
if not (key in net['Options']) or value != net['Options'][key]:
|
||||||
different = True
|
different = True
|
||||||
differences.append('driver_options.%s' % key)
|
differences.append('driver_options.%s' % key)
|
||||||
|
|
||||||
if self.parameters.ipam_driver:
|
if self.parameters.ipam_driver:
|
||||||
if not net.get('IPAM') or net['IPAM']['Driver'] != self.parameters.ipam_driver:
|
if not net.get('IPAM') or net['IPAM']['Driver'] != self.parameters.ipam_driver:
|
||||||
different = True
|
different = True
|
||||||
differences.append('ipam_driver')
|
differences.append('ipam_driver')
|
||||||
if self.parameters.ipam_options:
|
|
||||||
if not net.get('IPAM') or not net['IPAM'].get('Config'):
|
if self.parameters.ipam_config is not None and self.parameters.ipam_config:
|
||||||
|
if not net.get('IPAM') or not net['IPAM']['Config']:
|
||||||
different = True
|
different = True
|
||||||
differences.append('ipam_options')
|
differences.append('ipam_config')
|
||||||
else:
|
else:
|
||||||
for key, value in self.parameters.ipam_options.items():
|
for idx, ipam_config in enumerate(self.parameters.ipam_config):
|
||||||
camelkey = None
|
net_config = dict()
|
||||||
for net_key in net['IPAM']['Config'][0]:
|
try:
|
||||||
if key == net_key.lower():
|
ip_version = get_ip_version(ipam_config['subnet'])
|
||||||
camelkey = net_key
|
for net_ipam_config in net['IPAM']['Config']:
|
||||||
break
|
if ip_version == get_ip_version(net_ipam_config['Subnet']):
|
||||||
if not camelkey:
|
net_config = net_ipam_config
|
||||||
# key not found
|
except ValueError as e:
|
||||||
different = True
|
self.client.fail(str(e))
|
||||||
differences.append('ipam_options.%s' % key)
|
|
||||||
elif net['IPAM']['Config'][0].get(camelkey) != value:
|
for key, value in ipam_config.items():
|
||||||
# key has different value
|
camelkey = None
|
||||||
different = True
|
for net_key in net_config:
|
||||||
differences.append('ipam_options.%s' % key)
|
if key == net_key.lower():
|
||||||
|
camelkey = net_key
|
||||||
|
break
|
||||||
|
if not camelkey or net_config.get(camelkey) != value:
|
||||||
|
different = True
|
||||||
|
differences.append('ipam_config[%s].%s' % (idx, key))
|
||||||
|
|
||||||
|
if self.parameters.enable_ipv6 is not None and self.parameters.enable_ipv6 != net.get('EnableIPv6', False):
|
||||||
|
different = True
|
||||||
|
differences.append('enable_ipv6')
|
||||||
|
|
||||||
if self.parameters.internal is not None:
|
if self.parameters.internal is not None:
|
||||||
if self.parameters.internal:
|
if self.parameters.internal:
|
||||||
if not net.get('Internal'):
|
if not net.get('Internal'):
|
||||||
|
@ -289,26 +370,33 @@ class DockerNetworkManager(object):
|
||||||
|
|
||||||
def create_network(self):
|
def create_network(self):
|
||||||
if not self.existing_network:
|
if not self.existing_network:
|
||||||
|
params = dict(
|
||||||
|
driver=self.parameters.driver,
|
||||||
|
options=self.parameters.driver_options,
|
||||||
|
)
|
||||||
|
|
||||||
ipam_pools = []
|
ipam_pools = []
|
||||||
if self.parameters.ipam_options:
|
if self.parameters.ipam_config:
|
||||||
if HAS_DOCKER_PY_2 or HAS_DOCKER_PY_3:
|
for ipam_pool in self.parameters.ipam_config:
|
||||||
ipam_pools.append(IPAMPool(**self.parameters.ipam_options))
|
if HAS_DOCKER_PY_2 or HAS_DOCKER_PY_3:
|
||||||
else:
|
ipam_pools.append(IPAMPool(**ipam_pool))
|
||||||
ipam_pools.append(utils.create_ipam_pool(**self.parameters.ipam_options))
|
else:
|
||||||
|
ipam_pools.append(utils.create_ipam_pool(**ipam_pool))
|
||||||
|
|
||||||
if HAS_DOCKER_PY_2 or HAS_DOCKER_PY_3:
|
if HAS_DOCKER_PY_2 or HAS_DOCKER_PY_3:
|
||||||
ipam_config = IPAMConfig(driver=self.parameters.ipam_driver,
|
params['ipam'] = IPAMConfig(driver=self.parameters.ipam_driver,
|
||||||
pool_configs=ipam_pools)
|
pool_configs=ipam_pools)
|
||||||
else:
|
else:
|
||||||
ipam_config = utils.create_ipam_config(driver=self.parameters.ipam_driver,
|
params['ipam'] = utils.create_ipam_config(driver=self.parameters.ipam_driver,
|
||||||
pool_configs=ipam_pools)
|
pool_configs=ipam_pools)
|
||||||
|
|
||||||
|
if self.parameters.enable_ipv6 is not None:
|
||||||
|
params['enable_ipv6'] = self.parameters.enable_ipv6
|
||||||
|
if self.parameters.internal is not None:
|
||||||
|
params['internal'] = self.parameters.internal
|
||||||
|
|
||||||
if not self.check_mode:
|
if not self.check_mode:
|
||||||
resp = self.client.create_network(self.parameters.network_name,
|
resp = self.client.create_network(self.parameters.network_name, **params)
|
||||||
driver=self.parameters.driver,
|
|
||||||
options=self.parameters.driver_options,
|
|
||||||
ipam=ipam_config,
|
|
||||||
internal=self.parameters.internal)
|
|
||||||
|
|
||||||
self.existing_network = self.client.inspect_network(resp['Id'])
|
self.existing_network = self.client.inspect_network(resp['Id'])
|
||||||
self.results['actions'].append("Created network %s with driver %s" % (self.parameters.network_name, self.parameters.driver))
|
self.results['actions'].append("Created network %s with driver %s" % (self.parameters.network_name, self.parameters.driver))
|
||||||
|
@ -393,17 +481,24 @@ def main():
|
||||||
driver_options=dict(type='dict', default={}),
|
driver_options=dict(type='dict', default={}),
|
||||||
force=dict(type='bool', default=False),
|
force=dict(type='bool', default=False),
|
||||||
appends=dict(type='bool', default=False, aliases=['incremental']),
|
appends=dict(type='bool', default=False, aliases=['incremental']),
|
||||||
ipam_driver=dict(type='str', default=None),
|
ipam_driver=dict(type='str'),
|
||||||
ipam_options=dict(type='dict', default={}),
|
ipam_options=dict(type='dict', default={}, removed_in_version='2.12'),
|
||||||
internal=dict(type='bool', default=None),
|
ipam_config=dict(type='list', elements='dict'),
|
||||||
|
enable_ipv6=dict(type='bool'),
|
||||||
|
internal=dict(type='bool'),
|
||||||
debug=dict(type='bool', default=False)
|
debug=dict(type='bool', default=False)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
mutually_exclusive = [
|
||||||
|
('ipam_config', 'ipam_options')
|
||||||
|
]
|
||||||
|
|
||||||
client = AnsibleDockerClient(
|
client = AnsibleDockerClient(
|
||||||
argument_spec=argument_spec,
|
argument_spec=argument_spec,
|
||||||
|
mutually_exclusive=mutually_exclusive,
|
||||||
supports_check_mode=True,
|
supports_check_mode=True,
|
||||||
min_docker_version='1.9.0'
|
min_docker_version='1.10.0'
|
||||||
# "The docker server >= 1.9.0"
|
# "The docker server >= 1.10.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
cm = DockerNetworkManager(client)
|
cm = DockerNetworkManager(client)
|
||||||
|
|
212
test/integration/targets/docker_network/tasks/tests/ipam.yml
Normal file
212
test/integration/targets/docker_network/tasks/tests/ipam.yml
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
---
|
||||||
|
- name: Registering network names
|
||||||
|
set_fact:
|
||||||
|
nname_ipam_0: "{{ name_prefix ~ '-network-ipam-0' }}"
|
||||||
|
nname_ipam_1: "{{ name_prefix ~ '-network-ipam-1' }}"
|
||||||
|
nname_ipam_2: "{{ name_prefix ~ '-network-ipam-2' }}"
|
||||||
|
nname_ipam_3: "{{ name_prefix ~ '-network-ipam-3' }}"
|
||||||
|
|
||||||
|
- name: Registering network names
|
||||||
|
set_fact:
|
||||||
|
dnetworks: "{{ dnetworks }} + [nname_ipam_0, nname_ipam_1, nname_ipam_2, nname_ipam_3]"
|
||||||
|
|
||||||
|
|
||||||
|
#################### network-ipam-0 deprecated ####################
|
||||||
|
|
||||||
|
- name: Create network with ipam_config and deprecated ipam_options
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_0 }}"
|
||||||
|
ipam_options:
|
||||||
|
subnet: 172.3.29.0/24
|
||||||
|
ipam_config:
|
||||||
|
- subnet: 172.3.29.0/24
|
||||||
|
register: network
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- network is failed
|
||||||
|
- "network.msg == 'parameters are mutually exclusive: ipam_config, ipam_options'"
|
||||||
|
|
||||||
|
- name: Create network with deprecated custom IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_0 }}"
|
||||||
|
ipam_options:
|
||||||
|
subnet: 172.3.29.0/24
|
||||||
|
register: network
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- network is changed
|
||||||
|
|
||||||
|
- name: Change subnet of network with deprecated custom IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_0 }}"
|
||||||
|
ipam_options:
|
||||||
|
subnet: 172.3.30.0/24
|
||||||
|
register: network
|
||||||
|
diff: yes
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- network is changed
|
||||||
|
- network['diff'] | length == 1
|
||||||
|
- network['diff'][0] == "ipam_config[0].subnet"
|
||||||
|
|
||||||
|
- name: Cleanup network with ipam_config and deprecated ipam_options
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_0 }}"
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
|
||||||
|
#################### network-ipam-1 ####################
|
||||||
|
- name: Create network with custom IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_1 }}"
|
||||||
|
ipam_config:
|
||||||
|
- subnet: 172.3.27.0/24
|
||||||
|
gateway: 172.3.27.2
|
||||||
|
iprange: 172.3.27.0/26
|
||||||
|
aux_addresses:
|
||||||
|
host1: 172.3.27.3
|
||||||
|
host2: 172.3.27.4
|
||||||
|
register: network
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- network is changed
|
||||||
|
|
||||||
|
- name: Change subnet, gateway, iprange and auxiliary addresses of network with custom IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_1 }}"
|
||||||
|
ipam_config:
|
||||||
|
- subnet: 172.3.28.0/24
|
||||||
|
gateway: 172.3.28.2
|
||||||
|
iprange: 172.3.28.0/26
|
||||||
|
aux_addresses:
|
||||||
|
host1: 172.3.28.3
|
||||||
|
register: network
|
||||||
|
diff: yes
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- network is changed
|
||||||
|
- network['diff'] | length == 4
|
||||||
|
- '"ipam_config[0].subnet" in network["diff"]'
|
||||||
|
- '"ipam_config[0].gateway" in network["diff"]'
|
||||||
|
- '"ipam_config[0].iprange" in network["diff"]'
|
||||||
|
- '"ipam_config[0].aux_addresses" in network["diff"]'
|
||||||
|
|
||||||
|
- name: Remove gateway and iprange of network with custom IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_1 }}"
|
||||||
|
ipam_config:
|
||||||
|
- subnet: 172.3.28.0/24
|
||||||
|
register: network
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- network is not changed
|
||||||
|
|
||||||
|
- name: Cleanup network with custom IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_1 }}"
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
|
||||||
|
#################### network-ipam-2 ####################
|
||||||
|
|
||||||
|
- name: Create network with IPv6 IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_2 }}"
|
||||||
|
enable_ipv6: yes
|
||||||
|
ipam_config:
|
||||||
|
- subnet: fdd1:ac8c:0557:7ce0::/64
|
||||||
|
register: network
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- network is changed
|
||||||
|
|
||||||
|
- name: Change subnet of network with IPv6 IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_2 }}"
|
||||||
|
enable_ipv6: yes
|
||||||
|
ipam_config:
|
||||||
|
- subnet: fdd1:ac8c:0557:7ce1::/64
|
||||||
|
register: network
|
||||||
|
diff: yes
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- network is changed
|
||||||
|
- network['diff'] | length == 1
|
||||||
|
- network['diff'][0] == "ipam_config[0].subnet"
|
||||||
|
|
||||||
|
- name: Change subnet of network with IPv6 IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_2 }}"
|
||||||
|
enable_ipv6: yes
|
||||||
|
ipam_config:
|
||||||
|
- subnet: "fdd1:ac8c:0557:7ce1::"
|
||||||
|
register: network
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- network is failed
|
||||||
|
- "network.msg == '\"fdd1:ac8c:0557:7ce1::\" is not a valid CIDR'"
|
||||||
|
|
||||||
|
- name: Cleanup network with IPv6 IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_2 }}"
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
|
||||||
|
#################### network-ipam-3 ####################
|
||||||
|
|
||||||
|
- name: Create network with IPv6 and custom IPv4 IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_3 }}"
|
||||||
|
enable_ipv6: yes
|
||||||
|
ipam_config:
|
||||||
|
- subnet: 172.4.27.0/24
|
||||||
|
- subnet: fdd1:ac8c:0557:7ce2::/64
|
||||||
|
register: network
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- network is changed
|
||||||
|
|
||||||
|
- name: Change subnet order of network with IPv6 and custom IPv4 IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_3 }}"
|
||||||
|
enable_ipv6: yes
|
||||||
|
ipam_config:
|
||||||
|
- subnet: fdd1:ac8c:0557:7ce2::/64
|
||||||
|
- subnet: 172.4.27.0/24
|
||||||
|
register: network
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- network is not changed
|
||||||
|
|
||||||
|
- name: Remove IPv6 from network with custom IPv4 and IPv6 IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_3 }}"
|
||||||
|
enable_ipv6: no
|
||||||
|
ipam_config:
|
||||||
|
- subnet: 172.4.27.0/24
|
||||||
|
register: network
|
||||||
|
diff: yes
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- network is changed
|
||||||
|
- network['diff'] | length == 1
|
||||||
|
- network['diff'][0] == "enable_ipv6"
|
||||||
|
|
||||||
|
- name: Cleanup network with IPv6 and custom IPv4 IPAM config
|
||||||
|
docker_network:
|
||||||
|
name: "{{ nname_ipam_3 }}"
|
||||||
|
state: absent
|
27
test/units/modules/cloud/docker/test_docker_network.py
Normal file
27
test/units/modules/cloud/docker/test_docker_network.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
"""Unit tests for docker_network."""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from ansible.modules.cloud.docker.docker_network import get_ip_version
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("cidr,expected", [
|
||||||
|
('192.168.0.1/16', 'ipv4'),
|
||||||
|
('192.168.0.1/24', 'ipv4'),
|
||||||
|
('192.168.0.1/32', 'ipv4'),
|
||||||
|
('fdd1:ac8c:0557:7ce2::/64', 'ipv6'),
|
||||||
|
('fdd1:ac8c:0557:7ce2::/128', 'ipv6'),
|
||||||
|
])
|
||||||
|
def test_get_ip_version_positives(cidr, expected):
|
||||||
|
assert get_ip_version(cidr) == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("cidr", [
|
||||||
|
'192.168.0.1',
|
||||||
|
'192.168.0.1/34',
|
||||||
|
'192.168.0.1/asd',
|
||||||
|
'fdd1:ac8c:0557:7ce2::',
|
||||||
|
])
|
||||||
|
def test_get_ip_version_negatives(cidr):
|
||||||
|
with pytest.raises(ValueError) as e:
|
||||||
|
get_ip_version(cidr)
|
||||||
|
assert '"{0}" is not a valid CIDR'.format(cidr) == str(e.value)
|
Loading…
Reference in a new issue