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
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):
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())
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'
# 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):
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
@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)
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__)
@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, '')
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',