Merge "Make start/stop/pause/unpause/restart/kill action async"

This commit is contained in:
Jenkins 2017-01-09 16:06:42 +00:00 committed by Gerrit Code Review
commit 62482a6acc
9 changed files with 365 additions and 318 deletions

View File

@ -14,6 +14,7 @@
# under the License. # under the License.
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import strutils
from oslo_utils import timeutils from oslo_utils import timeutils
import pecan import pecan
from pecan import rest from pecan import rest
@ -28,6 +29,7 @@ from zun.common import exception
from zun.common.i18n import _LE from zun.common.i18n import _LE
from zun.common import name_generator from zun.common import name_generator
from zun.common import policy from zun.common import policy
from zun.common import utils
from zun.common import validation from zun.common import validation
from zun import objects from zun import objects
from zun.objects import fields from zun.objects import fields
@ -330,6 +332,9 @@ class ContainersController(rest.RestController):
""" """
container = _get_container(container_id) container = _get_container(container_id)
check_policy_on_container(container.as_dict(), "container:delete") 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 context = pecan.request.context
pecan.request.rpcapi.container_delete(context, container, force) pecan.request.rpcapi.container_delete(context, container, force)
container.destroy() container.destroy()
@ -340,57 +345,60 @@ class ContainersController(rest.RestController):
def start(self, container_id, **kw): def start(self, container_id, **kw):
container = _get_container(container_id) container = _get_container(container_id)
check_policy_on_container(container.as_dict(), "container:start") check_policy_on_container(container.as_dict(), "container:start")
utils.validate_container_state(container, 'start')
LOG.debug('Calling compute.container_start with %s', LOG.debug('Calling compute.container_start with %s',
container.uuid) container.uuid)
context = pecan.request.context context = pecan.request.context
container = pecan.request.rpcapi.container_start(context, container) pecan.request.rpcapi.container_start(context, container)
return Container.convert_with_links(container.as_dict()) pecan.response.status = 202
@pecan.expose('json') @pecan.expose('json')
@exception.wrap_pecan_controller_exception @exception.wrap_pecan_controller_exception
def stop(self, container_id, timeout=None, **kw): def stop(self, container_id, timeout=None, **kw):
container = _get_container(container_id) container = _get_container(container_id)
check_policy_on_container(container.as_dict(), "container:stop") check_policy_on_container(container.as_dict(), "container:stop")
utils.validate_container_state(container, 'stop')
LOG.debug('Calling compute.container_stop with %s' % LOG.debug('Calling compute.container_stop with %s' %
container.uuid) container.uuid)
context = pecan.request.context context = pecan.request.context
container = pecan.request.rpcapi.container_stop(context, container, pecan.request.rpcapi.container_stop(context, container, timeout)
timeout) pecan.response.status = 202
return Container.convert_with_links(container.as_dict())
@pecan.expose('json') @pecan.expose('json')
@exception.wrap_pecan_controller_exception @exception.wrap_pecan_controller_exception
def reboot(self, container_id, timeout=None, **kw): def reboot(self, container_id, timeout=None, **kw):
container = _get_container(container_id) container = _get_container(container_id)
check_policy_on_container(container.as_dict(), "container:reboot") check_policy_on_container(container.as_dict(), "container:reboot")
utils.validate_container_state(container, 'reboot')
LOG.debug('Calling compute.container_reboot with %s' % LOG.debug('Calling compute.container_reboot with %s' %
container.uuid) container.uuid)
context = pecan.request.context context = pecan.request.context
container = pecan.request.rpcapi.container_reboot(context, container, pecan.request.rpcapi.container_reboot(context, container, timeout)
timeout) pecan.response.status = 202
return Container.convert_with_links(container.as_dict())
@pecan.expose('json') @pecan.expose('json')
@exception.wrap_pecan_controller_exception @exception.wrap_pecan_controller_exception
def pause(self, container_id, **kw): def pause(self, container_id, **kw):
container = _get_container(container_id) container = _get_container(container_id)
check_policy_on_container(container.as_dict(), "container:pause") check_policy_on_container(container.as_dict(), "container:pause")
utils.validate_container_state(container, 'pause')
LOG.debug('Calling compute.container_pause with %s' % LOG.debug('Calling compute.container_pause with %s' %
container.uuid) container.uuid)
context = pecan.request.context context = pecan.request.context
container = pecan.request.rpcapi.container_pause(context, container) pecan.request.rpcapi.container_pause(context, container)
return Container.convert_with_links(container.as_dict()) pecan.response.status = 202
@pecan.expose('json') @pecan.expose('json')
@exception.wrap_pecan_controller_exception @exception.wrap_pecan_controller_exception
def unpause(self, container_id, **kw): def unpause(self, container_id, **kw):
container = _get_container(container_id) container = _get_container(container_id)
check_policy_on_container(container.as_dict(), "container:unpause") check_policy_on_container(container.as_dict(), "container:unpause")
utils.validate_container_state(container, 'unpause')
LOG.debug('Calling compute.container_unpause with %s' % LOG.debug('Calling compute.container_unpause with %s' %
container.uuid) container.uuid)
context = pecan.request.context context = pecan.request.context
container = pecan.request.rpcapi.container_unpause(context, container) pecan.request.rpcapi.container_unpause(context, container)
return Container.convert_with_links(container.as_dict()) pecan.response.status = 202
@pecan.expose('json') @pecan.expose('json')
@exception.wrap_pecan_controller_exception @exception.wrap_pecan_controller_exception
@ -407,6 +415,7 @@ class ContainersController(rest.RestController):
def execute(self, container_id, **kw): def execute(self, container_id, **kw):
container = _get_container(container_id) container = _get_container(container_id)
check_policy_on_container(container.as_dict(), "container:execute") 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' LOG.debug('Calling compute.container_exec with %s command %s'
% (container.uuid, kw['command'])) % (container.uuid, kw['command']))
context = pecan.request.context context = pecan.request.context
@ -418,9 +427,10 @@ class ContainersController(rest.RestController):
def kill(self, container_id, **kw): def kill(self, container_id, **kw):
container = _get_container(container_id) container = _get_container(container_id)
check_policy_on_container(container.as_dict(), "container:kill") 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' LOG.debug('Calling compute.container_kill with %s signal %s'
% (container.uuid, kw.get('signal', kw.get('signal')))) % (container.uuid, kw.get('signal', kw.get('signal'))))
context = pecan.request.context context = pecan.request.context
container = pecan.request.rpcapi.container_kill(context, container, pecan.request.rpcapi.container_kill(context, container,
kw.get('signal')) kw.get('signal', None))
return Container.convert_with_links(container.as_dict()) pecan.response.status = 202

