Resolve "Create ccfId on deployment (Helper component)"

Proposers

  • Guillermo Sanz López (Telefónica) ...

Description

Create a id for the capif in the helper deployment and save it in the database.

Demo or definition of done

Describe which high level conditions needs to be fulfilled to demonstrate this feature implementation is completed. You can reference external content (example, demo paper) listed in section "References" as [Ref-2].

Acknowledgements

This work is funded by the European Commission through the project with Grant Agreement number .

Closes #173 (closed)

Merge request reports

Loading
+6 −0
Changes for services/helper/helper_service/controllers/helper_controller.py: 6 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -191,3 +191,9 @@ def remove_config_category():
        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()
+46 −10
Changes for services/helper/helper_service/core/helper_operations.py: 46 added lines, 10 removed lines.
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@ from utils.utils import (

class HelperOperations:

    PROTECTED_FIELDS = ["ccf_id"]

    def __init__(self):
        self.db = MongoDatabse()
        self.mimetype = 'application/json'
@@ -228,6 +230,10 @@ class HelperOperations:
        """
        current_app.logger.debug(f"Updating configuration parameter: {param_path} with value: {new_value}")

        # Protect immutable fields
        if any(param_path.startswith(field) for field in self.PROTECTED_FIELDS):
            return jsonify(message=f"The parameter '{param_path}' is immutable and cannot be modified"), 403

        config_col = self.db.get_col_by_name(self.db.capif_configuration)

        existing_config = config_col.find_one({}, {"_id": 0})
@@ -251,9 +257,6 @@ class HelperOperations:
    
    
    def replace_configuration(self, new_config):
        """
        Replace all current settings with a new one.
        """
        current_app.logger.debug("Replacing entire CAPIF configuration")

        error_response = validate_snake_case_keys(new_config)
@@ -263,16 +266,18 @@ class HelperOperations:
        config_col = self.db.get_col_by_name(self.db.capif_configuration)
        existing_config = config_col.find_one({}, {"_id": 0})

        if existing_config:
            new_config = convert_nested_values(new_config, existing_config)
        if not existing_config:
            return jsonify(message="No existing configuration found"), 404

        result = config_col.replace_one({}, new_config, upsert=True)
        # Preserve protected fields
        for field in self.PROTECTED_FIELDS:
            if field in existing_config:
                new_config[field] = existing_config[field]

        if result.matched_count == 0:
            return jsonify(message="No existing configuration found; a new one was created"), 201

        return jsonify(message="Configuration replaced successfully"), 200
        new_config = convert_nested_values(new_config, existing_config)
        result = config_col.replace_one({}, new_config, upsert=True)

        return jsonify(message="Configuration replaced successfully (protected fields preserved)"), 200


    def add_new_configuration(self, category_name, category_values):
@@ -281,6 +286,10 @@ class HelperOperations:
        """
        current_app.logger.debug(f"Adding new category: {category_name} with values: {category_values}")

        # Block protected field creation
        if category_name in self.PROTECTED_FIELDS:
            return jsonify(message=f"The category '{category_name}' is immutable and cannot be modified"), 403

        config_col = self.db.get_col_by_name(self.db.capif_configuration)

        category_name_snake = to_snake_case(category_name)
@@ -299,6 +308,11 @@ class HelperOperations:
    def add_new_config_setting(self, param_path, new_value):
        """Add a new parameter in 'settings'."""
        current_app.logger.debug(f"Adding new configuration setting: {param_path} with value: {new_value}")

        # Block protected field creation
        if any(param_path.startswith(field) for field in self.PROTECTED_FIELDS):
            return jsonify(message=f"The parameter '{param_path}' is immutable and cannot be added or modified"), 403
    
        config_col = self.db.get_col_by_name(self.db.capif_configuration)

        param_path_snake = ".".join(to_snake_case(part) for part in param_path.split("."))
@@ -316,6 +330,10 @@ class HelperOperations:
        """Removes a specific parameter inside 'settings'."""
        current_app.logger.debug(f"Removing configuration parameter: {param_path}")

        # Prevent deletion of protected fields
        if any(param_path.startswith(field) for field in self.PROTECTED_FIELDS):
            return jsonify(message=f"The parameter '{param_path}' is immutable and cannot be removed"), 403

        config_col = self.db.get_col_by_name(self.db.capif_configuration)

        param_path_snake = ".".join(to_snake_case(part) for part in param_path.split("."))
@@ -334,6 +352,10 @@ class HelperOperations:
        """Removes an entire category inside 'settings'."""
        current_app.logger.debug(f"Removing configuration category: {category_name}")

        # Prevent deletion of protected fields
        if category_name in self.PROTECTED_FIELDS:
            return jsonify(message=f"The category '{category_name}' is immutable and cannot be removed"), 403

        config_col = self.db.get_col_by_name(self.db.capif_configuration)

        category_name_snake = to_snake_case(category_name)
@@ -346,3 +368,17 @@ class HelperOperations:
            return jsonify(message=f"No configuration found or category '{category_name_snake}' not removed"), 404

        return jsonify(message=f"Category '{category_name_snake}' removed successfully"), 200
    
    def get_ccf_id(self):
        """
        Returns the current CAPIF unique identifier (ccf_id).
        """
        current_app.logger.debug("Retrieving ccf_id from capif_configuration")

        config_col = self.db.get_col_by_name(self.db.capif_configuration)
        config = config_col.find_one({}, {"_id": 0, "ccf_id": 1})

        if not config or "ccf_id" not in config:
            return jsonify(message="ccf_id not found"), 404

        return jsonify(ccf_id=config["ccf_id"]), 200
+16 −2
Changes for services/helper/helper_service/db/db.py: 16 added lines, 2 removed lines.
Original line number Diff line number Diff line
import time
import secrets

from bson.codec_options import CodecOptions
from config import Config
@@ -59,8 +60,21 @@ class MongoDatabse():
            # Read configuration from config.yaml
            default_config = self.config["capif_configuration"]

            # Generate unique ccf_id
            ccf_id = "CCF" + secrets.token_hex(15)
            default_config["ccf_id"] = ccf_id

            capif_col.insert_one(default_config)
            print("Default data inserted into the capif_configuration collection from config.yaml")
            print(f"Default data inserted into capif_configuration from config.yaml with ccf_id={ccf_id}")

        else:
            print("The capif_configuration collection already contains data. No default values were inserted.")
            # Ensure ccf_id exists even if config already there
            existing_config = capif_col.find_one({}, {"_id": 0})
            if "ccf_id" not in existing_config:
                ccf_id = "CCF" + secrets.token_hex(15)
                capif_col.update_one({}, {"$set": {"ccf_id": ccf_id}})
                print(f"Added missing ccf_id={ccf_id} to existing CAPIF configuration")
            else:
                print("Capif_configuration already contains data with a unique ccf_id. No default values inserted.")

Loading