Make timestamps available in Stack/Resource objects
Provide the creation time and last-updated time as attributes of Stack and Resource objects so that external code does not need to access the database in order to retrieve them. Use a Descriptor class so that the latest values are always fetched from the database. Change-Id: Ic3fa173b1dc8f2e5dc676a9152e8928ed2290913 Signed-off-by: Zane Bitter <zbitter@redhat.com>
This commit is contained in:
parent
b0ec487799
commit
07be1d7269
@ -22,7 +22,7 @@ import logging
|
||||
from heat.common import exception
|
||||
from heat.engine import checkeddict
|
||||
from heat.engine import dependencies
|
||||
from heat.engine.resources import Resource
|
||||
from heat.engine import resources
|
||||
from heat.db import api as db_api
|
||||
|
||||
|
||||
@ -234,6 +234,9 @@ class Stack(object):
|
||||
DELETE_FAILED = 'DELETE_FAILED'
|
||||
DELETE_COMPLETE = 'DELETE_COMPLETE'
|
||||
|
||||
created_time = resources.Timestamp(db_api.stack_get, 'created_at')
|
||||
updated_time = resources.Timestamp(db_api.stack_get, 'updated_at')
|
||||
|
||||
def __init__(self, context, stack_name, template, parameters=None,
|
||||
stack_id=None, state=None, state_description='',
|
||||
timeout_mins=60):
|
||||
@ -257,7 +260,7 @@ class Stack(object):
|
||||
self.outputs = self.resolve_static_data(self.t[OUTPUTS])
|
||||
|
||||
self.resources = dict((name,
|
||||
Resource(name, data, self))
|
||||
resources.Resource(name, data, self))
|
||||
for (name, data) in self.t[RESOURCES].items())
|
||||
|
||||
self.dependencies = self._get_dependencies(self.resources.itervalues())
|
||||
|
@ -64,6 +64,32 @@ class Metadata(object):
|
||||
return None
|
||||
|
||||
|
||||
class Timestamp(object):
|
||||
'''
|
||||
A descriptor for fetching an up-to-date timestamp from the database.
|
||||
'''
|
||||
|
||||
def __init__(self, db_fetch, attribute):
|
||||
'''
|
||||
Initialise with a function to fetch the database representation of an
|
||||
object (given a context and ID) and the name of the attribute to
|
||||
retrieve.
|
||||
'''
|
||||
self.db_fetch = db_fetch
|
||||
self.attribute = attribute
|
||||
|
||||
def __get__(self, obj, obj_class):
|
||||
'''
|
||||
Get the latest data from the database for the given object and class.
|
||||
'''
|
||||
if obj is None or obj.id is None:
|
||||
return None
|
||||
|
||||
o = self.db_fetch(obj.context, obj.id)
|
||||
o.refresh(attrs=[self.attribute])
|
||||
return getattr(o, self.attribute)
|
||||
|
||||
|
||||
class Resource(object):
|
||||
CREATE_IN_PROGRESS = 'IN_PROGRESS'
|
||||
CREATE_FAILED = 'CREATE_FAILED'
|
||||
@ -78,6 +104,9 @@ class Resource(object):
|
||||
# If True, this resource must be created before it can be referenced.
|
||||
strict_dependency = True
|
||||
|
||||
created_time = Timestamp(db_api.resource_get, 'created_at')
|
||||
updated_time = Timestamp(db_api.resource_get, 'updated_at')
|
||||
|
||||
metadata = Metadata()
|
||||
|
||||
def __new__(cls, name, json, stack):
|
||||
|
@ -17,8 +17,9 @@ import nose
|
||||
import unittest
|
||||
from nose.plugins.attrib import attr
|
||||
import mox
|
||||
|
||||
import json
|
||||
|
||||
from heat.common import context
|
||||
from heat.common import exception
|
||||
from heat.engine import parser
|
||||
from heat.engine import checkeddict
|
||||
@ -318,6 +319,20 @@ class ParametersTest(unittest.TestCase):
|
||||
@attr(tag=['unit', 'parser', 'stack'])
|
||||
@attr(speed='fast')
|
||||
class StackTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.username = 'parser_stack_test_user'
|
||||
|
||||
self.m = mox.Mox()
|
||||
|
||||
self.ctx = context.get_admin_context()
|
||||
self.m.StubOutWithMock(self.ctx, 'username')
|
||||
self.ctx.username = self.username
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
||||
def tearDown(self):
|
||||
self.m.UnsetStubs()
|
||||
|
||||
def test_state_defaults(self):
|
||||
stack = parser.Stack(None, 'test_stack', parser.Template({}))
|
||||
self.assertEqual(stack.state, None)
|
||||
@ -341,6 +356,23 @@ class StackTest(unittest.TestCase):
|
||||
self.assertRaises(exception.NotFound, parser.Stack.load,
|
||||
None, -1)
|
||||
|
||||
def test_created_time(self):
|
||||
stack = parser.Stack(self.ctx, 'creation_time_test',
|
||||
parser.Template({}))
|
||||
self.assertEqual(stack.created_time, None)
|
||||
stack.store()
|
||||
self.assertNotEqual(stack.created_time, None)
|
||||
|
||||
def test_updated_time(self):
|
||||
stack = parser.Stack(self.ctx, 'update_time_test',
|
||||
parser.Template({}))
|
||||
self.assertEqual(stack.updated_time, None)
|
||||
stack.store()
|
||||
stored_time = stack.updated_time
|
||||
stack.state_set(stack.IN_PROGRESS, 'testing')
|
||||
self.assertNotEqual(stack.updated_time, None)
|
||||
self.assertNotEqual(stack.updated_time, stored_time)
|
||||
|
||||
# allows testing of the test directly, shown below
|
||||
if __name__ == '__main__':
|
||||
sys.argv.append(__file__)
|
||||
|
@ -28,11 +28,12 @@ from heat.engine import resources
|
||||
@attr(speed='fast')
|
||||
class ResourceTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.stack = parser.Stack(None, 'test_stack', parser.Template({}))
|
||||
self.stack = parser.Stack(None, 'test_stack', parser.Template({}),
|
||||
stack_id=-1)
|
||||
|
||||
def test_state_defaults(self):
|
||||
tmpl = {'Type': 'Foo'}
|
||||
res = resources.GenericResource('test_resource', tmpl, self.stack)
|
||||
res = resources.GenericResource('test_res_def', tmpl, self.stack)
|
||||
self.assertEqual(res.state, None)
|
||||
self.assertEqual(res.state_description, '')
|
||||
|
||||
@ -48,6 +49,22 @@ class ResourceTest(unittest.TestCase):
|
||||
res.state_set('blarg', 'wibble')
|
||||
self.assertEqual(res.state_description, 'wibble')
|
||||
|
||||
def test_created_time(self):
|
||||
tmpl = {'Type': 'Foo'}
|
||||
res = resources.GenericResource('test_res_new', tmpl, self.stack)
|
||||
self.assertEqual(res.created_time, None)
|
||||
res._store()
|
||||
self.assertNotEqual(res.created_time, None)
|
||||
|
||||
def test_updated_time(self):
|
||||
tmpl = {'Type': 'Foo'}
|
||||
res = resources.GenericResource('test_res_upd', tmpl, self.stack)
|
||||
res._store()
|
||||
stored_time = res.updated_time
|
||||
res.state_set(res.CREATE_IN_PROGRESS, 'testing')
|
||||
self.assertNotEqual(res.updated_time, None)
|
||||
self.assertNotEqual(res.updated_time, stored_time)
|
||||
|
||||
def test_parsed_template(self):
|
||||
tmpl = {
|
||||
'Type': 'Foo',
|
||||
|
Loading…
Reference in New Issue
Block a user