Merge Feat/10 challenge 10 slice ddbb integration

Merge request reports

Loading
+7 −26
Changes for src/api/main.py: 7 added lines, 26 removed lines.
Original line number Diff line number Diff line
@@ -14,10 +14,10 @@

# This file is an original contribution from Telefonica Innovación Digital S.L.

from src.config.constants import DATABASE_PATH
from src.utils.send_response import send_response
import os, json, logging
import logging
from flask import current_app
from src.database.db import get_data, delete_data, get_all_data, delete_all_data

class Api:
    def __init__(self, slice_service):
@@ -81,8 +81,7 @@ class Api:
        """
        try:
            # Read slice database from JSON file
            with open(os.path.join(DATABASE_PATH, "slice_ddbb.json"), 'r') as file:
                content = json.load(file)
            content = get_all_data()
            # If specific slice ID is provided, find and return matching slice
            if slice_id:
                for slice in content:
@@ -160,24 +159,14 @@ class Api:
            - If need_l2vpn_support is True, performs additional L2VPN cleanup
        """
        try:
            # Read current slice database
            with open(os.path.join(DATABASE_PATH, "slice_ddbb.json"), 'r') as file:
                content = json.load(file)
            id = None

            # Delete specific slice if slice_id is provided
            if slice_id:
                for i, slice in enumerate(content):
                    if slice["slice_id"] == slice_id and slice.get("controller") == self.slice_service.controller_type:
                        del content[i]
                        id = i
                        break
                slice = get_data(slice_id)
                # Raise error if slice not found
                if id is None:
                if not slice or slice.get("controller") != self.slice_service.controller_type:
                    raise ValueError("Transport network slice not found")
                # Update slice database
                with open(os.path.join(DATABASE_PATH, "slice_ddbb.json"), 'w') as file:
                    json.dump(content, file, indent=4)
                delete_data(slice_id)
                logging.info(f"Slice {slice_id} removed successfully")
                return {}, 204
            
@@ -189,16 +178,8 @@ class Api:
                    if current_app.config["TFS_L2VPN_SUPPORT"]:
                        self.slice_service.tfs_l2vpn_delete()

                data_removed = [slice for slice in content if slice.get("controller") == self.slice_service.controller_type] 

                # Verify slices exist before deletion
                if len(data_removed) == 0:
                    raise ValueError("Transport network slices not found")

                filtered_data = [slice for slice in content if slice.get("controller") != self.slice_service.controller_type]    
                # Clear slice database
                with open(os.path.join(DATABASE_PATH, "slice_ddbb.json"), 'w') as file:
                    json.dump(filtered_data, file, indent=4)
                delete_all_data()

                logging.info("All slices removed successfully")
                return {}, 204

src/database/db.py

0 → 100644
+138 −0
Changes for src/database/db.py: 138 added lines, 0 removed lines.
Original line number Diff line number Diff line
# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import sqlite3, json, logging

# Database file
DB_NAME = "slice.db"

