Implement stack event list --follow
This adds a --follow option which is similar to the --wait logging behaviour in changes like I72421c1adf9220e3440179fec672f49803a6cde2 except that --follow doesn't exit until the user does ctrl-c. This change also includes: - always sort events ascending for all formatters - the newest events should always be at the bottom of the screen as they are generally the most interesting - get_event marker handling tolerates the marker not being in the event list. --follow was triggering this, but ignoring the marker in this case has not lead to events being printed more than once Change-Id: Ie0964918fc1d05e7e18aa39ceea6d4777deeb87e Blueprint: heat-support-python-openstackclient
This commit is contained in:
parent
6c18458764
commit
ebdf0ebc94
|
@ -75,8 +75,11 @@ def get_events(hc, stack_id, event_args, nested_depth=0,
|
|||
|
||||
# Slice the list if marker is specified
|
||||
if marker:
|
||||
marker_index = [e.id for e in events].index(marker)
|
||||
events = events[marker_index:]
|
||||
try:
|
||||
marker_index = [e.id for e in events].index(marker)
|
||||
events = events[marker_index:]
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Slice the list if limit is specified
|
||||
if limit:
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# Copyright 2015 IBM Corp.
|
||||
|
||||
import logging
|
||||
import time
|
||||
|
||||
from cliff import lister
|
||||
from cliff import show
|
||||
|
@ -134,6 +135,11 @@ class ListEvent(lister.Lister):
|
|||
'(default: asc). Specify multiple times to sort on '
|
||||
'multiple keys')
|
||||
)
|
||||
parser.add_argument(
|
||||
'--follow',
|
||||
action='store_true',
|
||||
help=_('Print events until process is halted')
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
|
@ -149,6 +155,7 @@ class ListEvent(lister.Lister):
|
|||
'limit': parsed_args.limit,
|
||||
'marker': parsed_args.marker,
|
||||
'filters': heat_utils.format_parameters(parsed_args.filter),
|
||||
'sort_dir': 'asc'
|
||||
}
|
||||
|
||||
if parsed_args.resource and parsed_args.nested_depth:
|
||||
|
@ -165,6 +172,31 @@ class ListEvent(lister.Lister):
|
|||
else:
|
||||
nested_depth = 0
|
||||
|
||||
if parsed_args.follow:
|
||||
if parsed_args.formatter != 'value':
|
||||
msg = _('--follow can only be specified with --format value')
|
||||
raise exc.CommandError(msg)
|
||||
|
||||
marker = parsed_args.marker
|
||||
try:
|
||||
while True:
|
||||
kwargs['marker'] = marker
|
||||
events = event_utils.get_events(
|
||||
client,
|
||||
stack_id=parsed_args.stack,
|
||||
event_args=kwargs,
|
||||
nested_depth=nested_depth,
|
||||
marker=marker)
|
||||
if events:
|
||||
marker = getattr(events[-1], 'id', None)
|
||||
events_log = heat_utils.event_log_formatter(events)
|
||||
self.app.stdout.write(events_log)
|
||||
self.app.stdout.write('\n')
|
||||
time.sleep(5)
|
||||
# this loop never exits
|
||||
except (KeyboardInterrupt, EOFError): # ctrl-c, ctrl-d
|
||||
return [], []
|
||||
|
||||
events = event_utils.get_events(
|
||||
client, stack_id=parsed_args.stack, event_args=kwargs,
|
||||
nested_depth=nested_depth, marker=parsed_args.marker,
|
||||
|
@ -175,7 +207,6 @@ class ListEvent(lister.Lister):
|
|||
|
||||
if parsed_args.formatter == 'value':
|
||||
events = heat_utils.event_log_formatter(events).split('\n')
|
||||
events.reverse()
|
||||
return [], [e.split(' ') for e in events]
|
||||
|
||||
if len(events):
|
||||
|
|
|
@ -111,6 +111,7 @@ class TestEventList(TestEvent):
|
|||
'limit': None,
|
||||
'marker': None,
|
||||
'filters': {},
|
||||
'sort_dir': 'asc'
|
||||
}
|
||||
|
||||
fields = ['resource_name', 'id', 'resource_status',
|
||||
|
@ -199,6 +200,31 @@ class TestEventList(TestEvent):
|
|||
self.event_client.list.assert_called_with(**self.defaults)
|
||||
self.assertEqual(self.fields, columns)
|
||||
|
||||
@mock.patch('time.sleep')
|
||||
def test_event_list_follow(self, sleep):
|
||||
sleep.side_effect = [None, KeyboardInterrupt()]
|
||||
arglist = ['--follow', 'my_stack']
|
||||
expected = (
|
||||
'2015-11-13 10:02:17 [resource1]: '
|
||||
'CREATE_COMPLETE state changed\n'
|
||||
'2015-11-13 10:02:17 [resource1]: '
|
||||
'CREATE_COMPLETE state changed\n'
|
||||
)
|
||||
parsed_args = self.check_parser(self.cmd, arglist, [])
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
defaults_with_marker = dict(self.defaults)
|
||||
defaults_with_marker['marker'] = '1234'
|
||||
|
||||
self.event_client.list.assert_has_calls([
|
||||
mock.call(**self.defaults),
|
||||
mock.call(**defaults_with_marker)
|
||||
])
|
||||
self.assertEqual([], columns)
|
||||
self.assertEqual([], data)
|
||||
self.assertEqual(expected, self.fake_stdout.make_string())
|
||||
|
||||
def test_event_list_value_format(self):
|
||||
arglist = ['my_stack']
|
||||
expected = ('2015-11-13 10:02:17 [resource1]: CREATE_COMPLETE '
|
||||
|
|
Loading…
Reference in New Issue