예제 #1
0
    def worker(self, type):
        try:
            from datetime import datetime
            manager = ObjectManager(
                database_manager=self.database_manager
            )  # TODO: Replace when object api is updated
            object_list = self.object_manager.get_objects_by_type(
                type.public_id)
            matches = type.matches

            for obj in object_list:
                for field in obj.fields:
                    if [x for x in matches if x['name'] == field['name']]:
                        # name = field['name']
                        value = field['value']
                        if value:
                            if isinstance(value, datetime):
                                field['value'] = value
                            else:
                                field['value'] = datetime.strptime(
                                    value, '%Y-%m-%dT%H:%M:%S.%fZ')
                manager.update(public_id=obj.public_id,
                               data=obj,
                               user=None,
                               permission=None)
        except (ObjectManagerGetError, ObjectManagerUpdateError,
                CMDBError) as err:
            LOGGER.error(err.message)
예제 #2
0
    def from_database(self, database_manager, user: UserModel,
                      permission: AccessControlPermission):
        """Get all objects from the collection"""
        manager = ObjectManager(database_manager=database_manager)
        dep_object_manager = CmdbObjectManager(
            database_manager=database_manager)

        try:
            _params = self.export_config.parameters
            _result: List[CmdbObject] = manager.iterate(
                filter=_params.filter,
                sort=_params.sort,
                order=_params.order,
                limit=0,
                skip=0,
                user=user,
                permission=permission).results

            self.data = RenderList(
                object_list=_result,
                request_user=user,
                database_manager=database_manager,
                object_manager=dep_object_manager,
                ref_render=True).render_result_list(raw=False)

        except CMDBError as e:
            return abort(400, e)
예제 #3
0
def get_objects(params: CollectionParameters, request_user: UserModel):

    manager = ObjectManager(database_manager=current_app.database_manager)
    view = params.optional.get('view', 'native')

    if _fetch_only_active_objs():
        if isinstance(params.filter, dict):
            filter_ = params.filter
            params.filter = [{'$match': filter_}]
            params.filter.append({'$match': {'active': {"$eq": True}}})
        elif isinstance(params.filter, list):
            params.filter.append({'$match': {'active': {"$eq": True}}})

    try:
        iteration_result: IterationResult[CmdbObject] = manager.iterate(
            filter=params.filter,
            limit=params.limit,
            skip=params.skip,
            sort=params.sort,
            order=params.order,
            user=request_user,
            permission=AccessControlPermission.READ)

        if view == 'native':
            object_list: List[dict] = [
                object_.__dict__ for object_ in iteration_result.results
            ]
            api_response = GetMultiResponse(object_list,
                                            total=iteration_result.total,
                                            params=params,
                                            url=request.url,
                                            model=CmdbObject.MODEL,
                                            body=request.method == 'HEAD')
        elif view == 'render':
            rendered_list = RenderList(
                object_list=iteration_result.results,
                request_user=request_user,
                database_manager=current_app.database_manager,
                object_manager=object_manager,
                ref_render=True).render_result_list(raw=True)
            api_response = GetMultiResponse(rendered_list,
                                            total=iteration_result.total,
                                            params=params,
                                            url=request.url,
                                            model=Model('RenderResult'),
                                            body=request.method == 'HEAD')
        else:
            return abort(401, 'No possible view parameter')

    except ManagerIterationError as err:
        return abort(400, err.message)
    except ManagerGetError as err:
        return abort(404, err.message)
    return api_response.make_response()
예제 #4
0
def get_corresponding_object_logs(public_id: int, request_user: UserModel):
    try:
        selected_log = log_manager.get(public_id=public_id)
        ObjectManager(database_manager=database_manager).get(
            selected_log.object_id,
            user=request_user,
            permission=AccessControlPermission.READ)
        query = {
            'log_type': CmdbObjectLog.__name__,
            'object_id': selected_log.object_id,
            'action': LogAction.EDIT.value,
            '$nor': [{
                'public_id': public_id
            }]
        }
        logs = log_manager.iterate(filter=query,
                                   limit=0,
                                   skip=0,
                                   order=1,
                                   sort='public_id')
        corresponding_logs = [CmdbObjectLog.to_json(_) for _ in logs.results]
    except ManagerGetError as err:
        return abort(404, err.message)
    except AccessDeniedError as err:
        return abort(403, err.message)
    except ManagerIterationError as err:
        return abort(400, err.message)

    if len(corresponding_logs) < 1:
        return make_response(corresponding_logs, 204)

    return make_response(corresponding_logs)
