Loading src/api/main.py +24 −6 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ from src.utils.send_response import send_response import logging 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 class Api: def __init__(self, slice_service): Loading @@ -44,7 +46,7 @@ class Api: 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, Loading Loading @@ -120,7 +122,7 @@ class Api: result = self.slice_service.nsc(intent, slice_id) if not result: return send_response(False, code=404, message="Slice not found") logging.info(f"Slice {slice_id} modified successfully") return send_response( True, code=200, Loading Loading @@ -165,6 +167,14 @@ class Api: # Raise error if slice not found if not slice or slice.get("controller") != self.slice_service.controller_type: raise ValueError("Transport network slice not found") # Delete in Teraflow if not current_app.config["DUMMY_MODE"]: if self.slice_service.controller_type == "TFS": slice_type = safe_get(slice, ['intent', 'ietf-network-slice-service:network-slice-services', 'slice-service', 0, 'service-tags', 'tag-type', 0, 'tag-type-value', 0]) if not slice_type: slice_type = "L2" logging.warning(f"Slice type not found in slice intent. Defaulting to L2") tfs_connector().nbi_delete(current_app.config["TFS_IP"],slice_type, slice_id) # Update slice database delete_data(slice_id) logging.info(f"Slice {slice_id} removed successfully") Loading @@ -173,8 +183,16 @@ class Api: # Delete all slices else: # Optional: Delete in Teraflow if configured if not current_app.config["DUMMY_MODE"]: if self.slice_service.controller_type == "TFS": # TODO: should send a delete request to Teraflow content = get_all_data() for slice in content: if slice.get("controller") == self.slice_service.controller_type: slice_type = safe_get(slice, ['intent', 'ietf-network-slice-service:network-slice-services', 'slice-service', 0, 'service-tags', 'tag-type', 0, 'tag-type-value', 0]) if not slice_type: slice_type = "L2" logging.warning(f"Slice type not found in slice intent. Defaulting to L2") tfs_connector().nbi_delete(current_app.config["TFS_IP"],slice_type, slice.get("slice_id")) if current_app.config["TFS_L2VPN_SUPPORT"]: self.slice_service.tfs_l2vpn_delete() Loading src/realizer/tfs/helpers/tfs_connector.py +18 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ # This file includes original contributions from Telefonica Innovación Digital S.L. import logging, requests, json from src.config.constants import NBI_L2_PATH, NBI_L3_PATH class tfs_connector(): def webui_post(self, tfs_ip, service): Loading Loading @@ -50,5 +51,22 @@ class tfs_connector(): logging.debug("Posting to TFS NBI: %s",data) token={'csrf_token':token} response = session.post(url,headers=headers,data=data,timeout=60) response.raise_for_status() logging.debug("Http response: %s",response.text) return response def nbi_delete(self, tfs_ip: str, service_type: str , service_id: str) -> requests.Response: user="admin" password="admin" url = f'http://{user}:{password}@{tfs_ip}' if service_type == 'L2': url = url + f'/{NBI_L2_PATH}/vpn-service={service_id}' elif service_type == 'L3': url = url + f'/{NBI_L3_PATH}/vpn-service={service_id}' else: raise ValueError("Invalid service type. Use 'L2' or 'L3'.") response = requests.delete(url, timeout=60) response.raise_for_status() logging.debug('Service deleted successfully') logging.debug("Http response: %s",response.text) return response No newline at end of file src/realizer/tfs/service_types/tfs_l2vpn.py +3 −4 Original line number Diff line number Diff line Loading @@ -15,7 +15,6 @@ # This file includes original contributions from Telefonica Innovación Digital S.L. import logging, os from datetime import datetime from src.config.constants import TEMPLATES_PATH, NBI_L2_PATH from src.utils.load_template import load_template from ..helpers.cisco_connector import cisco_connector Loading Loading @@ -53,8 +52,8 @@ def tfs_l2vpn(ietf_intent, response): # Load L2VPN service template tfs_request = load_template(os.path.join(TEMPLATES_PATH, "L2-VPN_template_empty.json"))["services"][0] # Generate unique service UUID tfs_request["service_id"]["service_uuid"]["uuid"] += "-" + str(int(datetime.now().timestamp() * 1e7)) # Configure service UUID tfs_request["service_id"]["service_uuid"]["uuid"] = ietf_intent['ietf-network-slice-service:network-slice-services']['slice-service'][0]["id"] # Configure service endpoints for endpoint in tfs_request["service_endpoint_ids"]: Loading @@ -62,7 +61,7 @@ def tfs_l2vpn(ietf_intent, response): endpoint["endpoint_uuid"]["uuid"] = origin_router_if if endpoint is tfs_request["service_endpoint_ids"][0] else destination_router_if # Add service constraints for constraint in slice.get("QoS Requirements", []): for constraint in slice.get("requirements", []): tfs_request["service_constraints"].append({"custom": constraint}) # Add configuration rules Loading src/realizer/tfs/service_types/tfs_l3vpn.py +4 −5 Original line number Diff line number Diff line Loading @@ -15,7 +15,6 @@ # This file includes original contributions from Telefonica Innovación Digital S.L. import logging, os from datetime import datetime from src.config.constants import TEMPLATES_PATH, NBI_L3_PATH from src.utils.load_template import load_template from flask import current_app Loading Loading @@ -50,8 +49,8 @@ def tfs_l3vpn(ietf_intent, response): if current_app.config["UPLOAD_TYPE"] == "WEBUI": # Load L3VPN service template tfs_request = load_template(os.path.join(TEMPLATES_PATH, "L3-VPN_template_empty.json"))["services"][0] # Generate unique service UUID tfs_request["service_id"]["service_uuid"]["uuid"] += "-" + str(int(datetime.now().timestamp() * 1e7)) # Configure service UUID tfs_request["service_id"]["service_uuid"]["uuid"] = ietf_intent['ietf-network-slice-service:network-slice-services']['slice-service'][0]["id"] # Configure service endpoints for endpoint in tfs_request["service_endpoint_ids"]: Loading @@ -59,7 +58,7 @@ def tfs_l3vpn(ietf_intent, response): endpoint["endpoint_uuid"]["uuid"] = origin_router_if if endpoint is tfs_request["service_endpoint_ids"][0] else destination_router_if # Add service constraints for constraint in slice.get("QoS Requirements", []): for constraint in slice.get("requirements", []): tfs_request["service_constraints"].append({"custom": constraint}) # Add configuration rules Loading Loading @@ -112,7 +111,7 @@ def tfs_l3vpn(ietf_intent, response): access["vpn-attachment"]["vpn-id"] = full_id # Aplicar restricciones QoS for constraint in slice.get("QoS Requirements", []): for constraint in slice.get("requirements", []): ctype = constraint["constraint_type"] cvalue = float(constraint["constraint_value"]) if constraint["constraint_type"].startswith("one-way-bandwidth"): Loading Loading
src/api/main.py +24 −6 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ from src.utils.send_response import send_response import logging 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 class Api: def __init__(self, slice_service): Loading @@ -44,7 +46,7 @@ class Api: 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, Loading Loading @@ -120,7 +122,7 @@ class Api: result = self.slice_service.nsc(intent, slice_id) if not result: return send_response(False, code=404, message="Slice not found") logging.info(f"Slice {slice_id} modified successfully") return send_response( True, code=200, Loading Loading @@ -165,6 +167,14 @@ class Api: # Raise error if slice not found if not slice or slice.get("controller") != self.slice_service.controller_type: raise ValueError("Transport network slice not found") # Delete in Teraflow if not current_app.config["DUMMY_MODE"]: if self.slice_service.controller_type == "TFS": slice_type = safe_get(slice, ['intent', 'ietf-network-slice-service:network-slice-services', 'slice-service', 0, 'service-tags', 'tag-type', 0, 'tag-type-value', 0]) if not slice_type: slice_type = "L2" logging.warning(f"Slice type not found in slice intent. Defaulting to L2") tfs_connector().nbi_delete(current_app.config["TFS_IP"],slice_type, slice_id) # Update slice database delete_data(slice_id) logging.info(f"Slice {slice_id} removed successfully") Loading @@ -173,8 +183,16 @@ class Api: # Delete all slices else: # Optional: Delete in Teraflow if configured if not current_app.config["DUMMY_MODE"]: if self.slice_service.controller_type == "TFS": # TODO: should send a delete request to Teraflow content = get_all_data() for slice in content: if slice.get("controller") == self.slice_service.controller_type: slice_type = safe_get(slice, ['intent', 'ietf-network-slice-service:network-slice-services', 'slice-service', 0, 'service-tags', 'tag-type', 0, 'tag-type-value', 0]) if not slice_type: slice_type = "L2" logging.warning(f"Slice type not found in slice intent. Defaulting to L2") tfs_connector().nbi_delete(current_app.config["TFS_IP"],slice_type, slice.get("slice_id")) if current_app.config["TFS_L2VPN_SUPPORT"]: self.slice_service.tfs_l2vpn_delete() Loading
src/realizer/tfs/helpers/tfs_connector.py +18 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ # This file includes original contributions from Telefonica Innovación Digital S.L. import logging, requests, json from src.config.constants import NBI_L2_PATH, NBI_L3_PATH class tfs_connector(): def webui_post(self, tfs_ip, service): Loading Loading @@ -50,5 +51,22 @@ class tfs_connector(): logging.debug("Posting to TFS NBI: %s",data) token={'csrf_token':token} response = session.post(url,headers=headers,data=data,timeout=60) response.raise_for_status() logging.debug("Http response: %s",response.text) return response def nbi_delete(self, tfs_ip: str, service_type: str , service_id: str) -> requests.Response: user="admin" password="admin" url = f'http://{user}:{password}@{tfs_ip}' if service_type == 'L2': url = url + f'/{NBI_L2_PATH}/vpn-service={service_id}' elif service_type == 'L3': url = url + f'/{NBI_L3_PATH}/vpn-service={service_id}' else: raise ValueError("Invalid service type. Use 'L2' or 'L3'.") response = requests.delete(url, timeout=60) response.raise_for_status() logging.debug('Service deleted successfully') logging.debug("Http response: %s",response.text) return response No newline at end of file
src/realizer/tfs/service_types/tfs_l2vpn.py +3 −4 Original line number Diff line number Diff line Loading @@ -15,7 +15,6 @@ # This file includes original contributions from Telefonica Innovación Digital S.L. import logging, os from datetime import datetime from src.config.constants import TEMPLATES_PATH, NBI_L2_PATH from src.utils.load_template import load_template from ..helpers.cisco_connector import cisco_connector Loading Loading @@ -53,8 +52,8 @@ def tfs_l2vpn(ietf_intent, response): # Load L2VPN service template tfs_request = load_template(os.path.join(TEMPLATES_PATH, "L2-VPN_template_empty.json"))["services"][0] # Generate unique service UUID tfs_request["service_id"]["service_uuid"]["uuid"] += "-" + str(int(datetime.now().timestamp() * 1e7)) # Configure service UUID tfs_request["service_id"]["service_uuid"]["uuid"] = ietf_intent['ietf-network-slice-service:network-slice-services']['slice-service'][0]["id"] # Configure service endpoints for endpoint in tfs_request["service_endpoint_ids"]: Loading @@ -62,7 +61,7 @@ def tfs_l2vpn(ietf_intent, response): endpoint["endpoint_uuid"]["uuid"] = origin_router_if if endpoint is tfs_request["service_endpoint_ids"][0] else destination_router_if # Add service constraints for constraint in slice.get("QoS Requirements", []): for constraint in slice.get("requirements", []): tfs_request["service_constraints"].append({"custom": constraint}) # Add configuration rules Loading
src/realizer/tfs/service_types/tfs_l3vpn.py +4 −5 Original line number Diff line number Diff line Loading @@ -15,7 +15,6 @@ # This file includes original contributions from Telefonica Innovación Digital S.L. import logging, os from datetime import datetime from src.config.constants import TEMPLATES_PATH, NBI_L3_PATH from src.utils.load_template import load_template from flask import current_app Loading Loading @@ -50,8 +49,8 @@ def tfs_l3vpn(ietf_intent, response): if current_app.config["UPLOAD_TYPE"] == "WEBUI": # Load L3VPN service template tfs_request = load_template(os.path.join(TEMPLATES_PATH, "L3-VPN_template_empty.json"))["services"][0] # Generate unique service UUID tfs_request["service_id"]["service_uuid"]["uuid"] += "-" + str(int(datetime.now().timestamp() * 1e7)) # Configure service UUID tfs_request["service_id"]["service_uuid"]["uuid"] = ietf_intent['ietf-network-slice-service:network-slice-services']['slice-service'][0]["id"] # Configure service endpoints for endpoint in tfs_request["service_endpoint_ids"]: Loading @@ -59,7 +58,7 @@ def tfs_l3vpn(ietf_intent, response): endpoint["endpoint_uuid"]["uuid"] = origin_router_if if endpoint is tfs_request["service_endpoint_ids"][0] else destination_router_if # Add service constraints for constraint in slice.get("QoS Requirements", []): for constraint in slice.get("requirements", []): tfs_request["service_constraints"].append({"custom": constraint}) # Add configuration rules Loading Loading @@ -112,7 +111,7 @@ def tfs_l3vpn(ietf_intent, response): access["vpn-attachment"]["vpn-id"] = full_id # Aplicar restricciones QoS for constraint in slice.get("QoS Requirements", []): for constraint in slice.get("requirements", []): ctype = constraint["constraint_type"] cvalue = float(constraint["constraint_value"]) if constraint["constraint_type"].startswith("one-way-bandwidth"): Loading