diff --git a/brigade/core/exceptions.py b/brigade/core/exceptions.py index a07e5d85..2c215737 100644 --- a/brigade/core/exceptions.py +++ b/brigade/core/exceptions.py @@ -51,3 +51,24 @@ def __str__(self): text += "**** {}\n".format(sub_r.name) text += "{}\n".format(sub_r) return text + +class BrigadeSubTaskError(Exception): + """ + Raised by brigade when a sub task managed by :meth:`brigade.core.Task.run` + has failed + + Arguments: + task (str): Name of the sub task that failed + Attributes: + task (str): Name of the sub task that failed + """ + + def __init__(self, task): + self.task = task + + def __str__(self): + text = "\n" + text += "{}\n".format("#" * 40) + text += "# Subtask: {} (failed)\n".format(self.task) + text += "{}\n".format("#" * 40) + return text diff --git a/brigade/core/task.py b/brigade/core/task.py index 472eee8e..630b9d4a 100644 --- a/brigade/core/task.py +++ b/brigade/core/task.py @@ -3,6 +3,7 @@ from builtins import super from brigade.core.exceptions import BrigadeExecutionError +from brigade.core.exceptions import BrigadeSubTaskError class Task(object): @@ -61,10 +62,17 @@ def start(self, host, brigade): r = self.task(self, **self.params) if not isinstance(r, Result): r = Result(host=host, result=r) + + except BrigadeSubTaskError as e: + tb = traceback.format_exc() + logger.error("{}: {}".format(self.host, tb)) + r = Result(host, exception=e, result=str(e), failed=True) + except Exception as e: tb = traceback.format_exc() logger.error("{}: {}".format(self.host, tb)) r = Result(host, exception=e, result=tb, failed=True) + r.name = self.name r.severity_level = logging.ERROR if r.failed else self.severity_level @@ -93,11 +101,12 @@ def grouped_tasks(task): if "severity_level" not in kwargs: kwargs["severity_level"] = self.severity_level r = Task(task, **kwargs).start(self.host, self.brigade) + self.results.append(r[0] if len(r) == 1 else r) + if r.failed: # Without this we will keep running the grouped task - raise r.exception + raise BrigadeSubTaskError((r.name)) - self.results.append(r[0] if len(r) == 1 else r) return r def is_dry_run(self, override=None):