diff --git a/changelogs/fragments/999-add-ingress-option-to-docker_network-module.yml b/changelogs/fragments/999-add-ingress-option-to-docker_network-module.yml new file mode 100644 index 00000000..af284427 --- /dev/null +++ b/changelogs/fragments/999-add-ingress-option-to-docker_network-module.yml @@ -0,0 +1,6 @@ +minor_changes: + - docker_network - added ``ingress`` option (https://github.com/ansible-collections/community.docker/pull/999). +bugfixes: + - docker_network - containers are only reconnected to a network if they really exist (https://github.com/ansible-collections/community.docker/pull/999). + - docker_network - enabled "force" option in Docker network container disconnect API call (https://github.com/ansible-collections/community.docker/pull/999). + - docker_network - added waiting while container actually disconnect from Swarm network (https://github.com/ansible-collections/community.docker/pull/999). diff --git a/plugins/modules/docker_network.py b/plugins/modules/docker_network.py index 00b79cd2..914847c4 100644 --- a/plugins/modules/docker_network.py +++ b/plugins/modules/docker_network.py @@ -96,6 +96,12 @@ options: - Enable IPv6 networking. type: bool + ingress: + description: + - Enable Swarm routing-mesh. + type: bool + version_added: 4.2.0 + ipam_driver: description: - Specify an IPAM driver. @@ -273,6 +279,7 @@ network: import re import traceback +import time from ansible.module_utils.common.text.converters import to_native @@ -311,6 +318,7 @@ class TaskParameters(DockerBaseClass): self.enable_ipv6 = None self.scope = None self.attachable = None + self.ingress = None for key, value in client.module.params.items(): setattr(self, key, value) @@ -507,6 +515,10 @@ class DockerNetworkManager(object): differences.add('attachable', parameter=self.parameters.attachable, active=net.get('Attachable')) + if self.parameters.ingress is not None and self.parameters.ingress != net.get('Ingress', False): + differences.add('ingress', + parameter=self.parameters.ingress, + active=net.get('Ingress')) if self.parameters.labels: if not net.get('Labels'): differences.add('labels', @@ -543,6 +555,8 @@ class DockerNetworkManager(object): data['Scope'] = self.parameters.scope if self.parameters.attachable is not None: data['Attachable'] = self.parameters.attachable + if self.parameters.ingress is not None: + data['Ingress'] = self.parameters.ingress if self.parameters.labels is not None: data["Labels"] = self.parameters.labels @@ -579,6 +593,9 @@ class DockerNetworkManager(object): self.disconnect_all_containers() if not self.check_mode: self.client.delete_call('/networks/{0}', self.parameters.name) + if self.existing_network.get('Scope', 'local') == 'swarm': + while self.get_existing_network(): + time.sleep(0.1) self.results['actions'].append("Removed network %s" % (self.parameters.name,)) self.results['changed'] = True @@ -587,9 +604,21 @@ class DockerNetworkManager(object): return False return container_name in container_names_in_network(self.existing_network) + def is_container_exist(self, container_name): + try: + container = self.client.get_container(container_name) + return bool(container) + + except DockerException as e: + self.client.fail('An unexpected Docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc()) + except RequestException as e: + self.client.fail( + 'An unexpected requests error occurred when trying to talk to the Docker daemon: {0}'.format(to_native(e)), + exception=traceback.format_exc()) + def connect_containers(self): for name in self.parameters.connected: - if not self.is_container_connected(name): + if not self.is_container_connected(name) and self.is_container_exist(name): if not self.check_mode: data = { "Container": name, @@ -620,7 +649,7 @@ class DockerNetworkManager(object): def disconnect_container(self, container_name): if not self.check_mode: - data = {"Container": container_name} + data = {"Container": container_name, "Force": True} 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 @@ -684,6 +713,7 @@ def main(): debug=dict(type='bool', default=False), scope=dict(type='str', choices=['local', 'global', 'swarm']), attachable=dict(type='bool'), + ingress=dict(type='bool'), ) option_minimal_versions = dict( @@ -700,7 +730,6 @@ def main(): option_minimal_versions=option_minimal_versions, ) sanitize_labels(client.module.params['labels'], 'labels', client) - try: cm = DockerNetworkManager(client) client.module.exit_json(**cm.results) diff --git a/tests/integration/targets/docker_network/tasks/tests/overlay.yml b/tests/integration/targets/docker_network/tasks/tests/overlay.yml index 59d79cc0..e936cd60 100644 --- a/tests/integration/targets/docker_network/tasks/tests/overlay.yml +++ b/tests/integration/targets/docker_network/tasks/tests/overlay.yml @@ -10,10 +10,6 @@ set_fact: dnetworks: "{{ dnetworks + [nname_1] }}" -#################################################################### -## overlay ######################################################### -#################################################################### - - block: # Overlay networks require swarm initialization before they'll work - name: swarm @@ -21,6 +17,10 @@ state: present advertise_addr: "{{ ansible_default_ipv4.address | default('127.0.0.1') }}" +#################################################################### +## overlay ######################################################### +#################################################################### + - name: overlay docker_network: name: "{{ nname_1 }}" @@ -55,6 +55,48 @@ - overlay_2 is not changed - overlay_3 is changed +#################################################################### +## ingress ######################################################### +#################################################################### + + - name: cleanup default swarm ingress network + docker_network: + name: ingress + state: absent + + - name: ingress + docker_network: + name: "{{ nname_1 }}" + driver: overlay + ingress: true + register: ingress_1 + + - name: ingress (idempotency) + docker_network: + name: "{{ nname_1 }}" + driver: overlay + ingress: true + register: ingress_2 + + - name: ingress (change) + docker_network: + name: "{{ nname_1 }}" + driver: overlay + ingress: false + register: ingress_3 + + - name: cleanup network + docker_network: + name: "{{ nname_1 }}" + state: absent + force: true + + - assert: + that: + - ingress_1 is changed + - ingress_2 is not changed + - ingress_3 is changed + always: - name: cleanup swarm docker_swarm: