First objects - stack and raw template

Implementation of oslo.versionedobjects.
This commit consists basic mechanism and first objects.
This should be base of implementation versoning to other objects

Implements: blueprint versioned-objects

Co-Authored-By: ShaoHe Feng <shaohe.feng@intel.com>
Co-Authored-By: Grzegorz Grasza <grzegorz.grasza@intel.com>

Change-Id: I554162cf3681fe559c75f54c61c6f32c91f5c2f8
This commit is contained in:
Michal Jastrzebski 2014-12-09 09:36:03 +01:00 committed by Michal Jastrzebski (inc0)
parent bb5fec7725
commit dea0897f45
13 changed files with 371 additions and 74 deletions

View File

@ -84,6 +84,12 @@ class FaultWrapper(wsgi.Middleware):
'Invalid': webob.exc.HTTPBadRequest,
'ResourcePropertyConflict': webob.exc.HTTPBadRequest,
'PropertyUnspecifiedError': webob.exc.HTTPBadRequest,
'ObjectFieldInvalid': webob.exc.HTTPBadRequest,
'ReadOnlyFieldError': webob.exc.HTTPBadRequest,
'ObjectActionError': webob.exc.HTTPBadRequest,
'IncompatibleObjectVersion': webob.exc.HTTPBadRequest,
'OrphanedObjectError': webob.exc.HTTPBadRequest,
'UnsupportedObjectError': webob.exc.HTTPBadRequest,
}
def _map_exception_to_error(self, class_exception):

View File

@ -430,3 +430,27 @@ class EventSendFailed(HeatException):
class ServiceNotFound(HeatException):
msg_fmt = _("Service %(service_id)s does not found")
class UnsupportedObjectError(HeatException):
msg_fmt = _('Unsupported object type %(objtype)s')
class OrphanedObjectError(HeatException):
msg_fmt = _('Cannot call %(method)s on orphaned %(objtype)s object')
class IncompatibleObjectVersion(HeatException):
msg_fmt = _('Version %(objver)s of %(objname)s is not supported')
class ObjectActionError(HeatException):
msg_fmt = _('Object action %(action)s failed because: %(reason)s')
class ReadOnlyFieldError(HeatException):
msg_fmt = _('Cannot modify readonly field %(field)s')
class ObjectFieldInvalid(HeatException):
msg_fmt = _('Field %(field)s of %(objname)s is not an instance of Field')

View File

@ -51,6 +51,7 @@ from heat.engine import stack_lock
from heat.engine import template as templatem
from heat.engine import watchrule
from heat.engine import worker
from heat.objects import stack as stack_object
from heat.openstack.common import service
from heat.openstack.common import threadgroup
from heat.rpc import api as rpc_api
@ -306,7 +307,9 @@ class EngineService(service.Service):
# Create a periodic_watcher_task per-stack
admin_context = context.get_admin_context()
stacks = db_api.stack_get_all(admin_context, tenant_safe=False)
stacks = stack_object.Stack.get_all(
admin_context,
tenant_safe=False)
for s in stacks:
self.stack_watch.start_watch_task(s.id, admin_context)
@ -394,13 +397,16 @@ class EngineService(service.Service):
:param stack_name: Name or UUID of the stack to look up.
"""
if uuidutils.is_uuid_like(stack_name):
s = db_api.stack_get(cnxt, stack_name, show_deleted=True)
s = stack_object.Stack.get_by_id(
cnxt,
stack_name,
show_deleted=True)
# may be the name is in uuid format, so if get by id returns None,
# we should get the info by name again
if not s:
s = db_api.stack_get_by_name(cnxt, stack_name)
s = stack_object.Stack.get_by_name(cnxt, stack_name)
else:
s = db_api.stack_get_by_name(cnxt, stack_name)
s = stack_object.Stack.get_by_name(cnxt, stack_name)
if s:
stack = parser.Stack.load(cnxt, stack=s)
return dict(stack.identifier())
@ -410,9 +416,11 @@ class EngineService(service.Service):
def _get_stack(self, cnxt, stack_identity, show_deleted=False):
identity = identifier.HeatIdentifier(**stack_identity)
s = db_api.stack_get(cnxt, identity.stack_id,
show_deleted=show_deleted,
eager_load=True)
s = stack_object.Stack.get_by_id(
cnxt,
identity.stack_id,
show_deleted=show_deleted,
eager_load=True)
if s is None:
raise exception.StackNotFound(stack_name=identity.stack_name)
@ -485,10 +493,12 @@ class EngineService(service.Service):
:param show_nested: if true, count will include nested stacks
:returns: a integer representing the number of matched stacks
"""
return db_api.stack_count_all(cnxt, filters=filters,
tenant_safe=tenant_safe,
show_deleted=show_deleted,
show_nested=show_nested)
return stack_object.Stack.count_all(
cnxt,
filters=filters,
tenant_safe=tenant_safe,
show_deleted=show_deleted,
show_nested=show_nested)
def _validate_deferred_auth_context(self, cnxt, stack):
if cfg.CONF.deferred_auth_method != 'password':
@ -508,11 +518,11 @@ class EngineService(service.Service):
except Exception as ex:
raise exception.StackValidationFailed(message=six.text_type(ex))
if db_api.stack_get_by_name(cnxt, stack_name):
if stack_object.Stack.get_by_name(cnxt, stack_name):
raise exception.StackExists(stack_name=stack_name)
tenant_limit = cfg.CONF.max_stacks_per_tenant
if db_api.stack_count_all(cnxt) >= tenant_limit:
if stack_object.Stack.count_all(cnxt) >= tenant_limit:
message = _("You have reached the maximum stacks per tenant, %d."
" Please delete some stacks.") % tenant_limit
raise exception.RequestLimitExceeded(message=message)

View File

@ -41,6 +41,7 @@ from heat.engine import resources
from heat.engine import scheduler
from heat.engine import template as tmpl
from heat.engine import update
from heat.objects import stack as stack_object
from heat.rpc import api as rpc_api
cfg.CONF.import_opt('error_wait_time', 'heat.common.config')
@ -284,9 +285,11 @@ class Stack(collections.Mapping):
show_deleted=True, use_stored_context=False, force_reload=False):
'''Retrieve a Stack from the database.'''
if stack is None:
stack = db_api.stack_get(context, stack_id,
show_deleted=show_deleted,
eager_load=True)
stack = stack_object.Stack.get_by_id(
context,
stack_id,
show_deleted=show_deleted,
eager_load=True)
if stack is None:
message = _('No stack exists with id "%s"') % str(stack_id)
raise exception.NotFound(message)
@ -302,9 +305,16 @@ class Stack(collections.Mapping):
sort_dir=None, filters=None, tenant_safe=True,
show_deleted=False, resolve_data=True,
show_nested=False):
stacks = db_api.stack_get_all(context, limit, sort_keys, marker,
sort_dir, filters, tenant_safe,
show_deleted, show_nested) or []
stacks = stack_object.Stack.get_all(
context,
limit,
sort_keys,
marker,
sort_dir,
filters,
tenant_safe,
show_deleted,
show_nested) or []
for stack in stacks:
yield cls._from_db(context, stack, resolve_data=resolve_data)
@ -351,7 +361,7 @@ class Stack(collections.Mapping):
'current_traversal': self.current_traversal,
}
if self.id:
db_api.stack_update(self.context, self.id, s)
stack_object.Stack.update_by_id(self.context, self.id, s)
else:
if not self.user_creds_id:
# Create a context containing a trust_id and trustor_user_id
@ -365,7 +375,7 @@ class Stack(collections.Mapping):
s['user_creds_id'] = new_creds.id
self.user_creds_id = new_creds.id
new_s = db_api.stack_create(self.context, s)
new_s = stack_object.Stack.create(self.context, s)
self.id = new_s.id
self.created_time = new_s.created_at
@ -561,7 +571,7 @@ class Stack(collections.Mapping):
if self.id is None:
return
stack = db_api.stack_get(self.context, self.id)
stack = stack_object.Stack.get_by_id(self.context, self.id)
if stack is not None:
stack.update_and_save({'action': action,
'status': status,
@ -706,9 +716,10 @@ class Stack(collections.Mapping):
Get a Stack containing any in-progress resources from the previous
stack state prior to an update.
'''
s = db_api.stack_get_by_name_and_owner_id(self.context,
self._backup_name(),
owner_id=self.id)
s = stack_object.Stack.get_by_name_and_owner_id(
self.context,
self._backup_name(),
owner_id=self.id)
if s is not None:
LOG.debug('Loaded existing backup stack')
return self.load(self.context, stack=s)
@ -1060,7 +1071,7 @@ class Stack(collections.Mapping):
if stack_status != self.FAILED:
# delete the stack
try:
db_api.stack_delete(self.context, self.id)
stack_object.Stack.delete(self.context, self.id)
except exception.NotFound:
LOG.info(_LI("Tried to delete stack that does not exist "
"%s "), self.id)

View File

@ -22,8 +22,8 @@ from stevedore import extension
from heat.common import exception
from heat.common.i18n import _
from heat.db import api as db_api
from heat.engine import environment
from heat.objects import raw_template as template_object
LOG = logging.getLogger(__name__)
@ -125,7 +125,7 @@ class Template(collections.Mapping):
def load(cls, context, template_id, t=None):
'''Retrieve a Template with the given ID from the database.'''
if t is None:
t = db_api.raw_template_get(context, template_id)
t = template_object.RawTemplate.get_by_id(context, template_id)
env = environment.Environment(t.environment)
return cls(t.template, template_id=template_id, files=t.files, env=env)
@ -137,10 +137,10 @@ class Template(collections.Mapping):
'environment': self.env.user_env_as_dict()
}
if self.id is None:
new_rt = db_api.raw_template_create(context, rt)
new_rt = template_object.RawTemplate.create(context, rt)
self.id = new_rt.id
else:
db_api.raw_template_update(context, self.id, rt)
template_object.RawTemplate.update_by_id(context, self.id, rt)
return self.id
def __iter__(self):

View File

@ -24,6 +24,7 @@ from heat.common.i18n import _LW
from heat.db import api as db_api
from heat.engine import stack
from heat.engine import timestamp
from heat.objects import stack as stack_object
from heat.rpc import api as rpc_api
LOG = logging.getLogger(__name__)
@ -257,8 +258,10 @@ class WatchRule(object):
if self.ACTION_MAP[new_state] not in self.rule:
LOG.info(_LI('no action for new state %s'), new_state)
else:
s = db_api.stack_get(self.context, self.stack_id,
eager_load=True)
s = stack_object.Stack.get_by_id(
self.context,
self.stack_id,
eager_load=True)
stk = stack.Stack.load(self.context, stack=s)
if (stk.action != stk.DELETE
and stk.status == stk.COMPLETE):

0
heat/objects/__init__.py Executable file
View File

36
heat/objects/fields.py Normal file
View File

@ -0,0 +1,36 @@
# Copyright 2014 Intel Corp.
#
# 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.
from oslo_serialization import jsonutils as json
from oslo_versionedobjects import fields
import six
class Json(fields.FieldType):
def coerce(self, obj, attr, value):
if isinstance(value, six.string_types):
loaded = json.loads(value)
return loaded
return value
def from_primitive(self, obj, attr, value):
return self.coerce(obj, attr, value)
def to_primitive(self, obj, attr, value):
return json.dumps(value)
class JsonField(fields.AutoTypedField):
pass

View File

@ -0,0 +1,60 @@
# Copyright 2014 Intel Corp.
#
# 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.
"""
RawTemplate object
"""
from oslo_versionedobjects import base
from oslo_versionedobjects import fields
from heat.db import api as db_api
from heat.objects import fields as heat_fields
class RawTemplate(
base.VersionedObject,
base.VersionedObjectDictCompat,
base.ComparableVersionedObject,
):
fields = {
'id': fields.StringField(),
'files': heat_fields.JsonField(nullable=True),
'template': heat_fields.JsonField(),
'environment': heat_fields.JsonField(),
'predecessor': fields.IntegerField(),
}
@staticmethod
def _from_db_object(context, tpl, db_tpl):
for field in tpl.fields:
tpl[field] = db_tpl[field]
tpl._context = context
tpl.obj_reset_changes()
return tpl
@classmethod
def get_by_id(cls, context, template_id):
raw_template_db = db_api.raw_template_get(context, template_id)
raw_template = cls._from_db_object(context, cls(), raw_template_db)
return raw_template
@classmethod
def create(cls, context, values):
return db_api.raw_template_create(context, values)
@classmethod
def update_by_id(cls, context, template_id, values):
return db_api.raw_template_update(context, template_id, values)

133
heat/objects/stack.py Executable file
View File

@ -0,0 +1,133 @@
# Copyright 2014 Intel Corp.
#
# 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.
"""
Stack object
"""
from oslo_versionedobjects import base
from oslo_versionedobjects import fields
from heat.db import api as db_api
from heat import objects
from heat.objects import fields as heat_fields
class Stack(
base.VersionedObject,
base.VersionedObjectDictCompat,
base.ComparableVersionedObject,
):
fields = {
'id': fields.StringField(),
'name': fields.StringField(),
'raw_template_id': fields.IntegerField(),
'backup': fields.BooleanField(),
'created_at': fields.DateTimeField(read_only=True),
'deleted_at': fields.DateTimeField(nullable=True),
'disable_rollback': fields.BooleanField(),
'nested_depth': fields.IntegerField(),
'owner_id': fields.StringField(nullable=True),
'stack_user_project_id': fields.StringField(nullable=True),
'tenant': fields.StringField(nullable=True),
'timeout': fields.IntegerField(nullable=True),
'updated_at': fields.DateTimeField(nullable=True),
'user_creds_id': fields.StringField(nullable=True),
'username': fields.StringField(nullable=True),
'action': fields.StringField(nullable=True),
'status': fields.StringField(nullable=True),
'status_reason': fields.StringField(nullable=True),
'raw_template': fields.ObjectField('RawTemplate'),
'convergence': fields.BooleanField(),
'current_traversal': fields.StringField(),
'current_deps': heat_fields.JsonField(),
'prev_raw_template_id': fields.IntegerField(),
'prev_raw_template': fields.ObjectField('RawTemplate'),
}
@staticmethod
def _from_db_object(context, stack, db_stack):
for field in stack.fields:
if field == 'raw_template':
stack['raw_template'] = (
objects.raw_template.RawTemplate.get_by_id(
context, db_stack['raw_template_id']))
else:
stack[field] = db_stack[field]
stack._context = context
stack.obj_reset_changes()
return stack
@classmethod
def get_by_id(cls, context, stack_id, **kwargs):
db_stack = db_api.stack_get(context, stack_id, **kwargs)
if not db_stack:
return db_stack
stack = cls._from_db_object(context, cls(context), db_stack)
return stack
@classmethod
def get_by_name_and_owner_id(cls, context, stack_name, owner_id):
return db_api.stack_get_by_name_and_owner_id(context, stack_name,
owner_id)
@classmethod
def get_by_name(cls, context, stack_name):
return db_api.stack_get_by_name(context, stack_name)
@classmethod
def get_all(cls, context, *args, **kwargs):
return db_api.stack_get_all(context, *args, **kwargs)
@classmethod
def get_all_by_owner_id(cls, context, owner_id):
return db_api.stack_get_all_by_owner_id(context, owner_id)
@classmethod
def count_all(cls, context, **kwargs):
return db_api.stack_count_all(context, **kwargs)
@classmethod
def create(cls, context, values):
return db_api.stack_create(context, values)
@classmethod
def update_by_id(cls, context, stack_id, values):
return db_api.stack_update(context, stack_id, values)
@classmethod
def delete(cls, context, stack_id):
return db_api.stack_delete(context, stack_id)
def update_and_save(self, values):
db_stack = self.__class__.update_by_id(self._context, self.id, values)
self.refresh()
return db_stack
def __eq__(self, another):
self.refresh() # to make test object comparison work well
return super(Stack, self).__eq__(another)
def refresh(self):
return self.__class__._from_db_object(
self._context,
self,
db_api.stack_get(
self._context,
self.id,
show_deleted=True,
),
)

View File

@ -48,6 +48,7 @@ from heat.engine import stack_lock
from heat.engine import template as templatem
from heat.engine import watchrule
from heat.engine import worker
from heat.objects import stack as stack_object
from heat.openstack.common import threadgroup
from heat.rpc import api as rpc_api
from heat.rpc import worker_api
@ -231,14 +232,18 @@ def setup_mocks(mocks, stack, mock_image_constraint=True):
'ec2-user').AndReturn(server_userdata)
mocks.StubOutWithMock(fc.servers, 'create')
fc.servers.create(image=744, flavor=3, key_name='test',
name=utils.PhysName(stack.name, 'WebServer'),
security_groups=None,
userdata=server_userdata, scheduler_hints=None,
meta=None, nics=None,
availability_zone=None,
block_device_mapping=None).AndReturn(
fc.servers.list()[4])
fc.servers.create(
image=744,
flavor=3,
key_name='test',
name=utils.PhysName(stack.name, 'WebServer'),
security_groups=None,
userdata=server_userdata,
scheduler_hints=None,
meta=None,
nics=None,
availability_zone=None,
block_device_mapping=None).AndReturn(fc.servers.list()[4])
return fc
@ -412,7 +417,7 @@ class StackCreateTest(common.HeatTestCase):
stack_id = stack.store()
stack.create()
db_s = db_api.stack_get(ctx, stack_id)
db_s = stack_object.Stack.get_by_id(ctx, stack_id)
self.assertIsNotNone(db_s)
self.assertIsNotNone(stack['WebServer'])
@ -427,7 +432,9 @@ class StackCreateTest(common.HeatTestCase):
rsrc = stack['WebServer']
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
self.assertEqual((stack.DELETE, stack.COMPLETE), rsrc.state)
self.assertIsNone(db_api.stack_get(ctx, stack_id))
self.assertIsNone(stack_object.Stack.get_by_id(ctx, stack_id))
db_s.refresh()
self.assertEqual('DELETE', db_s.action)
self.assertEqual('COMPLETE', db_s.status, )
@ -562,7 +569,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
template, {}, None,
{'adopt_stack_data': str(adopt_data)})
stack = db_api.stack_get(self.ctx, result['stack_id'])
stack = stack_object.Stack.get_by_id(self.ctx, result['stack_id'])
self.assertEqual(template, stack.raw_template.template)
self.assertEqual(environment['parameters'],
stack.raw_template.environment['parameters'])
@ -805,7 +812,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
stack = get_wordpress_stack(stack_name, self.ctx)
sid = stack.store()
s = db_api.stack_get(self.ctx, sid)
s = stack_object.Stack.get_by_id(self.ctx, sid)
self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.ctx, stack=s).AndReturn(stack)
@ -832,7 +839,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
stack = get_wordpress_stack(stack_name, self.ctx)
sid = stack.store()
st = db_api.stack_get(self.ctx, sid)
st = stack_object.Stack.get_by_id(self.ctx, sid)
self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.ctx, stack=st).MultipleTimes().AndReturn(stack)
@ -849,7 +856,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
stack = get_wordpress_stack(stack_name, self.ctx)
sid = stack.store()
st = db_api.stack_get(self.ctx, sid)
st = stack_object.Stack.get_by_id(self.ctx, sid)
self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.ctx, stack=st).MultipleTimes().AndReturn(stack)
@ -876,7 +883,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
# Create a fake ThreadGroup too
self.man.thread_group_mgr.groups[stack.id] = DummyThreadGroup()
st = db_api.stack_get(self.ctx, sid)
st = stack_object.Stack.get_by_id(self.ctx, sid)
self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.ctx, stack=st).MultipleTimes().AndReturn(stack)
@ -902,7 +909,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
# Insert a fake lock into the db
db_api.stack_lock_create(stack.id, "other-engine-fake-uuid")
st = db_api.stack_get(self.ctx, sid)
st = stack_object.Stack.get_by_id(self.ctx, sid)
self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.ctx, stack=st).AndReturn(stack)
@ -935,7 +942,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
# Insert a fake lock into the db
db_api.stack_lock_create(stack.id, "other-engine-fake-uuid")
st = db_api.stack_get(self.ctx, sid)
st = stack_object.Stack.get_by_id(self.ctx, sid)
self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.ctx, stack=st).MultipleTimes().AndReturn(stack)
@ -967,7 +974,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
# Insert a fake lock into the db
db_api.stack_lock_create(stack.id, "other-engine-fake-uuid")
st = db_api.stack_get(self.ctx, sid)
st = stack_object.Stack.get_by_id(self.ctx, sid)
self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.ctx, stack=st).MultipleTimes().AndReturn(stack)
@ -1001,7 +1008,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
template = '{ "Template": "data" }'
old_stack = get_wordpress_stack(stack_name, self.ctx)
sid = old_stack.store()
s = db_api.stack_get(self.ctx, sid)
s = stack_object.Stack.get_by_id(self.ctx, sid)
stack = get_wordpress_stack(stack_name, self.ctx)
@ -1046,7 +1053,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
old_stack = get_wordpress_stack_no_params(stack_name, self.ctx)
sid = old_stack.store()
s = db_api.stack_get(self.ctx, sid)
s = stack_object.Stack.get_by_id(self.ctx, sid)
t = template_format.parse(wp_template_no_default)
template = templatem.Template(t)
@ -1095,7 +1102,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
old_stack.timeout_mins = 1
old_stack.disable_rollback = False
sid = old_stack.store()
s = db_api.stack_get(self.ctx, sid)
s = stack_object.Stack.get_by_id(self.ctx, sid)
stack = get_wordpress_stack(stack_name, self.ctx)
@ -1174,7 +1181,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
old_stack = parser.Stack(self.ctx, stack_name, template)
sid = old_stack.store()
s = db_api.stack_get(self.ctx, sid)
s = stack_object.Stack.get_by_id(self.ctx, sid)
stack = parser.Stack(self.ctx, stack_name, template)
@ -1231,7 +1238,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
self.assertEqual((create_stack.CREATE, create_stack.COMPLETE),
create_stack.state)
s = db_api.stack_get(self.ctx, sid)
s = stack_object.Stack.get_by_id(self.ctx, sid)
old_stack = parser.Stack.load(self.ctx, stack=s)
@ -1241,7 +1248,9 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
old_stack['A'].properties['Foo'])
self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.ctx, stack=s).AndReturn(old_stack)
parser.Stack.load(
self.ctx,
stack=s).AndReturn(old_stack)
self.m.ReplayAll()
@ -1296,8 +1305,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
old_stack = get_wordpress_stack(stack_name, self.ctx)
old_stack.store()
sid = old_stack.store()
s = db_api.stack_get(self.ctx, sid)
s = stack_object.Stack.get_by_id(self.ctx, sid)
stack = get_wordpress_stack(stack_name, self.ctx)
self._stub_update_mocks(s, old_stack)
@ -1350,7 +1358,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
old_stack['WebServer'].requires_deferred_auth = True
sid = old_stack.store()
s = db_api.stack_get(self.ctx, sid)
s = stack_object.Stack.get_by_id(self.ctx, sid)
self.ctx = utils.dummy_context(password=None)
@ -1448,7 +1456,7 @@ class StackServiceUpdateActionsNotSupportedTest(common.HeatTestCase):
old_stack.status = self.status
sid = old_stack.store()
s = db_api.stack_get(self.ctx, sid)
s = stack_object.Stack.get_by_id(self.ctx, sid)
self.m.StubOutWithMock(parser, 'Stack')
self.m.StubOutWithMock(parser.Stack, 'load')
@ -1479,7 +1487,7 @@ class StackServiceActionsTest(common.HeatTestCase):
stack_name = 'service_suspend_test_stack'
stack = get_wordpress_stack(stack_name, self.ctx)
sid = stack.store()
s = db_api.stack_get(self.ctx, sid)
s = stack_object.Stack.get_by_id(self.ctx, sid)
self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.ctx, stack=s).AndReturn(stack)
@ -1741,16 +1749,18 @@ class StackServiceTest(common.HeatTestCase):
@stack_context('service_name_tenants_test_stack', False)
def test_stack_by_name_tenants(self):
self.assertEqual(self.stack.id,
db_api.stack_get_by_name(self.ctx,
self.stack.name).id)
self.assertEqual(
self.stack.id,
stack_object.Stack.get_by_name(self.ctx, self.stack.name).id)
ctx2 = utils.dummy_context(tenant_id='stack_service_test_tenant2')
self.assertIsNone(db_api.stack_get_by_name(ctx2, self.stack.name))
self.assertIsNone(stack_object.Stack.get_by_name(
ctx2,
self.stack.name))
@stack_context('service_event_list_test_stack')
def test_stack_event_list(self):
self.m.StubOutWithMock(service.EngineService, '_get_stack')
s = db_api.stack_get(self.ctx, self.stack.id)
s = stack_object.Stack.get_by_id(self.ctx, self.stack.id)
service.EngineService._get_stack(self.ctx,
self.stack.identifier(),
show_deleted=True).AndReturn(s)
@ -2179,7 +2189,7 @@ class StackServiceTest(common.HeatTestCase):
@stack_context('service_describe_test_stack', False)
def test_stack_describe(self):
self.m.StubOutWithMock(service.EngineService, '_get_stack')
s = db_api.stack_get(self.ctx, self.stack.id)
s = stack_object.Stack.get_by_id(self.ctx, self.stack.id)
service.EngineService._get_stack(self.ctx,
self.stack.identifier(),
show_deleted=True).AndReturn(s)
@ -2591,7 +2601,7 @@ class StackServiceTest(common.HeatTestCase):
test_data = {'food': 'yum'}
self.m.StubOutWithMock(service.EngineService, '_get_stack')
s = db_api.stack_get(self.ctx, self.stack.id)
s = stack_object.Stack.get_by_id(self.ctx, self.stack.id)
service.EngineService._get_stack(self.ctx,
self.stack.identifier()).AndReturn(s)
@ -2620,7 +2630,7 @@ class StackServiceTest(common.HeatTestCase):
test_data = {'food': 'yum'}
self.m.StubOutWithMock(service.EngineService, '_get_stack')
s = db_api.stack_get(self.ctx, self.stack.id)
s = stack_object.Stack.get_by_id(self.ctx, self.stack.id)
service.EngineService._get_stack(self.ctx,
self.stack.identifier()).AndReturn(s)
self.m.ReplayAll()
@ -2677,7 +2687,7 @@ class StackServiceTest(common.HeatTestCase):
rsrc.metadata_set(test_metadata)
self.m.StubOutWithMock(service.EngineService, '_get_stack')
s = db_api.stack_get(self.ctx, self.stack.id)
s = stack_object.Stack.get_by_id(self.ctx, self.stack.id)
service.EngineService._get_stack(self.ctx,
self.stack.identifier()).AndReturn(s)
@ -2699,7 +2709,7 @@ class StackServiceTest(common.HeatTestCase):
pre_update_meta = self.stack['WebServer'].metadata_get()
self.m.StubOutWithMock(service.EngineService, '_get_stack')
s = db_api.stack_get(self.ctx, self.stack.id)
s = stack_object.Stack.get_by_id(self.ctx, self.stack.id)
service.EngineService._get_stack(self.ctx,
self.stack.identifier()).AndReturn(s)
self.m.StubOutWithMock(instances.Instance, 'metadata_update')
@ -4223,7 +4233,7 @@ class SnapshotServiceTest(common.HeatTestCase):
stack = get_wordpress_stack('stack', self.ctx)
sid = stack.store()
s = db_api.stack_get(self.ctx, sid)
s = stack_object.Stack.get_by_id(self.ctx, sid)
if stub:
self.m.StubOutWithMock(parser.Stack, 'load')
stack.state_set(stack.CREATE, stack.COMPLETE, 'mock completion')
@ -4324,12 +4334,14 @@ class SnapshotServiceTest(common.HeatTestCase):
def test_restore_snapshot_other_stack(self):
stack1 = self._create_stack()
stack2 = self._create_stack(stub=False)
self.m.ReplayAll()
snapshot1 = self.engine.stack_snapshot(
self.ctx, stack1.identifier(), 'snap1')
self.engine.thread_group_mgr.groups[stack1.id].wait()
snapshot_id = snapshot1['id']
self.m.UnsetStubs()
stack2 = self._create_stack()
self.m.ReplayAll()
self.engine.stack_restore(self.ctx, stack2.identifier(), snapshot_id)
self.engine.thread_group_mgr.groups[stack2.id].wait()
self.assertEqual((stack2.RESTORE, stack2.FAILED), stack2.state)

View File

@ -32,6 +32,7 @@ from heat.engine import resource
from heat.engine import scheduler
from heat.engine import stack
from heat.engine import template
from heat.objects import stack as stack_object
from heat.tests import common
from heat.tests import fakes
from heat.tests import generic_resource as generic_rsrc
@ -265,7 +266,7 @@ class StackTest(common.HeatTestCase):
def test_load_parent_resource(self):
self.stack = stack.Stack(self.ctx, 'load_parent_resource', self.tmpl)
self.stack.store()
stk = db_api.stack_get(self.ctx, self.stack.id)
stk = stack_object.Stack.get_by_id(self.ctx, self.stack.id)
t = template.Template.load(self.ctx, stk.raw_template_id)
self.m.StubOutWithMock(template.Template, 'load')

View File

@ -22,6 +22,7 @@ oslo.middleware>=0.3.0 # Apache-2.0
oslo.serialization>=1.2.0 # Apache-2.0
oslo.utils>=1.2.0 # Apache-2.0
osprofiler>=0.3.0 # Apache-2.0
oslo.versionedobjects>=0.1.0
PasteDeploy>=1.5.0
posix_ipc
pycrypto>=2.6