diff --git a/changelogs/fragments/48590-docker_container-unpause-stop.yml b/changelogs/fragments/48590-docker_container-unpause-stop.yml new file mode 100644 index 00000000000..e8767736b08 --- /dev/null +++ b/changelogs/fragments/48590-docker_container-unpause-stop.yml @@ -0,0 +1,3 @@ +bugfixes: +- "docker_container - some docker versions require containers to be unpaused before stopping or removing. + Adds check to do this when docker returns a corresponding error on stopping or removing." diff --git a/lib/ansible/modules/cloud/docker/docker_container.py b/lib/ansible/modules/cloud/docker/docker_container.py index 9603dcaef5a..b37a8a54f91 100644 --- a/lib/ansible/modules/cloud/docker/docker_container.py +++ b/lib/ansible/modules/cloud/docker/docker_container.py @@ -2057,18 +2057,34 @@ class ContainerManager(DockerBaseClass): self.results['changed'] = True response = None if not self.check_mode: - try: - response = self.client.remove_container(container_id, v=volume_state, link=link, force=force) - except NotFound as exc: - pass - except APIError as exc: - if exc.response.status_code == 409 and ('removal of container ' in exc.explanation and - ' is already in progress' in exc.explanation): + count = 0 + while True: + try: + response = self.client.remove_container(container_id, v=volume_state, link=link, force=force) + except NotFound as exc: pass - else: + except APIError as exc: + if 'Unpause the container before stopping or killing' in exc.explanation: + # New docker versions do not allow containers to be removed if they are paused + # Make sure we don't end up in an infinite loop + if count == 3: + self.fail("Error removing container %s (tried to unpause three times): %s" % (container_id, str(exc))) + count += 1 + # Unpause + try: + self.client.unpause(container=container_id) + except Exception as exc2: + self.fail("Error unpausing container %s for removal: %s" % (container_id, str(exc2))) + # Now try again + continue + if 'removal of container ' in exc.explanation and ' is already in progress' in exc.explanation: + pass + else: + self.fail("Error removing container %s: %s" % (container_id, str(exc))) + except Exception as exc: self.fail("Error removing container %s: %s" % (container_id, str(exc))) - except Exception as exc: - self.fail("Error removing container %s: %s" % (container_id, str(exc))) + # We only loop when explicitly requested by 'continue' + break return response def container_update(self, container_id, update_parameters): @@ -2106,13 +2122,32 @@ class ContainerManager(DockerBaseClass): self.results['changed'] = True response = None if not self.check_mode: - try: - if self.parameters.stop_timeout: - response = self.client.stop(container_id, timeout=self.parameters.stop_timeout) - else: - response = self.client.stop(container_id) - except Exception as exc: - self.fail("Error stopping container %s: %s" % (container_id, str(exc))) + count = 0 + while True: + try: + if self.parameters.stop_timeout: + response = self.client.stop(container_id, timeout=self.parameters.stop_timeout) + else: + response = self.client.stop(container_id) + except APIError as exc: + if 'Unpause the container before stopping or killing' in exc.explanation: + # New docker versions do not allow containers to be removed if they are paused + # Make sure we don't end up in an infinite loop + if count == 3: + self.fail("Error removing container %s (tried to unpause three times): %s" % (container_id, str(exc))) + count += 1 + # Unpause + try: + self.client.unpause(container=container_id) + except Exception as exc2: + self.fail("Error unpausing container %s for removal: %s" % (container_id, str(exc2))) + # Now try again + continue + self.fail("Error stopping container %s: %s" % (container_id, str(exc))) + except Exception as exc: + self.fail("Error stopping container %s: %s" % (container_id, str(exc))) + # We only loop when explicitly requested by 'continue' + break return response