Skip to content

Commit

Permalink
Rewrite the docker_network module (#408)
Browse files Browse the repository at this point in the history
* Rewrite the docker_network module.

* Update plugins/modules/docker_network.py

Co-authored-by: Brian Scholer <1260690+briantist@users.noreply.github.com>

* Improve error messages.

Co-authored-by: Brian Scholer <1260690+briantist@users.noreply.github.com>
  • Loading branch information
felixfontein and briantist committed Jul 6, 2022
1 parent a406b08 commit 4c02630
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 76 deletions.
4 changes: 4 additions & 0 deletions changelogs/fragments/408-docker-api.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
major_changes:
- "docker_network - no longer uses the Docker SDK for Python. It requires ``requests`` to be installed,
and depending on the features used has some more requirements. If the Docker SDK for Python is installed,
these requirements are likely met (https://github.com/ansible-collections/community.docker/pull/408)."
105 changes: 48 additions & 57 deletions plugins/modules/docker_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,7 @@
type: bool
extends_documentation_fragment:
- community.docker.docker
- community.docker.docker.docker_py_1_documentation
- community.docker.docker.api_documentation
notes:
Expand All @@ -165,7 +164,6 @@
- "Dave Bendit (@DBendit)"
requirements:
- "L(Docker SDK for Python,https://docker-py.readthedocs.io/en/stable/) >= 1.10.0"
- "Docker API >= 1.25"
'''

Expand Down Expand Up @@ -254,27 +252,16 @@

from ansible.module_utils.common.text.converters import to_native

from ansible_collections.community.docker.plugins.module_utils.version import LooseVersion

from ansible_collections.community.docker.plugins.module_utils.common import (
from ansible_collections.community.docker.plugins.module_utils.common_api import (
AnsibleDockerClient,
RequestException,
docker_version,
)
from ansible_collections.community.docker.plugins.module_utils.util import (
DockerBaseClass,
DifferenceTracker,
clean_dict_booleans_for_docker_api,
)

try:
from docker import utils
from docker.errors import DockerException
if LooseVersion(docker_version) >= LooseVersion('2.0.0'):
from docker.types import IPAMPool, IPAMConfig
except Exception:
# missing Docker SDK for Python handled in ansible.module_utils.docker.common
pass
from ansible_collections.community.docker.plugins.module_utils._api.errors import DockerException


class TaskParameters(DockerBaseClass):
Expand Down Expand Up @@ -496,45 +483,48 @@ def has_different_config(self, net):

def create_network(self):
if not self.existing_network:
params = dict(
driver=self.parameters.driver,
options=self.parameters.driver_options,
)
data = {
'Name': self.parameters.name,
'Driver': self.parameters.driver,
'Options': self.parameters.driver_options,
'IPAM': None,
'CheckDuplicate': None,
}

if self.parameters.enable_ipv6:
data['EnableIPv6'] = True
if self.parameters.internal:
data['Internal'] = True
if self.parameters.scope is not None:
data['Scope'] = self.parameters.scope
if self.parameters.attachable is not None:
data['Attachable'] = self.parameters.attachable
if self.parameters.labels is not None:
data["Labels"] = self.parameters.labels

ipam_pools = []
if self.parameters.ipam_config:
for ipam_pool in self.parameters.ipam_config:
if LooseVersion(docker_version) >= LooseVersion('2.0.0'):
ipam_pools.append(IPAMPool(**ipam_pool))
else:
ipam_pools.append(utils.create_ipam_pool(**ipam_pool))
ipam_pools.append({
'Subnet': ipam_pool['subnet'],
'IPRange': ipam_pool['iprange'],
'Gateway': ipam_pool['gateway'],
'AuxiliaryAddresses': ipam_pool['aux_addresses'],
})

if self.parameters.ipam_driver or self.parameters.ipam_driver_options or ipam_pools:
# Only add ipam parameter if a driver was specified or if IPAM parameters
# were specified. Leaving this parameter away can significantly speed up
# Only add IPAM if a driver was specified or if IPAM parameters were
# specified. Leaving this parameter out can significantly speed up
# creation; on my machine creation with this option needs ~15 seconds,
# and without just a few seconds.
if LooseVersion(docker_version) >= LooseVersion('2.0.0'):
params['ipam'] = IPAMConfig(driver=self.parameters.ipam_driver,
pool_configs=ipam_pools,
options=self.parameters.ipam_driver_options)
else:
params['ipam'] = utils.create_ipam_config(driver=self.parameters.ipam_driver,
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 self.parameters.scope is not None:
params['scope'] = self.parameters.scope
if self.parameters.attachable is not None:
params['attachable'] = self.parameters.attachable
if self.parameters.labels:
params['labels'] = self.parameters.labels
data['IPAM'] = {
'Driver': self.parameters.ipam_driver,
'Config': ipam_pools or [],
'Options': self.parameters.ipam_driver_options,
}

if not self.check_mode:
resp = self.client.create_network(self.parameters.name, **params)
resp = self.client.post_json_to_json('/networks/create', data=data)
self.client.report_warnings(resp, ['Warning'])
self.existing_network = self.client.get_network(network_id=resp['Id'])
self.results['actions'].append("Created network %s with driver %s" % (self.parameters.name, self.parameters.driver))
Expand All @@ -544,7 +534,7 @@ def remove_network(self):
if self.existing_network:
self.disconnect_all_containers()
if not self.check_mode:
self.client.remove_network(self.parameters.name)
self.client.delete_call('/networks/{0}', self.parameters.name)
self.results['actions'].append("Removed network %s" % (self.parameters.name,))
self.results['changed'] = True

Expand All @@ -557,12 +547,14 @@ def connect_containers(self):
for name in self.parameters.connected:
if not self.is_container_connected(name):
if not self.check_mode:
self.client.connect_container_to_network(name, self.parameters.name)
data = {
"Container": name,
"EndpointConfig": None,
}
self.client.post_json('/networks/{0}/connect', self.parameters.name, data=data)
self.results['actions'].append("Connected container %s" % (name,))
self.results['changed'] = True
self.diff_tracker.add('connected.{0}'.format(name),
parameter=True,
active=False)
self.diff_tracker.add('connected.{0}'.format(name), parameter=True, active=False)

def disconnect_missing(self):
if not self.existing_network:
Expand All @@ -584,7 +576,8 @@ def disconnect_all_containers(self):

def disconnect_container(self, container_name):
if not self.check_mode:
self.client.disconnect_container_from_network(container_name, self.parameters.name)
data = {"Container": container_name}
self.client.post_json('/networks/{0}/disconnect', self.parameters.name, data=data)
self.results['actions'].append("Disconnected container %s" % (container_name,))
self.results['changed'] = True
self.diff_tracker.add('connected.{0}'.format(container_name),
Expand Down Expand Up @@ -648,15 +641,13 @@ def main():
)

option_minimal_versions = dict(
scope=dict(docker_py_version='2.6.0', docker_api_version='1.30'),
attachable=dict(docker_py_version='2.0.0', docker_api_version='1.26'),
ipam_driver_options=dict(docker_py_version='2.0.0'),
scope=dict(docker_api_version='1.30'),
attachable=dict(docker_api_version='1.26'),
)

client = AnsibleDockerClient(
argument_spec=argument_spec,
supports_check_mode=True,
min_docker_version='1.10.0',
# "The docker server >= 1.10.0"
option_minimal_versions=option_minimal_versions,
)
Expand All @@ -665,10 +656,10 @@ def main():
cm = DockerNetworkManager(client)
client.module.exit_json(**cm.results)
except DockerException as e:
client.fail('An unexpected docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
client.fail('An unexpected Docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
except RequestException as e:
client.fail(
'An unexpected requests error occurred when Docker SDK for Python tried to talk to the docker daemon: {0}'.format(to_native(e)),
'An unexpected requests error occurred when trying to talk to the Docker daemon: {0}'.format(to_native(e)),
exception=traceback.format_exc())


Expand Down
4 changes: 2 additions & 2 deletions tests/integration/targets/docker_network/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
force: yes
loop: "{{ dnetworks }}"

when: docker_py_version is version('1.10.0', '>=') and docker_api_version is version('1.25', '>=')
when: docker_api_version is version('1.25', '>=') # FIXME: find out API version!

- fail: msg="Too old docker / docker-py version to run docker_network tests!"
when: not(docker_py_version is version('1.10.0', '>=') and docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
when: not(docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
7 changes: 0 additions & 7 deletions tests/integration/targets/docker_network/tasks/tests/ipam.yml
Original file line number Diff line number Diff line change
Expand Up @@ -303,10 +303,3 @@
- network_1 is changed
- network_2 is not changed
- network_3 is changed
when: docker_py_version is version('2.0.0', '>=')
- assert:
that:
- network_1 is failed
- "('version is ' ~ docker_py_version ~ ' ') in network_1.msg"
- "'Minimum version required is 2.0.0 ' in network_1.msg"
when: docker_py_version is version('2.0.0', '<')
10 changes: 0 additions & 10 deletions tests/integration/targets/docker_network/tasks/tests/options.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,6 @@
state: absent
force: yes

# Requirements for docker_swarm
when: docker_py_version is version('2.6.0', '>=')

####################################################################
## attachable ######################################################
####################################################################
Expand Down Expand Up @@ -183,13 +180,6 @@
- attachable_1 is changed
- attachable_2 is not changed
- attachable_3 is changed
when: docker_py_version is version('2.0.0', '>=')
- assert:
that:
- attachable_1 is failed
- "('version is ' ~ docker_py_version ~ ' ') in attachable_1.msg"
- "'Minimum version required is 2.0.0 ' in attachable_1.msg"
when: docker_py_version is version('2.0.0', '<')

####################################################################
## labels ##########################################################
Expand Down

0 comments on commit 4c02630

Please sign in to comment.