Commit 1c7ad31a authored by Pelayo Torres's avatar Pelayo Torres
Browse files

New modular helper service

parent dec6fd9f
Loading
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -3,9 +3,8 @@ import logging
import os
import requests
from config import Config
from controllers.helper_controller import helper_routes
from pathlib import Path
from db.db import MongoDatabse
from db.db import get_mongo
import connexion
import sys
from flask import Flask
@@ -28,7 +27,7 @@ app = connexion.App(__name__, specification_dir=str(SERVICES_DIR))
config = Config().get_config()

# Connect MongoDB and get TTL for superadmin certificate
db = MongoDatabse()
db = get_mongo()
capif_config = db.get_col_by_name("capif_configuration").find_one({})
ttl_superadmin_cert = capif_config["settings"]["certificates_expiry"].get("ttl_superadmin_cert", "43000h")

+0 −199
Original line number Diff line number Diff line
#!/usr/bin/env python3

from config import Config
from core.helper_operations import HelperOperations
from flask import Blueprint, current_app, jsonify, request

config = Config().get_config()

helper_routes = Blueprint("helper_routes", __name__)
helper_operation = HelperOperations()

@helper_routes.route("/helper/getInvokers", methods=["GET"])
def getInvokers():
    uuid = request.args.get('uuid')
    invoker_id = request.args.get('api_invoker_id')
    page_size = request.args.get('page_size')
    page = request.args.get('page')
    sort_order = request.args.get('sort_order')
    if page_size:
        page_size = int(page_size)
        if page_size < 0:
            return jsonify(message="The value of the page_size parameter must be greater than 0"), 400
    if page:
        page = int(page)
        if page < 0:
            return jsonify(message="The value of the page parameter must be greater than 0"), 400
    
    current_app.logger.debug(f"uuid: {uuid}, invoker_id: {invoker_id}, page: {page}, page_size: {page_size}, sort_order: {sort_order}")

    return helper_operation.get_invokers(uuid, invoker_id, page, page_size, sort_order)

@helper_routes.route("/helper/getProviders", methods=["GET"])
def getProviders():
    uuid = request.args.get('uuid')
    provider_id = request.args.get('api_prov_dom_id')
    page_size = request.args.get('page_size')
    page = request.args.get('page')
    sort_order = request.args.get('sort_order')

    if page_size:
        page_size = int(page_size)
        if page_size < 0:
            return jsonify(message="The value of the page_size parameter must be greater than 0"), 400
    if page:
        page = int(page)
        if page < 0:
            return jsonify(message="The value of the page parameter must be greater than 0"), 400
    
    current_app.logger.debug(f"uuid: {uuid}, provider_id: {provider_id}, page: {page}, page_size: {page_size}, sort_order: {sort_order}")

    return helper_operation.get_providers(uuid, provider_id, page, page_size, sort_order)


@helper_routes.route("/helper/getServices", methods=["GET"])
def getServices():
    service_id = request.args.get('service_id')
    apf_id = request.args.get('apf_id')
    api_name = request.args.get('api_name')
    page_size = request.args.get('page_size')
    page = request.args.get('page')
    sort_order = request.args.get('sort_order')
    if page_size:
        page_size = int(page_size)
        if page_size < 0:
            return jsonify(message="The value of the page_size parameter must be greater than 0"), 400
    if page:
        page = int(page)
        if page < 0:
            return jsonify(message="The value of the page parameter must be greater than 0"), 400
    
    current_app.logger.debug(f"service_id: {service_id}, apf_id: {apf_id}, api_name: {api_name}, page: {page}, page_size: {page_size}, sort_order: {sort_order}")

    return helper_operation.get_services(service_id, apf_id, api_name, page, page_size, sort_order)

@helper_routes.route("/helper/getSecurity", methods=["GET"])
def getSecurity():
    invoker_id = request.args.get('invoker_id')
    page_size = request.args.get('page_size')
    page = request.args.get('page')
    if page_size:
        page_size = int(page_size)
        if page_size < 0:
            return jsonify(message="The value of the page_size parameter must be greater than 0"), 400
    if page:
        page = int(page)
        if page < 0:
            return jsonify(message="The value of the page parameter must be greater than 0"), 400
    
    current_app.logger.debug(f"invoker_id: {invoker_id}, page: {page}, page_size: {page_size} ")

    return helper_operation.get_security(invoker_id, page, page_size)

@helper_routes.route("/helper/getEvents", methods=["GET"])
def getEvents():
    subscriber_id = request.args.get('subscriber_id')
    subscription_id = request.args.get('subscription_id')
    page_size = request.args.get('page_size')
    page = request.args.get('page')
    if page_size:
        page_size = int(page_size)
        if page_size < 0:
            return jsonify(message="The value of the page_size parameter must be greater than 0"), 400
    if page:
        page = int(page)
        if page < 0:
            return jsonify(message="The value of the page parameter must be greater than 0"), 400
    
    current_app.logger.debug(f"subscriber_id: {subscriber_id}, subscription_id: {subscription_id}, page: {page}, page_size: {page_size} ")

    return helper_operation.get_events(subscriber_id, subscription_id, page, page_size)


