Implement event list nested-depth
The GET call to list events will support a nested_depth parameter. The response will have an additional links url with the ref 'root_stack' to indicate that this API supports nested_depth queries. This has the following consequences for old/new combinations of client/server - new heatclient, new server - nested_depth param is set, server returns nested events - new heatclient, old server - nested_depth param is set, server returns events with no root_stack, heatclient falls back to recursive event fetch - old heatclient, new server - nested_depth param is never set, recursive event fetch works as before Here are some timings for a TripleO overcloud stack with ~700 events. Current heat and python-heatclient master: time openstack stack event list --nested-depth 4 overcloud |wc -l 744 real 0m17.500s This change, with heatclient 31278ff5f77b152b5ef7a4197e15c441c72ff163: time openstack stack event list --nested-depth 4 overcloud |wc -l 608 real 0m1.725s The difference in event count (744 vs 608) is due to the stack events being filtered out for stacks with zero resources - these are a source of unnecessary noise so their removal should be considered an improvement. Closes-Bug: #1588561 Change-Id: I27e1ffb770e00a7f929c081b2a505e2007f5d584
This commit is contained in:
parent
2a04ea4bb5
commit
32ade7a243
@ -69,9 +69,15 @@ def format_event(req, event, keys=None):
|
|||||||
else:
|
else:
|
||||||
yield (key, value)
|
yield (key, value)
|
||||||
|
|
||||||
return dict(itertools.chain.from_iterable(
|
ev = dict(itertools.chain.from_iterable(
|
||||||
transform(k, v) for k, v in event.items()))
|
transform(k, v) for k, v in event.items()))
|
||||||
|
|
||||||
|
root_stack_id = event.get(rpc_api.EVENT_ROOT_STACK_ID)
|
||||||
|
if root_stack_id:
|
||||||
|
root_identifier = identifier.HeatIdentifier(**root_stack_id)
|
||||||
|
ev['links'].append(util.make_link(req, root_identifier, 'root_stack'))
|
||||||
|
return ev
|
||||||
|
|
||||||
|
|
||||||
class EventController(object):
|
class EventController(object):
|
||||||
"""WSGI controller for Events in Heat v1 API.
|
"""WSGI controller for Events in Heat v1 API.
|
||||||
@ -86,14 +92,16 @@ class EventController(object):
|
|||||||
self.rpc_client = rpc_client.EngineClient()
|
self.rpc_client = rpc_client.EngineClient()
|
||||||
|
|
||||||
def _event_list(self, req, identity, detail=False, filters=None,
|
def _event_list(self, req, identity, detail=False, filters=None,
|
||||||
limit=None, marker=None, sort_keys=None, sort_dir=None):
|
limit=None, marker=None, sort_keys=None, sort_dir=None,
|
||||||
|
nested_depth=None):
|
||||||
events = self.rpc_client.list_events(req.context,
|
events = self.rpc_client.list_events(req.context,
|
||||||
identity,
|
identity,
|
||||||
filters=filters,
|
filters=filters,
|
||||||
limit=limit,
|
limit=limit,
|
||||||
marker=marker,
|
marker=marker,
|
||||||
sort_keys=sort_keys,
|
sort_keys=sort_keys,
|
||||||
sort_dir=sort_dir)
|
sort_dir=sort_dir,
|
||||||
|
nested_depth=nested_depth)
|
||||||
keys = None if detail else summary_keys
|
keys = None if detail else summary_keys
|
||||||
|
|
||||||
return [format_event(req, e, keys) for e in events]
|
return [format_event(req, e, keys) for e in events]
|
||||||
@ -106,6 +114,7 @@ class EventController(object):
|
|||||||
'marker': util.PARAM_TYPE_SINGLE,
|
'marker': util.PARAM_TYPE_SINGLE,
|
||||||
'sort_dir': util.PARAM_TYPE_SINGLE,
|
'sort_dir': util.PARAM_TYPE_SINGLE,
|
||||||
'sort_keys': util.PARAM_TYPE_MULTI,
|
'sort_keys': util.PARAM_TYPE_MULTI,
|
||||||
|
'nested_depth': util.PARAM_TYPE_SINGLE,
|
||||||
}
|
}
|
||||||
filter_whitelist = {
|
filter_whitelist = {
|
||||||
'resource_status': util.PARAM_TYPE_MIXED,
|
'resource_status': util.PARAM_TYPE_MIXED,
|
||||||
@ -115,14 +124,15 @@ class EventController(object):
|
|||||||
}
|
}
|
||||||
params = util.get_allowed_params(req.params, whitelist)
|
params = util.get_allowed_params(req.params, whitelist)
|
||||||
filter_params = util.get_allowed_params(req.params, filter_whitelist)
|
filter_params = util.get_allowed_params(req.params, filter_whitelist)
|
||||||
key = rpc_api.PARAM_LIMIT
|
|
||||||
if key in params:
|
int_params = (rpc_api.PARAM_LIMIT, rpc_api.PARAM_NESTED_DEPTH)
|
||||||
try:
|
try:
|
||||||
limit = param_utils.extract_int(key, params[key],
|
for key in int_params:
|
||||||
allow_zero=True)
|
if key in params:
|
||||||
except ValueError as e:
|
params[key] = param_utils.extract_int(
|
||||||
raise exc.HTTPBadRequest(six.text_type(e))
|
key, params[key], allow_zero=True)
|
||||||
params[key] = limit
|
except ValueError as e:
|
||||||
|
raise exc.HTTPBadRequest(six.text_type(e))
|
||||||
|
|
||||||
if resource_name is None:
|
if resource_name is None:
|
||||||
if not filter_params:
|
if not filter_params:
|
||||||
|
@ -379,7 +379,7 @@ def format_stack_preview(stack):
|
|||||||
return fmt_stack
|
return fmt_stack
|
||||||
|
|
||||||
|
|
||||||
def format_event(event, stack_identifier):
|
def format_event(event, stack_identifier, root_stack_identifier=None):
|
||||||
result = {
|
result = {
|
||||||
rpc_api.EVENT_ID: dict(event.identifier(stack_identifier)),
|
rpc_api.EVENT_ID: dict(event.identifier(stack_identifier)),
|
||||||
rpc_api.EVENT_STACK_ID: dict(stack_identifier),
|
rpc_api.EVENT_STACK_ID: dict(stack_identifier),
|
||||||
@ -393,6 +393,8 @@ def format_event(event, stack_identifier):
|
|||||||
rpc_api.EVENT_RES_TYPE: event.resource_type,
|
rpc_api.EVENT_RES_TYPE: event.resource_type,
|
||||||
rpc_api.EVENT_RES_PROPERTIES: event.resource_properties,
|
rpc_api.EVENT_RES_PROPERTIES: event.resource_properties,
|
||||||
}
|
}
|
||||||
|
if root_stack_identifier:
|
||||||
|
result[rpc_api.EVENT_ROOT_STACK_ID] = dict(root_stack_identifier)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -297,7 +297,7 @@ class EngineService(service.Service):
|
|||||||
by the RPC caller.
|
by the RPC caller.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RPC_API_VERSION = '1.30'
|
RPC_API_VERSION = '1.31'
|
||||||
|
|
||||||
def __init__(self, host, topic):
|
def __init__(self, host, topic):
|
||||||
super(EngineService, self).__init__()
|
super(EngineService, self).__init__()
|
||||||
@ -1575,7 +1575,8 @@ class EngineService(service.Service):
|
|||||||
|
|
||||||
@context.request_context
|
@context.request_context
|
||||||
def list_events(self, cnxt, stack_identity, filters=None, limit=None,
|
def list_events(self, cnxt, stack_identity, filters=None, limit=None,
|
||||||
marker=None, sort_keys=None, sort_dir=None):
|
marker=None, sort_keys=None, sort_dir=None,
|
||||||
|
nested_depth=None):
|
||||||
"""Lists all events associated with a given stack.
|
"""Lists all events associated with a given stack.
|
||||||
|
|
||||||
It supports pagination (``limit`` and ``marker``),
|
It supports pagination (``limit`` and ``marker``),
|
||||||
@ -1589,21 +1590,52 @@ class EngineService(service.Service):
|
|||||||
:param marker: the ID of the last event in the previous page
|
:param marker: the ID of the last event in the previous page
|
||||||
:param sort_keys: an array of fields used to sort the list
|
:param sort_keys: an array of fields used to sort the list
|
||||||
:param sort_dir: the direction of the sort ('asc' or 'desc').
|
:param sort_dir: the direction of the sort ('asc' or 'desc').
|
||||||
|
:param nested_depth: Levels of nested stacks to list events for.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
stack_identifiers = None
|
stack_identifiers = None
|
||||||
if stack_identity is not None:
|
root_stack_identifier = None
|
||||||
|
if stack_identity:
|
||||||
st = self._get_stack(cnxt, stack_identity, show_deleted=True)
|
st = self._get_stack(cnxt, stack_identity, show_deleted=True)
|
||||||
|
|
||||||
events = list(event_object.Event.get_all_by_stack(
|
if nested_depth:
|
||||||
cnxt,
|
root_stack_identifier = st.identifier()
|
||||||
st.id,
|
# find all resources associated with a root stack
|
||||||
limit=limit,
|
all_r = resource_objects.Resource.get_all_by_root_stack(
|
||||||
marker=marker,
|
cnxt, st.id, None)
|
||||||
sort_keys=sort_keys,
|
|
||||||
sort_dir=sort_dir,
|
# find stacks to the requested nested_depth
|
||||||
filters=filters))
|
stack_ids = {r.stack_id for r in six.itervalues(all_r)}
|
||||||
stack_identifiers = {st.id: st.identifier()}
|
stack_filters = {
|
||||||
|
'id': stack_ids,
|
||||||
|
'nested_depth': list(range(nested_depth + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
stacks = stack_object.Stack.get_all(cnxt,
|
||||||
|
filters=stack_filters,
|
||||||
|
show_nested=True)
|
||||||
|
stack_identifiers = {s.id: s.identifier() for s in stacks}
|
||||||
|
|
||||||
|
if filters is None:
|
||||||
|
filters = {}
|
||||||
|
filters['stack_id'] = list(stack_identifiers.keys())
|
||||||
|
events = list(event_object.Event.get_all_by_tenant(
|
||||||
|
cnxt, limit=limit,
|
||||||
|
marker=marker,
|
||||||
|
sort_keys=sort_keys,
|
||||||
|
sort_dir=sort_dir,
|
||||||
|
filters=filters))
|
||||||
|
|
||||||
|
else:
|
||||||
|
events = list(event_object.Event.get_all_by_stack(
|
||||||
|
cnxt,
|
||||||
|
st.id,
|
||||||
|
limit=limit,
|
||||||
|
marker=marker,
|
||||||
|
sort_keys=sort_keys,
|
||||||
|
sort_dir=sort_dir,
|
||||||
|
filters=filters))
|
||||||
|
stack_identifiers = {st.id: st.identifier()}
|
||||||
else:
|
else:
|
||||||
events = list(event_object.Event.get_all_by_tenant(
|
events = list(event_object.Event.get_all_by_tenant(
|
||||||
cnxt, limit=limit,
|
cnxt, limit=limit,
|
||||||
@ -1618,8 +1650,8 @@ class EngineService(service.Service):
|
|||||||
show_nested=True)
|
show_nested=True)
|
||||||
stack_identifiers = {s.id: s.identifier() for s in stacks}
|
stack_identifiers = {s.id: s.identifier() for s in stacks}
|
||||||
|
|
||||||
return [api.format_event(e, stack_identifiers.get(e.stack_id))
|
return [api.format_event(e, stack_identifiers.get(e.stack_id),
|
||||||
for e in events]
|
root_stack_identifier) for e in events]
|
||||||
|
|
||||||
def _authorize_stack_user(self, cnxt, stack, resource_name):
|
def _authorize_stack_user(self, cnxt, stack, resource_name):
|
||||||
"""Filter access to describe_stack_resource for in-instance users.
|
"""Filter access to describe_stack_resource for in-instance users.
|
||||||
|
@ -89,14 +89,14 @@ EVENT_KEYS = (
|
|||||||
EVENT_TIMESTAMP,
|
EVENT_TIMESTAMP,
|
||||||
EVENT_RES_NAME, EVENT_RES_PHYSICAL_ID, EVENT_RES_ACTION,
|
EVENT_RES_NAME, EVENT_RES_PHYSICAL_ID, EVENT_RES_ACTION,
|
||||||
EVENT_RES_STATUS, EVENT_RES_STATUS_DATA, EVENT_RES_TYPE,
|
EVENT_RES_STATUS, EVENT_RES_STATUS_DATA, EVENT_RES_TYPE,
|
||||||
EVENT_RES_PROPERTIES,
|
EVENT_RES_PROPERTIES, EVENT_ROOT_STACK_ID
|
||||||
) = (
|
) = (
|
||||||
'event_identity',
|
'event_identity',
|
||||||
STACK_ID, STACK_NAME,
|
STACK_ID, STACK_NAME,
|
||||||
'event_time',
|
'event_time',
|
||||||
RES_NAME, RES_PHYSICAL_ID, RES_ACTION,
|
RES_NAME, RES_PHYSICAL_ID, RES_ACTION,
|
||||||
RES_STATUS, RES_STATUS_DATA, RES_TYPE,
|
RES_STATUS, RES_STATUS_DATA, RES_TYPE,
|
||||||
'resource_properties',
|
'resource_properties', 'root_stack_id'
|
||||||
)
|
)
|
||||||
|
|
||||||
NOTIFY_KEYS = (
|
NOTIFY_KEYS = (
|
||||||
|
@ -51,6 +51,8 @@ class EngineClient(object):
|
|||||||
1.28 - Add environment_show call
|
1.28 - Add environment_show call
|
||||||
1.29 - Add template_id to create_stack/update_stack
|
1.29 - Add template_id to create_stack/update_stack
|
||||||
1.30 - Add possibility to resource_type_* return descriptions
|
1.30 - Add possibility to resource_type_* return descriptions
|
||||||
|
1.31 - Add nested_depth to list_events, when nested_depth is specified
|
||||||
|
add root_stack_id to response
|
||||||
"""
|
"""
|
||||||
|
|
||||||
BASE_RPC_API_VERSION = '1.0'
|
BASE_RPC_API_VERSION = '1.0'
|
||||||
@ -494,7 +496,8 @@ class EngineClient(object):
|
|||||||
version='1.9')
|
version='1.9')
|
||||||
|
|
||||||
def list_events(self, ctxt, stack_identity, filters=None, limit=None,
|
def list_events(self, ctxt, stack_identity, filters=None, limit=None,
|
||||||
marker=None, sort_keys=None, sort_dir=None,):
|
marker=None, sort_keys=None, sort_dir=None,
|
||||||
|
nested_depth=None):
|
||||||
"""Lists all events associated with a given stack.
|
"""Lists all events associated with a given stack.
|
||||||
|
|
||||||
It supports pagination (``limit`` and ``marker``),
|
It supports pagination (``limit`` and ``marker``),
|
||||||
@ -508,6 +511,7 @@ class EngineClient(object):
|
|||||||
:param marker: the ID of the last event in the previous page
|
:param marker: the ID of the last event in the previous page
|
||||||
:param sort_keys: an array of fields used to sort the list
|
:param sort_keys: an array of fields used to sort the list
|
||||||
:param sort_dir: the direction of the sort ('asc' or 'desc').
|
:param sort_dir: the direction of the sort ('asc' or 'desc').
|
||||||
|
:param nested_depth: Levels of nested stacks to list events for.
|
||||||
"""
|
"""
|
||||||
return self.call(ctxt, self.make_msg('list_events',
|
return self.call(ctxt, self.make_msg('list_events',
|
||||||
stack_identity=stack_identity,
|
stack_identity=stack_identity,
|
||||||
@ -515,7 +519,9 @@ class EngineClient(object):
|
|||||||
limit=limit,
|
limit=limit,
|
||||||
marker=marker,
|
marker=marker,
|
||||||
sort_keys=sort_keys,
|
sort_keys=sort_keys,
|
||||||
sort_dir=sort_dir))
|
sort_dir=sort_dir,
|
||||||
|
nested_depth=nested_depth),
|
||||||
|
version='1.31')
|
||||||
|
|
||||||
def describe_stack_resource(self, ctxt, stack_identity, resource_name,
|
def describe_stack_resource(self, ctxt, stack_identity, resource_name,
|
||||||
with_attr=False):
|
with_attr=False):
|
||||||
|
@ -1216,7 +1216,7 @@ class CfnStackControllerTest(common.HeatTestCase):
|
|||||||
u'resource_properties': {u'UserData': u'blah'},
|
u'resource_properties': {u'UserData': u'blah'},
|
||||||
u'resource_type': u'AWS::EC2::Instance'}]
|
u'resource_type': u'AWS::EC2::Instance'}]
|
||||||
|
|
||||||
kwargs = {'stack_identity': identity,
|
kwargs = {'stack_identity': identity, 'nested_depth': None,
|
||||||
'limit': None, 'sort_keys': None, 'marker': None,
|
'limit': None, 'sort_keys': None, 'marker': None,
|
||||||
'sort_dir': None, 'filters': None}
|
'sort_dir': None, 'filters': None}
|
||||||
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
||||||
@ -1224,7 +1224,9 @@ class CfnStackControllerTest(common.HeatTestCase):
|
|||||||
dummy_req.context, ('identify_stack', {'stack_name': stack_name})
|
dummy_req.context, ('identify_stack', {'stack_name': stack_name})
|
||||||
).AndReturn(identity)
|
).AndReturn(identity)
|
||||||
rpc_client.EngineClient.call(
|
rpc_client.EngineClient.call(
|
||||||
dummy_req.context, ('list_events', kwargs)
|
dummy_req.context,
|
||||||
|
('list_events', kwargs),
|
||||||
|
version='1.31'
|
||||||
).AndReturn(engine_resp)
|
).AndReturn(engine_resp)
|
||||||
|
|
||||||
self.m.ReplayAll()
|
self.m.ReplayAll()
|
||||||
@ -1262,7 +1264,9 @@ class CfnStackControllerTest(common.HeatTestCase):
|
|||||||
dummy_req.context, ('identify_stack', {'stack_name': stack_name})
|
dummy_req.context, ('identify_stack', {'stack_name': stack_name})
|
||||||
).AndReturn(identity)
|
).AndReturn(identity)
|
||||||
rpc_client.EngineClient.call(
|
rpc_client.EngineClient.call(
|
||||||
dummy_req.context, ('list_events', {'stack_identity': identity})
|
dummy_req.context,
|
||||||
|
('list_events', {'stack_identity': identity}),
|
||||||
|
version='1.31'
|
||||||
).AndRaise(Exception())
|
).AndRaise(Exception())
|
||||||
|
|
||||||
self.m.ReplayAll()
|
self.m.ReplayAll()
|
||||||
|
@ -50,9 +50,16 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
self._test_resource_index('a3455d8c-9f88-404d-a85b-5315293e67de',
|
self._test_resource_index('a3455d8c-9f88-404d-a85b-5315293e67de',
|
||||||
mock_enforce)
|
mock_enforce)
|
||||||
|
|
||||||
def _test_resource_index(self, event_id, mock_enforce):
|
def test_resource_index_nested_depth(self, mock_enforce):
|
||||||
|
self._test_resource_index('a3455d8c-9f88-404d-a85b-5315293e67de',
|
||||||
|
mock_enforce, nested_depth=1)
|
||||||
|
|
||||||
|
def _test_resource_index(self, event_id, mock_enforce, nested_depth=None):
|
||||||
self._mock_enforce_setup(mock_enforce, 'index', True)
|
self._mock_enforce_setup(mock_enforce, 'index', True)
|
||||||
res_name = 'WikiDatabase'
|
res_name = 'WikiDatabase'
|
||||||
|
params = {}
|
||||||
|
if nested_depth:
|
||||||
|
params['nested_depth'] = nested_depth
|
||||||
stack_identity = identifier.HeatIdentifier(self.tenant,
|
stack_identity = identifier.HeatIdentifier(self.tenant,
|
||||||
'wordpress', '6')
|
'wordpress', '6')
|
||||||
res_identity = identifier.ResourceIdentifier(resource_name=res_name,
|
res_identity = identifier.ResourceIdentifier(resource_name=res_name,
|
||||||
@ -61,9 +68,11 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
**res_identity)
|
**res_identity)
|
||||||
|
|
||||||
req = self._get(stack_identity._tenant_path() +
|
req = self._get(stack_identity._tenant_path() +
|
||||||
'/resources/' + res_name + '/events')
|
'/resources/' + res_name + '/events',
|
||||||
|
params=params)
|
||||||
|
|
||||||
kwargs = {'stack_identity': stack_identity,
|
kwargs = {'stack_identity': stack_identity,
|
||||||
|
'nested_depth': nested_depth,
|
||||||
'limit': None, 'sort_keys': None, 'marker': None,
|
'limit': None, 'sort_keys': None, 'marker': None,
|
||||||
'sort_dir': None, 'filters': {'resource_name': res_name}}
|
'sort_dir': None, 'filters': {'resource_name': res_name}}
|
||||||
|
|
||||||
@ -82,9 +91,14 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
u'resource_type': u'AWS::EC2::Instance',
|
u'resource_type': u'AWS::EC2::Instance',
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
if nested_depth:
|
||||||
|
engine_resp[0]['root_stack_id'] = dict(stack_identity)
|
||||||
|
|
||||||
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
||||||
rpc_client.EngineClient.call(
|
rpc_client.EngineClient.call(
|
||||||
req.context, ('list_events', kwargs)
|
req.context,
|
||||||
|
('list_events', kwargs),
|
||||||
|
version='1.31'
|
||||||
).AndReturn(engine_resp)
|
).AndReturn(engine_resp)
|
||||||
self.m.ReplayAll()
|
self.m.ReplayAll()
|
||||||
|
|
||||||
@ -111,6 +125,10 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
if nested_depth:
|
||||||
|
expected['events'][0]['links'].append(
|
||||||
|
{'href': self._url(stack_identity), 'rel': 'root_stack'}
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEqual(expected, result)
|
self.assertEqual(expected, result)
|
||||||
self.m.VerifyAll()
|
self.m.VerifyAll()
|
||||||
@ -155,7 +173,7 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
|
|
||||||
rpc_call_args, _ = mock_call.call_args
|
rpc_call_args, _ = mock_call.call_args
|
||||||
engine_args = rpc_call_args[1][1]
|
engine_args = rpc_call_args[1][1]
|
||||||
self.assertEqual(6, len(engine_args))
|
self.assertEqual(7, len(engine_args))
|
||||||
self.assertIn('filters', engine_args)
|
self.assertIn('filters', engine_args)
|
||||||
self.assertIn('resource_name', engine_args['filters'])
|
self.assertIn('resource_name', engine_args['filters'])
|
||||||
self.assertEqual(res_name, engine_args['filters']['resource_name'])
|
self.assertEqual(res_name, engine_args['filters']['resource_name'])
|
||||||
@ -202,7 +220,7 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
|
|
||||||
rpc_call_args, _ = mock_call.call_args
|
rpc_call_args, _ = mock_call.call_args
|
||||||
engine_args = rpc_call_args[1][1]
|
engine_args = rpc_call_args[1][1]
|
||||||
self.assertEqual(6, len(engine_args))
|
self.assertEqual(7, len(engine_args))
|
||||||
self.assertIn('filters', engine_args)
|
self.assertIn('filters', engine_args)
|
||||||
self.assertIn('resource_name', engine_args['filters'])
|
self.assertIn('resource_name', engine_args['filters'])
|
||||||
self.assertIn('resource1', engine_args['filters']['resource_name'])
|
self.assertIn('resource1', engine_args['filters']['resource_name'])
|
||||||
@ -227,7 +245,7 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
|
|
||||||
req = self._get(stack_identity._tenant_path() + '/events')
|
req = self._get(stack_identity._tenant_path() + '/events')
|
||||||
|
|
||||||
kwargs = {'stack_identity': stack_identity,
|
kwargs = {'stack_identity': stack_identity, 'nested_depth': None,
|
||||||
'limit': None, 'sort_keys': None, 'marker': None,
|
'limit': None, 'sort_keys': None, 'marker': None,
|
||||||
'sort_dir': None, 'filters': {'resource_name': res_name}}
|
'sort_dir': None, 'filters': {'resource_name': res_name}}
|
||||||
|
|
||||||
@ -249,7 +267,8 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
||||||
rpc_client.EngineClient.call(
|
rpc_client.EngineClient.call(
|
||||||
req.context,
|
req.context,
|
||||||
('list_events', kwargs)
|
('list_events', kwargs),
|
||||||
|
version='1.31'
|
||||||
).AndReturn(engine_resp)
|
).AndReturn(engine_resp)
|
||||||
self.m.ReplayAll()
|
self.m.ReplayAll()
|
||||||
|
|
||||||
@ -287,7 +306,7 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
|
|
||||||
req = self._get(stack_identity._tenant_path() + '/events')
|
req = self._get(stack_identity._tenant_path() + '/events')
|
||||||
|
|
||||||
kwargs = {'stack_identity': stack_identity,
|
kwargs = {'stack_identity': stack_identity, 'nested_depth': None,
|
||||||
'limit': None, 'sort_keys': None, 'marker': None,
|
'limit': None, 'sort_keys': None, 'marker': None,
|
||||||
'sort_dir': None, 'filters': None}
|
'sort_dir': None, 'filters': None}
|
||||||
|
|
||||||
@ -295,7 +314,8 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
||||||
rpc_client.EngineClient.call(
|
rpc_client.EngineClient.call(
|
||||||
req.context,
|
req.context,
|
||||||
('list_events', kwargs)
|
('list_events', kwargs),
|
||||||
|
version='1.31'
|
||||||
).AndRaise(tools.to_remote_error(error))
|
).AndRaise(tools.to_remote_error(error))
|
||||||
self.m.ReplayAll()
|
self.m.ReplayAll()
|
||||||
|
|
||||||
@ -336,7 +356,7 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
req = self._get(stack_identity._tenant_path() +
|
req = self._get(stack_identity._tenant_path() +
|
||||||
'/resources/' + res_name + '/events')
|
'/resources/' + res_name + '/events')
|
||||||
|
|
||||||
kwargs = {'stack_identity': stack_identity,
|
kwargs = {'stack_identity': stack_identity, 'nested_depth': None,
|
||||||
'limit': None, 'sort_keys': None, 'marker': None,
|
'limit': None, 'sort_keys': None, 'marker': None,
|
||||||
'sort_dir': None, 'filters': {'resource_name': res_name}}
|
'sort_dir': None, 'filters': {'resource_name': res_name}}
|
||||||
|
|
||||||
@ -344,7 +364,8 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
||||||
rpc_client.EngineClient.call(
|
rpc_client.EngineClient.call(
|
||||||
req.context,
|
req.context,
|
||||||
('list_events', kwargs)
|
('list_events', kwargs),
|
||||||
|
version='1.31'
|
||||||
).AndReturn(engine_resp)
|
).AndReturn(engine_resp)
|
||||||
self.m.ReplayAll()
|
self.m.ReplayAll()
|
||||||
|
|
||||||
@ -380,7 +401,7 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
|
|
||||||
rpc_call_args, _ = mock_call.call_args
|
rpc_call_args, _ = mock_call.call_args
|
||||||
engine_args = rpc_call_args[1][1]
|
engine_args = rpc_call_args[1][1]
|
||||||
self.assertEqual(6, len(engine_args))
|
self.assertEqual(7, len(engine_args))
|
||||||
self.assertIn('limit', engine_args)
|
self.assertIn('limit', engine_args)
|
||||||
self.assertEqual(10, engine_args['limit'])
|
self.assertEqual(10, engine_args['limit'])
|
||||||
self.assertIn('sort_keys', engine_args)
|
self.assertIn('sort_keys', engine_args)
|
||||||
@ -469,7 +490,7 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
|
|
||||||
kwargs = {'stack_identity': stack_identity,
|
kwargs = {'stack_identity': stack_identity,
|
||||||
'limit': None, 'sort_keys': None, 'marker': None,
|
'limit': None, 'sort_keys': None, 'marker': None,
|
||||||
'sort_dir': None,
|
'sort_dir': None, 'nested_depth': None,
|
||||||
'filters': {'resource_name': res_name, 'uuid': event_id}}
|
'filters': {'resource_name': res_name, 'uuid': event_id}}
|
||||||
|
|
||||||
engine_resp = [
|
engine_resp = [
|
||||||
@ -491,7 +512,8 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
||||||
rpc_client.EngineClient.call(
|
rpc_client.EngineClient.call(
|
||||||
req.context,
|
req.context,
|
||||||
('list_events', kwargs)
|
('list_events', kwargs),
|
||||||
|
version='1.31'
|
||||||
).AndReturn(engine_resp)
|
).AndReturn(engine_resp)
|
||||||
self.m.ReplayAll()
|
self.m.ReplayAll()
|
||||||
|
|
||||||
@ -536,13 +558,16 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
|
|
||||||
kwargs = {'stack_identity': stack_identity,
|
kwargs = {'stack_identity': stack_identity,
|
||||||
'limit': None, 'sort_keys': None, 'marker': None,
|
'limit': None, 'sort_keys': None, 'marker': None,
|
||||||
'sort_dir': None,
|
'sort_dir': None, 'nested_depth': None,
|
||||||
'filters': {'resource_name': res_name, 'uuid': '42'}}
|
'filters': {'resource_name': res_name, 'uuid': '42'}}
|
||||||
|
|
||||||
engine_resp = []
|
engine_resp = []
|
||||||
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
||||||
rpc_client.EngineClient.call(
|
rpc_client.EngineClient.call(
|
||||||
req.context, ('list_events', kwargs)).AndReturn(engine_resp)
|
req.context,
|
||||||
|
('list_events', kwargs),
|
||||||
|
version='1.31'
|
||||||
|
).AndReturn(engine_resp)
|
||||||
self.m.ReplayAll()
|
self.m.ReplayAll()
|
||||||
|
|
||||||
self.assertRaises(webob.exc.HTTPNotFound,
|
self.assertRaises(webob.exc.HTTPNotFound,
|
||||||
@ -565,13 +590,15 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
|
|
||||||
kwargs = {'stack_identity': stack_identity,
|
kwargs = {'stack_identity': stack_identity,
|
||||||
'limit': None, 'sort_keys': None, 'marker': None,
|
'limit': None, 'sort_keys': None, 'marker': None,
|
||||||
'sort_dir': None,
|
'sort_dir': None, 'nested_depth': None,
|
||||||
'filters': {'resource_name': res_name, 'uuid': '42'}}
|
'filters': {'resource_name': res_name, 'uuid': '42'}}
|
||||||
|
|
||||||
error = heat_exc.EntityNotFound(entity='Stack', name='a')
|
error = heat_exc.EntityNotFound(entity='Stack', name='a')
|
||||||
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
self.m.StubOutWithMock(rpc_client.EngineClient, 'call')
|
||||||
rpc_client.EngineClient.call(
|
rpc_client.EngineClient.call(
|
||||||
req.context, ('list_events', kwargs)
|
req.context,
|
||||||
|
('list_events', kwargs),
|
||||||
|
version='1.31'
|
||||||
).AndRaise(tools.to_remote_error(error))
|
).AndRaise(tools.to_remote_error(error))
|
||||||
self.m.ReplayAll()
|
self.m.ReplayAll()
|
||||||
|
|
||||||
@ -647,7 +674,7 @@ class EventControllerTest(tools.ControllerTest, common.HeatTestCase):
|
|||||||
|
|
||||||
rpc_call_args, _ = mock_call.call_args
|
rpc_call_args, _ = mock_call.call_args
|
||||||
engine_args = rpc_call_args[1][1]
|
engine_args = rpc_call_args[1][1]
|
||||||
self.assertEqual(6, len(engine_args))
|
self.assertEqual(7, len(engine_args))
|
||||||
self.assertIn('filters', engine_args)
|
self.assertIn('filters', engine_args)
|
||||||
self.assertIn('resource_name', engine_args['filters'])
|
self.assertIn('resource_name', engine_args['filters'])
|
||||||
self.assertIn(res_name, engine_args['filters']['resource_name'])
|
self.assertIn(res_name, engine_args['filters']['resource_name'])
|
||||||
|
@ -40,7 +40,7 @@ class ServiceEngineTest(common.HeatTestCase):
|
|||||||
|
|
||||||
def test_make_sure_rpc_version(self):
|
def test_make_sure_rpc_version(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'1.30',
|
'1.31',
|
||||||
service.EngineService.RPC_API_VERSION,
|
service.EngineService.RPC_API_VERSION,
|
||||||
('RPC version is changed, please update this test to new version '
|
('RPC version is changed, please update this test to new version '
|
||||||
'and make sure additional test cases are added for RPC APIs '
|
'and make sure additional test cases are added for RPC APIs '
|
||||||
|
@ -43,6 +43,7 @@ class StackEventTest(common.HeatTestCase):
|
|||||||
|
|
||||||
self.assertEqual(4, len(events))
|
self.assertEqual(4, len(events))
|
||||||
for ev in events:
|
for ev in events:
|
||||||
|
self.assertNotIn('root_stack_id', ev)
|
||||||
self.assertIn('event_identity', ev)
|
self.assertIn('event_identity', ev)
|
||||||
self.assertIsInstance(ev['event_identity'], dict)
|
self.assertIsInstance(ev['event_identity'], dict)
|
||||||
self.assertTrue(ev['event_identity']['path'].rsplit('/', 1)[1])
|
self.assertTrue(ev['event_identity']['path'].rsplit('/', 1)[1])
|
||||||
@ -87,6 +88,20 @@ class StackEventTest(common.HeatTestCase):
|
|||||||
mock_get.assert_called_once_with(self.ctx, self.stack.identifier(),
|
mock_get.assert_called_once_with(self.ctx, self.stack.identifier(),
|
||||||
show_deleted=True)
|
show_deleted=True)
|
||||||
|
|
||||||
|
@tools.stack_context('service_event_list_test_stack')
|
||||||
|
@mock.patch.object(service.EngineService, '_get_stack')
|
||||||
|
def test_event_list_nested_depth(self, mock_get):
|
||||||
|
mock_get.return_value = stack_object.Stack.get_by_id(self.ctx,
|
||||||
|
self.stack.id)
|
||||||
|
events = self.eng.list_events(self.ctx, self.stack.identifier(),
|
||||||
|
nested_depth=1)
|
||||||
|
|
||||||
|
self.assertEqual(4, len(events))
|
||||||
|
for ev in events:
|
||||||
|
self.assertIn('root_stack_id', ev)
|
||||||
|
mock_get.assert_called_once_with(self.ctx, self.stack.identifier(),
|
||||||
|
show_deleted=True)
|
||||||
|
|
||||||
@tools.stack_context('service_event_list_deleted_resource')
|
@tools.stack_context('service_event_list_deleted_resource')
|
||||||
@mock.patch.object(instances.Instance, 'handle_delete')
|
@mock.patch.object(instances.Instance, 'handle_delete')
|
||||||
def test_event_list_deleted_resource(self, mock_delete):
|
def test_event_list_deleted_resource(self, mock_delete):
|
||||||
|
@ -239,7 +239,8 @@ class EngineRpcAPITestCase(common.HeatTestCase):
|
|||||||
'marker': None,
|
'marker': None,
|
||||||
'sort_keys': None,
|
'sort_keys': None,
|
||||||
'sort_dir': None,
|
'sort_dir': None,
|
||||||
'filters': None}
|
'filters': None,
|
||||||
|
'nested_depth': None}
|
||||||
self._test_engine_api('list_events', 'call', **kwargs)
|
self._test_engine_api('list_events', 'call', **kwargs)
|
||||||
|
|
||||||
def test_describe_stack_resource(self):
|
def test_describe_stack_resource(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user