Example #1
0
    def load_playbook(resource):
        """Loads a playbook from a file.

        Args:
            resource (str): Path to the workflow.
        """
        try:
            playbook_file = open(resource, 'r')
        except (IOError, OSError) as e:
            logger.error(
                'Could not load workflow from {0}. Reason: {1}'.format(
                    resource, format_exception_message(e)))
            return None
        else:
            with playbook_file:
                workflow_loaded = playbook_file.read()
                try:
                    playbook_json = json.loads(workflow_loaded)
                    return Playbook.create(playbook_json)
                except ValueError as e:
                    logger.exception('Cannot parse {0}. Reason: {1}'.format(
                        resource, format_exception_message(e)))
                except (InvalidArgument, UnknownApp, UnknownAppAction,
                        UnknownTransform, UnknownCondition) as e:
                    logger.error('Error constructing playbook from {0}. '
                                 'Reason: {1}'.format(
                                     resource, format_exception_message(e)))
                    return None
Example #2
0
def validate_primitive_parameter(value, param, parameter_type, message_prefix, hide_input=False):
    try:
        converted_value = convert_primitive_type(value, parameter_type)
    except (ValueError, TypeError):
        message = '{0} has invalid input. ' \
                  'Input {1} could not be converted to type {2}'.format(message_prefix, value, parameter_type)
        logger.error(message)
        raise InvalidArgument(message)
    else:
        param = deepcopy(param)
        if param['type'] in ('user', 'role'):
            handle_user_roles_validation(param)

        if 'required' in param:
            param.pop('required')
        try:
            Draft4Validator(
                param, format_checker=draft4_format_checker).validate(converted_value)
        except ValidationError as exception:
            if not hide_input:
                message = '{0} has invalid input. ' \
                          'Input {1} with type {2} does not conform to ' \
                          'validators: {3}'.format(message_prefix, value, parameter_type,
                                                   format_exception_message(exception))
            else:
                message = '{0} has invalid input. {1} does not conform to ' \
                          'validators: {2}'.format(message_prefix, parameter_type,
                                                   format_exception_message(exception))
            logger.error(message)
            raise InvalidArgument(message)
        return converted_value
Example #3
0
 def __func():
     data = request.get_json()
     filename = (data['filename'] if
                 (data is not None and 'filename' in data
                  and data['filename']) else
                 walkoff.config.paths.default_case_export_path)
     if os.path.isfile(filename):
         try:
             with open(filename, 'r') as cases_file:
                 cases_file = cases_file.read()
                 cases_file = cases_file.replace('\n', '')
                 cases = json.loads(cases_file)
             case_subscription.add_cases(cases)
             for case in cases:
                 db.session.add(CaseSubscription(name=case))
                 CaseSubscription.update(case)
             db.session.commit()
             return {"cases": case_subscription.subscriptions}, SUCCESS
         except (OSError, IOError) as e:
             current_app.logger.error('Error importing cases from file '
                                      '{0}: {1}'.format(
                                          filename,
                                          format_exception_message(e)))
             return {"error": "Error reading file."}, IO_ERROR
         except ValueError as e:
             current_app.logger.error(
                 'Error importing cases from file {0}: '
                 'Invalid JSON {1}'.format(filename,
                                           format_exception_message(e)))
             return {"error": "Invalid JSON file."}, INVALID_INPUT_ERROR
     else:
         current_app.logger.debug(
             'Cases successfully imported from {0}'.format(filename))
         return {"error": "File does not exist."}, IO_ERROR
Example #4
0
def validate_parameter(value, param, message_prefix):
    param = deepcopy(param)
    primitive_type = 'primitive' if 'type' in param else 'object'
    converted_value = None
    if value is not None:
        if primitive_type == 'primitive':
            primitive_type = param['type']
            if primitive_type in TYPE_MAP:
                converted_value = validate_primitive_parameter(
                    value, param, primitive_type, message_prefix)
            elif primitive_type == 'array':
                try:
                    converted_value = convert_array(param, value,
                                                    message_prefix)
                    if 'items' in param and param['items']['type'] in ('user',
                                                                       'role'):
                        handle_user_roles_validation(param['items'])

                    Draft4Validator(
                        param, format_checker=draft4_format_checker).validate(
                            converted_value)
                except ValidationError as exception:
                    message = '{0} has invalid input. Input {1} does not conform to ' \
                              'validators: {2}'.format(message_prefix, value, format_exception_message(exception))
                    logger.error(message)
                    raise InvalidArgument(message)
            else:
                raise InvalidArgument(
                    'In {0}: Unknown parameter type {1}'.format(
                        message_prefix, primitive_type))
        else:
            try:
                converted_value = convert_json(param, value, message_prefix)
                Draft4Validator(param['schema'],
                                format_checker=draft4_format_checker).validate(
                                    converted_value)
            except ValidationError as exception:
                message = '{0} has invalid input. Input {1} does not conform to ' \
                          'validators: {2}'.format(message_prefix, value, format_exception_message(exception))
                logger.error(message)
                raise InvalidArgument(message)
    elif param.get('required'):
        message = "In {0}: Missing {1} parameter '{2}'".format(
            message_prefix, primitive_type, param['name'])
        logger.error(message)
        raise InvalidArgument(message)

    return converted_value
