Add container action object and sql db api

Add container action object and sql db api for container actions.

Change-Id: I62cd021d4fc4b69432cc67b3506b9b24a9e7c779
Implements: blueprint container-actions-api
This commit is contained in:
Chaolei Li
2017-12-04 15:29:07 +08:00
parent b254fc2737
commit a33fbbab05
10 changed files with 730 additions and 3 deletions

View File

@@ -13,6 +13,8 @@
import copy import copy
from eventlet.green import threading from eventlet.green import threading
from oslo_context import context from oslo_context import context
from oslo_utils import timeutils
import six
from zun.common import exception from zun.common import exception
from zun.common import policy from zun.common import policy
@@ -27,7 +29,7 @@ class RequestContext(context.RequestContext):
project_name=None, project_id=None, roles=None, project_name=None, project_id=None, roles=None,
is_admin=None, read_only=False, show_deleted=False, is_admin=None, read_only=False, show_deleted=False,
request_id=None, trust_id=None, auth_token_info=None, request_id=None, trust_id=None, auth_token_info=None,
all_tenants=False, password=None, **kwargs): all_tenants=False, password=None, timestamp=None, **kwargs):
"""Stores several additional request parameters: """Stores several additional request parameters:
:param domain_id: The ID of the domain. :param domain_id: The ID of the domain.
@@ -65,6 +67,12 @@ class RequestContext(context.RequestContext):
else: else:
self.is_admin = is_admin self.is_admin = is_admin
if not timestamp:
timestamp = timeutils.utcnow()
if isinstance(timestamp, six.string_types):
timestamp = timeutils.parse_strtime(timestamp)
self.timestamp = timestamp
def to_dict(self): def to_dict(self):
value = super(RequestContext, self).to_dict() value = super(RequestContext, self).to_dict()
value.update({'auth_token': self.auth_token, value.update({'auth_token': self.auth_token,
@@ -85,7 +93,10 @@ class RequestContext(context.RequestContext):
'trust_id': self.trust_id, 'trust_id': self.trust_id,
'auth_token_info': self.auth_token_info, 'auth_token_info': self.auth_token_info,
'password': self.password, 'password': self.password,
'all_tenants': self.all_tenants}) 'all_tenants': self.all_tenants,
'timestamp': timeutils.strtime(self.timestamp) if
hasattr(self, 'timestamp') else None
})
return value return value
def to_policy_values(self): def to_policy_values(self):

View File

@@ -655,3 +655,12 @@ class VolumeCreateFailed(Invalid):
class VolumeDeleteFailed(Invalid): class VolumeDeleteFailed(Invalid):
message = _("Volume Deletion failed: %(deletion_failed)s") message = _("Volume Deletion failed: %(deletion_failed)s")
class ContainerActionNotFound(ZunException):
message = _("Action for request_id %(request_id)s on container"
" %(container_uuid)s not fount")
class ContainerActionEventNotFound(ZunException):
message = _("Event %(event)s not found for action id %(action_id)s")

View File

@@ -857,3 +857,40 @@ def destroy_pci_device(node_id, address):
def update_pci_device(node_id, address, value): def update_pci_device(node_id, address, value):
"""Update a pci device.""" """Update a pci device."""
return _get_dbdriver_instance().update_pci_device(node_id, address, value) return _get_dbdriver_instance().update_pci_device(node_id, address, value)
@profiler.trace("db")
def action_start(context, values):
"""Start an action for an container."""
return _get_dbdriver_instance().action_start(context, values)
@profiler.trace("db")
def actions_get(context, uuid):
"""Get all container actions for the provided container."""
return _get_dbdriver_instance().actions_get(context, uuid)
@profiler.trace("db")
def action_get_by_request_id(context, uuid, request_id):
"""Get the action by request_id and given container."""
return _get_dbdriver_instance().action_get_by_request_id(context, uuid,
request_id)
@profiler.trace("db")
def action_event_start(context, values):
"""Start an event on an container action."""
return _get_dbdriver_instance().action_event_start(context, values)
@profiler.trace("db")
def action_event_finish(context, values):
"""Finish an event on an container action."""
return _get_dbdriver_instance().action_event_finish(context, values)
@profiler.trace("db")
def action_events_get(context, action_id):
"""Get the events by action id."""
return _get_dbdriver_instance().action_events_get(context, action_id)

