Pass and use the environment in validate_template

Use the environment passed in validate_template to be able to validate
template using custom resources.

Change-Id: I464d837c74d8be16e125d7701830d0bcbced75ab
Closes-Bug: #1298450
This commit is contained in:
Thomas Herve 2014-03-27 16:50:18 +01:00 committed by Steve Baker
parent 84d9cd083e
commit d2ab7249fc
7 changed files with 59 additions and 31 deletions

View File

@ -346,7 +346,8 @@ class StackController(object):
data = InstantiationData(body)
result = self.rpc_client.validate_template(req.context,
data.template())
data.template(),
data.environment())
if 'Error' in result:
raise exc.HTTPBadRequest(result['Error'])

View File

@ -583,13 +583,14 @@ class EngineService(service.Service):
return dict(current_stack.identifier())
@request_context
def validate_template(self, cnxt, template):
def validate_template(self, cnxt, template, params=None):
"""
The validate_template method uses the stack parser to check
the validity of a template.
:param cnxt: RPC context.
:param template: Template of stack you want to create.
:param params: Stack Input Params
"""
logger.info(_('validate_template'))
if template is None:
@ -608,6 +609,8 @@ class EngineService(service.Service):
if not tmpl_resources:
return {'Error': 'At least one Resources member must be defined.'}
env = environment.Environment(params)
for res in tmpl_resources.values():
try:
if not res.get('Type'):
@ -622,7 +625,7 @@ class EngineService(service.Service):
'Resources must contain Resource. '
'Found a [%s] instead' % type_res}
ResourceClass = resource.get_class(res['Type'])
ResourceClass = env.get_class(res['Type'])
if ResourceClass == resources.template_resource.TemplateResource:
# we can't validate a TemplateResource unless we instantiate
# it as we need to download the template and convert the

View File

