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
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
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
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
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))))
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
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))))
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)))
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)))
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))
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)))
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
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))))
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
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
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())
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)))
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'
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
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)))
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
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
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
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)
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
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)
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
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
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())
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
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)
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
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
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
def from_exception(cls, exc, status): formatted_error = format_exception_message(exc) return cls('error: {0}'.format(formatted_error), status)