From 70a7395cb9b868ba4d8460e7d30bf3136c7cc589 Mon Sep 17 00:00:00 2001 From: Oleksii Chuprykov Date: Wed, 17 Jun 2015 09:30:00 -0400 Subject: [PATCH] Add template-version-list DOCImpact APIImpact Implements bp: template-version-list Change-Id: I827e4554b8f33c61c36d17447ca40cef8ce35680 --- etc/heat/policy.json | 1 + heat/api/openstack/v1/__init__.py | 7 +++++++ heat/api/openstack/v1/stacks.py | 10 ++++++++++ heat/engine/service.py | 15 ++++++++++++++- heat/rpc/client.py | 10 ++++++++++ heat/tests/engine/test_service_engine.py | 2 +- heat/tests/test_api_openstack_v1.py | 19 +++++++++++++++++++ heat/tests/test_engine_service.py | 24 ++++++++++++++++++++++++ 8 files changed, 86 insertions(+), 2 deletions(-) diff --git a/etc/heat/policy.json b/etc/heat/policy.json index 5964faf393..c926e2fa89 100644 --- a/etc/heat/policy.json +++ b/etc/heat/policy.json @@ -45,6 +45,7 @@ "stacks:global_index": "rule:deny_everybody", "stacks:index": "rule:deny_stack_user", "stacks:list_resource_types": "rule:deny_stack_user", + "stacks:list_template_versions": "rule:deny_stack_user", "stacks:lookup": "", "stacks:preview": "rule:deny_stack_user", "stacks:resource_schema": "rule:deny_stack_user", diff --git a/heat/api/openstack/v1/__init__.py b/heat/api/openstack/v1/__init__.py index d3f344a72f..d23870d868 100644 --- a/heat/api/openstack/v1/__init__.py +++ b/heat/api/openstack/v1/__init__.py @@ -112,6 +112,13 @@ class API(wsgi.Router): 'method': 'GET' }, + { + 'name': 'template_versions', + 'url': '/template_versions', + 'action': 'list_template_versions', + 'method': 'GET' + }, + # Stack collection { 'name': 'stack_index', diff --git a/heat/api/openstack/v1/stacks.py b/heat/api/openstack/v1/stacks.py index 020ae70092..4f60a33366 100644 --- a/heat/api/openstack/v1/stacks.py +++ b/heat/api/openstack/v1/stacks.py @@ -517,6 +517,16 @@ class StackController(object): 'resource_types': self.rpc_client.list_resource_types(req.context, support_status)} + @util.policy_enforce + def list_template_versions(self, req): + """ + Returns a list of available template versions + """ + return { + 'template_versions': + self.rpc_client.list_template_versions(req.context) + } + @util.policy_enforce def resource_schema(self, req, type_name): """ diff --git a/heat/engine/service.py b/heat/engine/service.py index 2ba6557078..a4020be039 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -40,6 +40,7 @@ from heat.common import messaging as rpc_messaging from heat.common import service_utils from heat.engine import api from heat.engine import attributes +from heat.engine.cfn import template as cfntemplate from heat.engine import clients from heat.engine import environment from heat.engine import event as evt @@ -266,7 +267,7 @@ class EngineService(service.Service): by the RPC caller. """ - RPC_API_VERSION = '1.10' + RPC_API_VERSION = '1.11' def __init__(self, host, topic, manager=None): super(EngineService, self).__init__() @@ -1023,6 +1024,18 @@ class EngineService(service.Service): """ return resources.global_env().get_types(support_status) + def list_template_versions(self, cnxt): + mgr = templatem._get_template_extension_manager() + _template_classes = [(name, mgr[name].plugin) + for name in mgr.names()] + versions = [] + for t in _template_classes: + if t[1] in [cfntemplate.CfnTemplate, cfntemplate.HeatTemplate]: + versions.append({'version': t[0], 'type': 'cfn'}) + else: + versions.append({'version': t[0], 'type': 'hot'}) + return versions + def resource_schema(self, cnxt, type_name): """ Return the schema of the specified type. diff --git a/heat/rpc/client.py b/heat/rpc/client.py index 2780e6d073..911e2dbc3b 100644 --- a/heat/rpc/client.py +++ b/heat/rpc/client.py @@ -31,6 +31,7 @@ class EngineClient(object): 1.4 - Add support for service list 1.9 - Add template_type option to generate_template() 1.10 - Add support for software config list + 1.11 - Add support for template versions list ''' BASE_RPC_API_VERSION = '1.0' @@ -327,6 +328,15 @@ class EngineClient(object): support_status=support_status), version='1.1') + def list_template_versions(self, ctxt): + """ + Get a list of available template versions + + :param ctxt: RPC context. + """ + return self.call(ctxt, self.make_msg('list_template_versions'), + version='1.11') + def resource_schema(self, ctxt, type_name): """ Get the schema for a resource type. diff --git a/heat/tests/engine/test_service_engine.py b/heat/tests/engine/test_service_engine.py index 7d4798b9c7..3854a7e9f2 100644 --- a/heat/tests/engine/test_service_engine.py +++ b/heat/tests/engine/test_service_engine.py @@ -39,7 +39,7 @@ class ServiceEngineTest(common.HeatTestCase): def test_make_sure_rpc_version(self): self.assertEqual( - '1.10', + '1.11', service.EngineService.RPC_API_VERSION, ('RPC version is changed, please update this test to new version ' 'and make sure additional test cases are added for RPC APIs ' diff --git a/heat/tests/test_api_openstack_v1.py b/heat/tests/test_api_openstack_v1.py index e582f06981..9e68b10638 100644 --- a/heat/tests/test_api_openstack_v1.py +++ b/heat/tests/test_api_openstack_v1.py @@ -2022,6 +2022,25 @@ class StackControllerTest(ControllerTest, common.HeatTestCase): self.assertEqual(403, resp.status_int) self.assertIn('403 Forbidden', six.text_type(resp)) + def test_list_template_versions(self, mock_enforce): + self._mock_enforce_setup(mock_enforce, 'list_template_versions', True) + req = self._get('/template_versions') + + engine_response = [ + {'version': 'heat_template_version.2013-05-23', 'type': 'hot'}, + {'version': 'AWSTemplateFormatVersion.2010-09-09', 'type': 'cfn'}] + + self.m.StubOutWithMock(rpc_client.EngineClient, 'call') + rpc_client.EngineClient.call( + req.context, ('list_template_versions', {}), + version="1.11" + ).AndReturn(engine_response) + self.m.ReplayAll() + response = self.controller.list_template_versions( + req, tenant_id=self.tenant) + self.assertEqual({'template_versions': engine_response}, response) + self.m.VerifyAll() + def test_resource_schema(self, mock_enforce): self._mock_enforce_setup(mock_enforce, 'resource_schema', True) req = self._get('/resource_types/ResourceWithProps') diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index 12ba38cf30..6f0118279e 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -27,8 +27,10 @@ from heat.common import exception from heat.common import identifier from heat.common import messaging from heat.common import template_format +from heat.engine.cfn import template as cfntemplate from heat.engine import dependencies from heat.engine import environment +from heat.engine.hot import template as hottemplate from heat.engine import resource as res from heat.engine.resources.aws.ec2 import instance as instances from heat.engine import service @@ -2154,6 +2156,28 @@ class StackServiceTest(common.HeatTestCase): self.assertNotIn(['OS::Neutron::RouterGateway'], resources) self.assertIn('AWS::EC2::Instance', resources) + @mock.patch('heat.engine.template._get_template_extension_manager') + def test_list_template_versions(self, templ_mock): + + class DummyMgr(object): + def names(self): + return ['a.b', 'c.d'] + + def __getitem__(self, item): + m = mock.MagicMock() + if item == 'a.b': + m.plugin = cfntemplate.CfnTemplate + return m + else: + m.plugin = hottemplate.HOTemplate20130523 + return m + + templ_mock.return_value = DummyMgr() + templates = self.eng.list_template_versions(self.ctx) + expected = [{'version': 'a.b', 'type': 'cfn'}, + {'version': 'c.d', 'type': 'hot'}] + self.assertEqual(expected, templates) + def test_resource_schema(self): type_name = 'ResourceWithPropsType' expected = {