Esempio n. 1
0
def update_catalogue(workspace_id, catalogue_id, catalogue_data):
    """
    Updates a specific catalogue by its id. The catalogue
    applies the given name and url, that are in the json parameter.
    :param workspace_id: The Workspace ID
    :param catalogue_id: The Catalogue ID
    :return: The updated Catalogue descriptor
    """
    catalogue_name = shlex.quote(catalogue_data['name'])
    catalogue_url = shlex.quote(catalogue_data['url'])
    session = db_session()
    workspace = session.query(Workspace).filter(Workspace.id == workspace_id).first()
    if workspace is None:
        raise NotFound("workspace with id {} could not be found".format(workspace_id))

    catalogue = session.query(Catalogue). \
        filter(Catalogue.workspace == workspace). \
        filter(Catalogue.id == catalogue_id). \
        first()
    if catalogue is None:
        raise NotFound("catalogue with id {} could not be found".format(catalogue_id))

    if catalogue_name != catalogue.name:
        existing_catalogues = session.query(catalogue). \
            filter(catalogue.workspace == workspace). \
            filter(catalogue.name == catalogue_data['name']). \
            all()
        if len(existing_catalogues) > 0:
            raise NameConflict("catalogue with name {} already exists".format(catalogue_data['name']))

    catalogue.name = catalogue_name
    catalogue.url = catalogue_url
    session.commit()
    update_workspace_descriptor(catalogue.workspace)
    return catalogue.as_dict()
Esempio n. 2
0
def delete(workspace_id: int, platform_id: int) -> dict:
    """
    Deletes the platform from the workspace
    :param workspace_id:
    :param platform_id:
    :return: the deleted platform description
    """
    session = db_session()
    workspace = session.query(Workspace).filter(
        Workspace.id == workspace_id).first()
    if workspace is None:
        raise NotFound(
            "workspace with id {} could not be found".format(workspace_id))

    platform = session.query(Platform). \
        filter(Platform.workspace == workspace). \
        filter(Platform.id == platform_id). \
        first()
    if platform is None:
        raise NotFound(
            "Platform with id {} could not be found".format(platform_id))

    session.delete(platform)
    update_workspace_descriptor(platform.workspace)
    session.commit()
    return platform.as_dict()
Esempio n. 3
0
def delete_image_file(ws_id, project_id, vnf_id, filename):
    """
    Deletes the image file with the given name
    
    :param ws_id:  The workspace ID
    :param project_id: The project ID
    :param vnf_id: The VNF ID
    :param filename: The name of the file to delete
    :return: A success message
    :raises NotFound: if the image file could not be located
    """
    session = db_session()
    function = session.query(Function). \
        join(Project). \
        join(Workspace). \
        filter(Workspace.id == ws_id). \
        filter(Project.id == project_id). \
        filter(Function.id == vnf_id).first()
    if function:
        save_name = secure_filename(filename)
        if not save_name == get_file_name(function):
            file_path = get_file_path("vnf", function).replace(
                get_file_name(function), save_name)
            if os.path.exists(file_path):
                os.remove(file_path)
                return "File {} was deleted".format(save_name)
            else:
                raise NotFound("File {} not found!".format(save_name))
    else:
        raise NotFound("Function with id " + vnf_id + " does not exist")
def delete_service(project_id: int, service_id: int) -> dict:
    """
    Deletes the service from the Database and from the disk

    :param project_id: The Projects ID
    :param service_id: The Services ID
    :return: The descriptor of the deleted service
    """
    session = db_session()
    project = session.query(Project).filter(Project.id == project_id).first()

    if project is None:
        raise NotFound("Could not delete service: project with id {} not found".format(service_id))

    service = session.query(Service). \
        filter(Service.id == service_id). \
        filter(Service.project == project). \
        first()
    if service is None:
        raise NotFound("Could not delete service: service with id {} not found".format(service_id))

    refs = get_references(service, session)
    if refs:
        session.rollback()
        ref_str = ",\n".join(ref.uid for ref in refs)
        raise StillReferenced("Could not delete service because it is still referenced by \n" + ref_str)
    session.delete(service)
    try:
        os.remove(get_file_path("nsd", service))
    except:
        session.rollback()
        logger.exception("Could not delete service:")
        raise
    session.commit()
    return service.as_dict()
