From: Andrew Plunk Date: Fri, 12 Jul 2013 14:56:07 +0000 (-0500) Subject: Add rest endpoints for resource template generation. X-Git-Tag: 2014.1~310^2 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=48fe2f04baba57c0e6856c30f050eb83cacc6f2b;p=openstack-build%2Fheat-build.git Add rest endpoints for resource template generation. Add api endpoints for generating a template based on a resource implementation. blueprint resource-template Change-Id: Iebebad70befd1df6cd8989538cbb61350a17bc23 --- diff --git a/heat/api/aws/exception.py b/heat/api/aws/exception.py index c1090770..a0207b67 100644 --- a/heat/api/aws/exception.py +++ b/heat/api/aws/exception.py @@ -259,6 +259,7 @@ def map_remote_error(ex): 'StackNotFound', 'ResourceNotFound', 'ResourceNotAvailable', + 'ResourceTypeNotFound', 'PhysicalResourceNotFound', 'WatchRuleNotFound', 'StackValidationFailed', diff --git a/heat/api/middleware/fault.py b/heat/api/middleware/fault.py index 370fe495..9df7ae60 100644 --- a/heat/api/middleware/fault.py +++ b/heat/api/middleware/fault.py @@ -57,6 +57,7 @@ class FaultWrapper(wsgi.Middleware): 'ValueError': webob.exc.HTTPBadRequest, 'StackNotFound': webob.exc.HTTPNotFound, 'ResourceNotFound': webob.exc.HTTPNotFound, + 'ResourceTypeNotFound': webob.exc.HTTPNotFound, 'ResourceNotAvailable': webob.exc.HTTPNotFound, 'PhysicalResourceNotFound': webob.exc.HTTPNotFound, 'InvalidTenant': webob.exc.HTTPForbidden, diff --git a/heat/api/openstack/v1/__init__.py b/heat/api/openstack/v1/__init__.py index b0898f1f..a1ab038f 100644 --- a/heat/api/openstack/v1/__init__.py +++ b/heat/api/openstack/v1/__init__.py @@ -53,6 +53,10 @@ class API(wsgi.Router): "/resource_types", action="list_resource_types", conditions={'method': 'GET'}) + stack_mapper.connect("generate_template", + "/resource_types/{type_name}/template", + action="generate_template", + conditions={'method': 'GET'}) # Stack collection stack_mapper.connect("stack_index", diff --git a/heat/api/openstack/v1/stacks.py b/heat/api/openstack/v1/stacks.py index d7bb53d3..617f25a3 100644 --- a/heat/api/openstack/v1/stacks.py +++ b/heat/api/openstack/v1/stacks.py @@ -329,10 +329,14 @@ class StackController(object): """ Returns a list of valid resource types that may be used in a template. """ + return {'resource_types': self.engine.list_resource_types(req.context)} - types = self.engine.list_resource_types(req.context) - - return {'resource_types': types} + @util.tenant_local + def generate_template(self, req, type_name): + """ + Generates a template based on the specified type. + """ + return self.engine.generate_template(req.context, type_name) class StackSerializer(wsgi.JSONResponseSerializer): diff --git a/heat/common/exception.py b/heat/common/exception.py index 0fc68e9a..eb236a5a 100644 --- a/heat/common/exception.py +++ b/heat/common/exception.py @@ -248,6 +248,10 @@ class ResourceNotFound(OpenstackException): "in Stack %(stack_name)s.") +class ResourceTypeNotFound(OpenstackException): + message = _("The Resource Type (%(type_name)s) could not be found.") + + class ResourceNotAvailable(OpenstackException): message = _("The Resource (%(resource_name)s) is not available.") diff --git a/heat/engine/service.py b/heat/engine/service.py index d91423ad..add8e1a8 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -383,6 +383,18 @@ class EngineService(service.Service): """ return list(resource.get_types()) + def generate_template(self, cnxt, type_name): + """ + Generate a template based on the specified type. + arg1 -> RPC context. + arg2 -> Name of the resource type to generate a template for. + """ + try: + return \ + resource.get_class(type_name).resource_to_template(type_name) + except exception.StackValidationFailed: + raise exception.ResourceTypeNotFound(type_name=type_name) + @request_context def list_events(self, cnxt, stack_identity): """ diff --git a/heat/rpc/client.py b/heat/rpc/client.py index dba3c4ff..c0a32300 100644 --- a/heat/rpc/client.py +++ b/heat/rpc/client.py @@ -160,6 +160,16 @@ class EngineClient(heat.openstack.common.rpc.proxy.RpcProxy): """ return self.call(ctxt, self.make_msg('list_resource_types')) + def generate_template(self, ctxt, type_name): + """ + Generate a template based on the specified type. + + :param ctxt: RPC context. + :param type_name: The resource type name to generate a template for. + """ + return self.call(ctxt, self.make_msg('generate_template', + type_name=type_name)) + def list_events(self, ctxt, stack_identity): """ The list_events method lists all events associated with a given stack. diff --git a/heat/tests/test_api_openstack_v1.py b/heat/tests/test_api_openstack_v1.py index ce38c4eb..db0275a2 100644 --- a/heat/tests/test_api_openstack_v1.py +++ b/heat/tests/test_api_openstack_v1.py @@ -1138,6 +1138,42 @@ class StackControllerTest(ControllerTest, HeatTestCase): self.assertEqual(resp.json['error']['type'], 'ServerError') self.m.VerifyAll() + def test_generate_template(self): + + req = self._get('/resource_types/TEST_TYPE/template') + + engine_response = {'Type': 'TEST_TYPE'} + + self.m.StubOutWithMock(rpc, 'call') + rpc.call(req.context, self.topic, + {'namespace': None, + 'method': 'generate_template', + 'args': {'type_name': 'TEST_TYPE'}, + 'version': self.api_version}, + None).AndReturn(engine_response) + self.m.ReplayAll() + self.controller.generate_template(req, tenant_id=self.tenant, + type_name='TEST_TYPE') + self.m.VerifyAll() + + def test_generate_template_not_found(self): + req = self._get('/resource_types/NOT_FOUND/template') + self.m.StubOutWithMock(rpc, 'call') + rpc.call(req.context, self.topic, + {'namespace': None, + 'method': 'generate_template', + 'args': {'type_name': 'NOT_FOUND'}, + 'version': self.api_version}, + None).AndRaise(remote_error(heat_exc.ResourceTypeNotFound)) + self.m.ReplayAll() + resp = request_with_middleware(fault.FaultWrapper, + self.controller.generate_template, + req, tenant_id=self.tenant, + type_name='NOT_FOUND') + self.assertEqual(resp.json['code'], 404) + self.assertEqual(resp.json['error']['type'], 'ResourceTypeNotFound') + self.m.VerifyAll() + class StackSerializerTest(HeatTestCase): @@ -1953,8 +1989,20 @@ class RoutesTest(HeatTestCase): 'list_resource_types', 'StackController', { - 'tenant_id': 'aaaa' + 'tenant_id': 'aaaa', + }) + + self.assertRoute( + self.m, + '/aaaa/resource_types/test_type/template', + 'GET', + 'generate_template', + 'StackController', + { + 'tenant_id': 'aaaa', + 'type_name': 'test_type' }) + self.assertRoute( self.m, '/aaaa/validate', diff --git a/heat/tests/test_rpc_client.py b/heat/tests/test_rpc_client.py index 3b25f7fb..93a1bbe3 100644 --- a/heat/tests/test_rpc_client.py +++ b/heat/tests/test_rpc_client.py @@ -139,6 +139,9 @@ class EngineRpcAPITestCase(testtools.TestCase): self._test_engine_api('list_stack_resources', 'call', stack_identity=self.identity) + def test_generate_template(self): + self._test_engine_api('generate_template', 'call', type_name="TYPE") + def test_stack_suspend(self): self._test_engine_api('stack_suspend', 'call', stack_identity=self.identity)