From 7b95f0316db1ce1b0192926f9c12167c97a48c67 Mon Sep 17 00:00:00 2001 From: Sebastian Wagner Date: Thu, 21 Nov 2019 15:18:10 +0100 Subject: [PATCH] mgr/orchestrator: add pretty_print() Signed-off-by: Sebastian Wagner --- src/pybind/mgr/ansible/module.py | 6 ++-- src/pybind/mgr/orchestrator.py | 41 ++++++++++++++++++++-- src/pybind/mgr/rook/module.py | 2 +- src/pybind/mgr/ssh/module.py | 2 +- src/pybind/mgr/test_orchestrator/module.py | 2 +- src/pybind/mgr/tests/test_orchestrator.py | 40 +++++++++++++++++++++ 6 files changed, 84 insertions(+), 9 deletions(-) diff --git a/src/pybind/mgr/ansible/module.py b/src/pybind/mgr/ansible/module.py index ba58cecb90b7d..eaf93b710b34b 100644 --- a/src/pybind/mgr/ansible/module.py +++ b/src/pybind/mgr/ansible/module.py @@ -287,10 +287,8 @@ class Module(MgrModule, orchestrator.Orchestrator): :Returns : True if everything is done. """ - # Check progress and update status in each operation - # Access completion.status property do the trick - for operation in completions: - self.log.info("<%s> is_finished:%s", operation, operation.is_finished) + if completions: + self.log.info("process: completions={0}".format(orchestrator.pretty_print(completions))) def serve(self): """ Mandatory for standby modules diff --git a/src/pybind/mgr/orchestrator.py b/src/pybind/mgr/orchestrator.py index aa0f6c2a9d944..8b313922a9856 100644 --- a/src/pybind/mgr/orchestrator.py +++ b/src/pybind/mgr/orchestrator.py @@ -198,6 +198,25 @@ class _Promise(object): self.__class__, self._state, val, self._on_complete, id(self), name, getattr(next, '_progress_reference', 'NA'), repr(self._next_promise) ) + def pretty_print_1(self): + if self._name: + name = self._name + elif self._on_complete is None: + name = 'lambda x: x' + elif hasattr(self._on_complete, '__name__'): + name = getattr(self._on_complete, '__name__') + else: + name = self._on_complete.__class__.__name__ + val = repr(self._value) if self._value not in (self.NO_RESULT, self.ASYNC_RESULT) else '...' + if hasattr(val, 'debug_str'): + val = val.debug_str() + prefix = { + self.INITIALIZED: ' ', + self.RUNNING: ' >>>', + self.FINISHED: '(done)' + }[self._state] + return '{} {}({}),'.format(prefix, name, val) + def then(self, on_complete): # type: (Any, Callable) -> Any """ @@ -475,14 +494,22 @@ class Completion(_Promise): _first_promise=_first_promise, value=value, on_complete=on_complete - ).then( + ).add_progress(message, mgr, calc_percent) + + return c._first_promise + + def add_progress(self, + message, # type: str + mgr, + calc_percent=None # type: Optional[Callable[[], Any]] + ): + return self.then( on_complete=ProgressReference( message=message, mgr=mgr, completion=calc_percent ) ) - return c._first_promise def fail(self, e): super(Completion, self).fail(e) @@ -561,6 +588,16 @@ class Completion(_Promise): """ return self.is_errored or (self.has_result) + def pretty_print(self): + + reprs = '\n'.join(p.pretty_print_1() for p in iter(self._first_promise)) + return """<{}>[\n{}\n]""".format(self.__class__.__name__, reprs) + + +def pretty_print(completions): + # type: (List[Completion]) -> str + return ', '.join(c.pretty_print() for c in completions) + def raise_if_exception(c): # type: (Completion) -> None diff --git a/src/pybind/mgr/rook/module.py b/src/pybind/mgr/rook/module.py index a0accd69c607e..4b534d967f21b 100644 --- a/src/pybind/mgr/rook/module.py +++ b/src/pybind/mgr/rook/module.py @@ -103,7 +103,7 @@ class RookOrchestrator(MgrModule, orchestrator.Orchestrator): # type: (List[RookCompletion]) -> None if completions: - self.log.info("wait: promises={0}".format(completions)) + self.log.info("process: completions={0}".format(orchestrator.pretty_print(completions))) for p in completions: p.evaluate() diff --git a/src/pybind/mgr/ssh/module.py b/src/pybind/mgr/ssh/module.py index a458a4a7bc0b4..790e6b2c44a95 100644 --- a/src/pybind/mgr/ssh/module.py +++ b/src/pybind/mgr/ssh/module.py @@ -409,7 +409,7 @@ class SSHOrchestrator(MgrModule, orchestrator.Orchestrator): Does nothing, as completions are processed in another thread. """ if completions: - self.log.info("wait: promises={0}".format(completions)) + self.log.info("process: completions={0}".format(orchestrator.pretty_print(completions))) for p in completions: p.finalize() diff --git a/src/pybind/mgr/test_orchestrator/module.py b/src/pybind/mgr/test_orchestrator/module.py index 6067276a2be0b..474bb31aad635 100644 --- a/src/pybind/mgr/test_orchestrator/module.py +++ b/src/pybind/mgr/test_orchestrator/module.py @@ -67,7 +67,7 @@ class TestOrchestrator(MgrModule, orchestrator.Orchestrator): def process(self, completions): # type: (List[TestCompletion]) -> None if completions: - self.log.info("wait: promises={0}".format(completions)) + self.log.info("process: completions={0}".format(orchestrator.pretty_print(completions))) for p in completions: p.evaluate() diff --git a/src/pybind/mgr/tests/test_orchestrator.py b/src/pybind/mgr/tests/test_orchestrator.py index a0095db172402..584c407cb4cfc 100644 --- a/src/pybind/mgr/tests/test_orchestrator.py +++ b/src/pybind/mgr/tests/test_orchestrator.py @@ -227,3 +227,43 @@ def test_fail(): c = Completion().then(lambda _: 3) c._first_promise.fail(KeyError()) assert isinstance(c.exception, KeyError) + + +def test_pretty_print(): + mgr = mock.MagicMock() + mgr.process = lambda cs: [c.finalize(None) for c in cs] + + def add_one(x): + return x+1 + + c = Completion(value=1, on_complete=add_one).then( + str + ).add_progress('message', mgr) + + assert c.pretty_print() == """[ + add_one(1), + str(...), + ProgressReference(...), +]""" + c.finalize() + assert c.pretty_print() == """[ +(done) add_one(1), +(done) str(2), +(done) ProgressReference('2'), +]""" + + p = some_complex_completion() + assert p.pretty_print() == """[ + (3), + lambda x: x(...), +]""" + p.finalize() + assert p.pretty_print() == """[ +(done) (3), +(done) (4), +(done) lambda x: x(5), +(done) lambda x: x(5), +]""" + + assert p.result == 5 + -- 2.39.5