@helper_routes.route("/helper/deleteEntities/<uuid>", methods=["DELETE"])
def deleteUserEntities(uuid):
    return helper_operation.remove_entities(uuid)


@helper_routes.route("/helper/getConfiguration", methods=["GET"])
def getConfiguration():
    """Returns the current configuration"""
    return helper_operation.get_configuration()


@helper_routes.route("/helper/updateConfigParam", methods=["PATCH"])
def updateConfigParam():
    """Updates a single configuration parameter"""
    data = request.json
    param_path = data.get("param_path")
    new_value = data.get("new_value")

    if not param_path or new_value is None:
        return jsonify(message="Missing 'param_path' or 'new_value' in request body"), 400

    return helper_operation.update_config_param(param_path, new_value)


@helper_routes.route("/helper/replaceConfiguration", methods=["PUT"])
def replaceConfiguration():
    """Replaces the entire configuration with a new one"""
    new_config = request.json
    if not new_config:
        return jsonify(message="Missing new configuration in request body"), 400

    return helper_operation.replace_configuration(new_config)


@helper_routes.route("/helper/addNewConfiguration", methods=["POST"])
def add_new_configuration():
    """Adds a new category inside 'settings'."""
    data = request.json
    category_name = data.get("category_name")
    category_values = data.get("category_values")

    if not category_name or not category_values:
        return jsonify(message="Missing 'category_name' or 'category_values' in request body"), 400

    return helper_operation.add_new_configuration(category_name, category_values)

@helper_routes.route("/helper/addNewConfigSetting", methods=["PATCH"])
def add_new_config_setting():
    """Adds a new configuration inside 'settings'."""
    data = request.json
    param_path = data.get("param_path")
    new_value = data.get("new_value")
    
    if not param_path or new_value is None:
        return jsonify(message="Missing 'param_path' or 'new_value' in request body"), 400
    
    return helper_operation.add_new_config_setting(param_path, new_value)


@helper_routes.route("/helper/removeConfigParam", methods=["DELETE"])
def remove_config_param():
    """Deletes a specific parameter inside 'settings'."""
    data = request.json
    param_path = data.get("param_path")

    if not param_path:
        return jsonify(message="Missing 'param_path' in request body"), 400

    return helper_operation.remove_config_param(param_path)


@helper_routes.route("/helper/removeConfigCategory", methods=["DELETE"])
def remove_config_category():
    """Deletes an entire category inside 'settings'."""
    data = request.json
    category_name = data.get("category_name")

    if not category_name:
        return jsonify(message="Missing 'category_name' in request body"), 400

    return helper_operation.remove_config_category(category_name)


@helper_routes.route("/helper/getCcfId", methods=["GET"])
def get_ccf_id():
    """Returns the current CAPIF ccfId"""
    return helper_operation.get_ccf_id()
+27 −1
Original line number Diff line number Diff line
import time
import secrets
from threading import Lock

from bson.codec_options import CodecOptions
from config import Config
@@ -9,7 +10,26 @@ from pymongo.errors import AutoReconnect

class MongoDatabse():

    def __init__(self):
    _instance = None
    _lock = Lock()

    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:  # double-checked
                    cls._instance = super().__new__(cls)
                    cls._instance._init_once()
        return cls._instance

    def close(self):
        if getattr(self, "_client", None):
            self._client.close()
            self._client = None

    def get_col_by_name(self, name):
        return self.db[name].with_options(codec_options=CodecOptions(tz_aware=True))

    def _init_once(self):
        self.config = Config().get_config()
        self.db = self.__connect()
        self.invoker_col = self.config['mongo']['invoker_col']
@@ -78,3 +98,9 @@ class MongoDatabse():
                print("Capif_configuration already contains data with a unique ccf_id. No default values inserted.")


_singleton = None
def get_mongo():
    global _singleton
    if _singleton is None:
        _singleton = MongoDatabse()
    return _singleton
 No newline at end of file
+14 −0
Original line number Diff line number Diff line
@@ -33,6 +33,20 @@ paths:
          $ref: '#/components/responses/InternalError'
        default:
          $ref: '#/components/responses/GenericError'
  /getCcfId:
    get:
      summary: Get CCF ID
      description: Retrieves the CCF ID of the CAPIF Core Function.
      operationId: helper_controller.get_ccf_id
      responses:
        '200':
          description: CCF ID retrieved successfully.
        '400':
          $ref: '#/components/responses/BadRequest'
        '500':
          $ref: '#/components/responses/InternalError'
        default:
          $ref: '#/components/responses/GenericError'
  /getInvokers:
    get:
      summary: Retrieve API invokers
