From 8cd028bd8e5cc59019d8acc9c485de5a4fa2c461 Mon Sep 17 00:00:00 2001 From: chouseknecht Date: Mon, 30 May 2016 11:56:29 -0400 Subject: [PATCH 1/8] First pass at implementing networks parameter. Also added purge_networks option to remove container from networks not included in networks param. --- cloud/docker/docker_container.py | 169 ++++++++++++++++++++++++------- 1 file changed, 135 insertions(+), 34 deletions(-) diff --git a/cloud/docker/docker_container.py b/cloud/docker/docker_container.py index e71300a197a..3d22ebfc4ea 100644 --- a/cloud/docker/docker_container.py +++ b/cloud/docker/docker_container.py @@ -253,6 +253,15 @@ options: - none default: null required: false + networks: + description: + - List of networks to which the container is a member. + - Each network is dict with keys C(name), C(ipv4_address), C(ipv6_address), C(links), C(aliases). + - For each network C(name) is required. Optional parameters C(links) and C(aliases) are type list. + - For more information see U(https://docs.docker.com/engine/userguide/networking/dockernetworks/). + - To remove a container from one or more networks, use the C(purge_networks) option. + default: null + required: false oom_killer: description: - Whether or not to disable OOM Killer for the container. @@ -290,6 +299,11 @@ options: - If true, always pull the latest version of an image. Otherwise, will only pull an image when missing. default: false required: false + purge_networks: + description: + - Remove the container from all networks not included in C(networks) parameter. + default: false + required: false read_only: description: - Mount the container's root file system as read-only. @@ -619,6 +633,7 @@ class TaskParameters(DockerBaseClass): self.paused = None self.pid_mode = None self.privileged = None + self.purge_networks = None self.pull = None self.read_only = None self.recreate = None @@ -670,6 +685,14 @@ class TaskParameters(DockerBaseClass): self.exp_links = None self._parse_volumes() + if self.networks: + for network in self.networks: + if not network.get('name'): + self.fail("Parameter error: network must have a name attribute.") + id = self._get_network_id(network['name']) + if not id: + self.fail("Parameter error: network named %s could not be found. Does it exist?" % network['name']) + def fail(self, msg): self.client.module.fail_json(msg=msg) @@ -950,6 +973,16 @@ class TaskParameters(DockerBaseClass): final_env[name] = str(value) return final_env + def _get_network_id(self, network_name): + network_id = None + try: + for network in self.client.networks(names=[network_name]): + network_id = network['Id'] + except Exception, exc: + self.fail("Error getting network id for %s - %s" % (network_name, str(exc))) + return network_id + + class Container(DockerBaseClass): @@ -1170,26 +1203,50 @@ class Container(DockerBaseClass): different = (len(differences) > 0) return different, differences - def has_missing_networks(self): + def has_network_differences(self): ''' - Check if the container is connected to requested networks + Check if the container is connected to requested networks with expected options: links, aliases, ipv4, ipv6 ''' - missing_networks = [] - missing = False + different = False + differences = [] if not self.parameters.networks: - return missing, missing_networks + return different, differences if not self.container.get('NetworkSettings'): self.fail("has_missing_networks: Error parsing container properties. NetworkSettings missing.") connected_networks = self.container['NetworkSettings']['Networks'] - for network, config in self.parameters.networks.iteritems(): - if connected_networks.get(network, None) is None: - missing_networks.append(network) - if len(missing_networks) > 0: - missing = True - return missing, missing_networks + for network in self.parameters.networks: + if connected_networks.get(network['name'], None) is None: + different = True + differences.append(dict( + parameter=network, + container=None + )) + else: + diff = False + if network.get('ipv4_address') and network['ipv4_address'] != connected_networks[network['name']].get('IPAddress'): + diff = True + if network.get('ipv6_address') and network['ipv6_address'] != connected_networks[network['name']].get('GlobalIPv6Address'): + diff = True + if network.get('aliases') and network['aliases'] != connected_networks[network['name']].get('Aliases'): + diff = True + if network.get('links') and network['links'] != connected_networks[network['name']].get('Links'): + diff = True + if diff: + different = True + differences.append(dict( + prarameter=network, + container=dict( + name=network['name'], + ipv4_address=connected_networks[network['name']].get('IPAddress'), + ipv6_address=connected_networks[network['name']].get('GlobalIPv6Address'), + aliases=connected_networks[network['name']].get('Aliases'), + links=connected_networks[network['name']].get('Links') + ) + )) + return different, differences def has_extra_networks(self): ''' @@ -1198,19 +1255,20 @@ class Container(DockerBaseClass): extra_networks = [] extra = False - if not self.parameters.networks: - return extra, extra_networks - if not self.container.get('NetworkSettings'): self.fail("has_extra_networks: Error parsing container properties. NetworkSettings missing.") - connected_networks = self.container['NetworkSettings']['Networks'] - for network in connected_networks: - if network not in ('bridge', 'host') and not network.startswith('container:'): - if network not in self.parameters.networks: - extra_networks.append(network) - if len(extra_networks) > 0: - extra = True + connected_networks = self.container['NetworkSettings'].get('Networks') + if connected_networks: + for network, network_config in connected_networks.iteritems(): + keep = False + if self.parameters.networks: + for expected_network in self.parameters.networks: + if expected_network['name'] == network: + keep = True + if not keep: + extra = True + extra_networks.append(dict(name=netowork, id=network_config['NetworkID'])) return extra, extra_networks def _get_expected_entrypoint(self, image): @@ -1422,9 +1480,25 @@ class ContainerManager(DockerBaseClass): self.diff['image_different'] = True container = self.update_limits(container) - container = self.update_networks(container) - # TODO implement has_extra_networks + has_network_differences, network_differences = container.has_network_differences() + if has_network_differences: + if self.diff.get('differences'): + self.diff['differences'].append(dict(network_differences=network_differences)) + else: + self.diff['differences'] = dict(network_differences=network_differences) + self.results['changed'] = True + container = self.update_networks(container, network_differences) + + if self.parameters.purge_networks: + has_extra_networks, extra_networks = container.has_extra_networks() + if has_extra_networks: + if self.diff.get('differences'): + self.diff['differences'].append(dict(purge_networks=extra_networks)) + else: + self.diff['differences'] = dict(purge_networks=extra_networks) + self.results['changed'] = True + container = self.remove_networks(container, extra_networks) if state == 'started' and not container.running: container = self.container_start(container.Id) @@ -1488,16 +1562,42 @@ class ContainerManager(DockerBaseClass): return self._get_container(container.Id) return container - def update_networks(self, container): - networks_missing, missing_networks = container.has_missing_networks() - if networks_missing: - self.log("networks missing") - self.log(missing_networks, pretty_print=True) - if networks_missing and not self.check_mode: - for network in missing_networks: - self.connect_container_to_network(container.Id, network) - return self._get_container(container.Id) - return container + def update_networks(self, container, differences): + for diff in differences: + # remove the container from the network, if connected + if diff.get('container'): + self.results['actions'].append(dict(removed_from_network=diff['parameter']['name'])) + if not self.check_mode: + try: + self.client.disconnect_container_from_network(container.Id, diff['parameter']['id']) + except Exception, exc: + self.fail("Error disconnecting container from network %s - %s" % (diff['parameter']['name'], + str(exc))) + # connect to the network + params = dict( + ipv4_address=diff['parameter'].get('ipv4_address', None), + ipv6_address=diff['parameter'].get('ipv6_address', None), + links=diff['parameter'].get('links', None), + aliases=diff['parameter'].get('aliases', None) + ) + self.results['actions'].append(dict(added_to_network=diff['parameter']['name'], network_parameters=params)) + if not self.check_mode: + try: + self.client.connect_container_to_network(container.Id, diff['parameter']['id'], **params) + except Exception, exc: + self.fail("Error connecting container to network %s - %s" % (diff['parameter']['name'], str(exc))) + return self._get_container(container.Id) + + def remove_networks(self, container, networks): + for network in networks: + self.results['actions'].append(dict(removed_from_network=network['name'])) + if not self.check_mode: + try: + self.client.disconnect_container_from_network(container.Id, network['id']) + except Exception, exc: + self.fail("Error disconnecting container from network %s - %s" % (network['name'], + str(exc))) + return self._get_container(container.Id) def container_create(self, image, create_parameters): self.log("create container") @@ -1627,13 +1727,14 @@ def main(): memory_swappiness=dict(type='int'), name=dict(type='str', required=True), network_mode=dict(type='str'), - networks=dict(type='dict'), + networks=dict(type='list'), oom_killer=dict(type='bool'), paused=dict(type='bool', default=False), pid_mode=dict(type='str'), privileged=dict(type='bool', default=False), published_ports=dict(type='list', aliases=['ports']), pull=dict(type='bool', default=False), + purge_networks=dict(type='bool', deault=False), read_only=dict(type='bool', default=False), recreate=dict(type='bool', default=False), restart=dict(type='bool', default=False), From 3292121e6de0646a6e52209b08d221059feda12f Mon Sep 17 00:00:00 2001 From: chouseknecht Date: Mon, 30 May 2016 15:04:43 -0400 Subject: [PATCH 2/8] Fixed issues post testing. --- cloud/docker/docker_container.py | 61 ++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/cloud/docker/docker_container.py b/cloud/docker/docker_container.py index 3d22ebfc4ea..afa3f4e6546 100644 --- a/cloud/docker/docker_container.py +++ b/cloud/docker/docker_container.py @@ -689,8 +689,8 @@ class TaskParameters(DockerBaseClass): for network in self.networks: if not network.get('name'): self.fail("Parameter error: network must have a name attribute.") - id = self._get_network_id(network['name']) - if not id: + network['id'] = self._get_network_id(network['name']) + if not network['id']: self.fail("Parameter error: network named %s could not be found. Does it exist?" % network['name']) def fail(self, msg): @@ -1231,13 +1231,14 @@ class Container(DockerBaseClass): if network.get('ipv6_address') and network['ipv6_address'] != connected_networks[network['name']].get('GlobalIPv6Address'): diff = True if network.get('aliases') and network['aliases'] != connected_networks[network['name']].get('Aliases'): + self.log('network aliases different') diff = True if network.get('links') and network['links'] != connected_networks[network['name']].get('Links'): diff = True if diff: different = True differences.append(dict( - prarameter=network, + parameter=network, container=dict( name=network['name'], ipv4_address=connected_networks[network['name']].get('IPAddress'), @@ -1246,6 +1247,7 @@ class Container(DockerBaseClass): links=connected_networks[network['name']].get('Links') ) )) + self.log(differences, pretty_print=True) return different, differences def has_extra_networks(self): @@ -1268,7 +1270,7 @@ class Container(DockerBaseClass): keep = True if not keep: extra = True - extra_networks.append(dict(name=netowork, id=network_config['NetworkID'])) + extra_networks.append(dict(name=network, id=network_config['NetworkID'])) return extra, extra_networks def _get_expected_entrypoint(self, image): @@ -1480,25 +1482,7 @@ class ContainerManager(DockerBaseClass): self.diff['image_different'] = True container = self.update_limits(container) - - has_network_differences, network_differences = container.has_network_differences() - if has_network_differences: - if self.diff.get('differences'): - self.diff['differences'].append(dict(network_differences=network_differences)) - else: - self.diff['differences'] = dict(network_differences=network_differences) - self.results['changed'] = True - container = self.update_networks(container, network_differences) - - if self.parameters.purge_networks: - has_extra_networks, extra_networks = container.has_extra_networks() - if has_extra_networks: - if self.diff.get('differences'): - self.diff['differences'].append(dict(purge_networks=extra_networks)) - else: - self.diff['differences'] = dict(purge_networks=extra_networks) - self.results['changed'] = True - container = self.remove_networks(container, extra_networks) + container = self.update_networks(container) if state == 'started' and not container.running: container = self.container_start(container.Id) @@ -1562,7 +1546,29 @@ class ContainerManager(DockerBaseClass): return self._get_container(container.Id) return container - def update_networks(self, container, differences): + def update_networks(self, container): + has_network_differences, network_differences = container.has_network_differences() + updated_container = container + if has_network_differences: + if self.diff.get('differences'): + self.diff['differences'].append(dict(network_differences=network_differences)) + else: + self.diff['differences'] = dict(network_differences=network_differences) + self.results['changed'] = True + updated_container = self._add_networks(container, network_differences) + + if self.parameters.purge_networks: + has_extra_networks, extra_networks = container.has_extra_networks() + if has_extra_networks: + if self.diff.get('differences'): + self.diff['differences'].append(dict(purge_networks=extra_networks)) + else: + self.diff['differences'] = dict(purge_networks=extra_networks) + self.results['changed'] = True + updated_container = self._purge_networks(container, extra_networks) + return updated_container + + def _add_networks(self, container, differences): for diff in differences: # remove the container from the network, if connected if diff.get('container'): @@ -1572,7 +1578,7 @@ class ContainerManager(DockerBaseClass): self.client.disconnect_container_from_network(container.Id, diff['parameter']['id']) except Exception, exc: self.fail("Error disconnecting container from network %s - %s" % (diff['parameter']['name'], - str(exc))) + str(exc))) # connect to the network params = dict( ipv4_address=diff['parameter'].get('ipv4_address', None), @@ -1582,13 +1588,16 @@ class ContainerManager(DockerBaseClass): ) self.results['actions'].append(dict(added_to_network=diff['parameter']['name'], network_parameters=params)) if not self.check_mode: + self.log("network diffs:") + self.log(diff, pretty_print=True) try: + self.log("Connecting conainer to network %s" % diff['parameter']['id']) self.client.connect_container_to_network(container.Id, diff['parameter']['id'], **params) except Exception, exc: self.fail("Error connecting container to network %s - %s" % (diff['parameter']['name'], str(exc))) return self._get_container(container.Id) - def remove_networks(self, container, networks): + def _purge_networks(self, container, networks): for network in networks: self.results['actions'].append(dict(removed_from_network=network['name'])) if not self.check_mode: From 6d9de1b5a1c518c04b3ff84a0e6a02a46889e9ec Mon Sep 17 00:00:00 2001 From: chouseknecht Date: Mon, 30 May 2016 15:14:14 -0400 Subject: [PATCH 3/8] Fix doc strings. --- cloud/docker/docker_container.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cloud/docker/docker_container.py b/cloud/docker/docker_container.py index afa3f4e6546..7805e91231c 100644 --- a/cloud/docker/docker_container.py +++ b/cloud/docker/docker_container.py @@ -255,13 +255,14 @@ options: required: false networks: description: - - List of networks to which the container is a member. - - Each network is dict with keys C(name), C(ipv4_address), C(ipv6_address), C(links), C(aliases). - - For each network C(name) is required. Optional parameters C(links) and C(aliases) are type list. + - List of networks that the container belongs to. + - Each network is a dict with keys C(name), C(ipv4_address), C(ipv6_address), C(links), C(aliases). + - For each network C(name) is required. Optional parameters C(links) and C(aliases) are of type list. - For more information see U(https://docs.docker.com/engine/userguide/networking/dockernetworks/). - To remove a container from one or more networks, use the C(purge_networks) option. default: null required: false + version_added: "2.2" oom_killer: description: - Whether or not to disable OOM Killer for the container. @@ -304,6 +305,7 @@ options: - Remove the container from all networks not included in C(networks) parameter. default: false required: false + version_added: "2.2" read_only: description: - Mount the container's root file system as read-only. From 633e11be1ee1d161edf83cdb4615aef6b1d6724d Mon Sep 17 00:00:00 2001 From: chouseknecht Date: Mon, 30 May 2016 18:37:28 -0400 Subject: [PATCH 4/8] Fixed bug in _get_network_id --- cloud/docker/docker_container.py | 48 ++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/cloud/docker/docker_container.py b/cloud/docker/docker_container.py index 7805e91231c..0c24e017501 100644 --- a/cloud/docker/docker_container.py +++ b/cloud/docker/docker_container.py @@ -255,9 +255,10 @@ options: required: false networks: description: - - List of networks that the container belongs to. + - List of networks the container belongs to. - Each network is a dict with keys C(name), C(ipv4_address), C(ipv6_address), C(links), C(aliases). - - For each network C(name) is required. Optional parameters C(links) and C(aliases) are of type list. + - For each network C(name) is required, all other keys are optional. + - If included, C(links) or C(aliases) are lists. - For more information see U(https://docs.docker.com/engine/userguide/networking/dockernetworks/). - To remove a container from one or more networks, use the C(purge_networks) option. default: null @@ -524,6 +525,43 @@ EXAMPLES = ''' syslog-facility: daemon syslog-tag: myservice +- name: Start a container with a command + docker_container: + name: sleepy + image: ubuntu:14.04 + command: sleep infinity + +- name: Add container to networks + docker_container: + docker_container: + name: sleepy + networks: + - name: TestingNet + ipv4_address: 172.1.1.18 + - name: TestingNet2 + ipv4_address: 172.1.10.20 + +- name: Update network with aliases + docker_container: + name: sleepy + networks: + - name: TestingNet + aliases: + - sleepyz + - zzzz + +- name: Remove container from one network + docker_container: + name: sleepy + networks: + - name: TestingNet2 + purge_networks: yes + +- name: Remove container from all networks + docker_container: + name: sleepy + purge_networks: yes + ''' RETURN = ''' @@ -979,7 +1017,9 @@ class TaskParameters(DockerBaseClass): network_id = None try: for network in self.client.networks(names=[network_name]): - network_id = network['Id'] + if network['Name'] == network_name: + network_id = network['Id'] + break except Exception, exc: self.fail("Error getting network id for %s - %s" % (network_name, str(exc))) return network_id @@ -1590,8 +1630,6 @@ class ContainerManager(DockerBaseClass): ) self.results['actions'].append(dict(added_to_network=diff['parameter']['name'], network_parameters=params)) if not self.check_mode: - self.log("network diffs:") - self.log(diff, pretty_print=True) try: self.log("Connecting conainer to network %s" % diff['parameter']['id']) self.client.connect_container_to_network(container.Id, diff['parameter']['id'], **params) From 78019e43884083e9f34c903b705ef0f00827a701 Mon Sep 17 00:00:00 2001 From: chouseknecht Date: Mon, 30 May 2016 18:39:52 -0400 Subject: [PATCH 5/8] For new options move vesion_added to 2.1.1 --- cloud/docker/docker_container.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cloud/docker/docker_container.py b/cloud/docker/docker_container.py index 0c24e017501..5b7814195ee 100644 --- a/cloud/docker/docker_container.py +++ b/cloud/docker/docker_container.py @@ -98,7 +98,7 @@ options: default: null required: false env_file: - version_added: "2.2" + version_added: "2.1.1" description: - Path to a file containing environment variables I(FOO=BAR). - If variable also present in C(env), then C(env) value will override. @@ -263,7 +263,7 @@ options: - To remove a container from one or more networks, use the C(purge_networks) option. default: null required: false - version_added: "2.2" + version_added: "2.1.1" oom_killer: description: - Whether or not to disable OOM Killer for the container. @@ -306,7 +306,7 @@ options: - Remove the container from all networks not included in C(networks) parameter. default: false required: false - version_added: "2.2" + version_added: "2.1.1" read_only: description: - Mount the container's root file system as read-only. From d9c751be16a4a89aaccd9d0b3404ebb4f3678665 Mon Sep 17 00:00:00 2001 From: chouseknecht Date: Mon, 30 May 2016 18:48:42 -0400 Subject: [PATCH 6/8] Set version added to 2.2 so that tests pass --- cloud/docker/docker_container.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cloud/docker/docker_container.py b/cloud/docker/docker_container.py index 5b7814195ee..0c24e017501 100644 --- a/cloud/docker/docker_container.py +++ b/cloud/docker/docker_container.py @@ -98,7 +98,7 @@ options: default: null required: false env_file: - version_added: "2.1.1" + version_added: "2.2" description: - Path to a file containing environment variables I(FOO=BAR). - If variable also present in C(env), then C(env) value will override. @@ -263,7 +263,7 @@ options: - To remove a container from one or more networks, use the C(purge_networks) option. default: null required: false - version_added: "2.1.1" + version_added: "2.2" oom_killer: description: - Whether or not to disable OOM Killer for the container. @@ -306,7 +306,7 @@ options: - Remove the container from all networks not included in C(networks) parameter. default: false required: false - version_added: "2.1.1" + version_added: "2.2" read_only: description: - Mount the container's root file system as read-only. From 0601df8c705c03207e9e7ef75364477ac797af41 Mon Sep 17 00:00:00 2001 From: chouseknecht Date: Tue, 31 May 2016 10:14:42 -0400 Subject: [PATCH 7/8] Fix network comparison. Fix handling of links. Updated doc strings. Added more examples. --- cloud/docker/docker_container.py | 72 ++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/cloud/docker/docker_container.py b/cloud/docker/docker_container.py index 0c24e017501..d2bf10fd30c 100644 --- a/cloud/docker/docker_container.py +++ b/cloud/docker/docker_container.py @@ -259,7 +259,7 @@ options: - Each network is a dict with keys C(name), C(ipv4_address), C(ipv6_address), C(links), C(aliases). - For each network C(name) is required, all other keys are optional. - If included, C(links) or C(aliases) are lists. - - For more information see U(https://docs.docker.com/engine/userguide/networking/dockernetworks/). + - For examples of the data structure and usage see EXAMPLES below. - To remove a container from one or more networks, use the C(purge_networks) option. default: null required: false @@ -303,7 +303,8 @@ options: required: false purge_networks: description: - - Remove the container from all networks not included in C(networks) parameter. + - Remove the container from ALL networks not included in C(networks) parameter. + - Any default networks such as I(bridge), if not found in C(networks), will be removed as well. default: false required: false version_added: "2.2" @@ -357,16 +358,16 @@ options: required: false state: description: - - '"absent" - A container matching the specified name will be stopped and removed. Use force_kill to kill the container + - 'I(absent) - A container matching the specified name will be stopped and removed. Use force_kill to kill the container rather than stopping it. Use keep_volumes to retain volumes associated with the removed container.' - - '"present" - Asserts the existence of a container matching the name and any provided configuration parameters. If no + - 'I(present)" - Asserts the existence of a container matching the name and any provided configuration parameters. If no container matches the name, a container will be created. If a container matches the name but the provided configuration does not match, the container will be updated, if it can be. If it cannot be updated, it will be removed and re-created with the requested config. Image version will be taken into account when comparing configuration. To ignore image version use the ignore_image option. Use the recreate option to force the re-creation of the matching container. Use force_kill to kill the container rather than stopping it. Use keep_volumes to retain volumes associated with a removed container.' - - '"started" - Asserts there is a running container matching the name and any provided configuration. If no container + - 'I(started) - Asserts there is a running container matching the name and any provided configuration. If no container matches the name, a container will be created and started. If a container matching the name is found but the configuration does not match, the container will be updated, if it can be. If it cannot be updated, it will be removed and a new container will be created with the requested configuration and started. Image version will be taken into @@ -374,7 +375,7 @@ options: re-create a matching container, even if it is running. Use restart to force a matching container to be stopped and restarted. Use force_kill to kill a container rather than stopping it. Use keep_volumes to retain volumes associated with a removed container.' - - '"stopped" - a container matching the specified name will be stopped. Use force_kill to kill a container rather than + - 'I(stopped) - a container matching the specified name will be stopped. Use force_kill to kill a container rather than stopping it.' required: false default: started @@ -525,6 +526,28 @@ EXAMPLES = ''' syslog-facility: daemon syslog-tag: myservice +- name: Create db container and connect to network + docker_container: + name: db_test + image: "postgres:latest" + networks: + - name: "{{ docker_network_name }}" + debug: "{{ playbook_debug }}" + register: output + +- name: Start container, connect to network and link + docker_container: + name: sleeper + image: ubuntu:14.04 + networks: + - name: TestingNet + ipv4_address: "172.1.1.100" + aliases: + - sleepyzz + links: + - db_test:db + - name: TestingNet2 + - name: Start a container with a command docker_container: name: sleepy @@ -538,6 +561,8 @@ EXAMPLES = ''' networks: - name: TestingNet ipv4_address: 172.1.1.18 + links: + - sleeper - name: TestingNet2 ipv4_address: 172.1.10.20 @@ -711,7 +736,7 @@ class TaskParameters(DockerBaseClass): self.publish_all_ports = True self.published_ports = None - self.links = self._parse_links() + self.links = self._parse_links(self.links) if self.volumes: self.volumes = self._expand_host_paths() @@ -732,6 +757,8 @@ class TaskParameters(DockerBaseClass): network['id'] = self._get_network_id(network['name']) if not network['id']: self.fail("Parameter error: network named %s could not be found. Does it exist?" % network['name']) + if network.get('links'): + network['links'] = self._parse_links(network['links']) def fail(self, msg): self.client.module.fail_json(msg=msg) @@ -940,21 +967,22 @@ class TaskParameters(DockerBaseClass): exposed.append(port_with_proto) return exposed - def _parse_links(self): + @staticmethod + def _parse_links(links): ''' Turn links into a dictionary ''' - if self.links is None: + if links is None: return None - links = {} - for link in self.links: + result = {} + for link in links: parsed_link = link.split(':', 1) if len(parsed_link) == 2: - links[parsed_link[0]] = parsed_link[1] + result[parsed_link[0]] = parsed_link[1] else: - links[parsed_link[0]] = parsed_link[0] - return links + result[parsed_link[0]] = parsed_link[0] + return result def _parse_ulimits(self): ''' @@ -1272,11 +1300,19 @@ class Container(DockerBaseClass): diff = True if network.get('ipv6_address') and network['ipv6_address'] != connected_networks[network['name']].get('GlobalIPv6Address'): diff = True - if network.get('aliases') and network['aliases'] != connected_networks[network['name']].get('Aliases'): - self.log('network aliases different') + if network.get('aliases') and not connected_networks[network['name']].get('Aliases'): diff = True - if network.get('links') and network['links'] != connected_networks[network['name']].get('Links'): + if network.get('aliases') and connected_networks[network['name']].get('Aliases'): + if set(network.get('aliases')) != set(connected_networks[network['name']].get('Aliases')): + diff = True + if network.get('links') and not connected_networks[network['name']].get('Links'): diff = True + if network.get('links') and connected_networks[network['name']].get('Links'): + expected_links = [] + for link, alias in network['links'].iteritems(): + expected_links.append("%s:%s" % (link, alias)) + if set(expected_links) != set(connected_networks[network['name']].get('Links', [])): + diff = True if diff: different = True differences.append(dict( @@ -1289,7 +1325,6 @@ class Container(DockerBaseClass): links=connected_networks[network['name']].get('Links') ) )) - self.log(differences, pretty_print=True) return different, differences def has_extra_networks(self): @@ -1632,6 +1667,7 @@ class ContainerManager(DockerBaseClass): if not self.check_mode: try: self.log("Connecting conainer to network %s" % diff['parameter']['id']) + self.log(params, pretty_print=True) self.client.connect_container_to_network(container.Id, diff['parameter']['id'], **params) except Exception, exc: self.fail("Error connecting container to network %s - %s" % (diff['parameter']['name'], str(exc))) From e8db7fd8cc96299b6758164c8e1f45ebef04e7fc Mon Sep 17 00:00:00 2001 From: chouseknecht Date: Tue, 31 May 2016 10:33:43 -0400 Subject: [PATCH 8/8] Remove debug/register from examples. --- cloud/docker/docker_container.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cloud/docker/docker_container.py b/cloud/docker/docker_container.py index d2bf10fd30c..474ef881f5c 100644 --- a/cloud/docker/docker_container.py +++ b/cloud/docker/docker_container.py @@ -532,8 +532,6 @@ EXAMPLES = ''' image: "postgres:latest" networks: - name: "{{ docker_network_name }}" - debug: "{{ playbook_debug }}" - register: output - name: Start container, connect to network and link docker_container: @@ -591,7 +589,7 @@ EXAMPLES = ''' RETURN = ''' ansible_docker_container: - description: Facts representing the current state of the container. Note that facts are not part of registred vars but accessible directly. + description: Facts representing the current state of the container. Note that facts are not part of registered vars but accessible directly. returned: always type: dict sample: '{