RPC: Add an RPC call to get a resource type schema

blueprint resource-properties-schema

Change-Id: Id316393d84b6f1112b80caf14ffb98c937597f40
This commit is contained in:
Zane Bitter 2013-08-12 09:51:39 +02:00
parent 5f301b87db
commit ea83af8836
6 changed files with 77 additions and 1 deletions

View 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.

View 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.

View 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,

View 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.

View 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')

View 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")