예제 #5
0
def get_logs_by_object(object_id: int, params: CollectionParameters,
                       request_user: UserModel):
    manager = CmdbLogManager(database_manager=database_manager)
    try:
        ObjectManager(database_manager=database_manager).get(
            object_id,
            user=request_user,
            permission=AccessControlPermission.READ)
        body = request.method == 'HEAD'
        iteration_result = manager.iterate(public_id=object_id,
                                           filter=params.filter,
                                           limit=params.limit,
                                           skip=params.skip,
                                           sort=params.sort,
                                           order=params.order)
        logs = [CmdbObjectLog.to_json(_) for _ in iteration_result.results]
        api_response = GetMultiResponse(logs,
                                        total=iteration_result.total,
                                        params=params,
                                        url=request.url,
                                        model=CmdbMetaLog.MODEL,
                                        body=body)
    except ManagerGetError as err:
        return abort(404, err.message)
    except AccessDeniedError as err:
        return abort(403, err.message)
    except ManagerIterationError as err:
        return abort(400, err.message)

    return api_response.make_response()
예제 #6
0
def get_log(public_id: int, request_user: UserModel):
    manager = CmdbLogManager(database_manager=database_manager)
    try:
        selected_log: CmdbObjectLog = manager.get(public_id=public_id)
        ObjectManager(database_manager=database_manager).get(
            selected_log.object_id,
            user=request_user,
            permission=AccessControlPermission.READ)
    except ManagerGetError as err:
        return abort(404, err.message)
    except AccessDeniedError as err:
        return abort(403, err.message)
    return make_response(selected_log)
예제 #7
0
def get_unstructured_objects(public_id: int, request_user: UserModel):
    """
    HTTP `GET`/`HEAD` route for a multi resources which are not formatted according the type structure.
    Args:
        public_id (int): Public ID of the type.
    Raises:
        ManagerGetError: When the selected type does not exists or the objects could not be loaded.
    Returns:
        GetListResponse: Which includes the json data of multiple objects.
    """
    manager = ObjectManager(database_manager=current_app.database_manager)

    try:
        type_instance: TypeModel = type_manager.get(public_id=public_id)
        objects: List[CmdbObject] = manager.iterate({
            'type_id': public_id
        },
                                                    limit=0,
                                                    skip=0,
                                                    sort='public_id',
                                                    order=1,
                                                    user=request_user).results
    except ManagerGetError as err:
        return abort(400, err.message)
    type_fields = sorted([field.get('name') for field in type_instance.fields])
    unstructured: List[dict] = []
    for object_ in objects:
        object_fields = [field.get('name') for field in object_.fields]
        if sorted(object_fields) != type_fields:
            unstructured.append(object_.__dict__)

    api_response = GetListResponse(unstructured,
                                   url=request.url,
                                   model=CmdbObject.MODEL,
                                   body=request.method == 'HEAD')
    return api_response.make_response()
