Add link to a resource's nested stack
When viewing a resource, it's valuable to know whether the resource is a nested stack with additional resources attached to it. This change provides a new 'nested' link in the links section of a resource, which points to the nested stack. Co-Authored-By: Richard Lee <rblee88@gmail.com> Implements: blueprint nested-stack-link Change-Id: Ibc8768d2be8f1dae9a60d3818ae9f56c27bbdc9b
This commit is contained in:
parent
e4577e01a8
commit
8844d4413a
@ -30,11 +30,19 @@ def format_resource(req, res, keys=[]):
|
||||
|
||||
if key == engine_api.RES_ID:
|
||||
identity = identifier.ResourceIdentifier(**value)
|
||||
yield ('links', [util.make_link(req, identity),
|
||||
util.make_link(req, identity.stack(), 'stack')])
|
||||
links = [util.make_link(req, identity),
|
||||
util.make_link(req, identity.stack(), 'stack')]
|
||||
|
||||
nested_id = res.get(engine_api.RES_NESTED_STACK_ID)
|
||||
if nested_id:
|
||||
nested_identity = identifier.HeatIdentifier(**nested_id)
|
||||
links.append(util.make_link(req, nested_identity, 'nested'))
|
||||
|
||||
yield ('links', links)
|
||||
elif (key == engine_api.RES_STACK_NAME or
|
||||
key == engine_api.RES_STACK_ID or
|
||||
key == engine_api.RES_ACTION):
|
||||
key == engine_api.RES_ACTION or
|
||||
key == engine_api.RES_NESTED_STACK_ID):
|
||||
return
|
||||
elif (key == engine_api.RES_METADATA):
|
||||
return
|
||||
|
@ -130,6 +130,9 @@ def format_stack_resource(resource, detail=True):
|
||||
api.RES_REQUIRED_BY: resource.required_by(),
|
||||
}
|
||||
|
||||
if hasattr(resource, 'nested') and callable(resource.nested):
|
||||
res[api.RES_NESTED_STACK_ID] = dict(resource.nested().identifier())
|
||||
|
||||
if detail:
|
||||
res[api.RES_DESCRIPTION] = resource.parsed_template('Description', '')
|
||||
res[api.RES_METADATA] = resource.metadata
|
||||
|
@ -50,13 +50,13 @@ RES_KEYS = (
|
||||
RES_NAME, RES_PHYSICAL_ID, RES_METADATA,
|
||||
RES_ACTION, RES_STATUS, RES_STATUS_DATA,
|
||||
RES_TYPE, RES_ID, RES_STACK_ID, RES_STACK_NAME,
|
||||
RES_REQUIRED_BY,
|
||||
RES_REQUIRED_BY, RES_NESTED_STACK_ID,
|
||||
) = (
|
||||
'description', 'updated_time',
|
||||
'resource_name', 'physical_resource_id', 'metadata',
|
||||
'resource_action', 'resource_status', 'resource_status_reason',
|
||||
'resource_type', 'resource_identity', STACK_ID, STACK_NAME,
|
||||
'required_by',
|
||||
'required_by', 'nested_stack_id',
|
||||
)
|
||||
|
||||
RES_SCHEMA_KEYS = (
|
||||
|
@ -1851,6 +1851,58 @@ class ResourceControllerTest(ControllerTest, HeatTestCase):
|
||||
self.assertEqual(expected, result)
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_show_with_nested_stack(self, mock_enforce):
|
||||
self._mock_enforce_setup(mock_enforce, 'show', True)
|
||||
res_name = 'WikiDatabase'
|
||||
stack_identity = identifier.HeatIdentifier(self.tenant,
|
||||
'wordpress', '6')
|
||||
res_identity = identifier.ResourceIdentifier(resource_name=res_name,
|
||||
**stack_identity)
|
||||
nested_stack_identity = identifier.HeatIdentifier(self.tenant,
|
||||
'nested', 'some_id')
|
||||
|
||||
req = self._get(stack_identity._tenant_path())
|
||||
|
||||
engine_resp = {
|
||||
u'description': u'',
|
||||
u'resource_identity': dict(res_identity),
|
||||
u'stack_name': stack_identity.stack_name,
|
||||
u'resource_name': res_name,
|
||||
u'resource_status_reason': None,
|
||||
u'updated_time': u'2012-07-23T13:06:00Z',
|
||||
u'stack_identity': dict(stack_identity),
|
||||
u'resource_action': u'CREATE',
|
||||
u'resource_status': u'COMPLETE',
|
||||
u'physical_resource_id':
|
||||
u'a3455d8c-9f88-404d-a85b-5315293e67de',
|
||||
u'resource_type': u'AWS::EC2::Instance',
|
||||
u'metadata': {u'ensureRunning': u'true'},
|
||||
u'nested_stack_id': dict(nested_stack_identity)
|
||||
}
|
||||
self.m.StubOutWithMock(rpc, 'call')
|
||||
rpc.call(req.context, self.topic,
|
||||
{'namespace': None,
|
||||
'method': 'describe_stack_resource',
|
||||
'args': {'stack_identity': stack_identity,
|
||||
'resource_name': res_name},
|
||||
'version': self.api_version},
|
||||
None).AndReturn(engine_resp)
|
||||
self.m.ReplayAll()
|
||||
|
||||
result = self.controller.show(req, tenant_id=self.tenant,
|
||||
stack_name=stack_identity.stack_name,
|
||||
stack_id=stack_identity.stack_id,
|
||||
resource_name=res_name)
|
||||
|
||||
expected = [{'href': self._url(res_identity), 'rel': 'self'},
|
||||
{'href': self._url(stack_identity), 'rel': 'stack'},
|
||||
{'href': self._url(nested_stack_identity), 'rel': 'nested'}
|
||||
]
|
||||
|
||||
self.assertEqual(expected, result['resource']['links'])
|
||||
self.assertIsNone(result.get(rpc_api.RES_NESTED_STACK_ID))
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_show_nonexist(self, mock_enforce):
|
||||
self._mock_enforce_setup(mock_enforce, 'show', True)
|
||||
res_name = 'WikiDatabase'
|
||||
|
@ -159,6 +159,15 @@ class FormatTest(HeatTestCase):
|
||||
formatted = api.format_stack_resource(res, False)
|
||||
self.assertEqual(resource_keys, set(formatted.keys()))
|
||||
|
||||
def test_format_stack_resource_with_nested_stack(self):
|
||||
res = self.stack['generic1']
|
||||
nested_id = {'foo': 'bar'}
|
||||
res.nested = mock.Mock()
|
||||
res.nested.return_value.identifier.return_value = nested_id
|
||||
|
||||
formatted = api.format_stack_resource(res, False)
|
||||
self.assertEqual(nested_id, formatted[rpc_api.RES_NESTED_STACK_ID])
|
||||
|
||||
def test_format_stack_resource_required_by(self):
|
||||
res1 = api.format_stack_resource(self.stack['generic1'])
|
||||
res2 = api.format_stack_resource(self.stack['generic2'])
|
||||
|
Loading…
Reference in New Issue
Block a user