heat engine : WaitCondition add Handle property validation

Add validation to the Handle property for WaitCondition, so
we check that the identifier in the provided URL maps to
a WaitConditionHandle resource in the same stack as the
WaitCondition

fixes bug 1100754

Change-Id: I44c8f52435016fad5a35183472d2b0df26c1915d
This commit is contained in:
Steven Hardy 2013-02-01 13:01:18 +00:00
parent 7574ce87bc
commit c751abc05d
2 changed files with 143 additions and 10 deletions

View File

@ -204,6 +204,26 @@ class WaitCondition(resource.Resource):
self.timeout / self.SLEEP_DIV), self.timeout / self.SLEEP_DIV),
self.MIN_SLEEP) self.MIN_SLEEP)
def _validate_handle_url(self):
handle_url = self.properties['Handle']
handle_id = identifier.ResourceIdentifier.from_arn_url(handle_url)
if handle_id.tenant != self.stack.context.tenant_id:
raise ValueError("WaitCondition invalid Handle tenant %s" %
handle_id.tenant)
if handle_id.stack_name != self.stack.name:
raise ValueError("WaitCondition invalid Handle stack %s" %
handle_id.stack_name)
if handle_id.stack_id != self.stack.id:
raise ValueError("WaitCondition invalid Handle stack %s" %
handle_id.stack_id)
if handle_id.resource_name not in self.stack:
raise ValueError("WaitCondition invalid Handle %s" %
handle_id.resource_name)
if not isinstance(self.stack[handle_id.resource_name],
WaitConditionHandle):
raise ValueError("WaitCondition invalid Handle %s" %
handle_id.resource_name)
def _get_handle_resource_name(self): def _get_handle_resource_name(self):
handle_url = self.properties['Handle'] handle_url = self.properties['Handle']
handle_id = identifier.ResourceIdentifier.from_arn_url(handle_url) handle_id = identifier.ResourceIdentifier.from_arn_url(handle_url)
@ -213,6 +233,7 @@ class WaitCondition(resource.Resource):
return eventlet.Timeout(self.timeout) return eventlet.Timeout(self.timeout)
def handle_create(self): def handle_create(self):
self._validate_handle_url()
tmo = None tmo = None
status = FAILURE status = FAILURE
reason = "Unknown reason" reason = "Unknown reason"

View File