View File

@@ -25,6 +25,7 @@ import sqlalchemy as sa
from sqlalchemy.orm import contains_eager from sqlalchemy.orm import contains_eager
from sqlalchemy.orm.exc import MultipleResultsFound from sqlalchemy.orm.exc import MultipleResultsFound
from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.sql.expression import desc
from sqlalchemy.sql import func from sqlalchemy.sql import func
from zun.common import consts from zun.common import consts
@@ -960,3 +961,109 @@ class Connection(object):
device.update(values) device.update(values)
device.save() device.save()
return query.one() return query.one()
def action_start(self, context, values):
action = models.ContainerAction()
action.update(values)
action.save()
return action
def actions_get(self, context, container_uuid):
"""Get all container actions for the provided uuid."""
query = model_query(models.ContainerAction).\
filter_by(container_uuid=container_uuid)
actions = _paginate_query(models.ContainerAction, sort_dir='desc',
sort_key='created_at', query=query)
return actions
def action_get_by_request_id(self, context, container_uuid, request_id):
"""Get the action by request_id and given container."""
action = self._action_get_by_request_id(context, container_uuid,
request_id)
return action
def _action_get_by_request_id(self, context, container_uuid, request_id):
result = model_query(models.ContainerAction).\
filter_by(container_uuid=container_uuid).\
filter_by(request_id=request_id).\
first()
return result
def _action_get_last_created_by_container_uuid(self, context,
container_uuid):
result = model_query(models.ContainerAction).\
filter_by(container_uuid=container_uuid).\
order_by(desc("created_at"), desc("id")).\
first()
return result
def action_event_start(self, context, values):
"""Start an event on a container action."""
action = self._action_get_by_request_id(context,
values['container_uuid'],
values['request_id'])
# When zun-compute restarts, the request_id was different with
# request_id recorded in ContainerAction, so we can't get the original
# recode according to request_id. Try to get the last created action
# so that init_container can continue to finish the recovery action.
if not action and not context.project_id:
action = self._action_get_last_created_by_container_uuid(
context, values['container_uuid'])
if not action:
raise exception.ContainerActionNotFound(
request_id=values['request_id'],
container_uuid=values['container_uuid'])
values['action_id'] = action['id']
event = models.ContainerActionEvent()
event.update(values)
event.save()
return event
def action_event_finish(self, context, values):
"""Finish an event on a container action."""
action = self._action_get_by_request_id(context,
values['container_uuid'],
values['request_id'])
# When zun-compute restarts, the request_id was different with
# request_id recorded in ContainerAction, so we can't get the original
# recode according to request_id. Try to get the last created action
# so that init_container can continue to finish the recovery action.
if not action and not context.project_id:
action = self._action_get_last_created_by_container_uuid(
context, values['container_uuid'])
if not action:
raise exception.ContainerActionNotFound(
request_id=values['request_id'],
container_uuid=values['container_uuid'])
event = model_query(models.ContainerActionEvent).\
filter_by(action_id=action['id']).\
filter_by(event=values['event']).\
first()
if not event:
raise exception.ContainerActionEventNotFound(
action_id=action['id'], event=values['event'])
event.update(values)
event.save()
if values['result'].lower() == 'error':
action.update({'message': 'Error'})
action.save()
return event
def action_events_get(self, context, action_id):
query = model_query(models.ContainerActionEvent).\
filter_by(action_id=action_id)
events = _paginate_query(models.ContainerActionEvent, sort_dir='desc',
sort_key='created_at', query=query)
return events

View File

