diff --git a/changelogs/fragments/763-docker_container-mac_address.yml b/changelogs/fragments/763-docker_container-mac_address.yml new file mode 100644 index 00000000..c7e6d752 --- /dev/null +++ b/changelogs/fragments/763-docker_container-mac_address.yml @@ -0,0 +1,4 @@ +minor_changes: + - "docker_container - add ``networks[].mac_address`` option for Docker API 1.44+. + Note that Docker API 1.44 no longer uses the global ``mac_address`` option, this new option is the only way to set the MAC address for a container + (https://github.com/ansible-collections/community.docker/pull/763)." diff --git a/plugins/module_utils/module_container/base.py b/plugins/module_utils/module_container/base.py index cd38a07f..0f776aa5 100644 --- a/plugins/module_utils/module_container/base.py +++ b/plugins/module_utils/module_container/base.py @@ -177,6 +177,7 @@ class OptionGroup(object): class Engine(object): min_api_version = None # string or None min_api_version_obj = None # LooseVersion object or None + extra_option_minimal_versions = None # dict[str, dict[str, Any]] or None @abc.abstractmethod def get_value(self, module, container, api_version, options, image, host_info): @@ -509,6 +510,8 @@ def _preprocess_networks(module, values): parsed_link = (link, link) parsed_links.append(tuple(parsed_link)) network['links'] = parsed_links + if network['mac_address']: + network['mac_address'] = network['mac_address'].replace('-', ':') return values @@ -945,7 +948,7 @@ OPTION_HOSTNAME = ( ) OPTION_IMAGE = ( - OptionGroup(preprocess=_preprocess_networks) + OptionGroup() .add_option('image', type='str') ) @@ -1019,6 +1022,7 @@ OPTION_NETWORK = ( ipv6_address=dict(type='str'), aliases=dict(type='list', elements='str'), links=dict(type='list', elements='str'), + mac_address=dict(type='str'), )) ) diff --git a/plugins/module_utils/module_container/docker_api.py b/plugins/module_utils/module_container/docker_api.py index 7ba27e1f..61a5500c 100644 --- a/plugins/module_utils/module_container/docker_api.py +++ b/plugins/module_utils/module_container/docker_api.py @@ -170,6 +170,8 @@ class DockerAPIEngineDriver(EngineDriver): for option in options.options: if not option.not_an_ansible_option: option_minimal_versions[option.name] = {'docker_api_version': engine.min_api_version} + if engine.extra_option_minimal_versions: + option_minimal_versions.update(engine.extra_option_minimal_versions) active_options.append(options) @@ -244,7 +246,13 @@ class DockerAPIEngineDriver(EngineDriver): def connect_container_to_network(self, client, container_id, network_id, parameters=None): parameters = (parameters or {}).copy() params = {} - for para, dest_para in {'ipv4_address': 'IPv4Address', 'ipv6_address': 'IPv6Address', 'links': 'Links', 'aliases': 'Aliases'}.items(): + for para, dest_para in { + 'ipv4_address': 'IPv4Address', + 'ipv6_address': 'IPv6Address', + 'links': 'Links', + 'aliases': 'Aliases', + 'mac_address': 'MacAddress', + }.items(): value = parameters.pop(para, None) if value: if para == 'links': @@ -398,6 +406,7 @@ class DockerAPIEngine(Engine): compare_value=None, needs_container_image=None, needs_host_info=None, + extra_option_minimal_versions=None, ): self.min_api_version = min_api_version self.min_api_version_obj = None if min_api_version is None else LooseVersion(min_api_version) @@ -414,6 +423,7 @@ class DockerAPIEngine(Engine): self.needs_host_info = needs_host_info or (lambda values: False) if compare_value is not None: self.compare_value = compare_value + self.extra_option_minimal_versions = extra_option_minimal_versions @classmethod def config_value( @@ -1330,6 +1340,12 @@ OPTION_NETWORK.add_engine('docker_api', DockerAPIEngine( get_value=_get_values_network, set_value=_set_values_network, ignore_mismatching_result=_ignore_mismatching_network_result, + extra_option_minimal_versions={ + 'networks.mac_address': { + 'docker_api_version': '1.44', + 'detect_usage': lambda c: any(net_info.get('mac_address') is not None for net_info in (c.module.params['networks'] or [])), + }, + }, )) OPTION_OOM_KILLER.add_engine('docker_api', DockerAPIEngine.host_config_value('OomKillDisable')) diff --git a/plugins/module_utils/module_container/module.py b/plugins/module_utils/module_container/module.py index 9eb38964..94dd07de 100644 --- a/plugins/module_utils/module_container/module.py +++ b/plugins/module_utils/module_container/module.py @@ -614,6 +614,8 @@ class ContainerManager(DockerBaseClass): expected_links.append("%s:%s" % (link, alias)) if not compare_generic(expected_links, network_info.get('Links'), 'allow_more_present', 'set'): diff = True + if network.get('mac_address') and network['mac_address'] != network_info.get('MacAddress'): + diff = True if diff: different = True differences.append(dict( @@ -623,7 +625,8 @@ class ContainerManager(DockerBaseClass): ipv4_address=network_info_ipam.get('IPv4Address'), ipv6_address=network_info_ipam.get('IPv6Address'), aliases=network_info.get('Aliases'), - links=network_info.get('Links') + links=network_info.get('Links'), + mac_address=network_info.get('MacAddress'), ) )) return different, differences diff --git a/plugins/modules/docker_container.py b/plugins/modules/docker_container.py index 7135f594..adf07aaf 100644 --- a/plugins/modules/docker_container.py +++ b/plugins/modules/docker_container.py @@ -525,6 +525,7 @@ options: description: - Container MAC address (for example, V(92:d0:c6:0a:29:33)). - Note that the global container-wide MAC address is deprecated and no longer used since Docker API version 1.44. + - Use O(networks[].mac_address) instead. type: str memory: description: @@ -690,6 +691,12 @@ options: can be used in the network to reach this container. type: list elements: str + mac_address: + description: + - Endpoint MAC address (for example, V(92:d0:c6:0a:29:33)). + - This is only available for Docker API version 1.44 and later. + type: str + version_added: 3.6.0 networks_cli_compatible: description: - "If O(networks_cli_compatible=true) (default), this module will behave as