From ab7a6593c46ddc8b365f519c36879145ed5c55b2 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Singh Date: Thu, 5 Jan 2017 09:28:16 +0000 Subject: [PATCH] Make start/stop/pause/unpause/restart/kill action async This patch makes start/stop/pause/unpause/restart/kill actions async and removes the body from the response, as the operation is async. Implements: bp async-container-action Change-Id: I61dea7f16c0a353f73f10fa34094f892038fcb5f --- zun/api/controllers/v1/containers.py | 40 ++-- zun/common/utils.py | 20 ++ zun/compute/manager.py | 138 +++++++------- zun/compute/rpcapi.py | 12 +- zun/tests/tempest/api/clients.py | 47 ++--- zun/tests/tempest/api/test_containers.py | 52 +++--- .../api/controllers/v1/test_containers.py | 174 ++++++++++++++---- zun/tests/unit/common/test_utils.py | 32 +++- .../unit/compute/test_compute_manager.py | 168 ++++------------- 9 files changed, 365 insertions(+), 318 deletions(-) diff --git a/zun/api/controllers/v1/containers.py b/zun/api/controllers/v1/containers.py index 84254ea61..116743d9f 100644 --- a/zun/api/controllers/v1/containers.py +++ b/zun/api/controllers/v1/containers.py @@ -14,6 +14,7 @@ # under the License. from oslo_log import log as logging +from oslo_utils import strutils from oslo_utils import timeutils import pecan from pecan import rest @@ -28,6 +29,7 @@ from zun.common import exception from zun.common.i18n import _LE from zun.common import name_generator from zun.common import policy +from zun.common import utils from zun.common import validation from zun import objects from zun.objects import fields @@ -330,6 +332,9 @@ class ContainersController(rest.RestController): """ container = _get_container(container_id) check_policy_on_container(container.as_dict(), "container:delete") + force = strutils.bool_from_string(force, strict=True) + if not force: + utils.validate_container_state(container, 'delete') context = pecan.request.context pecan.request.rpcapi.container_delete(context, container, force) container.destroy() @@ -340,57 +345,60 @@ class ContainersController(rest.RestController): def start(self, container_id, **kw): container = _get_container(container_id) check_policy_on_container(container.as_dict(), "container:start") + utils.validate_container_state(container, 'start') LOG.debug('Calling compute.container_start with %s', container.uuid) context = pecan.request.context - container = pecan.request.rpcapi.container_start(context, container) - return Container.convert_with_links(container.as_dict()) + pecan.request.rpcapi.container_start(context, container) + pecan.response.status = 202 @pecan.expose('json') @exception.wrap_pecan_controller_exception def stop(self, container_id, timeout=None, **kw): container = _get_container(container_id) check_policy_on_container(container.as_dict(), "container:stop") + utils.validate_container_state(container, 'stop') LOG.debug('Calling compute.container_stop with %s' % container.uuid) context = pecan.request.context - container = pecan.request.rpcapi.container_stop(context, container, - timeout) - return Container.convert_with_links(container.as_dict()) + pecan.request.rpcapi.container_stop(context, container, timeout) + pecan.response.status = 202 @pecan.expose('json') @exception.wrap_pecan_controller_exception def reboot(self, container_id, timeout=None, **kw): container = _get_container(container_id) check_policy_on_container(container.as_dict(), "container:reboot") + utils.validate_container_state(container, 'reboot') LOG.debug('Calling compute.container_reboot with %s' % container.uuid) context = pecan.request.context - container = pecan.request.rpcapi.container_reboot(context, container, - timeout) - return Container.convert_with_links(container.as_dict()) + pecan.request.rpcapi.container_reboot(context, container, timeout) + pecan.response.status = 202 @pecan.expose('json') @exception.wrap_pecan_controller_exception def pause(self, container_id, **kw): container = _get_container(container_id) check_policy_on_container(container.as_dict(), "container:pause") + utils.validate_container_state(container, 'pause') LOG.debug('Calling compute.container_pause with %s' % container.uuid) context = pecan.request.context - container = pecan.request.rpcapi.container_pause(context, container) - return Container.convert_with_links(container.as_dict()) + pecan.request.rpcapi.container_pause(context, container) + pecan.response.status = 202 @pecan.expose('json') @exception.wrap_pecan_controller_exception def unpause(self, container_id, **kw): container = _get_container(container_id) check_policy_on_container(container.as_dict(), "container:unpause") + utils.validate_container_state(container, 'unpause') LOG.debug('Calling compute.container_unpause with %s' % container.uuid) context = pecan.request.context - container = pecan.request.rpcapi.container_unpause(context, container) - return Container.convert_with_links(container.as_dict()) + pecan.request.rpcapi.container_unpause(context, container) + pecan.response.status = 202 @pecan.expose('json') @exception.wrap_pecan_controller_exception @@ -407,6 +415,7 @@ class ContainersController(rest.RestController): def execute(self, container_id, **kw): container = _get_container(container_id) check_policy_on_container(container.as_dict(), "container:execute") + utils.validate_container_state(container, 'execute') LOG.debug('Calling compute.container_exec with %s command %s' % (container.uuid, kw['command'])) context = pecan.request.context @@ -418,9 +427,10 @@ class ContainersController(rest.RestController): def kill(self, container_id, **kw): container = _get_container(container_id) check_policy_on_container(container.as_dict(), "container:kill") + utils.validate_container_state(container, 'kill') LOG.debug('Calling compute.container_kill with %s signal %s' % (container.uuid, kw.get('signal', kw.get('signal')))) context = pecan.request.context - container = pecan.request.rpcapi.container_kill(context, container, - kw.get('signal')) - return Container.convert_with_links(container.as_dict()) + pecan.request.rpcapi.container_kill(context, container, + kw.get('signal', None)) + pecan.response.status = 202 diff --git a/zun/common/utils.py b/zun/common/utils.py index 8440b3b99..698297281 100644 --- a/zun/common/utils.py +++ b/zun/common/utils.py @@ -35,6 +35,26 @@ from zun.common.i18n import _LW LOG = logging.getLogger(__name__) +VALID_STATES = { + 'delete': ['Stopped', 'Error'], + 'start': ['Stopped'], + 'stop': ['Running'], + 'reboot': ['Running', 'Stopped'], + 'pause': ['Running'], + 'unpause': ['Paused'], + 'kill': ['Running'], + 'execute': ['Running'], +} + + +def validate_container_state(container, action): + if container.status not in VALID_STATES[action]: + raise exception.InvalidStateException( + id=container.uuid, + action=action, + actual_state=container.status) + + def safe_rstrip(value, chars=None): """Removes trailing characters from a string if that does not make it empty diff --git a/zun/compute/manager.py b/zun/compute/manager.py index 67d2db9f5..c3b82d126 100644 --- a/zun/compute/manager.py +++ b/zun/compute/manager.py @@ -16,7 +16,6 @@ import six from oslo_log import log as logging from oslo_utils import excutils -from oslo_utils import strutils from zun.common import exception from zun.common.i18n import _LE @@ -29,17 +28,6 @@ from zun.objects import fields LOG = logging.getLogger(__name__) -VALID_STATES = { - 'delete': ['Stopped', 'Error'], - 'start': ['Stopped'], - 'stop': ['Running'], - 'reboot': ['Running', 'Stopped'], - 'pause': ['Running'], - 'unpause': ['Paused'], - 'kill': ['Running'], - 'exec': ['Running'], -} - class Manager(object): '''Manages the running containers.''' @@ -54,17 +42,9 @@ class Manager(object): container.task_state = None container.save() - def _validate_container_state(self, container, action): - if container.status not in VALID_STATES[action]: - raise exception.InvalidStateException( - id=container.uuid, - action=action, - actual_state=container.status) - def container_create(self, context, container): utils.spawn_n(self._do_container_create, context, container) - @translate_exception def container_run(self, context, container): utils.spawn_n(self._do_container_run, context, container) @@ -156,32 +136,28 @@ class Manager(object): self._fail_container(container, six.text_type(e)) return - def _do_container_start(self, context, container): + def _do_container_start(self, context, container, reraise=False): LOG.debug('Starting container: %s', container.uuid) try: - # Although we dont need this validation, but i still - # keep it for extra surity - self._validate_container_state(container, 'start') container = self.driver.start(container) container.save() return container except exception.DockerError as e: - LOG.error(_LE("Error occurred while calling Docker start API: %s"), - six.text_type(e)) - self._fail_container(container, six.text_type(e)) - raise + with excutils.save_and_reraise_exception(reraise=reraise): + LOG.error(_LE( + "Error occurred while calling Docker start API: %s"), + six.text_type(e)) + self._fail_container(container, six.text_type(e)) except Exception as e: - LOG.exception(_LE("Unexpected exception: %s"), six.text_type(e)) - self._fail_container(container, six.text_type(e)) - raise + with excutils.save_and_reraise_exception(reraise=reraise): + LOG.exception(_LE("Unexpected exception: %s"), + six.text_type(e)) + self._fail_container(container, six.text_type(e)) @translate_exception def container_delete(self, context, container, force): LOG.debug('Deleting container: %s', container.uuid) try: - force = strutils.bool_from_string(force, strict=True) - if not force: - self._validate_container_state(container, 'delete') self.driver.delete(container, force) except exception.DockerError as e: LOG.error(_LE("Error occurred while calling Docker " @@ -230,74 +206,83 @@ class Manager(object): LOG.exception(_LE("Unexpected exception: %s"), six.text_type(e)) raise - @translate_exception - def container_reboot(self, context, container, timeout): + def _do_container_reboot(self, context, container, timeout, reraise=False): LOG.debug('Rebooting container: %s', container.uuid) try: - self._validate_container_state(container, 'reboot') container = self.driver.reboot(container, timeout) container.save() return container except exception.DockerError as e: - LOG.error(_LE("Error occurred while calling Docker reboot " - "API: %s"), six.text_type(e)) - raise + with excutils.save_and_reraise_exception(reraise=reraise): + LOG.error(_LE("Error occurred while calling Docker reboot " + "API: %s"), six.text_type(e)) except Exception as e: - LOG.exception(_LE("Unexpected exception: %s"), six.text_type(e)) - raise + with excutils.save_and_reraise_exception(reraise=reraise): + LOG.exception(_LE("Unexpected exception: %s"), + six.text_type(e)) - @translate_exception - def container_stop(self, context, container, timeout): + def container_reboot(self, context, container, timeout): + utils.spawn_n(self._do_container_reboot, context, container, timeout) + + def _do_container_stop(self, context, container, timeout, reraise=False): LOG.debug('Stopping container: %s', container.uuid) try: - self._validate_container_state(container, 'stop') container = self.driver.stop(container, timeout) container.save() return container except exception.DockerError as e: - LOG.error(_LE("Error occurred while calling Docker stop API: %s"), - six.text_type(e)) - raise + with excutils.save_and_reraise_exception(reraise=reraise): + LOG.error(_LE( + "Error occurred while calling Docker stop API: %s"), + six.text_type(e)) except Exception as e: - LOG.exception(_LE("Unexpected exception: %s"), six.text_type(e)) - raise + with excutils.save_and_reraise_exception(reraise=reraise): + LOG.exception(_LE("Unexpected exception: %s"), + six.text_type(e)) + + def container_stop(self, context, container, timeout): + utils.spawn_n(self._do_container_stop, context, container, timeout) - @translate_exception def container_start(self, context, container): - return self._do_container_start(context, container) + utils.spawn_n(self._do_container_start, context, container) - @translate_exception - def container_pause(self, context, container): + def _do_container_pause(self, context, container, reraise=False): LOG.debug('Pausing container: %s', container.uuid) try: - self._validate_container_state(container, 'pause') container = self.driver.pause(container) container.save() return container except exception.DockerError as e: - LOG.error(_LE("Error occurred while calling Docker pause API: %s"), - six.text_type(e)) - raise + with excutils.save_and_reraise_exception(reraise=reraise): + LOG.error(_LE( + "Error occurred while calling Docker pause API: %s"), + six.text_type(e)) except Exception as e: - LOG.exception(_LE("Unexpected exception: %s,"), six.text_type(e)) - raise + with excutils.save_and_reraise_exception(reraise=reraise): + LOG.exception(_LE("Unexpected exception: %s,"), + six.text_type(e)) - @translate_exception - def container_unpause(self, context, container): + def container_pause(self, context, container): + utils.spawn_n(self._do_container_pause, context, container) + + def _do_container_unpause(self, context, container, reraise=False): LOG.debug('Unpausing container: %s', container.uuid) try: - self._validate_container_state(container, 'unpause') container = self.driver.unpause(container) container.save() return container except exception.DockerError as e: - LOG.error(_LE("Error occurred while calling Docker unpause " - "API: %s"), - six.text_type(e)) - raise + with excutils.save_and_reraise_exception(reraise=reraise): + LOG.error(_LE( + "Error occurred while calling Docker unpause API: %s"), + six.text_type(e)) except Exception as e: - LOG.exception(_LE("Unexpected exception: %s"), six.text_type(e)) - raise + with excutils.save_and_reraise_exception(reraise=reraise): + LOG.exception(_LE("Unexpected exception: %s"), + six.text_type(e)) + + def container_unpause(self, context, container): + utils.spawn_n(self._do_container_unpause, context, container) @translate_exception def container_logs(self, context, container): @@ -317,7 +302,6 @@ class Manager(object): # TODO(hongbin): support exec command interactively LOG.debug('Executing command in container: %s', container.uuid) try: - self._validate_container_state(container, 'exec') return self.driver.execute(container, command) except exception.DockerError as e: LOG.error(_LE("Error occurred while calling Docker exec API: %s"), @@ -327,18 +311,20 @@ class Manager(object): LOG.exception(_LE("Unexpected exception: %s"), six.text_type(e)) raise - @translate_exception - def container_kill(self, context, container, signal): + def _do_container_kill(self, context, container, signal, reraise=False): LOG.debug('kill signal to container: %s', container.uuid) try: - self._validate_container_state(container, 'kill') container = self.driver.kill(container, signal) container.save() return container except exception.DockerError as e: - LOG.error(_LE("Error occurred while calling Docker kill API: %s"), - six.text_type(e)) - raise + with excutils.save_and_reraise_exception(reraise=reraise): + LOG.error(_LE( + "Error occurred while calling Docker kill API: %s"), + six.text_type(e)) + + def container_kill(self, context, container, signal): + utils.spawn_n(self._do_container_kill, context, container, signal) def image_pull(self, context, image): utils.spawn_n(self._do_image_pull, context, image) diff --git a/zun/compute/rpcapi.py b/zun/compute/rpcapi.py index 5fe5fea90..252057a4f 100644 --- a/zun/compute/rpcapi.py +++ b/zun/compute/rpcapi.py @@ -47,21 +47,21 @@ class API(rpc_service.API): return self._call('container_show', container=container) def container_reboot(self, context, container, timeout): - return self._call('container_reboot', container=container, + return self._cast('container_reboot', container=container, timeout=timeout) def container_stop(self, context, container, timeout): - return self._call('container_stop', container=container, + return self._cast('container_stop', container=container, timeout=timeout) def container_start(self, context, container): - return self._call('container_start', container=container) + return self._cast('container_start', container=container) def container_pause(self, context, container): - return self._call('container_pause', container=container) + return self._cast('container_pause', container=container) def container_unpause(self, context, container): - return self._call('container_unpause', container=container) + return self._cast('container_unpause', container=container) def container_logs(self, context, container): return self._call('container_logs', container=container) @@ -71,7 +71,7 @@ class API(rpc_service.API): command=command) def container_kill(self, context, container, signal): - return self._call('container_kill', container=container, + return self._cast('container_kill', container=container, signal=signal) def image_show(self, context, image): diff --git a/zun/tests/tempest/api/clients.py b/zun/tests/tempest/api/clients.py index 86a619460..4434f9d9f 100644 --- a/zun/tests/tempest/api/clients.py +++ b/zun/tests/tempest/api/clients.py @@ -123,34 +123,28 @@ class ZunClient(rest_client.RestClient): self.container_uri(container_id, params=params), **kwargs) def start_container(self, container_id, **kwargs): - resp, body = self.post( + return self.post( self.container_uri(container_id, action='start'), None, **kwargs) - return self.deserialize(resp, body, container_model.ContainerEntity) def stop_container(self, container_id, **kwargs): - resp, body = self.post( + return self.post( self.container_uri(container_id, action='stop'), None, *kwargs) - return self.deserialize(resp, body, container_model.ContainerEntity) def pause_container(self, container_id, **kwargs): - resp, body = self.post( + return self.post( self.container_uri(container_id, action='pause'), None, **kwargs) - return self.deserialize(resp, body, container_model.ContainerEntity) def unpause_container(self, container_id, **kwargs): - resp, body = self.post( + return self.post( self.container_uri(container_id, action='unpause'), None, **kwargs) - return self.deserialize(resp, body, container_model.ContainerEntity) def kill_container(self, container_id, **kwargs): - resp, body = self.post( + return self.post( self.container_uri(container_id, action='kill'), None, **kwargs) - return self.deserialize(resp, body, container_model.ContainerEntity) def reboot_container(self, container_id, **kwargs): - resp, body = self.post( + return self.post( self.container_uri(container_id, action='reboot'), None, **kwargs) - return self.deserialize(resp, body, container_model.ContainerEntity) def exec_container(self, container_id, command, **kwargs): return self.post( @@ -166,25 +160,14 @@ class ZunClient(rest_client.RestClient): return self.deserialize(resp, body, service_model.ServiceCollection) - def ensure_container_created(self, container_id): - def container_created(): + def ensure_container_in_desired_state(self, container_id, status): + def is_container_in_desired_state(): _, container = self.get_container(container_id) - if container.status == 'Creating': - return False - else: - return True - - utils.wait_for_condition(container_created) - - def ensure_container_started(self, container_id): - def container_started(): - _, container = self.get_container(container_id) - if container.status == 'Running': + if container.status == status: return True else: return False - - utils.wait_for_condition(container_started) + utils.wait_for_condition(is_container_in_desired_state) class DockerClient(object): @@ -195,3 +178,13 @@ class DockerClient(object): if container_id in info['Name']: return info return None + + def ensure_container_pid_changed(self, container_id, pid): + def is_pid_changed(): + container = self.get_container(container_id) + new_pid = container.get('State').get('Pid') + if pid != new_pid: + return True + else: + return False + utils.wait_for_condition(is_pid_changed) diff --git a/zun/tests/tempest/api/test_containers.py b/zun/tests/tempest/api/test_containers.py index 59ea1abaf..cf280c308 100644 --- a/zun/tests/tempest/api/test_containers.py +++ b/zun/tests/tempest/api/test_containers.py @@ -81,37 +81,42 @@ class TestContainer(base.BaseZunTest): def test_start_stop_container(self): _, model = self._run_container() - resp, model = self.container_client.stop_container(model.uuid) - self.assertEqual(200, resp.status) - self.assertEqual('Stopped', model.status) + resp, _ = self.container_client.stop_container(model.uuid) + self.assertEqual(202, resp.status) + self.container_client.ensure_container_in_desired_state( + model.uuid, 'Stopped') self.assertEqual('Stopped', self._get_container_state(model.uuid)) - resp, model = self.container_client.start_container(model.uuid) - self.assertEqual(200, resp.status) - self.assertEqual('Running', model.status) + resp, _ = self.container_client.start_container(model.uuid) + self.assertEqual(202, resp.status) + self.container_client.ensure_container_in_desired_state( + model.uuid, 'Running') self.assertEqual('Running', self._get_container_state(model.uuid)) @decorators.idempotent_id('b5f39756-8898-4e0e-a48b-dda0a06b66b6') def test_pause_unpause_container(self): _, model = self._run_container() - resp, model = self.container_client.pause_container(model.uuid) - self.assertEqual(200, resp.status) - self.assertEqual('Paused', model.status) + resp, _ = self.container_client.pause_container(model.uuid) + self.assertEqual(202, resp.status) + self.container_client.ensure_container_in_desired_state( + model.uuid, 'Paused') self.assertEqual('Paused', self._get_container_state(model.uuid)) - resp, model = self.container_client.unpause_container(model.uuid) - self.assertEqual(200, resp.status) - self.assertEqual('Running', model.status) + resp, _ = self.container_client.unpause_container(model.uuid) + self.assertEqual(202, resp.status) + self.container_client.ensure_container_in_desired_state( + model.uuid, 'Running') self.assertEqual('Running', self._get_container_state(model.uuid)) @decorators.idempotent_id('6179a588-3d48-4372-9599-f228411d1449') def test_kill_container(self): _, model = self._run_container() - resp, model = self.container_client.kill_container(model.uuid) - self.assertEqual(200, resp.status) - self.assertEqual('Stopped', model.status) + resp, _ = self.container_client.kill_container(model.uuid) + self.assertEqual(202, resp.status) + self.container_client.ensure_container_in_desired_state( + model.uuid, 'Stopped') self.assertEqual('Stopped', self._get_container_state(model.uuid)) @decorators.idempotent_id('c2e54321-0a70-4331-ba62-9dcaa75ac250') @@ -120,9 +125,9 @@ class TestContainer(base.BaseZunTest): container = self.docker_client.get_container(model.uuid) pid = container.get('State').get('Pid') - resp, model = self.container_client.reboot_container(model.uuid) - self.assertEqual(200, resp.status) - self.assertEqual('Running', model.status) + resp, _ = self.container_client.reboot_container(model.uuid) + self.assertEqual(202, resp.status) + self.docker_client.ensure_container_pid_changed(model.uuid, pid) self.assertEqual('Running', self._get_container_state(model.uuid)) # assert pid is changed container = self.docker_client.get_container(model.uuid) @@ -149,7 +154,8 @@ class TestContainer(base.BaseZunTest): resp, model = self.container_client.post_container(gen_model) self.assertEqual(202, resp.status) # Wait for container to finish creation - self.container_client.ensure_container_created(model.uuid) + self.container_client.ensure_container_in_desired_state( + model.uuid, 'Stopped') # Assert the container is created resp, model = self.container_client.get_container(model.uuid) @@ -163,13 +169,13 @@ class TestContainer(base.BaseZunTest): resp, model = self.container_client.run_container(gen_model) self.assertEqual(202, resp.status) # Wait for container to started - self.container_client.ensure_container_started(model.uuid) + self.container_client.ensure_container_in_desired_state( + model.uuid, 'Running') # Assert the container is started resp, model = self.container_client.get_container(model.uuid) - self.assertTrue(model.status in ['Running', 'Stopped']) - self.assertTrue(self._get_container_state(model.uuid) in - ['Running', 'Stopped']) + self.assertEqual('Running', model.status) + self.assertEqual('Running', self._get_container_state(model.uuid)) return resp, model def _delete_container(self, container_id): diff --git a/zun/tests/unit/api/controllers/v1/test_containers.py b/zun/tests/unit/api/controllers/v1/test_containers.py index 904b6dd4e..3022b3734 100644 --- a/zun/tests/unit/api/controllers/v1/test_containers.py +++ b/zun/tests/unit/api/controllers/v1/test_containers.py @@ -146,7 +146,8 @@ class TestContainerController(api_base.FunctionalTest): self.assertEqual({"key1": "val1", "key2": "val2"}, c.get('environment')) # Delete the container we created - response = self.app.delete('/v1/containers/%s/' % c.get('uuid')) + response = self.app.delete( + '/v1/containers/%s?force=True' % c.get('uuid')) self.assertEqual(204, response.status_int) response = self.app.get('/v1/containers/') @@ -415,7 +416,7 @@ class TestContainerController(api_base.FunctionalTest): self.assertEqual('new_name', test_container_obj.name) def _action_test(self, container, action, ident_field, - mock_container_action, query_param=''): + mock_container_action, status_code, query_param=''): test_container_obj = objects.Container(self.context, **container) ident = container.get(ident_field) get_by_ident_loc = 'zun.objects.Container.get_by_%s' % ident_field @@ -423,7 +424,7 @@ class TestContainerController(api_base.FunctionalTest): mock_get_by_indent.return_value = test_container_obj response = self.app.post('/v1/containers/%s/%s/?%s' % (ident, action, query_param)) - self.assertEqual(200, response.status_int) + self.assertEqual(status_code, response.status_int) # Only PUT should work, others like GET should fail self.assertRaises(AppError, self.app.get, @@ -437,98 +438,154 @@ class TestContainerController(api_base.FunctionalTest): mock_container_action.assert_called_once_with( mock.ANY, test_container_obj) + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_start') - def test_start_by_uuid(self, mock_container_start): + def test_start_by_uuid(self, mock_container_start, mock_validate): test_container_obj = objects.Container(self.context, **utils.get_test_container()) mock_container_start.return_value = test_container_obj test_container = utils.get_test_container() self._action_test(test_container, 'start', 'uuid', - mock_container_start) + mock_container_start, 202) + def test_start_by_uuid_invalid_state(self): + uuid = uuidutils.generate_uuid() + test_object = utils.create_test_container(context=self.context, + uuid=uuid, status='Running') + with self.assertRaisesRegexp( + AppError, "Cannot start container %s in Running state" % uuid): + self.app.post('/v1/containers/%s/%s/' % (test_object.uuid, + 'start')) + + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_start') - def test_start_by_name(self, mock_container_start): + def test_start_by_name(self, mock_container_start, mock_validate): test_container_obj = objects.Container(self.context, **utils.get_test_container()) mock_container_start.return_value = test_container_obj test_container = utils.get_test_container() self._action_test(test_container, 'start', 'name', - mock_container_start) + mock_container_start, 202) + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_stop') - def test_stop_by_uuid(self, mock_container_stop): + def test_stop_by_uuid(self, mock_container_stop, mock_validate): test_container_obj = objects.Container(self.context, **utils.get_test_container()) mock_container_stop.return_value = test_container_obj test_container = utils.get_test_container() self._action_test(test_container, 'stop', 'uuid', - mock_container_stop, + mock_container_stop, 202, query_param='timeout=10') + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_stop') - def test_stop_by_name(self, mock_container_stop): + def test_stop_by_name(self, mock_container_stop, mock_validate): test_container_obj = objects.Container(self.context, **utils.get_test_container()) mock_container_stop.return_value = test_container_obj test_container = utils.get_test_container() self._action_test(test_container, 'stop', 'name', - mock_container_stop, + mock_container_stop, 202, query_param='timeout=10') + def test_stop_by_uuid_invalid_state(self): + uuid = uuidutils.generate_uuid() + test_object = utils.create_test_container(context=self.context, + uuid=uuid, status='Stopped') + with self.assertRaisesRegexp( + AppError, "Cannot stop container %s in Stopped state" % uuid): + self.app.post('/v1/containers/%s/%s/' % (test_object.uuid, + 'stop')) + + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_pause') - def test_pause_by_uuid(self, mock_container_pause): + def test_pause_by_uuid(self, mock_container_pause, mock_validate): test_container_obj = objects.Container(self.context, **utils.get_test_container()) mock_container_pause.return_value = test_container_obj test_container = utils.get_test_container() self._action_test(test_container, 'pause', 'uuid', - mock_container_pause) + mock_container_pause, 202) + def test_pause_by_uuid_invalid_state(self): + uuid = uuidutils.generate_uuid() + test_object = utils.create_test_container(context=self.context, + uuid=uuid, status='Stopped') + with self.assertRaisesRegexp( + AppError, "Cannot pause container %s in Stopped state" % uuid): + self.app.post('/v1/containers/%s/%s/' % (test_object.uuid, + 'pause')) + + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_pause') - def test_pause_by_name(self, mock_container_pause): + def test_pause_by_name(self, mock_container_pause, mock_validate): test_container_obj = objects.Container(self.context, **utils.get_test_container()) mock_container_pause.return_value = test_container_obj test_container = utils.get_test_container() self._action_test(test_container, 'pause', 'name', - mock_container_pause) + mock_container_pause, 202) + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_unpause') - def test_unpause_by_uuid(self, mock_container_unpause): + def test_unpause_by_uuid(self, mock_container_unpause, mock_validate): test_container_obj = objects.Container(self.context, **utils.get_test_container()) mock_container_unpause.return_value = test_container_obj test_container = utils.get_test_container() self._action_test(test_container, 'unpause', 'uuid', - mock_container_unpause) + mock_container_unpause, 202) + def test_unpause_by_uuid_invalid_state(self): + uuid = uuidutils.generate_uuid() + test_object = utils.create_test_container(context=self.context, + uuid=uuid, status='Running') + with self.assertRaisesRegexp( + AppError, + "Cannot unpause container %s in Running state" % uuid): + self.app.post('/v1/containers/%s/%s/' % (test_object.uuid, + 'unpause')) + + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_unpause') - def test_unpause_by_name(self, mock_container_unpause): + def test_unpause_by_name(self, mock_container_unpause, mock_validate): test_container_obj = objects.Container(self.context, **utils.get_test_container()) mock_container_unpause.return_value = test_container_obj test_container = utils.get_test_container() self._action_test(test_container, 'unpause', 'name', - mock_container_unpause) + mock_container_unpause, 202) + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_reboot') - def test_reboot_by_uuid(self, mock_container_reboot): + def test_reboot_by_uuid(self, mock_container_reboot, mock_validate): test_container_obj = objects.Container(self.context, **utils.get_test_container()) mock_container_reboot.return_value = test_container_obj test_container = utils.get_test_container() self._action_test(test_container, 'reboot', 'uuid', - mock_container_reboot, + mock_container_reboot, 202, query_param='timeout=10') + def test_reboot_by_uuid_invalid_state(self): + uuid = uuidutils.generate_uuid() + test_object = utils.create_test_container(context=self.context, + uuid=uuid, status='Paused') + with self.assertRaisesRegexp( + AppError, "Cannot reboot container %s in Paused state" % uuid): + self.app.post('/v1/containers/%s/%s/' % (test_object.uuid, + 'reboot')) + + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_reboot') - def test_reboot_by_name(self, mock_container_reboot): + def test_reboot_by_name(self, mock_container_reboot, mock_validate): test_container_obj = objects.Container(self.context, **utils.get_test_container()) mock_container_reboot.return_value = test_container_obj test_container = utils.get_test_container() self._action_test(test_container, 'reboot', 'name', - mock_container_reboot, + mock_container_reboot, 202, query_param='timeout=10') @patch('zun.compute.rpcapi.API.container_logs') @@ -573,10 +630,11 @@ class TestContainerController(api_base.FunctionalTest): '/v1/containers/%s/logs/' % container_uuid) self.assertFalse(mock_container_logs.called) + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_exec') @patch('zun.objects.Container.get_by_uuid') def test_execute_command_by_uuid(self, mock_get_by_uuid, - mock_container_exec): + mock_container_exec, mock_validate): mock_container_exec.return_value = "" test_container = utils.get_test_container() test_container_obj = objects.Container(self.context, **test_container) @@ -590,10 +648,22 @@ class TestContainerController(api_base.FunctionalTest): mock_container_exec.assert_called_once_with( mock.ANY, test_container_obj, cmd['command']) + def test_exec_command_by_uuid_invalid_state(self): + uuid = uuidutils.generate_uuid() + test_object = utils.create_test_container(context=self.context, + uuid=uuid, status='Stopped') + cmd = {'command': 'ls'} + with self.assertRaisesRegexp( + AppError, + "Cannot execute container %s in Stopped state" % uuid): + self.app.post('/v1/containers/%s/%s/' % (test_object.uuid, + 'execute'), cmd) + + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_exec') @patch('zun.objects.Container.get_by_name') def test_execute_command_by_name(self, mock_get_by_name, - mock_container_exec): + mock_container_exec, mock_validate): mock_container_exec.return_value = "" test_container = utils.get_test_container() test_container_obj = objects.Container(self.context, **test_container) @@ -607,10 +677,11 @@ class TestContainerController(api_base.FunctionalTest): mock_container_exec.assert_called_once_with( mock.ANY, test_container_obj, cmd['command']) + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_delete') @patch('zun.objects.Container.get_by_uuid') def test_delete_container_by_uuid(self, mock_get_by_uuid, - mock_container_delete): + mock_container_delete, mock_validate): test_container = utils.get_test_container() test_container_obj = objects.Container(self.context, **test_container) mock_get_by_uuid.return_value = test_container_obj @@ -624,10 +695,29 @@ class TestContainerController(api_base.FunctionalTest): mock.ANY, test_container_obj, False) mock_destroy.assert_called_once_with() + def test_delete_by_uuid_invalid_state(self): + uuid = uuidutils.generate_uuid() + test_object = utils.create_test_container(context=self.context, + uuid=uuid, status='Running') + with self.assertRaisesRegexp( + AppError, + "Cannot delete container %s in Running state" % uuid): + self.app.delete('/v1/containers/%s' % (test_object.uuid)) + + @patch('zun.compute.rpcapi.API.container_delete') + def test_delete_by_uuid_invalid_state_force_true(self, mock_delete): + uuid = uuidutils.generate_uuid() + test_object = utils.create_test_container(context=self.context, + uuid=uuid, status='Running') + response = self.app.delete('/v1/containers/%s?force=True' % ( + test_object.uuid)) + self.assertEqual(204, response.status_int) + + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_delete') @patch('zun.objects.Container.get_by_name') def test_delete_container_by_name(self, mock_get_by_name, - mock_container_delete): + mock_container_delete, mock_validate): test_container = utils.get_test_container() test_container_obj = objects.Container(self.context, **test_container) mock_get_by_name.return_value = test_container_obj @@ -641,10 +731,12 @@ class TestContainerController(api_base.FunctionalTest): mock.ANY, test_container_obj, False) mock_destroy.assert_called_once_with() + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_kill') @patch('zun.objects.Container.get_by_uuid') def test_kill_container_by_uuid(self, - mock_get_by_uuid, mock_container_kill): + mock_get_by_uuid, mock_container_kill, + mock_validate): test_container_obj = objects.Container(self.context, **utils.get_test_container()) mock_container_kill.return_value = test_container_obj @@ -656,14 +748,26 @@ class TestContainerController(api_base.FunctionalTest): url = '/v1/containers/%s/%s/' % (container_uuid, 'kill') cmd = {'signal': '9'} response = self.app.post(url, cmd) - self.assertEqual(200, response.status_int) + self.assertEqual(202, response.status_int) mock_container_kill.assert_called_once_with( mock.ANY, test_container_obj, cmd['signal']) + def test_kill_by_uuid_invalid_state(self): + uuid = uuidutils.generate_uuid() + test_object = utils.create_test_container(context=self.context, + uuid=uuid, status='Stopped') + body = {'signal': 9} + with self.assertRaisesRegexp( + AppError, "Cannot kill container %s in Stopped state" % uuid): + self.app.post('/v1/containers/%s/%s/' % (test_object.uuid, + 'kill'), body) + + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_kill') @patch('zun.objects.Container.get_by_name') def test_kill_container_by_name(self, - mock_get_by_name, mock_container_kill): + mock_get_by_name, mock_container_kill, + mock_validate): test_container_obj = objects.Container(self.context, **utils.get_test_container()) mock_container_kill.return_value = test_container_obj @@ -675,15 +779,17 @@ class TestContainerController(api_base.FunctionalTest): url = '/v1/containers/%s/%s/' % (container_name, 'kill') cmd = {'signal': '9'} response = self.app.post(url, cmd) - self.assertEqual(200, response.status_int) + self.assertEqual(202, response.status_int) mock_container_kill.assert_called_once_with( mock.ANY, test_container_obj, cmd['signal']) + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_kill') @patch('zun.objects.Container.get_by_uuid') def test_kill_container_which_not_exist(self, mock_get_by_uuid, - mock_container_kill): + mock_container_kill, + mock_validate): mock_container_kill.return_value = "" test_container = utils.get_test_container() test_container_obj = objects.Container(self.context, **test_container) @@ -695,11 +801,13 @@ class TestContainerController(api_base.FunctionalTest): '/v1/containers/%s/%s/' % (container_uuid, 'kill')) self.assertTrue(mock_container_kill.called) + @patch('zun.common.utils.validate_container_state') @patch('zun.compute.rpcapi.API.container_kill') @patch('zun.objects.Container.get_by_uuid') def test_kill_container_with_exception(self, mock_get_by_uuid, - mock_container_kill): + mock_container_kill, + mock_validate): mock_container_kill.return_value = "" test_container = utils.get_test_container() test_container_obj = objects.Container(self.context, **test_container) diff --git a/zun/tests/unit/common/test_utils.py b/zun/tests/unit/common/test_utils.py index a2454b536..a5fe7b238 100644 --- a/zun/tests/unit/common/test_utils.py +++ b/zun/tests/unit/common/test_utils.py @@ -18,10 +18,12 @@ from zun.common import exception from zun.common import utils from zun.common.utils import check_container_id from zun.common.utils import translate_exception +from zun.objects.container import Container from zun.tests import base +from zun.tests.unit.db import utils as db_utils -class TestUtils(base.BaseTestCase): +class TestUtils(base.TestCase): """Test cases for zun.common.utils""" def test_check_container_id(self): @@ -73,3 +75,31 @@ class TestUtils(base.BaseTestCase): self.assertTrue(utils.should_pull_image('always', False)) self.assertTrue(utils.should_pull_image('ifnotpresent', False)) self.assertFalse(utils.should_pull_image('ifnotpresent', True)) + + def test_validate_container_state(self): + container = Container(self.context, **db_utils.get_test_container()) + container.status = 'Stopped' + with self.assertRaisesRegexp(exception.InvalidStateException, + "%s" % container.uuid): + utils.validate_container_state(container, 'stop') + with self.assertRaisesRegexp(exception.InvalidStateException, + "%s" % container.uuid): + utils.validate_container_state(container, 'pause') + container.status = 'Running' + with self.assertRaisesRegexp(exception.InvalidStateException, + "%s" % container.uuid): + utils.validate_container_state(container, 'start') + with self.assertRaisesRegexp(exception.InvalidStateException, + "%s" % container.uuid): + utils.validate_container_state(container, 'unpause') + with self.assertRaisesRegexp(exception.InvalidStateException, + "%s" % container.uuid): + utils.validate_container_state(container, 'delete') + self.assertIsNone(utils.validate_container_state( + container, 'reboot')) + container.status = 'Stopped' + self.assertIsNone(utils.validate_container_state( + container, 'reboot')) + container.status = 'Running' + self.assertIsNone(utils.validate_container_state( + container, 'execute')) diff --git a/zun/tests/unit/compute/test_compute_manager.py b/zun/tests/unit/compute/test_compute_manager.py index e92ab5eea..364dc592c 100644 --- a/zun/tests/unit/compute/test_compute_manager.py +++ b/zun/tests/unit/compute/test_compute_manager.py @@ -42,33 +42,6 @@ class TestManager(base.TestCase): self.assertEqual("Creation Failed", container.status_reason) self.assertIsNone(container.task_state) - def test_validate_container_state(self): - container = Container(self.context, **utils.get_test_container()) - container.status = 'Stopped' - with self.assertRaisesRegexp(exception.InvalidStateException, - "%s" % container.uuid): - self.compute_manager._validate_container_state(container, 'stop') - with self.assertRaisesRegexp(exception.InvalidStateException, - "%s" % container.uuid): - self.compute_manager._validate_container_state(container, 'pause') - container.status = 'Running' - with self.assertRaisesRegexp(exception.InvalidStateException, - "%s" % container.uuid): - self.compute_manager._validate_container_state(container, 'start') - with self.assertRaisesRegexp(exception.InvalidStateException, - "%s" % container.uuid): - self.compute_manager._validate_container_state(container, - 'unpause') - container.status = 'Running' - self.assertIsNone(self.compute_manager._validate_container_state( - container, 'reboot')) - container.status = 'Stopped' - self.assertIsNone(self.compute_manager._validate_container_state( - container, 'reboot')) - container.status = 'Running' - self.assertIsNone(self.compute_manager._validate_container_state( - container, 'exec')) - @mock.patch.object(Container, 'save') @mock.patch('zun.image.driver.pull_image') @mock.patch.object(fake_driver, 'create') @@ -218,24 +191,14 @@ class TestManager(base.TestCase): mock_create.assert_called_once_with(container, None, {'name': 'nginx', 'path': None}) - @mock.patch.object(manager.Manager, '_validate_container_state') @mock.patch.object(fake_driver, 'delete') - def test_container_delete(self, mock_delete, mock_validate): + def test_container_delete(self, mock_delete): container = Container(self.context, **utils.get_test_container()) self.compute_manager.container_delete(self. context, container, False) mock_delete.assert_called_once_with(container, False) - @mock.patch.object(manager.Manager, '_validate_container_state') - def test_container_delete_invalid_state(self, mock_validate): - container = Container(self.context, **utils.get_test_container()) - mock_validate.side_effect = exception.InvalidStateException - self.assertRaises(exception.InvalidStateException, - self.compute_manager.container_delete, - self.context, container, False) - - @mock.patch.object(manager.Manager, '_validate_container_state') @mock.patch.object(fake_driver, 'delete') - def test_container_delete_failed(self, mock_delete, mock_validate): + def test_container_delete_failed(self, mock_delete): container = Container(self.context, **utils.get_test_container()) mock_delete.side_effect = exception.DockerError self.assertRaises(exception.DockerError, @@ -268,130 +231,78 @@ class TestManager(base.TestCase): self.compute_manager.container_show, self.context, container) - @mock.patch.object(manager.Manager, '_validate_container_state') @mock.patch.object(fake_driver, 'reboot') - def test_container_reboot(self, mock_reboot, mock_validate): + def test_container_reboot(self, mock_reboot): container = Container(self.context, **utils.get_test_container()) - self.compute_manager.container_reboot(self.context, container, 10) + self.compute_manager._do_container_reboot(self.context, container, 10) mock_reboot.assert_called_once_with(container, 10) - @mock.patch.object(manager.Manager, '_validate_container_state') - def test_container_reboot_invalid_state(self, mock_validate): - container = Container(self.context, **utils.get_test_container()) - mock_validate.side_effect = exception.InvalidStateException - self.assertRaises(exception.InvalidStateException, - self.compute_manager.container_reboot, - self.context, container, 10) - - @mock.patch.object(manager.Manager, '_validate_container_state') @mock.patch.object(fake_driver, 'reboot') - def test_container_reboot_failed(self, mock_reboot, mock_validate): + def test_container_reboot_failed(self, mock_reboot): container = Container(self.context, **utils.get_test_container()) mock_reboot.side_effect = exception.DockerError self.assertRaises(exception.DockerError, - self.compute_manager.container_reboot, - self.context, container, 10) + self.compute_manager._do_container_reboot, + self.context, container, 10, reraise=True) - @mock.patch.object(manager.Manager, '_validate_container_state') @mock.patch.object(fake_driver, 'stop') - def test_container_stop(self, mock_stop, mock_validate): + def test_container_stop(self, mock_stop): container = Container(self.context, **utils.get_test_container()) - self.compute_manager.container_stop(self.context, container, 10) + self.compute_manager._do_container_stop(self.context, container, 10) mock_stop.assert_called_once_with(container, 10) - @mock.patch.object(manager.Manager, '_validate_container_state') - def test_container_stop_invalid_state(self, mock_validate): - container = Container(self.context, **utils.get_test_container()) - mock_validate.side_effect = exception.InvalidStateException - self.assertRaises(exception.InvalidStateException, - self.compute_manager.container_stop, - self.context, container, 10) - - @mock.patch.object(manager.Manager, '_validate_container_state') @mock.patch.object(fake_driver, 'stop') - def test_container_stop_failed(self, mock_stop, mock_validate): + def test_container_stop_failed(self, mock_stop): container = Container(self.context, **utils.get_test_container()) mock_stop.side_effect = exception.DockerError self.assertRaises(exception.DockerError, - self.compute_manager.container_stop, - self.context, container, 10) + self.compute_manager._do_container_stop, + self.context, container, 10, reraise=True) - @mock.patch.object(manager.Manager, '_validate_container_state') @mock.patch.object(fake_driver, 'start') - def test_container_start(self, mock_start, mock_validate): + def test_container_start(self, mock_start): container = Container(self.context, **utils.get_test_container()) - self.compute_manager.container_start(self.context, container) + self.compute_manager._do_container_start(self.context, container) mock_start.assert_called_once_with(container) - @mock.patch.object(manager.Manager, '_validate_container_state') - @mock.patch.object(manager.Manager, '_fail_container') - def test_container_start_invalid_state(self, mock_fail, mock_validate): - container = Container(self.context, **utils.get_test_container()) - mock_validate.side_effect = exception.InvalidStateException - self.assertRaises(exception.InvalidStateException, - self.compute_manager.container_start, - self.context, container) - mock_fail.assert_called_once() - - @mock.patch.object(manager.Manager, '_validate_container_state') @mock.patch.object(manager.Manager, '_fail_container') @mock.patch.object(fake_driver, 'start') def test_container_start_failed(self, mock_start, - mock_fail, mock_validate): + mock_fail): container = Container(self.context, **utils.get_test_container()) mock_start.side_effect = exception.DockerError self.assertRaises(exception.DockerError, - self.compute_manager.container_start, - self.context, container) + self.compute_manager._do_container_start, + self.context, container, reraise=True) mock_fail.assert_called_once() - @mock.patch.object(manager.Manager, '_validate_container_state') @mock.patch.object(fake_driver, 'pause') - def test_container_pause(self, mock_pause, mock_validate): + def test_container_pause(self, mock_pause): container = Container(self.context, **utils.get_test_container()) - self.compute_manager.container_pause(self.context, container) + self.compute_manager._do_container_pause(self.context, container) mock_pause.assert_called_once_with(container) - @mock.patch.object(manager.Manager, '_validate_container_state') - def test_container_pause_invalid_state(self, mock_validate): - container = Container(self.context, **utils.get_test_container()) - mock_validate.side_effect = exception.InvalidStateException - self.assertRaises(exception.InvalidStateException, - self.compute_manager.container_pause, - self.context, container) - - @mock.patch.object(manager.Manager, '_validate_container_state') @mock.patch.object(fake_driver, 'pause') - def test_container_pause_failed(self, mock_pause, mock_validate): + def test_container_pause_failed(self, mock_pause): container = Container(self.context, **utils.get_test_container()) mock_pause.side_effect = exception.DockerError self.assertRaises(exception.DockerError, - self.compute_manager.container_pause, - self.context, container) + self.compute_manager._do_container_pause, + self.context, container, reraise=True) - @mock.patch.object(manager.Manager, '_validate_container_state') @mock.patch.object(fake_driver, 'unpause') - def test_container_unpause(self, mock_unpause, mock_validate): + def test_container_unpause(self, mock_unpause): container = Container(self.context, **utils.get_test_container()) - self.compute_manager.container_unpause(self.context, container) + self.compute_manager._do_container_unpause(self.context, container) mock_unpause.assert_called_once_with(container) - @mock.patch.object(manager.Manager, '_validate_container_state') - def test_container_unpause_invalid_state(self, mock_validate): - container = Container(self.context, **utils.get_test_container()) - mock_validate.side_effect = exception.InvalidStateException - self.assertRaises(exception.InvalidStateException, - self.compute_manager.container_unpause, - self.context, container) - - @mock.patch.object(manager.Manager, '_validate_container_state') @mock.patch.object(fake_driver, 'unpause') - def test_container_unpause_failed(self, mock_unpause, mock_validate): + def test_container_unpause_failed(self, mock_unpause): container = Container(self.context, **utils.get_test_container()) mock_unpause.side_effect = exception.DockerError self.assertRaises(exception.DockerError, - self.compute_manager.container_unpause, - self.context, container) + self.compute_manager._do_container_unpause, + self.context, container, reraise=True) @mock.patch.object(fake_driver, 'show_logs') def test_container_logs(self, mock_logs): @@ -414,14 +325,6 @@ class TestManager(base.TestCase): self.context, container, 'fake_cmd') mock_execute.assert_called_once_with(container, 'fake_cmd') - @mock.patch.object(manager.Manager, '_validate_container_state') - def test_container_execute_invalid_state(self, mock_validate): - container = Container(self.context, **utils.get_test_container()) - mock_validate.side_effect = exception.InvalidStateException - self.assertRaises(exception.InvalidStateException, - self.compute_manager.container_exec, - self.context, container, 'fake_cmd') - @mock.patch.object(fake_driver, 'execute') def test_container_execute_failed(self, mock_execute): container = Container(self.context, **utils.get_test_container()) @@ -433,22 +336,13 @@ class TestManager(base.TestCase): @mock.patch.object(fake_driver, 'kill') def test_container_kill(self, mock_kill): container = Container(self.context, **utils.get_test_container()) - self.compute_manager.container_kill(self.context, container, None) + self.compute_manager._do_container_kill(self.context, container, None) mock_kill.assert_called_once_with(container, None) - @mock.patch.object(manager.Manager, '_validate_container_state') - def test_container_kill_invalid_state(self, mock_validate): - container = Container(self.context, **utils.get_test_container()) - mock_validate.side_effect = exception.InvalidStateException - self.assertRaises(exception.InvalidStateException, - self.compute_manager.container_kill, - self.context, container, None) - - @mock.patch.object(manager.Manager, '_validate_container_state') @mock.patch.object(fake_driver, 'kill') - def test_container_kill_failed(self, mock_kill, mock_validate): + def test_container_kill_failed(self, mock_kill): container = Container(self.context, **utils.get_test_container()) mock_kill.side_effect = exception.DockerError self.assertRaises(exception.DockerError, - self.compute_manager.container_kill, - self.context, container, None) + self.compute_manager._do_container_kill, + self.context, container, None, reraise=True)