@ -17,6 +17,7 @@ import mox
import uuid import uuid
import time import time
import datetime import datetime
import json
import eventlet import eventlet
import unittest import unittest
@ -96,22 +97,26 @@ class WaitConditionTest(unittest.TestCase):
# Note tests creating a stack should be decorated with @stack_delete_after # Note tests creating a stack should be decorated with @stack_delete_after
# to ensure the stack is properly cleaned up # to ensure the stack is properly cleaned up
def create_stack(self, stack_name='test_stack', def create_stack(self, stack_name='test_stack',
template=test_template_waitcondition, params={}): template=test_template_waitcondition, params={},
stub=True):
temp = template_format.parse(template) temp = template_format.parse(template)
template = parser.Template(temp) template = parser.Template(temp)
parameters = parser.Parameters(stack_name, template, params) parameters = parser.Parameters(stack_name, template, params)
stack = parser.Stack(context.get_admin_context(), stack_name, ctx = context.get_admin_context()
template, parameters) ctx.tenant_id = 'test_tenant'
stack = parser.Stack(ctx, stack_name, template, parameters)
stack.store() self.stack_id = stack.store()
self.m.StubOutWithMock(wc.WaitConditionHandle, 'keystone') if stub:
wc.WaitConditionHandle.keystone().MultipleTimes().AndReturn(self.fc) self.m.StubOutWithMock(wc.WaitConditionHandle, 'keystone')
wc.WaitConditionHandle.keystone().MultipleTimes().AndReturn(
self.fc)
id = identifier.ResourceIdentifier('test_tenant', stack.name, id = identifier.ResourceIdentifier('test_tenant', stack.name,
stack.id, '', 'WaitHandle') stack.id, '', 'WaitHandle')
self.m.StubOutWithMock(wc.WaitConditionHandle, 'identifier') self.m.StubOutWithMock(wc.WaitConditionHandle, 'identifier')
wc.WaitConditionHandle.identifier().MultipleTimes().AndReturn(id) wc.WaitConditionHandle.identifier().MultipleTimes().AndReturn(id)
return stack return stack
@ -263,6 +268,113 @@ class WaitConditionTest(unittest.TestCase):
self.assertEqual(wc_att, u'{"123": "foo", "456": "dog"}') self.assertEqual(wc_att, u'{"123": "foo", "456": "dog"}')
self.m.VerifyAll() self.m.VerifyAll()
@stack_delete_after
def test_validate_handle_url_bad_stackid(self):
# Stub out the stack ID so we have a known value
stack_id = 'STACKABCD1234'
self.m.StubOutWithMock(uuid, 'uuid4')
uuid.uuid4().AndReturn(stack_id)
self.m.ReplayAll()
t = json.loads(test_template_waitcondition)
badhandle = ("http://127.0.0.1:8000/v1/waitcondition/" +
"arn%3Aopenstack%3Aheat%3A%3Atest_tenant" +
"%3Astacks%2Ftest_stack%2F" +
"bad1" +
"%2Fresources%2FWaitHandle")
t['Resources']['WaitForTheHandle']['Properties']['Handle'] = badhandle
self.stack = self.create_stack(template=json.dumps(t), stub=False)
self.m.ReplayAll()
resource = self.stack.resources['WaitForTheHandle']
self.assertRaises(ValueError, resource.handle_create)
self.m.VerifyAll()
@stack_delete_after
def test_validate_handle_url_bad_stackname(self):
# Stub out the stack ID so we have a known value
stack_id = 'STACKABCD1234'
self.m.StubOutWithMock(uuid, 'uuid4')
uuid.uuid4().AndReturn(stack_id)
self.m.ReplayAll()
t = json.loads(test_template_waitcondition)
badhandle = ("http://127.0.0.1:8000/v1/waitcondition/" +
"arn%3Aopenstack%3Aheat%3A%3Atest_tenant" +
"%3Astacks%2FBAD_stack%2F" +
stack_id + "%2Fresources%2FWaitHandle")
t['Resources']['WaitForTheHandle']['Properties']['Handle'] = badhandle
self.stack = self.create_stack(template=json.dumps(t), stub=False)
resource = self.stack.resources['WaitForTheHandle']
self.assertRaises(ValueError, resource.handle_create)
self.m.VerifyAll()
@stack_delete_after
def test_validate_handle_url_bad_tenant(self):
# Stub out the stack ID so we have a known value
stack_id = 'STACKABCD1234'
self.m.StubOutWithMock(uuid, 'uuid4')
uuid.uuid4().AndReturn(stack_id)
self.m.ReplayAll()
t = json.loads(test_template_waitcondition)
badhandle = ("http://127.0.0.1:8000/v1/waitcondition/" +
"arn%3Aopenstack%3Aheat%3A%3ABAD_tenant" +
"%3Astacks%2Ftest_stack%2F" +
stack_id + "%2Fresources%2FWaitHandle")
t['Resources']['WaitForTheHandle']['Properties']['Handle'] = badhandle
self.stack = self.create_stack(template=json.dumps(t), stub=False)
resource = self.stack.resources['WaitForTheHandle']
self.assertRaises(ValueError, resource.handle_create)
self.m.VerifyAll()
@stack_delete_after
def test_validate_handle_url_bad_resource(self):
# Stub out the stack ID so we have a known value
stack_id = 'STACKABCD1234'
self.m.StubOutWithMock(uuid, 'uuid4')
uuid.uuid4().AndReturn(stack_id)
self.m.ReplayAll()
t = json.loads(test_template_waitcondition)
badhandle = ("http://127.0.0.1:8000/v1/waitcondition/" +
"arn%3Aopenstack%3Aheat%3A%3Atest_tenant" +
"%3Astacks%2Ftest_stack%2F" +
stack_id + "%2Fresources%2FBADHandle")
t['Resources']['WaitForTheHandle']['Properties']['Handle'] = badhandle
self.stack = self.create_stack(template=json.dumps(t), stub=False)
resource = self.stack.resources['WaitForTheHandle']
self.assertRaises(ValueError, resource.handle_create)
self.m.VerifyAll()
@stack_delete_after
def test_validate_handle_url_bad_resource_type(self):
# Stub out the stack ID so we have a known value
stack_id = 'STACKABCD1234'
self.m.StubOutWithMock(uuid, 'uuid4')
uuid.uuid4().AndReturn(stack_id)
self.m.ReplayAll()
t = json.loads(test_template_waitcondition)
badhandle = ("http://127.0.0.1:8000/v1/waitcondition/" +
"arn%3Aopenstack%3Aheat%3A%3Atest_tenant" +
"%3Astacks%2Ftest_stack%2F" +
stack_id + "%2Fresources%2FWaitForTheHandle")
t['Resources']['WaitForTheHandle']['Properties']['Handle'] = badhandle
self.stack = self.create_stack(template=json.dumps(t), stub=False)
resource = self.stack.resources['WaitForTheHandle']
self.assertRaises(ValueError, resource.handle_create)
self.m.VerifyAll()
@attr(tag=['unit', 'resource', 'WaitConditionHandle']) @attr(tag=['unit', 'resource', 'WaitConditionHandle'])
@attr(speed='fast') @attr(speed='fast')