Example #1
0
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)
Example #2
0
def read_app_metrics():
    @jwt_required
    @permissions_accepted_for_resources(ResourcePermissions('metrics', ['read']))
    def __func():
        return _convert_action_time_averages(), SUCCESS

    return __func()
Example #3
0
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:
Example #4
0
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()
Example #6
0
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()
Example #7
0
def read_config_values():
    @jwt_required
    @permissions_accepted_for_resources(ResourcePermissions('configuration', ['read']))
    def __func():
        return __get_current_configuration(), SUCCESS

    return __func()
Example #8
0
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()
Example #9
0
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()
Example #10
0
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()
Example #11
0
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()
Example #12
0
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()
Example #13
0
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()
Example #14
0
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()
Example #15
0
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()
Example #16
0
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()
Example #17
0
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()
Example #18
0
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()
Example #19
0
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()
Example #20
0
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()
Example #21
0
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()
Example #22
0
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()
Example #23
0
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()
Example #24
0
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()
Example #25
0
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()
Example #26
0
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()
Example #27
0
def get_system_usage():
    @jwt_required
    @permissions_accepted_for_resources(
        ResourcePermissions('metrics', ['read']))
    def __func():
        return _system_resource_usage(), SUCCESS

    return __func()
Example #28
0
def read_all_interfaces():
    @jwt_required
    @permissions_accepted_for_resources(
        ResourcePermissions('app_apis', ['read']))
    def __func():
        return helpers.list_interfaces(), SUCCESS

    return __func()
Example #29
0
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()
Example #30
0
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()