Example #5
0
def load_app_apis(apps_path=None):
    from walkoff.helpers import list_apps, format_exception_message
    global app_apis
    if apps_path is None:
        apps_path = walkoff.config.paths.apps_path
    try:
        with open(join(walkoff.config.paths.walkoff_schema_path),
                  'r') as schema_file:
            json.loads(schema_file.read())
    except Exception as e:
        __logger.fatal(
            'Could not load JSON schema for apps. Shutting down...: ' + str(e))
        sys.exit(1)
    else:
        for app in list_apps(apps_path):
            try:
                url = join(apps_path, app, 'api.yaml')
                with open(url) as function_file:
                    api = yaml.load(function_file.read())
                    from walkoff.appgateway.validator import validate_app_spec
                    validate_app_spec(api, app)
                    app_apis[app] = api
            except Exception as e:
                __logger.error(
                    'Cannot load apps api for app {0}: Error {1}'.format(
                        app, str(format_exception_message(e))))
Example #6
0
def import_device(app, device, device_type, fields):
    try:
        device_api = get_app_device_api(app, device_type)
        device_fields_api = device_api['fields']
        validate_device_fields(device_fields_api, fields, device_type, app)
    except UnknownDevice:
        current_app.logger.error('Cannot import device for app {0}, type {1}. '
                                 'Type does not exist'.format(
                                     app, device_type))
    except InvalidArgument as e:
        current_app.logger.error('Cannot import device for app {0}, type {1}. '
                                 'Invalid input'.format(
                                     app, device_type,
                                     format_exception_message(e)))
    else:
        fields = device['fields']
        add_configuration_keys_to_device_json(fields, device_fields_api)
        app = device_db.session.query(App).filter(App.name == app).first()
        if app is not None:
            device_obj = Device.from_json(device)
            app.add_device(device_obj)
            device_db.session.add(device_obj)
            device_db.session.commit()
        else:
            current_app.logger.error(
                'SEVERE: App defined in api does not have corresponding entry in database. '
                'Cannot import device')
    return app
Example #7
0
def load_app_apis(apps_path=None):
    """Loads App APIs
    
    Args:
        apps_path (str, optional): Optional path to specify for the apps. Defaults to None, but will be set to the
            apps_path variable in Config object
    """
    from walkoff.helpers import list_apps, format_exception_message
    global app_apis
    if apps_path is None:
        apps_path = Config.APPS_PATH
    try:
        with open(join(Config.WALKOFF_SCHEMA_PATH), 'r') as schema_file:
            json.loads(schema_file.read())
    except Exception as e:
        logger.fatal('Could not load JSON schema for apps. Shutting down...: ' + str(e))
        sys.exit(1)
    else:
        for app in list_apps(apps_path):
            try:
                url = join(apps_path, app, 'api.yaml')
                with open(url) as function_file:
                    api = yaml.load(function_file.read())
                    from walkoff.appgateway.validator import validate_app_spec
                    validate_app_spec(api, app, Config.WALKOFF_SCHEMA_PATH)
                    app_apis[app] = api
            except Exception as e:
                logger.error(
                    'Cannot load apps api for app {0}: Error {1}'.format(app, str(format_exception_message(e))))
Example #8
0
    def __func():
        config_in = request.get_json()
        if not _reset_token_durations(access_token_duration=config_in.get('access_token_duration', None),
                                      refresh_token_duration=config_in.get('refresh_token_duration', None)):
            return Problem.from_crud_resource(
                BAD_REQUEST,
                'configuration',
                'update',
                'Access token duration must be less than refresh token duration.')

        for config, config_value in config_in.items():
            if hasattr(walkoff.config.Config, config.upper()):
                setattr(walkoff.config.Config, config.upper(), config_value)
            elif hasattr(current_app.config, config.upper()):
                setattr(current_app.config, config.upper(), config_value)

        current_app.logger.info('Changed configuration')
        try:
            walkoff.config.Config.write_values_to_file()
            return __get_current_configuration(), SUCCESS
        except (IOError, OSError) as e:
            current_app.logger.error('Could not write changes to configuration to file')
            return Problem(
                IO_ERROR,
                'Could not write changes to file.',
                'Could not write configuration changes to file. Problem: {}'.format(format_exception_message(e)))
