Loading src/api/main.py +277 −19 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ from flask import current_app from src.database.db import get_data, delete_data, get_all_data, delete_all_data from src.realizer.tfs.helpers.tfs_connector import tfs_connector from src.utils.safe_get import safe_get from src.database.sysrepo_store import get_data_store, create_data_store, delete_data_store from src.database.sysrepo_store import get_data_store, create_data_store, delete_data_store, update_data_store, normalize_libyang_data class Api: def __init__(self, slice_service): Loading Loading @@ -299,15 +299,14 @@ class Api: def add_network_slice_service(self, intent): try: # result = self.slice_service.nsc(intent) result = self.slice_service.nsc(intent) if result: create_data_store(intent) # if not result: # return send_response(False, code=404, message="No intents found") logging.info(f"Slice created successfully") logging.info(f"Network Slice created successfully") return send_response( True, code=201, data="Data stored successfully" data=result ) except RuntimeError as e: # Handle case where there is no content to process Loading @@ -328,7 +327,7 @@ class Api: return send_response( True, code=201, message="Template created successfully" data="Template created successfully" # Añadir otra data? ) except Exception as e: # Handle unexpected errors Loading @@ -336,21 +335,47 @@ class Api: def add_slice_service(self, intent): try: slice_id = intent.pop("id", None) xpath = f"/ietf-network-slice-service:network-slice-services/slice-service[id='{slice_id}']" xpath = f"/ietf-network-slice-service:network-slice-services/slice-service[id='{intent.get('id')}']" existing_slice = get_data_store(xpath) if existing_slice: return send_response(False, code=409, message="Slice already exists") if "slo-sle-template" in intent: template_ref = intent.get("slo-sle-template") xpath_template = f"/ietf-network-slice-service:network-slice-services/slo-sle-templates/slo-sle-template[id='{template_ref}']" existing_template = get_data_store(xpath_template) if not existing_template: return send_response(False, code=404, message="Referenced SLO/SLE template not found") full_intent = { "ietf-network-slice-service:network-slice-services": { "slo-sle-templates": { "slo-sle-template": [existing_template["network-slice-services"]["slo-sle-templates"]["slo-sle-template"][template_ref]] }, "slice-service": [intent] } } elif "service-slo-sle-policy" in intent: full_intent = { "ietf-network-slice-service:network-slice-services": { "slo-sle-templates": { "slo-sle-template": intent.get("service-slo-sle-policy") }, "slice-service": [intent] } } else: return send_response(False, code=400, message="No SLO/SLE template or policy provided in intent") full_intent = normalize_libyang_data(full_intent) result = self.slice_service.nsc(full_intent) if result: intent.pop("id", None) create_data_store(intent, xpath) #result = self.slice_service.nsc(intent) # if not result: # return send_response(False, code=404, message="No intents found") logging.info(f"Slice created successfully") return send_response( True, code=201, data="Data stored successfully" data=result ) except RuntimeError as e: # Handle case where there is no content to process Loading @@ -377,14 +402,226 @@ class Api: # Handle unexpected errors return send_response(False, code=500, message=str(e)) ### PUT def update_network_slice_service(self, intent): """ Modifica (reemplaza) toda la configuración de network-slice-services """ try: xpath = "/ietf-network-slice-service:network-slice-services" # Verificar que existe algo que modificar existing_data = get_data_store(xpath) if not existing_data: return send_response(False, code=404, message="Network slice services not found") # Si no está en modo DUMMY, procesar con TFS result = self.slice_service.nsc(intent) if not result: return send_response(False, code=500, message="Failed to process slice in TFS") # Reemplazar completamente el recurso update_data_store(intent) logging.info("Network slice services modified successfully") return send_response( True, code=200, message="Network slice services updated successfully" ) except ValueError as e: return send_response(False, code=404, message=str(e)) except Exception as e: return send_response(False, code=500, message=str(e)) def update_slo_sle_template(self, template_id, template): """ Modifica (reemplaza) un template SLO/SLE específico """ try: xpath = f"/ietf-network-slice-service:network-slice-services/slo-sle-templates/slo-sle-template[id='{template_id}']" # Verificar que el template existe existing_template = get_data_store(xpath) if not existing_template: return send_response(False, code=404, message="Template not found") # Asegurar que el ID en el body coincide con el de la URL if "id" in template and template["id"] != template_id: return send_response(False, code=400, message="Template ID in body does not match URL") slices = get_data_store("/ietf-network-slice-service:network-slice-services/slice-service") for slice in slices["network-slice-services"]["slice-service"]: if "slo-sle-template" in slice: if slice.get("slo-sle-template") == template_id: full_intent = { "ietf-network-slice-service:network-slice-services": { "slo-sle-templates": { "slo-sle-template": [existing_template["network-slice-services"]["slo-sle-templates"]["slo-sle-template"][template_id]] }, "slice-service": [slice] } } full_intent = normalize_libyang_data(full_intent) result = self.slice_service.nsc(full_intent, slice.get("id")) if not result: return send_response(False, code=500, message="Slice not updated") # Eliminar el ID del body si existe (ya está en el predicado) template_data = template.copy() template_data.pop("id", None) # Reemplazar el template update_data_store(template_data, xpath) logging.info(f"Template {template_id} modified successfully") return send_response( True, code=200, message="Template updated successfully", data=result ) except ValueError as e: return send_response(False, code=404, message=str(e)) except Exception as e: return send_response(False, code=500, message=str(e)) def update_slice_service(self, slice_id, intent): """ Modifica (reemplaza) un slice service específico """ try: xpath = f"/ietf-network-slice-service:network-slice-services/slice-service[id='{slice_id}']" # Verificar que el slice existe existing_slice = get_data_store(xpath) if not existing_slice: return send_response(False, code=404, message="Slice not found") # Asegurar que el ID en el body coincide con el de la URL if "id" in intent and intent["id"] != slice_id: return send_response(False, code=400, message="Slice ID in body does not match URL") # Validar que existe el template SLO/SLE referenciado if "slo-sle-template" in intent: template_ref = intent.get("slo-sle-template") xpath_template = f"/ietf-network-slice-service:network-slice-services/slo-sle-templates/slo-sle-template[id='{template_ref}']" existing_template = get_data_store(xpath_template) if not existing_template: return send_response(False, code=404, message="Referenced SLO/SLE template not found") # Construir el intent completo para TFS full_intent = { "ietf-network-slice-service:network-slice-services": { "slo-sle-templates": { "slo-sle-template": [existing_template["network-slice-services"]["slo-sle-templates"]["slo-sle-template"][template_ref]] }, "slice-service": [intent] } } elif "service-slo-sle-policy" in intent: full_intent = { "ietf-network-slice-service:network-slice-services": { "slo-sle-templates": { "slo-sle-template": intent.get("service-slo-sle-policy") }, "slice-service": [intent] } } else: return send_response(False, code=400, message="No SLO/SLE template or policy provided in intent") full_intent = normalize_libyang_data(full_intent) result = self.slice_service.nsc(full_intent) if not result: return send_response(False, code=500, message="Slice not updated") # Eliminar el ID del body (ya está en el predicado) intent_data = intent.copy() intent_data.pop("id", None) # Reemplazar el slice update_data_store(intent_data, xpath) logging.info(f"Slice {slice_id} modified successfully") return send_response( True, code=200, message="Slice updated successfully", data=result ) except ValueError as e: return send_response(False, code=404, message=str(e)) except RuntimeError as e: return send_response(False, code=200, message=str(e)) except Exception as e: return send_response(False, code=500, message=str(e)) def update_sdp(self, slice_id, sdp_id, sdp): """ Modifica (reemplaza) un SDP específico dentro de un slice """ try: # Verificar que el slice existe slice_xpath = f"/ietf-network-slice-service:network-slice-services/slice-service[id='{slice_id}']" existing_slice = get_data_store(slice_xpath) if not existing_slice: return send_response(False, code=404, message="Slice not found") # Verificar que el SDP existe sdp_xpath = f"/ietf-network-slice-service:network-slice-services/slice-service[id='{slice_id}']/sdps/sdp[id='{sdp_id}']" existing_sdp = get_data_store(sdp_xpath) if not existing_sdp: return send_response(False, code=404, message="SDP not found") # Asegurar que el ID en el body coincide con el de la URL if "id" in sdp and sdp["id"] != sdp_id: return send_response(False, code=400, message="SDP ID in body does not match URL") # Eliminar el ID del body (ya está en el predicado) sdp_data = sdp.copy() sdp_data.pop("id", None) # Reemplazar el SDP update_data_store(sdp_data, sdp_xpath) logging.info(f"SDP {sdp_id} in slice {slice_id} modified successfully") return send_response( True, code=200, message="SDP updated successfully" ) except ValueError as e: return send_response(False, code=404, message=str(e)) except Exception as e: return send_response(False, code=500, message=str(e)) ### DELETE def delete_network_slice_services(self): try: # Delete specific slice if slice_id is provided xpath = f"/ietf-network-slice-service:network-slice-services" if not current_app.config["DUMMY_MODE"]: content = get_data_store(xpath) for slice in content["network-slice-services"]["slice-service"]: slice_type = list(slice["service-tags"]["tag-type"]["ietf-network-slice-service:service"]["tag-type-value"])[0] if not slice_type: slice_type = "L2" logging.warning(f"Slice type not found in slice intent. Defaulting to L2") logging.debug(f"Send slice to delete in TFS with slice_type {slice_type}") tfs_connector().nbi_delete(current_app.config["TFS_IP"], slice_type, slice.get("id")) if current_app.config["TFS_L2VPN_SUPPORT"]: self.slice_service.tfs_l2vpn_delete() delete_data_store(xpath) logging.info("All slices removed successfully") return {}, 204 except ValueError as e: Loading Loading @@ -424,6 +661,16 @@ class Api: existing_slice = get_data_store(xpath) if not existing_slice: raise ValueError("Slice not found") if not current_app.config["DUMMY_MODE"]: slice_type = list(existing_slice["network-slice-services"]["slice-service"][slice_id]["service-tags"]["tag-type"]["ietf-network-slice-service:service"]["tag-type-value"])[0] if not slice_type: slice_type = "L2" logging.warning(f"Slice type not found in slice intent. Defaulting to L2") logging.debug(f"Send slice to delete in TFS with slice_type {slice_type}") tfs_connector().nbi_delete(current_app.config["TFS_IP"], slice_type, existing_slice.get("id")) if current_app.config["TFS_L2VPN_SUPPORT"]: self.slice_service.tfs_l2vpn_delete() delete_data_store(xpath) logging.info(f"Slice {slice_id} removed successfully") return {}, 204 Loading @@ -431,6 +678,17 @@ class Api: # Delete all slices else: xpath = f"/ietf-network-slice-service:network-slice-services/slice-service" if not current_app.config["DUMMY_MODE"]: content = get_data_store(xpath) for slice in content["network-slice-services"]["slice-service"]: slice_type = list(slice["service-tags"]["tag-type"]["ietf-network-slice-service:service"]["tag-type-value"])[0] if not slice_type: slice_type = "L2" logging.warning(f"Slice type not found in slice intent. Defaulting to L2") logging.debug(f"Send slice to delete in TFS with slice_type {slice_type}") tfs_connector().nbi_delete(current_app.config["TFS_IP"], slice_type, slice.get("id")) if current_app.config["TFS_L2VPN_SUPPORT"]: self.slice_service.tfs_l2vpn_delete() delete_data_store(xpath) logging.info("All slices removed successfully") return {}, 204 Loading src/database/store_data.py +5 −3 Original line number Diff line number Diff line Loading @@ -32,9 +32,11 @@ def store_data(intent, slice_id, controller_type=None): """ # Update or add new slice intent if slice_id: if controller_type != "RESTCONF": update_data(slice_id, intent, controller_type) else: # Add new slice intent slice_id = intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["id"] #save_data(slice_id, intent, controller_type) create_data_store(intent, xpath=f"/ietf-network-slice-service:network-slice-services/slice-service[id='{slice_id}']") No newline at end of file if controller_type != "RESTCONF": save_data(slice_id, intent, controller_type) No newline at end of file src/database/sysrepo_store.py +140 −30 File changed.Preview size limit exceeded, changes collapsed. Show changes swagger/models/create_models_restconf.py +1 −1 Original line number Diff line number Diff line Loading @@ -283,5 +283,5 @@ def create_ietf_network_slice_nbi_yang_model(slice_ns): slice_service_model, slo_sle_template_model, sdp_model, NetworkSliceServicesFull common_template ) swagger/restconf_namespace.py +42 −4 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ restconf_ns = Namespace( "restconf", description="RESTCONF operations for IETF Network Slice Service YANG model" ) ietf_network_slice_service_response, slice_service_response, slo_sle_template_response, sdp_response, slice_response_model, slice_service_model, slo_sle_template_model, sdp_model, ietf_network_slice_service_model = create_ietf_network_slice_nbi_yang_model(restconf_ns) ietf_network_slice_service_response, slice_service_response, slo_sle_template_response, sdp_response, slice_response_model, slice_service_model, slo_sle_template_model, sdp_model, common_template = create_ietf_network_slice_nbi_yang_model(restconf_ns) @restconf_ns.route("/data/ietf-network-slice-service:network-slice-services") class NetworkSliceServices(Resource): Loading @@ -23,7 +23,7 @@ class NetworkSliceServices(Resource): return Api(controller).get_network_slice_services() @restconf_ns.doc(summary="Create Network Slice Services") @restconf_ns.expect(ietf_network_slice_service_model) @restconf_ns.expect(common_template) @restconf_ns.response(201, "Container network-slice-services created", slice_response_model) @restconf_ns.response(500, "Internal server error") def post(self): Loading @@ -31,6 +31,16 @@ class NetworkSliceServices(Resource): controller = NSController(controller_type="RESTCONF") return Api(controller).add_network_slice_service(json_data) @restconf_ns.doc(summary="Update Network Slice Services") @restconf_ns.expect(common_template) @restconf_ns.response(200, "Container network-slice-services updated", slice_response_model) @restconf_ns.response(404, "Nothing found to update") @restconf_ns.response(500, "Internal server error") def put(self): json_data = request.get_json() controller = NSController(controller_type="RESTCONF") return Api(controller).update_network_slice_service(json_data) @restconf_ns.doc(summary="Delete Network Slice Services") @restconf_ns.response(204, "All slices deleted") @restconf_ns.response(500, "Internal server error") Loading @@ -49,7 +59,8 @@ class SliceServiceList(Resource): return Api(controller).get_slice_services() @restconf_ns.doc(summary="Create Slice Services") @restconf_ns.expect(slice_service_model) @restconf_ns.expect(common_template) #@restconf_ns.expect(slice_service_model) @restconf_ns.response(201, "Slice created", slice_response_model) @restconf_ns.response(409, "Slice already exists") def post(self): Loading @@ -74,6 +85,15 @@ class SliceService(Resource): controller = NSController(controller_type="RESTCONF") return Api(controller).get_slice_services(slice_service_id) @restconf_ns.doc(summary="Update Slice Service by ID") @restconf_ns.expect(common_template) @restconf_ns.response(200, "Slice updated", slice_response_model) @restconf_ns.response(404, "No slice found to update") def put(self, slice_service_id): json_data = request.get_json() controller = NSController(controller_type="RESTCONF") return Api(controller).update_slice_service(slice_service_id, json_data) @restconf_ns.doc(summary="Delete a Slice Service by ID") @restconf_ns.response(204, "Slice deleted") @restconf_ns.response(404, "Slice not found") Loading Loading @@ -115,6 +135,15 @@ class SloSleTemplate(Resource): controller = NSController(controller_type="RESTCONF") return Api(controller).get_slo_sle_templates(slo_sle_template_id) @restconf_ns.doc(summary="Update SLO/SLE template by ID") @restconf_ns.expect(slo_sle_template_model) @restconf_ns.response(200, "Template updated", slice_response_model) @restconf_ns.response(404, "No template found to update") def put(self, slo_sle_template_id): json_data = request.get_json() controller = NSController(controller_type="RESTCONF") return Api(controller).update_slo_sle_template(slo_sle_template_id, json_data) @restconf_ns.doc(summary="Delete SLO/SLE template by ID") @restconf_ns.response(204, "Template deleted") def delete(self, slo_sle_template_id): Loading @@ -131,7 +160,8 @@ class SdpList(Resource): return Api(controller).get_sdps(slice_service_id) @restconf_ns.doc(summary="Create Slice Service SDPs") @restconf_ns.expect(sdp_model) @restconf_ns.expect(common_template) #@restconf_ns.expect(sdp_model) @restconf_ns.response(201, "SDP created", slice_response_model) @restconf_ns.response(409, "SDP already exists") def post(self, slice_service_id): Loading @@ -153,6 +183,14 @@ class Sdp(Resource): def get(self, slice_service_id, sdp_id): controller = NSController(controller_type="RESTCONF") return Api(controller).get_sdps(slice_service_id, sdp_id) @restconf_ns.doc(summary="Update Slice Service SDP by ID") @restconf_ns.expect(common_template) @restconf_ns.response(200, "SDP updated", slice_response_model) @restconf_ns.response(404, "No SDP found to update") def put(self, slice_service_id, sdp_id): json_data = request.get_json() controller = NSController(controller_type="RESTCONF") return Api(controller).update_sdp(slice_service_id, sdp_id, json_data) @restconf_ns.doc(summary="Delete Slice Service SDP by ID") @restconf_ns.response(204, "SDP deleted") def delete(self, slice_service_id, sdp_id): Loading Loading
src/api/main.py +277 −19 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ from flask import current_app from src.database.db import get_data, delete_data, get_all_data, delete_all_data from src.realizer.tfs.helpers.tfs_connector import tfs_connector from src.utils.safe_get import safe_get from src.database.sysrepo_store import get_data_store, create_data_store, delete_data_store from src.database.sysrepo_store import get_data_store, create_data_store, delete_data_store, update_data_store, normalize_libyang_data class Api: def __init__(self, slice_service): Loading Loading @@ -299,15 +299,14 @@ class Api: def add_network_slice_service(self, intent): try: # result = self.slice_service.nsc(intent) result = self.slice_service.nsc(intent) if result: create_data_store(intent) # if not result: # return send_response(False, code=404, message="No intents found") logging.info(f"Slice created successfully") logging.info(f"Network Slice created successfully") return send_response( True, code=201, data="Data stored successfully" data=result ) except RuntimeError as e: # Handle case where there is no content to process Loading @@ -328,7 +327,7 @@ class Api: return send_response( True, code=201, message="Template created successfully" data="Template created successfully" # Añadir otra data? ) except Exception as e: # Handle unexpected errors Loading @@ -336,21 +335,47 @@ class Api: def add_slice_service(self, intent): try: slice_id = intent.pop("id", None) xpath = f"/ietf-network-slice-service:network-slice-services/slice-service[id='{slice_id}']" xpath = f"/ietf-network-slice-service:network-slice-services/slice-service[id='{intent.get('id')}']" existing_slice = get_data_store(xpath) if existing_slice: return send_response(False, code=409, message="Slice already exists") if "slo-sle-template" in intent: template_ref = intent.get("slo-sle-template") xpath_template = f"/ietf-network-slice-service:network-slice-services/slo-sle-templates/slo-sle-template[id='{template_ref}']" existing_template = get_data_store(xpath_template) if not existing_template: return send_response(False, code=404, message="Referenced SLO/SLE template not found") full_intent = { "ietf-network-slice-service:network-slice-services": { "slo-sle-templates": { "slo-sle-template": [existing_template["network-slice-services"]["slo-sle-templates"]["slo-sle-template"][template_ref]] }, "slice-service": [intent] } } elif "service-slo-sle-policy" in intent: full_intent = { "ietf-network-slice-service:network-slice-services": { "slo-sle-templates": { "slo-sle-template": intent.get("service-slo-sle-policy") }, "slice-service": [intent] } } else: return send_response(False, code=400, message="No SLO/SLE template or policy provided in intent") full_intent = normalize_libyang_data(full_intent) result = self.slice_service.nsc(full_intent) if result: intent.pop("id", None) create_data_store(intent, xpath) #result = self.slice_service.nsc(intent) # if not result: # return send_response(False, code=404, message="No intents found") logging.info(f"Slice created successfully") return send_response( True, code=201, data="Data stored successfully" data=result ) except RuntimeError as e: # Handle case where there is no content to process Loading @@ -377,14 +402,226 @@ class Api: # Handle unexpected errors return send_response(False, code=500, message=str(e)) ### PUT def update_network_slice_service(self, intent): """ Modifica (reemplaza) toda la configuración de network-slice-services """ try: xpath = "/ietf-network-slice-service:network-slice-services" # Verificar que existe algo que modificar existing_data = get_data_store(xpath) if not existing_data: return send_response(False, code=404, message="Network slice services not found") # Si no está en modo DUMMY, procesar con TFS result = self.slice_service.nsc(intent) if not result: return send_response(False, code=500, message="Failed to process slice in TFS") # Reemplazar completamente el recurso update_data_store(intent) logging.info("Network slice services modified successfully") return send_response( True, code=200, message="Network slice services updated successfully" ) except ValueError as e: return send_response(False, code=404, message=str(e)) except Exception as e: return send_response(False, code=500, message=str(e)) def update_slo_sle_template(self, template_id, template): """ Modifica (reemplaza) un template SLO/SLE específico """ try: xpath = f"/ietf-network-slice-service:network-slice-services/slo-sle-templates/slo-sle-template[id='{template_id}']" # Verificar que el template existe existing_template = get_data_store(xpath) if not existing_template: return send_response(False, code=404, message="Template not found") # Asegurar que el ID en el body coincide con el de la URL if "id" in template and template["id"] != template_id: return send_response(False, code=400, message="Template ID in body does not match URL") slices = get_data_store("/ietf-network-slice-service:network-slice-services/slice-service") for slice in slices["network-slice-services"]["slice-service"]: if "slo-sle-template" in slice: if slice.get("slo-sle-template") == template_id: full_intent = { "ietf-network-slice-service:network-slice-services": { "slo-sle-templates": { "slo-sle-template": [existing_template["network-slice-services"]["slo-sle-templates"]["slo-sle-template"][template_id]] }, "slice-service": [slice] } } full_intent = normalize_libyang_data(full_intent) result = self.slice_service.nsc(full_intent, slice.get("id")) if not result: return send_response(False, code=500, message="Slice not updated") # Eliminar el ID del body si existe (ya está en el predicado) template_data = template.copy() template_data.pop("id", None) # Reemplazar el template update_data_store(template_data, xpath) logging.info(f"Template {template_id} modified successfully") return send_response( True, code=200, message="Template updated successfully", data=result ) except ValueError as e: return send_response(False, code=404, message=str(e)) except Exception as e: return send_response(False, code=500, message=str(e)) def update_slice_service(self, slice_id, intent): """ Modifica (reemplaza) un slice service específico """ try: xpath = f"/ietf-network-slice-service:network-slice-services/slice-service[id='{slice_id}']" # Verificar que el slice existe existing_slice = get_data_store(xpath) if not existing_slice: return send_response(False, code=404, message="Slice not found") # Asegurar que el ID en el body coincide con el de la URL if "id" in intent and intent["id"] != slice_id: return send_response(False, code=400, message="Slice ID in body does not match URL") # Validar que existe el template SLO/SLE referenciado if "slo-sle-template" in intent: template_ref = intent.get("slo-sle-template") xpath_template = f"/ietf-network-slice-service:network-slice-services/slo-sle-templates/slo-sle-template[id='{template_ref}']" existing_template = get_data_store(xpath_template) if not existing_template: return send_response(False, code=404, message="Referenced SLO/SLE template not found") # Construir el intent completo para TFS full_intent = { "ietf-network-slice-service:network-slice-services": { "slo-sle-templates": { "slo-sle-template": [existing_template["network-slice-services"]["slo-sle-templates"]["slo-sle-template"][template_ref]] }, "slice-service": [intent] } } elif "service-slo-sle-policy" in intent: full_intent = { "ietf-network-slice-service:network-slice-services": { "slo-sle-templates": { "slo-sle-template": intent.get("service-slo-sle-policy") }, "slice-service": [intent] } } else: return send_response(False, code=400, message="No SLO/SLE template or policy provided in intent") full_intent = normalize_libyang_data(full_intent) result = self.slice_service.nsc(full_intent) if not result: return send_response(False, code=500, message="Slice not updated") # Eliminar el ID del body (ya está en el predicado) intent_data = intent.copy() intent_data.pop("id", None) # Reemplazar el slice update_data_store(intent_data, xpath) logging.info(f"Slice {slice_id} modified successfully") return send_response( True, code=200, message="Slice updated successfully", data=result ) except ValueError as e: return send_response(False, code=404, message=str(e)) except RuntimeError as e: return send_response(False, code=200, message=str(e)) except Exception as e: return send_response(False, code=500, message=str(e)) def update_sdp(self, slice_id, sdp_id, sdp): """ Modifica (reemplaza) un SDP específico dentro de un slice """ try: # Verificar que el slice existe slice_xpath = f"/ietf-network-slice-service:network-slice-services/slice-service[id='{slice_id}']" existing_slice = get_data_store(slice_xpath) if not existing_slice: return send_response(False, code=404, message="Slice not found") # Verificar que el SDP existe sdp_xpath = f"/ietf-network-slice-service:network-slice-services/slice-service[id='{slice_id}']/sdps/sdp[id='{sdp_id}']" existing_sdp = get_data_store(sdp_xpath) if not existing_sdp: return send_response(False, code=404, message="SDP not found") # Asegurar que el ID en el body coincide con el de la URL if "id" in sdp and sdp["id"] != sdp_id: return send_response(False, code=400, message="SDP ID in body does not match URL") # Eliminar el ID del body (ya está en el predicado) sdp_data = sdp.copy() sdp_data.pop("id", None) # Reemplazar el SDP update_data_store(sdp_data, sdp_xpath) logging.info(f"SDP {sdp_id} in slice {slice_id} modified successfully") return send_response( True, code=200, message="SDP updated successfully" ) except ValueError as e: return send_response(False, code=404, message=str(e)) except Exception as e: return send_response(False, code=500, message=str(e)) ### DELETE def delete_network_slice_services(self): try: # Delete specific slice if slice_id is provided xpath = f"/ietf-network-slice-service:network-slice-services" if not current_app.config["DUMMY_MODE"]: content = get_data_store(xpath) for slice in content["network-slice-services"]["slice-service"]: slice_type = list(slice["service-tags"]["tag-type"]["ietf-network-slice-service:service"]["tag-type-value"])[0] if not slice_type: slice_type = "L2" logging.warning(f"Slice type not found in slice intent. Defaulting to L2") logging.debug(f"Send slice to delete in TFS with slice_type {slice_type}") tfs_connector().nbi_delete(current_app.config["TFS_IP"], slice_type, slice.get("id")) if current_app.config["TFS_L2VPN_SUPPORT"]: self.slice_service.tfs_l2vpn_delete() delete_data_store(xpath) logging.info("All slices removed successfully") return {}, 204 except ValueError as e: Loading Loading @@ -424,6 +661,16 @@ class Api: existing_slice = get_data_store(xpath) if not existing_slice: raise ValueError("Slice not found") if not current_app.config["DUMMY_MODE"]: slice_type = list(existing_slice["network-slice-services"]["slice-service"][slice_id]["service-tags"]["tag-type"]["ietf-network-slice-service:service"]["tag-type-value"])[0] if not slice_type: slice_type = "L2" logging.warning(f"Slice type not found in slice intent. Defaulting to L2") logging.debug(f"Send slice to delete in TFS with slice_type {slice_type}") tfs_connector().nbi_delete(current_app.config["TFS_IP"], slice_type, existing_slice.get("id")) if current_app.config["TFS_L2VPN_SUPPORT"]: self.slice_service.tfs_l2vpn_delete() delete_data_store(xpath) logging.info(f"Slice {slice_id} removed successfully") return {}, 204 Loading @@ -431,6 +678,17 @@ class Api: # Delete all slices else: xpath = f"/ietf-network-slice-service:network-slice-services/slice-service" if not current_app.config["DUMMY_MODE"]: content = get_data_store(xpath) for slice in content["network-slice-services"]["slice-service"]: slice_type = list(slice["service-tags"]["tag-type"]["ietf-network-slice-service:service"]["tag-type-value"])[0] if not slice_type: slice_type = "L2" logging.warning(f"Slice type not found in slice intent. Defaulting to L2") logging.debug(f"Send slice to delete in TFS with slice_type {slice_type}") tfs_connector().nbi_delete(current_app.config["TFS_IP"], slice_type, slice.get("id")) if current_app.config["TFS_L2VPN_SUPPORT"]: self.slice_service.tfs_l2vpn_delete() delete_data_store(xpath) logging.info("All slices removed successfully") return {}, 204 Loading
src/database/store_data.py +5 −3 Original line number Diff line number Diff line Loading @@ -32,9 +32,11 @@ def store_data(intent, slice_id, controller_type=None): """ # Update or add new slice intent if slice_id: if controller_type != "RESTCONF": update_data(slice_id, intent, controller_type) else: # Add new slice intent slice_id = intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["id"] #save_data(slice_id, intent, controller_type) create_data_store(intent, xpath=f"/ietf-network-slice-service:network-slice-services/slice-service[id='{slice_id}']") No newline at end of file if controller_type != "RESTCONF": save_data(slice_id, intent, controller_type) No newline at end of file
src/database/sysrepo_store.py +140 −30 File changed.Preview size limit exceeded, changes collapsed. Show changes
swagger/models/create_models_restconf.py +1 −1 Original line number Diff line number Diff line Loading @@ -283,5 +283,5 @@ def create_ietf_network_slice_nbi_yang_model(slice_ns): slice_service_model, slo_sle_template_model, sdp_model, NetworkSliceServicesFull common_template )
swagger/restconf_namespace.py +42 −4 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ restconf_ns = Namespace( "restconf", description="RESTCONF operations for IETF Network Slice Service YANG model" ) ietf_network_slice_service_response, slice_service_response, slo_sle_template_response, sdp_response, slice_response_model, slice_service_model, slo_sle_template_model, sdp_model, ietf_network_slice_service_model = create_ietf_network_slice_nbi_yang_model(restconf_ns) ietf_network_slice_service_response, slice_service_response, slo_sle_template_response, sdp_response, slice_response_model, slice_service_model, slo_sle_template_model, sdp_model, common_template = create_ietf_network_slice_nbi_yang_model(restconf_ns) @restconf_ns.route("/data/ietf-network-slice-service:network-slice-services") class NetworkSliceServices(Resource): Loading @@ -23,7 +23,7 @@ class NetworkSliceServices(Resource): return Api(controller).get_network_slice_services() @restconf_ns.doc(summary="Create Network Slice Services") @restconf_ns.expect(ietf_network_slice_service_model) @restconf_ns.expect(common_template) @restconf_ns.response(201, "Container network-slice-services created", slice_response_model) @restconf_ns.response(500, "Internal server error") def post(self): Loading @@ -31,6 +31,16 @@ class NetworkSliceServices(Resource): controller = NSController(controller_type="RESTCONF") return Api(controller).add_network_slice_service(json_data) @restconf_ns.doc(summary="Update Network Slice Services") @restconf_ns.expect(common_template) @restconf_ns.response(200, "Container network-slice-services updated", slice_response_model) @restconf_ns.response(404, "Nothing found to update") @restconf_ns.response(500, "Internal server error") def put(self): json_data = request.get_json() controller = NSController(controller_type="RESTCONF") return Api(controller).update_network_slice_service(json_data) @restconf_ns.doc(summary="Delete Network Slice Services") @restconf_ns.response(204, "All slices deleted") @restconf_ns.response(500, "Internal server error") Loading @@ -49,7 +59,8 @@ class SliceServiceList(Resource): return Api(controller).get_slice_services() @restconf_ns.doc(summary="Create Slice Services") @restconf_ns.expect(slice_service_model) @restconf_ns.expect(common_template) #@restconf_ns.expect(slice_service_model) @restconf_ns.response(201, "Slice created", slice_response_model) @restconf_ns.response(409, "Slice already exists") def post(self): Loading @@ -74,6 +85,15 @@ class SliceService(Resource): controller = NSController(controller_type="RESTCONF") return Api(controller).get_slice_services(slice_service_id) @restconf_ns.doc(summary="Update Slice Service by ID") @restconf_ns.expect(common_template) @restconf_ns.response(200, "Slice updated", slice_response_model) @restconf_ns.response(404, "No slice found to update") def put(self, slice_service_id): json_data = request.get_json() controller = NSController(controller_type="RESTCONF") return Api(controller).update_slice_service(slice_service_id, json_data) @restconf_ns.doc(summary="Delete a Slice Service by ID") @restconf_ns.response(204, "Slice deleted") @restconf_ns.response(404, "Slice not found") Loading Loading @@ -115,6 +135,15 @@ class SloSleTemplate(Resource): controller = NSController(controller_type="RESTCONF") return Api(controller).get_slo_sle_templates(slo_sle_template_id) @restconf_ns.doc(summary="Update SLO/SLE template by ID") @restconf_ns.expect(slo_sle_template_model) @restconf_ns.response(200, "Template updated", slice_response_model) @restconf_ns.response(404, "No template found to update") def put(self, slo_sle_template_id): json_data = request.get_json() controller = NSController(controller_type="RESTCONF") return Api(controller).update_slo_sle_template(slo_sle_template_id, json_data) @restconf_ns.doc(summary="Delete SLO/SLE template by ID") @restconf_ns.response(204, "Template deleted") def delete(self, slo_sle_template_id): Loading @@ -131,7 +160,8 @@ class SdpList(Resource): return Api(controller).get_sdps(slice_service_id) @restconf_ns.doc(summary="Create Slice Service SDPs") @restconf_ns.expect(sdp_model) @restconf_ns.expect(common_template) #@restconf_ns.expect(sdp_model) @restconf_ns.response(201, "SDP created", slice_response_model) @restconf_ns.response(409, "SDP already exists") def post(self, slice_service_id): Loading @@ -153,6 +183,14 @@ class Sdp(Resource): def get(self, slice_service_id, sdp_id): controller = NSController(controller_type="RESTCONF") return Api(controller).get_sdps(slice_service_id, sdp_id) @restconf_ns.doc(summary="Update Slice Service SDP by ID") @restconf_ns.expect(common_template) @restconf_ns.response(200, "SDP updated", slice_response_model) @restconf_ns.response(404, "No SDP found to update") def put(self, slice_service_id, sdp_id): json_data = request.get_json() controller = NSController(controller_type="RESTCONF") return Api(controller).update_sdp(slice_service_id, sdp_id, json_data) @restconf_ns.doc(summary="Delete Slice Service SDP by ID") @restconf_ns.response(204, "SDP deleted") def delete(self, slice_service_id, sdp_id): Loading