Change Resource timestamps to save correct info

Resource.updated_time is currently being treated as modification time
of the object in the database.  Since it's not a very useful thing to
have and the CFN API treats this value as "the last time an update
call was issued", it makes sense to have the same behavior here as
well.

This changes the current real-time retrieval of created_time and
updated_time in favor of the attributes already present in the
resource and changes the information stored in these two fields to be
the time the resource was created and the time the resource was last
updated by the user, respectively.

Co-Authored-By: Richard Lee <rblee88@gmail.com>
Related-Bug: #1193269
Change-Id: Iad689b97d237fa63856b878827a1fcb1676c991c
This commit is contained in:
Anderson Mesquita 2014-02-26 15:24:17 -05:00
parent ce690963e7
commit cc1d2dddfb
3 changed files with 30 additions and 8 deletions

View File

@ -222,6 +222,11 @@ class Resource(BASE, HeatBase):
cascade="all,delete",
backref=backref('resource'))
# Override timestamp column to store the correct value: it should be the
# time the create/update call was issued, not the time the DB entry is
# created/modified. (bug #1193269)
updated_at = sqlalchemy.Column(sqlalchemy.DateTime)
class WatchRule(BASE, HeatBase):
"""Represents a watch_rule created by the heat engine."""

View File

@ -13,8 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import base64
import copy
from datetime import datetime
from heat.engine import event
from heat.common import exception
@ -25,7 +26,6 @@ from heat.common import short_id
from heat.engine import scheduler
from heat.engine import resources
from heat.engine import support
from heat.engine import timestamp
# import class to avoid name collisions and ugly aliasing
from heat.engine.attributes import Attributes
from heat.engine.properties import Properties
@ -102,9 +102,6 @@ class Resource(object):
# If True, this resource must be created before it can be referenced.
strict_dependency = True
created_time = timestamp.Timestamp(db_api.resource_get, 'created_at')
updated_time = timestamp.Timestamp(db_api.resource_get, 'updated_at')
_metadata = Metadata()
# Resource implementation set this to the subset of template keys
@ -167,6 +164,8 @@ class Resource(object):
self.status_reason = resource.status_reason
self.id = resource.id
self.data = resource.data
self.created_time = resource.created_at
self.updated_time = resource.updated_at
else:
self.resource_id = None
# if the stack is being deleted, assume we've already been deleted
@ -178,6 +177,8 @@ class Resource(object):
self.status_reason = ''
self.id = None
self.data = []
self.created_time = None
self.updated_time = None
def reparse(self):
self.t = self.stack.resolve_static_data(self.json_snippet)
@ -539,6 +540,7 @@ class Resource(object):
logger.info('updating %s' % str(self))
try:
self.updated_time = datetime.utcnow()
self.state_set(action, self.IN_PROGRESS)
properties = Properties(self.properties_schema,
after.get('Properties', {}),
@ -750,6 +752,7 @@ class Resource(object):
new_rs = db_api.resource_create(self.context, rs)
self.id = new_rs.id
self.created_time = new_rs.created_at
except Exception as ex:
logger.error(_('DB error %s') % str(ex))
@ -776,6 +779,7 @@ class Resource(object):
'status': self.status,
'status_reason': reason,
'stack_id': self.stack.id,
'updated_at': self.updated_time,
'nova_instance': self.resource_id})
except Exception as ex:
logger.error(_('DB error %s') % str(ex))

View File

@ -226,14 +226,27 @@ class ResourceTest(HeatTestCase):
self.assertIsNotNone(res.created_time)
def test_updated_time(self):
tmpl = {'Type': 'Foo'}
res = generic_rsrc.GenericResource('test_res_upd', tmpl, self.stack)
tmpl = {'Type': 'GenericResourceType'}
res = generic_rsrc.GenericResource('test_resource', tmpl, self.stack)
res.update_allowed_keys = ('Type',)
res._store()
stored_time = res.updated_time
res.state_set(res.CREATE, res.IN_PROGRESS, 'testing')
utmpl = {'Type': 'Foo'}
scheduler.TaskRunner(res.update, utmpl)()
self.assertIsNotNone(res.updated_time)
self.assertNotEqual(res.updated_time, stored_time)
def test_updated_time_changes_only_on_update_calls(self):
tmpl = {'Type': 'GenericResourceType'}
res = generic_rsrc.GenericResource('test_resource', tmpl, self.stack)
res.update_allowed_keys = ('Type',)
res._store()
self.assertIsNone(res.updated_time)
res._store_or_update(res.UPDATE, res.COMPLETE, 'should not change')
self.assertIsNone(res.updated_time)
def test_store_or_update(self):
tmpl = {'Type': 'Foo'}
res = generic_rsrc.GenericResource('test_res_upd', tmpl, self.stack)