@ -153,16 +153,18 @@ class EngineClient(heat.openstack.common.rpc.proxy.RpcProxy):
files=files,
args=args))
def validate_template(self, ctxt, template):
def validate_template(self, ctxt, template, params=None):
"""
The validate_template method uses the stack parser to check
the validity of a template.
:param ctxt: RPC context.
:param template: Template of stack you want to create.
:param params: Stack Input Params/Environment
"""
return self.call(ctxt, self.make_msg('validate_template',
template=template))
template=template,
params=params))
def authenticated_to_backend(self, ctxt):
"""

View File

@ -1146,7 +1146,7 @@ class CfnStackControllerTest(HeatTestCase):
rpc.call(dummy_req.context, self.topic,
{'namespace': None,
'method': 'validate_template',
'args': {'template': json_template},
'args': {'template': json_template, 'params': None},
'version': self.api_version}, None).AndReturn(response)
self.m.ReplayAll()

View File

@ -1442,7 +1442,9 @@ class StackControllerTest(ControllerTest, HeatTestCase):
rpc.call(req.context, self.topic,
{'namespace': None,
'method': 'validate_template',
'args': {'template': template},
'args': {'template': template,
'params': {'parameters': {},
'resource_registry': {}}},
'version': self.api_version},
None).AndReturn(engine_response)
self.m.ReplayAll()
@ -1464,7 +1466,9 @@ class StackControllerTest(ControllerTest, HeatTestCase):
rpc.call(req.context, self.topic,
{'namespace': None,
'method': 'validate_template',
'args': {'template': template},
'args': {'template': template,
'params': {'parameters': {},
'resource_registry': {}}},
'version': self.api_version},
None).AndReturn({'Error': 'fubar'})
self.m.ReplayAll()

View File

@ -142,7 +142,8 @@ class EngineRpcAPITestCase(testtools.TestCase):
def test_validate_template(self):
self._test_engine_api('validate_template', 'call',
template={u'Foo': u'bar'})
template={u'Foo': u'bar'},
params={u'Egg': u'spam'})
def test_list_resource_types(self):
self._test_engine_api('list_resource_types', 'call',

View File

@ -806,7 +806,24 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t))
res = dict(engine.validate_template(None, t, {}))
self.assertEqual('test.', res['Description'])
def test_validate_with_environment(self):
test_template = test_template_ref % 'WikiDatabase'
test_template = test_template.replace('AWS::EC2::Instance',
'My::Instance')
t = template_format.parse(test_template)
self.m.StubOutWithMock(instances.Instance, 'nova')
instances.Instance.nova().AndReturn(self.fc)
self.m.StubOutWithMock(service.EngineListener, 'start')
service.EngineListener.start().AndReturn(None)
self.m.ReplayAll()
engine = service.EngineService('a', 't')
params = {'resource_registry': {'My::Instance': 'AWS::EC2::Instance'}}
res = dict(engine.validate_template(None, t, params))
self.assertEqual('test.', res['Description'])
def test_validate_hot_valid(self):
@ -825,7 +842,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t))
res = dict(engine.validate_template(None, t, {}))
self.assertEqual('test.', res['Description'])
def test_validate_ref_invalid(self):
@ -838,7 +855,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t))
res = dict(engine.validate_template(None, t, {}))
self.assertNotEqual(res['Description'], 'Successfully validated')
def test_validate_findinmap_valid(self):
@ -851,7 +868,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t))
res = dict(engine.validate_template(None, t, {}))
self.assertEqual('test.', res['Description'])
def test_validate_findinmap_invalid(self):
@ -864,7 +881,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t))
res = dict(engine.validate_template(None, t, {}))
self.assertNotEqual(res['Description'], 'Successfully validated')
def test_validate_parameters(self):
@ -877,7 +894,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t))
res = dict(engine.validate_template(None, t, {}))
# Note: the assertion below does not expect a CFN dict of the parameter
# but a dict of the parameters.Schema object.
# For API CFN backward compatibility, formating to CFN is done in the
@ -899,7 +916,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t))
res = dict(engine.validate_template(None, t, {}))
parameters = res['Parameters']
expected = {'KeyName': {
@ -919,7 +936,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t))
res = dict(engine.validate_template(None, t, {}))
parameters = res['Parameters']
expected = {'KeyName': {
@ -939,7 +956,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t))
res = dict(engine.validate_template(None, t, {}))
parameters = res['Parameters']
expected = {'KeyName': {
@ -959,7 +976,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t))
res = dict(engine.validate_template(None, t, {}))
self.assertEqual({'Error': 'Unknown Property UnknownProperty'}, res)
def test_invalid_resources(self):
@ -971,7 +988,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t))
res = dict(engine.validate_template(None, t, {}))
self.assertEqual({'Error': 'Resources must contain Resource. '
'Found a [string] instead'},
res)
@ -1035,7 +1052,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t))
res = dict(engine.validate_template(None, t, {}))
self.assertEqual(
{'Error': 'Property SourceDestCheck not implemented yet'},
res)
@ -1049,7 +1066,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t))
res = dict(engine.validate_template(None, t, {}))
self.assertEqual({'Error': 'Invalid DeletionPolicy Destroy'}, res)
def test_snapshot_deletion_policy(self):
@ -1061,7 +1078,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t))
res = dict(engine.validate_template(None, t, {}))
self.assertEqual(
{'Error': 'Snapshot DeletionPolicy not supported'}, res)
@ -1076,7 +1093,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t))
res = dict(engine.validate_template(None, t, {}))
self.assertEqual({'Description': u'test.', 'Parameters': {}}, res)
def test_validate_template_without_resources(self):
@ -1089,7 +1106,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, hot_tpl))
res = dict(engine.validate_template(None, hot_tpl, {}))
self.assertEqual({'Error': 'At least one Resources member '
'must be defined.'}, res)
@ -1114,7 +1131,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, hot_tpl))
res = dict(engine.validate_template(None, hot_tpl, {}))
self.assertEqual({'Error': 'u\'"Type" is not a valid keyword '
'inside a resource definition\''}, res)
@ -1139,7 +1156,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, hot_tpl))
res = dict(engine.validate_template(None, hot_tpl, {}))
self.assertEqual({'Error': 'u\'"Properties" is not a valid keyword '
'inside a resource definition\''}, res)
@ -1164,7 +1181,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, hot_tpl))
res = dict(engine.validate_template(None, hot_tpl, {}))
self.assertEqual({'Error': 'u\'"Metadata" is not a valid keyword '
'inside a resource definition\''}, res)
@ -1189,7 +1206,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, hot_tpl))
res = dict(engine.validate_template(None, hot_tpl, {}))
self.assertEqual({'Error': 'u\'"DependsOn" is not a valid keyword '
'inside a resource definition\''}, res)
@ -1214,7 +1231,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, hot_tpl))
res = dict(engine.validate_template(None, hot_tpl, {}))
self.assertEqual({'Error': 'u\'"DeletionPolicy" is not a valid '
'keyword inside a resource definition\''},
res)
@ -1240,7 +1257,7 @@ class validateTest(HeatTestCase):
self.m.ReplayAll()
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, hot_tpl))
res = dict(engine.validate_template(None, hot_tpl, {}))
self.assertEqual({'Error': 'u\'"UpdatePolicy" is not a valid '
'keyword inside a resource definition\''},
res)