Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite the docker_network module #408

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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