def act_on_messages(): from walkoff.messaging import MessageAction @jwt_required @permissions_accepted_for_resources( ResourcePermissions('messages', ['update'])) def other_action_func(action_): return act_on_message_helper(action_) @jwt_required @permissions_accepted_for_resources( ResourcePermissions('messages', ['delete'])) def delete_message_action(): return act_on_message_helper(MessageAction.delete) action = MessageAction.convert_string(request.get_json()['action']) if action is None or action == MessageAction.respond: possible_actions = [ action.name for action in MessageAction if action != MessageAction.respond ] return Problem( OBJECT_DNE_ERROR, 'Unknown action on messages.', 'Unknown action: {0}. Possible actions are {1}.'.format( action, possible_actions)) if action == MessageAction.delete: return delete_message_action() else: return other_action_func(action)
def read_app_metrics(): @jwt_required @permissions_accepted_for_resources(ResourcePermissions('metrics', ['read'])) def __func(): return _convert_action_time_averages(), SUCCESS return __func()
def update_case(): @jwt_required @permissions_accepted_for_resources( ResourcePermissions('cases', ['update'])) def __func(): data = request.get_json() case_obj = CaseSubscription.query.filter_by(id=data['id']).first() if case_obj: original_name = case_obj.name case = current_app.running_context.case_db.session.query( case_database.Case).filter( case_database.Case.name == original_name).first() if 'note' in data and data['note']: case_obj.note = data['note'] if 'name' in data and data['name']: case_obj.name = data['name'] if case: case.name = data['name'] current_app.running_context.case_db.session.commit() current_app.logger.debug( 'Case name changed from {0} to {1}'.format( original_name, data['name'])) if 'subscriptions' in data: case_obj.subscriptions = data['subscriptions'] subscriptions = convert_subscriptions(data['subscriptions']) subscriptions, controller_subscriptions = split_subscriptions( subscriptions) current_app.running_context.executor.update_case( case.id, subscriptions) if controller_subscriptions: current_app.running_context.case_logger.update_subscriptions( case.id, subscriptions) db.session.commit() return case_obj.as_json(), SUCCESS else:
def delete_case(case_id): @jwt_required @permissions_accepted_for_resources( ResourcePermissions('cases', ['delete'])) def __func(): case_obj = CaseSubscription.query.filter_by(id=case_id).first() if case_obj: case_name = case_obj.name db.session.delete(case_obj) db.session.commit() case = current_app.running_context.case_db.session.query( case_database.Case).filter( case_database.Case.name == case_name).first() if case: current_app.running_context.executor.delete_case(case_id) current_app.running_context.case_logger.delete_case(case_id) current_app.running_context.case_db.session.delete(case) current_app.running_context.case_db.commit() current_app.logger.debug('Case deleted {0}'.format(case_id)) return None, NO_CONTENT else: current_app.logger.error( 'Cannot delete case {0}. Case does not exist.'.format(case_id)) return Problem.from_crud_resource( OBJECT_DNE_ERROR, 'case', 'delete', 'Case {} does not exist.'.format(case_id)) return __func()
def clear_workflow_status(all=False, days=30): @jwt_required @permissions_accepted_for_resources( ResourcePermissions('playbooks', ['read'])) def __func(): if all: current_app.running_context.execution_db.session.query( WorkflowStatus).filter( or_(WorkflowStatus.status == WorkflowStatusEnum.aborted, WorkflowStatus.status == WorkflowStatusEnum.completed)).delete() elif days > 0: delete_date = datetime.datetime.today() - datetime.timedelta( days=days) current_app.running_context.execution_db.session.query( WorkflowStatus).filter( and_( WorkflowStatus.status.in_([ WorkflowStatusEnum.aborted, WorkflowStatusEnum.completed ]), WorkflowStatus.completed_at <= delete_date)).delete( synchronize_session=False) current_app.running_context.execution_db.session.commit() return None, NO_CONTENT return __func()
def read_all_scheduled_tasks(): @jwt_required @permissions_accepted_for_resources(ResourcePermissions('scheduler', ['read'])) def __func(): return [task.as_json() for task in ScheduledTask.query.all()], SUCCESS return __func()
def read_config_values(): @jwt_required @permissions_accepted_for_resources(ResourcePermissions('configuration', ['read'])) def __func(): return __get_current_configuration(), SUCCESS return __func()
def read_all_app_apis(field_name=None): @jwt_required @permissions_accepted_for_resources( ResourcePermissions('app_apis', ['read'])) def __func(): # TODO: Remove this once connexion can validate enums with openapi3. if field_name and field_name not in [ 'info', 'action_apis', 'condition_apis', 'transform_apis', 'device_apis', 'tags', 'external_docs' ]: return Problem(BAD_REQUEST, 'Could not read app api.', '{} is not a valid field name.'.format(field_name)) ret = [] for app_name, app_api in walkoff.config.app_apis.items(): ret.append(format_full_app_api(app_api, app_name)) if field_name is not None: default = [] if field_name not in ('info', 'external_docs') else {} ret = [{ 'name': api['name'], field_name: api.get(field_name, default) } for api in ret] return ret, SUCCESS return __func()
def create_user(): @jwt_required @permissions_accepted_for_resources( ResourcePermissions('users', ['create'])) def __func(): data = request.get_json() username = data['username'] if not User.query.filter_by(username=username).first(): user = add_user(username=username, password=data['password']) if 'roles' in data or 'active' in data: role_update_user_fields(data, user) db.session.commit() current_app.logger.info('User added: {0}'.format(user.as_json())) return user.as_json(), OBJECT_CREATED else: current_app.logger.warning( 'Could not create user {0}. User already exists.'.format( username)) return { "error": "User {0} already exists.".format(username) }, OBJECT_EXISTS_ERROR return __func()
def read_available_resource_actions(): @jwt_required @permissions_accepted_for_resources(ResourcePermissions('roles', ['read'])) def __func(): return get_all_available_resource_actions(), SUCCESS return __func()
def update_workflow(): data = request.get_json() workflow_id = data['id'] @jwt_required @permissions_accepted_for_resources( ResourcePermissions('playbooks', ['update'])) @with_workflow('update', workflow_id) def __func(workflow): errors = workflow_schema.load(data, instance=workflow).errors if errors: return Problem.from_crud_resource( INVALID_INPUT_ERROR, 'workflow', 'update', 'Could not update workflow {}. Invalid input.'.format( workflow_id), ext=errors) try: current_app.running_context.execution_db.session.commit() except IntegrityError: current_app.running_context.execution_db.session.rollback() current_app.logger.error( 'Could not update workflow {}. Unique constraint failed'. format(workflow_id)) return unique_constraint_problem('workflow', 'update', workflow_id) current_app.logger.info('Updated workflow {0}'.format(workflow_id)) return workflow_schema.dump(workflow).data, SUCCESS return __func()
def send_data_to_trigger(): @jwt_required @permissions_accepted_for_resources( ResourcePermissions('playbooks', ['execute'])) def __func(): data = request.get_json() workflows_in = set(data['execution_ids']) data_in = data['data_in'] arguments = data['arguments'] if 'arguments' in data else [] workflows_awaiting_data = set( current_app.running_context.executor.get_waiting_workflows()) execution_ids = set.intersection(workflows_in, workflows_awaiting_data) user_id = get_jwt_identity() authorization_not_required, authorized_execution_ids = get_authorized_execution_ids( execution_ids, user_id, get_jwt_claims().get('roles', [])) execution_ids = list(authorized_execution_ids | authorization_not_required) completed_execution_ids = [] arg_objects = [] for arg in arguments: arg_objects.append(Argument(**arg)) for execution_id in execution_ids: if current_app.running_context.executor.resume_trigger_step( execution_id, data_in, arg_objects): completed_execution_ids.append(execution_id) log_action_taken_on_message(user_id, execution_id) return completed_execution_ids, SUCCESS return __func()
def create_workflow(playbook_name): from walkoff.server.context import running_context @jwt_required @permissions_accepted_for_resources( ResourcePermissions('playbooks', ['create'])) def __func(): data = request.get_json() workflow_name = data['name'] if running_context.controller.is_workflow_registered( playbook_name, workflow_name): current_app.logger.warning( 'Could not create workflow {0}. Workflow already exists.'. format(workflow_name)) return {"error": "Workflow already exists."}, OBJECT_EXISTS_ERROR running_context.controller.create_workflow(playbook_name, workflow_name) current_app.logger.info('Workflow {0}-{1} created'.format( playbook_name, workflow_name)) if running_context.controller.is_workflow_registered( playbook_name, workflow_name): workflow = running_context.controller.get_workflow( playbook_name, workflow_name) return workflow.read(), OBJECT_CREATED else: current_app.logger.error('Could not add workflow {0}-{1}'.format( playbook_name, workflow_name)) return {'error': 'Could not add workflow.'}, INVALID_INPUT_ERROR return __func()
def resume_workflow(playbook_name, workflow_name): from walkoff.server.context import running_context @jwt_required @permissions_accepted_for_resources( ResourcePermissions('playbooks', ['execute'])) @validate_workflow_is_registered('resume', playbook_name, workflow_name) def __func(): data = request.get_json() execution_uid = data['id'] status = running_context.controller.executor.get_workflow_status( execution_uid) if status == 2: # WORKFLOW_PAUSED if running_context.controller.resume_workflow(execution_uid): current_app.logger.info('Resumed workflow {0}-{1}:{2}'.format( playbook_name, workflow_name, execution_uid)) return {"info": "Workflow resumed"}, SUCCESS else: return {"error": "Invalid UUID."}, INVALID_INPUT_ERROR elif status == 1: return {"info": "Workflow already running"}, SUCCESS elif status == 0: return {"error": 'Invalid UUID'}, INVALID_INPUT_ERROR else: return {"error": 'Workflow stopped or awaiting data'} return __func()
def delete_playbook(playbook_name): from walkoff.server.context import running_context @jwt_required @permissions_accepted_for_resources( ResourcePermissions('playbooks', ['delete'])) @validate_playbook_is_registered('delete', playbook_name) def __func(): running_context.controller.remove_playbook(playbook_name) current_app.logger.info( 'Deleted playbook {0} from controller'.format(playbook_name)) if playbook_name in [ os.path.splitext(playbook)[0] for playbook in helpers.locate_playbooks_in_directory() ]: try: os.remove( os.path.join(walkoff.config.paths.workflows_path, '{0}.playbook'.format(playbook_name))) current_app.logger.info( 'Deleted playbook {0} from workflow directory'.format( playbook_name)) except (IOError, OSError) as e: current_app.logger.error( 'Error deleting playbook {0}: {1}'.format( playbook_name, e)) return { 'error': 'Error occurred while remove playbook file: {0}.'.format(e) }, IO_ERROR return {}, SUCCESS return __func()
def copy_playbook(playbook_name): from walkoff.server.context import running_context from walkoff.server.flaskserver import write_playbook_to_file @jwt_required @permissions_accepted_for_resources( ResourcePermissions('playbooks', ['create', 'read'])) @validate_playbook_is_registered('copy', playbook_name) def __func(): data = request.get_json() if 'playbook' in data and data['playbook']: new_playbook_name = data['playbook'] else: new_playbook_name = playbook_name + "_Copy" if running_context.controller.is_playbook_registered( new_playbook_name): current_app.logger.error('Cannot copy playbook {0} to {1}. ' 'Name already exists'.format( playbook_name, new_playbook_name)) return {"error": 'Playbook already exists.'}, OBJECT_EXISTS_ERROR else: running_context.controller.copy_playbook(playbook_name, new_playbook_name) write_playbook_to_file(new_playbook_name) current_app.logger.info('Copied playbook {0} to {1}'.format( playbook_name, new_playbook_name)) return running_context.controller.get_all_workflows(), OBJECT_CREATED return __func()
def update_configuration(configuration): @jwt_required @permissions_accepted_for_resources( ResourcePermissions('configuration', ['update'])) 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))) return __func()
def update_scheduler_status(): @jwt_required @permissions_accepted_for_resources( ResourcePermissions('scheduler', ['update', 'execute'])) def __func(): status = request.get_json()['status'] updated_status = current_app.running_context.scheduler.scheduler.state if status == "start": updated_status = current_app.running_context.scheduler.start() current_app.logger.info( 'Scheduler started. Status {0}'.format(updated_status)) elif status == "stop": updated_status = current_app.running_context.scheduler.stop() current_app.logger.info( 'Scheduler stopped. Status {0}'.format(updated_status)) elif status == "pause": updated_status = current_app.running_context.scheduler.pause() current_app.logger.info( 'Scheduler paused. Status {0}'.format(updated_status)) elif status == "resume": updated_status = current_app.running_context.scheduler.resume() current_app.logger.info( 'Scheduler resumed. Status {0}'.format(updated_status)) return {"status": updated_status}, SUCCESS return __func()
def execute_workflow(): from walkoff.server.context import running_context data = request.get_json() workflow_id = data['workflow_id'] @jwt_required @permissions_accepted_for_resources( ResourcePermissions('playbooks', ['execute'])) @validate_workflow_is_registered('execute', workflow_id) def __func(): args = data['arguments'] if 'arguments' in data else None start = data['start'] if 'start' in data else None arguments = [] if args: try: arguments = [Argument(**arg) for arg in args] except InvalidArgument as e: current_app.logger.error( 'Could not execute workflow. Invalid Argument construction' ) return Problem( INVALID_INPUT_ERROR, 'Cannot execute workflow.', 'An argument is invalid. Reason: {}'.format(e.message)) execution_id = running_context.executor.execute_workflow( workflow_id, start=start, start_arguments=arguments) current_app.logger.info('Executed workflow {0}'.format(workflow_id)) return {'id': execution_id}, SUCCESS_ASYNC return __func()
def get_playbooks(full=None): @jwt_required @permissions_accepted_for_resources( ResourcePermissions('playbooks', ['read'])) def __func(): full_rep = bool(full) playbooks = current_app.running_context.execution_db.session.query( Playbook).all() if full_rep: ret_playbooks = [ playbook_schema.dump(playbook).data for playbook in playbooks ] else: ret_playbooks = [] for playbook in playbooks: entry = {'id': playbook.id, 'name': playbook.name} workflows = [] for workflow in playbook.workflows: workflows.append({ 'id': workflow.id, 'name': workflow.name }) entry['workflows'] = sorted( workflows, key=(lambda wf: workflow.name.lower())) ret_playbooks.append(entry) return sorted(ret_playbooks, key=(lambda pb: pb['name'].lower())), SUCCESS return __func()
def update_scheduled_task(): @jwt_required @permissions_accepted_for_resources( ResourcePermissions('scheduler', ['update', 'execute'])) @with_task('update', request.get_json()['id']) def __func(task): data = request.get_json() invalid_uuids = validate_uuids(data.get('workflows', [])) if invalid_uuids: return invalid_uuid_problem(invalid_uuids) if 'name' in data: same_name = ScheduledTask.query.filter_by( name=data['name']).first() if same_name is not None and same_name.id != data['id']: return scheduled_task_name_already_exists_problem( same_name, 'update') try: task.update(data) except InvalidTriggerArgs: return invalid_scheduler_args_problem else: db.session.commit() return task.as_json(), SUCCESS return __func()
def delete_workflow(workflow_id): @jwt_required @permissions_accepted_for_resources( ResourcePermissions('playbooks', ['delete'])) @with_workflow('delete', workflow_id) def __func(workflow): playbook = current_app.running_context.execution_db.session.query( Playbook).filter_by(id=workflow.playbook_id).first() playbook_workflows = len(playbook.workflows) - 1 workflow = current_app.running_context.execution_db.session.query( Workflow).filter_by(id=workflow_id).first() current_app.running_context.execution_db.session.delete(workflow) if playbook_workflows == 0: current_app.logger.debug( 'Removing playbook {0} since it is empty.'.format( workflow.playbook_id)) current_app.running_context.execution_db.session.delete(playbook) current_app.running_context.execution_db.session.commit() current_app.logger.info('Deleted workflow {0}'.format(workflow_id)) return None, NO_CONTENT return __func()
def read_all_users(): @jwt_required @permissions_accepted_for_resources(ResourcePermissions('users', ['read'])) def __func(): return [user.as_json() for user in User.query.all()], SUCCESS return __func()
def update_playbook(): data = request.get_json() playbook_id = data['id'] @jwt_required @permissions_accepted_for_resources( ResourcePermissions('playbooks', ['update'])) @with_playbook('update', playbook_id) def __func(playbook): if 'name' in data and playbook.name != data['name']: playbook.name = data['name'] try: current_app.running_context.execution_db.session.commit() except IntegrityError: current_app.running_context.execution_db.session.rollback() current_app.logger.error( 'Could not update Playbook {}. Unique constraint failed'. format(playbook_id)) return unique_constraint_problem('playbook', 'update', playbook_id) current_app.logger.info('Playbook {} updated'.format(playbook_id)) return playbook_schema.dump(playbook).data, SUCCESS return __func()
def get_recent_notifications(): @jwt_required @permissions_accepted_for_resources(ResourcePermissions('messages', ['read'])) def __func(): user_id = get_jwt_identity() user = User.query.filter(User.id == user_id).first() # This should probably be replaced by a better SqlAlchemy command! unread_messages = [] read_messages = [] fill_in_with_read = True for message in user.messages: if not message.user_has_read(user): unread_messages.append(message) elif fill_in_with_read: if len(unread_messages) > min_notifications: fill_in_with_read = False else: read_messages.append(message) if fill_in_with_read and len(unread_messages) < min_notifications: unread_messages += read_messages unread_messages = unread_messages[:5] unread_messages.sort(key=(lambda x: x.created_at), reverse=True) return [message.as_json(user=user, summary=True) for message in unread_messages[:max_notifications]] return __func()
def send_data_to_trigger(): from walkoff.server.context import running_context @jwt_required @permissions_accepted_for_resources( ResourcePermissions('playbooks', ['execute'])) def __func(): data = request.get_json() workflows_in = set(data['execution_uids']) data_in = data['data_in'] arguments = data['arguments'] if 'arguments' in data else [] workflows_awaiting_data = set( running_context.controller.get_waiting_workflows()) uids = set.intersection(workflows_in, workflows_awaiting_data) user_id = get_jwt_identity() authorization_not_required, authorized_uids = get_authorized_uids( uids, user_id, get_jwt_claims().get('roles', [])) add_user_in_progress(authorized_uids, user_id) uids = list(authorized_uids | authorization_not_required) arg_objects = [] for arg in arguments: arg_objects.append(Argument(**arg)) running_context.controller.send_data_to_trigger( data_in, uids, arg_objects) return list(uids), SUCCESS return __func()
def get_system_usage(): @jwt_required @permissions_accepted_for_resources( ResourcePermissions('metrics', ['read'])) def __func(): return _system_resource_usage(), SUCCESS return __func()
def read_all_interfaces(): @jwt_required @permissions_accepted_for_resources( ResourcePermissions('app_apis', ['read'])) def __func(): return helpers.list_interfaces(), SUCCESS return __func()
def read_all_apps(): @jwt_required @permissions_accepted_for_resources(ResourcePermissions('app_apis', ['read'])) def __func(): apps = helpers.list_apps() return sorted(apps, key=(lambda app_name: app_name.lower())), SUCCESS return __func()
def read_all_cases(): @jwt_required @permissions_accepted_for_resources(ResourcePermissions('cases', ['read'])) def __func(): return [case.as_json() for case in CaseSubscription.query.all()], SUCCESS return __func()