예제 #8
0
def update_unstructured_objects(public_id: int, request_user: UserModel):
    """
    HTTP `PUT`/`PATCH` route for a multi resources which will be formatted based on the TypeModel
    Args:
        public_id (int): Public ID of the type.
    Raises:
        ManagerGetError: When the type with the `public_id` was not found.
        ManagerUpdateError: When something went wrong during the update.
    Returns:
        UpdateMultiResponse: Which includes the json data of multiple updated objects.
    """
    manager = ObjectManager(database_manager=current_app.database_manager)

    try:
        update_type_instance = type_manager.get(public_id)
        type_fields = update_type_instance.fields
        objects_by_type = manager.iterate({
            'type_id': public_id
        },
                                          limit=0,
                                          skip=0,
                                          sort='public_id',
                                          order=1,
                                          user=request_user).results

        for obj in objects_by_type:
            incorrect = []
            correct = []
            obj_fields = obj.get_all_fields()
            for t_field in type_fields:
                name = t_field["name"]
                for field in obj_fields:
                    if name == field["name"]:
                        correct.append(field["name"])
                    else:
                        incorrect.append(field["name"])
            removed_type_fields = [
                item for item in incorrect if not item in correct
            ]
            for field in removed_type_fields:
                manager.update_many(
                    query={'public_id': obj.public_id},
                    update={'$pull': {
                        'fields': {
                            "name": field
                        }
                    }})

        objects_by_type = manager.iterate({
            'type_id': public_id
        },
                                          limit=0,
                                          skip=0,
                                          sort='public_id',
                                          order=1,
                                          user=request_user).results
        for obj in objects_by_type:
            for t_field in type_fields:
                name = t_field["name"]
                value = None
                if [
                        item for item in obj.get_all_fields()
                        if item["name"] == name
                ]:
                    continue
                if "value" in t_field:
                    value = t_field["value"]

                manager.update_many(query={'public_id': obj.public_id},
                                    update={
                                        '$addToSet': {
                                            'fields': {
                                                "name": name,
                                                "value": value
                                            }
                                        }
                                    })

    except ManagerUpdateError as err:
        return abort(400, err.message)

    api_response = UpdateMultiResponse([],
                                       url=request.url,
                                       model=CmdbObject.MODEL)

    return api_response.make_response()
예제 #9
0
def update_object_state(public_id: int, request_user: UserModel):
    if isinstance(request.json, bool):
        state = request.json
    else:
        return abort(400)
    try:
        manager = ObjectManager(database_manager=current_app.database_manager,
                                event_queue=current_app.event_queue)
        founded_object = manager.get(public_id=public_id,
                                     user=request_user,
                                     permission=AccessControlPermission.READ)
    except ObjectManagerGetError as err:
        LOGGER.error(err)
        return abort(404, err.message)
    if founded_object.active == state:
        return make_response(False, 204)
    try:
        founded_object.active = state
        manager.update(public_id,
                       founded_object,
                       user=request_user,
                       permission=AccessControlPermission.UPDATE)
    except AccessDeniedError as err:
        return abort(403, err.message)
    except ObjectManagerUpdateError as err:
        LOGGER.error(err)
        return abort(500, err.message)

        # get current object state
    try:
        current_type_instance = type_manager.get(founded_object.get_type_id())
        current_object_render_result = CmdbRender(
            object_instance=founded_object,
            object_manager=object_manager,
            type_instance=current_type_instance,
            render_user=request_user).result()
    except ObjectManagerGetError as err:
        LOGGER.error(err)
        return abort(404)
    except RenderError as err:
        LOGGER.error(err)
        return abort(500)
    try:
        # generate log
        change = {'old': not state, 'new': state}
        log_data = {
            'object_id':
            public_id,
            'version':
            founded_object.version,
            'user_id':
            request_user.get_public_id(),
            'user_name':
            request_user.get_display_name(),
            'render_state':
            json.dumps(current_object_render_result,
                       default=default).encode('UTF-8'),
            'comment':
            'Active status has changed',
            'changes':
            change,
        }
        log_manager.insert(action=LogAction.ACTIVE_CHANGE,
                           log_type=CmdbObjectLog.__name__,
                           **log_data)
    except (CMDBError, LogManagerInsertError) as err:
        LOGGER.error(err)

    api_response = UpdateSingleResponse(result=founded_object.__dict__,
                                        url=request.url,
                                        model=CmdbObject.MODEL)
    return api_response.make_response()
