From: Angus Salkeld Date: Thu, 21 Jun 2012 10:10:53 +0000 (+1000) Subject: Fix the wait condition's reading of the metadata. X-Git-Tag: 2014.1~1692 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=c44746d8d500825211b53cfdc54ee8ea73fb639d;p=openstack-build%2Fheat-build.git Fix the wait condition's reading of the metadata. the db was caching the object, so we need to 'expire' it to make sure we are getting live data. Change-Id: I1108daccc96f3dcfa33fda968ea30d83e03aad2d Signed-off-by: Angus Salkeld --- diff --git a/heat/db/sqlalchemy/models.py b/heat/db/sqlalchemy/models.py index 9d477815..24285526 100644 --- a/heat/db/sqlalchemy/models.py +++ b/heat/db/sqlalchemy/models.py @@ -61,6 +61,22 @@ class HeatBase(object): else: raise + def expire(self, session=None): + """Expire this object ().""" + if not session: + session = Session.object_session(self) + if not session: + session = get_session() + session.expire(self) + + def refresh(self, session=None): + """Refresh this object.""" + if not session: + session = Session.object_session(self) + if not session: + session = get_session() + session.refresh(self) + def delete(self, session=None): """Delete this object.""" self.deleted = True diff --git a/heat/engine/manager.py b/heat/engine/manager.py index be8b6465..0fee2e77 100644 --- a/heat/engine/manager.py +++ b/heat/engine/manager.py @@ -492,6 +492,7 @@ class EngineManager(manager.Manager): """ s = db_api.stack_get_by_name(None, stack_name) if not s: + logger.warn("Stack not found %s." % (stack_name)) return ['stack', None] r = db_api.resource_get_by_name_and_stack(None, resource_id, s.id) diff --git a/heat/engine/wait_condition.py b/heat/engine/wait_condition.py index f43f5674..894cb0d8 100644 --- a/heat/engine/wait_condition.py +++ b/heat/engine/wait_condition.py @@ -78,6 +78,7 @@ class WaitCondition(Resource): status = 'WAITING' reason = '' res = None + sleep_time = 1 try: while status == 'WAITING': try: @@ -85,21 +86,28 @@ class WaitCondition(Resource): res_name, self.stack.id) except Exception as ex: + logger.exception('resource %s not found' % res_name) if 'not found' in ex: # it has been deleted status = 'DELETED' else: pass - if res and res.rsrc_metadata: - metadata = res.rsrc_metadata - if metadata: - status = metadata.get('Status', 'WAITING') - reason = metadata.get('Reason', 'Reason not provided') - logger.debug('got %s' % json.dumps(metadata)) + if res: + if res.rsrc_metadata: + meta = res.rsrc_metadata + status = meta.get('Status', + 'WAITING') + reason = meta.get('Reason', + 'Reason not provided') + logger.debug('got %s' % json.dumps(res.rsrc_metadata)) if status == 'WAITING': logger.debug('Waiting some more for the Metadata[Status]') - eventlet.sleep(30) + eventlet.sleep(sleep_time) + sleep_time = min(sleep_time * 2, self.timeout / 4) + if res: + res.expire() + except eventlet.Timeout, t: if t is not tmo: # not my timeout diff --git a/heat/tests/test_waitcondition.py b/heat/tests/test_waitcondition.py new file mode 100644 index 00000000..34ab5258 --- /dev/null +++ b/heat/tests/test_waitcondition.py @@ -0,0 +1,108 @@ +from datetime import datetime +import eventlet +import json +import logging +import os +import sys + +import nose +import unittest +import mox +from nose.plugins.attrib import attr +from nose import with_setup + +import heat.db as db_api +from heat.engine import parser + +logger = logging.getLogger('test_waitcondition') + +test_template_waitcondition = ''' +{ + "AWSTemplateFormatVersion" : "2010-09-09", + "Description" : "Just a WaitCondition.", + "Parameters" : {}, + "Resources" : { + "WaitHandle" : { + "Type" : "AWS::CloudFormation::WaitConditionHandle" + }, + "WaitForTheHandle" : { + "Type" : "AWS::CloudFormation::WaitCondition", + "Properties" : { + "Handle" : {"Ref" : "WaitHandle"}, + "Timeout" : "5" + } + } + } +} +''' + + +@attr(tag=['unit', 'resource']) +@attr(speed='slow') +class stacksTest(unittest.TestCase): + def setUp(self): + self.m = mox.Mox() + self.greenpool = eventlet.GreenPool() + + def tearDown(self): + self.m.UnsetStubs() + + def create_stack(self, stack_name, temp, params): + stack = parser.Stack(None, stack_name, temp, 0, params) + + rt = {} + rt['template'] = temp + rt['StackName'] = stack_name + new_rt = db_api.raw_template_create(None, rt) + + ct = {'username': 'fred', + 'password': 'mentions_fruit'} + new_creds = db_api.user_creds_create(ct) + + s = {} + s['name'] = stack_name + s['raw_template_id'] = new_rt.id + s['user_creds_id'] = new_creds.id + s['username'] = ct['username'] + new_s = db_api.stack_create(None, s) + stack.id = new_s.id + pt = {} + pt['template'] = stack.t + pt['raw_template_id'] = new_rt.id + new_pt = db_api.parsed_template_create(None, pt) + + stack.parsed_template_id = new_pt.id + return stack + + def test_post_success_to_handle(self): + params = {} + t = json.loads(test_template_waitcondition) + stack = self.create_stack('test_stack', t, params) + + self.m.ReplayAll() + self.greenpool.spawn_n(stack.create) + eventlet.sleep(1) + assert(stack.resources['WaitForTheHandle'].state == 'IN_PROGRESS') + + r = db_api.resource_get_by_name_and_stack(None, 'WaitHandle', + stack.id) + assert(r.name == 'WaitHandle') + + metadata = {"Status": "SUCCESS", + "Reason": "woot toot", + "Data": "Application has completed configuration.", + "UniqueId": "00000"} + + r.update_and_save({'rsrc_metadata': metadata}) + + eventlet.sleep(2) + + logger.debug('state %s' % stack.resources['WaitForTheHandle'].state) + assert(stack.resources['WaitForTheHandle'].state == 'CREATE_COMPLETE') + + self.greenpool.waitall() + + # allows testing of the test directly + if __name__ == '__main__': + sys.argv.append(__file__) + nose.main()