From fdc702bc7870dc1e7438f124e2c077ea53f89bc7 Mon Sep 17 00:00:00 2001 From: Sergey Kraynev Date: Thu, 10 Apr 2014 04:33:25 -0400 Subject: [PATCH] Adding attribute schema class for attributes This patch introduces simple schema class for attributes. There are two options avaliable for this schema: - description - support status It gives ability for adding support status for each attribute. Change-Id: I46cbf776f315cbe6414005cbee65da1cefdc5f7d Closes-Bug: #1305584 --- heat/engine/attributes.py | 61 +++++++++++++++++++++++++++++++---- heat/engine/service.py | 6 ++-- heat/tests/test_attributes.py | 51 +++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 9 deletions(-) diff --git a/heat/engine/attributes.py b/heat/engine/attributes.py index 4418c8cafc..c7c440c5d3 100644 --- a/heat/engine/attributes.py +++ b/heat/engine/attributes.py @@ -13,23 +13,72 @@ import collections +from heat.engine import constraints as constr +from heat.engine import support + + +class Schema(constr.Schema): + """ + Simple schema class for attributes. + + Schema objects are serialisable to dictionaries following a superset of + the HOT input Parameter schema using dict(). + """ + + KEYS = ( + DESCRIPTION, + ) = ( + 'description', + ) + + def __init__(self, description=None, + support_status=support.SupportStatus()): + self.description = description + self.support_status = support_status + + def __getitem__(self, key): + if key == self.DESCRIPTION: + if self.description is not None: + return self.description + + raise KeyError(key) + + @classmethod + def from_attribute(cls, schema_dict): + """ + Return a Property Schema corresponding to a Attribute Schema. + """ + if isinstance(schema_dict, cls): + return schema_dict + # it's necessary for supporting old attribute schema format, + # where value is not Schema object + return cls(description=schema_dict) + + +def schemata(schema): + """ + Return dictionary of Schema objects for given dictionary of schemata. + """ + return dict((n, Schema.from_attribute(s)) for n, s in schema.items()) + class Attribute(object): """ An Attribute schema. """ - (DESCRIPTION,) = ('description',) - - def __init__(self, attr_name, description): + def __init__(self, attr_name, schema): """ Initialise with a name and description. :param attr_name: the name of the attribute - :param description: attribute description + :param schema: attribute schema """ self.name = attr_name - self.description = description + self.schema = Schema.from_attribute(schema) + + def support_status(self): + return self.schema.support_status def as_output(self, resource_name): """ @@ -42,7 +91,7 @@ class Attribute(object): return { "Value": '{"Fn::GetAtt": ["%s", "%s"]}' % (resource_name, self.name), - "Description": self.description + "Description": self.schema.description } diff --git a/heat/engine/service.py b/heat/engine/service.py index e6d80ef9e9..5289dfbefd 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -787,9 +787,9 @@ class EngineService(service.Service): yield name, dict(schema) def attributes_schema(): - for schema_item in resource_class.attributes_schema.items(): - schema = attributes.Attribute(*schema_item) - yield schema.name, {schema.DESCRIPTION: schema.description} + for name, schema_data in resource_class.attributes_schema.items(): + schema = attributes.Schema.from_attribute(schema_data) + yield name, {schema.DESCRIPTION: schema.description} return { rpc_api.RES_SCHEMA_RES_TYPE: type_name, diff --git a/heat/tests/test_attributes.py b/heat/tests/test_attributes.py index 0f929cd83c..451ae8c99b 100644 --- a/heat/tests/test_attributes.py +++ b/heat/tests/test_attributes.py @@ -11,10 +11,61 @@ # License for the specific language governing permissions and limitations # under the License. +import testtools + from heat.engine import attributes +from heat.engine import resources +from heat.engine import support from heat.tests import common +class AttributeSchemaTest(testtools.TestCase): + def test_schema_all(self): + d = {'description': 'A attribute'} + s = attributes.Schema('A attribute') + self.assertEqual(d, dict(s)) + + def test_all_resource_schemata(self): + for resource_type in resources.global_env().get_types(): + for schema in getattr(resource_type, + 'attributes_schema', + {}).itervalues(): + attributes.Schema.from_attribute(schema) + + def test_from_attribute_new_schema_format(self): + s = attributes.Schema('Test description.') + self.assertIs(s, attributes.Schema.from_attribute(s)) + self.assertEqual('Test description.', + attributes.Schema.from_attribute(s).description) + + def test_schema_support_status(self): + schema = { + 'foo_sup': attributes.Schema( + 'Description1' + ), + 'bar_dep': attributes.Schema( + 'Description2', + support_status=support.SupportStatus( + support.DEPRECATED, + 'Do not use this ever') + ) + } + attrs = attributes.Attributes('test_rsrc', schema, lambda d: d) + self.assertEqual(support.SUPPORTED, + attrs._attributes['foo_sup'].support_status().status) + self.assertEqual(support.DEPRECATED, + attrs._attributes['bar_dep'].support_status().status) + self.assertEqual('Do not use this ever', + attrs._attributes['bar_dep'].support_status().message) + + def test_from_attribute_old_schema_format(self): + s = 'Test description.' + self.assertEqual(type(attributes.Schema(s)), + type(attributes.Schema.from_attribute(s))) + self.assertEqual('Test description.', + attributes.Schema.from_attribute(s).description) + + class AttributeTest(common.HeatTestCase): """Test the Attribute class."""