@@ -13,6 +13,7 @@
from zun.objects import capsule from zun.objects import capsule
from zun.objects import compute_node from zun.objects import compute_node
from zun.objects import container from zun.objects import container
from zun.objects import container_action
from zun.objects import container_pci_requests from zun.objects import container_pci_requests
from zun.objects import image from zun.objects import image
from zun.objects import numa from zun.objects import numa
@@ -23,6 +24,7 @@ from zun.objects import resource_provider
from zun.objects import volume_mapping from zun.objects import volume_mapping
from zun.objects import zun_service from zun.objects import zun_service
Container = container.Container Container = container.Container
VolumeMapping = volume_mapping.VolumeMapping VolumeMapping = volume_mapping.VolumeMapping
ZunService = zun_service.ZunService ZunService = zun_service.ZunService
@@ -37,6 +39,8 @@ PciDevice = pci_device.PciDevice
PciDevicePool = pci_device_pool.PciDevicePool PciDevicePool = pci_device_pool.PciDevicePool
ContainerPCIRequest = container_pci_requests.ContainerPCIRequest ContainerPCIRequest = container_pci_requests.ContainerPCIRequest
ContainerPCIRequests = container_pci_requests.ContainerPCIRequests ContainerPCIRequests = container_pci_requests.ContainerPCIRequests
ContainerAction = container_action.ContainerAction
ContainerActionEvent = container_action.ContainerActionEvent
__all__ = ( __all__ = (
Container, Container,
@@ -53,4 +57,6 @@ __all__ = (
PciDevicePool, PciDevicePool,
ContainerPCIRequest, ContainerPCIRequest,
ContainerPCIRequests, ContainerPCIRequests,
ContainerAction,
ContainerActionEvent,
) )

View File

@@ -0,0 +1,175 @@
# 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.
import traceback
from oslo_log import log as logging
from oslo_utils import timeutils
from oslo_versionedobjects import fields
import six
from zun.db import api as dbapi
from zun.objects import base
LOG = logging.getLogger(__name__)
@base.ZunObjectRegistry.register
class ContainerAction(base.ZunPersistentObject, base.ZunObject):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'id': fields.IntegerField(),
'action': fields.StringField(nullable=True),
'container_uuid': fields.UUIDField(nullable=True),
'request_id': fields.StringField(nullable=True),
'user_id': fields.StringField(nullable=True),
'project_id': fields.StringField(nullable=True),
'start_time': fields.DateTimeField(nullable=True),
'finish_time': fields.DateTimeField(nullable=True),
'message': fields.StringField(nullable=True),
}
@staticmethod
def _from_db_object(context, action, db_action):
for field in action.fields:
setattr(action, field, db_action[field])
action.obj_reset_changes()
return action
@staticmethod
def _from_db_object_list(context, cls, db_objects):
"""Converts a list of database entities to a list of formal objects."""
return [ContainerAction._from_db_object(context, cls(context), obj)
for obj in db_objects]
@staticmethod
def pack_action_start(context, container_uuid, action_name):
values = {'request_id': context.request_id,
'container_uuid': container_uuid,
'user_id': context.user_id,
'project_id': context.project_id,
'action': action_name,
'start_time': context.timestamp}
return values
@staticmethod
def pack_action_finish(context, container_uuid):
values = {'request_id': context.request_id,
'container_uuid': container_uuid,
'finish_time': timeutils.utcnow()}
return values
@base.remotable_classmethod
def get_by_request_id(cls, context, container_uuid, request_id):
db_action = dbapi.action_get_by_request_id(context, container_uuid,
request_id)
if db_action:
return cls._from_db_object(context, cls(context), db_action)
@base.remotable_classmethod
def action_start(cls, context, container_uuid, action_name,
want_result=True):
values = cls.pack_action_start(context, container_uuid, action_name)
db_action = dbapi.action_start(context, values)
if want_result:
return cls._from_db_object(context, cls(context), db_action)
@base.remotable_classmethod
def get_by_container_uuid(cls, context, instance_uuid):
db_actions = dbapi.actions_get(context, instance_uuid)
return ContainerAction._from_db_object_list(context, cls, db_actions)
@base.ZunObjectRegistry.register
class ContainerActionEvent(base.ZunPersistentObject, base.ZunObject):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'id': fields.IntegerField(),
'event': fields.StringField(nullable=True),
'action_id': fields.IntegerField(nullable=True),
'start_time': fields.DateTimeField(nullable=True),
'finish_time': fields.DateTimeField(nullable=True),
'result': fields.StringField(nullable=True),
'traceback': fields.StringField(nullable=True),
}
@staticmethod
def _from_db_object(context, event, db_event):
for field in event.fields:
setattr(event, field, db_event[field])
event.obj_reset_changes()
return event
@staticmethod
def _from_db_object_list(context, cls, db_objects):
"""Converts a list of database entities to a list of formal objects."""
return [ContainerActionEvent._from_db_object(context, cls(context),
obj)
for obj in db_objects]
@staticmethod
def pack_action_event_start(context, container_uuid, event_name):
values = {'event': event_name,
'container_uuid': container_uuid,
'request_id': context.request_id,
'start_time': timeutils.utcnow()}
return values
@staticmethod
def pack_action_event_finish(context, container_uuid, event_name,
exc_val=None, exc_tb=None):
values = {'event': event_name,
'container_uuid': container_uuid,
'request_id': context.request_id,
'finish_time': timeutils.utcnow()}
if exc_tb is None:
values['result'] = 'Success'
else:
values['result'] = 'Error'
values['message'] = exc_val
values['traceback'] = exc_tb
return values
@base.remotable_classmethod
def event_start(cls, context, container_uuid, event_name,
want_result=True):
values = cls.pack_action_event_start(context, container_uuid,
event_name)
db_event = dbapi.action_event_start(context, values)
if want_result:
return cls._from_db_object(context, cls(context), db_event)
@base.remotable_classmethod
def event_finish(cls, context, container_uuid, event_name, exc_val=None,
exc_tb=None, want_result=None):
if exc_val:
exc_val = six.text_type(exc_val)
if exc_tb and not isinstance(exc_tb, six.string_types):
exc_tb = ''.join(traceback.format_tb(exc_tb))
values = cls.pack_action_event_finish(context, container_uuid,
event_name, exc_val=exc_val,
exc_tb=exc_tb)
db_event = dbapi.action_event_finish(context, values)
if want_result:
return cls._from_db_object(context, cls(context), db_event)
@base.remotable_classmethod
def get_by_action(cls, context, action_id):
db_events = dbapi.action_events_get(context, action_id)
return ContainerActionEvent._from_db_object_list(context, cls,
db_events)

