Esempio n. 1
0
 def __setup_app_instance(self, instances, step):
     device_id = (step.app, step.device)
     if device_id not in instances:
         instances[device_id] = AppInstance.create(step.app, step.device)
         data_sent.send(self, callback_name="App Instance Created", object_type="Workflow")
         logger.debug('Created new app instance: App {0}, device {1}'.format(step.app, step.device))
     return device_id
Esempio n. 2
0
 def __swap_step_input(self, step, start_input):
     logger.debug('Swapping input to first step of workflow {0}'.format(self.name))
     try:
         step.set_input(start_input)
         data_sent.send(self, callback_name="Workflow Input Validated", object_type="Workflow")
     except InvalidInput as e:
         logger.error('Cannot change input to workflow {0}. '
                      'Invalid input. Error: {1}'.format(self.name, format_exception_message(e)))
         data_sent.send(self, callback_name="Workflow Input Invalid", object_type="Workflow")
Esempio n. 3
0
    def execute(self, execution_uid, start=None, start_input=''):
        """Executes a Workflow by executing all Steps in the Workflow list of Step objects.

        Args:
            execution_uid (str): The UUID4 hex string uniquely identifying this workflow instance
            start (str, optional): The name of the first Step. Defaults to None.
            start_input (str, optional): Input into the first Step. Defaults to an empty string.
        """
        self._execution_uid = execution_uid
        logger.info('Executing workflow {0}'.format(self.name))
        data_sent.send(self, callback_name="Workflow Execution Start", object_type="Workflow")
        start = start if start is not None else self.start
        executor = self.__execute(start, start_input)
        next(executor)
Esempio n. 4
0
    def get_next_step(self, accumulator):
        """Gets the NextStep object to be executed after the current Step.

        Args:
            accumulator (dict): A record of teh previously-executed steps. Of form {step_name: result}

        Returns:
            The NextStep object to be executed.
        """

        for next_step in self.next_steps:
            next_step = next_step.execute(self._output, accumulator)
            if next_step is not None:
                self._next_up = next_step
                data_sent.send(self,
                               callback_name="Conditionals Executed",
                               object_type="Step")
                return next_step
Esempio n. 5
0
 def __execute_step(self, step, instance):
     data = {"app": step.app,
             "action": step.action,
             "name": step.name,
             "input": step.inputs}
     try:
         step.execute(instance=instance(), accumulator=self._accumulator)
         data['result'] = step.get_output().as_json() if step.get_output() is not None else None
         data['execution_uid'] = step.get_execution_uid()
         data_sent.send(self, callback_name="Step Execution Success", object_type="Workflow", data=json.dumps(data))
     except Exception as e:
         data['result'] = step.get_output().as_json() if step.get_output() is not None else None
         data['execution_uid'] = step.get_execution_uid()
         data_sent.send(self, callback_name="Step Execution Error", object_type="Workflow", data=json.dumps(data))
         if self._total_risk > 0:
             self.accumulated_risk += float(step.risk) / self._total_risk
         logger.debug('Step {0} of workflow {1} executed with error {2}'.format(step, self.name,
                                                                                format_exception_message(e)))
Esempio n. 6
0
    def execute(self, data_in, accumulator):
        if data_in is not None and data_in.status == self.status:
            if all(
                    flag.execute(data_in=data_in.result,
                                 accumulator=accumulator)
                    for flag in self.flags):
                data_sent.send(self,
                               callback_name="Next Step Taken",
                               object_type="NextStep")
                logger.debug('NextStep is valid for input {0}'.format(data_in))

                return self.name
            else:
                logger.debug(
                    'NextStep is not valid for input {0}'.format(data_in))
                data_sent.send(self,
                               callback_name="Next Step Not Taken",
                               object_type="NextStep")
                return None
        else:
            return None
Esempio n. 7
0
    def __execute(self, start, start_input):
        instances = {}
        total_steps = []
        steps = self.__steps(start=start)
        first = True
        for step in (step_ for step_ in steps if step_ is not None):
            self._executing_step = step
            logger.debug('Executing step {0} of workflow {1}'.format(step, self.name))
            data_sent.send(self, callback_name="Next Step Found", object_type="Workflow")

            if self._is_paused:
                data_sent.send(self, callback_name="Workflow Paused", object_type="Workflow")
                while self._is_paused:
                    gevent.sleep(1)
                    continue
                data_sent.send(self, callback_name="Workflow Resumed", object_type="Workflow")

            device_id = self.__setup_app_instance(instances, step)
            step.render_step(steps=total_steps)

            if first:
                first = False
                if start_input:
                    self.__swap_step_input(step, start_input)
            self.__execute_step(step, instances[device_id])
            total_steps.append(step)
            self._accumulator[step.name] = step.get_output().result
        self.__shutdown(instances)
        yield
Esempio n. 8
0
 def __shutdown(self, instances):
     # Upon finishing shuts down instances
     for instance in instances:
         try:
             logger.debug('Shutting down app instance: Device: {0}'.format(instance))
             instances[instance].shutdown()
         except Exception as e:
             logger.error('Error caught while shutting down app instance. '
                          'Device: {0}. Error {1}'.format(instance, format_exception_message(e)))
     result_str = {}
     for step, step_result in self._accumulator.items():
         try:
             result_str[step] = json.dumps(step_result)
         except TypeError:
             logger.error('Result of workflow is neither string or a JSON-able. Cannot record')
             result_str[step] = 'error: could not convert to JSON'
     data = dict(self._accumulator)
     try:
         data_json = json.dumps(data)
     except TypeError:
         data_json = str(data)
     data_sent.send(self, callback_name="Workflow Shutdown", object_type="Workflow", data=data_json)
     logger.info('Workflow {0} completed. Result: {1}'.format(self.name, self._accumulator))
