def run_action(self, action_ex_id, action_class_str, attributes, action_params): """Runs action. :param action_ex_id: Corresponding task id. :param action_class_str: Path to action class in dot notation. :param attributes: Attributes of action class which will be set to. :param action_params: Action parameters. """ def send_error_back(error_msg): error_result = wf_utils.Result(error=error_msg) if action_ex_id: self._engine_client.on_action_complete( action_ex_id, error_result ) else: return error_result action_cls = a_f.construct_action_class(action_class_str, attributes) try: action = action_cls(**action_params) result = action.run() # Note: it's made for backwards compatibility with already # existing Mistral actions which don't return result as # instance of workflow.utils.Result. if not isinstance(result, wf_utils.Result): result = wf_utils.Result(data=result) if action_ex_id and (action.is_sync() or result.is_error()): self._engine_client.on_action_complete(action_ex_id, result) return result except TypeError as e: msg = ("Failed to initialize action %s. Action init params = %s." " Actual init params = %s. More info: %s" % (action_class_str, i_u.get_arg_list(action_cls.__init__), action_params.keys(), e)) LOG.warning(msg) except exc.ActionException as e: msg = ("Failed to run action [action_ex_id=%s, action_cls='%s'," " attributes='%s', params='%s']\n %s" % (action_ex_id, action_cls, attributes, action_params, e)) LOG.exception(msg) except Exception as e: msg = str(e) # Send error info to engine. return send_error_back(msg)
def get_action_class(action_full_name, namespace=''): """Finds action class by full action name (i.e. 'namespace.action_name'). :param action_full_name: Full action name (that includes namespace). :return: Action class or None if not found. """ action_db = get_action_db(action_full_name, namespace) if action_db: return action_factory.construct_action_class(action_db.action_class, action_db.attributes)
def run_action(self, action_ex_id, action_class_str, attributes, action_params): """Runs action. :param action_ex_id: Corresponding task id. :param action_class_str: Path to action class in dot notation. :param attributes: Attributes of action class which will be set to. :param action_params: Action parameters. """ def send_error_back(error_msg): if action_ex_id: self._engine_client.on_action_complete( action_ex_id, wf_utils.Result(error=error_msg) ) else: return error_msg action_cls = a_f.construct_action_class(action_class_str, attributes) try: action = action_cls(**action_params) result = action.run() if action.is_sync() and action_ex_id: # Note: it's made for backwards compatibility with already # existing Mistral actions which don't return result as # instance of workflow.utils.Result. if not isinstance(result, wf_utils.Result): result = wf_utils.Result(data=result) self._engine_client.on_action_complete(action_ex_id, result) return result except TypeError as e: msg = ("Failed to initialize action %s. Action init params = %s." " Actual init params = %s. More info: %s" % (action_class_str, i_u.get_arg_list(action_cls.__init__), action_params.keys(), e)) LOG.warn(msg) except exc.ActionException as e: msg = ("Failed to run action [action_ex_id=%s, action_cls='%s'," " attributes='%s', params='%s']\n %s" % (action_ex_id, action_cls, attributes, action_params, e)) LOG.exception(msg) except Exception as e: msg = str(e) # Send error info to engine. return send_error_back(msg)
def get_action_class(action_full_name): """Finds action class by full action name (i.e. 'namespace.action_name'). :param action_full_name: Full action name (that includes namespace). :return: Action class or None if not found. """ action_db = get_action_db(action_full_name) if action_db: return action_factory.construct_action_class( action_db.action_class, action_db.attributes )
def run_action(self, action_ex_id, action_class_str, attributes, action_params): """Runs action. :param action_ex_id: Action execution id. :param action_class_str: Path to action class in dot notation. :param attributes: Attributes of action class which will be set to. :param action_params: Action parameters. """ def send_error_back(error_msg): error_result = wf_utils.Result(error=error_msg) if action_ex_id: self._engine_client.on_action_complete(action_ex_id, error_result) return None return error_result action_cls = a_f.construct_action_class(action_class_str, attributes) # Instantiate action. try: action = action_cls(**action_params) except Exception as e: msg = ("Failed to initialize action %s. Action init params = %s." " Actual init params = %s. More info: %s" % (action_class_str, i_u.get_arg_list( action_cls.__init__), action_params.keys(), e)) LOG.warning(msg) return send_error_back(msg) # Run action. try: result = action.run() # Note: it's made for backwards compatibility with already # existing Mistral actions which don't return result as # instance of workflow.utils.Result. if not isinstance(result, wf_utils.Result): result = wf_utils.Result(data=result) except Exception as e: msg = ("Failed to run action [action_ex_id=%s, action_cls='%s'," " attributes='%s', params='%s']\n %s" % (action_ex_id, action_cls, attributes, action_params, e)) LOG.exception(msg) return send_error_back(msg) # Send action result. try: if action_ex_id and (action.is_sync() or result.is_error()): self._engine_client.on_action_complete(action_ex_id, result) except Exception as e: msg = ("Exception occurred when calling engine on_action_complete" " [action_ex_id=%s, action_cls='%s'," " attributes='%s', params='%s']\n %s" % (action_ex_id, action_cls, attributes, action_params, e)) LOG.exception(msg) return result
def _has_argument(action, attributes, argument_name): action_cls = action_factory.construct_action_class(action, attributes) arg_spec = inspect.getargspec(action_cls.__init__) return argument_name in arg_spec.args
def run_action(self, action_ex_id, action_cls_str, action_cls_attrs, params, safe_rerun, redelivered=False, target=None, async_=True): """Runs action. :param action_ex_id: Action execution id. :param action_cls_str: Path to action class in dot notation. :param action_cls_attrs: Attributes of action class which will be set to. :param params: Action parameters. :param safe_rerun: Tells if given action can be safely rerun. :param redelivered: Tells if given action was run before on another executor. :param target: Target (group of action executors). :param async_: If True, run action in asynchronous mode (w/o waiting for completion). :return: Action result. """ def send_error_back(error_msg): error_result = wf_utils.Result(error=error_msg) if action_ex_id: self._engine_client.on_action_complete(action_ex_id, error_result) return None return error_result if redelivered and not safe_rerun: msg = ( "Request to run action %s was redelivered, but action %s " "cannot be re-run safely. The only safe thing to do is fail " "action." % (action_cls_str, action_cls_str)) return send_error_back(msg) # Load action module. action_cls = a_f.construct_action_class(action_cls_str, action_cls_attrs) # Instantiate action. try: action = action_cls(**params) except Exception as e: msg = ("Failed to initialize action %s. Action init params = %s. " "Actual init params = %s. More info: %s" % (action_cls_str, i_u.get_arg_list( action_cls.__init__), params.keys(), e)) LOG.warning(msg) return send_error_back(msg) # Run action. try: # NOTE(d0ugal): If the action is a subclass of mistral-lib we know # that it expects to be passed the context. We should deprecate # the builtin action class in Mistral. if isinstance(action, mistral_lib.Action): result = action.run(context.ctx()) else: result = action.run() # Note: it's made for backwards compatibility with already # existing Mistral actions which don't return result as # instance of workflow.utils.Result. if not isinstance(result, wf_utils.Result): result = wf_utils.Result(data=result) except Exception as e: msg = ("Failed to run action [action_ex_id=%s, action_cls='%s', " "attributes='%s', params='%s']\n %s" % (action_ex_id, action_cls, action_cls_attrs, params, e)) LOG.exception(msg) return send_error_back(msg) # Send action result. try: if action_ex_id and (action.is_sync() or result.is_error()): self._engine_client.on_action_complete(action_ex_id, result, async_=True) except exc.MistralException as e: # In case of a Mistral exception we can try to send error info to # engine because most likely it's not related to the infrastructure # such as message bus or network. One known case is when the action # returns a bad result (e.g. invalid unicode) which can't be # serialized. msg = ("Failed to complete action due to a Mistral exception " "[action_ex_id=%s, action_cls='%s', " "attributes='%s', params='%s']\n %s" % (action_ex_id, action_cls, action_cls_attrs, params, e)) LOG.exception(msg) return send_error_back(msg) except Exception as e: # If it's not a Mistral exception all we can do is only # log the error. msg = ("Failed to complete action due to an unexpected exception " "[action_ex_id=%s, action_cls='%s', " "attributes='%s', params='%s']\n %s" % (action_ex_id, action_cls, action_cls_attrs, params, e)) LOG.exception(msg) return result
def _do_run_action(self, action_cls_attrs, action_cls_str, action_ex_id, execution_context, params, redelivered, safe_rerun, timeout): def send_error_back(error_msg): error_result = mistral_lib.Result(error=error_msg) if action_ex_id: self._engine_client.on_action_complete(action_ex_id, error_result) return None return error_result if redelivered and not safe_rerun: msg = ( "Request to run action %s was redelivered, but action %s " "cannot be re-run safely. The only safe thing to do is fail " "action." % (action_cls_str, action_cls_str)) return send_error_back(msg) # Load action module. action_cls = a_f.construct_action_class(action_cls_str, action_cls_attrs) # Instantiate action. try: action = action_cls(**params) except Exception as e: msg = ("Failed to initialize action %s. Action init params = %s. " "Actual init params = %s. More info: %s" % (action_cls_str, i_u.get_arg_list( action_cls.__init__), params.keys(), e)) LOG.warning(msg) return send_error_back(msg) # Run action. try: with ev_timeout.Timeout(seconds=timeout): # NOTE(d0ugal): If the action is a subclass of mistral-lib we # know that it expects to be passed the context. if isinstance(action, mistral_lib.Action): action_ctx = context.create_action_context( execution_context) result = action.run(action_ctx) else: result = action.run() # Note: it's made for backwards compatibility with already # existing Mistral actions which don't return result as # instance of workflow.utils.Result. if not isinstance(result, mistral_lib.Result): result = mistral_lib.Result(data=result) except BaseException as e: msg = ( "The action raised an exception [action_ex_id=%s, msg='%s', " "action_cls='%s', attributes='%s', params='%s']" % (action_ex_id, e, action_cls, action_cls_attrs, params)) LOG.warning(msg, exc_info=True) return send_error_back(msg) # Send action result. try: if action_ex_id and (action.is_sync() or result.is_error()): self._engine_client.on_action_complete(action_ex_id, result, async_=True) except exc.MistralException as e: # In case of a Mistral exception we can try to send error info to # engine because most likely it's not related to the infrastructure # such as message bus or network. One known case is when the action # returns a bad result (e.g. invalid unicode) which can't be # serialized. msg = ("Failed to complete action due to a Mistral exception " "[action_ex_id=%s, action_cls='%s', " "attributes='%s', params='%s']\n %s" % (action_ex_id, action_cls, action_cls_attrs, params, e)) LOG.exception(msg) return send_error_back(msg) except Exception as e: # If it's not a Mistral exception all we can do is only # log the error. msg = ("Failed to complete action due to an unexpected exception " "[action_ex_id=%s, action_cls='%s', " "attributes='%s', params='%s']\n %s" % (action_ex_id, action_cls, action_cls_attrs, params, e)) LOG.exception(msg) return result
def run_action(self, action_ex_id, action_class_str, attributes, action_params, safe_rerun, redelivered=False): """Runs action. :param action_ex_id: Action execution id. :param action_class_str: Path to action class in dot notation. :param attributes: Attributes of action class which will be set to. :param action_params: Action parameters. :param safe_rerun: Tells if given action can be safely rerun. :param redelivered: Tells if given action was run before on another executor. """ def send_error_back(error_msg): error_result = wf_utils.Result(error=error_msg) if action_ex_id: self._engine_client.on_action_complete( action_ex_id, error_result ) return None return error_result if redelivered and not safe_rerun: msg = ( "Request to run action %s was redelivered, but action %s" " cannot be re-run safely. The only safe thing to do is fail" " action." % (action_class_str, action_class_str) ) return send_error_back(msg) action_cls = a_f.construct_action_class(action_class_str, attributes) # Instantiate action. try: action = action_cls(**action_params) except Exception as e: msg = ("Failed to initialize action %s. Action init params = %s." " Actual init params = %s. More info: %s" % (action_class_str, i_u.get_arg_list(action_cls.__init__), action_params.keys(), e)) LOG.warning(msg) return send_error_back(msg) # Run action. try: result = action.run() # Note: it's made for backwards compatibility with already # existing Mistral actions which don't return result as # instance of workflow.utils.Result. if not isinstance(result, wf_utils.Result): result = wf_utils.Result(data=result) except Exception as e: msg = ("Failed to run action [action_ex_id=%s, action_cls='%s'," " attributes='%s', params='%s']\n %s" % (action_ex_id, action_cls, attributes, action_params, e)) LOG.exception(msg) return send_error_back(msg) # Send action result. try: if action_ex_id and (action.is_sync() or result.is_error()): self._engine_client.on_action_complete( action_ex_id, result, async_=True ) except exc.MistralException as e: # In case of a Mistral exception we can try to send error info to # engine because most likely it's not related to the infrastructure # such as message bus or network. One known case is when the action # returns a bad result (e.g. invalid unicode) which can't be # serialized. msg = ("Failed to call engine's on_action_complete() method due" " to a Mistral exception" " [action_ex_id=%s, action_cls='%s'," " attributes='%s', params='%s']\n %s" % (action_ex_id, action_cls, attributes, action_params, e)) LOG.exception(msg) return send_error_back(msg) except Exception as e: # If it's not a Mistral exception all we can do is only # log the error. msg = ("Failed to call engine's on_action_complete() method due" " to an unexpected exception" " [action_ex_id=%s, action_cls='%s'," " attributes='%s', params='%s']\n %s" % (action_ex_id, action_cls, attributes, action_params, e)) LOG.exception(msg) return result
def run_action(self, action_ex_id, action_class_str, attributes, action_params, safe_rerun, redelivered=False): """Runs action. :param action_ex_id: Action execution id. :param action_class_str: Path to action class in dot notation. :param attributes: Attributes of action class which will be set to. :param action_params: Action parameters. :param safe_rerun: Tells if given action can be safely rerun. :param redelivered: Tells if given action was run before on another executor. """ def send_error_back(error_msg): error_result = wf_utils.Result(error=error_msg) if action_ex_id: self._engine_client.on_action_complete( action_ex_id, error_result ) return None return error_result if redelivered and not safe_rerun: msg = ( "Request to run action %s was redelivered, but action %s" " cannot be re-run safely. The only safe thing to do is fail" " action." % (action_class_str, action_class_str) ) return send_error_back(msg) action_cls = a_f.construct_action_class(action_class_str, attributes) # Instantiate action. try: action = action_cls(**action_params) except Exception as e: msg = ("Failed to initialize action %s. Action init params = %s." " Actual init params = %s. More info: %s" % (action_class_str, i_u.get_arg_list(action_cls.__init__), action_params.keys(), e)) LOG.warning(msg) return send_error_back(msg) # Run action. try: result = action.run() # Note: it's made for backwards compatibility with already # existing Mistral actions which don't return result as # instance of workflow.utils.Result. if not isinstance(result, wf_utils.Result): result = wf_utils.Result(data=result) except Exception as e: msg = ("Failed to run action [action_ex_id=%s, action_cls='%s'," " attributes='%s', params='%s']\n %s" % (action_ex_id, action_cls, attributes, action_params, e)) LOG.exception(msg) return send_error_back(msg) # Send action result. try: if action_ex_id and (action.is_sync() or result.is_error()): self._engine_client.on_action_complete(action_ex_id, result) except Exception as e: msg = ("Exception occurred when calling engine on_action_complete" " [action_ex_id=%s, action_cls='%s'," " attributes='%s', params='%s']\n %s" % (action_ex_id, action_cls, attributes, action_params, e)) LOG.exception(msg) return result