Example #9
0
    def __func():
        if not _reset_token_durations(access_token_duration=configuration.get(
                'access_token_duration', None),
                                      refresh_token_duration=configuration.get(
                                          'refresh_token_duration', None)):
            return Problem.from_crud_resource(
                BAD_REQUEST, 'configuration', 'update',
                'Access token duration must be less than refresh token duration.'
            )

        for config, config_value in configuration.items():
            if hasattr(walkoff.config.paths, config):
                setattr(walkoff.config.paths, config, config_value)
            elif hasattr(walkoff.config.config, config):
                setattr(walkoff.config.config, config, config_value)

        current_app.logger.info('Changed configuration')
        try:
            walkoff.config.config.write_values_to_file()
            return __get_current_configuration(), SUCCESS
        except (IOError, OSError) as e:
            current_app.logger.error(
                'Could not write changes to configuration to file')
            return Problem(
                IO_ERROR, 'Could not write changes to file.',
                'Could not write configuration changes to file. Problem: {}'.
                format(format_exception_message(e)))
Example #10
0
 def __shutdown(self, instances):
     # Upon finishing shuts down instances
     for instance_name, instance in instances.items():
         try:
             if instance() is not None:
                 logger.debug(
                     'Shutting down app instance: Device: {0}'.format(
                         instance_name))
                 instance.shutdown()
         except Exception as e:
             logger.error('Error caught while shutting down app instance. '
                          'Device: {0}. Error {1}'.format(
                              instance_name, format_exception_message(e)))
     result_str = {}
     for action, action_result in self._accumulator.items():
         try:
             result_str[action] = json.dumps(action_result)
         except TypeError:
             logger.error(
                 'Result of workflow is neither string or a JSON-able. Cannot record'
             )
             result_str[action] = 'error: could not convert to JSON'
     data = dict(self._accumulator)
     try:
         data_json = json.dumps(data)
     except TypeError:
         data_json = str(data)
     WalkoffEvent.CommonWorkflowSignal.send(
         self, event=WalkoffEvent.WorkflowShutdown, data=data_json)
     logger.info('Workflow {0} completed. Result: {1}'.format(
         self.name, self._accumulator))
Example #11
0
    def create(cls, json_in, element_class=None):
        """
        Creates an ExecutionElement from json

        Args:
            json_in (dict): The JSON to convert to an ExecutionElement
            element_class (cls): The class of the ExecutionElement to convert

        Returns:
            (ExecutionElement) The constructed ExecutionElement
        """
        from walkoff.core.executionelements.playbook import Playbook
        cls._setup_ordering()
        if element_class is None:
            element_class = Playbook
        class_iterator = iteritems(cls.playbook_class_ordering)
        current_class, subfield_lookup = next(class_iterator)
        while current_class != element_class:
            try:
                current_class, subfield_lookup = next(class_iterator)
            except StopIteration:
                raise ValueError('Unknown class {}'.format(
                    element_class.__class__.__name__))
        try:
            return cls.construct_current_class(current_class, json_in,
                                               subfield_lookup)
        except (KeyError, TypeError) as e:
            from walkoff.helpers import format_exception_message
            raise ValueError(
                'Improperly formatted JSON for ExecutionElement {0} {1}'.
                format(current_class.__name__, format_exception_message(e)))
Example #12
0
    def load_playbook(resource):
        """Loads a playbook from a file.

        Args:
            resource (str): Path to the workflow.
        """
        try:
            playbook_file = open(resource, 'r')
        except (IOError, OSError) as e:
            logger.error('Could not load workflow from {0}. Reason: {1}'.format(resource, format_exception_message(e)))
            return None
        else:
            with playbook_file:
                workflow_loaded = playbook_file.read()
                try:
                    playbook_json = json.loads(workflow_loaded)

                    playbook = PlaybookSchema().load(playbook_json)
                    return playbook
                except ValueError as e:
                    logger.exception('Cannot parse {0}. Reason: {1}'.format(resource, format_exception_message(e)))
                except (InvalidArgument, UnknownApp, UnknownAppAction, UnknownTransform, UnknownCondition) as e:
                    logger.error(
                        'Error constructing playbook from {0}. '
                        'Reason: {1}'.format(resource, format_exception_message(e)))
                    return None
Example #13
0
def load_app_apis(apps_path=None):
    """Loads App APIs
    
    Args:
        apps_path (str, optional): Optional path to specify for the apps. Defaults to None, but will be set to the
            apps_path variable in Config object
    """
    from walkoff.helpers import list_apps, format_exception_message
    global app_apis
    if apps_path is None:
        apps_path = Config.APPS_PATH
    try:
        with open(join(Config.WALKOFF_SCHEMA_PATH), 'r') as schema_file:
            json.loads(schema_file.read())
    except Exception as e:
        logger.fatal(
            'Could not load JSON schema for apps. Shutting down...: ' + str(e))
        sys.exit(1)
    else:
        for app in list_apps(apps_path):
            try:
                url = join(apps_path, app, 'api.yaml')
                with open(url) as function_file:
                    api = yaml.load(function_file.read())
                    from walkoff.appgateway.validator import validate_app_spec
                    validate_app_spec(api, app, Config.WALKOFF_SCHEMA_PATH)
                    app_apis[app] = api
            except Exception as e:
                logger.error(
                    'Cannot load apps api for app {0}: Error {1}'.format(
                        app, str(format_exception_message(e))))
