From: Zane Bitter Date: Mon, 12 Aug 2013 07:51:39 +0000 (+0200) Subject: RPC: Add an RPC call to get a resource type schema X-Git-Tag: 2014.1~235 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=ea83af8836a55537ef6426edae9b6aaad879772c;p=openstack-build%2Fheat-build.git RPC: Add an RPC call to get a resource type schema blueprint resource-properties-schema Change-Id: Id316393d84b6f1112b80caf14ffb98c937597f40 --- diff --git a/heat/engine/attributes.py b/heat/engine/attributes.py index c8729fca..857c79bf 100644 --- a/heat/engine/attributes.py +++ b/heat/engine/attributes.py @@ -21,6 +21,8 @@ class Attribute(object): An Attribute schema. """ + (DESCRIPTION,) = ('description',) + def __init__(self, attr_name, description): """ Initialise with a name and description. diff --git a/heat/engine/service.py b/heat/engine/service.py index 81916b94..6b6270e6 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -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. diff --git a/heat/rpc/api.py b/heat/rpc/api.py index 6144f046..21ff5ecc 100644 --- a/heat/rpc/api.py +++ b/heat/rpc/api.py @@ -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, diff --git a/heat/rpc/client.py b/heat/rpc/client.py index c0a32300..2b88eb44 100644 --- a/heat/rpc/client.py +++ b/heat/rpc/client.py @@ -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. diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index bb76568a..75865447 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -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') diff --git a/heat/tests/test_rpc_client.py b/heat/tests/test_rpc_client.py index f238e6c2..764e6f5d 100644 --- a/heat/tests/test_rpc_client.py +++ b/heat/tests/test_rpc_client.py @@ -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")