Merge "Record container action and event."
This commit is contained in:
commit
138281905e
@ -18,6 +18,7 @@
|
||||
"""Utilities and helper functions."""
|
||||
import eventlet
|
||||
import functools
|
||||
import inspect
|
||||
import mimetypes
|
||||
|
||||
from oslo_concurrency import lockutils
|
||||
@ -36,6 +37,7 @@ from zun.common.i18n import _
|
||||
from zun.common import privileged
|
||||
import zun.conf
|
||||
from zun.network import neutron
|
||||
from zun import objects
|
||||
|
||||
CONF = zun.conf.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -506,3 +508,71 @@ def check_external_network_attach(context, nets):
|
||||
if net.get('router:external') and not net.get('shared'):
|
||||
raise exception.ExternalNetworkAttachForbidden(
|
||||
network_uuid=net['network'])
|
||||
|
||||
|
||||
class EventReporter(object):
|
||||
"""Context manager to report container action events."""
|
||||
|
||||
def __init__(self, context, event_name, *container_uuids):
|
||||
self.context = context
|
||||
self.event_name = event_name
|
||||
self.container_uuids = container_uuids
|
||||
|
||||
def __enter__(self):
|
||||
for uuid in self.container_uuids:
|
||||
objects.ContainerActionEvent.event_start(
|
||||
self.context, uuid, self.event_name, want_result=False)
|
||||
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
for uuid in self.container_uuids:
|
||||
objects.ContainerActionEvent.event_finish(
|
||||
self.context, uuid, self.event_name, exc_val=exc_val,
|
||||
exc_tb=exc_tb, want_result=False)
|
||||
return False
|
||||
|
||||
|
||||
def get_wrapped_function(function):
|
||||
"""Get the method at the bottom of a stack of decorators."""
|
||||
if not hasattr(function, '__closure__') or not function.__closure__:
|
||||
return function
|
||||
|
||||
def _get_wrapped_function(function):
|
||||
if not hasattr(function, '__closure__') or not function.__closure__:
|
||||
return None
|
||||
|
||||
for closure in function.__closure__:
|
||||
func = closure.cell_contents
|
||||
|
||||
deeper_func = _get_wrapped_function(func)
|
||||
if deeper_func:
|
||||
return deeper_func
|
||||
elif hasattr(closure.cell_contents, '__call__'):
|
||||
return closure.cell_contents
|
||||
|
||||
return function
|
||||
|
||||
return _get_wrapped_function(function)
|
||||
|
||||
|
||||
def wrap_container_event(prefix):
|
||||
"""Warps a method to log the event taken on the container, and result.
|
||||
|
||||
This decorator wraps a method to log the start and result of an event, as
|
||||
part of an action taken on a container.
|
||||
"""
|
||||
def helper(function):
|
||||
|
||||
@functools.wraps(function)
|
||||
def decorated_function(self, context, *args, **kwargs):
|
||||
wrapped_func = get_wrapped_function(function)
|
||||
keyed_args = inspect.getcallargs(wrapped_func, self, context,
|
||||
*args, **kwargs)
|
||||
container_uuid = keyed_args['container'].uuid
|
||||
|
||||
event_name = '{0}_{1}'.format(prefix, function.__name__)
|
||||
with EventReporter(context, event_name, container_uuid):
|
||||
return function(self, context, *args, **kwargs)
|
||||
return decorated_function
|
||||
return helper
|
||||
|
@ -16,8 +16,10 @@ networking and storage of containers, and compute hosts on which they run)."""
|
||||
from zun.common import consts
|
||||
from zun.common import exception
|
||||
from zun.common import profiler
|
||||
from zun.compute import container_actions
|
||||
from zun.compute import rpcapi
|
||||
import zun.conf
|
||||
from zun import objects
|
||||
from zun.scheduler import client as scheduler_client
|
||||
|
||||
CONF = zun.conf.CONF
|
||||
@ -32,6 +34,10 @@ class API(object):
|
||||
self.scheduler_client = scheduler_client.SchedulerClient()
|
||||
super(API, self).__init__()
|
||||
|
||||
def _record_action_start(self, context, container, action):
|
||||
objects.ContainerAction.action_start(context, container.uuid,
|
||||
action, want_result=False)
|
||||
|
||||
def container_create(self, context, new_container, extra_spec,
|
||||
requested_networks, requested_volumes, run,
|
||||
pci_requests=None):
|
||||
@ -55,6 +61,8 @@ class API(object):
|
||||
if not images:
|
||||
raise exception.ImageNotFound(image=new_container.image)
|
||||
|
||||
self._record_action_start(context, new_container,
|
||||
container_actions.CREATE)
|
||||
self.rpcapi.container_create(context, host_state['host'],
|
||||
new_container, host_state['limits'],
|
||||
requested_networks, requested_volumes,
|
||||
@ -67,24 +75,31 @@ class API(object):
|
||||
return dests[0]
|
||||
|
||||
def container_delete(self, context, container, *args):
|
||||
self._record_action_start(context, container, container_actions.DELETE)
|
||||
return self.rpcapi.container_delete(context, container, *args)
|
||||
|
||||
def container_show(self, context, container, *args):
|
||||
return self.rpcapi.container_show(context, container, *args)
|
||||
|
||||
def container_reboot(self, context, container, *args):
|
||||
self._record_action_start(context, container, container_actions.REBOOT)
|
||||
return self.rpcapi.container_reboot(context, container, *args)
|
||||
|
||||
def container_stop(self, context, container, *args):
|
||||
self._record_action_start(context, container, container_actions.STOP)
|
||||
return self.rpcapi.container_stop(context, container, *args)
|
||||
|
||||
def container_start(self, context, container):
|
||||
self._record_action_start(context, container, container_actions.START)
|
||||
return self.rpcapi.container_start(context, container)
|
||||
|
||||
def container_pause(self, context, container):
|
||||
self._record_action_start(context, container, container_actions.PAUSE)
|
||||
return self.rpcapi.container_pause(context, container)
|
||||
|
||||
def container_unpause(self, context, container):
|
||||
self._record_action_start(context, container,
|
||||
container_actions.UNPAUSE)
|
||||
return self.rpcapi.container_unpause(context, container)
|
||||
|
||||
def container_logs(self, context, container, stdout, stderr,
|
||||
@ -99,6 +114,7 @@ class API(object):
|
||||
return self.rpcapi.container_exec_resize(context, container, *args)
|
||||
|
||||
def container_kill(self, context, container, *args):
|
||||
self._record_action_start(context, container, container_actions.KILL)
|
||||
return self.rpcapi.container_kill(context, container, *args)
|
||||
|
||||
def container_update(self, context, container, *args):
|
||||
@ -117,9 +133,13 @@ class API(object):
|
||||
return self.rpcapi.container_get_archive(context, container, *args)
|
||||
|
||||
def add_security_group(self, context, container, *args):
|
||||
self._record_action_start(context, container,
|
||||
container_actions.ADD_SECURITY_GROUP)
|
||||
return self.rpcapi.add_security_group(context, container, *args)
|
||||
|
||||
def remove_security_group(self, context, container, *args):
|
||||
self._record_action_start(context, container,
|
||||
container_actions.REMOVE_SECURITY_GROUP)
|
||||
return self.rpcapi.remove_security_group(context, container, *args)
|
||||
|
||||
def container_put_archive(self, context, container, *args):
|
||||
@ -129,6 +149,7 @@ class API(object):
|
||||
return self.rpcapi.container_stats(context, container)
|
||||
|
||||
def container_commit(self, context, container, *args):
|
||||
self._record_action_start(context, container, container_actions.COMMIT)
|
||||
return self.rpcapi.container_commit(context, container, *args)
|
||||
|
||||
def image_pull(self, context, image):
|
||||
@ -157,7 +178,11 @@ class API(object):
|
||||
return self.rpcapi.capsule_delete(context, capsule, *args)
|
||||
|
||||
def network_detach(self, context, container, *args):
|
||||
self._record_action_start(context, container,
|
||||
container_actions.NETWORK_DETACH)
|
||||
return self.rpcapi.network_detach(context, container, *args)
|
||||
|
||||
def network_attach(self, context, container, *args):
|
||||
self._record_action_start(context, container,
|
||||
container_actions.NETWORK_ATTACH)
|
||||
return self.rpcapi.network_attach(context, container, *args)
|
||||
|
40
zun/compute/container_actions.py
Normal file
40
zun/compute/container_actions.py
Normal file
@ -0,0 +1,40 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Possible actions on an container.
|
||||
|
||||
Action should probably match a user intention at the API level. Because they
|
||||
can be user visible that should help to avoid confusion. For that reason they
|
||||
tent to maintain the casing sent to the API.
|
||||
|
||||
Maintaining a list of actions here should protect against inconsistencies when
|
||||
they are used.
|
||||
"""
|
||||
|
||||
CREATE = 'create'
|
||||
DELETE = 'delete'
|
||||
REBOOT = 'reboot'
|
||||
STOP = 'stop'
|
||||
START = 'start'
|
||||
PAUSE = 'pause'
|
||||
UNPAUSE = 'unpause'
|
||||
EXEC_CMD = 'exec_cmd'
|
||||
KILL = 'kill'
|
||||
UPDATE = 'update'
|
||||
CONTAINER_ATTACH = 'container_attach'
|
||||
RESIZE = 'resize'
|
||||
ADD_SECURITY_GROUP = 'add_security_group'
|
||||
REMOVE_SECURITY_GROUP = 'remove_security_group'
|
||||
PUT_ARCHIVE = 'put_archive'
|
||||
COMMIT = 'commit'
|
||||
NETWORK_DETACH = 'network_detach'
|
||||
NETWORK_ATTACH = 'network_attach'
|
@ -25,6 +25,7 @@ from zun.common import exception
|
||||
from zun.common.i18n import _
|
||||
from zun.common import utils
|
||||
from zun.common.utils import translate_exception
|
||||
from zun.common.utils import wrap_container_event
|
||||
from zun.compute import compute_node_tracker
|
||||
import zun.conf
|
||||
from zun.container import driver
|
||||
@ -262,6 +263,7 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
unset_host=True)
|
||||
return
|
||||
|
||||
@wrap_container_event(prefix='compute')
|
||||
def _do_container_create(self, context, container, requested_networks,
|
||||
requested_volumes, pci_requests=None,
|
||||
limits=None, reraise=False):
|
||||
@ -378,6 +380,7 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
six.text_type(e))
|
||||
self._fail_container(context, container, six.text_type(e))
|
||||
|
||||
@wrap_container_event(prefix='compute')
|
||||
def _do_container_start(self, context, container, reraise=False):
|
||||
LOG.debug('Starting container: %s', container.uuid)
|
||||
self._update_task_state(context, container, consts.CONTAINER_STARTING)
|
||||
@ -451,6 +454,7 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
|
||||
utils.spawn_n(do_add_security_group)
|
||||
|
||||
@wrap_container_event(prefix='compute')
|
||||
def _add_security_group(self, context, container, security_group):
|
||||
LOG.debug('Adding security_group to container: %s', container.uuid)
|
||||
try:
|
||||
@ -468,6 +472,7 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
|
||||
utils.spawn_n(do_remove_security_group)
|
||||
|
||||
@wrap_container_event(prefix='compute')
|
||||
def _remove_security_group(self, context, container, security_group):
|
||||
LOG.debug('Removing security_group from container: %s', container.uuid)
|
||||
try:
|
||||
@ -510,6 +515,7 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
LOG.exception("Unexpected exception: %s", six.text_type(e))
|
||||
raise
|
||||
|
||||
@wrap_container_event(prefix='compute')
|
||||
def _do_container_reboot(self, context, container, timeout, reraise=False):
|
||||
LOG.debug('Rebooting container: %s', container.uuid)
|
||||
self._update_task_state(context, container, consts.CONTAINER_REBOOTING)
|
||||
@ -535,6 +541,7 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
|
||||
utils.spawn_n(do_container_reboot)
|
||||
|
||||
@wrap_container_event(prefix='compute')
|
||||
def _do_container_stop(self, context, container, timeout, reraise=False):
|
||||
LOG.debug('Stopping container: %s', container.uuid)
|
||||
self._update_task_state(context, container, consts.CONTAINER_STOPPING)
|
||||
@ -567,6 +574,7 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
|
||||
utils.spawn_n(do_container_start)
|
||||
|
||||
@wrap_container_event(prefix='compute')
|
||||
def _do_container_pause(self, context, container, reraise=False):
|
||||
LOG.debug('Pausing container: %s', container.uuid)
|
||||
try:
|
||||
@ -591,6 +599,7 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
|
||||
utils.spawn_n(do_container_pause)
|
||||
|
||||
@wrap_container_event(prefix='compute')
|
||||
def _do_container_unpause(self, context, container, reraise=False):
|
||||
LOG.debug('Unpausing container: %s', container.uuid)
|
||||
try:
|
||||
@ -667,6 +676,7 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
LOG.exception("Unexpected exception: %s", six.text_type(e))
|
||||
raise
|
||||
|
||||
@wrap_container_event(prefix='compute')
|
||||
def _do_container_kill(self, context, container, signal, reraise=False):
|
||||
LOG.debug('Killing a container: %s', container.uuid)
|
||||
try:
|
||||
@ -824,6 +834,7 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
self.driver.delete_image(container_image_id)
|
||||
raise
|
||||
|
||||
@wrap_container_event(prefix='compute')
|
||||
def _do_container_commit(self, context, snapshot_image, container,
|
||||
repository, tag=None):
|
||||
container_image_id = None
|
||||
@ -1034,6 +1045,7 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
capsule.save(context)
|
||||
capsule.destroy(context)
|
||||
|
||||
@wrap_container_event(prefix='compute')
|
||||
def network_detach(self, context, container, network):
|
||||
LOG.debug('Detach network: %(network)s from container: %(container)s.',
|
||||
{'container': container, 'network': network})
|
||||
@ -1043,6 +1055,7 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
with excutils.save_and_reraise_exception(reraise=False):
|
||||
LOG.exception("Unexpected exception: %s", six.text_type(e))
|
||||
|
||||
@wrap_container_event(prefix='compute')
|
||||
def network_attach(self, context, container, network):
|
||||
LOG.debug('Attach network: %(network)s to container: %(container)s.',
|
||||
{'container': container, 'network': network})
|
||||
|
@ -40,6 +40,8 @@ class ContainerAction(base.ZunPersistentObject, base.ZunObject):
|
||||
'start_time': fields.DateTimeField(nullable=True),
|
||||
'finish_time': fields.DateTimeField(nullable=True),
|
||||
'message': fields.StringField(nullable=True),
|
||||
# NOTE: By now, this field is only used for etcd. If using sql,
|
||||
# this field will be None.
|
||||
'uuid': fields.StringField(nullable=True),
|
||||
}
|
||||
|
||||
|
@ -215,3 +215,49 @@ class TestUtils(base.TestCase):
|
||||
mock.ANY,
|
||||
test_image['uuid'])
|
||||
self.assertEqual(test_image['uuid'], image.uuid)
|
||||
|
||||
@mock.patch.object(objects.ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(objects.ContainerActionEvent, 'event_finish')
|
||||
def test_wart_container_event(self, mock_finish, mock_start):
|
||||
container = Container(self.context, **db_utils.get_test_container())
|
||||
|
||||
@utils.wrap_container_event(prefix='compute')
|
||||
def fake_event(self, context, container):
|
||||
pass
|
||||
|
||||
fake_event(self, self.context, container=container)
|
||||
|
||||
self.assertTrue(mock_start.called)
|
||||
self.assertTrue(mock_finish.called)
|
||||
|
||||
@mock.patch.object(objects.ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(objects.ContainerActionEvent, 'event_finish')
|
||||
def test_wrap_container_event_return(self, mock_finish, mock_start):
|
||||
container = Container(self.context, **db_utils.get_test_container())
|
||||
|
||||
@utils.wrap_container_event(prefix='compute')
|
||||
def fake_event(self, context, container):
|
||||
return True
|
||||
|
||||
retval = fake_event(self, self.context, container=container)
|
||||
|
||||
self.assertTrue(retval)
|
||||
self.assertTrue(mock_start.called)
|
||||
self.assertTrue(mock_finish.called)
|
||||
|
||||
@mock.patch.object(objects.ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(objects.ContainerActionEvent, 'event_finish')
|
||||
def test_wrap_conatiner_event_log_exception(self, mock_finish, mock_start):
|
||||
container = Container(self.context, **db_utils.get_test_container())
|
||||
|
||||
@utils.wrap_container_event(prefix='compute')
|
||||
def fake_event(self, context, container):
|
||||
raise exception.ZunException()
|
||||
|
||||
self.assertRaises(exception.ZunException, fake_event,
|
||||
self, self.context, container=container)
|
||||
|
||||
self.assertTrue(mock_start.called)
|
||||
self.assertTrue(mock_finish.called)
|
||||
args, kwargs = mock_finish.call_args
|
||||
self.assertIsInstance(kwargs['exc_val'], exception.ZunException)
|
||||
|
@ -22,6 +22,7 @@ from zun.compute import claims
|
||||
from zun.compute import manager
|
||||
import zun.conf
|
||||
from zun.objects.container import Container
|
||||
from zun.objects.container_action import ContainerActionEvent
|
||||
from zun.objects.image import Image
|
||||
from zun.objects.volume_mapping import VolumeMapping
|
||||
from zun.tests import base
|
||||
@ -183,10 +184,13 @@ class TestManager(base.TestCase):
|
||||
self.assertEqual("Creation Failed", container.status_reason)
|
||||
self.assertIsNone(container.task_state)
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch('zun.image.driver.pull_image')
|
||||
@mock.patch.object(fake_driver, 'create')
|
||||
def test_container_create(self, mock_create, mock_pull, mock_save):
|
||||
def test_container_create(self, mock_create, mock_pull, mock_save,
|
||||
mock_event_finish, mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
image = {'image': 'repo', 'path': 'out_path', 'driver': 'glance'}
|
||||
mock_pull.return_value = image, False
|
||||
@ -201,11 +205,14 @@ class TestManager(base.TestCase):
|
||||
mock_create.assert_called_once_with(self.context, container, image,
|
||||
networks, volumes)
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch('zun.image.driver.pull_image')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
def test_container_create_pull_image_failed_docker_error(
|
||||
self, mock_fail, mock_pull, mock_save):
|
||||
self, mock_fail, mock_pull, mock_save, mock_event_finish,
|
||||
mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_pull.side_effect = exception.DockerError("Pull Failed")
|
||||
networks = []
|
||||
@ -215,11 +222,14 @@ class TestManager(base.TestCase):
|
||||
mock_fail.assert_called_once_with(self.context,
|
||||
container, "Pull Failed")
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch('zun.image.driver.pull_image')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
def test_container_create_pull_image_failed_image_not_found(
|
||||
self, mock_fail, mock_pull, mock_save):
|
||||
self, mock_fail, mock_pull, mock_save, mock_event_finish,
|
||||
mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_pull.side_effect = exception.ImageNotFound("Image Not Found")
|
||||
networks = []
|
||||
@ -229,11 +239,14 @@ class TestManager(base.TestCase):
|
||||
mock_fail.assert_called_once_with(self.context,
|
||||
container, "Image Not Found")
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch('zun.image.driver.pull_image')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
def test_container_create_pull_image_failed_zun_exception(
|
||||
self, mock_fail, mock_pull, mock_save):
|
||||
self, mock_fail, mock_pull, mock_save, mock_event_finish,
|
||||
mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_pull.side_effect = exception.ZunException(
|
||||
message="Image Not Found")
|
||||
@ -244,13 +257,15 @@ class TestManager(base.TestCase):
|
||||
mock_fail.assert_called_once_with(self.context,
|
||||
container, "Image Not Found")
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch('zun.image.driver.pull_image')
|
||||
@mock.patch.object(fake_driver, 'create')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
def test_container_create_docker_create_failed(self, mock_fail,
|
||||
mock_create, mock_pull,
|
||||
mock_save):
|
||||
def test_container_create_docker_create_failed(
|
||||
self, mock_fail, mock_create, mock_pull, mock_save,
|
||||
mock_event_finish, mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
image = {'image': 'repo', 'path': 'out_path', 'driver': 'glance',
|
||||
'repo': 'test', 'tag': 'testtag'}
|
||||
@ -264,6 +279,8 @@ class TestManager(base.TestCase):
|
||||
mock_fail.assert_called_once_with(
|
||||
self.context, container, "Creation Failed", unset_host=True)
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch('zun.common.utils.spawn_n')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(VolumeMapping, 'list_by_container',
|
||||
@ -278,7 +295,7 @@ class TestManager(base.TestCase):
|
||||
self, mock_start, mock_create,
|
||||
mock_is_volume_available, mock_attach_volume,
|
||||
mock_detach_volume, mock_pull, mock_list_by_container, mock_save,
|
||||
mock_spawn_n):
|
||||
mock_spawn_n, mock_event_finish, mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
image = {'image': 'repo', 'path': 'out_path', 'driver': 'glance'}
|
||||
mock_create.return_value = container
|
||||
@ -305,6 +322,8 @@ class TestManager(base.TestCase):
|
||||
mock_is_volume_available.assert_called_once()
|
||||
self.assertEqual(1, len(FakeVolumeMapping.volumes))
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch('zun.common.utils.spawn_n')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(VolumeMapping, 'list_by_container',
|
||||
@ -319,7 +338,7 @@ class TestManager(base.TestCase):
|
||||
self, mock_start, mock_create,
|
||||
mock_is_volume_available, mock_attach_volume,
|
||||
mock_detach_volume, mock_pull, mock_list_by_container, mock_save,
|
||||
mock_spawn_n):
|
||||
mock_spawn_n, mock_event_finish, mock_event_start):
|
||||
mock_is_volume_available.return_value = True
|
||||
mock_attach_volume.side_effect = [None, base.TestingException("fake")]
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
@ -349,6 +368,8 @@ class TestManager(base.TestCase):
|
||||
mock.call(mock.ANY, vol)])
|
||||
self.assertEqual(0, len(FakeVolumeMapping.volumes))
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch('zun.common.utils.spawn_n')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(VolumeMapping, 'list_by_container',
|
||||
@ -360,7 +381,8 @@ class TestManager(base.TestCase):
|
||||
def test_container_run_image_not_found(
|
||||
self, mock_pull, mock_is_volume_available,
|
||||
mock_attach_volume, mock_detach_volume,
|
||||
mock_list_by_container, mock_save, mock_spawn_n):
|
||||
mock_list_by_container, mock_save, mock_spawn_n, mock_event_finish,
|
||||
mock_event_start):
|
||||
container_dict = utils.get_test_container(
|
||||
image='test:latest', image_driver='docker',
|
||||
image_pull_policy='ifnotpresent')
|
||||
@ -386,6 +408,8 @@ class TestManager(base.TestCase):
|
||||
mock_is_volume_available.assert_called_once()
|
||||
self.assertEqual(0, len(FakeVolumeMapping.volumes))
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch('zun.common.utils.spawn_n')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(VolumeMapping, 'list_by_container',
|
||||
@ -397,7 +421,8 @@ class TestManager(base.TestCase):
|
||||
def test_container_run_image_pull_exception_raised(
|
||||
self, mock_pull, mock_is_volume_available,
|
||||
mock_attach_volume, mock_detach_volume,
|
||||
mock_list_by_container, mock_save, mock_spawn_n):
|
||||
mock_list_by_container, mock_save, mock_spawn_n, mock_event_finish,
|
||||
mock_event_start):
|
||||
container_dict = utils.get_test_container(
|
||||
image='test:latest', image_driver='docker',
|
||||
image_pull_policy='ifnotpresent')
|
||||
@ -423,6 +448,8 @@ class TestManager(base.TestCase):
|
||||
mock_is_volume_available.assert_called_once()
|
||||
self.assertEqual(0, len(FakeVolumeMapping.volumes))
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch('zun.common.utils.spawn_n')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(VolumeMapping, 'list_by_container',
|
||||
@ -434,7 +461,8 @@ class TestManager(base.TestCase):
|
||||
def test_container_run_image_pull_docker_error(
|
||||
self, mock_pull, mock_is_volume_available,
|
||||
mock_attach_volume, mock_detach_volume,
|
||||
mock_list_by_container, mock_save, mock_spawn_n):
|
||||
mock_list_by_container, mock_save, mock_spawn_n, mock_event_finish,
|
||||
mock_event_start):
|
||||
container_dict = utils.get_test_container(
|
||||
image='test:latest', image_driver='docker',
|
||||
image_pull_policy='ifnotpresent')
|
||||
@ -460,6 +488,8 @@ class TestManager(base.TestCase):
|
||||
mock_is_volume_available.assert_called_once()
|
||||
self.assertEqual(0, len(FakeVolumeMapping.volumes))
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch('zun.common.utils.spawn_n')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(VolumeMapping, 'list_by_container',
|
||||
@ -472,7 +502,8 @@ class TestManager(base.TestCase):
|
||||
def test_container_run_create_raises_docker_error(
|
||||
self, mock_create, mock_pull, mock_is_volume_available,
|
||||
mock_attach_volume, mock_detach_volume,
|
||||
mock_list_by_container, mock_save, mock_spawn_n):
|
||||
mock_list_by_container, mock_save, mock_spawn_n,
|
||||
mock_event_finish, mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
image = {'image': 'repo', 'path': 'out_path', 'driver': 'glance',
|
||||
'repo': 'test', 'tag': 'testtag'}
|
||||
@ -501,6 +532,8 @@ class TestManager(base.TestCase):
|
||||
mock_is_volume_available.assert_called_once()
|
||||
self.assertEqual(0, len(FakeVolumeMapping.volumes))
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(FakeResourceTracker,
|
||||
'remove_usage_from_container')
|
||||
@mock.patch.object(Container, 'destroy')
|
||||
@ -509,7 +542,8 @@ class TestManager(base.TestCase):
|
||||
@mock.patch.object(fake_driver, 'delete')
|
||||
def test_container_delete(
|
||||
self, mock_delete, mock_list_by_container, mock_save,
|
||||
mock_cnt_destroy, mock_remove_usage):
|
||||
mock_cnt_destroy, mock_remove_usage, mock_event_finish,
|
||||
mock_event_start):
|
||||
mock_list_by_container.return_value = []
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
self.compute_manager._do_container_delete(self. context, container,
|
||||
@ -520,6 +554,8 @@ class TestManager(base.TestCase):
|
||||
mock_remove_usage.assert_called_once_with(self.context, container,
|
||||
True)
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(FakeResourceTracker,
|
||||
'remove_usage_from_container')
|
||||
@mock.patch.object(Container, 'destroy')
|
||||
@ -528,7 +564,8 @@ class TestManager(base.TestCase):
|
||||
@mock.patch.object(fake_driver, 'delete')
|
||||
def test_container_delete_failed(self, mock_delete, mock_save,
|
||||
mock_fail, mock_destroy,
|
||||
mock_remove_usage):
|
||||
mock_remove_usage, mock_event_finish,
|
||||
mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_delete.side_effect = exception.DockerError(
|
||||
message="Docker Error occurred")
|
||||
@ -541,6 +578,8 @@ class TestManager(base.TestCase):
|
||||
mock_destroy.assert_not_called()
|
||||
mock_remove_usage.assert_not_called()
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(FakeResourceTracker,
|
||||
'remove_usage_from_container')
|
||||
@mock.patch.object(Container, 'destroy')
|
||||
@ -552,7 +591,9 @@ class TestManager(base.TestCase):
|
||||
mock_list_by_container,
|
||||
mock_save,
|
||||
mock_fail, mock_destroy,
|
||||
mock_remove_usage):
|
||||
mock_remove_usage,
|
||||
mock_event_finish,
|
||||
mock_event_start):
|
||||
mock_list_by_container.return_value = []
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_delete.side_effect = exception.DockerError(
|
||||
@ -566,6 +607,8 @@ class TestManager(base.TestCase):
|
||||
mock_remove_usage.assert_called_once_with(self.context, container,
|
||||
True)
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(FakeResourceTracker,
|
||||
'remove_usage_from_container')
|
||||
@mock.patch.object(Container, 'destroy')
|
||||
@ -576,7 +619,9 @@ class TestManager(base.TestCase):
|
||||
def test_container_delete_sandbox_failed(self, mock_delete, mock_save,
|
||||
mock_delete_sandbox,
|
||||
mock_fail, mock_destroy,
|
||||
mock_remove_usage):
|
||||
mock_remove_usage,
|
||||
mock_event_finish,
|
||||
mock_event_start):
|
||||
self.compute_manager.use_sandbox = True
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
container.set_sandbox_id("sandbox_id")
|
||||
@ -591,6 +636,8 @@ class TestManager(base.TestCase):
|
||||
mock_destroy.assert_not_called()
|
||||
mock_remove_usage.assert_not_called()
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(FakeResourceTracker,
|
||||
'remove_usage_from_container')
|
||||
@mock.patch.object(Container, 'destroy')
|
||||
@ -604,7 +651,9 @@ class TestManager(base.TestCase):
|
||||
mock_save,
|
||||
mock_delete_sandbox,
|
||||
mock_fail, mock_destroy,
|
||||
mock_remove_usage):
|
||||
mock_remove_usage,
|
||||
mock_event_finish,
|
||||
mock_event_start):
|
||||
mock_list_by_container.return_value = []
|
||||
self.compute_manager.use_sandbox = True
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
@ -643,19 +692,25 @@ class TestManager(base.TestCase):
|
||||
self.compute_manager.container_show,
|
||||
self.context, container)
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(fake_driver, 'reboot')
|
||||
def test_container_reboot(self, mock_reboot, mock_save):
|
||||
def test_container_reboot(self, mock_reboot, mock_save, mock_event_finish,
|
||||
mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
self.compute_manager._do_container_reboot(self.context, container, 10)
|
||||
mock_save.assert_called_with(self.context)
|
||||
mock_reboot.assert_called_once_with(self.context, container, 10)
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(fake_driver, 'reboot')
|
||||
def test_container_reboot_failed(self, mock_reboot, mock_save,
|
||||
mock_fail):
|
||||
mock_fail, mock_event_finish,
|
||||
mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_reboot.side_effect = exception.DockerError(
|
||||
message="Docker Error occurred")
|
||||
@ -666,18 +721,24 @@ class TestManager(base.TestCase):
|
||||
mock_fail.assert_called_with(self.context,
|
||||
container, 'Docker Error occurred')
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(fake_driver, 'stop')
|
||||
def test_container_stop(self, mock_stop, mock_save):
|
||||
def test_container_stop(self, mock_stop, mock_save, mock_event_finish,
|
||||
mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
self.compute_manager._do_container_stop(self.context, container, 10)
|
||||
mock_save.assert_called_with(self.context)
|
||||
mock_stop.assert_called_once_with(self.context, container, 10)
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(fake_driver, 'stop')
|
||||
def test_container_stop_failed(self, mock_stop, mock_save, mock_fail):
|
||||
def test_container_stop_failed(self, mock_stop, mock_save, mock_fail,
|
||||
mock_event_finish, mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_stop.side_effect = exception.DockerError(
|
||||
message="Docker Error occurred")
|
||||
@ -688,19 +749,25 @@ class TestManager(base.TestCase):
|
||||
mock_fail.assert_called_with(self.context,
|
||||
container, 'Docker Error occurred')
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(fake_driver, 'start')
|
||||
def test_container_start(self, mock_start, mock_save):
|
||||
def test_container_start(self, mock_start, mock_save, mock_event_finish,
|
||||
mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
self.compute_manager._do_container_start(self.context, container)
|
||||
mock_save.assert_called_with(self.context)
|
||||
mock_start.assert_called_once_with(self.context, container)
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
@mock.patch.object(fake_driver, 'start')
|
||||
def test_container_start_failed(self, mock_start,
|
||||
mock_fail, mock_save):
|
||||
mock_fail, mock_save, mock_event_finish,
|
||||
mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_start.side_effect = exception.DockerError(
|
||||
message="Docker Error occurred")
|
||||
@ -711,15 +778,21 @@ class TestManager(base.TestCase):
|
||||
mock_fail.assert_called_with(self.context,
|
||||
container, 'Docker Error occurred')
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(fake_driver, 'pause')
|
||||
def test_container_pause(self, mock_pause):
|
||||
def test_container_pause(self, mock_pause, mock_event_finish,
|
||||
mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
self.compute_manager._do_container_pause(self.context, container)
|
||||
mock_pause.assert_called_once_with(self.context, container)
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
@mock.patch.object(fake_driver, 'pause')
|
||||
def test_container_pause_failed(self, mock_pause, mock_fail):
|
||||
def test_container_pause_failed(self, mock_pause, mock_fail,
|
||||
mock_event_finish, mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_pause.side_effect = exception.DockerError(
|
||||
message="Docker Error occurred")
|
||||
@ -729,15 +802,21 @@ class TestManager(base.TestCase):
|
||||
mock_fail.assert_called_with(self.context,
|
||||
container, 'Docker Error occurred')
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(fake_driver, 'unpause')
|
||||
def test_container_unpause(self, mock_unpause):
|
||||
def test_container_unpause(self, mock_unpause, mock_event_finish,
|
||||
mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
self.compute_manager._do_container_unpause(self.context, container)
|
||||
mock_unpause.assert_called_once_with(self.context, container)
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
@mock.patch.object(fake_driver, 'unpause')
|
||||
def test_container_unpause_failed(self, mock_unpause, mock_fail):
|
||||
def test_container_unpause_failed(self, mock_unpause, mock_fail,
|
||||
mock_event_finish, mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_unpause.side_effect = exception.DockerError(
|
||||
message="Docker Error occurred")
|
||||
@ -785,15 +864,21 @@ class TestManager(base.TestCase):
|
||||
self.compute_manager.container_exec,
|
||||
self.context, container, 'fake_cmd', True, False)
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(fake_driver, 'kill')
|
||||
def test_container_kill(self, mock_kill):
|
||||
def test_container_kill(self, mock_kill, mock_event_finish,
|
||||
mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
self.compute_manager._do_container_kill(self.context, container, None)
|
||||
mock_kill.assert_called_once_with(self.context, container, None)
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
@mock.patch.object(fake_driver, 'kill')
|
||||
def test_container_kill_failed(self, mock_kill, mock_fail):
|
||||
def test_container_kill_failed(self, mock_kill, mock_fail,
|
||||
mock_event_finish, mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_kill.side_effect = exception.DockerError(
|
||||
message="Docker Error occurred")
|
||||
@ -897,11 +982,14 @@ class TestManager(base.TestCase):
|
||||
self.compute_manager.container_exec_resize,
|
||||
self.context, 'fake_exec_id', "100", "100")
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch('zun.image.driver.upload_image_data')
|
||||
@mock.patch.object(fake_driver, 'get_image')
|
||||
@mock.patch.object(fake_driver, 'commit')
|
||||
def test_container_commit(self, mock_commit,
|
||||
mock_get_image, mock_upload_image_data):
|
||||
mock_get_image, mock_upload_image_data,
|
||||
mock_event_finish, mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_get_image_response = mock.MagicMock()
|
||||
mock_get_image_response.data = StringIO().read()
|
||||
@ -914,24 +1002,36 @@ class TestManager(base.TestCase):
|
||||
mock_commit.assert_called_once_with(
|
||||
self.context, container, 'repo', 'tag')
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch('zun.image.driver.delete_image')
|
||||
@mock.patch.object(fake_driver, 'commit')
|
||||
def test_container_commit_failed(self, mock_commit, mock_delete):
|
||||
def test_container_commit_failed(self, mock_commit, mock_delete,
|
||||
mock_event_finish, mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_get_image_response = mock.MagicMock()
|
||||
mock_get_image_response.data = StringIO().read()
|
||||
mock_commit.side_effect = exception.DockerError
|
||||
self.assertRaises(exception.DockerError,
|
||||
self.compute_manager._do_container_commit,
|
||||
self.context, container, 'repo', 'tag')
|
||||
self.context, mock_get_image_response, container,
|
||||
'repo', 'tag')
|
||||
self.assertTrue(mock_delete.called)
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(fake_driver, 'network_detach')
|
||||
def test_container_network_detach(self, mock_detach):
|
||||
def test_container_network_detach(self, mock_detach, mock_event_finish,
|
||||
mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
self.compute_manager.network_detach(self.context, container, 'network')
|
||||
mock_detach.assert_called_once_with(self.context, container, mock.ANY)
|
||||
|
||||
@mock.patch.object(ContainerActionEvent, 'event_start')
|
||||
@mock.patch.object(ContainerActionEvent, 'event_finish')
|
||||
@mock.patch.object(fake_driver, 'network_attach')
|
||||
def test_container_network_attach(self, mock_attach):
|
||||
def test_container_network_attach(self, mock_attach, mock_event_finish,
|
||||
mock_event_start):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
self.compute_manager.network_attach(self.context, container, 'network')
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user