from requests import exceptions
+from heat.common import exception
from heat.common import template_format
from heat.common import urlfetch
from heat.engine import attributes
registry_type=environment.TemplateResourceInfo)
self.template_name = tri.template_name
- cri = stack.env.get_resource_info(
- json_snippet['Type'],
- registry_type=environment.ClassResourceInfo)
-
- # if we're not overriding via the environment, mirror the template as
- # a new resource
- if cri is None or cri.get_class() == self.__class__:
- tmpl = template.Template(self.parsed_nested)
- self.properties_schema = (properties.Properties
- .schema_from_params(tmpl.param_schemata()))
- self.attributes_schema = (attributes.Attributes
- .schema_from_outputs(tmpl[template.OUTPUTS]))
- # otherwise we are overriding a resource type via the environment
- # and should mimic that type
- else:
- cls_facade = cri.get_class()
- self.properties_schema = cls_facade.properties_schema
- self.attributes_schema = cls_facade.attributes_schema
+ tmpl = template.Template(self.parsed_nested)
+ self.properties_schema = (properties.Properties
+ .schema_from_params(tmpl.param_schemata()))
+ self.attributes_schema = (attributes.Attributes
+ .schema_from_outputs(tmpl[template.OUTPUTS]))
super(TemplateResource, self).__init__(name, json_snippet, stack)
self.stack.t.files[self.template_name] = t_data
return t_data
+ def validate(self):
+ cri = self.stack.env.get_resource_info(
+ self.type(),
+ registry_type=environment.ClassResourceInfo)
+
+ # If we're using an existing resource type as a facade for this
+ # template, check for compatibility between the interfaces.
+ if cri is not None and not isinstance(self, cri.get_class()):
+ facade_cls = cri.get_class()
+ facade_schemata = properties.schemata(facade_cls.properties_schema)
+
+ for n, fs in facade_schemata.items():
+ if fs.required and n not in self.properties_schema:
+ msg = ("Required property %s for facade %s "
+ "missing in provider") % (n, self.type())
+ raise exception.StackValidationFailed(message=msg)
+
+ ps = self.properties_schema.get(n)
+ if (n in self.properties_schema and
+ (fs.type != ps.type)):
+ # Type mismatch
+ msg = ("Property %s type mismatch between facade %s (%s) "
+ "and provider (%s)") % (n, self.type(),
+ fs.type, ps.type)
+ raise exception.StackValidationFailed(message=msg)
+
+ for n, ps in self.properties_schema.items():
+ if ps.required and n not in facade_schemata:
+ # Required property for template not present in facade
+ msg = ("Provider requires property %s "
+ "unknown in facade %s") % (n, self.type())
+ raise exception.StackValidationFailed(message=msg)
+
+ for attr in facade_cls.attributes_schema:
+ if attr not in self.attributes_schema:
+ msg = ("Attribute %s for facade %s "
+ "missing in provider") % (attr, self.type())
+ raise exception.StackValidationFailed(message=msg)
+
+ return super(TemplateResource, self).validate()
+
def handle_create(self):
return self.create_with_template(self.parsed_nested,
self._to_parameters())
# under the License.
import os
+import json
+from heat.common import exception
from heat.common import urlfetch
from heat.common import template_format
from heat.engine import environment
from heat.engine import parser
+from heat.engine import properties
from heat.engine import resource
from heat.engine.resources import template_resource
def test_to_parameters(self):
"""Tests property conversion to parameter values."""
- utils.setup_dummy_db()
+ provider = {
+ 'Parameters': {
+ 'Foo': {'Type': 'String'},
+ 'AList': {'Type': 'CommaDelimitedList'},
+ 'ANum': {'Type': 'Number'},
+ 'AMap': {'Type': 'Json'},
+ },
+ 'Outputs': {
+ 'Foo': {'Value': 'bar'},
+ },
+ }
+
+ files = {'test_resource.template': json.dumps(provider)}
class DummyResource(object):
attributes_schema = {"Foo": "A test attribute"}
env.load({'resource_registry':
{'DummyResource': 'test_resource.template'}})
stack = parser.Stack(utils.dummy_context(), 'test_stack',
- parser.Template({}), env=env,
+ parser.Template({}, files=files), env=env,
stack_id=uuidutils.generate_uuid())
map_prop_val = {
"AMap": map_prop_val
}
}
- self.m.ReplayAll()
temp_res = template_resource.TemplateResource('test_t_res',
json_snippet, stack)
- self.m.VerifyAll()
+ temp_res.validate()
converted_params = temp_res._to_parameters()
self.assertTrue(converted_params)
for key in DummyResource.properties_schema:
# verify Map conversion
self.assertEqual(map_prop_val, converted_params.get("AMap"))
+ def test_attributes_extra(self):
+ provider = {
+ 'Outputs': {
+ 'Foo': {'Value': 'bar'},
+ 'Blarg': {'Value': 'wibble'},
+ },
+ }
+ files = {'test_resource.template': json.dumps(provider)}
+
+ class DummyResource(object):
+ properties_schema = {}
+ attributes_schema = {"Foo": "A test attribute"}
+
+ env = environment.Environment()
+ resource._register_class('DummyResource', DummyResource)
+ env.load({'resource_registry':
+ {'DummyResource': 'test_resource.template'}})
+ stack = parser.Stack(utils.dummy_context(), 'test_stack',
+ parser.Template({}, files=files), env=env,
+ stack_id=uuidutils.generate_uuid())
+
+ json_snippet = {
+ "Type": "DummyResource",
+ }
+
+ temp_res = template_resource.TemplateResource('test_t_res',
+ json_snippet, stack)
+ self.assertEqual(None, temp_res.validate())
+
+ def test_attributes_missing(self):
+ provider = {
+ 'Outputs': {
+ 'Blarg': {'Value': 'wibble'},
+ },
+ }
+ files = {'test_resource.template': json.dumps(provider)}
+
+ class DummyResource(object):
+ properties_schema = {}
+ attributes_schema = {"Foo": "A test attribute"}
+
+ json_snippet = {
+ "Type": "DummyResource",
+ }
+
+ env = environment.Environment()
+ resource._register_class('DummyResource', DummyResource)
+ env.load({'resource_registry':
+ {'DummyResource': 'test_resource.template'}})
+ stack = parser.Stack(utils.dummy_context(), 'test_stack',
+ parser.Template({}, files=files), env=env,
+ stack_id=uuidutils.generate_uuid())
+
+ temp_res = template_resource.TemplateResource('test_t_res',
+ json_snippet, stack)
+ self.assertRaises(exception.StackValidationFailed,
+ temp_res.validate)
+
+ def test_properties_normal(self):
+ provider = {
+ 'Parameters': {
+ 'Foo': {'Type': 'String'},
+ 'Blarg': {'Type': 'String', 'Default': 'wibble'},
+ },
+ }
+ files = {'test_resource.template': json.dumps(provider)}
+
+ class DummyResource(object):
+ properties_schema = {"Foo": properties.Schema(properties.STRING,
+ required=True)}
+ attributes_schema = {}
+
+ json_snippet = {
+ "Type": "DummyResource",
+ "Properties": {
+ "Foo": "bar",
+ },
+ }
+
+ env = environment.Environment()
+ resource._register_class('DummyResource', DummyResource)
+ env.load({'resource_registry':
+ {'DummyResource': 'test_resource.template'}})
+ stack = parser.Stack(utils.dummy_context(), 'test_stack',
+ parser.Template({}, files=files), env=env,
+ stack_id=uuidutils.generate_uuid())
+
+ temp_res = template_resource.TemplateResource('test_t_res',
+ json_snippet, stack)
+ self.assertEqual(None, temp_res.validate())
+
+ def test_properties_missing(self):
+ provider = {
+ 'Parameters': {
+ 'Blarg': {'Type': 'String', 'Default': 'wibble'},
+ },
+ }
+ files = {'test_resource.template': json.dumps(provider)}
+
+ class DummyResource(object):
+ properties_schema = {"Foo": properties.Schema(properties.STRING,
+ required=True)}
+ attributes_schema = {}
+
+ json_snippet = {
+ "Type": "DummyResource",
+ }
+
+ env = environment.Environment()
+ resource._register_class('DummyResource', DummyResource)
+ env.load({'resource_registry':
+ {'DummyResource': 'test_resource.template'}})
+ stack = parser.Stack(utils.dummy_context(), 'test_stack',
+ parser.Template({}, files=files), env=env,
+ stack_id=uuidutils.generate_uuid())
+
+ temp_res = template_resource.TemplateResource('test_t_res',
+ json_snippet, stack)
+ self.assertRaises(exception.StackValidationFailed,
+ temp_res.validate)
+
+ def test_properties_extra_required(self):
+ provider = {
+ 'Parameters': {
+ 'Blarg': {'Type': 'String'},
+ },
+ }
+ files = {'test_resource.template': json.dumps(provider)}
+
+ class DummyResource(object):
+ properties_schema = {}
+ attributes_schema = {}
+
+ json_snippet = {
+ "Type": "DummyResource",
+ "Properties": {
+ "Blarg": "wibble",
+ },
+ }
+
+ env = environment.Environment()
+ resource._register_class('DummyResource', DummyResource)
+ env.load({'resource_registry':
+ {'DummyResource': 'test_resource.template'}})
+ stack = parser.Stack(utils.dummy_context(), 'test_stack',
+ parser.Template({}, files=files), env=env,
+ stack_id=uuidutils.generate_uuid())
+
+ temp_res = template_resource.TemplateResource('test_t_res',
+ json_snippet, stack)
+ self.assertRaises(exception.StackValidationFailed,
+ temp_res.validate)
+
+ def test_properties_type_mismatch(self):
+ provider = {
+ 'Parameters': {
+ 'Foo': {'Type': 'String'},
+ },
+ }
+ files = {'test_resource.template': json.dumps(provider)}
+
+ class DummyResource(object):
+ properties_schema = {"Foo": properties.Schema(properties.MAP)}
+ attributes_schema = {}
+
+ json_snippet = {
+ "Type": "DummyResource",
+ "Properties": {
+ "Foo": "bar",
+ },
+ }
+
+ env = environment.Environment()
+ resource._register_class('DummyResource', DummyResource)
+ env.load({'resource_registry':
+ {'DummyResource': 'test_resource.template'}})
+ stack = parser.Stack(utils.dummy_context(), 'test_stack',
+ parser.Template({}, files=files), env=env,
+ stack_id=uuidutils.generate_uuid())
+
+ temp_res = template_resource.TemplateResource('test_t_res',
+ json_snippet, stack)
+ self.assertRaises(exception.StackValidationFailed,
+ temp_res.validate)
+
def test_get_template_resource(self):
# assertion: if the name matches {.yaml|.template} we get the
# TemplateResource class.