View File

@@ -0,0 +1,221 @@
# 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.
"""Tests for manipulating Container Actions via the DB API"""
import datetime
from oslo_config import cfg
from oslo_utils import timeutils
from oslo_utils import uuidutils
from zun.common import exception
import zun.conf
from zun.db import api as dbapi
from zun.tests.unit.db import base
from zun.tests.unit.db import utils
CONF = zun.conf.CONF
class DbContainerActionTestCase(base.DbTestCase,
base.ModelsObjectComparatorMixin):
IGNORED_FIELDS = [
'id',
'created_at',
'updated_at',
]
def setUp(self):
cfg.CONF.set_override('db_type', 'sql')
super(DbContainerActionTestCase, self).setUp()
def _create_action_values(self, uuid, action='create_container'):
utils.create_test_container(context=self.context,
name='cont1',
uuid=uuid)
values = {
'action': action,
'container_uuid': uuid,
'request_id': self.context.request_id,
'user_id': self.context.user_id,
'project_id': self.context.project_id,
'start_time': timeutils.utcnow(),
'message': 'action-message'
}
return values
def _create_event_values(self, uuid, event='do_create', extra=None):
values = {
'event': event,
'container_uuid': uuid,
'request_id': self.context.request_id,
'start_time': timeutils.utcnow(),
'details': 'fake-details',
}
if extra is not None:
values.update(extra)
return values
def _assertActionSaved(self, action, uuid):
"""Retrieve the action to ensure it was successfully added."""
actions = dbapi.actions_get(self.context, uuid)
self.assertEqual(1, len(actions))
self._assertEqualObjects(action, actions[0])
def _assertActionEventSaved(self, event, action_id):
"""Retrieve the event to ensure it was successfully added."""
events = dbapi.action_events_get(self.context, action_id)
self.assertEqual(1, len(events))
self._assertEqualObjects(event, events[0],
['container_uuid', 'request_id'])
def test_container_action_start(self):
"""Create a container action."""
uuid = uuidutils.generate_uuid()
action_values = self._create_action_values(uuid)
action = dbapi.action_start(self.context, action_values)
ignored_keys = self.IGNORED_FIELDS + ['finish_time']
self._assertEqualObjects(action_values, action, ignored_keys)
self._assertActionSaved(action, uuid)
def test_container_actions_get_by_container(self):
"""Ensure we can get actions by UUID."""
uuid1 = uuidutils.generate_uuid()
expected = []
action_values = self._create_action_values(uuid1)
action = dbapi.action_start(self.context, action_values)
expected.append(action)
action_values['action'] = 'test-action'
action = dbapi.action_start(self.context, action_values)
expected.append(action)
# Create an other container action.
uuid2 = uuidutils.generate_uuid()
action_values = self._create_action_values(uuid2, 'test-action')
dbapi.action_start(self.context, action_values)
actions = dbapi.actions_get(self.context, uuid1)
self._assertEqualListsOfObjects(expected, actions)
def test_container_action_get_by_container_and_request(self):
"""Ensure we can get an action by container UUID and request_id"""
uuid1 = uuidutils.generate_uuid()
action_values = self._create_action_values(uuid1)
dbapi.action_start(self.context, action_values)
request_id = action_values['request_id']
# An other action using a different req id
action_values['action'] = 'test-action'
action_values['request_id'] = 'req-00000000-7522-4d99-7ff-111111111111'
dbapi.action_start(self.context, action_values)
action = dbapi.action_get_by_request_id(self.context, uuid1,
request_id)
self.assertEqual('create_container', action['action'])
self.assertEqual(self.context.request_id, action['request_id'])
def test_container_action_event_start(self):
"""Create a container action event."""
uuid = uuidutils.generate_uuid()
action_values = self._create_action_values(uuid)
action = dbapi.action_start(self.context, action_values)
event_values = self._create_event_values(uuid)
event = dbapi.action_event_start(self.context, event_values)
event_values['action_id'] = action['id']
ignored_keys = self.IGNORED_FIELDS + ['finish_time', 'traceback',
'result']
self._assertEqualObjects(event_values, event, ignored_keys)
self._assertActionEventSaved(event, action['id'])
def test_container_action_event_start_without_action(self):
uuid = uuidutils.generate_uuid()
event_values = self._create_event_values(uuid)
self.assertRaises(exception.ContainerActionNotFound,
dbapi.action_event_start, self.context, event_values)
def test_container_action_event_finish_success(self):
"""Finish a container action event."""
uuid = uuidutils.generate_uuid()
action = dbapi.action_start(self.context,
self._create_action_values(uuid))
dbapi.action_event_start(self.context,
self._create_event_values(uuid))
event_values = {
'finish_time': timeutils.utcnow() + datetime.timedelta(seconds=5),
'result': 'Success'
}
event_values = self._create_event_values(uuid, extra=event_values)
event = dbapi.action_event_finish(self.context, event_values)
self._assertActionEventSaved(event, action['id'])
action = dbapi.action_get_by_request_id(self.context, uuid,
self.context.request_id)
self.assertNotEqual('Error', action['message'])
def test_container_action_event_finish_without_action(self):
uuid = uuidutils.generate_uuid()
event_values = {
'finish_time': timeutils.utcnow() + datetime.timedelta(seconds=5),
'result': 'Success'
}
event_values = self._create_event_values(uuid, extra=event_values)
self.assertRaises(exception.ContainerActionNotFound,
dbapi.action_event_finish,
self.context, event_values)
def test_container_action_events_get_in_order(self):
"""Ensure retrived action events are in order."""
uuid1 = uuidutils.generate_uuid()
action = dbapi.action_start(self.context,
self._create_action_values(uuid1))
extra1 = {
'created_at': timeutils.utcnow()
}
extra2 = {
'created_at': timeutils.utcnow() + datetime.timedelta(seconds=5)
}
event_val1 = self._create_event_values(uuid1, 'fake1', extra=extra1)
event_val2 = self._create_event_values(uuid1, 'fake2', extra=extra1)
event_val3 = self._create_event_values(uuid1, 'fake3', extra=extra2)
event1 = dbapi.action_event_start(self.context, event_val1)
event2 = dbapi.action_event_start(self.context, event_val2)
event3 = dbapi.action_event_start(self.context, event_val3)
events = dbapi.action_events_get(self.context, action['id'])
self.assertEqual(3, len(events))
self._assertEqualOrderedListOfObjects([event3, event2, event1], events,
['container_uuid', 'request_id'])