Example #14
0
    def load_workflow(resource, workflow_name):
        """Loads a workflow from a file.

        Args:
            resource (str): Path to the workflow.
            workflow_name (str): Name of the workflow to load.

        Returns:
            True on success, False otherwise.
        """
        try:
            playbook_file = open(resource, 'r')
        except (IOError, OSError) as e:
            logger.error(
                'Could not load workflow from {0}. Reason: {1}'.format(
                    resource, format_exception_message(e)))
            return None
        else:
            with playbook_file:
                workflow_loaded = playbook_file.read()
                try:
                    playbook_json = json.loads(workflow_loaded)
                    playbook_name = playbook_json['name']
                    workflow_json = next(
                        (workflow for workflow in playbook_json['workflows']
                         if workflow['name'] == workflow_name), None)
                    if workflow_json is None:
                        logger.warning(
                            'Workflow {0} not found in playbook {0}. '
                            'Cannot load.'.format(workflow_name,
                                                  playbook_name))
                        return None
                    workflow = Workflow.create(workflow_json)
                    return playbook_name, workflow
                except ValueError as e:
                    logger.exception('Cannot parse {0}. Reason: {1}'.format(
                        resource, format_exception_message(e)))
                except (InvalidArgument, UnknownApp, UnknownAppAction,
                        UnknownTransform, UnknownCondition) as e:
                    logger.error(
                        'Error constructing workflow {0}. Reason: {1}'.format(
                            workflow_name, format_exception_message(e)))
                    return None
                except KeyError as e:
                    logger.error(
                        'Invalid Playbook JSON format. Details: {}'.format(e))
                    return None
Example #15
0
    def execute(self, data_in, accumulator):
        """Executes the Condition object, determining if the Condition evaluates to True or False.

        Args:
            data_in (): The input to the Transform objects associated with this Condition.
            accumulator (dict): The accumulated data from previous Actions.

        Returns:
            True if the Condition evaluated to True, False otherwise
        """
        data = data_in

        for transform in self.transforms:
            data = transform.execute(data, accumulator)
        try:
            self.arguments.update({
                self._data_param_name:
                Argument(self._data_param_name, value=data)
            })
            args = validate_condition_parameters(self._api,
                                                 self.arguments,
                                                 self.action_name,
                                                 accumulator=accumulator)
            logger.debug('Arguments passed to condition {} are valid'.format(
                self.uid))
            ret = self._condition_executable(**args)
            WalkoffEvent.CommonWorkflowSignal.send(
                self, event=WalkoffEvent.ConditionSuccess)
            return ret
        except InvalidArgument as e:
            logger.error(
                'Condition {0} has invalid input {1} which was converted to {2}. Error: {3}. '
                'Returning False'.format(self.action_name, data_in, data,
                                         format_exception_message(e)))
            WalkoffEvent.CommonWorkflowSignal.send(
                self, event=WalkoffEvent.ConditionError)
            return False
        except Exception as e:
            logger.error('Error encountered executing '
                         'condition {0} with arguments {1} and value {2}: '
                         'Error {3}. Returning False'.format(
                             self.action_name, self.arguments, data,
                             format_exception_message(e)))
            WalkoffEvent.CommonWorkflowSignal.send(
                self, event=WalkoffEvent.ConditionError)
            return False
Example #16
0
 def __handle_execution_error(self, e):
     formatted_error = format_exception_message(e)
     if isinstance(e, InvalidArgument):
         event = WalkoffEvent.ActionArgumentsInvalid
         return_type = 'InvalidArguments'
     else:
         event = WalkoffEvent.ActionExecutionError
         return_type = 'UnhandledException'
     self._output = ActionResult('error: {0}'.format(formatted_error), return_type)
     WalkoffEvent.CommonWorkflowSignal.send(self, event=event, data=self._output.as_json())
Example #17
0
 def shutdown_instances(self):
     """Calls the shutdown() method on all of the AppInstance objects"""
     for instance_name, instance in self._instances.items():
         try:
             if instance() is not None:
                 logger.debug('Shutting down app instance: Device: {0}'.format(instance_name))
                 instance.shutdown()
         except Exception as e:
             logger.exception('Error caught while shutting down app instance. '
                              'Device: {0}. Error {1}'.format(instance_name, format_exception_message(e)))
Example #18
0
def read_json(filename):
    if not os.path.exists(filename) or not os.path.isfile(filename):
        return 'File does not exist', 'FileDoesNotExist'
    try:
        with open(filename, 'r') as file_in:
            return json.loads(file_in.read())
    except (IOError, IOError) as e:
        return {'error': 'Could not read file', 'reason': format_exception_message(e)}, 'FileDoesNotExist'
    except ValueError:
        return 'Could not read file as json. Invalid JSON', 'InvalidJson'
Example #19
0
 def resume(self):
     """Resumes a Workflow that has previously been paused.
     """
     try:
         logger.info('Attempting to resume workflow {0}'.format(self.name))
         self._is_paused = False
         self._resume.set()
     except (StopIteration, AttributeError) as e:
         logger.warning('Cannot resume workflow {0}. Reason: {1}'.format(
             self.name, format_exception_message(e)))
         pass
Example #20
0
 def shutdown_instances(self):
     for instance_name, instance in self._instances.items():
         try:
             if instance() is not None:
                 logger.debug(
                     'Shutting down app instance: Device: {0}'.format(
                         instance_name))
                 instance.shutdown()
         except Exception as e:
             logger.error('Error caught while shutting down app instance. '
                          'Device: {0}. Error {1}'.format(
                              instance_name, format_exception_message(e)))
Example #21
0
def validate_parameter(value, param, message_prefix):
    param = deepcopy(param)
    primitive_type = 'primitive' if 'type' in param else 'object'
    converted_value = None
    if value is not None:
        if primitive_type == 'primitive':
            primitive_type = param['type']
            if primitive_type in TYPE_MAP:
                converted_value = validate_primitive_parameter(value, param, primitive_type, message_prefix)
            elif primitive_type == 'array':
                try:
                    converted_value = convert_array(param, value, message_prefix)
                    if 'items' in param and param['items']['type'] in ('user', 'role'):
                        handle_user_roles_validation(param['items'])

                    Draft4Validator(
                        param, format_checker=draft4_format_checker).validate(converted_value)
                except ValidationError as exception:
                    message = '{0} has invalid input. Input {1} does not conform to ' \
                              'validators: {2}'.format(message_prefix, value, format_exception_message(exception))
                    logger.error(message)
                    raise InvalidArgument(message)
            else:
                raise InvalidArgument('In {0}: Unknown parameter type {1}'.format(message_prefix, primitive_type))
        else:
            try:
                converted_value = convert_json(param, value, message_prefix)
                Draft4Validator(
                    param['schema'], format_checker=draft4_format_checker).validate(converted_value)
            except ValidationError as exception:
                message = '{0} has invalid input. Input {1} does not conform to ' \
                          'validators: {2}'.format(message_prefix, value, format_exception_message(exception))
                logger.error(message)
                raise InvalidArgument(message)
    elif param.get('required'):
        message = "In {0}: Missing {1} parameter '{2}'".format(message_prefix, primitive_type, param['name'])
        logger.error(message)
        raise InvalidArgument(message)

    return converted_value
Example #22
0
def validate_devices_api(devices_api, app_name):
    for device_type, device_type_api in devices_api.items():
        for field_api in device_type_api['fields']:
            if 'default' in field_api:
                message_prefix = 'App {0} device type {1}'.format(app_name, device_type)
                default_value = field_api['default']
                try:
                    validate_device_field(field_api, default_value, message_prefix)
                except InvalidArgument as e:
                    logger.error(
                        'For {0}: Default input {1} does not conform to schema. (Error: {2})'
                        'Using anyways'.format(message_prefix, field_api['name'], format_exception_message(e)))
                    raise
Example #23
0
def validate_parameters(api, arguments, message_prefix, accumulator=None):
    api_dict = {}
    for param in api:
        api_dict[param['name']] = param
    converted = {}
    seen_params = set()
    arg_names = [argument.name for argument in arguments] if arguments else []
    arguments_set = set(arg_names)
    errors = []
    for param_name, param_api in api_dict.items():
        try:
            argument = get_argument_by_name(arguments, param_name)
            if argument:
                arg_val = argument.get_value(accumulator)
                if accumulator or not argument.is_ref:
                    converted[param_name] = validate_parameter(
                        arg_val, param_api, message_prefix)
            elif 'default' in param_api:
                try:
                    default_param = validate_parameter(param_api['default'],
                                                       param_api,
                                                       message_prefix)
                except InvalidArgument as e:
                    default_param = param_api['default']
                    logger.warning(
                        'For {0}: Default input {1} (value {2}) does not conform to schema. (Error: {3})'
                        'Using anyways'.format(message_prefix, param_name,
                                               param_api['default'],
                                               format_exception_message(e)))

                converted[param_name] = default_param
                arguments_set.add(param_name)
            elif 'required' in param_api:
                message = 'For {0}: Parameter {1} is not specified and has no default'.format(
                    message_prefix, param_name)
                logger.error(message)
                raise InvalidArgument(message)
            else:
                converted[param_name] = None
                arguments_set.add(param_name)
            seen_params.add(param_name)
        except InvalidArgument as e:
            errors.append(e.message)
    if seen_params != arguments_set:
        message = 'For {0}: Too many arguments. Extra arguments: {1}'.format(
            message_prefix, arguments_set - seen_params)
        logger.error(message)
        errors.append(message)
    if errors:
        raise InvalidArgument('Invalid arguments', errors=errors)
    return converted
Example #24
0
 def __swap_action_arguments(self, action, start_arguments):
     logger.debug(
         'Swapping arguments to first action of workflow {0}'.format(
             self.name))
     try:
         action.set_arguments(start_arguments)
         WalkoffEvent.CommonWorkflowSignal.send(
             self, event=WalkoffEvent.WorkflowArgumentsValidated)
     except InvalidArgument as e:
         logger.error('Cannot change arguments to workflow {0}. '
                      'Invalid arguments. Error: {1}'.format(
                          self.name, format_exception_message(e)))
         WalkoffEvent.CommonWorkflowSignal.send(
             self, event=WalkoffEvent.WorkflowArgumentsInvalid)
Example #25
0
    def execute(self, action_execution_strategy, data_in, accumulator):
        """Executes the Condition object, determining if the Condition evaluates to True or False.

        Args:
            action_execution_strategy: The strategy used to execute the action (e.g. LocalActionExecutionStrategy)
            data_in (dict): The input to the Transform objects associated with this Condition.
            accumulator (dict): The accumulated data from previous Actions.

        Returns:
            (bool): True if the Condition evaluated to True, False otherwise
        """
        data = data_in

        for transform in self.transforms:
            data = transform.execute(action_execution_strategy, data,
                                     accumulator)
        try:
            arguments = self.__update_arguments_with_data(data)
            args = validate_condition_parameters(self._api,
                                                 arguments,
                                                 self.action_name,
                                                 accumulator=accumulator)
        except InvalidArgument as e:
            logger.error(
                'Condition {0} has invalid input {1} which was converted to {2}. Error: {3}. '
                'Returning False'.format(self.action_name, data_in, data,
                                         format_exception_message(e)))
            WalkoffEvent.CommonWorkflowSignal.send(
                self, event=WalkoffEvent.ConditionError)
            return False

        try:
            logger.debug('Arguments passed to condition {} are valid'.format(
                self.id))
            ret = action_execution_strategy.execute(self, accumulator, args)
            WalkoffEvent.CommonWorkflowSignal.send(
                self, event=WalkoffEvent.ConditionSuccess)
            if self.is_negated:
                return not ret
            else:
                return ret

        except ExecutionError:
            logger.exception(
                'Error encountered executing condition {0} with arguments {1} and value {2}: Returning False'
                .format(self.action_name, arguments, data))
            WalkoffEvent.CommonWorkflowSignal.send(
                self, event=WalkoffEvent.ConditionError)
            return False
Example #26
0
def write_playbook_to_file(playbook_name):
    """Writes a playbook to file.

    Args:
        playbook_name (str): The name of the playbook to write to a file.
    """
    playbook_filename = os.path.join(walkoff.config.paths.workflows_path,
                                     '{0}.playbook'.format(playbook_name))
    backup = None
    try:
        with open(playbook_filename) as original_file:
            backup = original_file.read()
        os.remove(playbook_filename)
    except (IOError, OSError) as e:
        logger.warning('Cannot read original playbook! Saving without backup! '
                       'Reason: {}'.format(
                           helpers.format_exception_message(e)))

    app.logger.debug('Writing playbook {0} to file'.format(playbook_name))

    try:
        with open(playbook_filename, 'w') as workflow_out:
            playbook_json = running_context.controller.get_playbook_representation(
                playbook_name)
            workflow_out.write(
                json.dumps(playbook_json,
                           sort_keys=True,
                           indent=4,
                           separators=(',', ': ')))
    except Exception as e:
        logger.error(
            'Could not save playbook to file. Reverting file to original. '
            'Error: {0}'.format(helpers.format_exception_message(e)))
        if backup is not None:
            with open(playbook_filename, 'w') as f:
                f.write(backup)
Example #27
0
def validate_primitive_parameter(value,
                                 param,
                                 parameter_type,
                                 message_prefix,
                                 hide_input=False):
    try:
        converted_value = convert_primitive_type(value, parameter_type)
    except (ValueError, TypeError):
        message = '{0} has invalid input. ' \
                  'Input {1} could not be converted to type {2}'.format(message_prefix, value, parameter_type)
        logger.error(message)
        raise InvalidArgument(message)
    else:
        param = deepcopy(param)
        if param['type'] in ('user', 'role'):
            handle_user_roles_validation(param)

        if 'required' in param:
            param.pop('required')
        try:
            Draft4Validator(
                param,
                format_checker=draft4_format_checker).validate(converted_value)
        except ValidationError as exception:
            if not hide_input:
                message = '{0} has invalid input. ' \
                          'Input {1} with type {2} does not conform to ' \
                          'validators: {3}'.format(message_prefix, value, parameter_type,
                                                   format_exception_message(exception))
            else:
                message = '{0} has invalid input. {1} does not conform to ' \
                          'validators: {2}'.format(message_prefix, parameter_type,
                                                   format_exception_message(exception))
            logger.error(message)
            raise InvalidArgument(message)
        return converted_value
