summaryrefslogtreecommitdiff
path: root/heatclient/common
diff options
context:
space:
mode:
authorSteve Baker <sbaker@redhat.com>2016-09-02 05:13:29 +0000
committerSteve Baker <sbaker@redhat.com>2016-09-06 13:54:12 +1200
commitb28d8c610147b2830930da532d6b42233d8cd468 (patch)
treefa3a6b961b224b4187d940860244f3779aad6413 /heatclient/common
parented287fb91364f6bdd8c91c2f60d6523c3cd2af70 (diff)
downloadpython-heatclient-b28d8c610147b2830930da532d6b42233d8cd468.tar.gz
Show resource name path in event log formatter
The resource name path was introduced in the 'openstack stack failures' command and is a user-friendly way of referring to a deeply nested resource. This change modifies the event log formatter to build and display the resource name path for each event based only off data in previous events. For building the full resource path, and omitting ugly stack names from the resource path, the following heat change is needed Ib8feb7752bd5736785d142216312bb35629b3601. However the output is still improved slightly when running against an older heat which does not have this change. Change-Id: I86b687fc516da215a6baeef8b365a520d12a8ab1 Closes-Bug: #1619415
Diffstat (limited to 'heatclient/common')
-rw-r--r--heatclient/common/event_utils.py3
-rw-r--r--heatclient/common/utils.py72
2 files changed, 72 insertions, 3 deletions
diff --git a/heatclient/common/event_utils.py b/heatclient/common/event_utils.py
index 6acbbd6..c0bc42e 100644
--- a/heatclient/common/event_utils.py
+++ b/heatclient/common/event_utils.py
@@ -179,6 +179,7 @@ def poll_for_events(hc, stack_name, action=None, poll_period=5, marker=None,
msg_template = _("\n Stack %(name)s %(status)s \n")
if not out:
out = sys.stdout
+ event_log_context = utils.EventLogContext()
while True:
events = get_events(hc, stack_id=stack_name, nested_depth=nested_depth,
event_args={'sort_dir': 'asc',
@@ -190,7 +191,7 @@ def poll_for_events(hc, stack_name, action=None, poll_period=5, marker=None,
no_event_polls = 0
# set marker to last event that was received.
marker = getattr(events[-1], 'id', None)
- events_log = utils.event_log_formatter(events)
+ events_log = utils.event_log_formatter(events, event_log_context)
out.write(events_log)
out.write('\n')
diff --git a/heatclient/common/utils.py b/heatclient/common/utils.py
index a36ab38..f2b20f1 100644
--- a/heatclient/common/utils.py
+++ b/heatclient/common/utils.py
@@ -97,16 +97,84 @@ def print_dict(d, formatters=None):
print(pt.get_string(sortby='Property'))
-def event_log_formatter(events):
+class EventLogContext(object):
+
+ def __init__(self):
+ # key is a stack id or the name of the nested stack, value is a tuple
+ # of the parent stack id, and the name of the resource in the parent
+ # stack
+ self.id_to_res_info = {}
+
+ def prepend_paths(self, resource_path, stack_id):
+ if stack_id not in self.id_to_res_info:
+ return
+ stack_id, res_name = self.id_to_res_info.get(stack_id)
+ if res_name in self.id_to_res_info:
+ # do a double lookup to skip the ugly stack name that doesn't
+ # correspond to an actual resource name
+ n_stack_id, res_name = self.id_to_res_info.get(res_name)
+ resource_path.insert(0, res_name)
+ self.prepend_paths(resource_path, n_stack_id)
+ elif res_name:
+ resource_path.insert(0, res_name)
+
+ def build_resource_name(self, event):
+ res_name = getattr(event, 'resource_name')
+
+ # Contribute this event to self.id_to_res_info to assist with
+ # future calls to build_resource_name
+
+ def get_stack_id():
+ for l in getattr(event, 'links', []):
+ if l.get('rel') == 'stack':
+ if 'href' not in l:
+ return None
+ stack_link = l['href']
+ return stack_link.split('/')[-1]
+
+ stack_id = get_stack_id()
+ if not stack_id:
+ return res_name
+ phys_id = getattr(event, 'physical_resource_id')
+ status = getattr(event, 'resource_status')
+
+ is_stack_event = stack_id == phys_id
+ if is_stack_event:
+ # this is an event for a stack
+ self.id_to_res_info[stack_id] = (stack_id, res_name)
+ elif phys_id and status == 'CREATE_IN_PROGRESS':
+ # this might be an event for a resource which creates a stack
+ self.id_to_res_info[phys_id] = (stack_id, res_name)
+
+ # Now build this resource path based on previous calls to
+ # build_resource_name
+ resource_path = []
+ if res_name and not is_stack_event:
+ resource_path.append(res_name)
+ self.prepend_paths(resource_path, stack_id)
+
+ return '.'.join(resource_path)
+
+
+def event_log_formatter(events, event_log_context=None):
"""Return the events in log format."""
event_log = []
log_format = ("%(event_time)s "
"[%(rsrc_name)s]: %(rsrc_status)s %(rsrc_status_reason)s")
+
+ # It is preferable for a context to be passed in, but there might be enough
+ # events in this call to build a better resource name, so create a context
+ # anyway
+ if event_log_context is None:
+ event_log_context = EventLogContext()
+
for event in events:
+ rsrc_name = event_log_context.build_resource_name(event)
+
event_time = getattr(event, 'event_time', '')
log = log_format % {
'event_time': event_time.replace('T', ' '),
- 'rsrc_name': getattr(event, 'resource_name', ''),
+ 'rsrc_name': rsrc_name,
'rsrc_status': getattr(event, 'resource_status', ''),
'rsrc_status_reason': getattr(event, 'resource_status_reason', '')
}