mirror of
https://github.com/ansible-collections/community.docker.git
synced 2025-12-16 11:58:43 +00:00
Rewrite the docker_network module (#408)
* 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>
This commit is contained in:
parent
a406b08981
commit
4c026307fb
4
changelogs/fragments/408-docker-api.yml
Normal file
4
changelogs/fragments/408-docker-api.yml
Normal file
@ -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)."
|
||||||
@ -146,8 +146,7 @@ options:
|
|||||||
type: bool
|
type: bool
|
||||||
|
|
||||||
extends_documentation_fragment:
|
extends_documentation_fragment:
|
||||||
- community.docker.docker
|
- community.docker.docker.api_documentation
|
||||||
- community.docker.docker.docker_py_1_documentation
|
|
||||||
|
|
||||||
|
|
||||||
notes:
|
notes:
|
||||||
@ -165,7 +164,6 @@ author:
|
|||||||
- "Dave Bendit (@DBendit)"
|
- "Dave Bendit (@DBendit)"
|
||||||
|
|
||||||
requirements:
|
requirements:
|
||||||
- "L(Docker SDK for Python,https://docker-py.readthedocs.io/en/stable/) >= 1.10.0"
|
|
||||||
- "Docker API >= 1.25"
|
- "Docker API >= 1.25"
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@ -254,27 +252,16 @@ import traceback
|
|||||||
|
|
||||||
from ansible.module_utils.common.text.converters import to_native
|
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_api import (
|
||||||
|
|
||||||
from ansible_collections.community.docker.plugins.module_utils.common import (
|
|
||||||
AnsibleDockerClient,
|
AnsibleDockerClient,
|
||||||
RequestException,
|
RequestException,
|
||||||
docker_version,
|
|
||||||
)
|
)
|
||||||
from ansible_collections.community.docker.plugins.module_utils.util import (
|
from ansible_collections.community.docker.plugins.module_utils.util import (
|
||||||
DockerBaseClass,
|
DockerBaseClass,
|
||||||
DifferenceTracker,
|
DifferenceTracker,
|
||||||
clean_dict_booleans_for_docker_api,
|
clean_dict_booleans_for_docker_api,
|
||||||
)
|
)
|
||||||
|
from ansible_collections.community.docker.plugins.module_utils._api.errors import DockerException
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
class TaskParameters(DockerBaseClass):
|
class TaskParameters(DockerBaseClass):
|
||||||
@ -496,45 +483,48 @@ class DockerNetworkManager(object):
|
|||||||
|
|
||||||
def create_network(self):
|
def create_network(self):
|
||||||
if not self.existing_network:
|
if not self.existing_network:
|
||||||
params = dict(
|
data = {
|
||||||
driver=self.parameters.driver,
|
'Name': self.parameters.name,
|
||||||
options=self.parameters.driver_options,
|
'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 = []
|
ipam_pools = []
|
||||||
if self.parameters.ipam_config:
|
if self.parameters.ipam_config:
|
||||||
for ipam_pool in self.parameters.ipam_config:
|
for ipam_pool in self.parameters.ipam_config:
|
||||||
if LooseVersion(docker_version) >= LooseVersion('2.0.0'):
|
ipam_pools.append({
|
||||||
ipam_pools.append(IPAMPool(**ipam_pool))
|
'Subnet': ipam_pool['subnet'],
|
||||||
else:
|
'IPRange': ipam_pool['iprange'],
|
||||||
ipam_pools.append(utils.create_ipam_pool(**ipam_pool))
|
'Gateway': ipam_pool['gateway'],
|
||||||
|
'AuxiliaryAddresses': ipam_pool['aux_addresses'],
|
||||||
|
})
|
||||||
|
|
||||||
if self.parameters.ipam_driver or self.parameters.ipam_driver_options or ipam_pools:
|
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
|
# Only add IPAM if a driver was specified or if IPAM parameters were
|
||||||
# were specified. Leaving this parameter away can significantly speed up
|
# specified. Leaving this parameter out can significantly speed up
|
||||||
# creation; on my machine creation with this option needs ~15 seconds,
|
# creation; on my machine creation with this option needs ~15 seconds,
|
||||||
# and without just a few seconds.
|
# and without just a few seconds.
|
||||||
if LooseVersion(docker_version) >= LooseVersion('2.0.0'):
|
data['IPAM'] = {
|
||||||
params['ipam'] = IPAMConfig(driver=self.parameters.ipam_driver,
|
'Driver': self.parameters.ipam_driver,
|
||||||
pool_configs=ipam_pools,
|
'Config': ipam_pools or [],
|
||||||
options=self.parameters.ipam_driver_options)
|
'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
|
|
||||||
|
|
||||||
if not self.check_mode:
|
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.client.report_warnings(resp, ['Warning'])
|
||||||
self.existing_network = self.client.get_network(network_id=resp['Id'])
|
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))
|
self.results['actions'].append("Created network %s with driver %s" % (self.parameters.name, self.parameters.driver))
|
||||||
@ -544,7 +534,7 @@ class DockerNetworkManager(object):
|
|||||||
if self.existing_network:
|
if self.existing_network:
|
||||||
self.disconnect_all_containers()
|
self.disconnect_all_containers()
|
||||||
if not self.check_mode:
|
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['actions'].append("Removed network %s" % (self.parameters.name,))
|
||||||
self.results['changed'] = True
|
self.results['changed'] = True
|
||||||
|
|
||||||
@ -557,12 +547,14 @@ class DockerNetworkManager(object):
|
|||||||
for name in self.parameters.connected:
|
for name in self.parameters.connected:
|
||||||
if not self.is_container_connected(name):
|
if not self.is_container_connected(name):
|
||||||
if not self.check_mode:
|
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['actions'].append("Connected container %s" % (name,))
|
||||||
self.results['changed'] = True
|
self.results['changed'] = True
|
||||||
self.diff_tracker.add('connected.{0}'.format(name),
|
self.diff_tracker.add('connected.{0}'.format(name), parameter=True, active=False)
|
||||||
parameter=True,
|
|
||||||
active=False)
|
|
||||||
|
|
||||||
def disconnect_missing(self):
|
def disconnect_missing(self):
|
||||||
if not self.existing_network:
|
if not self.existing_network:
|
||||||
@ -584,7 +576,8 @@ class DockerNetworkManager(object):
|
|||||||
|
|
||||||
def disconnect_container(self, container_name):
|
def disconnect_container(self, container_name):
|
||||||
if not self.check_mode:
|
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['actions'].append("Disconnected container %s" % (container_name,))
|
||||||
self.results['changed'] = True
|
self.results['changed'] = True
|
||||||
self.diff_tracker.add('connected.{0}'.format(container_name),
|
self.diff_tracker.add('connected.{0}'.format(container_name),
|
||||||
@ -648,15 +641,13 @@ def main():
|
|||||||
)
|
)
|
||||||
|
|
||||||
option_minimal_versions = dict(
|
option_minimal_versions = dict(
|
||||||
scope=dict(docker_py_version='2.6.0', docker_api_version='1.30'),
|
scope=dict(docker_api_version='1.30'),
|
||||||
attachable=dict(docker_py_version='2.0.0', docker_api_version='1.26'),
|
attachable=dict(docker_api_version='1.26'),
|
||||||
ipam_driver_options=dict(docker_py_version='2.0.0'),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
client = AnsibleDockerClient(
|
client = AnsibleDockerClient(
|
||||||
argument_spec=argument_spec,
|
argument_spec=argument_spec,
|
||||||
supports_check_mode=True,
|
supports_check_mode=True,
|
||||||
min_docker_version='1.10.0',
|
|
||||||
# "The docker server >= 1.10.0"
|
# "The docker server >= 1.10.0"
|
||||||
option_minimal_versions=option_minimal_versions,
|
option_minimal_versions=option_minimal_versions,
|
||||||
)
|
)
|
||||||
@ -665,10 +656,10 @@ def main():
|
|||||||
cm = DockerNetworkManager(client)
|
cm = DockerNetworkManager(client)
|
||||||
client.module.exit_json(**cm.results)
|
client.module.exit_json(**cm.results)
|
||||||
except DockerException as e:
|
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:
|
except RequestException as e:
|
||||||
client.fail(
|
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())
|
exception=traceback.format_exc())
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -42,7 +42,7 @@
|
|||||||
force: yes
|
force: yes
|
||||||
loop: "{{ dnetworks }}"
|
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!"
|
- 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)
|
||||||
|
|||||||
@ -303,10 +303,3 @@
|
|||||||
- network_1 is changed
|
- network_1 is changed
|
||||||
- network_2 is not changed
|
- network_2 is not changed
|
||||||
- network_3 is 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', '<')
|
|
||||||
|
|||||||
@ -144,9 +144,6 @@
|
|||||||
state: absent
|
state: absent
|
||||||
force: yes
|
force: yes
|
||||||
|
|
||||||
# Requirements for docker_swarm
|
|
||||||
when: docker_py_version is version('2.6.0', '>=')
|
|
||||||
|
|
||||||
####################################################################
|
####################################################################
|
||||||
## attachable ######################################################
|
## attachable ######################################################
|
||||||
####################################################################
|
####################################################################
|
||||||
@ -183,13 +180,6 @@
|
|||||||
- attachable_1 is changed
|
- attachable_1 is changed
|
||||||
- attachable_2 is not changed
|
- attachable_2 is not changed
|
||||||
- attachable_3 is 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 ##########################################################
|
## labels ##########################################################
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user