Example #28
0
def validate_parameters(api, arguments, message_prefix, accumulator=None):
    api_dict = {}
    for param in api:
        api_dict[param['name']] = param
    converted = {}
    seen_params = set()
    arg_names = [argument.name for argument in arguments] if arguments else []
    arguments_set = set(arg_names)
    errors = []
    for param_name, param_api in api_dict.items():
        try:
            argument = get_argument_by_name(arguments, param_name)
            if argument:
                arg_val = argument.get_value(accumulator)
                if accumulator or not argument.is_ref:
                    converted[param_name] = validate_parameter(arg_val, param_api, message_prefix)
            elif 'default' in param_api:
                try:
                    default_param = validate_parameter(param_api['default'], param_api, message_prefix)
                except InvalidArgument as e:
                    default_param = param_api['default']
                    logger.warning(
                        'For {0}: Default input {1} (value {2}) does not conform to schema. (Error: {3})'
                        'Using anyways'.format(message_prefix, param_name, param_api['default'],
                                               format_exception_message(e)))

                converted[param_name] = default_param
                arguments_set.add(param_name)
            elif 'required' in param_api:
                message = 'For {0}: Parameter {1} is not specified and has no default'.format(message_prefix,
                                                                                              param_name)
                logger.error(message)
                raise InvalidArgument(message)
            else:
                converted[param_name] = None
                arguments_set.add(param_name)
            seen_params.add(param_name)
        except InvalidArgument as e:
            errors.append(e.message)
    if seen_params != arguments_set:
        message = 'For {0}: Too many arguments. Extra arguments: {1}'.format(message_prefix,
                                                                             arguments_set - seen_params)
        logger.error(message)
        errors.append(message)
    if errors:
        raise InvalidArgument('Invalid arguments', errors=errors)
    return converted
Example #29
0
def validate_devices_api(devices_api, app_name):
    for device_type, device_type_api in devices_api.items():
        for field_api in device_type_api['fields']:
            if 'default' in field_api:
                message_prefix = 'App {0} device type {1}'.format(
                    app_name, device_type)
                default_value = field_api['default']
                try:
                    validate_device_field(field_api, default_value,
                                          message_prefix)
                except InvalidArgument as e:
                    logger.error(
                        'For {0}: Default input {1} does not conform to schema. (Error: {2})'
                        'Using anyways'.format(message_prefix,
                                               field_api['name'],
                                               format_exception_message(e)))
                    raise
Example #30
0
 def __handle_execution_error(self, e):
     formatted_error = format_exception_message(e)
     if isinstance(e, InvalidArgument):
         event = WalkoffEvent.ActionArgumentsInvalid
         return_type = 'InvalidArguments'
     else:
         event = WalkoffEvent.ActionExecutionError
         return_type = 'UnhandledException'
     logger.warning('Exception in {0}: \n{1}'.format(
         self.name, traceback.format_exc()))
     logger.error('Error calling action {0}. Error: {1}'.format(
         self.name, formatted_error))
     self._output = ActionResult('error: {0}'.format(formatted_error),
                                 return_type)
     WalkoffEvent.CommonWorkflowSignal.send(self,
                                            event=event,
                                            data=self._output.as_json())
Example #31
0
 def __func():
     data = request.get_json()
     filename = (data['filename'] if
                 (data is not None and 'filename' in data
                  and data['filename']) else
                 walkoff.config.paths.default_case_export_path)
     try:
         with open(filename, 'w') as cases_file:
             cases_file.write(json.dumps(case_subscription.subscriptions))
         current_app.logger.debug(
             'Cases successfully exported to {0}'.format(filename))
         return SUCCESS
     except (OSError, IOError) as e:
         current_app.logger.error(
             'Error exporting cases to {0}: {1}'.format(
                 filename, format_exception_message(e)))
         return {"error": "Could not write to file."}, IO_ERROR
Example #32
0
 def create(app_name, device_name):
     """Creates a new Instance object from an app name and a device name.
     
     Args:
         app_name (str): The name of the app from which to import the main module.
         device_name (str): A device pertaining to the App.
         
     Returns:
         A new Instance object.
     """
     try:
         return AppInstance(instance=get_app(app_name)(name=app_name, device=device_name))
     except Exception as e:
         if device_name:
             logger.error('Cannot create app instance. app: {0}, device: {1}. '
                          'Error: {2}'.format(app_name, device_name, format_exception_message(e)))
         return AppInstance(instance=None)
