diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a4c5d2232e..8a0bf82ad8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,14 @@ Added * Add make command to autogen JSON schema from the models of action, rule, etc. Add check to ensure update to the models require schema to be regenerated. (new feature) +Changed +~~~~~~~ +* Changed the output of elapsed time on `st2 execution get` to a more user-friendly format. + The new format is ``d hms``. Units without a value are omitted. + Old: ``status: succeeded (92342s elapsed)``, ``status: succeeded (113s elapsed)`` + New: ``stauts: succeeded (1d1h39m2s elapsed)``, ``status: succeeded (1m53s elapsed)`` + This was requested by Sheshagiri (@Sheshagiri) and contributed by Marcel Weinber (@winem). #4944 + Fixed ~~~~~ * Fixed a bug where `type` attribute was missing for netstat action in linux pack. Fixes #4946 diff --git a/st2client/st2client/commands/action.py b/st2client/st2client/commands/action.py index f458303bc0..851c66d795 100644 --- a/st2client/st2client/commands/action.py +++ b/st2client/st2client/commands/action.py @@ -25,6 +25,8 @@ import six import sys +from dateutil.relativedelta import relativedelta + from os.path import join as pjoin from six.moves import range @@ -167,20 +169,39 @@ def format_execution_status(instance): start_timestamp = parse_isotime(start_timestamp) start_timestamp = calendar.timegm(start_timestamp.timetuple()) now = int(time.time()) - elapsed_seconds = (now - start_timestamp) - instance.status = '%s (%ss elapsed)' % (instance.status, elapsed_seconds) + elapsed_time_string = format_elapsed_time(now - start_timestamp) + instance.status = '%s (%s elapsed)' % (instance.status, elapsed_time_string) elif status in LIVEACTION_COMPLETED_STATES and start_timestamp and end_timestamp: start_timestamp = parse_isotime(start_timestamp) start_timestamp = calendar.timegm(start_timestamp.timetuple()) end_timestamp = parse_isotime(end_timestamp) end_timestamp = calendar.timegm(end_timestamp.timetuple()) - elapsed_seconds = (end_timestamp - start_timestamp) - instance.status = '%s (%ss elapsed)' % (instance.status, elapsed_seconds) + elapsed_time_string = format_elapsed_time(end_timestamp - start_timestamp) + instance.status = '%s (%s elapsed)' % (instance.status, elapsed_time_string) return instance +def format_elapsed_time(delta_in_seconds): + delta = relativedelta(seconds=delta_in_seconds) + days = delta.days + hours = delta.hours + minutes = delta.minutes + seconds = delta.seconds + + if days > 0: + elapsed_time_string = '%sd%sh%sm%ss' % (days, hours, minutes, seconds) + elif hours > 0: + elapsed_time_string = '%sh%sm%ss' % (hours, minutes, seconds) + elif minutes > 0: + elapsed_time_string = '%sm%ss' % (minutes, seconds) + else: + elapsed_time_string = '%ss' % (seconds) + + return elapsed_time_string + + class ActionBranch(resource.ResourceBranch): def __init__(self, description, app, subparsers, parent_parser=None): diff --git a/st2client/tests/fixtures/execution_get_attribute_with_hours_in_elapsed_time.txt b/st2client/tests/fixtures/execution_get_attribute_with_hours_in_elapsed_time.txt new file mode 100644 index 0000000000..7bbcd96e0f --- /dev/null +++ b/st2client/tests/fixtures/execution_get_attribute_with_hours_in_elapsed_time.txt @@ -0,0 +1 @@ +status: succeeded (2h0m1s elapsed) diff --git a/st2client/tests/fixtures/execution_with_hours_in_elapsed_time.json b/st2client/tests/fixtures/execution_with_hours_in_elapsed_time.json new file mode 100644 index 0000000000..12771065fb --- /dev/null +++ b/st2client/tests/fixtures/execution_with_hours_in_elapsed_time.json @@ -0,0 +1,29 @@ +{ + "id": "547e19561e2e2417d3dde398", + "parameters": { + "cmd": "127.0.0.1 3" + }, + "callback": {}, + "context": { + "user": "stanley" + }, + "result": { + "localhost": { + "failed": false, + "stderr": "", + "return_code": 0, + "succeeded": true, + "stdout": "PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.\n64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.015 ms\n64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.024 ms\n64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.030 ms\n\n--- 127.0.0.1 ping statistics ---\n3 packets transmitted, 3 received, 0% packet loss, time 1998ms\nrtt min/avg/max/mdev = 0.015/0.023/0.030/0.006 ms" + } + }, + "status": "succeeded", + "start_timestamp": "2014-12-02T19:56:06.900000Z", + "end_timestamp": "2014-12-02T21:56:07.000000Z", + "action": { + "ref": "core.ping" + }, + "liveaction": { + "callback": {}, + "id": "1" + } +} \ No newline at end of file diff --git a/st2client/tests/unit/test_formatters.py b/st2client/tests/unit/test_formatters.py index 724444127f..a55f798b9b 100644 --- a/st2client/tests/unit/test_formatters.py +++ b/st2client/tests/unit/test_formatters.py @@ -42,6 +42,7 @@ 'execution_result_has_carriage_return.json', 'execution_unicode.json', 'execution_double_backslash.json', + 'execution_with_hours_in_elapsed_time.json', 'execution_with_stack_trace.json', 'execution_with_schema.json'], 'results': ['execution_get_default.txt', @@ -50,6 +51,7 @@ 'execution_result_has_carriage_return.txt', 'execution_result_has_carriage_return_py3.txt', 'execution_get_attributes.txt', + 'execution_get_attribute_with_hours_in_elapsed_time.txt', 'execution_list_attr_start_timestamp.txt', 'execution_list_empty_response_start_timestamp_attr.txt', 'execution_unescape_newline.txt', @@ -66,6 +68,7 @@ OUTPUT_SCHEMA = FIXTURES['executions']['execution_with_schema.json'] NEWLINE = FIXTURES['executions']['execution_with_stack_trace.json'] HAS_CARRIAGE_RETURN = FIXTURES['executions']['execution_result_has_carriage_return.json'] +DURATION_HOURS = FIXTURES['executions']['execution_with_hours_in_elapsed_time.json'] class TestExecutionResultFormatter(unittest2.TestCase): @@ -112,6 +115,12 @@ def test_execution_get_attributes(self): content = self._get_execution(argv) self.assertEqual(content, FIXTURES['results']['execution_get_attributes.txt']) + def test_execution_get_attribute_with_hours_in_elapsed_time(self): + argv = ['execution', 'get', DURATION_HOURS['id'], '--attr', 'status'] + content = self._get_execution(argv) + self.assertEqual( + content, FIXTURES['results']['execution_get_attribute_with_hours_in_elapsed_time.txt']) + def test_execution_get_default_in_json(self): argv = ['execution', 'get', EXECUTION['id'], '-j'] content = self._get_execution(argv)