]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Do a metadata refresh after an explicit metadata write.
authorAngus Salkeld <asalkeld@redhat.com>
Thu, 28 Feb 2013 22:40:59 +0000 (09:40 +1100)
committerAngus Salkeld <asalkeld@redhat.com>
Thu, 28 Feb 2013 22:40:59 +0000 (09:40 +1100)
if we have a template with (logically) the following:
instance2:
   metadata
     GetAtt waitcond.data

waitcond:

when the waitcond is fired, it updates the metadata but it needs a call
to update the references in "instance2's" metadata.

bug #1135229
Signed-off-by: Angus Salkeld <asalkeld@redhat.com>
Change-Id: I1a6af9112ba100b17075063f59165b448d6a11f4

heat/engine/service.py
heat/tests/test_metadata_refresh.py

index 27cd83bcd77ffa0f0473ad3011d9849ab9b32856..ee8bbcebe265b7198a43374559047d3ff8539050 100644 (file)
@@ -485,6 +485,14 @@ class EngineService(service.Service):
         resource = stack[resource_name]
         resource.metadata_update(new_metadata=metadata)
 
+        # Refresh the metadata for all other resources, since we expect
+        # resource_name to be a WaitCondition resource, and other
+        # resources may refer to WaitCondition Fn::GetAtt Data, which
+        # is updated here.
+        for res in stack:
+            if res.name != resource_name:
+                res.metadata_update()
+
         return resource.metadata
 
     def _periodic_watcher_task(self, sid):
index c7631cfeb4b672d0e0c2a9a71b33aa460fbf344e..fff98ff39d6aa2e3bdb708a9b857c8d79c8b1836 100644 (file)
@@ -19,13 +19,18 @@ import eventlet
 import unittest
 from nose.plugins.attrib import attr
 
+from oslo.config import cfg
 from heat.tests import fakes
 from heat.tests.utils import stack_delete_after
 
+from heat.common import identifier
 from heat.common import template_format
 from heat.engine import parser
+from heat.engine import service
 from heat.engine.resources import instance
 from heat.common import context
+from heat.engine.resources import wait_condition as wc
+
 
 test_template_metadata = '''
 {
@@ -73,6 +78,40 @@ test_template_metadata = '''
 }
 '''
 
+test_template_waitcondition = '''
+{
+  "AWSTemplateFormatVersion" : "2010-09-09",
+  "Description" : "Just a WaitCondition.",
+  "Parameters" : {
+    "KeyName" : {"Type" : "String", "Default": "mine" },
+  },
+  "Resources" : {
+    "S1": {
+      "Type": "AWS::EC2::Instance",
+      "Metadata" : {
+        "test" : {"Fn::GetAtt": ["WC", "Data"]}
+      },
+      "Properties": {
+        "ImageId"      : "a",
+        "InstanceType" : "m1.large",
+        "KeyName"      : { "Ref" : "KeyName" },
+        "UserData"     : "#!/bin/bash -v\n"
+      }
+    },
+    "WH" : {
+      "Type" : "AWS::CloudFormation::WaitConditionHandle"
+    },
+    "WC" : {
+      "Type" : "AWS::CloudFormation::WaitCondition",
+      "Properties" : {
+        "Handle" : {"Ref" : "WH"},
+        "Timeout" : "5"
+      }
+    }
+  }
+}
+'''
+
 
 @attr(tag=['unit', 'resource', 'Metadata'])
 @attr(speed='slow')
@@ -85,7 +124,6 @@ class MetadataRefreshTest(unittest.TestCase):
     def setUp(self):
         self.m = mox.Mox()
         self.m.StubOutWithMock(eventlet, 'sleep')
-
         self.fc = fakes.FakeKeystoneClient()
 
     def tearDown(self):
@@ -138,3 +176,88 @@ class MetadataRefreshTest(unittest.TestCase):
         self.assertEqual(cont, 's2-ip=10.0.0.5')
 
         self.m.VerifyAll()
+
+
+@attr(tag=['unit', 'resource', 'Metadata'])
+@attr(speed='slow')
+class WaitCondMetadataUpdateTest(unittest.TestCase):
+    def setUp(self):
+        self.m = mox.Mox()
+        self.ctx = context.get_admin_context()
+        self.ctx.tenant_id = 'test_tenant'
+        self.fc = fakes.FakeKeystoneClient()
+        self.man = service.EngineService('a-host', 'a-topic')
+        cfg.CONF.set_default('heat_waitcondition_server_url',
+                             'http://127.0.0.1:8000/v1/waitcondition')
+
+    def tearDown(self):
+        self.m.UnsetStubs()
+
+    # Note tests creating a stack should be decorated with @stack_delete_after
+    # to ensure the stack is properly cleaned up
+    def create_stack(self, stack_name='test_stack',
+                     template=test_template_metadata):
+        temp = template_format.parse(template)
+        template = parser.Template(temp)
+        parameters = parser.Parameters(stack_name, template, {})
+        stack = parser.Stack(self.ctx, stack_name, template, parameters,
+                             disable_rollback=True)
+
+        self.stack_id = stack.store()
+
+        self.m.StubOutWithMock(instance.Instance, 'handle_create')
+        instance.Instance.handle_create().MultipleTimes().AndReturn(None)
+
+        self.m.StubOutWithMock(wc.WaitConditionHandle, 'keystone')
+        wc.WaitConditionHandle.keystone().MultipleTimes().AndReturn(self.fc)
+
+        id = identifier.ResourceIdentifier('test_tenant', stack.name,
+                                           stack.id, '', 'WH')
+        self.m.StubOutWithMock(wc.WaitConditionHandle, 'identifier')
+        wc.WaitConditionHandle.identifier().MultipleTimes().AndReturn(id)
+
+        self.m.StubOutWithMock(wc.WaitConditionHandle, 'get_status')
+        self.m.StubOutWithMock(wc.WaitCondition, '_create_timeout')
+        self.m.StubOutWithMock(eventlet, 'sleep')
+
+        return stack
+
+    @stack_delete_after
+    def test_wait_meta(self):
+        '''
+        1 create stack
+        2 assert empty instance metadata
+        3 service.metadata_update()
+        4 assert valid waitcond metadata
+        5 assert valid instance metadata
+        '''
+
+        self.stack = self.create_stack(template=test_template_waitcondition)
+
+        wc.WaitCondition._create_timeout().AndReturn(eventlet.Timeout(5))
+        wc.WaitConditionHandle.get_status().AndReturn([])
+        eventlet.sleep(1).AndReturn(None)
+        wc.WaitConditionHandle.get_status().AndReturn([])
+        eventlet.sleep(1).AndReturn(None)
+        wc.WaitConditionHandle.get_status().AndReturn(['SUCCESS'])
+
+        self.m.ReplayAll()
+        self.stack.create()
+
+        s1 = self.stack.resources['S1']
+        s1._store()
+        watch = self.stack.resources['WC']
+
+        self.assertEqual(watch.FnGetAtt('Data'), '{}')
+        self.assertEqual(s1.metadata['test'], '{}')
+
+        test_metadata = {'Data': 'foo', 'Reason': 'bar',
+                         'Status': 'SUCCESS', 'UniqueId': '123'}
+        self.man.metadata_update(self.ctx,
+                                 dict(self.stack.identifier()),
+                                 'WH', test_metadata)
+
+        self.assertEqual(watch.FnGetAtt('Data'), '{"123": "foo"}')
+        self.assertEqual(s1.metadata['test'], '{"123": "foo"}')
+
+        self.m.VerifyAll()