Example #33
0
def validate_parameters(api, inputs, message_prefix, accumulator=None):
    api_dict = {}
    for param in api:
        api_dict[param['name']] = param
    converted = {}
    seen_params = set()
    input_set = set(inputs.keys())
    for param_name, param_api in api_dict.items():
        if param_name in inputs:
            arg_val = inputs[param_name].get_value(accumulator)
            if accumulator or not inputs[param_name].is_ref():
                converted[param_name] = validate_parameter(
                    arg_val, param_api, message_prefix)
        elif 'default' in param_api:
            try:
                default_param = validate_parameter(param_api['default'],
                                                   param_api, message_prefix)
            except InvalidArgument as e:
                default_param = param_api['default']
                logger.warning(
                    'For {0}: Default input {1} (value {2}) does not conform to schema. (Error: {3})'
                    'Using anyways'.format(message_prefix, param_name,
                                           param_api['default'],
                                           format_exception_message(e)))

            converted[param_name] = default_param
            input_set.add(param_name)
        elif 'required' in param_api:
            message = 'For {0}: Parameter {1} is not specified and has no default'.format(
                message_prefix, param_name)
            logger.error(message)
            raise InvalidArgument(message)
        else:
            converted[param_name] = None
            input_set.add(param_name)
        seen_params.add(param_name)
    if seen_params != input_set:
        message = 'For {0}: Too many inputs. Extra inputs: {1}'.format(
            message_prefix, input_set - seen_params)
        logger.error(message)
        raise InvalidArgument(message)
    return converted
Example #34
0
    def execute(self, action_execution_strategy, data_in, accumulator):
        """Executes the Condition object, determining if the Condition evaluates to True or False.

        Args:
            action_execution_strategy: The strategy used to execute the action (e.g. LocalActionExecutionStrategy)
            data_in (dict): The input to the Transform objects associated with this Condition.
            accumulator (dict): The accumulated data from previous Actions.

        Returns:
            (bool): True if the Condition evaluated to True, False otherwise
        """
        data = data_in

        for transform in self.transforms:
            data = transform.execute(action_execution_strategy, data, accumulator)
        try:
            arguments = self.__update_arguments_with_data(data)
            args = validate_condition_parameters(self._api, arguments, self.action_name, accumulator=accumulator)
        except InvalidArgument as e:
            logger.error('Condition {0} has invalid input {1} which was converted to {2}. Error: {3}. '
                         'Returning False'.format(self.action_name, data_in, data, format_exception_message(e)))
            WalkoffEvent.CommonWorkflowSignal.send(self, event=WalkoffEvent.ConditionError)
            return False

        try:
            logger.debug('Arguments passed to condition {} are valid'.format(self.id))
            ret = action_execution_strategy.execute(self, accumulator, args)
            WalkoffEvent.CommonWorkflowSignal.send(self, event=WalkoffEvent.ConditionSuccess)
            if self.is_negated:
                return not ret
            else:
                return ret

        except ExecutionError:
            logger.exception(
                'Error encountered executing condition {0} with arguments {1} and value {2}: Returning False'.format(
                    self.action_name, arguments, data))
            WalkoffEvent.CommonWorkflowSignal.send(self, event=WalkoffEvent.ConditionError)
            return False
Example #35
0
    def load_workflow(resource, workflow_name):
        """Loads a workflow from a file.

        Args:
            resource (str): Path to the workflow.
            workflow_name (str): Name of the workflow to load.

        Returns:
            True on success, False otherwise.
        """
        try:
            playbook_file = open(resource, 'r')
        except (IOError, OSError) as e:
            logger.error('Could not load workflow from {0}. Reason: {1}'.format(resource, format_exception_message(e)))
            return None
        else:
            with playbook_file:
                workflow_loaded = playbook_file.read()
                try:
                    playbook_json = json.loads(workflow_loaded)
                    playbook_name = playbook_json['name']
                    workflow_json = next(
                        (workflow for workflow in playbook_json['workflows']
                         if workflow['name'] == workflow_name), None)
                    if workflow_json is None:
                        logger.warning('Workflow {0} not found in playbook {0}. '
                                       'Cannot load.'.format(workflow_name, playbook_name))
                        return None
                    workflow = WorkflowSchema().load(workflow_json)
                    return playbook_name, workflow
                except ValueError as e:
                    logger.exception('Cannot parse {0}. Reason: {1}'.format(resource, format_exception_message(e)))
                except (InvalidArgument, UnknownApp, UnknownAppAction, UnknownTransform, UnknownCondition) as e:
                    logger.error('Error constructing workflow {0}. Reason: {1}'.format(workflow_name,
                                                                                       format_exception_message(e)))
                    return None
                except KeyError as e:
                    logger.error('Invalid Playbook JSON format. Details: {}'.format(e))
                    return None
Example #36
0
 def from_exception(cls, exc, status):
     formatted_error = format_exception_message(exc)
     return cls('error: {0}'.format(formatted_error), status)