]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
RPC: Add an RPC call to get a resource type schema
authorZane Bitter <zbitter@redhat.com>
Mon, 12 Aug 2013 07:51:39 +0000 (09:51 +0200)
committerZane Bitter <zbitter@redhat.com>
Mon, 12 Aug 2013 07:51:45 +0000 (09:51 +0200)
blueprint resource-properties-schema

Change-Id: Id316393d84b6f1112b80caf14ffb98c937597f40

heat/engine/attributes.py
heat/engine/service.py
heat/rpc/api.py
heat/rpc/client.py
heat/tests/test_engine_service.py
heat/tests/test_rpc_client.py

index c8729fcaea40dbcfe62dd58d3665bdc5fa492680..857c79bf3e40a3171adf64321efc2aa1b19de6aa 100644 (file)
@@ -21,6 +21,8 @@ class Attribute(object):
     An Attribute schema.
     """
 
+    (DESCRIPTION,) = ('description',)
+
     def __init__(self, attr_name, description):
         """
         Initialise with a name and description.
index 81916b949422baec189876df78a9bffd05de8c6a..6b6270e6c51069d353e5f11580cd5eccc8544ad4 100644 (file)
@@ -24,6 +24,7 @@ from heat.common import context
 from heat.db import api as db_api
 from heat.engine import api
 from heat.rpc import api as rpc_api
+from heat.engine import attributes
 from heat.engine import clients
 from heat.engine.event import Event
 from heat.engine import environment
@@ -405,6 +406,34 @@ class EngineService(service.Service):
         """
         return list(resource.get_types())
 
+    def resource_schema(self, cnxt, type_name):
+        """
+        Return the schema of the specified type.
+        arg1 -> RPC context.
+        arg2 -> Name of the resource type to obtain the schema of.
+        """
+        try:
+            resource_class = resource.get_class(type_name)
+        except exception.StackValidationFailed:
+            raise exception.ResourceTypeNotFound(type_name=type_name)
+
+        def properties_schema():
+            for name, schema_dict in resource_class.properties_schema.items():
+                schema = properties.Schema.from_legacy(schema_dict)
+                if schema.implemented:
+                    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}
+
+        return {
+            rpc_api.RES_SCHEMA_RES_TYPE: type_name,
+            rpc_api.RES_SCHEMA_PROPERTIES: dict(properties_schema()),
+            rpc_api.RES_SCHEMA_ATTRIBUTES: dict(attributes_schema()),
+        }
+
     def generate_template(self, cnxt, type_name):
         """
         Generate a template based on the specified type.
index 6144f046fc68d7c3814f8127f64a5129bff201e7..21ff5ecca9e61a8396b249129b61dbaae1604ead 100644 (file)
@@ -60,6 +60,12 @@ RES_KEYS = (
     'required_by',
 )
 
+RES_SCHEMA_KEYS = (
+    RES_SCHEMA_RES_TYPE, RES_SCHEMA_PROPERTIES, RES_SCHEMA_ATTRIBUTES,
+) = (
+    RES_TYPE, 'properties', 'attributes',
+)
+
 EVENT_KEYS = (
     EVENT_ID,
     EVENT_STACK_ID, EVENT_STACK_NAME,
index c0a32300b0f84ef8d6f35f911a76b16e28098d6a..2b88eb446655e4a854e7746d1b23860335b5df35 100644 (file)
@@ -160,6 +160,15 @@ class EngineClient(heat.openstack.common.rpc.proxy.RpcProxy):
         """
         return self.call(ctxt, self.make_msg('list_resource_types'))
 
+    def resource_schema(self, ctxt, type_name):
+        """
+        Get the schema for a resource type.
+
+        :param ctxt: RPC context.
+        """
+        return self.call(ctxt, self.make_msg('resource_schema',
+                                             type_name=type_name))
+
     def generate_template(self, ctxt, type_name):
         """
         Generate a template based on the specified type.
index bb76568a2dea9f21948a0aa5fd8c286ea480a482..75865447b7b0428fb252ea6312fbaa62c356a18e 100644 (file)
@@ -30,6 +30,7 @@ import heat.db.api as db_api
 from heat.common import identifier
 from heat.common import template_format
 from heat.engine import parser
+from heat.engine.resource import _register_class
 from heat.engine import service
 from heat.engine.properties import Properties
 from heat.engine.resources import instance as instances
@@ -38,6 +39,7 @@ from heat.engine import resource as rsrs
 from heat.engine import watchrule
 from heat.openstack.common import threadgroup
 from heat.tests.common import HeatTestCase
+from heat.tests import generic_resource as generic_rsrc
 from heat.tests import utils
 
 
@@ -655,6 +657,8 @@ class StackServiceTest(HeatTestCase):
                                   tenant_id='stack_service_test_tenant')
         self.eng = service.EngineService('a-host', 'a-topic')
         cfg.CONF.set_default('heat_stack_user_role', 'stack_user_role')
+        _register_class('ResourceWithPropsType',
+                        generic_rsrc.ResourceWithProps)
 
         utils.setup_dummy_db()
 
@@ -898,12 +902,35 @@ class StackServiceTest(HeatTestCase):
         self.assertNotEqual(s['description'].find('WordPress'), -1)
         self.assertTrue('parameters' in s)
 
-    @stack_context('service_list_resource_types_test_stack', False)
     def test_list_resource_types(self):
         resources = self.eng.list_resource_types(self.ctx)
         self.assertTrue(isinstance(resources, list))
         self.assertTrue('AWS::EC2::Instance' in resources)
 
+    def test_resource_schema(self):
+        type_name = 'ResourceWithPropsType'
+        expected = {
+            'resource_type': type_name,
+            'properties': {
+                'Foo': {
+                    'type': 'string',
+                    'required': False,
+                },
+            },
+            'attributes': {
+                'foo': {'description': 'A generic attribute'},
+                'Foo': {'description': 'Another generic attribute'},
+            },
+        }
+
+        schema = self.eng.resource_schema(self.ctx, type_name=type_name)
+        self.assertEqual(expected, schema)
+
+    def test_resource_schema_nonexist(self):
+        self.assertRaises(exception.ResourceTypeNotFound,
+                          self.eng.resource_schema,
+                          self.ctx, type_name='Bogus')
+
     @stack_context('service_stack_resource_describe__test_stack')
     def test_stack_resource_describe(self):
         self.m.StubOutWithMock(parser.Stack, 'load')
index f238e6c2b419f1c495e5bac88fa46b52a6d87e45..764e6f5da266a405c80ba009414232794102ed8c 100644 (file)
@@ -130,6 +130,9 @@ class EngineRpcAPITestCase(testtools.TestCase):
     def test_list_resource_types(self):
         self._test_engine_api('list_resource_types', 'call')
 
+    def test_resource_schema(self):
+        self._test_engine_api('resource_schema', 'call', type_name="TYPE")
+
     def test_generate_template(self):
         self._test_engine_api('generate_template', 'call', type_name="TYPE")