# Initialize database and create table
def init_db():
    conn = sqlite3.connect(DB_NAME)
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS slice (
            slice_id TEXT PRIMARY KEY,
            intent TEXT NOT NULL,
            controller TEXT NOT NULL
        )
    """)
    conn.commit()
    conn.close()

# Save data to the database
def save_data(slice_id: str, intent_dict: dict, controller: str):
    intent_str = json.dumps(intent_dict)
    conn = sqlite3.connect(DB_NAME)
    cursor = conn.cursor()
    try:
        cursor.execute("INSERT INTO slice (slice_id, intent, controller) VALUES (?, ?, ?)", (slice_id, intent_str, controller))
        conn.commit()
    except sqlite3.IntegrityError:
        raise ValueError(f"Slice with id '{slice_id}' already exists.")
    finally:
        conn.close()

# Update data in the database
def update_data(slice_id: str, new_intent_dict: dict, controller: str):
    intent_str = json.dumps(new_intent_dict)
    conn = sqlite3.connect(DB_NAME)
    cursor = conn.cursor()
    cursor.execute("UPDATE slice SET intent = ?, controller = ? WHERE slice_id = ?", (intent_str, controller, slice_id))
    if cursor.rowcount == 0:
        raise ValueError(f"No slice found with id '{slice_id}' to update.")
    else:
        logging.debug(f"Slice '{slice_id}' updated.")
    conn.commit()
    conn.close()

# Delete data from the database
def delete_data(slice_id: str):
    conn = sqlite3.connect(DB_NAME)
    cursor = conn.cursor()
    cursor.execute("DELETE FROM slice WHERE slice_id = ?", (slice_id,))
    if cursor.rowcount == 0:
        raise ValueError(f"No slice found with id '{slice_id}' to delete.")
    else:
        logging.debug(f"Slice '{slice_id}' deleted.")
    conn.commit()
    conn.close()

# Get data from the database
def get_data(slice_id: str) -> dict[str, dict, str]:
    conn = sqlite3.connect(DB_NAME)
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM slice WHERE slice_id = ?", (slice_id,))
    row = cursor.fetchone()
    conn.close()

    if row:
        column_names = [description[0] for description in cursor.description]
        result = dict(zip(column_names, row))
        if isinstance(result.get("intent"), str):
            try:
                result["intent"] = json.loads(result["intent"])
            except json.JSONDecodeError:
                raise Exception("Warning: 'intent' is not a valid JSON string.")
        return result

    else:
        raise ValueError(f"No slice found with id '{slice_id}'.")

# Get all slices
def get_all_data() -> dict[str, dict, str]:
    conn = sqlite3.connect(DB_NAME)
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM slice")
    rows = cursor.fetchall()
    conn.close()
    return [
        {
        "slice_id": row[0],
        "intent": json.loads(row[1]),
        "controller": row[2] 
        }
    for row in rows
    ]

def delete_all_data():
    conn = sqlite3.connect(DB_NAME)
    cursor = conn.cursor()
    cursor.execute("DELETE FROM slice")
    conn.commit()
    conn.close()
    logging.debug("All slice data deleted.")

# Example usage
if __name__ == "__main__":
    init_db()

    # Save a slice
    test_intent = {"bandwidth": "1Gbps", "latency": "10ms", "provider": "opensec"}
    save_data("slice-001", test_intent, "TFS")

    # Get the slice
    result = get_data("slice-001")
    if result:
        print(f"Retrieved intent for slice-001: {result}")

    # Update the slice
    updated_intent = {"bandwidth": "2Gbps", "latency": "5ms", "provider": "opensec"}
    update_data("slice-001", updated_intent, "TFS")

    # Delete the slice
    delete_data("slice-001")

    get_all_data()
    delete_all_data()

src/database/slice_ddbb.json

deleted100644 → 0
+0 −1
Changes for src/database/slice_ddbb.json: 0 added lines, 1 removed line.
Original line number Diff line number Diff line
[]
 No newline at end of file
+4 −26
Changes for src/database/store_data.py: 4 added lines, 26 removed lines.
Original line number Diff line number Diff line
@@ -14,8 +14,7 @@

# This file is an original contribution from Telefonica Innovación Digital S.L.

import json, os
from src.config.constants import DATABASE_PATH
from src.database.db import save_data, update_data

def store_data(intent, slice_id, controller_type=None):
    """
@@ -30,31 +29,10 @@ def store_data(intent, slice_id, controller_type=None):
        intent (dict): Network slice intent to be stored
        slice_id (str, optional): Existing slice ID to update. Defaults to None.
    """
    file_path = os.path.join(DATABASE_PATH, "slice_ddbb.json")
    # Create initial JSON file if it doesn't exist
    if not os.path.exists(file_path):
        with open(file_path, 'w') as file:
            json.dump([], file, indent=4)

    # Read existing content
    with open(file_path, 'r') as file:
        content = json.load(file)

    # Update or add new slice intent
    if slice_id:
        # Update existing slice intent
        for slice in content:
            if slice["slice_id"] == slice_id:
                slice["intent"] = intent
        update_data(slice_id, intent, controller_type)
    else:
        # Add new slice intent
        content.append(
            {
                "slice_id": intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["id"],
                "intent": intent,
                "controller": controller_type,
            })
    
    # # Write updated content back to file
    with open(file_path, 'w') as file:
        json.dump(content, file, indent=4)
 No newline at end of file
        slice_id = intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["id"]
        save_data(slice_id, intent, controller_type)
 No newline at end of file
+2 −3
Changes for src/webui/gui.py: 2 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -141,7 +141,6 @@ def __datos_json():
    try:
        with open(os.path.join(SRC_PATH, 'slice_ddbb.json'), 'r') as fichero:
            datos =json.load(fichero)
            print(datos)
            rows =[]
            for source_ip, source_info in datos["source"].items():
                vlan = source_info["vlan"]
@@ -165,8 +164,8 @@ def home():
    session['enter'] = False
    # Leer las IPs actuales del archivo de configuración
    try:
        tfs_ip = {"TFS_IP": current_app.config["TFS_IP"]}
        ixia_ip = {"IXIA_IP": current_app.config["IXIA_IP"]}
        tfs_ip = current_app.config["TFS_IP"]
        ixia_ip = current_app.config["IXIA_IP"]
    except Exception:
        tfs_ip = 'No configurada'
        ixia_ip = 'No configurada'
Loading
Loading