Add 'ingress' option to docker_network module (#999)

* Add 'ingress' option to docker_network module

* sanity fixes

* add changelog fragment

* Update plugins/modules/docker_network.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update changelogs/fragments/999-add-ingress-option-to-docker_network-module.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/docker_network.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* move 'ingress' tests to overlay.yml

* move Sworm init and Swarm cleanup to block

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
Maksim Vorobyev 2024-12-04 23:39:09 +03:00 committed by GitHub
parent d8548ef55f
commit e19812917d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 84 additions and 7 deletions

View File

@ -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).

View File

@ -96,6 +96,12 @@ options:
- Enable IPv6 networking. - Enable IPv6 networking.
type: bool type: bool
ingress:
description:
- Enable Swarm routing-mesh.
type: bool
version_added: 4.2.0
ipam_driver: ipam_driver:
description: description:
- Specify an IPAM driver. - Specify an IPAM driver.
@ -273,6 +279,7 @@ network:
import re import re
import traceback import traceback
import time
from ansible.module_utils.common.text.converters import to_native from ansible.module_utils.common.text.converters import to_native
@ -311,6 +318,7 @@ class TaskParameters(DockerBaseClass):
self.enable_ipv6 = None self.enable_ipv6 = None
self.scope = None self.scope = None
self.attachable = None self.attachable = None
self.ingress = 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)
@ -507,6 +515,10 @@ class DockerNetworkManager(object):
differences.add('attachable', differences.add('attachable',
parameter=self.parameters.attachable, parameter=self.parameters.attachable,
active=net.get('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 self.parameters.labels:
if not net.get('Labels'): if not net.get('Labels'):
differences.add('labels', differences.add('labels',
@ -543,6 +555,8 @@ class DockerNetworkManager(object):
data['Scope'] = self.parameters.scope data['Scope'] = self.parameters.scope
if self.parameters.attachable is not None: if self.parameters.attachable is not None:
data['Attachable'] = self.parameters.attachable data['Attachable'] = self.parameters.attachable
if self.parameters.ingress is not None:
data['Ingress'] = self.parameters.ingress
if self.parameters.labels is not None: if self.parameters.labels is not None:
data["Labels"] = self.parameters.labels data["Labels"] = self.parameters.labels
@ -579,6 +593,9 @@ class DockerNetworkManager(object):
self.disconnect_all_containers() self.disconnect_all_containers()
if not self.check_mode: if not self.check_mode:
self.client.delete_call('/networks/{0}', self.parameters.name) 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['actions'].append("Removed network %s" % (self.parameters.name,))
self.results['changed'] = True self.results['changed'] = True
@ -587,9 +604,21 @@ class DockerNetworkManager(object):
return False return False
return container_name in container_names_in_network(self.existing_network) 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): def connect_containers(self):
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) and self.is_container_exist(name):
if not self.check_mode: if not self.check_mode:
data = { data = {
"Container": name, "Container": name,
@ -620,7 +649,7 @@ 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:
data = {"Container": container_name} data = {"Container": container_name, "Force": True}
self.client.post_json('/networks/{0}/disconnect', self.parameters.name, data=data) 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
@ -684,6 +713,7 @@ def main():
debug=dict(type='bool', default=False), debug=dict(type='bool', default=False),
scope=dict(type='str', choices=['local', 'global', 'swarm']), scope=dict(type='str', choices=['local', 'global', 'swarm']),
attachable=dict(type='bool'), attachable=dict(type='bool'),
ingress=dict(type='bool'),
) )
option_minimal_versions = dict( option_minimal_versions = dict(
@ -700,7 +730,6 @@ def main():
option_minimal_versions=option_minimal_versions, option_minimal_versions=option_minimal_versions,
) )
sanitize_labels(client.module.params['labels'], 'labels', client) sanitize_labels(client.module.params['labels'], 'labels', client)
try: try:
cm = DockerNetworkManager(client) cm = DockerNetworkManager(client)
client.module.exit_json(**cm.results) client.module.exit_json(**cm.results)

View File

@ -10,10 +10,6 @@
set_fact: set_fact:
dnetworks: "{{ dnetworks + [nname_1] }}" dnetworks: "{{ dnetworks + [nname_1] }}"
####################################################################
## overlay #########################################################
####################################################################
- block: - block:
# Overlay networks require swarm initialization before they'll work # Overlay networks require swarm initialization before they'll work
- name: swarm - name: swarm
@ -21,6 +17,10 @@
state: present state: present
advertise_addr: "{{ ansible_default_ipv4.address | default('127.0.0.1') }}" advertise_addr: "{{ ansible_default_ipv4.address | default('127.0.0.1') }}"
####################################################################
## overlay #########################################################
####################################################################
- name: overlay - name: overlay
docker_network: docker_network:
name: "{{ nname_1 }}" name: "{{ nname_1 }}"
@ -55,6 +55,48 @@
- overlay_2 is not changed - overlay_2 is not changed
- overlay_3 is 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: always:
- name: cleanup swarm - name: cleanup swarm
docker_swarm: docker_swarm: