From 016133f538fd4136006e996d8a9da9130a29c85c Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Fri, 28 Jun 2013 22:27:59 +0800 Subject: [PATCH] add GET /{tenant_id}/stacks/detail to Heat API Enables the building of a useful dashboard interface for Heat stacks without looping through stacks returned from "/{tenant_id}/stacks/" to fetch the detailed data. Fixes bug #1191117 Change-Id: I06b1100873de462c69302e43259df13104cad79f --- heat/api/openstack/v1/__init__.py | 4 ++ heat/api/openstack/v1/stacks.py | 12 +++++ heat/tests/test_api_openstack_v1.py | 70 +++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/heat/api/openstack/v1/__init__.py b/heat/api/openstack/v1/__init__.py index 2f65ad81..7fdc86cc 100644 --- a/heat/api/openstack/v1/__init__.py +++ b/heat/api/openstack/v1/__init__.py @@ -62,6 +62,10 @@ class API(wsgi.Router): "/stacks", action="create", conditions={'method': 'POST'}) + stack_mapper.connect("stack_detail", + "/stacks/detail", + action="detail", + conditions={'method': 'GET'}) # Stack data stack_mapper.connect("stack_lookup", diff --git a/heat/api/openstack/v1/stacks.py b/heat/api/openstack/v1/stacks.py index 450be990..44473e13 100644 --- a/heat/api/openstack/v1/stacks.py +++ b/heat/api/openstack/v1/stacks.py @@ -205,6 +205,18 @@ class StackController(object): return {'stacks': [format_stack(req, s, summary_keys) for s in stacks]} + @util.tenant_local + def detail(self, req): + """ + Lists detailed information for all stacks + """ + try: + stacks = self.engine.list_stacks(req.context) + except rpc_common.RemoteError as ex: + return util.remote_error(ex) + + return {'stacks': [format_stack(req, s) for s in stacks]} + @util.tenant_local def create(self, req, body): """ diff --git a/heat/tests/test_api_openstack_v1.py b/heat/tests/test_api_openstack_v1.py index 7783a712..64ff6484 100644 --- a/heat/tests/test_api_openstack_v1.py +++ b/heat/tests/test_api_openstack_v1.py @@ -307,6 +307,67 @@ class StackControllerTest(ControllerTest, HeatTestCase): self.assertEqual(result, expected) self.m.VerifyAll() + def test_detail(self): + req = self._get('/stacks/detail') + + identity = identifier.HeatIdentifier(self.tenant, 'wordpress', '1') + + engine_resp = [ + { + u'stack_identity': dict(identity), + u'updated_time': u'2012-07-09T09:13:11Z', + u'template_description': u'blah', + u'description': u'blah', + u'stack_status_reason': u'Stack successfully created', + u'creation_time': u'2012-07-09T09:12:45Z', + u'stack_name': identity.stack_name, + u'stack_action': u'CREATE', + u'stack_status': u'COMPLETE', + u'parameters': {'foo': 'bar'}, + u'outputs': ['key', 'value'], + u'notification_topics': [], + u'capabilities': [], + u'disable_rollback': True, + u'timeout_mins': 60, + } + ] + self.m.StubOutWithMock(rpc, 'call') + rpc.call(req.context, self.topic, + {'namespace': None, + 'method': 'list_stacks', + 'args': {}, + 'version': self.api_version}, + None).AndReturn(engine_resp) + self.m.ReplayAll() + + result = self.controller.detail(req, tenant_id=identity.tenant) + + expected = { + 'stacks': [ + { + 'links': [{"href": self._url(identity), + "rel": "self"}], + 'id': '1', + u'updated_time': u'2012-07-09T09:13:11Z', + u'template_description': u'blah', + u'description': u'blah', + u'stack_status_reason': u'Stack successfully created', + u'creation_time': u'2012-07-09T09:12:45Z', + u'stack_name': identity.stack_name, + u'stack_status': u'CREATE_COMPLETE', + u'parameters': {'foo': 'bar'}, + u'outputs': ['key', 'value'], + u'notification_topics': [], + u'capabilities': [], + u'disable_rollback': True, + u'timeout_mins': 60, + } + ] + } + + self.assertEqual(result, expected) + self.m.VerifyAll() + def test_index_rmt_aterr(self): req = self._get('/stacks') @@ -1819,6 +1880,15 @@ class RoutesTest(HeatTestCase): { 'tenant_id': 'aaaa' }) + self.assertRoute( + self.m, + '/aaaa/stacks/detail', + 'GET', + 'detail', + 'StackController', + { + 'tenant_id': 'aaaa' + }) def test_stack_data(self): self.assertRoute( -- 2.45.2