View File

@ -35,6 +35,26 @@ from zun.common.i18n import _LW
LOG = logging.getLogger(__name__) 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): def safe_rstrip(value, chars=None):
"""Removes trailing characters from a string if that does not make it empty """Removes trailing characters from a string if that does not make it empty

View File

@ -16,7 +16,6 @@ import six
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import excutils from oslo_utils import excutils
from oslo_utils import strutils
from zun.common import exception from zun.common import exception
from zun.common.i18n import _LE from zun.common.i18n import _LE
@ -29,17 +28,6 @@ from zun.objects import fields
LOG = logging.getLogger(__name__) 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): class Manager(object):
'''Manages the running containers.''' '''Manages the running containers.'''
@ -54,17 +42,9 @@ class Manager(object):
container.task_state = None container.task_state = None
container.save() 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): def container_create(self, context, container):
utils.spawn_n(self._do_container_create, context, container) utils.spawn_n(self._do_container_create, context, container)
@translate_exception
def container_run(self, context, container): def container_run(self, context, container):
utils.spawn_n(self._do_container_run, 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)) self._fail_container(container, six.text_type(e))
return return
def _do_container_start(self, context, container): def _do_container_start(self, context, container, reraise=False):
LOG.debug('Starting container: %s', container.uuid) LOG.debug('Starting container: %s', container.uuid)
try: 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 = self.driver.start(container)
container.save() container.save()
return container return container
except exception.DockerError as e: except exception.DockerError as e:
LOG.error(_LE("Error occurred while calling Docker start API: %s"), with excutils.save_and_reraise_exception(reraise=reraise):
six.text_type(e)) LOG.error(_LE(
self._fail_container(container, six.text_type(e)) "Error occurred while calling Docker start API: %s"),
raise six.text_type(e))
self._fail_container(container, six.text_type(e))
except Exception as e: except Exception as e:
LOG.exception(_LE("Unexpected exception: %s"), six.text_type(e)) with excutils.save_and_reraise_exception(reraise=reraise):
self._fail_container(container, six.text_type(e)) LOG.exception(_LE("Unexpected exception: %s"),
raise six.text_type(e))
self._fail_container(container, six.text_type(e))
@translate_exception @translate_exception
def container_delete(self, context, container, force): def container_delete(self, context, container, force):
LOG.debug('Deleting container: %s', container.uuid) LOG.debug('Deleting container: %s', container.uuid)
try: try:
force = strutils.bool_from_string(force, strict=True)
if not force:
self._validate_container_state(container, 'delete')
self.driver.delete(container, force) self.driver.delete(container, force)
except exception.DockerError as e: except exception.DockerError as e:
LOG.error(_LE("Error occurred while calling Docker " 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)) LOG.exception(_LE("Unexpected exception: %s"), six.text_type(e))
raise raise
@translate_exception def _do_container_reboot(self, context, container, timeout, reraise=False):
def container_reboot(self, context, container, timeout):
LOG.debug('Rebooting container: %s', container.uuid) LOG.debug('Rebooting container: %s', container.uuid)
try: try:
self._validate_container_state(container, 'reboot')
container = self.driver.reboot(container, timeout) container = self.driver.reboot(container, timeout)
container.save() container.save()
return container return container
except exception.DockerError as e: except exception.DockerError as e:
LOG.error(_LE("Error occurred while calling Docker reboot " with excutils.save_and_reraise_exception(reraise=reraise):
"API: %s"), six.text_type(e)) LOG.error(_LE("Error occurred while calling Docker reboot "
raise "API: %s"), six.text_type(e))
except Exception as e: except Exception as e:
LOG.exception(_LE("Unexpected exception: %s"), six.text_type(e)) with excutils.save_and_reraise_exception(reraise=reraise):
raise LOG.exception(_LE("Unexpected exception: %s"),
six.text_type(e))
@translate_exception def container_reboot(self, context, container, timeout):
def container_stop(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) LOG.debug('Stopping container: %s', container.uuid)
try: try:
self._validate_container_state(container, 'stop')
container = self.driver.stop(container, timeout) container = self.driver.stop(container, timeout)
container.save() container.save()
return container return container
except exception.DockerError as e: except exception.DockerError as e:
LOG.error(_LE("Error occurred while calling Docker stop API: %s"), with excutils.save_and_reraise_exception(reraise=reraise):
six.text_type(e)) LOG.error(_LE(
raise "Error occurred while calling Docker stop API: %s"),
six.text_type(e))
except Exception as e: except Exception as e:
LOG.exception(_LE("Unexpected exception: %s"), six.text_type(e)) with excutils.save_and_reraise_exception(reraise=reraise):
raise 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): 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 _do_container_pause(self, context, container, reraise=False):
def container_pause(self, context, container):
LOG.debug('Pausing container: %s', container.uuid) LOG.debug('Pausing container: %s', container.uuid)
try: try:
self._validate_container_state(container, 'pause')
container = self.driver.pause(container) container = self.driver.pause(container)
container.save() container.save()
return container return container
except exception.DockerError as e: except exception.DockerError as e:
LOG.error(_LE("Error occurred while calling Docker pause API: %s"), with excutils.save_and_reraise_exception(reraise=reraise):
six.text_type(e)) LOG.error(_LE(
raise "Error occurred while calling Docker pause API: %s"),
six.text_type(e))
except Exception as e: except Exception as e:
LOG.exception(_LE("Unexpected exception: %s,"), six.text_type(e)) with excutils.save_and_reraise_exception(reraise=reraise):
raise LOG.exception(_LE("Unexpected exception: %s,"),
six.text_type(e))
@translate_exception def container_pause(self, context, container):
def container_unpause(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) LOG.debug('Unpausing container: %s', container.uuid)
try: try:
self._validate_container_state(container, 'unpause')
container = self.driver.unpause(container) container = self.driver.unpause(container)
container.save() container.save()
return container return container
except exception.DockerError as e: except exception.DockerError as e:
LOG.error(_LE("Error occurred while calling Docker unpause " with excutils.save_and_reraise_exception(reraise=reraise):
"API: %s"), LOG.error(_LE(
six.text_type(e)) "Error occurred while calling Docker unpause API: %s"),
raise six.text_type(e))
except Exception as e: except Exception as e:
LOG.exception(_LE("Unexpected exception: %s"), six.text_type(e)) with excutils.save_and_reraise_exception(reraise=reraise):
raise 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 @translate_exception
def container_logs(self, context, container): def container_logs(self, context, container):
@ -317,7 +302,6 @@ class Manager(object):
# TODO(hongbin): support exec command interactively # TODO(hongbin): support exec command interactively
LOG.debug('Executing command in container: %s', container.uuid) LOG.debug('Executing command in container: %s', container.uuid)
try: try:
self._validate_container_state(container, 'exec')
return self.driver.execute(container, command) return self.driver.execute(container, command)
except exception.DockerError as e: except exception.DockerError as e:
LOG.error(_LE("Error occurred while calling Docker exec API: %s"), 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)) LOG.exception(_LE("Unexpected exception: %s"), six.text_type(e))
raise raise
@translate_exception def _do_container_kill(self, context, container, signal, reraise=False):
def container_kill(self, context, container, signal):
LOG.debug('kill signal to container: %s', container.uuid) LOG.debug('kill signal to container: %s', container.uuid)
try: try:
self._validate_container_state(container, 'kill')
container = self.driver.kill(container, signal) container = self.driver.kill(container, signal)
container.save() container.save()
return container return container
except exception.DockerError as e: except exception.DockerError as e:
LOG.error(_LE("Error occurred while calling Docker kill API: %s"), with excutils.save_and_reraise_exception(reraise=reraise):
six.text_type(e)) LOG.error(_LE(
raise "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): def image_pull(self, context, image):
utils.spawn_n(self._do_image_pull, context, image) utils.spawn_n(self._do_image_pull, context, image)

View File

@ -47,21 +47,21 @@ class API(rpc_service.API):
return self._call('container_show', container=container) return self._call('container_show', container=container)
def container_reboot(self, context, container, timeout): def container_reboot(self, context, container, timeout):
return self._call('container_reboot', container=container, return self._cast('container_reboot', container=container,
timeout=timeout) timeout=timeout)
def container_stop(self, context, container, timeout): def container_stop(self, context, container, timeout):
return self._call('container_stop', container=container, return self._cast('container_stop', container=container,
timeout=timeout) timeout=timeout)
def container_start(self, context, container): 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): 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): 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): def container_logs(self, context, container):
return self._call('container_logs', container=container) return self._call('container_logs', container=container)
@ -71,7 +71,7 @@ class API(rpc_service.API):
command=command) command=command)
def container_kill(self, context, container, signal): def container_kill(self, context, container, signal):
return self._call('container_kill', container=container, return self._cast('container_kill', container=container,
signal=signal) signal=signal)
def image_show(self, context, image): def image_show(self, context, image):