+99 −43
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@ paths:
    get:
      summary: Read full configuration
      description: Returns the entire CAPIF configuration document.
      operationId: dynamic_config_controller.get_configuration
      operationId: configuration_controller.get_configuration
      responses:
        '200':
          description: Current configuration
@@ -100,20 +100,20 @@ paths:
          $ref: '#/components/responses/InternalError'
        default:
          $ref: '#/components/responses/GenericError'
  /removeConfigParam:
    delete:
      summary: Remove config parameter
      description: Deletes a leaf parameter by dotted path.
      operationId: dynamic_config_controller.remove_config_param
  /addNewConfigSetting:
    patch:
      summary: Add new configuration category
      description: Adds a brand new top-level category.
      operationId: dynamic_config_controller.add_new_configuration
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConfigParamRemoveRequest'
              $ref: '#/components/schemas/ConfigCategoryCreateRequest'
      responses:
        '200':
          description: Parameter removed
          description: Category added
          content:
            application/json:
              schema:
@@ -124,20 +124,21 @@ paths:
          $ref: '#/components/responses/InternalError'
        default:
          $ref: '#/components/responses/GenericError'
  /configuration/category:
    post:
      summary: Add new configuration category
      description: Adds a brand new top-level category.
      operationId: dynamic_config_controller.add_new_configuration
      requestBody:
  /removeConfigParam:
    delete:
      summary: Remove config parameter
      description: Deletes a leaf parameter by dotted path.
      operationId: dynamic_config_controller.remove_config_param
      parameters:
        - name: param_path
          in: query
          required: true
        content:
          application/json:
          schema:
              $ref: '#/components/schemas/ConfigCategoryCreateRequest'
            type: string
          description: Parameter path to remove
      responses:
        '200':
          description: Category added
          description: Parameter removed
          content:
            application/json:
              schema:
@@ -148,16 +149,18 @@ paths:
          $ref: '#/components/responses/InternalError'
        default:
          $ref: '#/components/responses/GenericError'
  /removeConfigCategory:
    delete:
      summary: Remove configuration category
      description: Deletes an entire top-level category by name.
      operationId: dynamic_config_controller.remove_config_category
      requestBody:
      parameters:
        - name: config_path
          in: query
          required: true
        content:
          application/json:
          schema:
              $ref: '#/components/schemas/ConfigCategoryRemoveRequest'
            type: string
          description: Configuration path to remove
      responses:
        '200':
          description: Category removed
@@ -196,7 +199,19 @@ components:
      type: object
      additionalProperties: true
      description: CAPIF runtime configuration document.
      
      properties:
        config_name:
          type: string
          example: default
          description: Configuration name
        version:
          type: string
          example: 1.0
          description: configuration version
        settings:
          type: object
          items:
            $ref: '#/components/schemas/Settings'
    ConfigParamUpdateRequest:
      type: object
      required:
@@ -208,14 +223,6 @@ components:
          description: Dotted path to the configuration value to update.
        new_value:
          description: New value for the configuration parameter.
    ConfigParamRemoveRequest:
      type: object
      required:
        - param_path
      properties:
        param_path:
          type: string
          description: Dotted path to the configuration value to delete.
    ConfigCategoryCreateRequest:
      type: object
      required:
@@ -229,14 +236,6 @@ components:
          type: object
          additionalProperties: true
          description: Key/value pairs that compose the new category.
    ConfigCategoryRemoveRequest:
      type: object
      required:
        - category_name
      properties:
        category_name:
          type: string
          description: Name of the category to remove.
    GenericError:
      type: object
      properties:
@@ -247,3 +246,60 @@ components:
      required:
        - code
        - message
    Settings:
      type: object
      description: Configuration Settings
      properties:
        certificates_expiry:
          type: object
          description: Expiry configuration for certificates
          properties:
            ttl_superadmin_cert:
              type: string
              example: 4300h
              description: ttl for superadmin certificates
            ttl_invoker_cert:
              type: string
              example: 4300h
              description: ttl for invoker certificates
            ttl_provider_cert:
              type: string
              example: 4300h
              description: ttl for provider certificates
        security_method_priority:
          type: object
          description: priority to follow in granting the security method
          properties:
            oauth:
              type: integer
              example: 1
            pki:
              type: integer
              example: 2
            psk:
              type: integer
              example: 3
        acl_policy_settings:
          type: object
          description: default access policies
          properties:
            allowed_total_invocations:
              type: string
              example: 5
              description: total number of requests the invoker can make
            allowed_invocations_per_second:
              type: string
              example: 5
              description: total number of requests the invoker can make per second
            allowed_invocations_time_range_days:
              type: integer
              example: 365
              description: time range when an invoker can make requests
          
          
          
          
          
          
          
          
 No newline at end of file
Loading