Esempio n. 5
0
def find_by_priority(user_data, ws_id, project_id, vendor, name, version,
                     is_vnf):
    """
    Tries to find vnf / network services by descending priority
     1. project
     2. private catalogue
     3. public catalogues.

    :param user_data: Information about the current user
    :param ws_id: The Workspace ID
    :param project_id: The project ID
    :param vendor: The descriptors vendor
    :param name: The descriptors name
    :param version: The descriptors versions
    :param is_vnf: if the descriptor is a VNF
    :return: The descriptor if found
    """
    # 1. Try to find in project
    project = get_project(project_id)
    if project is None:
        raise NotFound("No project with id {} found.".format(project_id))

    function = get_function(project.functions, vendor, name,
                            version) if is_vnf else get_function(
                                project.services, vendor, name, version)

    if function is not None:
        return function.as_dict()

    # 2. Try to find in private catalogue
    # private catalogue funcs/nss are cached in db
    function = query_private_nsfs(ws_id, vendor, name, version, is_vnf)
    if function is not None:
        return function.as_dict()

    # 3. Try to find in public catalogue
    catalogues = get_catalogues(ws_id)
    for catalogue in catalogues:
        try:
            function_list = get_all_in_catalogue(user_data, ws_id,
                                                 catalogue['id'], is_vnf)
        except:
            continue
        for func in function_list:
            if func['vendor'] == vendor and func['name'] == name and func[
                    'version'] == version:
                function = func
                return function.as_dict()

    # If none found, raise exception
    raise NotFound("VNF" if is_vnf else "NS" +
                   " {}:{}:{} not found".format(vendor, name, version))
Esempio n. 6
0
def get_image_files(ws_id, project_id, function_id):
    """
    Returns a list of image file names located in the vnf folder
    
    :param ws_id: The Workspace ID
    :param project_id: The project ID
    :param function_id: The function ID
    :return: A List of image file names for this VNF 
    """
    session = db_session()
    function = session.query(Function). \
        join(Project). \
        join(Workspace). \
        filter(Workspace.id == ws_id). \
        filter(Project.id == project_id). \
        filter(Function.id == function_id).first()
    if function:
        folder_path = get_file_path("vnf",
                                    function).replace(get_file_name(function),
                                                      "")
        image_files = []

        for filename in os.listdir(folder_path):
            if not Path(os.path.join(folder_path, filename)).is_dir():
                if not filename == get_file_name(function):
                    image_files.append(filename)
        return image_files
    else:
        raise NotFound("Function with id " + function_id + " does not exist")
Esempio n. 7
0
def create_catalogue(workspace_id: int, catalogue_data):
    """
    Creates a catalgoue in the given workspace. A catalogue is defined by its name and url. These are given as
    json data

    :param workspace_id: Workspace ID of the target workspace, where the catalogue should get created.
    :return: Catalogue descriptor
    """
    catalogue_name = shlex.quote(catalogue_data['name'])
    catalogue_url = shlex.quote(catalogue_data['url'])
    session = db_session()
    workspace = session.query(Workspace).filter(Workspace.id == workspace_id).first()
    if workspace is None:
        raise NotFound("workspace with id {} could not be found".format(workspace_id))

    existing_catalogues = session.query(Catalogue). \
        filter(Catalogue.workspace == workspace). \
        filter(Catalogue.name == catalogue_data['name']). \
        all()

    if len(existing_catalogues) > 0:
        raise NameConflict("catalogue with name {} already exists".format(catalogue_data['name']))
    catalogue = Catalogue(name=catalogue_name, url=catalogue_url, workspace=workspace)
    session.add(catalogue)
    session.commit()
    update_workspace_descriptor(catalogue.workspace)
    return catalogue.as_dict()
Esempio n. 8
0
def create_platform(workspace_id: int, platform_data) -> dict:
    """
    Create a new platform entry
    :param workspace_id:
    :param platform_data:
    :return:
    """
    platform_name = shlex.quote(platform_data['name'])
    platform_url = shlex.quote(platform_data['url'])
    session = db_session()
    workspace = session.query(Workspace).filter(
        Workspace.id == workspace_id).first()
    if workspace is None:
        raise NotFound(
            "workspace with id {} could not be found".format(workspace_id))

    existing_platforms = session.query(Platform). \
        filter(Platform.workspace == workspace). \
        filter(Platform.name == platform_data['name']). \
        all()

    if len(existing_platforms) > 0:
        raise NameConflict("Platform with name {} already exists".format(
            platform_data['name']))
    platform = Platform(name=platform_name,
                        url=platform_url,
                        workspace=workspace)
    session.add(platform)
    update_workspace_descriptor(platform.workspace)
    session.commit()
    return platform.as_dict()
def delete_function(ws_id: int, project_id: int, function_id: int) -> dict:
    """
    Deletes the function
    :param ws_id:
    :param project_id:
    :param function_id:
    :return: the deleted function
    """
    session = db_session()
    function = session.query(Function). \
        join(Project). \
        join(Workspace). \
        filter(Workspace.id == ws_id). \
        filter(Project.id == project_id). \
        filter(Function.id == function_id).first()
    if function is not None:
        session.delete(function)
    else:
        session.rollback()
        raise NotFound("Function with id " + function_id + " does not exist")
    try:
        os.remove(get_file_path("vnf", function))
    except:
        session.rollback()
        logger.exception("Could not delete function:")
        raise
    session.commit()
    return function.as_dict()
Esempio n. 10
0
def save_image_file(ws_id, project_id, function_id, file):
    """
    Saves the vnf image file into the vnfs folder
    
    :param ws_id: The workspace ID 
    :param project_id: The project ID 
    :param function_id: The function ID
    :param file: The image file
    :return: A success message
    """
    if file.filename == '':
        raise InvalidArgument("No file attached!")
    if file:
        filename = secure_filename(file.filename)
        session = db_session()
        function = session.query(Function). \
            join(Project). \
            join(Workspace). \
            filter(Workspace.id == ws_id). \
            filter(Project.id == project_id). \
            filter(Function.id == function_id).first()
        if function is not None:
            file_path = get_file_path("vnf", function)
            file_path = file_path.replace(get_file_name(function), filename)
            file.save(file_path)
            return "File {} successfully uploaded!".format(filename)
        else:
            raise NotFound("Function with id " + function_id +
                           " does not exist")
def update_project(project_data, project_id):
    """
    Update the Project
    :param project_data:
    :param project_id:
    :return:
    """
    session = db_session()
    project = session.query(Project).filter(Project.id == project_id).first()
    if project is None:
        raise NotFound("Project with id {} could not be found".format(project_id))

    # Update name
    if 'name' in project_data and project_data['name'] != project.name:
        if os.path.exists(get_project_path(project.workspace.path, project.rel_path)):
            new_name = shlex.quote(project_data['name'])
            old_path = get_project_path(project.workspace.path, project.rel_path)
            new_path = rreplace(old_path, project.name, new_name, 1)

            if os.path.exists(new_path):
                raise NameConflict("Invalid name parameter, workspace '{}' already exists".format(new_name))

            # Do not allow move directories outside of the workspaces_dir
            if not new_path.startswith(WORKSPACES_DIR):
                raise Exception("Invalid path parameter, you are not allowed to break out of {}".format(WORKSPACES_DIR))
            else:
                # Move the directory
                shutil.move(old_path, new_path)
                project.name = new_name
                project.rel_path = new_name
    set_data(project, project_data)
    sync_project_descriptor(project)
    db_session.commit()
    return project.as_dict()
def check_access(request):
    """
    checks if the current user is allowed to access a given resource.
    Session will be invalidated if the login information cannot be found

    :param request: The http request made to the server
    :return: nothing if access granted
    :raises UnauthorizedException: if user not logged in
    """
    if not all(key in session for key in ['user_data', 'access_token']):
        session.clear()
        raise UnauthorizedException(
            "Session invalid. Please try logging in again")

    # Access parsed values of the url
    # Check if wsID was in the url
    if request.view_args is None:
        return
    if 'ws_id' in request.view_args:
        ws_id = request.view_args['ws_id']
        data_session = db_session()
        ws = data_session.query(Workspace).filter_by(id=ws_id).first()
        # Get current user
        user = get_user(session['user_data']['login'])
        # If the requested workspace is in his workspaces, he is allowed to access it
        if ws in user.workspaces:
            if 'project_id' in request.view_args:
                pj_id = request.view_args['project_id']
                pj = data_session.query(Project).filter(
                    Project.id == pj_id).first()
                if pj in ws.projects:
                    return
                else:
                    raise NotFound("Project not found")
            elif 'parent_id' in request.view_args and PROJECTS in request.url.split(
                    "/"):
                pj_id = request.view_args['parent_id']
                pj = data_session.query(Project).filter(
                    Project.id == pj_id).first()
                if pj in ws.projects:
                    return
                else:
                    raise NotFound("Project not found")
            return
        raise NotFound("Workspace not found")
    return
def get_service(service_id):
    """Returns a service with the given service id"""
    session = db_session()
    service = session.query(Service).filter(Service.id == service_id).first()
    # Check if the function could be retrieved
    if not service:
        raise NotFound("Service with id '{}' does not exist".format(service_id))
    return service
def get_function(function_id):
    """ Returns a function with the given function id"""
    session = db_session()
    function = session.query(Function).filter(Function.id == function_id).first()
    # Check if the function could be retrieved
    if not function:
        raise NotFound("Function with id '{}' does not exist".format(function_id))
    return function
def create_service(ws_id: int, project_id: int, service_data: dict) -> dict:
    """
    Creates a service in the given project
    :param ws_id: The Workspace of the project
    :param project_id: The Project of the Service
    :param service_data: the service descriptor
    :return: The created service descriptor
    """
    session = db_session()
    project = session.query(Project).filter_by(id=project_id).first()

    if project:
        # Retrieve post parameters
        try:
            service_name = shlex.quote(service_data['descriptor']["name"])
            vendor_name = shlex.quote(service_data['descriptor']["vendor"])
            version = shlex.quote(service_data['descriptor']["version"])
        except KeyError as ke:
            raise InvalidArgument("Missing key {} in service data".format(
                str(ke)))

        existing_services = list(
            session.query(Service).join(Project).join(Workspace).filter(
                Workspace.id == ws_id).filter(
                    Service.project == project).filter(
                        Service.name == service_name).filter(
                            Service.vendor == vendor_name).filter(
                                Service.version == version))
        if len(existing_services) > 0:
            raise NameConflict(
                "A service with this name/vendor/version already exists")

        # validate service descriptor
        workspace = session.query(Workspace).filter(
            Workspace.id == ws_id).first()
        validate_service_descriptor(workspace.ns_schema_index,
                                    service_data["descriptor"])

        # Create db object
        service = Service(name=service_name,
                          vendor=vendor_name,
                          version=version,
                          project=project,
                          descriptor=json.dumps(service_data["descriptor"]),
                          meta=json.dumps(service_data["meta"]))
        session.add(service)
        try:
            write_ns_vnf_to_disk("nsd", service)
        except:
            logger.exception("Could not create service:")
            session.rollback()
            raise
        session.commit()
        return service.as_dict()

    else:
        session.rollback()
        raise NotFound("Project with id '{}‘ not found".format(project_id))
Esempio n. 16
0
def get_project(project_id):
    """ Retrieves the project which matches the given project id. Otherwise it raises NotFound Exception """
    session = db_session()
    current_project = session.query(Project).filter(
        Project.id == project_id).first()
    if current_project is not None:
        return current_project
    else:
        raise NotFound("Project {} does not exist".format(project_id))
def update_function(ws_id: int, prj_id: int, func_id: int, func_data: dict) -> dict:
    """
    Update the function descriptor
    :param ws_id:
    :param prj_id:
    :param func_id:
    :param func_data:
    :return: The updated function descriptor
    """
    session = db_session()

    ws = session.query(Workspace).filter(Workspace.id == ws_id).first()
    validate_vnf(ws.vnf_schema_index, func_data)

    # test if ws Name exists in database
    function = session.query(Function). \
        join(Project). \
        join(Workspace). \
        filter(Workspace.id == ws_id). \
        filter(Project.id == prj_id). \
        filter(Function.id == func_id).first()
    if function is None:
        session.rollback()
        raise NotFound("Function with id {} does not exist".format(func_id))
    function.descriptor = json.dumps(func_data)

    old_file_name = get_file_path("vnf", function)
    old_folder_path = old_file_name.replace(get_file_name(function), "")
    try:
        function.name = shlex.quote(func_data["name"])
        function.vendor = shlex.quote(func_data["vendor"])
        function.version = shlex.quote(func_data["version"])
    except KeyError as ke:
        session.rollback()
        raise InvalidArgument("Missing key {} in function data".format(str(ke)))

    try:
        new_file_name = get_file_path("vnf", function)
        new_folder_path = new_file_name.replace(get_file_name(function), "")
        if old_folder_path != new_folder_path:
            # move old files to new location
            os.makedirs(new_folder_path)
            for file in os.listdir(old_folder_path):
                if not old_file_name == os.path.join(old_folder_path, file):  # don't move descriptor yet
                    shutil.move(os.path.join(old_folder_path, file), os.path.join(new_folder_path, file))
        if not new_file_name == old_file_name:
            shutil.move(old_file_name, new_file_name)
        if old_folder_path != new_folder_path:
            # cleanup old folder
            shutil.rmtree(old_folder_path)
        write_ns_vnf_to_disk("vnf", function)
    except:
        session.rollback()
        logger.exception("Could not update descriptor file:")
        raise
    session.commit()
    return function.as_dict()
def delete_image_file(ws_id, project_id, vnf_id, filename):
    session = db_session()
    function = session.query(Function). \
        join(Project). \
        join(Workspace). \
        filter(Workspace.id == ws_id). \
        filter(Project.id == project_id). \
        filter(Function.id == vnf_id).first()
    if function:
        save_name = secure_filename(filename)
        if not save_name == get_file_name(function):
            file_path = get_file_path("vnf", function).replace(get_file_name(function), save_name)
            if os.path.exists(file_path):
                os.remove(file_path)
                return "File {} was deleted".format(save_name)
            else:
                raise NotFound("File {} not found!".format(save_name))
    else:
        raise NotFound("Function with id " + vnf_id + " does not exist")
Esempio n. 19
0
def get_workspace(ws_id: int) -> Workspace:
    """
    Returns the workspace model of the given workspace

    :param ws_id: The workspace ID
    :return: The corresponding workspace model
    """
    workspace = db_session().query(Workspace).filter(Workspace.id == ws_id).first()
    if not workspace:
        raise NotFound("Could not find workspace with id {}".format(ws_id))
    return workspace
def update_service(ws_id, project_id, service_id, service_data):
    """
    Update the service using the service data from the request
    :param ws_id:
    :param project_id:
    :param service_id:
    :param service_data:
    :return:
    """
    session = db_session()
    service = session.query(Service). \
        join(Project). \
        join(Workspace). \
        filter(Workspace.id == ws_id). \
        filter(Project.id == project_id). \
        filter(Service.id == service_id).first()
    if service:
        old_file_name = get_file_path("nsd", service)
        # Parse parameters and update record
        if 'descriptor' in service_data:
            # validate service descriptor
            workspace = session.query(Workspace).filter(
                Workspace.id == ws_id).first()
            validate_service_descriptor(workspace.ns_schema_index,
                                        service_data["descriptor"])
            service.descriptor = json.dumps(service_data["descriptor"])
            try:
                service.name = shlex.quote(service_data["descriptor"]["name"])
                service.vendor = shlex.quote(
                    service_data["descriptor"]["vendor"])
                service.version = shlex.quote(
                    service_data["descriptor"]["version"])
            except KeyError as ke:
                raise InvalidArgument("Missing key {} in function data".format(
                    str(ke)))

        if 'meta' in service_data:
            service.meta = json.dumps(service_data["meta"])

        new_file_name = get_file_path("nsd", service)
        try:
            if not old_file_name == new_file_name:
                shutil.move(old_file_name, new_file_name)
            write_ns_vnf_to_disk("nsd", service)
        except:
            logger.exception("Could not update descriptor file:")
            raise
        session.commit()
        return service.as_dict()
    else:
        raise NotFound(
            "Could not update service '{}', because no record was found".
            format(service_id))
def get_catalogue(catalogue_id):
    """
    Retrieves a catalogue by given id
    :param catalogue_id: int
    :return:
    """
    session = db_session()
    catalogue = session.query(Catalogue).filter(Catalogue.id == catalogue_id).first()
    # Check if catalogue exists
    if not catalogue:
        raise NotFound("Catalogue with id '{}' could not be found".format(catalogue_id))
    return catalogue
def get_project(ws_id, pj_id):
    session = db_session()
    project = session.query(Project). \
        join(Workspace). \
        filter(Workspace.id == ws_id). \
        filter(Project.id == pj_id). \
        first()
    session.commit()
    if project:
        return project.as_dict()
    else:
        raise NotFound("No project with id {} could be found".format(pj_id))
def get_catalogue(catalogue_id):
    """
    Retrieves a catalogue by its id
    :param catalogue_id:
    :return:
    """
    session = db_session()
    catalogue = session.query(Catalogue).filter(Catalogue.id == catalogue_id).first()
    session.commit()
    if catalogue is None:
        raise NotFound("catalogue with id {} could not be found".format(catalogue_id))
    return catalogue.as_dict()
Esempio n. 24
0
def create_function(ws_id: int, project_id: int, function_data: dict) -> dict:
    """
    Creates a new vnf in the project

    :param ws_id: The workspace ID
    :param project_id: The Project ID
    :param function_data: The function data to create
    :return: The created function as a dict
    """
    try:
        function_name = shlex.quote(function_data['descriptor']["name"])
        vendor_name = shlex.quote(function_data['descriptor']["vendor"])
        version = shlex.quote(function_data['descriptor']["version"])
    except KeyError as ke:
        raise InvalidArgument("Missing key {} in function data".format(
            str(ke)))

    session = db_session()

    ws = session.query(Workspace).filter(
        Workspace.id == ws_id).first()  # type: Workspace
    validate_vnf(ws.schema_index, function_data['descriptor'])

    # test if function Name exists in database
    existing_functions = list(
        session.query(Function).join(Project).join(Workspace).filter(
            Workspace.id == ws_id).filter(
                Function.project_id == project_id).filter(
                    Function.vendor == vendor_name).filter(
                        Function.name == function_name).filter(
                            Function.version == version))
    if len(existing_functions) > 0:
        raise NameConflict("Function with name " + function_name +
                           " already exists")
    project = session.query(Project).filter(Project.id == project_id).first()
    if project is None:
        raise NotFound("No project with id " + project_id + " was found")
    function = Function(name=function_name,
                        project=project,
                        vendor=vendor_name,
                        version=version,
                        descriptor=json.dumps(function_data['descriptor']))
    session.add(function)
    try:
        write_ns_vnf_to_disk("vnf", function)
    except:
        logger.exception("Could not write data to disk:")
        session.rollback()
        raise
    session.commit()
    return function.as_dict()
def get_project(ws_id, pj_id: int, session=db_session()) -> Project:
    """
    Returns a project and raises 404, when project not found.
    :param ws_id: Workspace id
    :param pj_id: Project id
    :param db session
    :return: Project model
    """
    project = session.query(Project).join(Workspace) \
        .filter(Workspace.id == ws_id) \
        .filter(Project.id == pj_id).first()
    if not project:
        raise NotFound("Could not find project with id {}".format(pj_id))
    return project
def get_services(ws_id: int, project_id: int) -> list:
    """
    Get a list of all services in this Project
    :param ws_id:
    :param project_id: The project ID
    :return: A list of service descriptors as dicts
    """
    session = db_session()
    project = session.query(Project).filter_by(id=project_id).first()
    session.commit()
    if project:
        return list(map(lambda x: x.as_dict(), project.services))
    else:
        raise NotFound("No project matching id {}".format(project_id))
Esempio n. 27
0
def get_workspace(ws_id: int) -> dict:
    """
    Get a workspace by ID
    :param ws_id:
    :return: A dictionary wich contains the Workspace configuration
    """
    session = db_session()
    workspace = session.query(Workspace). \
        filter(Workspace.id == ws_id).first()
    session.commit()
    if workspace is not None:
        return workspace.as_dict()
    else:
        raise NotFound("No workspace with id " + ws_id + " exists")
Esempio n. 28
0
def get_platform(platform_id: int) -> dict:
    """
    Get the platform definition
    :param platform_id:
    :return: The platform information
    """
    session = db_session()
    platform = session.query(Platform).filter(
        Platform.id == platform_id).first()
    session.commit()
    if platform is None:
        raise NotFound(
            "Platform with id {} could not be found".format(platform_id))
    return platform.as_dict()
def delete(workspace_id, catalogue_id):
    """
    Deletes a catalogue by its id
    :param workspace_id:
    :param catalogue_id:
    :return:
    """
    session = db_session()
    workspace = session.query(Workspace).filter(Workspace.id == workspace_id).first()
    if workspace is None:
        raise NotFound("workspace with id {} could not be found".format(workspace_id))

    catalogue = session.query(Catalogue). \
        filter(Catalogue.workspace == workspace). \
        filter(Catalogue.id == catalogue_id). \
        first()
    if catalogue is None:
        raise NotFound("catalogue with id {} could not be found".format(catalogue_id))

    session.delete(catalogue)
    session.commit()
    update_workspace_descriptor(catalogue.workspace)
    return catalogue.as_dict()
def get_service(ws_id, parent_id, service_id):
    """
    Get the service by ID
    :param ws_id: The workspace ID of the Project
    :param parent_id: The project ID
    :param service_id: the Service ID
    :return:
    """
    session = db_session()
    service = session.query(Service).filter_by(id=service_id).first()
    session.commit()
    if service:
        return service.as_dict()
    else:
        raise NotFound("No Service matching id {}".format(parent_id))