diff --git a/contrib/heat_docker/heat_docker/resources/docker_container.py b/contrib/heat_docker/heat_docker/resources/docker_container.py index 2c9216414d..e4f7ece495 100644 --- a/contrib/heat_docker/heat_docker/resources/docker_container.py +++ b/contrib/heat_docker/heat_docker/resources/docker_container.py @@ -293,11 +293,22 @@ class DockerContainer(resource.Resource): if self.resource_id is None: return client = self.get_client() - client.kill(self.resource_id) + try: + client.kill(self.resource_id) + except docker.errors.APIError as ex: + if ex.response.status_code != 404: + raise return self.resource_id def check_delete_complete(self, container_id): - status = self._get_container_status(container_id) + if container_id is None: + return True + try: + status = self._get_container_status(container_id) + except docker.errors.APIError as ex: + if ex.response.status_code == 404: + return True + raise return (not status['Running']) def handle_suspend(self): diff --git a/contrib/heat_docker/heat_docker/tests/test_docker_container.py b/contrib/heat_docker/heat_docker/tests/test_docker_container.py index 9c638c70de..378d4e163c 100644 --- a/contrib/heat_docker/heat_docker/tests/test_docker_container.py +++ b/contrib/heat_docker/heat_docker/tests/test_docker_container.py @@ -14,16 +14,23 @@ # License for the specific language governing permissions and limitations # under the License. +import mock + from heat.common import exception from heat.common import template_format from heat.engine import resource from heat.engine import scheduler +from heat.openstack.common.importutils import try_import from heat.tests.common import HeatTestCase from heat.tests import utils +from testtools import skipIf + from ..resources import docker_container # noqa from .fake_docker_client import FakeDockerClient # noqa +docker = try_import('docker') + template = ''' { @@ -144,6 +151,35 @@ class DockerContainerTest(HeatTestCase): running = self.get_container_state(container)['Running'] self.assertIs(False, running) + def test_resource_already_deleted(self): + container = self.create_container('Blog') + scheduler.TaskRunner(container.delete)() + running = self.get_container_state(container)['Running'] + self.assertIs(False, running) + + scheduler.TaskRunner(container.delete)() + self.m.VerifyAll() + + @skipIf(docker is None, 'docker-py not available') + def test_resource_delete_exception(self): + response = mock.MagicMock() + response.status_code = 404 + response.content = 'some content' + + container = self.create_container('Blog') + self.m.StubOutWithMock(container.get_client(), 'kill') + container.get_client().kill(container.resource_id).AndRaise( + docker.errors.APIError('Not found', response)) + + self.m.StubOutWithMock(container, '_get_container_status') + container._get_container_status(container.resource_id).AndRaise( + docker.errors.APIError('Not found', response)) + + self.m.ReplayAll() + + scheduler.TaskRunner(container.delete)() + self.m.VerifyAll() + def test_resource_suspend_resume(self): container = self.create_container('Blog') # Test suspend