View File

@ -123,34 +123,28 @@ class ZunClient(rest_client.RestClient):
self.container_uri(container_id, params=params), **kwargs) self.container_uri(container_id, params=params), **kwargs)
def start_container(self, container_id, **kwargs): def start_container(self, container_id, **kwargs):
resp, body = self.post( return self.post(
self.container_uri(container_id, action='start'), None, **kwargs) self.container_uri(container_id, action='start'), None, **kwargs)
return self.deserialize(resp, body, container_model.ContainerEntity)
def stop_container(self, container_id, **kwargs): def stop_container(self, container_id, **kwargs):
resp, body = self.post( return self.post(
self.container_uri(container_id, action='stop'), None, *kwargs) self.container_uri(container_id, action='stop'), None, *kwargs)
return self.deserialize(resp, body, container_model.ContainerEntity)
def pause_container(self, container_id, **kwargs): def pause_container(self, container_id, **kwargs):
resp, body = self.post( return self.post(
self.container_uri(container_id, action='pause'), None, **kwargs) self.container_uri(container_id, action='pause'), None, **kwargs)
return self.deserialize(resp, body, container_model.ContainerEntity)
def unpause_container(self, container_id, **kwargs): def unpause_container(self, container_id, **kwargs):
resp, body = self.post( return self.post(
self.container_uri(container_id, action='unpause'), None, **kwargs) self.container_uri(container_id, action='unpause'), None, **kwargs)
return self.deserialize(resp, body, container_model.ContainerEntity)
def kill_container(self, container_id, **kwargs): def kill_container(self, container_id, **kwargs):
resp, body = self.post( return self.post(
self.container_uri(container_id, action='kill'), None, **kwargs) self.container_uri(container_id, action='kill'), None, **kwargs)
return self.deserialize(resp, body, container_model.ContainerEntity)
def reboot_container(self, container_id, **kwargs): def reboot_container(self, container_id, **kwargs):
resp, body = self.post( return self.post(
self.container_uri(container_id, action='reboot'), None, **kwargs) 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): def exec_container(self, container_id, command, **kwargs):
return self.post( return self.post(
@ -166,25 +160,14 @@ class ZunClient(rest_client.RestClient):
return self.deserialize(resp, body, return self.deserialize(resp, body,
service_model.ServiceCollection) service_model.ServiceCollection)
def ensure_container_created(self, container_id): def ensure_container_in_desired_state(self, container_id, status):
def container_created(): def is_container_in_desired_state():
_, container = self.get_container(container_id) _, container = self.get_container(container_id)
if container.status == 'Creating': if container.status == status:
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':
return True return True
else: else:
return False return False
utils.wait_for_condition(is_container_in_desired_state)
utils.wait_for_condition(container_started)
class DockerClient(object): class DockerClient(object):
@ -195,3 +178,13 @@ class DockerClient(object):
if container_id in info['Name']: if container_id in info['Name']:
return info return info
return None 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)

View File

@ -81,37 +81,42 @@ class TestContainer(base.BaseZunTest):
def test_start_stop_container(self): def test_start_stop_container(self):
_, model = self._run_container() _, model = self._run_container()
resp, model = self.container_client.stop_container(model.uuid) resp, _ = self.container_client.stop_container(model.uuid)
self.assertEqual(200, resp.status) self.assertEqual(202, resp.status)
self.assertEqual('Stopped', model.status) self.container_client.ensure_container_in_desired_state(
model.uuid, 'Stopped')
self.assertEqual('Stopped', self._get_container_state(model.uuid)) self.assertEqual('Stopped', self._get_container_state(model.uuid))
resp, model = self.container_client.start_container(model.uuid) resp, _ = self.container_client.start_container(model.uuid)
self.assertEqual(200, resp.status) self.assertEqual(202, resp.status)
self.assertEqual('Running', model.status) self.container_client.ensure_container_in_desired_state(
model.uuid, 'Running')
self.assertEqual('Running', self._get_container_state(model.uuid)) self.assertEqual('Running', self._get_container_state(model.uuid))
@decorators.idempotent_id('b5f39756-8898-4e0e-a48b-dda0a06b66b6') @decorators.idempotent_id('b5f39756-8898-4e0e-a48b-dda0a06b66b6')
def test_pause_unpause_container(self): def test_pause_unpause_container(self):
_, model = self._run_container() _, model = self._run_container()
resp, model = self.container_client.pause_container(model.uuid) resp, _ = self.container_client.pause_container(model.uuid)
self.assertEqual(200, resp.status) self.assertEqual(202, resp.status)
self.assertEqual('Paused', model.status) self.container_client.ensure_container_in_desired_state(
model.uuid, 'Paused')
self.assertEqual('Paused', self._get_container_state(model.uuid)) self.assertEqual('Paused', self._get_container_state(model.uuid))
resp, model = self.container_client.unpause_container(model.uuid) resp, _ = self.container_client.unpause_container(model.uuid)
self.assertEqual(200, resp.status) self.assertEqual(202, resp.status)
self.assertEqual('Running', model.status) self.container_client.ensure_container_in_desired_state(
model.uuid, 'Running')
self.assertEqual('Running', self._get_container_state(model.uuid)) self.assertEqual('Running', self._get_container_state(model.uuid))
@decorators.idempotent_id('6179a588-3d48-4372-9599-f228411d1449') @decorators.idempotent_id('6179a588-3d48-4372-9599-f228411d1449')
def test_kill_container(self): def test_kill_container(self):
_, model = self._run_container() _, model = self._run_container()
resp, model = self.container_client.kill_container(model.uuid) resp, _ = self.container_client.kill_container(model.uuid)
self.assertEqual(200, resp.status) self.assertEqual(202, resp.status)
self.assertEqual('Stopped', model.status) self.container_client.ensure_container_in_desired_state(
model.uuid, 'Stopped')
self.assertEqual('Stopped', self._get_container_state(model.uuid)) self.assertEqual('Stopped', self._get_container_state(model.uuid))
@decorators.idempotent_id('c2e54321-0a70-4331-ba62-9dcaa75ac250') @decorators.idempotent_id('c2e54321-0a70-4331-ba62-9dcaa75ac250')
@ -120,9 +125,9 @@ class TestContainer(base.BaseZunTest):
container = self.docker_client.get_container(model.uuid) container = self.docker_client.get_container(model.uuid)
pid = container.get('State').get('Pid') pid = container.get('State').get('Pid')
resp, model = self.container_client.reboot_container(model.uuid) resp, _ = self.container_client.reboot_container(model.uuid)
self.assertEqual(200, resp.status) self.assertEqual(202, resp.status)
self.assertEqual('Running', model.status) self.docker_client.ensure_container_pid_changed(model.uuid, pid)
self.assertEqual('Running', self._get_container_state(model.uuid)) self.assertEqual('Running', self._get_container_state(model.uuid))
# assert pid is changed # assert pid is changed
container = self.docker_client.get_container(model.uuid) 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) resp, model = self.container_client.post_container(gen_model)
self.assertEqual(202, resp.status) self.assertEqual(202, resp.status)
# Wait for container to finish creation # 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 # Assert the container is created
resp, model = self.container_client.get_container(model.uuid) 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) resp, model = self.container_client.run_container(gen_model)
self.assertEqual(202, resp.status) self.assertEqual(202, resp.status)
# Wait for container to started # 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 # Assert the container is started
resp, model = self.container_client.get_container(model.uuid) resp, model = self.container_client.get_container(model.uuid)
self.assertTrue(model.status in ['Running', 'Stopped']) self.assertEqual('Running', model.status)
self.assertTrue(self._get_container_state(model.uuid) in self.assertEqual('Running', self._get_container_state(model.uuid))
['Running', 'Stopped'])
return resp, model return resp, model
def _delete_container(self, container_id): def _delete_container(self, container_id):