View File

@@ -395,3 +395,34 @@ def create_test_capsule(**kwargs):
del capsule['id'] del capsule['id']
dbapi = db_api._get_dbdriver_instance() dbapi = db_api._get_dbdriver_instance()
return dbapi.create_capsule(kwargs['context'], capsule) return dbapi.create_capsule(kwargs['context'], capsule)
def get_test_action(**kwargs):
return {
'created_at': kwargs.get('created_at'),
'updated_at': kwargs.get('updated_at'),
'id': kwargs.get('id', 123),
'action': kwargs.get('action', 'fake-action'),
'container_uuid': kwargs.get('container_uuid',
'ea8e2a25-2901-438d-8157-de7ffd68d051'),
'request_id': kwargs.get('request_id', 'fake-request'),
'user_id': kwargs.get('user_id', 'fake-user'),
'project_id': kwargs.get('project_id', 'fake-project'),
'start_time': kwargs.get('start_time'),
'finish_time': kwargs.get('finish_time'),
'message': kwargs.get('message', 'fake-message'),
}
def get_test_action_event(**kwargs):
return {
'created_at': kwargs.get('created_at'),
'updated_at': kwargs.get('updated_at'),
'id': kwargs.get('id', 123),
'event': kwargs.get('event', 'fake-event'),
'action_id': kwargs.get('action_id', 123),
'start_time': kwargs.get('start_time'),
'finish_time': kwargs.get('finish_time'),
'result': kwargs.get('result', 'Error'),
'traceback': kwargs.get('traceback', 'fake-tb'),
}