Esempio n. 9
0
    def execute(self, data_in, accumulator):
        """Executes the flag.

        Args:
            data_in: The input to the flag. Typically from the last step of the workflow or the input to a trigger.
            accumulator (dict): A record of executed steps and their results. Of form {step_name: result}.

        Returns:
            (bool): Is the flag true for the given data and accumulator
        """
        original_data_in = deepcopy(data_in)
        try:
            data_in = validate_parameter(data_in, self._data_in_api,
                                         'Filter {0}'.format(self.action))
            args = dereference_step_routing(self.args, accumulator,
                                            'In Filter {0}'.format(self.uid))
            args.update({self._data_in_api['name']: data_in})
            result = get_filter(self.action)(**args)
            data_sent.send(self,
                           callback_name="Filter Success",
                           object_type="Filter")
            return result
        except InvalidInput as e:
            data_sent.send(self,
                           callback_name="Filter Error",
                           object_type="Filter")
            logger.error('Filter {0} has invalid input {1}. Error: {2}. '
                         'Returning unmodified data'.format(
                             self.action, original_data_in, str(e)))
        except Exception as e:
            data_sent.send(self,
                           callback_name="Filter Error",
                           object_type="Filter")
            logger.error(
                'Filter {0} encountered an error: {1}. Returning unmodified data'
                .format(self.action, str(e)))
        return original_data_in
Esempio n. 10
0
    def execute(self, data_in, accumulator):
        data = data_in

        for filter_element in self.filters:
            data = filter_element.execute(data, accumulator)
        try:
            data = validate_parameter(data, self._data_in_api,
                                      'Flag {}'.format(self.action))
            args = dereference_step_routing(self.args, accumulator,
                                            'In Flag {}'.format(self.uid))
            data_sent.send(self,
                           callback_name="Flag Success",
                           object_type="Flag")
            logger.debug('Arguments passed to flag {} are valid'.format(
                self.uid))
            args.update({self._data_in_api['name']: data})
            return get_flag(self.action)(**args)
        except InvalidInput as e:
            logger.error(
                'Flag {0} has invalid input {1} which was converted to {2}. Error: {3}. '
                'Returning False'.format(self.action, data_in, data,
                                         format_exception_message(e)))
            data_sent.send(self,
                           callback_name="Flag Error",
                           object_type="Flag")
            return False
        except Exception as e:
            logger.error('Error encountered executing '
                         'flag {0} with arguments {1} and value {2}: '
                         'Error {3}. Returning False'.format(
                             self.action, self.args, data,
                             format_exception_message(e)))
            data_sent.send(self,
                           callback_name="Flag Error",
                           object_type="Flag")
            return False
Esempio n. 11
0
    def execute(self, instance, accumulator):
        """Executes a Step by calling the associated app function.

        Args:
            instance (App): The instance of an App object to be used to execute the associated function.
            accumulator (dict): Dict containing the results of the previous steps

        Returns:
            The result of the executed function.
        """
        self._execution_uid = uuid.uuid4().hex
        data_sent.send(self, callback_name="Step Started", object_type="Step")

        if self.triggers:
            data_sent.send(self,
                           callback_name="Trigger Step Awaiting Data",
                           object_type="Step")
            logger.debug('Trigger Step {} is awaiting data'.format(self.name))

            while True:
                try:
                    data = self._incoming_data.get(timeout=1)
                    self._incoming_data = AsyncResult()
                except gevent.Timeout:
                    gevent.sleep(0.1)
                    continue
                data_in = data['data_in']
                inputs = data['inputs'] if 'inputs' in data else {}

                if all(
                        flag.execute(data_in=data_in, accumulator=accumulator)
                        for flag in self.triggers):
                    data_sent.send(self,
                                   callback_name="Trigger Step Taken",
                                   object_type="Step")
                    logger.debug(
                        'Trigger is valid for input {0}'.format(data_in))
                    accumulator[self.name] = data_in

                    if inputs:
                        self.inputs.update(inputs)
                    break
                else:
                    logger.debug(
                        'Trigger is not valid for input {0}'.format(data_in))
                    data_sent.send(self,
                                   callback_name="Trigger Step Not Taken",
                                   object_type="Step")

                gevent.sleep(0.1)

        try:
            args = dereference_step_routing(self.inputs, accumulator,
                                            'In step {0}'.format(self.name))
            args = validate_app_action_parameters(self._input_api, args,
                                                  self.app, self.action)
            action = get_app_action(self.app, self._run)
            if is_app_action_bound(self.app, self._run):
                result = action(instance, **args)
            else:
                result = action(**args)

            data_sent.send(self,
                           callback_name="Function Execution Success",
                           object_type="Step",
                           data=json.dumps({"result": result.as_json()}))
        except InvalidInput as e:
            formatted_error = format_exception_message(e)
            logger.error('Error calling step {0}. Error: {1}'.format(
                self.name, formatted_error))
            data_sent.send(self,
                           callback_name="Step Input Invalid",
                           object_type="Step")
            self._output = ActionResult('error: {0}'.format(formatted_error),
                                        'InvalidInput')
            raise
        except Exception as e:
            formatted_error = format_exception_message(e)
            logger.error('Error calling step {0}. Error: {1}'.format(
                self.name, formatted_error))
            self._output = ActionResult('error: {0}'.format(formatted_error),
                                        'UnhandledException')
            raise
        else:
            self._output = result
            for widget in self.widgets:
                get_widget_signal(widget.app, widget.name).send(
                    self, data=json.dumps({"result": result.as_json()}))
            logger.debug('Step {0}-{1} (uid {2}) executed successfully'.format(
                self.app, self.action, self.uid))
            return result