Merge "Add resolve_outputs parameter to stacks API"
This commit is contained in:
commit
3ea35bad40
|
@ -407,9 +407,16 @@ class StackController(object):
|
|||
@util.identified_stack
|
||||
def show(self, req, identity):
|
||||
"""Gets detailed information for a stack."""
|
||||
params = req.params
|
||||
|
||||
p_name = rpc_api.RESOLVE_OUTPUTS
|
||||
if rpc_api.RESOLVE_OUTPUTS in params:
|
||||
resolve_outputs = self._extract_bool_param(
|
||||
p_name, params[p_name])
|
||||
else:
|
||||
resolve_outputs = True
|
||||
stack_list = self.rpc_client.show_stack(req.context,
|
||||
identity)
|
||||
identity, resolve_outputs)
|
||||
|
||||
if not stack_list:
|
||||
raise exc.HTTPInternalServerError()
|
||||
|
|
|
@ -204,7 +204,7 @@ def format_stack_output(stack, outputs, k, resolve_value=True):
|
|||
return result
|
||||
|
||||
|
||||
def format_stack(stack, preview=False):
|
||||
def format_stack(stack, preview=False, resolve_outputs=True):
|
||||
"""Return a representation of the given stack.
|
||||
|
||||
Return a representation of the given stack that matches the API output
|
||||
|
@ -239,7 +239,8 @@ def format_stack(stack, preview=False):
|
|||
info.update(update_info)
|
||||
|
||||
# allow users to view the outputs of stacks
|
||||
if stack.action != stack.DELETE and stack.status != stack.IN_PROGRESS:
|
||||
if (stack.action != stack.DELETE and stack.status != stack.IN_PROGRESS
|
||||
and resolve_outputs):
|
||||
info[rpc_api.STACK_OUTPUTS] = format_stack_outputs(stack,
|
||||
stack.outputs,
|
||||
resolve_value=True)
|
||||
|
|
|
@ -293,7 +293,7 @@ class EngineService(service.Service):
|
|||
by the RPC caller.
|
||||
"""
|
||||
|
||||
RPC_API_VERSION = '1.19'
|
||||
RPC_API_VERSION = '1.20'
|
||||
|
||||
def __init__(self, host, topic):
|
||||
super(EngineService, self).__init__()
|
||||
|
@ -468,20 +468,24 @@ class EngineService(service.Service):
|
|||
return s
|
||||
|
||||
@context.request_context
|
||||
def show_stack(self, cnxt, stack_identity):
|
||||
def show_stack(self, cnxt, stack_identity, resolve_outputs=True):
|
||||
"""Return detailed information about one or all stacks.
|
||||
|
||||
:param cnxt: RPC context.
|
||||
:param stack_identity: Name of the stack you want to show, or None
|
||||
to show all
|
||||
:param resolve_outputs: If True, outputs for given stack/stacks will
|
||||
be resolved
|
||||
"""
|
||||
if stack_identity is not None:
|
||||
db_stack = self._get_stack(cnxt, stack_identity, show_deleted=True)
|
||||
stacks = [parser.Stack.load(cnxt, stack=db_stack)]
|
||||
stacks = [parser.Stack.load(cnxt, stack=db_stack,
|
||||
resolve_data=resolve_outputs)]
|
||||
else:
|
||||
stacks = parser.Stack.load_all(cnxt)
|
||||
stacks = parser.Stack.load_all(cnxt, resolve_data=resolve_outputs)
|
||||
|
||||
return [api.format_stack(stack) for stack in stacks]
|
||||
return [api.format_stack(
|
||||
stack, resolve_outputs=resolve_outputs) for stack in stacks]
|
||||
|
||||
def get_revision(self, cnxt):
|
||||
return cfg.CONF.revision['heat_revision']
|
||||
|
|
|
@ -19,13 +19,15 @@ PARAM_KEYS = (
|
|||
PARAM_SHOW_DELETED, PARAM_SHOW_NESTED, PARAM_EXISTING,
|
||||
PARAM_CLEAR_PARAMETERS, PARAM_GLOBAL_TENANT, PARAM_LIMIT,
|
||||
PARAM_NESTED_DEPTH, PARAM_TAGS, PARAM_SHOW_HIDDEN, PARAM_TAGS_ANY,
|
||||
PARAM_NOT_TAGS, PARAM_NOT_TAGS_ANY, TEMPLATE_TYPE, PARAM_WITH_DETAIL
|
||||
PARAM_NOT_TAGS, PARAM_NOT_TAGS_ANY, TEMPLATE_TYPE, PARAM_WITH_DETAIL,
|
||||
RESOLVE_OUTPUTS
|
||||
) = (
|
||||
'timeout_mins', 'disable_rollback', 'adopt_stack_data',
|
||||
'show_deleted', 'show_nested', 'existing',
|
||||
'clear_parameters', 'global_tenant', 'limit',
|
||||
'nested_depth', 'tags', 'show_hidden', 'tags_any',
|
||||
'not_tags', 'not_tags_any', 'template_type', 'with_detail',
|
||||
'resolve_outputs',
|
||||
)
|
||||
|
||||
STACK_KEYS = (
|
||||
|
|
|
@ -38,6 +38,7 @@ class EngineClient(object):
|
|||
1.17 - Add files to validate_template
|
||||
1.18 - Add show_nested to validate_template
|
||||
1.19 - Add show_output and list_outputs for returning stack outputs
|
||||
1.20 - Add resolve_outputs to stack show
|
||||
"""
|
||||
|
||||
BASE_RPC_API_VERSION = '1.0'
|
||||
|
@ -172,15 +173,18 @@ class EngineClient(object):
|
|||
not_tags_any=not_tags_any),
|
||||
version='1.8')
|
||||
|
||||
def show_stack(self, ctxt, stack_identity):
|
||||
def show_stack(self, ctxt, stack_identity, resolve_outputs=True):
|
||||
"""Returns detailed information about one or all stacks.
|
||||
|
||||
:param ctxt: RPC context.
|
||||
:param stack_identity: Name of the stack you want to show, or None to
|
||||
show all
|
||||
:param resolve_outputs: If True, stack outputs will be resolved
|
||||
"""
|
||||
return self.call(ctxt, self.make_msg('show_stack',
|
||||
stack_identity=stack_identity))
|
||||
stack_identity=stack_identity,
|
||||
resolve_outputs=resolve_outputs),
|
||||
version='1.20')
|
||||
|
||||
def preview_stack(self, ctxt, stack_name, template, params, files, args):
|
||||
"""Simulates a new stack using the provided template.
|
||||
|
|
|
@ -221,7 +221,9 @@ class CfnStackControllerTest(common.HeatTestCase):
|
|||
|
||||
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
||||
rpc_client.EngineClient.call(
|
||||
dummy_req.context, ('show_stack', {'stack_identity': None})
|
||||
dummy_req.context, ('show_stack', {'stack_identity': None,
|
||||
'resolve_outputs': True}),
|
||||
version='1.20'
|
||||
).AndReturn(engine_resp)
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
@ -243,7 +245,9 @@ class CfnStackControllerTest(common.HeatTestCase):
|
|||
|
||||
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
||||
rpc_client.EngineClient.call(
|
||||
dummy_req.context, ('show_stack', {'stack_identity': None})
|
||||
dummy_req.context, ('show_stack', {'stack_identity': None,
|
||||
'resolve_outputs': True}),
|
||||
version='1.20'
|
||||
).AndReturn(engine_resp)
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
@ -298,7 +302,9 @@ class CfnStackControllerTest(common.HeatTestCase):
|
|||
).AndReturn(identity)
|
||||
rpc_client.EngineClient.call(
|
||||
dummy_req.context,
|
||||
('show_stack', {'stack_identity': identity})
|
||||
('show_stack', {'stack_identity': identity,
|
||||
'resolve_outputs': True}),
|
||||
version='1.20'
|
||||
).AndReturn(engine_resp)
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
@ -387,7 +393,9 @@ class CfnStackControllerTest(common.HeatTestCase):
|
|||
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
||||
rpc_client.EngineClient.call(
|
||||
dummy_req.context,
|
||||
('show_stack', {'stack_identity': identity})
|
||||
('show_stack', {'stack_identity': identity,
|
||||
'resolve_outputs': True}),
|
||||
version='1.20'
|
||||
).AndReturn(engine_resp)
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
@ -446,7 +454,9 @@ class CfnStackControllerTest(common.HeatTestCase):
|
|||
|
||||
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
||||
rpc_client.EngineClient.call(
|
||||
dummy_req.context, ('show_stack', {'stack_identity': identity})
|
||||
dummy_req.context, ('show_stack', {'stack_identity': identity,
|
||||
'resolve_outputs': True},),
|
||||
version='1.20'
|
||||
).AndRaise(heat_exception.InvalidTenant(target='test',
|
||||
actual='test'))
|
||||
|
||||
|
@ -469,7 +479,9 @@ class CfnStackControllerTest(common.HeatTestCase):
|
|||
dummy_req.context, ('identify_stack', {'stack_name': stack_name})
|
||||
).AndReturn(identity)
|
||||
rpc_client.EngineClient.call(
|
||||
dummy_req.context, ('show_stack', {'stack_identity': identity})
|
||||
dummy_req.context, ('show_stack', {'stack_identity': identity,
|
||||
'resolve_outputs': True}),
|
||||
version='1.20'
|
||||
).AndRaise(AttributeError())
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
|
|
@ -1399,8 +1399,8 @@ class StackControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||
def test_show(self, mock_enforce):
|
||||
self._mock_enforce_setup(mock_enforce, 'show', True)
|
||||
identity = identifier.HeatIdentifier(self.tenant, 'wordpress', '6')
|
||||
|
||||
req = self._get('/stacks/%(stack_name)s/%(stack_id)s' % identity)
|
||||
req = self._get('/stacks/%(stack_name)s/%(stack_id)s' % identity,
|
||||
params={'resolve_outputs': True})
|
||||
|
||||
parameters = {u'DBUsername': u'admin',
|
||||
u'LinuxDistribution': u'F17',
|
||||
|
@ -1433,10 +1433,11 @@ class StackControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
||||
rpc_client.EngineClient.call(
|
||||
req.context,
|
||||
('show_stack', {'stack_identity': dict(identity)})
|
||||
('show_stack', {'stack_identity': dict(identity),
|
||||
'resolve_outputs': True}),
|
||||
version='1.20'
|
||||
).AndReturn(engine_resp)
|
||||
self.m.ReplayAll()
|
||||
|
||||
response = self.controller.show(req,
|
||||
tenant_id=identity.tenant,
|
||||
stack_name=identity.stack_name,
|
||||
|
@ -1464,17 +1465,82 @@ class StackControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||
self.assertEqual(expected, response)
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_show_without_resolve_outputs(self, mock_enforce):
|
||||
self._mock_enforce_setup(mock_enforce, 'show', True)
|
||||
identity = identifier.HeatIdentifier(self.tenant, 'wordpress', '6')
|
||||
req = self._get('/stacks/%(stack_name)s/%(stack_id)s' % identity,
|
||||
params={'resolve_outputs': False})
|
||||
|
||||
parameters = {u'DBUsername': u'admin',
|
||||
u'LinuxDistribution': u'F17',
|
||||
u'InstanceType': u'm1.large',
|
||||
u'DBRootPassword': u'admin',
|
||||
u'DBPassword': u'admin',
|
||||
u'DBName': u'wordpress'}
|
||||
|
||||
engine_resp = [
|
||||
{
|
||||
u'stack_identity': dict(identity),
|
||||
u'updated_time': u'2012-07-09T09:13:11Z',
|
||||
u'parameters': parameters,
|
||||
u'stack_status_reason': u'Stack successfully created',
|
||||
u'creation_time': u'2012-07-09T09:12:45Z',
|
||||
u'stack_name': identity.stack_name,
|
||||
u'notification_topics': [],
|
||||
u'stack_action': u'CREATE',
|
||||
u'stack_status': u'COMPLETE',
|
||||
u'description': u'blah',
|
||||
u'disable_rollback': True,
|
||||
u'timeout_mins':60,
|
||||
u'capabilities': [],
|
||||
}
|
||||
]
|
||||
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
||||
rpc_client.EngineClient.call(
|
||||
req.context,
|
||||
('show_stack', {'stack_identity': dict(identity),
|
||||
'resolve_outputs': False}),
|
||||
version='1.20'
|
||||
).AndReturn(engine_resp)
|
||||
self.m.ReplayAll()
|
||||
response = self.controller.show(req,
|
||||
tenant_id=identity.tenant,
|
||||
stack_name=identity.stack_name,
|
||||
stack_id=identity.stack_id)
|
||||
|
||||
expected = {
|
||||
'stack': {
|
||||
'links': [{"href": self._url(identity),
|
||||
"rel": "self"}],
|
||||
'id': '6',
|
||||
u'updated_time': u'2012-07-09T09:13:11Z',
|
||||
u'parameters': parameters,
|
||||
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'capabilities': [],
|
||||
u'notification_topics': [],
|
||||
u'disable_rollback': True,
|
||||
u'timeout_mins': 60,
|
||||
}
|
||||
}
|
||||
self.assertEqual(expected, response)
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_show_notfound(self, mock_enforce):
|
||||
self._mock_enforce_setup(mock_enforce, 'show', True)
|
||||
identity = identifier.HeatIdentifier(self.tenant, 'wibble', '6')
|
||||
|
||||
req = self._get('/stacks/%(stack_name)s/%(stack_id)s' % identity)
|
||||
|
||||
error = heat_exc.EntityNotFound(entity='Stack', name='a')
|
||||
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
||||
rpc_client.EngineClient.call(
|
||||
req.context,
|
||||
('show_stack', {'stack_identity': dict(identity)})
|
||||
('show_stack', {'stack_identity': dict(identity),
|
||||
'resolve_outputs': True}),
|
||||
version='1.20'
|
||||
).AndRaise(tools.to_remote_error(error))
|
||||
self.m.ReplayAll()
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ class ServiceEngineTest(common.HeatTestCase):
|
|||
|
||||
def test_make_sure_rpc_version(self):
|
||||
self.assertEqual(
|
||||
'1.19',
|
||||
'1.20',
|
||||
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 '
|
||||
|
|
|
@ -390,6 +390,14 @@ class FormatTest(common.HeatTestCase):
|
|||
info = api.format_stack(self.stack)
|
||||
self.assertEqual('foobar', info[rpc_api.STACK_OUTPUTS])
|
||||
|
||||
@mock.patch.object(api, 'format_stack_outputs')
|
||||
def test_format_stack_without_resolving_outputs(self, mock_fmt_outputs):
|
||||
mock_fmt_outputs.return_value = 'foobar'
|
||||
self.stack.action = 'CREATE'
|
||||
self.stack.status = 'COMPLETE'
|
||||
info = api.format_stack(self.stack, resolve_outputs=False)
|
||||
self.assertIsNone(info.get(rpc_api.STACK_OUTPUTS))
|
||||
|
||||
def test_format_stack_outputs(self):
|
||||
tmpl = template.Template({
|
||||
'HeatTemplateFormatVersion': '2012-12-12',
|
||||
|
|
|
@ -858,7 +858,8 @@ class StackServiceTest(common.HeatTestCase):
|
|||
self.eng.abandon_stack(self.ctx, self.stack.identifier())
|
||||
ex = self.assertRaises(dispatcher.ExpectedException,
|
||||
self.eng.show_stack,
|
||||
self.ctx, self.stack.identifier())
|
||||
self.ctx, self.stack.identifier(),
|
||||
resolve_outputs=True)
|
||||
self.assertEqual(exception.EntityNotFound, ex.exc_info[0])
|
||||
self.m.VerifyAll()
|
||||
|
||||
|
@ -877,7 +878,8 @@ class StackServiceTest(common.HeatTestCase):
|
|||
|
||||
ex = self.assertRaises(dispatcher.ExpectedException,
|
||||
self.eng.show_stack,
|
||||
self.ctx, non_exist_identifier)
|
||||
self.ctx, non_exist_identifier,
|
||||
resolve_outputs=True)
|
||||
self.assertEqual(exception.EntityNotFound, ex.exc_info[0])
|
||||
self.m.VerifyAll()
|
||||
|
||||
|
@ -896,7 +898,8 @@ class StackServiceTest(common.HeatTestCase):
|
|||
|
||||
ex = self.assertRaises(dispatcher.ExpectedException,
|
||||
self.eng.show_stack,
|
||||
self.ctx, non_exist_identifier)
|
||||
self.ctx, non_exist_identifier,
|
||||
resolve_outputs=True)
|
||||
self.assertEqual(exception.InvalidTenant, ex.exc_info[0])
|
||||
|
||||
self.m.VerifyAll()
|
||||
|
@ -910,7 +913,8 @@ class StackServiceTest(common.HeatTestCase):
|
|||
show_deleted=True).AndReturn(s)
|
||||
self.m.ReplayAll()
|
||||
|
||||
sl = self.eng.show_stack(self.ctx, self.stack.identifier())
|
||||
sl = self.eng.show_stack(self.ctx, self.stack.identifier(),
|
||||
resolve_outputs=True)
|
||||
|
||||
self.assertEqual(1, len(sl))
|
||||
|
||||
|
@ -931,7 +935,7 @@ class StackServiceTest(common.HeatTestCase):
|
|||
|
||||
@tools.stack_context('service_describe_all_test_stack', False)
|
||||
def test_stack_describe_all(self):
|
||||
sl = self.eng.show_stack(self.ctx, None)
|
||||
sl = self.eng.show_stack(self.ctx, None, resolve_outputs=True)
|
||||
|
||||
self.assertEqual(1, len(sl))
|
||||
|
||||
|
@ -1103,7 +1107,7 @@ class StackServiceTest(common.HeatTestCase):
|
|||
self.assertEqual(0, len(sl))
|
||||
|
||||
def test_stack_describe_all_empty(self):
|
||||
sl = self.eng.show_stack(self.ctx, None)
|
||||
sl = self.eng.show_stack(self.ctx, None, resolve_outputs=True)
|
||||
|
||||
self.assertEqual(0, len(sl))
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ class EngineRpcAPITestCase(common.HeatTestCase):
|
|||
expected_retval = 'foo' if method == 'call' else None
|
||||
|
||||
kwargs.pop('version', None)
|
||||
|
||||
if 'expected_message' in kwargs:
|
||||
expected_message = kwargs['expected_message']
|
||||
del kwargs['expected_message']
|
||||
|
@ -141,7 +140,8 @@ class EngineRpcAPITestCase(common.HeatTestCase):
|
|||
stack_name='wordpress')
|
||||
|
||||
def test_show_stack(self):
|
||||
self._test_engine_api('show_stack', 'call', stack_identity='wordpress')
|
||||
self._test_engine_api('show_stack', 'call', stack_identity='wordpress',
|
||||
resolve_outputs=True)
|
||||
|
||||
def test_preview_stack(self):
|
||||
self._test_engine_api('preview_stack', 'call', stack_name='wordpress',
|
||||
|
|
Loading…
Reference in New Issue