View File

@@ -0,0 +1,128 @@
# Copyright 2015 OpenStack Foundation
# All Rights Reserved.
#
# 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.
import mock
from oslo_utils import fixture as utils_fixture
from oslo_utils import timeutils
from testtools.matchers import HasLength
from zun import objects
from zun.tests.unit.db import base
from zun.tests.unit.db import utils
NOW = timeutils.utcnow().replace(microsecond=0)
class TestContainerActionObject(base.DbTestCase):
def setUp(self):
super(TestContainerActionObject, self).setUp()
self.fake_action = utils.get_test_action()
def test_get_by_request_id(self):
container_ident = self.fake_action['container_uuid']
request_id = self.fake_action['request_id']
with mock.patch.object(self.dbapi, 'action_get_by_request_id',
autospec=True) as mock_get_action:
mock_get_action.return_value = self.fake_action
action = objects.ContainerAction.get_by_request_id(
self.context, container_ident, request_id)
mock_get_action.assert_called_once_with(
self.context, container_ident, request_id)
self.assertEqual(self.context, action._context)
def test_get_by_container_uuid(self):
container_ident = self.fake_action['container_uuid']
with mock.patch.object(self.dbapi, 'actions_get', autospec=True) \
as mock_get_actions:
mock_get_actions.return_value = [self.fake_action]
actions = objects.ContainerAction.get_by_container_uuid(
self.context, container_ident)
mock_get_actions.assert_called_once_with(self.context,
container_ident)
self.assertThat(actions, HasLength(1))
self.assertIsInstance(actions[0], objects.ContainerAction)
self.assertEqual(self.context, actions[0]._context)
def test_action_start(self):
self.useFixture(utils_fixture.TimeFixture(NOW))
container_ident = self.fake_action['container_uuid']
action_name = self.fake_action['action']
test_class = objects.ContainerAction
expected_packed_values = test_class.pack_action_start(
self.context, container_ident, action_name)
with mock.patch.object(self.dbapi, 'action_start', autospec=True) \
as mock_action_start:
mock_action_start.return_value = self.fake_action
action = objects.ContainerAction.action_start(
self.context, container_ident, action_name, want_result=True)
mock_action_start.assert_called_once_with(
self.context, expected_packed_values)
self.assertEqual(self.context, action._context)
class TestContainerActionEventObject(base.DbTestCase):
def setUp(self):
super(TestContainerActionEventObject, self).setUp()
self.fake_action = utils.get_test_action()
self.fake_event = utils.get_test_action_event()
def test_get_by_action(self):
action_id = self.fake_event['action_id']
with mock.patch.object(self.dbapi, 'action_events_get',
autospec=True) as mock_get_event:
mock_get_event.return_value = [self.fake_event]
events = objects.ContainerActionEvent.get_by_action(self.context,
action_id)
mock_get_event.assert_called_once_with(self.context, action_id)
self.assertThat(events, HasLength(1))
self.assertIsInstance(events[0], objects.ContainerActionEvent)
self.assertEqual(self.context, events[0]._context)
def test_event_start(self):
self.useFixture(utils_fixture.TimeFixture(NOW))
container_uuid = self.fake_action['container_uuid']
event_name = self.fake_event['event']
test_class = objects.ContainerActionEvent
expected_packed_values = test_class.pack_action_event_start(
self.context, container_uuid, event_name)
with mock.patch.object(self.dbapi, 'action_event_start',
autospec=True) as mock_event_start:
mock_event_start.return_value = self.fake_event
event = objects.ContainerActionEvent.event_start(
self.context, container_uuid, event_name, want_result=True)
mock_event_start.assert_called_once_with(self.context,
expected_packed_values)
self.assertEqual(self.context, event._context)
def test_event_finish(self):
self.useFixture(utils_fixture.TimeFixture(NOW))
container_uuid = self.fake_action['container_uuid']
event_name = self.fake_event['event']
test_class = objects.ContainerActionEvent
expected_packed_values = test_class.pack_action_event_finish(
self.context, container_uuid, event_name)
with mock.patch.object(self.dbapi, 'action_event_finish',
autospec=True) as mock_event_finish:
mock_event_finish.return_value = self.fake_event
event = objects.ContainerActionEvent.event_finish(
self.context, container_uuid, event_name, want_result=True)
mock_event_finish.assert_called_once_with(self.context,
expected_packed_values)
self.assertEqual(self.context, event._context)

View File

@@ -359,7 +359,9 @@ object_data = {
'PciDevicePool': '1.0-3f5ddc3ff7bfa14da7f6c7e9904cc000', 'PciDevicePool': '1.0-3f5ddc3ff7bfa14da7f6c7e9904cc000',
'PciDevicePoolList': '1.0-15ecf022a68ddbb8c2a6739cfc9f8f5e', 'PciDevicePoolList': '1.0-15ecf022a68ddbb8c2a6739cfc9f8f5e',
'ContainerPCIRequest': '1.0-b060f9f9f734bedde79a71a4d3112ee0', 'ContainerPCIRequest': '1.0-b060f9f9f734bedde79a71a4d3112ee0',
'ContainerPCIRequests': '1.0-7b8f7f044661fe4e24e6949c035af2c4' 'ContainerPCIRequests': '1.0-7b8f7f044661fe4e24e6949c035af2c4',
'ContainerAction': '1.0-8d6facdc65855c6c6afbed8531209279',
'ContainerActionEvent': '1.0-2974d0a6f5d4821fd4e223a88c10181a'
} }