예제 #10
0
def update_object(public_id: int, data: dict, request_user: UserModel):
    object_ids = request.args.getlist('objectIDs')

    if len(object_ids) > 0:
        object_ids = list(map(int, object_ids))
    else:
        object_ids = [public_id]

    manager = ObjectManager(database_manager=current_app.database_manager,
                            event_queue=current_app.event_queue)
    results: [dict] = []
    failed = []

    for obj_id in object_ids:
        # deep copy
        active_state = request.get_json().get('active', None)
        new_data = copy.deepcopy(data)
        try:
            current_object_instance = manager.get(
                obj_id,
                user=request_user,
                permission=AccessControlPermission.READ)
            current_type_instance = type_manager.get(
                current_object_instance.get_type_id())
            current_object_render_result = CmdbRender(
                object_instance=current_object_instance,
                object_manager=object_manager,
                type_instance=current_type_instance,
                render_user=request_user).result()
            update_comment = ''
            try:
                # check for comment
                new_data['public_id'] = obj_id
                new_data[
                    'creation_time'] = current_object_instance.creation_time
                new_data['author_id'] = current_object_instance.author_id
                new_data[
                    'active'] = active_state if active_state else current_object_instance.active

                if 'version' not in data:
                    new_data['version'] = current_object_instance.version

                old_fields = list(
                    map(
                        lambda x:
                        {k: v
                         for k, v in x.items() if k in ['name', 'value']},
                        current_object_render_result.fields))
                new_fields = data['fields']
                for item in new_fields:
                    for old in old_fields:
                        if item['name'] == old['name']:
                            old['value'] = item['value']
                new_data['fields'] = old_fields

                update_comment = data['comment']
                del new_data['comment']

            except (KeyError, IndexError, ValueError):
                update_comment = ''
            except TypeError as err:
                LOGGER.error(
                    f'Error: {str(err.args)} Object: {json.dumps(new_data, default=default)}'
                )
                failed.append(
                    ResponseFailedMessage(error_message=str(err.args),
                                          status=400,
                                          public_id=obj_id,
                                          obj=new_data).to_dict())
                continue

            # update edit time
            new_data['last_edit_time'] = datetime.now(timezone.utc)
            new_data['editor_id'] = request_user.public_id

            update_object_instance = CmdbObject(
                **json.loads(json.dumps(new_data, default=json_util.default),
                             object_hook=object_hook))

            # calc version
            changes = current_object_instance / update_object_instance

            if len(changes['new']) == 1:
                new_data['version'] = update_object_instance.update_version(
                    update_object_instance.VERSIONING_PATCH)
            elif len(changes['new']) == len(update_object_instance.fields):
                new_data['version'] = update_object_instance.update_version(
                    update_object_instance.VERSIONING_MAJOR)
            elif len(
                    changes['new']) > (len(update_object_instance.fields) / 2):
                new_data['version'] = update_object_instance.update_version(
                    update_object_instance.VERSIONING_MINOR)
            else:
                new_data['version'] = update_object_instance.update_version(
                    update_object_instance.VERSIONING_PATCH)

            manager.update(obj_id, new_data, request_user,
                           AccessControlPermission.UPDATE)
            results.append(new_data)

            # Generate log entry
            try:
                log_data = {
                    'object_id':
                    obj_id,
                    'version':
                    update_object_instance.get_version(),
                    'user_id':
                    request_user.get_public_id(),
                    'user_name':
                    request_user.get_display_name(),
                    'comment':
                    update_comment,
                    'changes':
                    changes,
                    'render_state':
                    json.dumps(update_object_instance,
                               default=default).encode('UTF-8')
                }
                log_manager.insert(action=LogAction.EDIT,
                                   log_type=CmdbObjectLog.__name__,
                                   **log_data)
            except (CMDBError, LogManagerInsertError) as err:
                LOGGER.error(err)

        except AccessDeniedError as err:
            LOGGER.error(err)
            return abort(403)
        except ObjectManagerGetError as err:
            LOGGER.error(err)
            failed.append(
                ResponseFailedMessage(error_message=err.message,
                                      status=400,
                                      public_id=obj_id,
                                      obj=new_data).to_dict())
            continue
        except (ManagerGetError, ObjectManagerUpdateError) as err:
            LOGGER.error(err)
            failed.append(
                ResponseFailedMessage(error_message=err.message,
                                      status=404,
                                      public_id=obj_id,
                                      obj=new_data).to_dict())
            continue
        except (CMDBError, RenderError) as e:
            LOGGER.warning(e)
            failed.append(
                ResponseFailedMessage(error_message=str(e.__repr__),
                                      status=500,
                                      public_id=obj_id,
                                      obj=new_data).to_dict())
            continue

    api_response = UpdateMultiResponse(results=results,
                                       failed=failed,
                                       url=request.url,
                                       model=CmdbObject.MODEL)
    return api_response.make_response()