View File

@ -146,7 +146,8 @@ class TestContainerController(api_base.FunctionalTest):
self.assertEqual({"key1": "val1", "key2": "val2"}, self.assertEqual({"key1": "val1", "key2": "val2"},
c.get('environment')) c.get('environment'))
# Delete the container we created # 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) self.assertEqual(204, response.status_int)
response = self.app.get('/v1/containers/') response = self.app.get('/v1/containers/')
@ -415,7 +416,7 @@ class TestContainerController(api_base.FunctionalTest):
self.assertEqual('new_name', test_container_obj.name) self.assertEqual('new_name', test_container_obj.name)
def _action_test(self, container, action, ident_field, 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) test_container_obj = objects.Container(self.context, **container)
ident = container.get(ident_field) ident = container.get(ident_field)
get_by_ident_loc = 'zun.objects.Container.get_by_%s' % 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 mock_get_by_indent.return_value = test_container_obj
response = self.app.post('/v1/containers/%s/%s/?%s' % response = self.app.post('/v1/containers/%s/%s/?%s' %
(ident, action, query_param)) (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 # Only PUT should work, others like GET should fail
self.assertRaises(AppError, self.app.get, self.assertRaises(AppError, self.app.get,
@ -437,98 +438,154 @@ class TestContainerController(api_base.FunctionalTest):
mock_container_action.assert_called_once_with( mock_container_action.assert_called_once_with(
mock.ANY, test_container_obj) mock.ANY, test_container_obj)
@patch('zun.common.utils.validate_container_state')
@patch('zun.compute.rpcapi.API.container_start') @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, test_container_obj = objects.Container(self.context,
**utils.get_test_container()) **utils.get_test_container())
mock_container_start.return_value = test_container_obj mock_container_start.return_value = test_container_obj
test_container = utils.get_test_container() test_container = utils.get_test_container()
self._action_test(test_container, 'start', 'uuid', 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') @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, test_container_obj = objects.Container(self.context,
**utils.get_test_container()) **utils.get_test_container())
mock_container_start.return_value = test_container_obj mock_container_start.return_value = test_container_obj
test_container = utils.get_test_container() test_container = utils.get_test_container()
self._action_test(test_container, 'start', 'name', 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') @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, test_container_obj = objects.Container(self.context,
**utils.get_test_container()) **utils.get_test_container())
mock_container_stop.return_value = test_container_obj mock_container_stop.return_value = test_container_obj
test_container = utils.get_test_container() test_container = utils.get_test_container()
self._action_test(test_container, 'stop', 'uuid', self._action_test(test_container, 'stop', 'uuid',
mock_container_stop, mock_container_stop, 202,
query_param='timeout=10') query_param='timeout=10')
@patch('zun.common.utils.validate_container_state')
@patch('zun.compute.rpcapi.API.container_stop') @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, test_container_obj = objects.Container(self.context,
**utils.get_test_container()) **utils.get_test_container())
mock_container_stop.return_value = test_container_obj mock_container_stop.return_value = test_container_obj
test_container = utils.get_test_container() test_container = utils.get_test_container()
self._action_test(test_container, 'stop', 'name', self._action_test(test_container, 'stop', 'name',
mock_container_stop, mock_container_stop, 202,
query_param='timeout=10') 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') @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, test_container_obj = objects.Container(self.context,
**utils.get_test_container()) **utils.get_test_container())
mock_container_pause.return_value = test_container_obj mock_container_pause.return_value = test_container_obj
test_container = utils.get_test_container() test_container = utils.get_test_container()
self._action_test(test_container, 'pause', 'uuid', 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') @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, test_container_obj = objects.Container(self.context,
**utils.get_test_container()) **utils.get_test_container())
mock_container_pause.return_value = test_container_obj mock_container_pause.return_value = test_container_obj
test_container = utils.get_test_container() test_container = utils.get_test_container()
self._action_test(test_container, 'pause', 'name', 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') @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, test_container_obj = objects.Container(self.context,
**utils.get_test_container()) **utils.get_test_container())
mock_container_unpause.return_value = test_container_obj mock_container_unpause.return_value = test_container_obj
test_container = utils.get_test_container() test_container = utils.get_test_container()
self._action_test(test_container, 'unpause', 'uuid', 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') @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, test_container_obj = objects.Container(self.context,
**utils.get_test_container()) **utils.get_test_container())
mock_container_unpause.return_value = test_container_obj mock_container_unpause.return_value = test_container_obj
test_container = utils.get_test_container() test_container = utils.get_test_container()
self._action_test(test_container, 'unpause', 'name', 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') @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, test_container_obj = objects.Container(self.context,
**utils.get_test_container()) **utils.get_test_container())
mock_container_reboot.return_value = test_container_obj mock_container_reboot.return_value = test_container_obj
test_container = utils.get_test_container() test_container = utils.get_test_container()
self._action_test(test_container, 'reboot', 'uuid', self._action_test(test_container, 'reboot', 'uuid',
mock_container_reboot, mock_container_reboot, 202,
query_param='timeout=10') 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') @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, test_container_obj = objects.Container(self.context,
**utils.get_test_container()) **utils.get_test_container())
mock_container_reboot.return_value = test_container_obj mock_container_reboot.return_value = test_container_obj
test_container = utils.get_test_container() test_container = utils.get_test_container()
self._action_test(test_container, 'reboot', 'name', self._action_test(test_container, 'reboot', 'name',
mock_container_reboot, mock_container_reboot, 202,
query_param='timeout=10') query_param='timeout=10')
@patch('zun.compute.rpcapi.API.container_logs') @patch('zun.compute.rpcapi.API.container_logs')
@ -573,10 +630,11 @@ class TestContainerController(api_base.FunctionalTest):
'/v1/containers/%s/logs/' % container_uuid) '/v1/containers/%s/logs/' % container_uuid)
self.assertFalse(mock_container_logs.called) self.assertFalse(mock_container_logs.called)
@patch('zun.common.utils.validate_container_state')
@patch('zun.compute.rpcapi.API.container_exec') @patch('zun.compute.rpcapi.API.container_exec')
@patch('zun.objects.Container.get_by_uuid') @patch('zun.objects.Container.get_by_uuid')
def test_execute_command_by_uuid(self, mock_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 = "" mock_container_exec.return_value = ""
test_container = utils.get_test_container() test_container = utils.get_test_container()
test_container_obj = objects.Container(self.context, **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_container_exec.assert_called_once_with(
mock.ANY, test_container_obj, cmd['command']) 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.compute.rpcapi.API.container_exec')
@patch('zun.objects.Container.get_by_name') @patch('zun.objects.Container.get_by_name')
def test_execute_command_by_name(self, mock_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 = "" mock_container_exec.return_value = ""
test_container = utils.get_test_container() test_container = utils.get_test_container()
test_container_obj = objects.Container(self.context, **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_container_exec.assert_called_once_with(
mock.ANY, test_container_obj, cmd['command']) mock.ANY, test_container_obj, cmd['command'])
@patch('zun.common.utils.validate_container_state')
@patch('zun.compute.rpcapi.API.container_delete') @patch('zun.compute.rpcapi.API.container_delete')
@patch('zun.objects.Container.get_by_uuid') @patch('zun.objects.Container.get_by_uuid')
def test_delete_container_by_uuid(self, mock_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 = utils.get_test_container()
test_container_obj = objects.Container(self.context, **test_container) test_container_obj = objects.Container(self.context, **test_container)
mock_get_by_uuid.return_value = test_container_obj 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.ANY, test_container_obj, False)
mock_destroy.assert_called_once_with() 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.compute.rpcapi.API.container_delete')
@patch('zun.objects.Container.get_by_name') @patch('zun.objects.Container.get_by_name')
def test_delete_container_by_name(self, mock_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 = utils.get_test_container()
test_container_obj = objects.Container(self.context, **test_container) test_container_obj = objects.Container(self.context, **test_container)
mock_get_by_name.return_value = test_container_obj 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.ANY, test_container_obj, False)
mock_destroy.assert_called_once_with() mock_destroy.assert_called_once_with()
@patch('zun.common.utils.validate_container_state')
@patch('zun.compute.rpcapi.API.container_kill') @patch('zun.compute.rpcapi.API.container_kill')
@patch('zun.objects.Container.get_by_uuid') @patch('zun.objects.Container.get_by_uuid')
def test_kill_container_by_uuid(self, 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, test_container_obj = objects.Container(self.context,
**utils.get_test_container()) **utils.get_test_container())
mock_container_kill.return_value = test_container_obj 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') url = '/v1/containers/%s/%s/' % (container_uuid, 'kill')
cmd = {'signal': '9'} cmd = {'signal': '9'}
response = self.app.post(url, cmd) 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_container_kill.assert_called_once_with(
mock.ANY, test_container_obj, cmd['signal']) 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.compute.rpcapi.API.container_kill')
@patch('zun.objects.Container.get_by_name') @patch('zun.objects.Container.get_by_name')
def test_kill_container_by_name(self, 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, test_container_obj = objects.Container(self.context,
**utils.get_test_container()) **utils.get_test_container())
mock_container_kill.return_value = test_container_obj 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') url = '/v1/containers/%s/%s/' % (container_name, 'kill')
cmd = {'signal': '9'} cmd = {'signal': '9'}
response = self.app.post(url, cmd) 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_container_kill.assert_called_once_with(
mock.ANY, test_container_obj, cmd['signal']) mock.ANY, test_container_obj, cmd['signal'])
@patch('zun.common.utils.validate_container_state')
@patch('zun.compute.rpcapi.API.container_kill') @patch('zun.compute.rpcapi.API.container_kill')
@patch('zun.objects.Container.get_by_uuid') @patch('zun.objects.Container.get_by_uuid')
def test_kill_container_which_not_exist(self, def test_kill_container_which_not_exist(self,
mock_get_by_uuid, mock_get_by_uuid,
mock_container_kill): mock_container_kill,
mock_validate):
mock_container_kill.return_value = "" mock_container_kill.return_value = ""
test_container = utils.get_test_container() test_container = utils.get_test_container()
test_container_obj = objects.Container(self.context, **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')) '/v1/containers/%s/%s/' % (container_uuid, 'kill'))
self.assertTrue(mock_container_kill.called) self.assertTrue(mock_container_kill.called)
@patch('zun.common.utils.validate_container_state')
@patch('zun.compute.rpcapi.API.container_kill') @patch('zun.compute.rpcapi.API.container_kill')
@patch('zun.objects.Container.get_by_uuid') @patch('zun.objects.Container.get_by_uuid')
def test_kill_container_with_exception(self, def test_kill_container_with_exception(self,
mock_get_by_uuid, mock_get_by_uuid,
mock_container_kill): mock_container_kill,
mock_validate):
mock_container_kill.return_value = "" mock_container_kill.return_value = ""
test_container = utils.get_test_container() test_container = utils.get_test_container()
test_container_obj = objects.Container(self.context, **test_container) test_container_obj = objects.Container(self.context, **test_container)

View File

@ -18,10 +18,12 @@ from zun.common import exception
from zun.common import utils from zun.common import utils
from zun.common.utils import check_container_id from zun.common.utils import check_container_id
from zun.common.utils import translate_exception from zun.common.utils import translate_exception
from zun.objects.container import Container
from zun.tests import base 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""" """Test cases for zun.common.utils"""
def test_check_container_id(self): 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('always', False))
self.assertTrue(utils.should_pull_image('ifnotpresent', False)) self.assertTrue(utils.should_pull_image('ifnotpresent', False))
self.assertFalse(utils.should_pull_image('ifnotpresent', True)) 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'))

View File

@ -42,33 +42,6 @@ class TestManager(base.TestCase):
self.assertEqual("Creation Failed", container.status_reason) self.assertEqual("Creation Failed", container.status_reason)
self.assertIsNone(container.task_state) 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.object(Container, 'save')
@mock.patch('zun.image.driver.pull_image') @mock.patch('zun.image.driver.pull_image')
@mock.patch.object(fake_driver, 'create') @mock.patch.object(fake_driver, 'create')
@ -218,24 +191,14 @@ class TestManager(base.TestCase):
mock_create.assert_called_once_with(container, None, mock_create.assert_called_once_with(container, None,
{'name': 'nginx', 'path': None}) {'name': 'nginx', 'path': None})
@mock.patch.object(manager.Manager, '_validate_container_state')
@mock.patch.object(fake_driver, 'delete') @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()) container = Container(self.context, **utils.get_test_container())
self.compute_manager.container_delete(self. context, container, False) self.compute_manager.container_delete(self. context, container, False)
mock_delete.assert_called_once_with(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') @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()) container = Container(self.context, **utils.get_test_container())
mock_delete.side_effect = exception.DockerError mock_delete.side_effect = exception.DockerError
self.assertRaises(exception.DockerError, self.assertRaises(exception.DockerError,
@ -268,130 +231,78 @@ class TestManager(base.TestCase):
self.compute_manager.container_show, self.compute_manager.container_show,
self.context, container) self.context, container)
@mock.patch.object(manager.Manager, '_validate_container_state')
@mock.patch.object(fake_driver, 'reboot') @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()) 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_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') @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()) container = Container(self.context, **utils.get_test_container())
mock_reboot.side_effect = exception.DockerError mock_reboot.side_effect = exception.DockerError
self.assertRaises(exception.DockerError, self.assertRaises(exception.DockerError,
self.compute_manager.container_reboot, self.compute_manager._do_container_reboot,
self.context, container, 10) self.context, container, 10, reraise=True)
@mock.patch.object(manager.Manager, '_validate_container_state')
@mock.patch.object(fake_driver, 'stop') @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()) 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_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') @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()) container = Container(self.context, **utils.get_test_container())
mock_stop.side_effect = exception.DockerError mock_stop.side_effect = exception.DockerError
self.assertRaises(exception.DockerError, self.assertRaises(exception.DockerError,
self.compute_manager.container_stop, self.compute_manager._do_container_stop,
self.context, container, 10) self.context, container, 10, reraise=True)
@mock.patch.object(manager.Manager, '_validate_container_state')
@mock.patch.object(fake_driver, 'start') @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()) 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_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(manager.Manager, '_fail_container')
@mock.patch.object(fake_driver, 'start') @mock.patch.object(fake_driver, 'start')
def test_container_start_failed(self, mock_start, def test_container_start_failed(self, mock_start,
mock_fail, mock_validate): mock_fail):
container = Container(self.context, **utils.get_test_container()) container = Container(self.context, **utils.get_test_container())
mock_start.side_effect = exception.DockerError mock_start.side_effect = exception.DockerError
self.assertRaises(exception.DockerError, self.assertRaises(exception.DockerError,
self.compute_manager.container_start, self.compute_manager._do_container_start,
self.context, container) self.context, container, reraise=True)
mock_fail.assert_called_once() mock_fail.assert_called_once()
@mock.patch.object(manager.Manager, '_validate_container_state')
@mock.patch.object(fake_driver, 'pause') @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()) 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_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') @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()) container = Container(self.context, **utils.get_test_container())
mock_pause.side_effect = exception.DockerError mock_pause.side_effect = exception.DockerError
self.assertRaises(exception.DockerError, self.assertRaises(exception.DockerError,
self.compute_manager.container_pause, self.compute_manager._do_container_pause,
self.context, container) self.context, container, reraise=True)
@mock.patch.object(manager.Manager, '_validate_container_state')
@mock.patch.object(fake_driver, 'unpause') @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()) 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_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') @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()) container = Container(self.context, **utils.get_test_container())
mock_unpause.side_effect = exception.DockerError mock_unpause.side_effect = exception.DockerError
self.assertRaises(exception.DockerError, self.assertRaises(exception.DockerError,
self.compute_manager.container_unpause, self.compute_manager._do_container_unpause,
self.context, container) self.context, container, reraise=True)
@mock.patch.object(fake_driver, 'show_logs') @mock.patch.object(fake_driver, 'show_logs')
def test_container_logs(self, mock_logs): def test_container_logs(self, mock_logs):
@ -414,14 +325,6 @@ class TestManager(base.TestCase):
self.context, container, 'fake_cmd') self.context, container, 'fake_cmd')
mock_execute.assert_called_once_with(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') @mock.patch.object(fake_driver, 'execute')
def test_container_execute_failed(self, mock_execute): def test_container_execute_failed(self, mock_execute):
container = Container(self.context, **utils.get_test_container()) container = Container(self.context, **utils.get_test_container())
@ -433,22 +336,13 @@ class TestManager(base.TestCase):
@mock.patch.object(fake_driver, 'kill') @mock.patch.object(fake_driver, 'kill')
def test_container_kill(self, mock_kill): def test_container_kill(self, mock_kill):
container = Container(self.context, **utils.get_test_container()) 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_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') @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()) container = Container(self.context, **utils.get_test_container())
mock_kill.side_effect = exception.DockerError mock_kill.side_effect = exception.DockerError
self.assertRaises(exception.DockerError, self.assertRaises(exception.DockerError,
self.compute_manager.container_kill, self.compute_manager._do_container_kill,
self.context, container, None) self.context, container, None, reraise=True)