diff --git a/app.py b/app.py index 1e34ec5486daeb0eb38f32e84494ba5f4fcb4db0..61503b3b4600483708559bac25bee7cb4588a2a6 100644 --- a/app.py +++ b/app.py @@ -14,11 +14,14 @@ # This file is an original contribution from Telefonica Innovación Digital S.L. +import os from flask import Flask from flask_restx import Api from flask_cors import CORS -from swagger.slice_namespace import slice_ns -from src.Constants import NSC_PORT +from swagger.tfs_namespace import tfs_ns +from swagger.ixia_namespace import ixia_ns +from src.Constants import NSC_PORT, WEBUI_DEPLOY +from src.webui.gui import gui_bp app = Flask(__name__) CORS(app) @@ -33,7 +36,14 @@ api = Api( ) # Register namespaces -api.add_namespace(slice_ns, path="/slice") +api.add_namespace(tfs_ns, path="/tfs") +api.add_namespace(ixia_ns, path="/ixia") +#gui_bp = Blueprint('gui', __name__, template_folder='templates') + +if WEBUI_DEPLOY: + app.secret_key = 'clave-secreta-dev' + app.register_blueprint(gui_bp) + if __name__ == "__main__": app.run(host="0.0.0.0", port=NSC_PORT, debug=True) diff --git a/src/Constants.py b/src/Constants.py index 337be8856e4a91907a76466498fb6cb57634bca9..3b02ffd287c6eced608c00b993a71605fe53d0d4 100644 --- a/src/Constants.py +++ b/src/Constants.py @@ -12,9 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This file is an original contribution from Telefonica Innovación Digital S.L. +# This file includes original contributions from Telefonica Innovación Digital S.L. + +import logging, os, json -import logging, os # Default logging level DEFAULT_LOGGING_LEVEL = logging.INFO @@ -24,14 +25,44 @@ NSC_PORT = 8081 # Paths # Obtain the absolute path of the current file SRC_PATH = os.path.dirname(os.path.abspath(__file__)) +with open(os.path.join(SRC_PATH, 'IPs.json')) as f: + ips = json.load(f) # Create the path to the desired file relative to the current file TEMPLATES_PATH = os.path.join(SRC_PATH, "templates") -# TFS Flags -# Flag to determine if configurations should be uploaded to Teraflow -TFS_UPLOAD = False +# Dump templates +DUMP_TEMPLATES = False + +# Mapper + +# Flag to determine if the NSC performs NRPs +NRP_ENABLED = False +# Planner Flags +PLANNER_ENABLED = True +# Flag to determine if external PCE is used +PCE_EXTERNAL = False + +# Realizer + +# Controller Flags +# If True, config is not sent to controllers +DUMMY_MODE = False + +#####TERAFLOW##### # Teraflow IP -TFS_IP = "192.168.165.10" +TFS_IP = ips.get('TFS_IP') +UPLOAD_TYPE = "WEBUI" # "WEBUI" or "NBI" +NBI_L2_PATH = "restconf/data/ietf-l2vpn-svc:l2vpn-svc/vpn-services" +NBI_L3_PATH = "restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services" # Flag to determine if additional L2VPN configuration support is required for deploying L2VPNs with path selection -TFS_L2VPN_SUPPORT = False \ No newline at end of file +TFS_L2VPN_SUPPORT = False + +#####IXIA##### +# IXIA NEII IP +IXIA_IP = ips.get('IXIA_IP') + +# WebUI + +# Flag to deploy the WebUI +WEBUI_DEPLOY = True \ No newline at end of file diff --git a/src/IPs.json b/src/IPs.json new file mode 100644 index 0000000000000000000000000000000000000000..e56bdb0ea8dbb92225dae67bdda6176929eb211a --- /dev/null +++ b/src/IPs.json @@ -0,0 +1,4 @@ +{ + "TFS_IP": "192.168.27.165", + "IXIA_IP": "192.168.27.59" +} \ No newline at end of file diff --git a/src/helpers.py b/src/helpers.py index 47adc1619360e8f8438842b73efe31a07b3c1252..0e150791ac742c02c03aaa755c04a980481b4336 100644 --- a/src/helpers.py +++ b/src/helpers.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +# This file includes original contributions from Telefonica Innovación Digital S.L. + import logging, requests, json from netmiko import ConnectHandler from src.Constants import DEFAULT_LOGGING_LEVEL @@ -24,7 +26,7 @@ logging.basicConfig( #Teraflow class tfs_connector(): - def simple_post(self, tfs_ip, service): + def webui_post(self, tfs_ip, service): user="admin" password="admin" token="" @@ -44,6 +46,22 @@ class tfs_connector(): logging.debug("Http response: %s",response.text) return response + def nbi_post(self, tfs_ip, service, path): + token="" + user="admin" + password="admin" + token="" + session = requests.Session() + session.auth = (user, password) + url = f'http://{tfs_ip}/{path}' + headers = {'Content-Type': 'application/json'} + data = json.dumps(service) + logging.debug("Posting to TFS NBI: %s",data) + token={'csrf_token':token} + response = session.post(url,headers=headers,data=data,timeout=60) + logging.debug("Http response: %s",response.text) + return response + #CISCO class cisco_connector(): def __init__(self, address, configs=None): diff --git a/src/network_slice_controller.py b/src/network_slice_controller.py index 7d141146d3a4cf1862008ef031ebfdfc10957f38..6ac70885c872dda4d18e919a602abd4f1a15c870 100644 --- a/src/network_slice_controller.py +++ b/src/network_slice_controller.py @@ -12,10 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json, time, os, logging, uuid +# This file includes original contributions from Telefonica Innovación Digital S.L. + +import json, time, os, logging, uuid, traceback, sys from datetime import datetime from src.helpers import tfs_connector, cisco_connector -from src.Constants import DEFAULT_LOGGING_LEVEL, TFS_UPLOAD, TFS_IP, TFS_L2VPN_SUPPORT, SRC_PATH, TEMPLATES_PATH +from src.Constants import DEFAULT_LOGGING_LEVEL, TFS_IP, TFS_L2VPN_SUPPORT, IXIA_IP, SRC_PATH, TEMPLATES_PATH, DUMMY_MODE, DUMP_TEMPLATES, PLANNER_ENABLED, NRP_ENABLED, UPLOAD_TYPE, NBI_L2_PATH, NBI_L3_PATH +from src.realizers.ixia.NEII_V4 import NEII_controller +from src.planner.planner import Planner # Configure logging to provide clear and informative log messages logging.basicConfig( @@ -38,26 +42,26 @@ class NSController: - Slice Realization: Convert intents to specific network configurations (L2VPN, L3VPN) """ - def __init__(self, upload_to_tfs = TFS_UPLOAD, tfs_ip=TFS_IP, need_l2vpn_support=TFS_L2VPN_SUPPORT): + def __init__(self, controller_type = "TFS", tfs_ip=TFS_IP, ixia_ip =IXIA_IP, need_l2vpn_support=TFS_L2VPN_SUPPORT): """ Initialize the Network Slice Controller. Args: - upload_to_tfs (bool, optional): Flag to determine if configurations - should be uploaded to Teraflow system. Defaults to False. + controller_type (str): Flag to determine if configurations + should be uploaded to Teraflow or IXIA system. need_l2vpn_support (bool, optional): Flag to determine if additional L2VPN configuration support is required. Defaults to False. Attributes: - upload_to_tfs (bool): Flag for Teraflow upload + controller_type (str): Flag for Teraflow or Ixia upload answer (dict): Stores slice creation responses - tfs_requests (dict): Stores requests to be sent to Teraflow start_time (float): Tracks slice setup start time end_time (float): Tracks slice setup end time need_l2vpn_support (bool): Flag for additional L2VPN configuration support """ - self.upload_to_tfs = upload_to_tfs + self.controller_type = controller_type self.tfs_ip = tfs_ip + self.path = "" self.answer = {} self.cool_answer = {} self.start_time = 0 @@ -130,7 +134,7 @@ class NSController: raise ValueError("Transport network slices not found") # Return all slices if no specific ID is given - return content + return [slice for slice in content if slice.get("controller") == self.controller_type] except ValueError as e: # Handle case where no slices are found @@ -179,7 +183,7 @@ class NSController: Exception: For unexpected errors during deletion process Notes: - - If upload_to_tfs is True, attempts to delete from Teraflow + - If controller_type is TFS, attempts to delete from Teraflow - If need_l2vpn_support is True, performs additional L2VPN cleanup """ try: @@ -191,7 +195,7 @@ class NSController: # Delete specific slice if slice_id is provided if slice_id: for i, slice in enumerate(content): - if slice["slice_id"] == slice_id: + if slice["slice_id"] == slice_id and slice.get("controller") == self.controller_type: del content[i] id = i break @@ -207,19 +211,21 @@ class NSController: # Delete all slices else: # Optional: Delete in Teraflow if configured - if self.upload_to_tfs == True: + if self.controller_type == "TFS": # TODO: should send a delete request to Teraflow if self.need_l2vpn_support: self.__tfs_l2vpn_delete() + data_removed = [slice for slice in content if slice.get("controller") == self.controller_type] + # Verify slices exist before deletion - with open(os.path.join(SRC_PATH, "slice_ddbb.json"), 'r') as file: - if len(json.load(file)) == 0: - raise ValueError("Transport network slices not found") - + if len(data_removed) == 0: + raise ValueError("Transport network slices not found") + + filtered_data = [slice for slice in content if slice.get("controller") != self.controller_type] # Clear slice database with open(os.path.join(SRC_PATH, "slice_ddbb.json"), 'w') as file: - json.dump([], file, indent=4) + json.dump(filtered_data, file, indent=4) logging.info("All slices removed successfully") return self.__send_response(False, code=200, status="success", message="All transport network slices deleted successfully.") @@ -257,11 +263,21 @@ class NSController: # Reset requests and load IETF template self.__load_template(1, os.path.join(TEMPLATES_PATH, "ietf_template_empty.json")) - tfs_requests = {"services":[]} + requests = {"services":[]} + + # Store the received template for debugging + if DUMP_TEMPLATES: + with open(os.path.join(TEMPLATES_PATH, "nbi_template.json"), "w") as file: + file.write(json.dumps(intent_json,indent=2)) # Process intent (translate if 3GPP) ietf_intents = self.__nbi_processor(intent_json) + # Store the generated template for debugging + if DUMP_TEMPLATES: + with open(os.path.join(TEMPLATES_PATH, "ietf_template.json"), "w") as file: + file.write(json.dumps(ietf_intents,indent=2)) + if ietf_intents: for intent in ietf_intents: # Extract and store slice request details @@ -271,25 +287,39 @@ class NSController: self.__mapper(intent) # Realizer tfs_request = self.__realizer(intent) - tfs_requests["services"].append(tfs_request) + requests["services"].append(tfs_request) else: return self.__send_response(False, code=404, message="No intents found") - - # Generated service - logging.debug(json.dumps(tfs_requests, indent=2)) + + # Store the generated template for debugging + if DUMP_TEMPLATES: + with open(os.path.join(TEMPLATES_PATH, "realizer_template.json"), "w") as archivo: + archivo.write(json.dumps(requests,indent=2)) # Optional: Upload template to Teraflow - if self.upload_to_tfs == True: - response = tfs_connector().simple_post(self.tfs_ip, tfs_requests) - - if not response.ok: - return self.__send_response(False, code=response.status_code, message=f"Teraflow upload failed. Response: {response.text}") - - # For deploying an L2VPN with path selection (not supported by Teraflow) - if self.need_l2vpn_support: - self.__tfs_l2vpn_support(tfs_requests["services"]) + if not DUMMY_MODE: + if self.controller_type == "TFS": + if UPLOAD_TYPE == "WEBUI": + response = tfs_connector().webui_post(self.tfs_ip, requests) + elif UPLOAD_TYPE == "NBI": + for intent in requests["services"]: + # Send each separate NBI request + response = tfs_connector().nbi_post(self.tfs_ip, intent, self.path) + + if not response.ok: + return self.__send_response(False, code=response.status_code, message=f"Teraflow upload failed. Response: {response.text}") + + # For deploying an L2VPN with path selection (not supported by Teraflow) + if self.need_l2vpn_support: + self.__tfs_l2vpn_support(requests["services"]) - logging.info("Request sent to Teraflow") + logging.info("Request sent to Teraflow") + elif self.controller_type == "IXIA": + neii_controller = NEII_controller() + for intent in requests["services"]: + # Send each separate IXIA request + neii_controller.nscNEII(intent) + logging.info("Requests sent to Ixia") # End performance tracking self.end_time = time.perf_counter() @@ -319,7 +349,6 @@ class NSController: # Detect the input JSON format (3GPP or IETF) format = self.__detect_format(intent_json) ietf_intents = [] - logging.info("--------NEW REQUEST--------") # TODO Needs to be generalized to support different names of slicesubnets # Process different input formats @@ -356,35 +385,42 @@ class NSController: Raises: Exception: If no suitable NRP is found and slice creation fails. """ - # Retrieve NRP view - self.__realizer(None, True, "READ") - - # Extract Service Level Objectives (SLOs) from the intent - slos = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"] - - # Find candidate NRPs that can meet the SLO requirements - candidates = [ - (nrp, self.__slo_viability(slos, nrp)[1]) - for nrp in self.__nrp_view - if self.__slo_viability(slos, nrp)[0] and nrp["available"] - ] - logging.debug(f"Candidates: {candidates}") - - # Select the best NRP based on candidates - best_nrp = max(candidates, key=lambda x: x[1])[0] if candidates else None - logging.debug(f"Best NRP: {best_nrp}") - - if best_nrp: - best_nrp["slices"].append(ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["id"]) - # Update NRP view - self.__realizer(ietf_intent, True, "UPDATE") - # TODO Here we should put how the slice is attached to an already created nrp - else: - # Request the controller to create a new NRP that meets the SLOs - answer = self.__realizer(ietf_intent, True, "CREATE", best_nrp) - if not answer: - raise Exception("Slice rejected due to lack of NRPs") - # TODO Here we should put how the slice is attached to the new nrp + if NRP_ENABLED: + # Retrieve NRP view + self.__realizer(None, True, "READ") + + # Extract Service Level Objectives (SLOs) from the intent + slos = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"] + + if slos: + # Find candidate NRPs that can meet the SLO requirements + candidates = [ + (nrp, self.__slo_viability(slos, nrp)[1]) + for nrp in self.__nrp_view + if self.__slo_viability(slos, nrp)[0] and nrp["available"] + ] + logging.debug(f"Candidates: {candidates}") + + # Select the best NRP based on candidates + best_nrp = max(candidates, key=lambda x: x[1])[0] if candidates else None + logging.debug(f"Best NRP: {best_nrp}") + + if best_nrp: + best_nrp["slices"].append(ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["id"]) + # Update NRP view + self.__realizer(ietf_intent, True, "UPDATE") + # TODO Here we should put how the slice is attached to an already created nrp + else: + # Request the controller to create a new NRP that meets the SLOs + answer = self.__realizer(ietf_intent, True, "CREATE", best_nrp) + if not answer: + raise Exception("Slice rejected due to lack of NRPs") + # TODO Here we should put how the slice is attached to the new nrp + + if PLANNER_ENABLED: + optimal_path = Planner().planner(ietf_intent) + + logging.info(f"Optimal path: {optimal_path}") def __realizer(self, ietf_intent, need_nrp=False, order=None, nrp=None): """ @@ -405,7 +441,9 @@ class NSController: self.__nrp(order, nrp) else: # Select slice service method - return self.__select_way("L2VPN", ietf_intent) + way = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["service-tags"]["tag-type"]["value"] + way = "L3VPN" + return self.__select_way(controller=self.controller_type, way=way, ietf_intent=ietf_intent) ### Generic functionalities def __load_template(self, which, dir_t): @@ -467,8 +505,7 @@ class NSController: "source": self.answer[subnet]["Source"], "destination": self.answer[subnet]["Destination"], "vlan": self.answer[subnet]["VLAN"], - "bandwidth(Mbps)": self.answer[subnet]["QoS Requirements"][0], - "latency(ms)": self.answer[subnet]["QoS Requirements"][1] + "requirements": self.answer[subnet]["QoS Requirements"], } answer["slices"].append(slice_info) self.cool_answer = answer @@ -537,7 +574,8 @@ class NSController: content.append( { "slice_id": intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["id"], - "intent": intent + "intent": intent, + "controller": self.controller_type, }) # # Write updated content back to file @@ -597,8 +635,38 @@ class NSController: # Populate template with SLOs (currently supporting QoS profile, latency and bandwidth) ietf_i["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["id"] = gpp_intent[ep_transport_objects[0]]["qosProfile"] - ietf_i["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"][0]["bound"] = gpp_intent[subnet]["SliceProfileList"][0]["RANSliceSubnetProfile"]["uLThptPerSliceSubnet"]["MaxThpt"] - ietf_i["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"][1]["bound"] = gpp_intent[subnet]["SliceProfileList"][0]["RANSliceSubnetProfile"]["uLLatency"] + + profile = gpp_intent.get(subnet, {}).get("SliceProfileList", [{}])[0].get("RANSliceSubnetProfile", {}) + + + metrics = { + ("uLThptPerSliceSubnet", "MaxThpt"): ("one-way-bandwidth", "kbps"), + ("uLLatency",): ("one-way-delay-maximum", "milliseconds"), + ("EnergyConsumption",): ("energy_consumption", "Joules"), + ("EnergyEfficiency",): ("energy_efficiency", "W/bps"), + ("CarbonEmissions",): ("carbon_emission", "gCO2eq"), + ("RenewableEnergyUsage",): ("renewable_energy_usage", "rate") + } + + # Aux + def get_nested(d, keys): + for k in keys: + if isinstance(d, dict) and k in d: + d = d[k] + else: + return None + return d + + for key_path, (metric_type, metric_unit) in metrics.items(): + value = get_nested(profile, key_path) + if value is not None: + ietf_i["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]\ + ["slo-sle-template"][0]["slo-policy"]["metric-bound"].append({ + "metric-type": metric_type, + "metric-unit": metric_unit, + "bound": value + }) + # Generate unique slice service ID and description ietf_i["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["id"] = f"slice-service-{uuid.uuid4()}" @@ -626,10 +694,6 @@ class NSController: ietf_i["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["service-match-criteria"]["match-criterion"][0]["target-connection-group-id"] = f"{ep_transport_objects[0].split(' ', 1)[1]}_{ep_transport_objects[1].split(' ', 1)[1]}" ietf_i["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][1]["service-match-criteria"]["match-criterion"][0]["target-connection-group-id"] = f"{ep_transport_objects[0].split(' ', 1)[1]}_{ep_transport_objects[1].split(' ', 1)[1]}" - # Log translated intent for debugging - logging.debug(json.dumps(ietf_i,indent=2)) - with open(os.path.join(TEMPLATES_PATH, "ietf_template_example.json"), "w") as archivo: - archivo.write(json.dumps(ietf_i,indent=2)) return ietf_i ### Mapper functionalities @@ -677,102 +741,6 @@ class NSController: score = sum(flexibility_scores) / len(flexibility_scores) if flexibility_scores else 0 return True, score # Si pasó todas las verificaciones, la NRP es viable - def __planner(self, intent, nrp_view): - """ - TODO - Request slice viability from the Planner module. - - This method prepares and sends a viability request for network slice creation, - detaching the implementation from the main core thread. - - Args: - intent (dict): Network slice intent - nrp_view (list): Current Network Resource Pool view - - Returns: - tuple: A tuple containing: - - Viability status (str): "Good" or other status - - Reason (str): Explanation of viability - - Notes: - - Calculates source and destination service delivery points (SDP) - - Extracts QoS requirements - - Performs viability check through internal methods - """ - - #Version 1 - matriz = {} - matriz["payloads"] = [] - #for i in intent: - # SI ya existe, suma, si no existe, lo crea - origen = self.__calculate_sdp(intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["sdp-ip-address"]) - destino = self.__calculate_sdp(intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][1]["sdp-ip-address"]) - #qos_req = i["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["slo-sle-policy"]["slo-sle-template"] - qos_req = intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"][0]["bound"] - payload = { - "Source": origen, - "Destination": destino, - "QoS requirements": qos_req - } - matriz["payloads"].append(payload) - m_res = [] - m_qos = [] - for p in matriz["payloads"]: - res = p - m_res.append(res) - m_qos.append(p["QoS requirements"]) - m_res, m_qos = self.__viability(m_res,intent, m_qos) - reason="Viable" - viability = "Good" - return viability, reason - - def __viability(self, matrix, intent, qos): - """ - TODO - """ - aux = {} - aux["good"] = [] - aux["bad"] = [] - l_qos = [] - for i in range(len(intent)): - # if matrix[i]['success'] == True: - aux["good"].append(matrix[i]) - l_qos.append(qos[i]) - # else: - # aux["bad"].append(intent[i]) - return aux, l_qos - - def __calculate_sdp(self, pip): - ''' - TODO - Imput: - Output: - Work: Identifies the network entpoint from the IP-sdp received. - Version 0 will be done directly with next hop. - Version 1 will translate directly from the public IP of each node to their Loopback address. - ''' - nid = 0 - with open(os.path.join(TEMPLATES_PATH, "ips.json"), 'r') as source: - jason = source.read() - jason = jason.replace('\t', '').replace('\n', '').replace("'", '"').strip() - nodos = json.loads(str(jason)) - #template = json.loads(str(jason)) - # Once we have the template, we search for the one charged. - for nodo in nodos["public-prefixes"]: - if pip == nodo["prefix"]: - #nid = nodo["node-id"] - nid = nodo["node-name"] - for nodo in nodos["CU"]: - if pip == nodo["prefix"]: - #nid = nodo["node-id"] - nid = nodo["node-name"] - for nodo in nodos["DU"]: - if pip == nodo["prefix"]: - #nid = nodo["node-id"] - nid = nodo["node-name"] - return nid - - ### Realizer functionalities. def __nrp(self, request, nrp): """ @@ -826,11 +794,15 @@ class NSController: logging.debug("Updating NRP") answer = "" - def __select_way(self,way, ietf_intent): + def __select_way(self, controller=None, way=None, ietf_intent=None): """ Determine the method of slice realization. Args: + controller (str): The controller to use for slice realization. + Supported values: + - "IXIA": IXIA NEII for network testing + - "TFS": TeraFlow Service for network slice management way (str): The type of technology to use. Supported values: - "L2VPN": Layer 2 Virtual Private Network @@ -842,12 +814,22 @@ class NSController: dict: A realization request for the specified network slice type. """ - if way == "L2VPN": + realizing_request = None + if controller == "TFS": + if way == "L2VPN": + realizing_request = self.__tfs_l2vpn(ietf_intent) + elif way == "L3VPN": + realizing_request = self.__tfs_l3vpn(ietf_intent) + else: + logging.warning(f"Unsupported way: {way}. Defaulting to L2VPN realization.") + realizing_request = self.__tfs_l2vpn(ietf_intent) + elif controller == "IXIA": + realizing_request = self.__ixia(ietf_intent) + else: + logging.warning(f"Unsupported controller: {controller}. Defaulting to TFS L2VPN realization.") realizing_request = self.__tfs_l2vpn(ietf_intent) - elif way == "L3VPN": - realizing_request = self.__tfs_l3vpn(ietf_intent) return realizing_request - + def __tfs_l2vpn(self, ietf_intent): """ Translate slice intent into a TeraFlow service request. @@ -872,49 +854,100 @@ class NSController: origin_router_id = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["attachment-circuits"]["attachment-circuit"][0]["sdp-peering"]["peer-sap-id"] origin_router_if = '0/0/0-GigabitEthernet0/0/0/0' destination_router_id = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][1]["attachment-circuits"]["attachment-circuit"][0]["sdp-peering"]["peer-sap-id"] - destination_router_if = '0/0/3-GigabitEthernet0/0/0/3' + destination_router_if = '0/0/0-GigabitEthernet0/0/0/0' # Extract QoS Profile from intent QoSProfile = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["id"] - vlan_value = 0 - - # Load L2VPN service template - self.__load_template(2, os.path.join(TEMPLATES_PATH, "L2-VPN_template_empty.json")) - tfs_request = json.loads(str(self.__teraflow_template))["services"][0] - - # Generate unique service UUID - tfs_request["service_id"]["service_uuid"]["uuid"] += "-" + str(int(datetime.now().timestamp() * 1e7)) - - # Configure service endpoints - for endpoint in tfs_request["service_endpoint_ids"]: - endpoint["device_id"]["device_uuid"]["uuid"] = origin_router_id if endpoint is tfs_request["service_endpoint_ids"][0] else destination_router_id - endpoint["endpoint_uuid"]["uuid"] = origin_router_if if endpoint is tfs_request["service_endpoint_ids"][0] else destination_router_if self.answer[self.subnet]["QoS Requirements"] = [] - # Add service constraints - for i, constraint in enumerate(tfs_request["service_constraints"]): - bound = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"][i]["bound"] - self.answer[self.subnet]["QoS Requirements"].append(bound) - constraint["custom"]["constraint_value"] = str(bound) - - # Add configuration rules - for i, config_rule in enumerate(tfs_request["service_config"]["config_rules"][1:], start=1): - router_id = origin_router_id if i == 1 else destination_router_id - router_if = origin_router_if if i == 1 else destination_router_if - resource_value = config_rule["custom"]["resource_value"] - - sdp_index = i - 1 - vlan_value = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][sdp_index]["service-match-criteria"]["match-criterion"][0]["value"] - resource_value["vlan_id"] = int(vlan_value) - resource_value["circuit_id"] = vlan_value - resource_value["remote_router"] = destination_router_id if i == 1 else origin_router_id - resource_value["ni_name"] = 'ELAN{:s}'.format(str(vlan_value)) - config_rule["custom"]["resource_key"] = f"/device[{router_id}]/endpoint[{router_if}]/settings" - - # Log and store VLAN information - logging.info(f"Intent with VLAN {vlan_value} realized\n") + + # Populate response with QoS requirements and VLAN from intent + slo_policy = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"] + + # Process metrics + for metric in slo_policy.get("metric-bound", []): + constraint_type = f"{metric['metric-type']}[{metric['metric-unit']}]" + constraint_value = str(metric["bound"]) + self.answer[self.subnet]["QoS Requirements"].append({ + "constraint_type": constraint_type, + "constraint_value": constraint_value + }) + + # Availability + if "availability" in slo_policy: + self.answer[self.subnet]["QoS Requirements"].append({ + "constraint_type": "availability[%]", + "constraint_value": str(slo_policy["availability"]) + }) + + # MTU + if "mtu" in slo_policy: + self.answer[self.subnet]["QoS Requirements"].append({ + "constraint_type": "mtu[bytes]", + "constraint_value": str(slo_policy["mtu"]) + }) + + # VLAN + vlan_value = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["service-match-criteria"]["match-criterion"][0]["value"] self.answer[self.subnet]["VLAN"] = vlan_value + + if UPLOAD_TYPE == "WEBUI": + # Load L2VPN service template + self.__load_template(2, os.path.join(TEMPLATES_PATH, "L2-VPN_template_empty.json")) + tfs_request = json.loads(str(self.__teraflow_template))["services"][0] + + # Generate unique service UUID + tfs_request["service_id"]["service_uuid"]["uuid"] += "-" + str(int(datetime.now().timestamp() * 1e7)) + + # Configure service endpoints + for endpoint in tfs_request["service_endpoint_ids"]: + endpoint["device_id"]["device_uuid"]["uuid"] = origin_router_id if endpoint is tfs_request["service_endpoint_ids"][0] else destination_router_id + 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 self.answer[self.subnet]["QoS Requirements"]: + tfs_request["service_constraints"].append({"custom": constraint}) + + # Add configuration rules + for i, config_rule in enumerate(tfs_request["service_config"]["config_rules"][1:], start=1): + router_id = origin_router_id if i == 1 else destination_router_id + router_if = origin_router_if if i == 1 else destination_router_if + resource_value = config_rule["custom"]["resource_value"] + + sdp_index = i - 1 + vlan_value = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][sdp_index]["service-match-criteria"]["match-criterion"][0]["value"] + if vlan_value: + resource_value["vlan_id"] = int(vlan_value) + resource_value["circuit_id"] = vlan_value + resource_value["remote_router"] = destination_router_id if i == 1 else origin_router_id + resource_value["ni_name"] = 'ELAN{:s}'.format(str(vlan_value)) + config_rule["custom"]["resource_key"] = f"/device[{router_id}]/endpoint[{router_if}]/settings" + + elif UPLOAD_TYPE == "NBI": + self.path = NBI_L2_PATH + # Load IETF L2VPN service template + self.__load_template(2, os.path.join(TEMPLATES_PATH, "ietfL2VPN_template_empty.json")) + tfs_request = json.loads(str(self.__teraflow_template)) + + # Generate service UUID + full_id = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["id"] + uuid_only = full_id.split("slice-service-")[-1] + tfs_request["ietf-l2vpn-svc:vpn-service"][0]["vpn-id"] = uuid_only + + # Configure service endpoints + sites = tfs_request["ietf-l2vpn-svc:vpn-service"][0]["site"] + sdps = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"] + + for i, site in enumerate(sites): + is_origin = (i == 0) + router_id = origin_router_id if is_origin else destination_router_id + sdp = sdps[0] if is_origin else sdps[1] + site["site-id"] = router_id + site["site-location"] = sdp["node-id"] + site["site-network-access"]["interface"]["ip-address"] = sdp["sdp-ip-address"] + + logging.info(f"L2VPN Intent realized\n") return tfs_request def __tfs_l2vpn_support(self, requests): @@ -1006,50 +1039,221 @@ class NSController: dict: A TeraFlow service request for L3VPN configuration. """ # Hardcoded router endpoints - # TODO should be dynamically determined + # TODO (should be dynamically determined) origin_router_id = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["attachment-circuits"]["attachment-circuit"][0]["sdp-peering"]["peer-sap-id"] origin_router_if = '0/0/0-GigabitEthernet0/0/0/0' destination_router_id = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][1]["attachment-circuits"]["attachment-circuit"][0]["sdp-peering"]["peer-sap-id"] - destination_router_if = '0/0/3-GigabitEthernet0/0/0/3' - - # Load L3VPN service template - self.__load_template(2, os.path.join(TEMPLATES_PATH, "L3-VPN_template_empty.json")) - tfs_request = json.loads(str(self.__teraflow_template))["services"][0] + destination_router_if = '0/0/0-GigabitEthernet0/0/0/0' + + # Extract QoS Profile from intent + QoSProfile = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["id"] + vlan_value = 0 - # Generate unique service UUID - tfs_request["service_id"]["service_uuid"]["uuid"] += "-" + str(int(datetime.now().timestamp() * 1e7)) + self.answer[self.subnet]["QoS Requirements"] = [] - # Configure service endpoints - for endpoint in tfs_request["service_endpoint_ids"]: - endpoint["device_id"]["device_uuid"]["uuid"] = origin_router_id if endpoint is tfs_request["service_endpoint_ids"][0] else destination_router_id - endpoint["endpoint_uuid"]["uuid"] = origin_router_if if endpoint is tfs_request["service_endpoint_ids"][0] else destination_router_if + # Populate response with QoS requirements and VLAN from intent + slo_policy = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"] + + # Process metrics + for metric in slo_policy.get("metric-bound", []): + constraint_type = f"{metric['metric-type']}[{metric['metric-unit']}]" + constraint_value = str(metric["bound"]) + self.answer[self.subnet]["QoS Requirements"].append({ + "constraint_type": constraint_type, + "constraint_value": constraint_value + }) + + # Availability + if "availability" in slo_policy: + self.answer[self.subnet]["QoS Requirements"].append({ + "constraint_type": "availability[%]", + "constraint_value": str(slo_policy["availability"]) + }) + + # MTU + if "mtu" in slo_policy: + self.answer[self.subnet]["QoS Requirements"].append({ + "constraint_type": "mtu[bytes]", + "constraint_value": str(slo_policy["mtu"]) + }) + + # VLAN + vlan_value = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["service-match-criteria"]["match-criterion"][0]["value"] + self.answer[self.subnet]["VLAN"] = vlan_value - # Add service constraints - for i, constraint in enumerate(tfs_request["service_constraints"]): - bound = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"][i]["bound"] - constraint["custom"]["constraint_value"] = str(bound) - - # Add configuration rules - for i, config_rule in enumerate(tfs_request["service_config"]["config_rules"][1:], start=1): - router_id = origin_router_id if i == 1 else destination_router_id - router_if = origin_router_if if i == 1 else destination_router_if - resource_value = config_rule["custom"]["resource_value"] - - sdp_index = i - 1 - vlan_value = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][sdp_index]["service-match-criteria"]["match-criterion"][0]["value"] - resource_value["router_id"] = destination_router_id if i == 1 else origin_router_id - resource_value["vlan_id"] = int(vlan_value) - resource_value["address_ip"] = destination_router_id if i == 1 else origin_router_id - resource_value["policy_AZ"] = "policyA" - resource_value["policy_ZA"] = "policyB" - resource_value["ni_name"] = 'ELAN{:s}'.format(str(vlan_value)) - config_rule["custom"]["resource_key"] = f"/device[{router_id}]/endpoint[{router_if}]/settings" + if UPLOAD_TYPE == "WEBUI": + # Load L3VPN service template + self.__load_template(2, os.path.join(TEMPLATES_PATH, "L3-VPN_template_empty.json")) + tfs_request = json.loads(str(self.__teraflow_template))["services"][0] + + # Generate unique service UUID + tfs_request["service_id"]["service_uuid"]["uuid"] += "-" + str(int(datetime.now().timestamp() * 1e7)) + + # Configure service endpoints + for endpoint in tfs_request["service_endpoint_ids"]: + endpoint["device_id"]["device_uuid"]["uuid"] = origin_router_id if endpoint is tfs_request["service_endpoint_ids"][0] else destination_router_id + 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 self.answer[self.subnet]["QoS Requirements"]: + tfs_request["service_constraints"].append({"custom": constraint}) + + # Add configuration rules + for i, config_rule in enumerate(tfs_request["service_config"]["config_rules"][1:], start=1): + router_id = origin_router_id if i == 1 else destination_router_id + router_if = origin_router_if if i == 1 else destination_router_if + resource_value = config_rule["custom"]["resource_value"] + + sdp_index = i - 1 + vlan_value = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][sdp_index]["service-match-criteria"]["match-criterion"][0]["value"] + resource_value["router_id"] = destination_router_id if i == 1 else origin_router_id + resource_value["vlan_id"] = int(vlan_value) + resource_value["address_ip"] = destination_router_id if i == 1 else origin_router_id + resource_value["policy_AZ"] = "policyA" + resource_value["policy_ZA"] = "policyB" + resource_value["ni_name"] = 'ELAN{:s}'.format(str(vlan_value)) + config_rule["custom"]["resource_key"] = f"/device[{router_id}]/endpoint[{router_if}]/settings" - return tfs_request + elif UPLOAD_TYPE == "NBI": + self.path = NBI_L3_PATH + # Load IETF L3VPN service template + self.__load_template(2, os.path.join(TEMPLATES_PATH, "ietfL3VPN_template_empty.json")) + tfs_request = json.loads(str(self.__teraflow_template)) + + # Generate service UUID + full_id = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["id"] + tfs_request["ietf-l3vpn-svc:l3vpn-svc"]["vpn-services"]["vpn-service"][0]["vpn-id"] = full_id + # Configure service endpoints + for i, site in enumerate(tfs_request["ietf-l3vpn-svc:l3vpn-svc"]["sites"]["site"]): + + # Determine if origin or destination + is_origin = (i == 0) + sdp_index = 0 if is_origin else 1 + location = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][sdp_index]["node-id"] + router_id = origin_router_id if is_origin else destination_router_id + router_if = origin_router_if if is_origin else destination_router_if + + # Assign common values + site["site-id"] = f"site_{location}" + site["locations"]["location"][0]["location-id"] = location + site["devices"]["device"][0]["device-id"] = router_id + site["devices"]["device"][0]["location"] = location + + access = site["site-network-accesses"]["site-network-access"][0] + access["site-network-access-id"] = router_if + access["device-reference"] = router_id + access["vpn-attachment"]["vpn-id"] = full_id + + # Aplicar restricciones QoS + for constraint in self.answer[self.subnet]["QoS Requirements"]: + ctype = constraint["constraint_type"] + cvalue = float(constraint["constraint_value"]) + if constraint["constraint_type"].startswith("one-way-bandwidth"): + unit = constraint["constraint_type"].split("[")[-1].rstrip("]") + multiplier = {"bps": 1, "kbps": 1_000, "Mbps": 1_000_000, "Gbps": 1_000_000_000}.get(unit, 1) + value = int(cvalue * multiplier) + access["service"]["svc-input-bandwidth"] = value + access["service"]["svc-output-bandwidth"] = value + elif ctype == "one-way-delay-maximum[milliseconds]": + access["service"]["qos"]["qos-profile"]["classes"]["class"][0]["latency"]["latency-boundary"] = int(cvalue) + elif ctype == "availability[%]": + access["service"]["qos"]["qos-profile"]["classes"]["class"][0]["bandwidth"]["guaranteed-bw-percent"] = int(cvalue) + elif ctype == "mtu[bytes]": + access["service"]["svc-mtu"] = int(cvalue) + + logging.info(f"L3VPN Intent realized\n") + self.answer[self.subnet]["VLAN"] = vlan_value + return tfs_request + def __ixia(self, ietf_intent): + """ + Prepare an Ixia service request based on the IETF intent. + This method configures an Ixia service request by: + 1. Defining endpoint routers + 2. Loading a service template + 3. Generating a unique service UUID + 4. Configuring service endpoints + 5. Adding QoS constraints + Args: + ietf_intent (dict): IETF-formatted network slice intent. + Returns: + dict: An Ixia service request for configuration. + """ + self.answer[self.subnet]["QoS Requirements"] = [] + # Add service constraints + for i, constraint in enumerate(ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"]): + bound = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"][i]["bound"] + metric_type = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"][i]["metric-type"] + metric_unit = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"][i]["metric-unit"] + service_constraint ={ + "custom": { + "constraint_type": f"{metric_type}[{metric_unit}]", + "constraint_value": f"{bound}" + } + } + self.answer[self.subnet]["QoS Requirements"].append(service_constraint["custom"]) + self.answer[self.subnet]["VLAN"] = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["service-match-criteria"]["match-criterion"][0]["value"] + # Extraer la lista de métricas de forma segura + metric_bounds = ietf_intent.get("ietf-network-slice-service:network-slice-services", {}) \ + .get("slo-sle-templates", {}) \ + .get("slo-sle-template", [{}])[0] \ + .get("slo-policy", {}) \ + .get("metric-bound", []) + + # Inicializar valores + bandwidth = None + latency = None + tolerance = None + + # Asignar valores según el tipo de métrica + for metric in metric_bounds: + metric_type = metric.get("metric-type") + bound = metric.get("bound") + + if metric_type == "one-way-bandwidth": + bandwidth = bound + elif metric_type == "one-way-delay-maximum": + latency = bound + elif metric_type == "one-way-delay-variation-maximum": + tolerance = bound + + # Construcción del diccionario intent + intent = { + "src_node_ip": ietf_intent.get("ietf-network-slice-service:network-slice-services", {}) + .get("slice-service", [{}])[0] + .get("sdps", {}).get("sdp", [{}])[0] + .get("attachment-circuits", {}).get("attachment-circuit", [{}])[0] + .get("sdp-peering", {}).get("peer-sap-id"), + + "dst_node_ip": ietf_intent.get("ietf-network-slice-service:network-slice-services", {}) + .get("slice-service", [{}])[0] + .get("sdps", {}).get("sdp", [{}, {}])[1] + .get("attachment-circuits", {}).get("attachment-circuit", [{}])[0] + .get("sdp-peering", {}).get("peer-sap-id"), + + "vlan_id": ietf_intent.get("ietf-network-slice-service:network-slice-services", {}) + .get("slice-service", [{}])[0] + .get("sdps", {}).get("sdp", [{}])[0] + .get("service-match-criteria", {}).get("match-criterion", [{}])[0] + .get("value"), + + "bandwidth": bandwidth, + "latency": latency, + "tolerance": tolerance, + + "latency_version": ietf_intent.get("ietf-network-slice-service:network-slice-services", {}) + .get("slo-sle-templates", {}).get("slo-sle-template", [{}])[0] + .get("description"), + + "reliability": ietf_intent.get("ietf-network-slice-service:network-slice-services", {}) + .get("slo-sle-templates", {}).get("slo-sle-template", [{}])[0] + .get("sle-policy", {}).get("reliability"), + } + logging.info(f"IXIA Intent realized\n") + return intent diff --git a/src/planner/energy_ddbb.json b/src/planner/energy_ddbb.json new file mode 100644 index 0000000000000000000000000000000000000000..7826de6031621fb4103690cc02ac8b655c8996ad --- /dev/null +++ b/src/planner/energy_ddbb.json @@ -0,0 +1,156 @@ +[ + { + "name": "A", + "typical-power": 3500, + "maximum-traffic": 100.0, + "max-power": 150.0, + "efficiency": 0.9, + "nominal-power": 130.0, + "carbon-emissions": 130.0, + "renewable-energy-usage": 0.7, + "power-supply": [ + {"name": "PSU-1", "type": "AC", "capacity": 200.0, "typical-power": 100.0, "nominal-power": 110.0} + ], + "boards": [ + {"name": "Board-1", "type": "Linecard", "capacity": 40.0, "typical-power": 20.0, "nominal-power": 25.0} + ], + "components": [ + {"name": "CPU", "type": "Control", "capacity": 10.0, "typical-power": 5.0, "nominal-power": 6.0} + ], + "transceivers": [ + {"name": "XFP1", "type": "10G", "capacity": 10.0, "typical-power": 2.0, "nominal-power": 2.5} + ] + }, + { + "name": "B", + "typical-power": 6000, + "maximum-traffic": 120.0, + "max-power": 180.0, + "efficiency": 1, + "nominal-power": 160.0, + "carbon-emissions": 180.0, + "renewable-energy-usage": 0.6, + "power-supply": [ + {"name": "PSU-1", "type": "DC", "capacity": 250.0, "typical-power": 120.0, "nominal-power": 130.0} + ], + "boards": [ + {"name": "Board-2", "type": "Switching", "capacity": 60.0, "typical-power": 30.0, "nominal-power": 35.0} + ], + "components": [ + {"name": "ASIC", "type": "Forwarding", "capacity": 15.0, "typical-power": 7.0, "nominal-power": 8.0} + ], + "transceivers": [ + {"name": "SFP1", "type": "1G", "capacity": 1.0, "typical-power": 1.0, "nominal-power": 1.2} + ] + }, + { + "name": "C", + "typical-power": 3200, + "maximum-traffic": 150.0, + "max-power": 250.0, + "efficiency": 1.2, + "nominal-power": 210.0, + "carbon-emissions": 160.0, + "renewable-energy-usage": 0.5, + "power-supply": [ + {"name": "PSU-2", "type": "AC", "capacity": 300.0, "typical-power": 150.0, "nominal-power": 160.0} + ], + "boards": [ + {"name": "Board-3", "type": "Routing", "capacity": 80.0, "typical-power": 40.0, "nominal-power": 45.0} + ], + "components": [ + {"name": "FPGA", "type": "Processing", "capacity": 20.0, "typical-power": 10.0, "nominal-power": 12.0} + ], + "transceivers": [ + {"name": "QSFP1", "type": "40G", "capacity": 40.0, "typical-power": 4.0, "nominal-power": 5.0} + ] + }, + { + "name": "D", + "typical-power": 6000, + "maximum-traffic": 200.0, + "max-power": 300.0, + "efficiency": 0.9, + "nominal-power": 260.0, + "carbon-emissions": 100.0, + "renewable-energy-usage": 0.5, + "power-supply": [ + {"name": "PSU-3", "type": "DC", "capacity": 350.0, "typical-power": 180.0, "nominal-power": 190.0} + ], + "boards": [ + {"name": "Board-4", "type": "Access", "capacity": 100.0, "typical-power": 50.0, "nominal-power": 55.0} + ], + "components": [ + {"name": "GPU", "type": "Accelerator", "capacity": 25.0, "typical-power": 12.0, "nominal-power": 14.0} + ], + "transceivers": [ + {"name": "CFP1", "type": "100G", "capacity": 100.0, "typical-power": 8.0, "nominal-power": 10.0} + ] + }, + { + "name": "E", + "typical-power": 4500, + "maximum-traffic": 250.0, + "max-power": 350.0, + "efficiency": 1.4, + "nominal-power": 310.0, + "carbon-emissions": 180, + "renewable-energy-usage": 0.6, + "power-supply": [ + {"name": "PSU-4", "type": "AC", "capacity": 400.0, "typical-power": 200.0, "nominal-power": 210.0} + ], + "boards": [ + {"name": "Board-5", "type": "Core", "capacity": 120.0, "typical-power": 60.0, "nominal-power": 65.0} + ], + "components": [ + {"name": "TPU", "type": "Neural Processing", "capacity": 30.0, "typical-power": 15.0, "nominal-power": 18.0} + ], + "transceivers": [ + {"name": "OSFP1", "type": "400G", "capacity": 400.0, "typical-power": 12.0, "nominal-power": 15.0} + ] + }, + { + "name": "F", + "typical-power": 3000, + "maximum-traffic": 300.0, + "max-power": 400.0, + "efficiency": 1.3, + "nominal-power": 360.0, + "carbon-emissions": 140, + "renewable-energy-usage": 0.6, + "power-supply": [ + {"name": "PSU-5", "type": "DC", "capacity": 450.0, "typical-power": 220.0, "nominal-power": 230.0} + ], + "boards": [ + {"name": "Board-6", "type": "Edge", "capacity": 150.0, "typical-power": 75.0, "nominal-power": 80.0} + ], + "components": [ + {"name": "ASIC2", "type": "Edge Processing", "capacity": 40.0, "typical-power": 20.0, "nominal-power": 22.0} + ], + "transceivers": [ + {"name": "QSFP-DD1", "type": "800G", "capacity": 800.0, "typical-power": 16.0, "nominal-power": 20.0} + ] + }, + { + "name": "G", + "typical-power": 3100, + "maximum-traffic": 350.0, + "max-power": 450.0, + "efficiency": 1.1, + "nominal-power": 410.0, + "carbon-emissions": 105.0, + "renewable-energy-usage": 0.6, + "power-supply": [ + {"name": "PSU-6", "type": "AC", "capacity": 500.0, "typical-power": 250.0, "nominal-power": 260.0} + ], + "boards": [ + {"name": "Board-7", "type": "Virtualization", "capacity": 180.0, "typical-power": 90.0, "nominal-power": 95.0} + ], + "components": [ + {"name": "FPGA2", "type": "Reconfigurable Processing", "capacity": 50.0, "typical-power": 25.0, "nominal-power": 28.0} + ], + "transceivers": [ + {"name": "CFP2", "type": "1.6T", "capacity": 1600.0, "typical-power": 20.0, "nominal-power": 25.0} + ] + } +] \ No newline at end of file diff --git a/src/planner/ext_topo_ddbb.json b/src/planner/ext_topo_ddbb.json new file mode 100644 index 0000000000000000000000000000000000000000..72dc93dc10ca271adf670d9b85466920a4736929 --- /dev/null +++ b/src/planner/ext_topo_ddbb.json @@ -0,0 +1,195 @@ +{ +"nodes": [ + { + "nodeId": 1, + "name": "A", + "type": "SITE", + "footprint": { "cpu": 2, "memory": 1024, "disk": 5000 }, + "vulnerability": 1 + }, + { + "nodeId": 2, + "name": "B", + "type": "SITE", + "footprint": { "cpu": 1, "memory": 512, "disk": 3000 }, + "vulnerability": 2 + }, + { + "nodeId": 3, + "name": "C", + "type": "SITE", + "footprint": { "cpu": 2, "memory": 2048, "disk": 6000 }, + "vulnerability": 3 + }, + { + "nodeId": 4, + "name": "D", + "type": "SITE", + "footprint": { "cpu": 1, "memory": 1024, "disk": 4000 }, + "vulnerability": 1 + }, + { + "nodeId": 5, + "name": "E", + "type": "SITE", + "footprint": { "cpu": 2, "memory": 1024, "disk": 5000 }, + "vulnerability": 2 + }, + { + "nodeId": 6, + "name": "F", + "type": "SITE", + "footprint": { "cpu": 1, "memory": 512, "disk": 3000 }, + "vulnerability": 2 + }, + { + "nodeId": 7, + "name": "G", + "type": "SITE", + "footprint": { "cpu": 2, "memory": 1024, "disk": 7000 }, + "vulnerability": 3 + } +], +"links":[ + { + "linkId": "A-E", + "sourceNodeId": "1", + "destNodeId": "5", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 5 }] + }, + { + "linkId": "E-A", + "sourceNodeId": "5", + "destNodeId": "1", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 5 }] + }, + { + "linkId": "A-D", + "sourceNodeId": "1", + "destNodeId": "4", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 4 }] + }, + { + "linkId": "D-A", + "sourceNodeId": "4", + "destNodeId": "1", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 4 }] + }, + { + "linkId": "A-C", + "sourceNodeId": "1", + "destNodeId": "3", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 3 }] + }, + { + "linkId": "C-A", + "sourceNodeId": "3", + "destNodeId": "1", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 3 }] + }, + { + "linkId": "B-C", + "sourceNodeId": "2", + "destNodeId": "3", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 6 }] + }, + { + "linkId": "C-B", + "sourceNodeId": "3", + "destNodeId": "2", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 6 }] + }, + { + "linkId": "B-D", + "sourceNodeId": "2", + "destNodeId": "4", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 7 }] + }, + { + "linkId": "D-B", + "sourceNodeId": "4", + "destNodeId": "2", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 7 }] + }, + { + "linkId": "B-F", + "sourceNodeId": "2", + "destNodeId": "6", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 5 }] + }, + { + "linkId": "F-B", + "sourceNodeId": "6", + "destNodeId": "2", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 5 }] + }, + { + "linkId": "D-E", + "sourceNodeId": "4", + "destNodeId": "5", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 2 }] + }, + { + "linkId": "E-D", + "sourceNodeId": "5", + "destNodeId": "4", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 2 }] + }, + { + "linkId": "D-F", + "sourceNodeId": "4", + "destNodeId": "6", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 6 }] + }, + { + "linkId": "F-D", + "sourceNodeId": "6", + "destNodeId": "4", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 6 }] + }, + { + "linkId": "E-G", + "sourceNodeId": "5", + "destNodeId": "7", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 3 }] + }, + { + "linkId": "G-E", + "sourceNodeId": "7", + "destNodeId": "5", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 3 }] + }, + { + "linkId": "F-G", + "sourceNodeId": "6", + "destNodeId": "7", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 4 }] + }, + { + "linkId": "G-F", + "sourceNodeId": "7", + "destNodeId": "6", + "bandwidth": 1000000000, + "metrics": [{ "metric": "DELAY", "value": 4 }] + } +] +} \ No newline at end of file diff --git a/src/planner/planner.py b/src/planner/planner.py new file mode 100644 index 0000000000000000000000000000000000000000..b5fb1ba1ee624fcc090d4c85dfc252f2463ac042 --- /dev/null +++ b/src/planner/planner.py @@ -0,0 +1,286 @@ +# 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. + +# This file is an original contribution from Telefonica Innovación Digital S.L. + +import logging, random, os, json, heapq +from src.Constants import SRC_PATH, PCE_EXTERNAL, DEFAULT_LOGGING_LEVEL + +# Configure logging to provide clear and informative log messages +logging.basicConfig( + level=DEFAULT_LOGGING_LEVEL, + format='%(levelname)s - %(message)s') + +class Planner: + """ + Planner class to compute the optimal path for a network slice based on energy consumption and topology. + """ + + def planner(self, intent): + """ + Plan the optimal path for a network slice based on energy consumption and topology. + """ + energy_metrics = self.__retrieve_energy() + topology = self.__retrieve_topology() + source = intent.get("ietf-network-slice-service:network-slice-services", {}).get("slice-service", [])[0].get("sdps", {}).get("sdp", [])[0].get("id") or "A" + destination = intent.get("ietf-network-slice-service:network-slice-services", {}).get("slice-service", [])[0].get("sdps", {}).get("sdp", [])[1].get("id") or "B" + optimal_path = [] + # If using an external PCE + if PCE_EXTERNAL: + logging.info("Using external PCE for path planning") + def build_slice_input(node_source, node_destination): + return { + "clientName": "demo-client", + "requestId": random.randint(1000, 9999), + "sites": [node_source["nodeId"], node_destination["nodeId"]], + "graph": { + "nodes": [ + { + "nodeId": node_source["nodeId"], + "name": node_source["name"], + "footprint": node_source["footprint"], + "sticky": [node_source["nodeId"]] + }, + { + "nodeId": node_destination["nodeId"], + "name": node_destination["name"], + "footprint": node_destination["footprint"], + "sticky": [node_destination["nodeId"]] + } + ], + "links": [ + { + "fromNodeId": node_source["nodeId"], + "toNodeId": node_destination["nodeId"], + "bandwidth": 1000000000, + "metrics": [ + { + "metric": "DELAY", + "value": 10, + "bound": True, + "required": True + } + ] + } + ], + "constraints": { + "maxVulnerability": 3, + "maxDeployedServices": 10, + "metricLimits": [] + } + } + } + source = next((node for node in topology["nodes"] if node["name"] == source), None) + destination = next((node for node in topology["nodes"] if node["name"] == destination), None) + slice_input = build_slice_input(source, destination) + + # POST /sss/v1/slice/compute + def simulate_slice_output(input_data): + return { + "input": input_data, + "slice": { + "nodes": [ + {"site": 1, "service": 1}, + {"site": 2, "service": 2} + ], + "links": [ + { + "fromNodeId": 1, + "toNodeId": 2, + "lspId": 500, + "path": { + "ingressNodeId": 1, + "egressNodeId": 2, + "hops": [ + {"nodeId": 3, "linkId": "A-C", "portId": 1}, + {"nodeId": 2, "linkId": "C-B", "portId": 2} + ] + } + } + ], + "metric": {"value": 9} + }, + "error": None + } + slice_output = simulate_slice_output(slice_input) + # Mostrar resultado + optimal_path.append(source["name"]) + for link in slice_output["slice"]["links"]: + for hop in link["path"]["hops"]: + optimal_path.append(next((node for node in topology["nodes"] if node["nodeId"] == hop['nodeId']), None)["name"]) + + else: + logging.info("Using internal PCE for path planning") + ietf_dlos = intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"] + logging.info(ietf_dlos), + # Solo asigna los DLOS que existan, el resto a None + dlos = { + "EC": next((item.get("bound") for item in ietf_dlos if item.get("metric-type") == "energy_consumption"), None), + "CE": next((item.get("bound") for item in ietf_dlos if item.get("metric-type") == "carbon_emission"), None), + "EE": next((item.get("bound") for item in ietf_dlos if item.get("metric-type") == "energy_efficiency"), None), + "URE": next((item.get("bound") for item in ietf_dlos if item.get("metric-type") == "renewable_energy_usage"), None) + } + logging.debug(f"Planning optimal path from {source} to {destination} with DLOS: {dlos}") + optimal_path = self.__calculate_optimal_path(topology, energy_metrics, source, destination, dlos) + + if not optimal_path: + logging.error("No valid path found") + raise Exception("No valid energy path found") + + return optimal_path + + def __retrieve_energy(self): + # TODO : Implement the logic to retrieve energy consumption data from controller + # Taking it from static file + with open(os.path.join(SRC_PATH, "planner/energy_ddbb.json"), "r") as archivo: + energy_metrics = json.load(archivo) + return energy_metrics + + def __retrieve_topology(self): + if PCE_EXTERNAL: + # TODO : Implement the logic to retrieve topology data from external PCE + # GET /sss/v1/topology/node and /sss/v1/topology/link + with open(os.path.join(SRC_PATH, "planner/ext_topo_ddbb.json"), "r") as archivo: + topology = json.load(archivo) + else: + # TODO : Implement the logic to retrieve topology data from controller + # Taking it from static file + with open(os.path.join(SRC_PATH, "planner/topo_ddbb.json"), "r") as archivo: + topology = json.load(archivo) + return topology + + + + def __calculate_optimal_path(self, topology, energy_metrics, source, destination, dlos): + logging.debug("Starting optimal path calculation...") + + # Create a dictionary with the weights of each node + node_data_map = {} + for node_data in energy_metrics: + node_id = node_data["name"] + ec = node_data["typical-power"] + ce = node_data["carbon-emissions"] + ee = node_data["efficiency"] + ure = node_data["renewable-energy-usage"] + + total_power_supply = sum(ps["typical-power"] for ps in node_data["power-supply"]) + total_power_boards = sum(b["typical-power"] for b in node_data["boards"]) + total_power_components = sum(c["typical-power"] for c in node_data["components"]) + total_power_transceivers = sum(t["typical-power"] for t in node_data["transceivers"]) + + logging.debug(f"Node {node_id}: EC={ec}, CE={ce}, EE={ee}, URE={ure}") + logging.debug(f"Node {node_id}: PS={total_power_supply}, BO={total_power_boards}, CO={total_power_components}, TR={total_power_transceivers}") + + weight = self.__compute_node_weight(ec, ce, ee, ure, + total_power_supply, + total_power_boards, + total_power_components, + total_power_transceivers) + logging.debug(f"Weight for node {node_id}: {weight}") + + node_data_map[node_id] = { + "weight": weight, + "ec": ec, + "ce": ce, + "ee": ee, + "ure": ure + } + + # Create a graph representation of the topology + graph = {} + for node in topology["ietf-network:networks"]["network"][0]["node"]: + graph[node["node-id"]] = [] + for link in topology["ietf-network:networks"]["network"][0]["link"]: + src = link["source"]["source-node"] + dst = link["destination"]["dest-node"] + graph[src].append((dst, node_data_map[dst]["weight"])) + logging.debug(f"Added link: {src} -> {dst} with weight {node_data_map[dst]['weight']}") + + # Dijkstra's algorithm with restrictions + queue = [(0, source, [], 0, 0, 0, 1)] # (accumulated cost, current node, path, sum_ec, sum_ce, sum_ee, min_ure) + visited = set() + + logging.debug(f"Starting search from {source} to {destination} with restrictions: {dlos}") + + + while queue: + cost, node, path, sum_ec, sum_ce, sum_ee, min_ure = heapq.heappop(queue) + logging.debug(f"Exploring node {node} with cost {cost} and path {path + [node]}") + + if node in visited: + logging.debug(f"Node {node} already visited, skipped.") + continue + visited.add(node) + path = path + [node] + + node_metrics = node_data_map[node] + sum_ec += node_metrics["ec"] + sum_ce += node_metrics["ce"] + sum_ee += node_metrics["ee"] + min_ure = min(min_ure, node_metrics["ure"]) if path[:-1] else node_metrics["ure"] + + logging.debug(f"Accumulated -> EC: {sum_ec}, CE: {sum_ce}, EE: {sum_ee}, URE min: {min_ure}") + + if dlos["EC"] is not None and sum_ec > dlos["EC"]: + logging.debug(f"Discarded path {path} for exceeding EC ({sum_ec} > {dlos['EC']})") + continue + if dlos["CE"] is not None and sum_ce > dlos["CE"]: + logging.debug(f"Discarded path {path} for exceeding CE ({sum_ce} > {dlos['CE']})") + continue + if dlos["EE"] is not None and sum_ee > dlos["EE"]: + logging.debug(f"Discarded path {path} for exceeding EE ({sum_ee} > {dlos['EE']})") + continue + if dlos["URE"] is not None and min_ure < dlos["URE"]: + logging.debug(f"Discarded path {path} for not reaching minimum URE ({min_ure} < {dlos['URE']})") + continue + + if node == destination: + logging.debug(f"Destination {destination} reached with a valid path: {path}") + return path + + for neighbor, weight in graph.get(node, []): + if neighbor not in visited: + logging.debug(f"Qeue -> neighbour: {neighbor}, weight: {weight}") + heapq.heappush(queue, ( + cost + weight, + neighbor, + path, + sum_ec, + sum_ce, + sum_ee, + min_ure + )) + logging.debug("No valid path found that meets the restrictions.") + return [] + + + def __compute_node_weight(self, ec, ce, ee, ure, total_power_supply, total_power_boards, total_power_components, total_power_transceivers, alpha=1, beta=1, gamma=1, delta=1): + """ + Calcula el peso de un nodo con la fórmula: + w(v) = α·EC + β·CE + γ/EE + δ·(1 - URE) + """ + traffic = 100 + # Measure one hour of traffic + time = 1 + + power_idle = ec + total_power_supply + total_power_boards + total_power_components + total_power_transceivers + power_traffic = traffic * ee + + power_total = (power_idle + power_traffic) + + green_index = power_total * time / 1000 * (1 - ure) * ce + + return green_index + + diff --git a/src/planner/topo_ddbb.json b/src/planner/topo_ddbb.json new file mode 100644 index 0000000000000000000000000000000000000000..76fb08c68d4c7337e09f79ce827004fba810a5b9 --- /dev/null +++ b/src/planner/topo_ddbb.json @@ -0,0 +1,43 @@ +{ + "ietf-network:networks":{ + "network":[ + { + "network-id":"example_network", + "network-types":{ + + }, + "node":[ + {"node-id":"A"}, + {"node-id":"B"}, + {"node-id":"C"}, + {"node-id":"D"}, + {"node-id":"E"}, + {"node-id":"F"}, + {"node-id":"G"} + ], + "link":[ + {"link-id":"A-E","source":{"source-node":"A"},"destination":{"dest-node":"E"}}, + {"link-id":"E-A","source":{"source-node":"E"},"destination":{"dest-node":"A"}}, + {"link-id":"A-D","source":{"source-node":"A"},"destination":{"dest-node":"D"}}, + {"link-id":"D-A","source":{"source-node":"D"},"destination":{"dest-node":"A"}}, + {"link-id":"A-C","source":{"source-node":"A"},"destination":{"dest-node":"C"}}, + {"link-id":"C-A","source":{"source-node":"C"},"destination":{"dest-node":"A"}}, + {"link-id":"B-C","source":{"source-node":"B"},"destination":{"dest-node":"C"}}, + {"link-id":"C-B","source":{"source-node":"C"},"destination":{"dest-node":"B"}}, + {"link-id":"B-D","source":{"source-node":"B"},"destination":{"dest-node":"D"}}, + {"link-id":"D-B","source":{"source-node":"D"},"destination":{"dest-node":"B"}}, + {"link-id":"B-F","source":{"source-node":"B"},"destination":{"dest-node":"F"}}, + {"link-id":"F-B","source":{"source-node":"F"},"destination":{"dest-node":"B"}}, + {"link-id":"D-E","source":{"source-node":"D"},"destination":{"dest-node":"E"}}, + {"link-id":"E-D","source":{"source-node":"E"},"destination":{"dest-node":"D"}}, + {"link-id":"D-F","source":{"source-node":"D"},"destination":{"dest-node":"F"}}, + {"link-id":"F-D","source":{"source-node":"F"},"destination":{"dest-node":"D"}}, + {"link-id":"E-G","source":{"source-node":"E"},"destination":{"dest-node":"G"}}, + {"link-id":"G-E","source":{"source-node":"G"},"destination":{"dest-node":"E"}}, + {"link-id":"F-G","source":{"source-node":"F"},"destination":{"dest-node":"G"}}, + {"link-id":"G-F","source":{"source-node":"G"},"destination":{"dest-node":"F"}} + ] + } + ] + } + } \ No newline at end of file diff --git a/src/realizers/ixia/NEII_V4.py b/src/realizers/ixia/NEII_V4.py new file mode 100644 index 0000000000000000000000000000000000000000..f9379d2cc0ddb0aceecb38ad918e0a995b0cebfe --- /dev/null +++ b/src/realizers/ixia/NEII_V4.py @@ -0,0 +1,375 @@ +# 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. + +# This file is an original contribution from Telefonica Innovación Digital S.L. + +from .automatizacion_ne2v4 import automatizacion +import ipaddress, logging +from src.Constants import IXIA_IP + +class NEII_controller: + def __init__(self, ixia_ip=IXIA_IP): + self.ixia_ip = ixia_ip + + def menu_principal(self, ip=IXIA_IP): + ''' + Inputs: + Outputs: + Work: The main menu of the application. + Notes: If the file is executed from the terminal, ensure that the import + of "automatizacion_ne2v4" does not include a dot at the beggining. + ''' + ip=input("¿Cuál es la IP del network emulator?: ") + accion=input("¿Qué deseas hacer?: \n(1) Ver información de IP\n(2) Consultar información del Hardware\n(3) Configurar un perfil nuevo\n(4) Consultar perfiles existentes\nSelecciona una opción: ") + if accion=="1": + self.ver_info(ip) + if accion=="2": + self.hardware(ip) + if accion=="3": + self.nuevo_perfil(ip) + if accion=="4": + self.existentes(ip) + return + + ## FUNCIONES MENÚ PRINCIPAL ## + + def ver_info(self,ip): + ''' + Inputs: -ip: the ip where the Axia API is located. + Outputs: + Work: It gives the information of the API. + + ''' + informacion_ip=automatizacion.obtener_informacion_ip(ip) + if informacion_ip: + print(informacion_ip) + + def hardware(self,ip): + ''' + Inputs: -ip: the ip where the Axia API is located. + Outputs: + Work: It gives the information of the hardware. + + ''' + informacion_hardware=automatizacion.obtener_informacion_hardware(ip) + if informacion_hardware: + print(informacion_hardware) + + def nuevo_perfil(self,ip): + ''' + Inputs: -ip: the ip where the Axia API is located. + Outputs: + Work: Creates and configures the profiles requested in the Axia API on the specified port. + Notes: It is NOT required to fill all the information requested. + + ''' + puerto=input("¿Qué puerto quieres configurar?: ") + num_perfiles=int(input("¿Cuantos perfiles quieres añadir?: ")) + configuraciones_totales=[] + for i in range(num_perfiles): + nombre=f"perfil{i+1}" + accion=input("¿Qué deseas configurar?\n1)IPv4\t2)IPv6\n3)VLAN\t4)Delay\n5)Packet Drop\t6)Policer (Rx Bandwidth)\n7)Shaper (Rx Bandwidth)\nPor favor, separa las opciones con comas: ") + opciones=accion.split(',') + configuraciones={} + for opcion in opciones: + opcion=opcion.strip() + if opcion=="1": + source_ip=input("Introduce la IP de origen (IPv4): ") + destination_ip=input("Introduce la IP destino (IPv4): ") + prt=input("¿Qué protocolo quieres usar, IP o TCP? ") + configuraciones['ipv4']=self.ipv4(source_ip,destination_ip,prt) + elif opcion=="2": + source=input("Introduce la IP de origen (IPv6): ") + destination=input("Introduce la IP destino (IPv6): ") + configuraciones['ipv6']=self.ipv6(source, destination) + elif opcion=="3": + vlan_id=int(input("Introduce identificador de VLAN: ")) + configuraciones['vlan']=self.vlan(vlan_id) + elif opcion=="4": + delay_perfil=input("Introduce el delay que quieres introducir en el perfil test_api: ") + configuraciones['ethernetDelay']=self.delay(delay_perfil) + elif opcion=="5": + configuraciones['packetDrop']=self.packetDrop() + elif opcion=="6": + bandwidth=int(input('Introduzca el ancho de banda (Kbps): ')) + configuraciones['policer']=self.policer(bandwidth) + elif opcion=="7": + configuraciones['shaper']=self.shaper() + else: + print(f"Opción '{opcion}' no es válida.") + configuracion_perfil=self.configuracion_total(configuraciones, nombre) + configuraciones_totales.append(configuracion_perfil) + perfil_final = {'profiles': configuraciones_totales} + configuracion_puerto=automatizacion.envio_peticion(ip, puerto, perfil_final) + if configuracion_puerto: + print(configuracion_puerto) + + def existentes(self,ip): + ''' + Inputs: -ip: the ip where the Axia API is located. + Outputs: + Work: Shows the information of a given port- + + ''' + puerto=input("¿Qué puerto quieres consultar?: ") + informacion_puerto=automatizacion.obtener_informacion_puerto(ip, puerto) + if informacion_puerto: + print(informacion_puerto) + + def existentes_auto(self,ip,puerto): + ''' + Inputs: -ip: the ip where the Axia API is located. + - puerto: the port we want to get the information. + Outputs: + Work: Creates and configures the profiles requested in the Axia API on the specified port. + + ''' + informacion_puerto=automatizacion.obtener_informacion_puerto(ip, puerto) + if informacion_puerto: + print(f'info puerto\n{informacion_puerto}') + return informacion_puerto + + ## FUNCION PARA LA GUI DEL NSC ## + + import ipaddress + + def nscNEII(self, json_data): + configuraciones = {} + ip = self.ixia_ip + puerto = "5" + dataProfile = self.existentes_auto(ip, puerto) + + print(f'\n\n{json_data}\n') + + ip_version = json_data.get("ip_version", None) + src_node_ip = json_data.get("src_node_ip", None) + dst_node_ip = json_data.get("dst_node_ip", None) + src_node_ipv6 = json_data.get("src_node_ipv6", None) + dst_node_ipv6 = json_data.get("dst_node_ipv6", None) + vlan_id = json_data.get("vlan_id", None) + bandwidth = json_data.get("bandwidth", None) + latency = json_data.get("latency", None) + latency_version = json_data.get("latency_version", None) + reliability = json_data.get("reliability", None) + tolerance = json_data.get("tolerance", None) + packet_reorder = json_data.get("packet_reorder", None) + num_pack = json_data.get("num_pack", None) + pack_reorder = json_data.get("pack_reorder", None) + num_reorder = json_data.get("num_reorder", None) + max_reorder = json_data.get("max_reorder", None) + drop_version = json_data.get("drop_version", None) + desv_reorder = json_data.get("desv_reorder", None) + packets_drop = json_data.get("packets_drop", None) + drops = json_data.get("drops", None) + desv_drop = json_data.get("desv_drop", None) + + # --- Variables de configuración --- + + # Configuración de IPv4 / IPv6 + if src_node_ip and dst_node_ip: + if isinstance(ipaddress.ip_address(src_node_ip), ipaddress.IPv4Address) and isinstance(ipaddress.ip_address(dst_node_ip), ipaddress.IPv4Address): + configuraciones['ipv4'] = self.ipv4(src_node_ip, dst_node_ip, 5) + if src_node_ipv6 and dst_node_ipv6: + if isinstance(ipaddress.ip_address(src_node_ipv6), ipaddress.IPv6Address) and isinstance(ipaddress.ip_address(dst_node_ipv6), ipaddress.IPv6Address): + configuraciones['ipv6'] = self.ipv6(src_node_ipv6, dst_node_ipv6) + + # VLAN + if vlan_id: + configuraciones['vlan'] = self.vlan(int(vlan_id)) + + # Policer + if bandwidth: + configuraciones['policer'] = self.policer(bandwidth) + + # Latencia + if latency: + if float(latency) > 0: + configuraciones['ethernetDelay'] = self.delay_gui(float(latency), latency_version, float(tolerance)) + + # Packet Reorder + if packet_reorder: + configuraciones['reorder'] = self.packetReorder(num_reorder, pack_reorder, num_pack, max_reorder, packet_reorder, desv_reorder) + + # Packet Reorder when reliability + if reliability: + configuraciones['reorder'] = self.packetReorder(int(reliability)) + + #Dropper + if drop_version: + configuraciones['packetDrop'] = self.packetDrop(drops, packets_drop, drop_version, desv_drop) + + # Agregar perfil + num_profiles = len(dataProfile.get("profiles", [])) + configuracion_perfil = self.configuracion_total(configuraciones, f"profile{num_profiles + 1}") + dataProfile['profiles'].append(configuracion_perfil) + logging.info(f"Configuración del perfil: {configuracion_perfil}") + + # Enviar la configuración + automatizacion.envio_peticion(ip, puerto, dataProfile) + return automatizacion.obtener_informacion_puerto(ip, puerto) + + + ## FUNCIONES DE CONFIGURACIÓN DE PUERTO ## + + def delay(self,delay_perfil): + ''' + Inputs: -delay_perfil: the delay we want to configurate. + Outputs: the information of the delay for the controller. + Work: Creates the configuration JSON for delay of the controller. + + ''' + delay_perfil = input("Enter the delay you want to set in the test_api profile: ") + print(f"delay en main: {delay_perfil}") + delay_type = input("Select one option of stadistics:\n1)None\t2)Gaussian\n3)Internet\n(Type the number)") + configuracion_delay = automatizacion.añadir_configuracion_puerto_delay(delay_perfil,delay_type) + print(f"Config delay:\n{configuracion_delay}") + return configuracion_delay + + def delay_gui(self,delay_perfil, latency_version, max_latency): + ''' + Inputs: -delay_perfil: the delay we want to configurate. + Outputs: the information of the delay for the controller. + Work: Creates the configuration JSON for delay of the controller. + + ''' + print(f'\nPero: {max_latency}\n') + configuracion_delay = automatizacion.añadir_configuracion_puerto_delay(delay_perfil,latency_version,max_latency) + return configuracion_delay + + def ipv4(self,source_ip,destination_ip,prt): + ''' + Inputs: -source_ip: the source IPv4 we want to configurate. + -destination_ip: the destination IPv4 we want to configurate. + -prt: the protocol we want to configurate + Outputs: the information of the IPv4 for the controller. + Work: Creates the configuration JSON for IPv4 of the controller. + Notes: by default, the protocol is TCP (6). + + ''' + source_hx=None + destination_hx=None + protocolo=None + if source_ip: + source_hx=hex(int(ipaddress.IPv4Address(source_ip)))[2:] + if destination_ip: + destination_hx=hex(int(ipaddress.IPv4Address(destination_ip)))[2:] + if prt: + protocolo="4" if prt=="IP" else "6" + configuracion_puerto=automatizacion.añadir_configuracion_puerto_ipv4(source_hx, destination_hx, protocolo) + return configuracion_puerto + + def ipv6(self,source, destination): + ''' + Inputs: -source: the source IPv6 we want to configurate. + -destination: the destination IPv6 we want to configurate. + Outputs: the information of the IPv6 for the controller. + Work: Creates the configuration JSON for IPv6 of the controller. + + ''' + if source: + source=ipaddress.IPv6Address(source).exploded.replace(":", "") + elif not source: source=None + if destination: + destination=ipaddress.IPv6Address(destination).exploded.replace(":", "") + elif not destination: destination=None + configuracion_puerto=automatizacion.añadir_configuracion_puerto_ipv6(source, destination) + return configuracion_puerto + + def vlan(self,vlan_id): + ''' + Inputs: -vlan_id: the VLAN we want to configurate. + Outputs: the information of the VLAN for the controller. + Work: Creates the configuration JSON for VLAN of the controller. + + ''' + configuracion_vlan=automatizacion.añadir_configuracion_VLAN(vlan_id) + return configuracion_vlan + + def packetDrop(self, drop, total,version,dev): + ''' + Inputs: + Outputs: the information of the packet drop configuration for the controller. + Work: Creates the configuration JSON for packet drop of the controller. + + ''' + configuracionPD=automatizacion.añadir_configuración_packetDrop(drop,total,version,dev) + return configuracionPD + + def policer(self,bandwidth): + ''' + Inputs: -bandwidth: the TX bandwdth we want to configurate. + Outputs: the information of the TX bandwidth for the controller. + Work: Creates the configuration JSON for the TX bandwidth of the controller. + + ''' + configuracion_policer=automatizacion.añadir_configuracion_policer(bandwidth) + return configuracion_policer + + def shaper(self): + ''' + Inputs: + Outputs: the information of the RX bandwidth for the controller. + Work: Creates the configuration JSON for the RX bandwidth of the controller. + + ''' + bandwidth=int(input('Introduzca el ancho de banda (Kbps): ')) + configuracion_policer=automatizacion.añadir_configuracion_shaper(bandwidth) + return configuracion_policer + + def packetReorder(self,reorder,packages=None, npackagesreorder=None, maxreord=None, version=None, stev=None): + print(f"\n\n\nNEII ANTES DEL PASO\nPACKAGES:{packages}\nREORDER:{reorder}\nMAXREORD:{maxreord}\nNPACKAGESORDER:{npackagesreorder}\n\n\n") + configuracion_reorder=automatizacion.añadir_configuracion_reorder(packages,reorder,npackagesreorder, maxreord, version, stev) + return configuracion_reorder + + def configuracion_total(self,configuraciones, nombre_perfil): + ''' + Inputs: -configuraciones: the informtion of all the configurations for the controller. + -nombre_perfil: the name of the profile where the information is going to be allocated. + Outputs: the information of a configurated profile. + Work: Creates the configuration JSON for a profile for the controller. + + ''' + perfil = { + 'tag': nombre_perfil, + 'dramAllocation': {}, + 'rules': [], + 'ethernetDelay': {'enabled': False}, + 'packetDrop': {'enabled': False}, + 'enabled':True + } + if 'ipv4' in configuraciones: + ipv4_config = configuraciones['ipv4'] + perfil['dramAllocation'] = ipv4_config['profiles'][0]['dramAllocation'] + perfil['rules'].extend(ipv4_config['profiles'][0]['rules']) + if 'ipv6' in configuraciones: + ipv6_config = configuraciones['ipv6'] + perfil['rules'].extend(ipv6_config['profiles'][0]['rules']) + if 'vlan' in configuraciones: + vlan_config = configuraciones['vlan'] + perfil['rules'].extend(vlan_config['profiles'][0]['rules']) + if 'ethernetDelay' in configuraciones: + perfil['ethernetDelay'] = configuraciones['ethernetDelay']['ethernetDelay'] + if 'packetDrop' in configuraciones: + perfil['packetDrop'] = configuraciones['packetDrop']['packetDrop'] + if 'policer' in configuraciones: + perfil['policer']=configuraciones['policer']['policer'] + if 'shaper' in configuraciones: + perfil['shaper']=configuraciones['shaper']['shaper'] + if 'reorder' in configuraciones: + perfil['reorder']=configuraciones['reorder']['reorder'] + return perfil + +if __name__=="__main__": + controller=NEII_controller() + controller.menu_principal() \ No newline at end of file diff --git a/src/realizers/ixia/automatizacion_ne2v4.py b/src/realizers/ixia/automatizacion_ne2v4.py new file mode 100644 index 0000000000000000000000000000000000000000..fd8fc4f5c7b5f093fc60963687d8564001eb224d --- /dev/null +++ b/src/realizers/ixia/automatizacion_ne2v4.py @@ -0,0 +1,467 @@ +# 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. + +# This file is an original contribution from Telefonica Innovación Digital S.L. + +import requests +class automatizacion: + def obtener_informacion_ip(ip): + ''' + Gets the information IP of the NE2 + Args: + ip: IP. + Returns: + A dictionary with the IP infotmationx. + ''' + url= "http://"+ip+"/api/actions/ipInfo" + body= {"ip": ip} + response = requests.get(url, json=body, auth=('admin', 'admin')) + if response.status_code==200: + return response.json() + else: + print(f"error al obtener la informacion de la IP; {response.status_code}") + return None + + def obtener_informacion_hardware(ip): + """ + Obtiene información de una dirección IP. + + Args: + ip: La dirección IP del NE2. + + Returns: + Un diccionario con la información de IP. + """ + url = "http://"+ip+"/api/actions/hwInfo" + body = {"ip": ip} + response = requests.get(url, json=body, auth=('admin', 'admin')) + if response.status_code == 200: + return response.json() + else: + print(f"Error al obtener la información de la IP: {response.status_code}") + return None + + def obtener_informacion_puerto(ip,puerto): + """ + Obtiene información de una dirección IP. + + Args: + ip: La dirección IP del NE2. + + Returns: + Un diccionario con la información de IP. + """ + url = "http://"+ip+"/api/hw/Port/"+puerto + body = {"ip": ip} + response = requests.get(url, json=body, auth=('admin', 'admin')) + if response.status_code == 200: + return response.json() + else: + print(f"Error al obtener la información de la IP: {response.status_code}") + return None + + def añadir_configuracion_puerto_delay(delay, latency_type, max_latency): + """ + Añade una configuración de puerto según su delay a un NE2. + + Args: + delay (int): Cantidad de delay en la simulación. + + Returns: + La respuesta de la API (texto). + """ + configuracion=None + print(f'\n\nTipo de latencia: {latency_type}\n latencia: {delay}\n') + if latency_type=='1' or latency_type==None: + configuracion={'ethernetDelay': {'delay': delay, 'delayMax': 15.0, 'isUncorrelated': False, 'maxNegDelta': 0.1, 'pdvMode': 'NONE', 'delayMin': 5.0, 'units': 'MS', 'maxPosDelta': 0.1, 'enabled': True, 'spread': 1.0}} + if latency_type=='2' or latency_type=='gauss': + delay_f=float(delay) + ancho=float(max_latency) + max_delay=delay_f+ancho + min_delay=delay_f-ancho + configuracion={'ethernetDelay': {'delay': delay, 'delayMax': max_delay, 'isUncorrelated': False,'maxNegDelta': ancho/3, 'pdvMode': 'GAUSSIAN', 'delayMin':min_delay, 'units': 'MS', 'maxPosDelta':ancho/3, 'enabled': True, 'spread': 1.58}} + if latency_type =='3' or latency_type=='internet': + ancho=float(max_latency) + max_delay = float(delay)+0.9*float(ancho) + min_delay = float(delay)-0.1*float(ancho) + configuracion={'ethernetDelay': {'delay': delay, 'delayMax': max_delay, 'isUncorrelated': False, 'maxNegDelta': 0.4, 'pdvMode': 'INTERNET', 'delayMin': min_delay, 'units': 'MS', 'maxPosDelta': 0.5, 'enabled': True, 'spread': 100.0}} + print(f"\n\nConf Delay: {configuracion}\n") + return configuracion + + def añadir_configuracion_puerto_ipv4(source_hx,destination_hx,protocolo): + """ + Añade una configuración de puerto según las IPv4s de origen y destino de la comunicación. + + Args: + source_hx (int): Dirección IPv4 de origen en hexadecimal. + destination_hx (int): Dirección IPv4 de destino en hexadecimal. + protocolo (string): Numero asociado al protocolo elegido. + + Returns: + La respuesta de la API (texto). + """ + reglas = [{"field": "Common::IPv4::Version", "value": "4", "mask": "f"}] + if source_hx: + reglas.append({"field": "Common::IPv4::Source Address", "value": source_hx, "mask": "ffffffff"}) + if destination_hx: + reglas.append({"field": "Common::IPv4::Destination Address", "value": destination_hx, "mask": "ffffffff"}) + if protocolo: + reglas.append({"field": "Common::IPv4::Protocol", "value": protocolo, "mask": "ff"}) + configuracion = {"profiles": [{"dramAllocation": {"mode": "AUTO","fixedSize": 1700352},"rules": reglas,"tag": "test_api"}],"defaultProfile": {"dramAllocation": {"mode": "AUTO","fixedSize": 1700352},"tag": "defaultProfile"}} + return configuracion + + def añadir_configuracion_puerto_ipv6(source,destination): + """ + Añade una configuración de puerto según las IPv6s de origen y destino de la comunicación. + + Args: + source (int): Dirección IPv6 de origen en hexadecimal. + destination (int): Dirección IPv6 de destino en hexadecimal. + + Returns: + La respuesta de la API (texto). + """ + reglas=[{'field': 'Common::IPv6::Version', 'bitRange': 'L3@0[7]+3', 'value': '6', 'mask': 'f'}] + if source: + reglas.append({'field': 'Common::IPv6::Source Address', 'bitRange': 'L3@8[7]+127', 'value': source, 'mask': 'ffffffffffffffffffffffffffffffff'}) + if destination: + reglas.append({'field': 'Common::IPv6::Destination Address', 'bitRange': 'L3@24[7]+127', 'value': destination, 'mask': 'ffffffffffffffffffffffffffffffff'}) + configuracion = {"profiles": [{"dramAllocation": {"mode": "AUTO","fixedSize": 1700352},"rules": reglas,"tag": "test_api"}],"defaultProfile": {"dramAllocation": {"mode": "AUTO","fixedSize": 1700352},"tag": "defaultProfile"}} + return configuracion + + def añadir_configuracion_VLAN(vlan): + """ + Añade una configuración de puerto según su VLAN. + + Args: + vlan (int): Número de identificación de la VLAN. + + Returns: + La respuesta de la API (texto). + """ + vlan=hex(vlan)[2:] + configuracion={'profiles': [{'dramAllocation': {'mode': 'AUTO', 'fixedSize': 1700352}, 'rules': [{'field': 'Common::Second Tag::VLAN ID', 'bitRange': 'L2@18[3]+11', 'value': vlan, 'mask': 'fff'}]}]} + return configuracion + + def añadir_configuración_packetDrop(drops,total): + """ + Añade una configuración de puerto según su configuracion de packet Drop un NE2. + + Args: + drops (int): cantidad de paquetes dropeados + total (int): cantidad total de paquetes + + Returns: + La respuesta de la API (texto). + """ + configuracion={'packetDrop': {'rdmSel': {'dist': 'PERIODIC', 'burstlen': drops, 'interval': total, 'stddev': 10.0}, 'enabled': True}} + return configuracion + + def añadir_configuracion_policer(bitrate): + """ + Añade una configuración de puerto según su TX bandwidth a un NE2. + + Args: + bitrate (int): bandwith en Tx + + Returns: + La respuesta de la API (texto). + """ + configuracion={'policer':{'excessBitRate': bitrate, 'excessBurstTolerance': 64000, 'commitedBurstTolerance': 64000, 'commitedBitRate': bitrate, 'enabled': True, 'enableRateCoupling': False}} + return configuracion + + def añadir_configuracion_shaper(bitrate): + """ + Añade una configuración de puerto según su RX bandwidth a un NE2. + + Args: + bitrate (int): bandwith en Rx + + Returns: + La respuesta de la API (texto). + """ + configuracion={'shaper': {'burstTolerance': 64000, 'bitRate': bitrate, 'enabled': True}} + return configuracion + + def añadir_configuracion_reorder(reorder): + """ + Adds reorder configuration. + + Args: + reorder (int): reorder + + Returns: + response of the API (texto). + """ + reorder=100-reorder + print(f"\nReorder:{reorder}\n") + configuracion={"reorder": {"rdmSel": {"dist": "PERIODIC", "burstlen": reorder, "interval": 100, "stddev": 10.0 }, "reorderByMin": 1, "reorderByMax": 5, "enabled": True}} #Los demas valores los he dejado como defecto por no poder configurarlos + return configuracion + + def envio_peticion(ip,puerto, configuracion): + """ + Envía una configuración de puerto a un NE2. + + Args: + ip (int): IP del NE2 + puerto: número del puerto a configurar + configuración: la información que se quiere configurar en el puerto + + Returns: + La respuesta de la API (texto). + """ + +import requests +class automatizacion: + def obtener_informacion_ip(ip): + ''' + obtiene informacion ip del NE2 + Args: + ip: la direccion IP del NE2. + + Returns: + un diccionario con la informacion de IP. + ''' + url= "http://"+ip+"/api/actions/ipInfo" + body= {"ip": ip} + response = requests.get(url, json=body, auth=('admin', 'admin')) + if response.status_code==200: + return response.json() + else: + print(f"error al obtener la informacion de la IP; {response.status_code}") + return None + + def obtener_informacion_hardware(ip): + """ + Obtiene información de una dirección IP. + + Args: + ip: La dirección IP del NE2. + + Returns: + Un diccionario con la información de IP. + """ + url = "http://"+ip+"/api/actions/hwInfo" + body = {"ip": ip} + response = requests.get(url, json=body, auth=('admin', 'admin')) + if response.status_code == 200: + return response.json() + else: + print(f"Error al obtener la información de la IP: {response.status_code}") + return None + + def obtener_informacion_puerto(ip,puerto): + """ + Obtiene información de una dirección IP. + + Args: + ip: La dirección IP del NE2. + + Returns: + Un diccionario con la información de IP. + """ + url = "http://"+ip+"/api/hw/Port/"+puerto + body = {"ip": ip} + response = requests.get(url, json=body, auth=('admin', 'admin')) + if response.status_code == 200: + return response.json() + else: + print(f"Error al obtener la información de la IP: {response.status_code}") + return None + + def añadir_configuracion_puerto_delay(delay, latency_type, max_latency): + """ + Añade una configuración de puerto según su delay a un NE2. + + Args: + delay (int): Cantidad de delay en la simulación. + + Returns: + La respuesta de la API (texto). + """ + configuracion=None + print(f'\n\nTipo de latencia: {latency_type}\n latencia: {delay}\n') + if latency_type=='1' or latency_type==None: + configuracion={'ethernetDelay': {'delay': delay, 'delayMax': 15.0, 'isUncorrelated': False, 'maxNegDelta': 0.1, 'pdvMode': 'NONE', 'delayMin': 5.0, 'units': 'MS', 'maxPosDelta': 0.1, 'enabled': True, 'spread': 1.0}} + if latency_type=='2' or latency_type=='gauss': + delay_f=float(delay) + ancho=float(max_latency) + max_delay=delay_f+ancho + min_delay=delay_f-ancho + configuracion={'ethernetDelay': {'delay': delay, 'delayMax': max_delay, 'isUncorrelated': False,'maxNegDelta': ancho/3, 'pdvMode': 'GAUSSIAN', 'delayMin':min_delay, 'units': 'MS', 'maxPosDelta':ancho/3, 'enabled': True, 'spread': 1.58}} + if latency_type =='3' or latency_type=='internet': + ancho=float(max_latency) + max_delay = float(delay)+0.9*float(ancho) + min_delay = float(delay)-0.1*float(ancho) + configuracion={'ethernetDelay': {'delay': delay, 'delayMax': max_delay, 'isUncorrelated': False, 'maxNegDelta': 0.4, 'pdvMode': 'INTERNET', 'delayMin': min_delay, 'units': 'MS', 'maxPosDelta': 0.5, 'enabled': True, 'spread': 100.0}} + print(f"\n\nConf Delay: {configuracion}\n") + return configuracion + + def añadir_configuracion_puerto_ipv4(source_hx,destination_hx,protocolo): + """ + Añade una configuración de puerto según las IPv4s de origen y destino de la comunicación. + + Args: + source_hx (int): Dirección IPv4 de origen en hexadecimal. + destination_hx (int): Dirección IPv4 de destino en hexadecimal. + protocolo (string): Numero asociado al protocolo elegido. + + Returns: + La respuesta de la API (texto). + """ + reglas = [{"field": "Common::IPv4::Version", "value": "4", "mask": "f"}] + if source_hx: + reglas.append({"field": "Common::IPv4::Source Address", "value": source_hx, "mask": "ffffffff"}) + if destination_hx: + reglas.append({"field": "Common::IPv4::Destination Address", "value": destination_hx, "mask": "ffffffff"}) + if protocolo: + reglas.append({"field": "Common::IPv4::Protocol", "value": protocolo, "mask": "ff"}) + configuracion = {"profiles": [{"dramAllocation": {"mode": "AUTO","fixedSize": 1700352},"rules": reglas,"tag": "test_api"}],"defaultProfile": {"dramAllocation": {"mode": "AUTO","fixedSize": 1700352},"tag": "defaultProfile"}} + return configuracion + + def añadir_configuracion_puerto_ipv6(source,destination): + """ + Añade una configuración de puerto según las IPv6s de origen y destino de la comunicación. + + Args: + source (int): Dirección IPv6 de origen en hexadecimal. + destination (int): Dirección IPv6 de destino en hexadecimal. + + Returns: + La respuesta de la API (texto). + """ + reglas=[{'field': 'Common::IPv6::Version', 'bitRange': 'L3@0[7]+3', 'value': '6', 'mask': 'f'}] + if source: + reglas.append({'field': 'Common::IPv6::Source Address', 'bitRange': 'L3@8[7]+127', 'value': source, 'mask': 'ffffffffffffffffffffffffffffffff'}) + if destination: + reglas.append({'field': 'Common::IPv6::Destination Address', 'bitRange': 'L3@24[7]+127', 'value': destination, 'mask': 'ffffffffffffffffffffffffffffffff'}) + configuracion = {"profiles": [{"dramAllocation": {"mode": "AUTO","fixedSize": 1700352},"rules": reglas,"tag": "test_api"}],"defaultProfile": {"dramAllocation": {"mode": "AUTO","fixedSize": 1700352},"tag": "defaultProfile"}} + return configuracion + + def añadir_configuracion_VLAN(vlan): + """ + Añade una configuración de puerto según su VLAN. + + Args: + vlan (int): Número de identificación de la VLAN. + + Returns: + La respuesta de la API (texto). + """ + vlan=hex(vlan)[2:] + configuracion={'profiles': [{'dramAllocation': {'mode': 'AUTO', 'fixedSize': 1700352}, 'rules': [{'field': 'Common::Second Tag::VLAN ID', 'bitRange': 'L2@18[3]+11', 'value': vlan, 'mask': 'fff'}]}]} + return configuracion + + def añadir_configuración_packetDrop(drops,total,version,desv): + """ + Añade una configuración de puerto según su configuracion de packet Drop un NE2. + + Args: + drops (int): cantidad de paquetes dropeados + total (int): cantidad total de paquetes + version (string): version of the probability + + Returns: + La respuesta de la API (texto). + """ + if version != "GAUSSIAN" and version !="POISSON": + configuracion={'packetDrop': {'rdmSel': {'dist': version, 'burstlen': drops, 'interval': total, 'stddev': 10.0}, 'enabled': True}} + else: + configuracion={'packetDrop': {'rdmSel': {'dist': version, 'burstlen': drops, 'interval': total, 'stddev': desv}, 'enabled': True}} + return configuracion + + def añadir_configuracion_policer(bitrate): + """ + Añade una configuración de puerto según su TX bandwidth a un NE2. + + Args: + bitrate (int): bandwith en Tx + + Returns: + La respuesta de la API (texto). + """ + configuracion={'policer':{'excessBitRate': bitrate, 'excessBurstTolerance': 64000, 'commitedBurstTolerance': 64000, 'commitedBitRate': bitrate, 'enabled': True, 'enableRateCoupling': False}} + return configuracion + + def añadir_configuracion_shaper(bitrate): + """ + Añade una configuración de puerto según su RX bandwidth a un NE2. + + Args: + bitrate (int): bandwith en Rx + + Returns: + La respuesta de la API (texto). + """ + configuracion={'shaper': {'burstTolerance': 64000, 'bitRate': bitrate, 'enabled': True}} + return configuracion + + def añadir_configuracion_reorder(packages,reorder,npackagesreorder, maxreord, version, stev): + """ + Adds reorder configuration. + + Args: + packages: number of packages total + reorder: number of packages to reorder + npackagesreorder: number of packages of reorder + maxreord: total number of packages of reorder + version: version of reorder + stev: desviation + + Returns: + response of the API (text). + """ + if packages is not None and npackagesreorder is not None and maxreord is not None: + reorderByMin = min(npackagesreorder, maxreord) + reorderByMax = max(npackagesreorder, maxreord) + if version != 'GAUSSIAN': + configuracion={"reorder": {"rdmSel": {"dist": version, "burstlen": reorder, "interval": packages, "stddev": 10.0 }, "reorderByMin": reorderByMin, "reorderByMax": reorderByMax, "enabled": True}} + else: + configuracion={"reorder": {"rdmSel": {"dist": "GAUSSIAN", "burstlen": reorder, "interval": packages, "stddev": stev }, "reorderByMin": reorderByMin, "reorderByMax": reorderByMax, "enabled": True}} + if int(reorder) <= 0: + configuracion["filterWarning"] = "El valor de reorder es inválido, está fuera del rango permitido." + else: + reorder=10000-reorder + configuracion={"reorder": {"rdmSel": {"dist": "PERIODIC", "burstlen": int(reorder/100), "interval": 100, "stddev": 10.0 }, "reorderByMin": 1, "reorderByMax": 5, "enabled": True}} + return configuracion + + def envio_peticion(ip,puerto, configuracion): + """ + Envía una configuración de puerto a un NE2. + + Args: + ip (int): IP del NE2 + puerto: número del puerto a configurar + configuración: la información que se quiere configurar en el puerto + + Returns: + La respuesta de la API (texto). + """ + print(f'\nCONFIGURACION\n{configuracion}') + url = f"http://{ip}/api/hw/Port/{puerto}" + response = requests.put(url, json=configuracion, auth=('admin', 'admin')) + + if response.status_code == 200: + print(f'\n{configuracion}') + return response.text + else: + try: + error_info = response.json() + except ValueError: + error_info = response.text + + print(f"\n\nError al añadir configuración de puerto: {response.status_code}") + print(f"Mensaje de error: {error_info}") + print(f"Configuración enviada: {configuracion}\n\n") + return None \ No newline at end of file diff --git a/src/templates/3gpp_template_example.json b/src/templates/3gpp_template_example.json deleted file mode 100644 index 28471a8b2026b00c6d60222e8a9943290c6bc45a..0000000000000000000000000000000000000000 --- a/src/templates/3gpp_template_example.json +++ /dev/null @@ -1,187 +0,0 @@ -{ - "NetworkSlice1": { - "operationalState": "", - "administrativeState": "", - "serviceProfileList": [], - "networkSliceSubnetRef": "TopSliceSubnet1" - }, - "TopSliceSubnet1": { - "operationalState": "", - "administrativeState": "", - "nsInfo": {}, - "managedFunctionRef": [], - "networkSliceSubnetType": "TOP_SLICESUBNET", - "SliceProfileList": [ - { - "sliceProfileId": "TopId", - "pLMNInfoList": null, - "TopSliceSubnetProfile": { - "dLThptPerSliceSubnet": { - "GuaThpt": 200, - "MaxThpt": 400 - }, - "uLThptPerSliceSubnet": { - "GuaThpt": 200, - "MaxThpt": 400 - }, - "dLLatency": 20, - "uLLatency": 20 - } - } - ], - "networkSliceSubnetRef": [ - "CNSliceSubnet1", - "RANSliceSubnet1" - ] - }, - "CNSliceSubnet1": { - "operationalState": "", - "administrativeState": "", - "nsInfo": {}, - "managedFunctionRef": [], - "networkSliceSubnetType": "CN_SLICESUBNET", - "SliceProfileList": [ - { - "sliceProfileId": "CNId", - "pLMNInfoList": null, - "CNSliceSubnetProfile": { - "dLThptPerSliceSubnet": { - "GuaThpt": 100, - "MaxThpt": 200 - }, - "uLThptPerSliceSubnet": { - "GuaThpt": 100, - "MaxThpt": 200 - }, - "dLLatency": 8, - "uLLatency": 8 - } - } - ] - }, - "RANSliceSubnet1": { - "operationalState": "", - "administrativeState": "", - "nsInfo": {}, - "managedFunctionRef": [], - "networkSliceSubnetType": "RAN_SLICESUBNET", - "SliceProfileList": [ - { - "sliceProfileId": "RANId", - "pLMNInfoList": null, - "RANSliceSubnetProfile": { - "dLThptPerSliceSubnet": { - "GuaThpt": 100, - "MaxThpt": 200 - }, - "uLThptPerSliceSubnet": { - "GuaThpt": 100, - "MaxThpt": 200 - }, - "dLLatency": 12, - "uLLatency": 12 - } - } - ], - "networkSliceSubnetRef": [ - "MidhaulSliceSubnet1", - "BackhaulSliceSubnet1" - ] - }, - "MidhaulSliceSubnet1": { - "operationalState": "", - "administrativeState": "", - "nsInfo": {}, - "managedFunctionRef": [], - "networkSliceSubnetType": "RAN_SLICESUBNET", - "SliceProfileList": [ - { - "sliceProfileId": "MidhaulId", - "pLMNInfoList": null, - "RANSliceSubnetProfile": { - "dLThptPerSliceSubnet": { - "GuaThpt": 60, - "MaxThpt": 120 - }, - "uLThptPerSliceSubnet": { - "GuaThpt": 60, - "MaxThpt": 120 - }, - "dLLatency": 4, - "uLLatency": 4 - } - } - ], - "EpTransport": [ - "EpTransport CU-UP1", - "EpTransport DU3" - ] - }, - "BackhaulSliceSubnet1": { - "operationalState": "", - "administrativeState": "", - "nsInfo": {}, - "managedFunctionRef": [], - "networkSliceSubnetType": "RAN_SLICESUBNET", - "SliceProfileList": [ - { - "sliceProfileId": "BackhaulId", - "pLMNInfoList": null, - "RANSliceSubnetProfile": { - "dLThptPerSliceSubnet": { - "GuaThpt": 40, - "MaxThpt": 80 - }, - "uLThptPerSliceSubnet": { - "GuaThpt": 40, - "MaxThpt": 80 - }, - "dLLatency": 8, - "uLLatency": 8 - } - } - ], - "EpTransport": [ - "EpTransport CU-UP2", - "EpTransport UPF" - ] - }, - "EpTransport CU-UP1": { - "IpAddress": "100.1.1.1", - "logicalInterfaceInfo": { - "logicalInterfaceType": "VLAN", - "logicalInterfaceId": "300" - }, - "NextHopInfo": "100.1.1.254", - "qosProfile": "5QI100", - "EpApplicationRef": [ - "EP_F1U CU-UP1" - ] - }, - "EP_F1U CU-UP1": { - "localAddress": "100.1.1.2", - "remoteAddress": "1.1.3.2", - "epTransportRef": [ - "EpTransport CU-UP1" - ] - }, - "EpTransport DU3": { - "IpAddress": "1.1.3.1", - "logicalInterfaceInfo": { - "logicalInterfaceType": "VLAN", - "logicalInterfaceId": "300" - }, - "NextHopInfo": "1.1.3.254", - "qosProfile": "5QI100", - "EpApplicationRef": [ - "EP_F1U DU3" - ] - }, - "EP_F1U DU3": { - "localAddress": "1.1.3.2", - "remoteAddress": "100.1.1.2", - "epTransportRef": [ - "EpTransport DU3" - ] - } -} \ No newline at end of file diff --git a/src/templates/3gpp_template_filled.json b/src/templates/3gpp_template_filled.json deleted file mode 100644 index dcab03aa3d095fd133fbddbac12c3621ddb481ee..0000000000000000000000000000000000000000 --- a/src/templates/3gpp_template_filled.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "NetworkSlice1":{ - "operationalState":"", - "administrativeState":"", - "serviceProfileList":[ // Requisitos generales de una NetworkSlice. Lo suponemos vacío. The attributes in ServiceProfile represent mapped requirements from an Network Slice Customer (e.g. an enterprise) to an Network Slice Provider - //{ - // "serviceProfileId":"", - // "pLMNInfoList": null, //It defines which PLMN and S-NSSAI combinations that are assigned for the service to satisfy service requirements represented by the ServiceProfile - // "sST":"2" // 1 (eMBB), 2(URLLC), 3(MIoT), 4(V2X) o 5(HMTC) - //} - ], - "networkSliceSubnetRef":"TopSliceSubnet1" //Es un DN (string) - }, - "TopSliceSubnet1":{ - "operationalState":"", - "administrativeState":"", - "nsInfo":{}, // Se usa si la slice está en un entorno virtualizado - "managedFunctionRef":[], // ??? Es un DNList (array de strings) - "networkSliceSubnetType":"TOP_SLICESUBNET", - "SliceProfileList":[ // Requisitos de una NetworkSliceSubnet, la cual representa un conjunto de funciones de red agrupadas. - { - "sliceProfileId":"TopId", - "pLMNInfoList":null, - "TopSliceSubnetProfile":{ //Condition: It shall be present when the slice profile is for top/root network slice subnet - "dLThptPerSliceSubnet":{ //kbps - "GuaThpt":1000, - "MaxThpt":2000 - }, - "uLThptPerSliceSubnet":{ - "GuaThpt":1000, - "MaxThpt":2000 - }, - "dLLatency":5, //ms - "uLLatency":5 - } - } - ], - "networkSliceSubnetRef":["CNSliceSubnet1","RANSliceSubnet1"] - }, - "CNSliceSubnet1":{ - "operationalState":"", - "administrativeState":"", - "nsInfo":{}, // Se usa si la slice está en un entorno virtualizado - "managedFunctionRef":[], // ??? Es un DNList (array de strings) - "networkSliceSubnetType":"CN_SLICESUBNET", - "SliceProfileList":[ // Requisitos de una NetworkSliceSubnet, la cual representa un conjunto de funciones de red agrupadas. Los requisitos de transporte se representan aquí - { - "sliceProfileId":"CNId", - "pLMNInfoList":null, - "CNSliceSubnetProfile":{ - "dLThptPerSliceSubnet":{ - "GuaThpt":500, - "MaxThpt":1000 - }, - "uLThptPerSliceSubnet":{ - "GuaThpt":500, - "MaxThpt":1000 - }, - "dLLatency":2, - "uLLatency":2 - } - } - ] - }, - "RANSliceSubnet1":{ - "operationalState":"", - "administrativeState":"", - "nsInfo":{}, // Se usa si la slice está en un entorno virtualizado - "managedFunctionRef":[], // ??? Es un DNList (array de strings) - "networkSliceSubnetType":"RAN_SLICESUBNET", - "SliceProfileList":[ // Requisitos de una NetworkSliceSubnet, la cual representa un conjunto de funciones de red agrupadas. Los requisitos de transporte se representan aquí - { - "sliceProfileId":"RANId", - "pLMNInfoList":null, - "RANSliceSubnetProfile":{ - "dLThptPerSliceSubnet":{ - "GuaThpt":500, - "MaxThpt":1000 - }, - "uLThptPerSliceSubnet":{ - "GuaThpt":500, - "MaxThpt":1000 - }, - "dLLatency":3, - "uLLatency":3 - } - } - ], - "networkSliceSubnetRef":["MidhaulSliceSubnet1", "BackhaulSliceSubnet1"] - }, - "MidhaulSliceSubnet1":{ - "operationalState":"", - "administrativeState":"", - "nsInfo":{}, // Se usa si la slice está en un entorno virtualizado - "managedFunctionRef":[], // ??? Es un DNList (array de strings), - "networkSliceSubnetType":"RAN_SLICESUBNET", - "SliceProfileList":[ // Requisitos de una NetworkSliceSubnet, la cual representa un conjunto de funciones de red agrupadas. Los requisitos de transporte se representan aquí - { - "sliceProfileId":"MidhaulId", - "pLMNInfoList":null, - "RANSliceSubnetProfile":{ - "dLThptPerSliceSubnet":{ - "GuaThpt":300, - "MaxThpt":600 - }, - "uLThptPerSliceSubnet":{ - "GuaThpt":300, - "MaxThpt":600 - }, - "dLLatency":1, - "uLLatency":1 - } - } - ], - "EpTransport":["EpTransport DU1","EpTransport CU-UP1"] // Es un DNList (array de strings) - }, - "BackhaulSliceSubnet1":{ - "operationalState":"", - "administrativeState":"", - "nsInfo":{}, // Se usa si la slice está en un entorno virtualizado - "managedFunctionRef":[], // ??? Es un DNList (array de strings), - "networkSliceSubnetType":"RAN_SLICESUBNET", - "SliceProfileList":[ // Requisitos de una NetworkSliceSubnet, la cual representa un conjunto de funciones de red agrupadas. Los requisitos de transporte se representan aquí - { - "sliceProfileId":"BackhaulId", - "pLMNInfoList":null, - "RANSliceSubnetProfile":{ - "dLThptPerSliceSubnet":{ - "GuaThpt":200, - "MaxThpt":400 - }, - "uLThptPerSliceSubnet":{ - "GuaThpt":200, - "MaxThpt":400 - }, - "dLLatency":2, - "uLLatency":2 - } - } - ], - "EpTransport":["EpTransport CU-UP2","EpTransport UPF"] // Es un DNList (array de strings) - }, - "EpTransport DU1": - { - "IpAddress":"100.1.1.1", - "logicalInterfaceInfo":{ - "logicalInterfaceType":"VLAN", //VLAN, MPLS o Segment - "logicalInterfaceId":"100" - }, - "NextHopInfo": "100.1.1.254", - "qosProfile":"5QI100", //Revisar el mapeo de los requisitos de la slice con esto - "EpApplicationRef":["EP_F1U DU1"] //Es un DNList (array de string) - }, - "EpTransport CU-UP1": - { - "IpAddress":"1.1.1.1", - "logicalInterfaceInfo":{ - "logicalInterfaceType":"VLAN", //VLAN, MPLS o Segment - "logicalInterfaceId":"100" - }, - "NextHopInfo": "1.1.1.254", - "QosProfile":"5QI100", - "EpApplicationRef":["EP_F1U CU-UP1"] //Es un DNList (array de string) - }, - "EP_F1U DU1":[ // El 3GPP parece que aun no ha definido las interfaces entre los distinos functional splits, por lo que estos objetos no están claros. Suponemos EP_F1U para todo, que es el que se usa para la interfaz F1-U entre gNB-DU y gNB-CU - { - "localAddress":"100.1.1.2", - "remoteAddress":"1.1.1.2", - "epTransportRef":["EpTransport DU1"] //Es un DNList (array de string) - } - ], - "EP_F1U CU-UP1":[ //Otras opciones son EP_N3 (interfaz N3 entre RAN y UPF) y EP_NgU (interfaz NG-U entre gNB y UPF) - { - "localAddress":"1.1.1.2", - "remoteAddress":"100.1.1.2", - "epTransportRef":["EpTransport CU-UP1"] //Es un DNList (array de string) - } - ] -} - - - diff --git a/src/templates/L2-VPN_template_empty.json b/src/templates/L2-VPN_template_empty.json index 85caed08d492bff56396c2e2e87b5098dee84209..9c2137c7c72479792e0c3608e6781e521f33550d 100644 --- a/src/templates/L2-VPN_template_empty.json +++ b/src/templates/L2-VPN_template_empty.json @@ -12,8 +12,6 @@ {"device_id": {"device_uuid": {"uuid": ""}}, "endpoint_uuid": {"uuid": "eth-1/0/21"}} ], "service_constraints": [ - {"custom": {"constraint_type": "bandwidth[kbps]", "constraint_value": "0"}}, - {"custom": {"constraint_type": "latency[ms]", "constraint_value": "0"}} ], "service_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "/settings", "resource_value": { diff --git a/src/templates/L2-VPN_template_example.json b/src/templates/L2-VPN_template_example.json deleted file mode 100644 index b29e3c69911c332fa5bac045f0f2b994008d629f..0000000000000000000000000000000000000000 --- a/src/templates/L2-VPN_template_example.json +++ /dev/null @@ -1,271 +0,0 @@ -{ - "services": [ - { - "service_id": { - "context_id": { - "context_uuid": { - "uuid": "admin" - } - }, - "service_uuid": { - "uuid": "l2-acl-svc-17429923732568250" - } - }, - "service_type": 2, - "service_status": { - "service_status": 1 - }, - "service_endpoint_ids": [ - { - "device_id": { - "device_uuid": { - "uuid": "4.4.4.4" - } - }, - "endpoint_uuid": { - "uuid": "0/0/0-GigabitEthernet0/0/0/0" - } - }, - { - "device_id": { - "device_uuid": { - "uuid": "5.5.5.5" - } - }, - "endpoint_uuid": { - "uuid": "0/0/3-GigabitEthernet0/0/0/3" - } - } - ], - "service_constraints": [ - { - "custom": { - "constraint_type": "bandwidth[kbps]", - "constraint_value": "20" - } - }, - { - "custom": { - "constraint_type": "latency[ms]", - "constraint_value": "20" - } - } - ], - "service_config": { - "config_rules": [ - { - "action": 1, - "custom": { - "resource_key": "/settings", - "resource_value": {} - } - }, - { - "action": 1, - "custom": { - "resource_key": "/device[4.4.4.4]/endpoint[0/0/0-GigabitEthernet0/0/0/0]/settings", - "resource_value": { - "sub_interface_index": 0, - "vlan_id": 100, - "circuit_id": "100", - "remote_router": "5.5.5.5", - "ni_name": "ELAN100" - } - } - }, - { - "action": 1, - "custom": { - "resource_key": "/device[5.5.5.5]/endpoint[0/0/3-GigabitEthernet0/0/0/3]/settings", - "resource_value": { - "sub_interface_index": 0, - "vlan_id": 100, - "circuit_id": "100", - "remote_router": "4.4.4.4", - "ni_name": "ELAN100" - } - } - } - ] - } - }, - { - "service_id": { - "context_id": { - "context_uuid": { - "uuid": "admin" - } - }, - "service_uuid": { - "uuid": "l2-acl-svc-17429923733224160" - } - }, - "service_type": 2, - "service_status": { - "service_status": 1 - }, - "service_endpoint_ids": [ - { - "device_id": { - "device_uuid": { - "uuid": "4.4.4.4" - } - }, - "endpoint_uuid": { - "uuid": "0/0/0-GigabitEthernet0/0/0/0" - } - }, - { - "device_id": { - "device_uuid": { - "uuid": "5.5.5.5" - } - }, - "endpoint_uuid": { - "uuid": "0/0/3-GigabitEthernet0/0/0/3" - } - } - ], - "service_constraints": [ - { - "custom": { - "constraint_type": "bandwidth[kbps]", - "constraint_value": "200" - } - }, - { - "custom": { - "constraint_type": "latency[ms]", - "constraint_value": "5" - } - } - ], - "service_config": { - "config_rules": [ - { - "action": 1, - "custom": { - "resource_key": "/settings", - "resource_value": {} - } - }, - { - "action": 1, - "custom": { - "resource_key": "/device[4.4.4.4]/endpoint[0/0/0-GigabitEthernet0/0/0/0]/settings", - "resource_value": { - "sub_interface_index": 0, - "vlan_id": 101, - "circuit_id": "101", - "remote_router": "5.5.5.5", - "ni_name": "ELAN101" - } - } - }, - { - "action": 1, - "custom": { - "resource_key": "/device[5.5.5.5]/endpoint[0/0/3-GigabitEthernet0/0/0/3]/settings", - "resource_value": { - "sub_interface_index": 0, - "vlan_id": 101, - "circuit_id": "101", - "remote_router": "4.4.4.4", - "ni_name": "ELAN101" - } - } - } - ] - } - }, - { - "service_id": { - "context_id": { - "context_uuid": { - "uuid": "admin" - } - }, - "service_uuid": { - "uuid": "l2-acl-svc-17429923733753200" - } - }, - "service_type": 2, - "service_status": { - "service_status": 1 - }, - "service_endpoint_ids": [ - { - "device_id": { - "device_uuid": { - "uuid": "4.4.4.4" - } - }, - "endpoint_uuid": { - "uuid": "0/0/0-GigabitEthernet0/0/0/0" - } - }, - { - "device_id": { - "device_uuid": { - "uuid": "5.5.5.5" - } - }, - "endpoint_uuid": { - "uuid": "0/0/3-GigabitEthernet0/0/0/3" - } - } - ], - "service_constraints": [ - { - "custom": { - "constraint_type": "bandwidth[kbps]", - "constraint_value": "200" - } - }, - { - "custom": { - "constraint_type": "latency[ms]", - "constraint_value": "10" - } - } - ], - "service_config": { - "config_rules": [ - { - "action": 1, - "custom": { - "resource_key": "/settings", - "resource_value": {} - } - }, - { - "action": 1, - "custom": { - "resource_key": "/device[4.4.4.4]/endpoint[0/0/0-GigabitEthernet0/0/0/0]/settings", - "resource_value": { - "sub_interface_index": 0, - "vlan_id": 102, - "circuit_id": "102", - "remote_router": "5.5.5.5", - "ni_name": "ELAN102" - } - } - }, - { - "action": 1, - "custom": { - "resource_key": "/device[5.5.5.5]/endpoint[0/0/3-GigabitEthernet0/0/0/3]/settings", - "resource_value": { - "sub_interface_index": 0, - "vlan_id": 102, - "circuit_id": "102", - "remote_router": "4.4.4.4", - "ni_name": "ELAN102" - } - } - } - ] - } - } - ] -} \ No newline at end of file diff --git a/src/templates/L2-VPN_template_filled.json b/src/templates/L2-VPN_template_filled.json deleted file mode 100644 index 594fc27321d4628b7f1fb3cf803063eceb228b7f..0000000000000000000000000000000000000000 --- a/src/templates/L2-VPN_template_filled.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "services": [ - { - "service_id": { - "context_id": {"context_uuid": {"uuid": "admin"}}, //Siempre usaremos admin - "service_uuid": {"uuid": "l2-acl-svc"} //identificador unico - }, - "service_type": 2, // Numero que identifica que es una vpn de nivel 2, se mantiene - "service_status": {"service_status": 1}, - "service_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "R149"}}, "endpoint_uuid": {"uuid": "eth-1/0/21"}}, // Se tiene que cambiar por el endpoint de origen - {"device_id": {"device_uuid": {"uuid": "R155"}}, "endpoint_uuid": {"uuid": "eth-1/0/21"}} // Se tiene que cambiar por el endpoint de destino - ], - "service_constraints": [ //Requerimientos que han de darse, de momento no funciona por lo que mantener igual - {"custom": {"constraint_type": "bandwidth[kbps]", "constraint_value": "10.0"}}, - {"custom": {"constraint_type": "latency[ms]", "constraint_value": "15.2"}} - ], - "service_config": {"config_rules": [ - {"action": 1, "custom": {"resource_key": "/settings", "resource_value": { //Regla default, se mantiene - }}}, - {"action": 1, "custom": {"resource_key": "/device[R149]/endpoint[eth-1/0/21]/settings", "resource_value": { //Camino de ida, hay que cambiar la vlan, circuit_id y sub_interface_index por el valor de vlan que queramos usar - "sub_interface_index": 0, - "vlan_id": 999, - "circuit_id": "999", - "remote_router":"5.5.5.1" // Este valor es la ip del router en el otro extremo - }}}, - {"action": 1, "custom": {"resource_key": "/device[R155]/endpoint[eth-1/0/21]/settings", "resource_value": { //Camino de vuelta, hay que cambiar la vlan, circuit_id y sub_interface_index por el valor de vlan que queramos usar - "sub_interface_index": 0, - "vlan_id": 999, - "circuit_id": "999", - "remote_router":"5.5.5.5" // Este valor es la ip del router en el otro extremo - }}} - ]} - } - ] -} \ No newline at end of file diff --git a/src/templates/L3-VPN_template_empty.json b/src/templates/L3-VPN_template_empty.json index e894cfa4208734dc75c822ced467b7aa8e7d67a9..41d1f1bf6562bbf1530df77883978199cb6d9f91 100644 --- a/src/templates/L3-VPN_template_empty.json +++ b/src/templates/L3-VPN_template_empty.json @@ -12,8 +12,6 @@ {"device_id": {"device_uuid": {"uuid": ""}}, "endpoint_uuid": {"uuid": ""}} ], "service_constraints": [ - {"custom": {"constraint_type": "bandwidth[kbps]", "constraint_value": "0"}}, - {"custom": {"constraint_type": "latency[ms]", "constraint_value": "0"}} ], "service_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "/settings", "resource_value": { diff --git a/src/templates/L3-VPN_template_example.json b/src/templates/L3-VPN_template_example.json deleted file mode 100644 index d0a70b7d738121afb27c9ad0cad178fb797d6193..0000000000000000000000000000000000000000 --- a/src/templates/L3-VPN_template_example.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "services": [ - { - "service_id": { - "context_id": { - "context_uuid": { - "uuid": "admin" - } - }, - "service_uuid": { - "uuid": "l3-acl-svc-17258860855224490" - } - }, - "service_type": 1, - "service_status": { - "service_status": 1 - }, - "service_endpoint_ids": [ - { - "device_id": { - "device_uuid": { - "uuid": "4.4.4.4" - } - }, - "endpoint_uuid": { - "uuid": "0/0/1-GigabitEthernet0/0/0/1" - } - }, - { - "device_id": { - "device_uuid": { - "uuid": "5.5.5.5" - } - }, - "endpoint_uuid": { - "uuid": "0/0/1-GigabitEthernet0/0/0/1" - } - } - ], - "service_constraints": [ - { - "custom": { - "constraint_type": "bandwidth[kbps]", - "constraint_value": "120" - } - }, - { - "custom": { - "constraint_type": "latency[ms]", - "constraint_value": "2" - } - } - ], - "service_config": { - "config_rules": [ - { - "action": 1, - "custom": { - "resource_key": "/settings", - "resource_value": { - "bgp_as": 65000, - "route_distinguisher": "65000:533" - } - } - }, - { - "action": 1, - "custom": { - "resource_key": "/device[4.4.4.4]/endpoint[0/0/1-GigabitEthernet0/0/0/1]/settings", - "resource_value": { - "router_id": "5.5.5.5", - "sub_interface_index": 0, - "vlan_id": 300, - "address_ip": "5.5.5.5", - "address_prefix": 16, - "policy_AZ": "policyA", - "policy_ZA": "policyB", - "ni_name": "ELAN300" - } - } - }, - { - "action": 1, - "custom": { - "resource_key": "/device[5.5.5.5]/endpoint[0/0/1-GigabitEthernet0/0/0/1]/settings", - "resource_value": { - "router_id": "4.4.4.4", - "sub_interface_index": 0, - "vlan_id": 300, - "address_ip": "4.4.4.4", - "address_prefix": 16, - "policy_AZ": "policyA", - "policy_ZA": "policyB", - "ni_name": "ELAN300" - } - } - } - ] - } - } - ] -} \ No newline at end of file diff --git a/src/templates/L3-VPN_template_filled.json b/src/templates/L3-VPN_template_filled.json deleted file mode 100644 index 12bea2aa922a55b17d5906cc03032ac9c5bdba42..0000000000000000000000000000000000000000 --- a/src/templates/L3-VPN_template_filled.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "servs": [ - { - "service_id": { - "context_id": {"context_uuid": {"uuid": "admin"}}, //Siempre usaremos admin - "service_uuid": {"uuid": "l3-svc"} //identificador unico - }, - "service_type": 1, // Numero que identifica que es una vpn de nivel 3, se mantiene - "service_status": {"service_status": 1}, - "service_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "R149"}}, "endpoint_uuid": {"uuid": "eth-1/0/20"}}, // Se tiene que cambiar por el endpoint de origen - {"device_id": {"device_uuid": {"uuid": "R155"}}, "endpoint_uuid": {"uuid": "eth-1/0/20"}} // Se tiene que cambiar por el endpoint de destino - ], - "service_constraints": [ // Requerimientos que han de darse, de momento no funciona por lo que mantener igual - {"custom": {"constraint_type": "bandwidth[gbps]", "constraint_value": "10.0"}}, - {"custom": {"constraint_type": "latency[ms]", "constraint_value": "15.2"}} - ], - "service_config": {"config_rules": [ - {"action": 1, "custom": {"resource_key": "/settings", "resource_value": { //Regla default, se mantiene - "bgp_as" : 65000, - "route_distinguisher": "65000:533" - }}}, - {"action": 1, "custom": {"resource_key": "/device[R149]/endpoint[eth-1/0/20]/settings", "resource_value": { - "router_id" : "5.5.5.5", - "sub_interface_index": 0, - "vlan_id" : 533, - "address_ip" : "172.16.12.12", - "address_prefix" : 16, - "policy_AZ" : "srv_ACL", - "policy_ZA" : "srv_ACLr" - }}}, - {"action": 1, "custom": {"resource_key": "/device[R155]/endpoint[eth-1/0/20]/settings", "resource_value": { - "router_id" : "5.5.5.1", - "sub_interface_index": 0, - "vlan_id" : 533, - "address_ip" : "172.16.13.13", - "address_prefix" : 16, - "policy_AZ" : "srv_ACLr", - "policy_ZA" : "srv_ACL" - }}} - ]} - } - ] -} \ No newline at end of file diff --git a/src/templates/descriptor-topology copy.json b/src/templates/descriptor-topology copy.json deleted file mode 100644 index 304373aceb7a48ac4898c361833d46e21590d04b..0000000000000000000000000000000000000000 --- a/src/templates/descriptor-topology copy.json +++ /dev/null @@ -1,570 +0,0 @@ -{ - "dummy_mode": true, - "contexts":[ - { - "context_id":{ - "context_uuid":{ - "uuid":"admin" - } - }, - "topology_ids":[ - - ], - "service_ids":[ - - ] - } - ], - "topologies":[ - { - "topology_id":{ - "context_id":{ - "context_uuid":{ - "uuid":"admin" - } - }, - "topology_uuid":{ - "uuid":"admin" - } - }, - "device_ids":[ - { - "device_uuid":{ - "uuid":"1.1.1.1" - } - }, - { - "device_uuid":{ - "uuid":"2.2.2.2" - } - } - ], - "link_ids":[ - { - "link_uuid":{ - "uuid":"4.4.4.4/0/0/1-GigabitEthernet0/0/0/1==2.2.2.2/GigabitEthernet2" - } - }, - { - "link_uuid":{ - "uuid":"2.2.2.2/GigabitEthernet2==4.4.4.4/0/0/1-GigabitEthernet0/0/0/1" - } - }, - { - "link_uuid":{ - "uuid":"2.2.2.2/GigabitEthernet1==1.1.1.1/GigabitEthernet1" - } - }, - { - "link_uuid":{ - "uuid":"1.1.1.1/GigabitEthernet1==2.2.2.2/GigabitEthernet1" - } - }, - { - "link_uuid":{ - "uuid":"2.2.2.2/GigabitEthernet4==5.5.5.5/0/0/0-GigabitEthernet0/0/0/0" - } - }, - { - "link_uuid":{ - "uuid":"5.5.5.5/0/0/0-GigabitEthernet0/0/0/0==2.2.2.2/GigabitEthernet4" - } - }, - { - "link_uuid":{ - "uuid":"2.2.2.2/GigabitEthernet3==3.3.3.3/0/0/3-GigabitEthernet0/0/0/3" - } - }, - { - "link_uuid":{ - "uuid":"3.3.3.3/0/0/3-GigabitEthernet0/0/0/3==2.2.2.2/GigabitEthernet3" - } - }, - { - "link_uuid":{ - "uuid":"1.1.1.1/GigabitEthernet2==5.5.5.5/0/0/2-GigabitEthernet0/0/0/2" - } - }, - { - "link_uuid":{ - "uuid":"5.5.5.5/0/0/2-GigabitEthernet0/0/0/2==1.1.1.1/GigabitEthernet2" - } - } - ] - } - ], - "devices":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"1.1.1.1" - } - }, - "device_type":"packet-router", - "device_config":{ - "config_rules":[ - { - "action":1, - "custom":{ - "resource_key":"_connect/address", - "resource_value":"10.60.125.41" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/port", - "resource_value":"830" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/settings", - "resource_value":{ - "username":"cisco", - "password":"cisco12345", - "vendor":"CISCO", - "force_running":false, - "hostkey_verify":false, - "message_renderer":"pyangbind", - "look_for_keys":false, - "allow_agent":false, - "commit_per_rule":true, - "device_params":{ - "name":"default" - }, - "manager_params":{ - "timeout":120 - } - } - } - }, - {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[GigabitEthernet1]", "resource_value": { - "uuid": "GigabitEthernet1", "name": "GigabitEthernet1", "type": "-" - }}}, - {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[GigabitEthernet2]", "resource_value": { - "uuid": "GigabitEthernet2", "name": "GigabitEthernet2", "type": "-" - }}}, - {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[GigabitEthernet3]", "resource_value": { - "uuid": "GigabitEthernet3", "name": "GigabitEthernet3", "type": "-" - }}}, - {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[GigabitEthernet4]", "resource_value": { - "uuid": "GigabitEthernet4", "name": "GigabitEthernet4", "type": "-" - }}}, - {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[GigabitEthernet5]", "resource_value": { - "uuid": "GigabitEthernet5", "name": "GigabitEthernet5", "type": "-" - }}} - ] - }, - "device_operational_status":2, - "device_drivers":[ - 1 - ], - "device_endpoints":[ - {"name": "GigabitEthernet1", "endpoint_type": "-", "endpoint_id": { - "device_id": {"device_uuid": {"uuid": "1.1.1.1"}}, "endpoint_uuid": {"uuid": "GigabitEthernet1"}, - "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} - }}, - {"name": "GigabitEthernet2", "endpoint_type": "-", "endpoint_id": { - "device_id": {"device_uuid": {"uuid": "1.1.1.1"}}, "endpoint_uuid": {"uuid": "GigabitEthernet2"}, - "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} - }}, - {"name": "GigabitEthernet3", "endpoint_type": "-", "endpoint_id": { - "device_id": {"device_uuid": {"uuid": "1.1.1.1"}}, "endpoint_uuid": {"uuid": "GigabitEthernet3"}, - "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} - }}, - {"name": "GigabitEthernet4", "endpoint_type": "-", "endpoint_id": { - "device_id": {"device_uuid": {"uuid": "1.1.1.1"}}, "endpoint_uuid": {"uuid": "GigabitEthernet4"}, - "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} - }}, - {"name": "GigabitEthernet5", "endpoint_type": "-", "endpoint_id": { - "device_id": {"device_uuid": {"uuid": "1.1.1.1"}}, "endpoint_uuid": {"uuid": "GigabitEthernet5"}, - "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} - }} - ] - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "device_type":"packet-router", - "device_config":{ - "config_rules":[ - { - "action":1, - "custom":{ - "resource_key":"_connect/address", - "resource_value":"10.60.125.42" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/port", - "resource_value":"830" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/settings", - "resource_value":{ - "username":"cisco", - "password":"cisco12345", - "vendor":"CISCO", - "force_running":false, - "hostkey_verify":false, - "message_renderer":"pyangbind", - "look_for_keys":false, - "allow_agent":false, - "commit_per_rule":true, - "device_params":{ - "name":"default" - }, - "manager_params":{ - "timeout":120 - } - } - } - }, - {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[GigabitEthernet1]", "resource_value": { - "uuid": "GigabitEthernet1", "name": "GigabitEthernet1", "type": "-" - }}}, - {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[GigabitEthernet2]", "resource_value": { - "uuid": "GigabitEthernet2", "name": "GigabitEthernet2", "type": "-" - }}}, - {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[GigabitEthernet3]", "resource_value": { - "uuid": "GigabitEthernet3", "name": "GigabitEthernet3", "type": "-" - }}}, - {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[GigabitEthernet4]", "resource_value": { - "uuid": "GigabitEthernet4", "name": "GigabitEthernet4", "type": "-" - }}}, - {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[GigabitEthernet5]", "resource_value": { - "uuid": "GigabitEthernet5", "name": "GigabitEthernet5", "type": "-" - }}} - ] - }, - "device_operational_status":2, - "device_drivers":[ - 1 - ], - "device_endpoints":[ - {"name": "GigabitEthernet1", "endpoint_type": "-", "endpoint_id": { - "device_id": {"device_uuid": {"uuid": "2.2.2.2"}}, "endpoint_uuid": {"uuid": "GigabitEthernet1"}, - "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} - }}, - {"name": "GigabitEthernet2", "endpoint_type": "-", "endpoint_id": { - "device_id": {"device_uuid": {"uuid": "2.2.2.2"}}, "endpoint_uuid": {"uuid": "GigabitEthernet2"}, - "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} - }}, - {"name": "GigabitEthernet3", "endpoint_type": "-", "endpoint_id": { - "device_id": {"device_uuid": {"uuid": "2.2.2.2"}}, "endpoint_uuid": {"uuid": "GigabitEthernet3"}, - "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} - }}, - {"name": "GigabitEthernet4", "endpoint_type": "-", "endpoint_id": { - "device_id": {"device_uuid": {"uuid": "2.2.2.2"}}, "endpoint_uuid": {"uuid": "GigabitEthernet4"}, - "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} - }}, - {"name": "GigabitEthernet5", "endpoint_type": "-", "endpoint_id": { - "device_id": {"device_uuid": {"uuid": "2.2.2.2"}}, "endpoint_uuid": {"uuid": "GigabitEthernet5"}, - "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} - }} - ] - } - ], - "links":[ - { - "link_id":{ - "link_uuid":{ - "uuid":"4.4.4.4/0/0/1-GigabitEthernet0/0/0/1==2.2.2.2/GigabitEthernet2" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"4.4.4.4" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"GigabitEthernet2" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"2.2.2.2/GigabitEthernet2==4.4.4.4/0/0/1-GigabitEthernet0/0/0/1" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"GigabitEthernet2" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"4.4.4.4" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"2.2.2.2/GigabitEthernet1==1.1.1.1/GigabitEthernet1" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"GigabitEthernet1" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"1.1.1.1" - } - }, - "endpoint_uuid":{ - "uuid":"GigabitEthernet1" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"1.1.1.1/GigabitEthernet1==2.2.2.2/GigabitEthernet1" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"1.1.1.1" - } - }, - "endpoint_uuid":{ - "uuid":"GigabitEthernet1" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"GigabitEthernet1" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"2.2.2.2/GigabitEthernet4==5.5.5.5/0/0/0-GigabitEthernet0/0/0/0" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"GigabitEthernet4" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"5.5.5.5" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/0-GigabitEthernet0/0/0/0" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"5.5.5.5/0/0/0-GigabitEthernet0/0/0/0==2.2.2.2/GigabitEthernet4" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"5.5.5.5" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/0-GigabitEthernet0/0/0/0" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"GigabitEthernet4" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"2.2.2.2/GigabitEthernet3==3.3.3.3/0/0/3-GigabitEthernet0/0/0/3" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"GigabitEthernet3" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"3.3.3.3" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/3-GigabitEthernet0/0/0/3" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"3.3.3.3/0/0/3-GigabitEthernet0/0/0/3==2.2.2.2/GigabitEthernet3" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"3.3.3.3" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/3-GigabitEthernet0/0/0/3" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"GigabitEthernet3" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"1.1.1.1/GigabitEthernet2==5.5.5.5/0/0/2-GigabitEthernet0/0/0/2" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"1.1.1.1" - } - }, - "endpoint_uuid":{ - "uuid":"GigabitEthernet2" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"5.5.5.5" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/2-GigabitEthernet0/0/0/2" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"5.5.5.5/0/0/2-GigabitEthernet0/0/0/2==1.1.1.1/GigabitEthernet2" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"5.5.5.5" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/2-GigabitEthernet0/0/0/2" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"1.1.1.1" - } - }, - "endpoint_uuid":{ - "uuid":"GigabitEthernet2" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/src/templates/descriptor-topology-tid.json b/src/templates/descriptor-topology-tid.json deleted file mode 100644 index 588d9e90e08589b8d78d7a51c6c5ef8c3f607c0b..0000000000000000000000000000000000000000 --- a/src/templates/descriptor-topology-tid.json +++ /dev/null @@ -1,752 +0,0 @@ -{ - "contexts":[ - { - "context_id":{ - "context_uuid":{ - "uuid":"admin" - } - }, - "topology_ids":[ - - ], - "service_ids":[ - - ] - } - ], - "topologies":[ - { - "topology_id":{ - "context_id":{ - "context_uuid":{ - "uuid":"admin" - } - }, - "topology_uuid":{ - "uuid":"admin" - } - }, - "device_ids":[ - { - "device_uuid":{ - "uuid":"1.1.1.1" - } - }, - { - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - { - "device_uuid":{ - "uuid":"3.3.3.3" - } - }, - { - "device_uuid":{ - "uuid":"4.4.4.4" - } - }, - { - "device_uuid":{ - "uuid":"5.5.5.5" - } - } - ], - "link_ids":[ - { - "link_uuid":{ - "uuid":"5.5.5.5/0/0/1-GigabitEthernet0/0/0/1==3.3.3.3/0/0/1-GigabitEthernet0/0/0/1" - } - }, - { - "link_uuid":{ - "uuid":"3.3.3.3/0/0/1-GigabitEthernet0/0/0/1==5.5.5.5/0/0/1-GigabitEthernet0/0/0/1" - } - }, - { - "link_uuid":{ - "uuid":"5.5.5.5/0/0/2-GigabitEthernet0/0/0/2==1.1.1.1/0/0/1-GigabitEthernet0/0/0/1" - } - }, - { - "link_uuid":{ - "uuid":"1.1.1.1/0/0/1-GigabitEthernet0/0/0/1==5.5.5.5/0/0/2-GigabitEthernet0/0/0/2" - } - }, - { - "link_uuid":{ - "uuid":"5.5.5.5/0/0/0-GigabitEthernet0/0/0/0==2.2.2.2/0/0/2-GigabitEthernet0/0/0/2" - } - }, - { - "link_uuid":{ - "uuid":"2.2.2.2/0/0/2-GigabitEthernet0/0/0/2==5.5.5.5/0/0/0-GigabitEthernet0/0/0/0" - } - }, - { - "link_uuid":{ - "uuid":"3.3.3.3/0/0/3-GigabitEthernet0/0/0/3==2.2.2.2/0/0/3-GigabitEthernet0/0/0/3" - } - }, - { - "link_uuid":{ - "uuid":"2.2.2.2/0/0/3-GigabitEthernet0/0/0/3==3.3.3.3/0/0/3-GigabitEthernet0/0/0/3" - } - }, - { - "link_uuid":{ - "uuid":"1.1.1.1/0/0/0-GigabitEthernet0/0/0/0==2.2.2.2/0/0/0-GigabitEthernet0/0/0/0" - } - }, - { - "link_uuid":{ - "uuid":"2.2.2.2/0/0/0-GigabitEthernet0/0/0/0==1.1.1.1/0/0/0-GigabitEthernet0/0/0/0" - } - }, - { - "link_uuid":{ - "uuid":"4.4.4.4/0/0/1-GigabitEthernet0/0/0/1==2.2.2.2/0/0/1-GigabitEthernet0/0/0/1" - } - }, - { - "link_uuid":{ - "uuid":"2.2.2.2/0/0/1-GigabitEthernet0/0/0/1==4.4.4.4/0/0/1-GigabitEthernet0/0/0/1" - } - } - ] - } - ], - "devices":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"1.1.1.1" - } - }, - "device_type":"packet-router", - "device_config":{ - "config_rules":[ - { - "action":1, - "custom":{ - "resource_key":"_connect/address", - "resource_value":"10.95.90.41" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/port", - "resource_value":"830" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/settings", - "resource_value":{ - "username":"cisco", - "password":"cisco12345", - "vendor":"CISCO", - "force_running":false, - "hostkey_verify":false, - "message_renderer":"pyangbind", - "look_for_keys":false, - "allow_agent":false, - "commit_per_rule":true, - "device_params":{ - "name":"default" - }, - "manager_params":{ - "timeout":120 - } - } - } - } - ] - }, - "device_operational_status":2, - "device_drivers":[ - 1 - ], - "device_endpoints":[ - - ] - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "device_type":"packet-router", - "device_config":{ - "config_rules":[ - { - "action":1, - "custom":{ - "resource_key":"_connect/address", - "resource_value":"10.95.90.42" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/port", - "resource_value":"830" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/settings", - "resource_value":{ - "username":"cisco", - "password":"cisco12345", - "vendor":"CISCO", - "force_running":false, - "hostkey_verify":false, - "message_renderer":"pyangbind", - "look_for_keys":false, - "allow_agent":false, - "commit_per_rule":true, - "device_params":{ - "name":"default" - }, - "manager_params":{ - "timeout":120 - } - } - } - } - ] - }, - "device_operational_status":2, - "device_drivers":[ - 1 - ], - "device_endpoints":[ - - ] - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"3.3.3.3" - } - }, - "device_type":"packet-router", - "device_config":{ - "config_rules":[ - { - "action":1, - "custom":{ - "resource_key":"_connect/address", - "resource_value":"10.95.90.43" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/port", - "resource_value":"830" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/settings", - "resource_value":{ - "username":"cisco", - "password":"cisco12345", - "vendor":"CISCO", - "force_running":false, - "hostkey_verify":false, - "message_renderer":"pyangbind", - "look_for_keys":false, - "allow_agent":false, - "commit_per_rule":true, - "device_params":{ - "name":"default" - }, - "manager_params":{ - "timeout":120 - } - } - } - } - ] - }, - "device_operational_status":2, - "device_drivers":[ - 1 - ], - "device_endpoints":[ - - ] - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"4.4.4.4" - } - }, - "device_type":"packet-router", - "device_config":{ - "config_rules":[ - { - "action":1, - "custom":{ - "resource_key":"_connect/address", - "resource_value":"10.95.90.44" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/port", - "resource_value":"830" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/settings", - "resource_value":{ - "username":"cisco", - "password":"cisco12345", - "vendor":"CISCO", - "force_running":false, - "hostkey_verify":false, - "message_renderer":"pyangbind", - "look_for_keys":false, - "allow_agent":false, - "commit_per_rule":true, - "device_params":{ - "name":"default" - }, - "manager_params":{ - "timeout":120 - } - } - } - } - ] - }, - "device_operational_status":2, - "device_drivers":[ - 1 - ], - "device_endpoints":[ - - ] - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"5.5.5.5" - } - }, - "device_type":"packet-router", - "device_config":{ - "config_rules":[ - { - "action":1, - "custom":{ - "resource_key":"_connect/address", - "resource_value":"10.95.90.45" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/port", - "resource_value":"830" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/settings", - "resource_value":{ - "username":"cisco", - "password":"cisco12345", - "vendor":"CISCO", - "force_running":false, - "hostkey_verify":false, - "message_renderer":"pyangbind", - "look_for_keys":false, - "allow_agent":false, - "commit_per_rule":true, - "device_params":{ - "name":"default" - }, - "manager_params":{ - "timeout":120 - } - } - } - } - ] - }, - "device_operational_status":2, - "device_drivers":[ - 1 - ], - "device_endpoints":[ - - ] - } - ], - "links":[ - { - "link_id":{ - "link_uuid":{ - "uuid":"5.5.5.5/0/0/1-GigabitEthernet0/0/0/1==3.3.3.3/0/0/1-GigabitEthernet0/0/0/1" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"5.5.5.5" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"3.3.3.3" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"3.3.3.3/0/0/1-GigabitEthernet0/0/0/1==5.5.5.5/0/0/1-GigabitEthernet0/0/0/1" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"3.3.3.3" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"5.5.5.5" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"5.5.5.5/0/0/2-GigabitEthernet0/0/0/2==1.1.1.1/0/0/1-GigabitEthernet0/0/0/1" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"5.5.5.5" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/2-GigabitEthernet0/0/0/2" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"1.1.1.1" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"1.1.1.1/0/0/1-GigabitEthernet0/0/0/1==5.5.5.5/0/0/2-GigabitEthernet0/0/0/2" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"1.1.1.1" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"5.5.5.5" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/2-GigabitEthernet0/0/0/2" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"5.5.5.5/0/0/0-GigabitEthernet0/0/0/0==2.2.2.2/0/0/2-GigabitEthernet0/0/0/2" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"5.5.5.5" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/0-GigabitEthernet0/0/0/0" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/2-GigabitEthernet0/0/0/2" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"2.2.2.2/0/0/2-GigabitEthernet0/0/0/2==5.5.5.5/0/0/0-GigabitEthernet0/0/0/0" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/2-GigabitEthernet0/0/0/2" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"5.5.5.5" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/0-GigabitEthernet0/0/0/0" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"3.3.3.3/0/0/3-GigabitEthernet0/0/0/3==2.2.2.2/0/0/3-GigabitEthernet0/0/0/3" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"3.3.3.3" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/3-GigabitEthernet0/0/0/3" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/3-GigabitEthernet0/0/0/3" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"2.2.2.2/0/0/3-GigabitEthernet0/0/0/3==3.3.3.3/0/0/3-GigabitEthernet0/0/0/3" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/3-GigabitEthernet0/0/0/3" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"3.3.3.3" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/3-GigabitEthernet0/0/0/3" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"1.1.1.1/0/0/0-GigabitEthernet0/0/0/0==2.2.2.2/0/0/0-GigabitEthernet0/0/0/0" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"1.1.1.1" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/0-GigabitEthernet0/0/0/0" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/0-GigabitEthernet0/0/0/0" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"2.2.2.2/0/0/0-GigabitEthernet0/0/0/0==1.1.1.1/0/0/0-GigabitEthernet0/0/0/0" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/0-GigabitEthernet0/0/0/0" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"1.1.1.1" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/0-GigabitEthernet0/0/0/0" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"4.4.4.4/0/0/1-GigabitEthernet0/0/0/1==2.2.2.2/0/0/1-GigabitEthernet0/0/0/1" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"4.4.4.4" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"2.2.2.2/0/0/1-GigabitEthernet0/0/0/1==4.4.4.4/0/0/1-GigabitEthernet0/0/0/1" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"2.2.2.2" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"4.4.4.4" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/src/templates/descriptor-topology.json b/src/templates/descriptor-topology.json deleted file mode 100644 index e22737b52783b5db72e5809d83f4cbbc3a936c09..0000000000000000000000000000000000000000 --- a/src/templates/descriptor-topology.json +++ /dev/null @@ -1,290 +0,0 @@ -{ - "contexts":[ - { - "context_id":{ - "context_uuid":{ - "uuid":"admin" - } - }, - "topology_ids":[ - - ], - "service_ids":[ - - ] - } - ], - "topologies":[ - { - "topology_id":{ - "context_id":{ - "context_uuid":{ - "uuid":"admin" - } - }, - "topology_uuid":{ - "uuid":"admin" - } - }, - "device_ids":[ - { - "device_uuid":{ - "uuid":"3.3.3.3" - } - }, - { - "device_uuid":{ - "uuid":"4.4.4.4" - } - }, - { - "device_uuid":{ - "uuid":"5.5.5.5" - } - } - ], - "link_ids":[ - { - "link_uuid":{ - "uuid":"5.5.5.5/0/0/1-GigabitEthernet0/0/0/1==3.3.3.3/0/0/1-GigabitEthernet0/0/0/1" - } - }, - { - "link_uuid":{ - "uuid":"3.3.3.3/0/0/1-GigabitEthernet0/0/0/1==5.5.5.5/0/0/1-GigabitEthernet0/0/0/1" - } - } - ] - } - ], - "devices":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"3.3.3.3" - } - }, - "device_type":"packet-router", - "device_config":{ - "config_rules":[ - { - "action":1, - "custom":{ - "resource_key":"_connect/address", - "resource_value":"10.60.125.43" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/port", - "resource_value":"830" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/settings", - "resource_value":{ - "username":"cisco", - "password":"cisco12345", - "vendor":"CISCO", - "force_running":false, - "hostkey_verify":false, - "message_renderer":"pyangbind", - "look_for_keys":false, - "allow_agent":false, - "commit_per_rule":true, - "device_params":{ - "name":"default" - }, - "manager_params":{ - "timeout":120 - } - } - } - } - ] - }, - "device_operational_status":2, - "device_drivers":[ - 1 - ], - "device_endpoints":[ - - ] - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"4.4.4.4" - } - }, - "device_type":"packet-router", - "device_config":{ - "config_rules":[ - { - "action":1, - "custom":{ - "resource_key":"_connect/address", - "resource_value":"10.60.125.44" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/port", - "resource_value":"830" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/settings", - "resource_value":{ - "username":"cisco", - "password":"cisco12345", - "vendor":"CISCO", - "force_running":false, - "hostkey_verify":false, - "message_renderer":"pyangbind", - "look_for_keys":false, - "allow_agent":false, - "commit_per_rule":true, - "device_params":{ - "name":"default" - }, - "manager_params":{ - "timeout":120 - } - } - } - } - ] - }, - "device_operational_status":2, - "device_drivers":[ - 1 - ], - "device_endpoints":[ - - ] - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"5.5.5.5" - } - }, - "device_type":"packet-router", - "device_config":{ - "config_rules":[ - { - "action":1, - "custom":{ - "resource_key":"_connect/address", - "resource_value":"10.60.125.45" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/port", - "resource_value":"830" - } - }, - { - "action":1, - "custom":{ - "resource_key":"_connect/settings", - "resource_value":{ - "username":"cisco", - "password":"cisco12345", - "vendor":"CISCO", - "force_running":false, - "hostkey_verify":false, - "message_renderer":"pyangbind", - "look_for_keys":false, - "allow_agent":false, - "commit_per_rule":true, - "device_params":{ - "name":"default" - }, - "manager_params":{ - "timeout":120 - } - } - } - } - ] - }, - "device_operational_status":2, - "device_drivers":[ - 1 - ], - "device_endpoints":[ - - ] - } - ], - "links":[ - { - "link_id":{ - "link_uuid":{ - "uuid":"5.5.5.5/0/0/1-GigabitEthernet0/0/0/1==3.3.3.3/0/0/1-GigabitEthernet0/0/0/1" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"5.5.5.5" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"3.3.3.3" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - } - ] - }, - { - "link_id":{ - "link_uuid":{ - "uuid":"3.3.3.3/0/0/1-GigabitEthernet0/0/0/1==5.5.5.5/0/0/1-GigabitEthernet0/0/0/1" - } - }, - "link_endpoint_ids":[ - { - "device_id":{ - "device_uuid":{ - "uuid":"3.3.3.3" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - }, - { - "device_id":{ - "device_uuid":{ - "uuid":"5.5.5.5" - } - }, - "endpoint_uuid":{ - "uuid":"0/0/1-GigabitEthernet0/0/0/1" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/src/templates/descriptor.json b/src/templates/descriptor.json deleted file mode 100644 index 4923ab4427b5723d970c006043242373fb4eafdd..0000000000000000000000000000000000000000 --- a/src/templates/descriptor.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "contexts": [ - { - "context_id": { - "context_uuid": { - "uuid": "admin" - } - }, - "topology_ids": [], - "service_ids": [] - } - ], - "topologies": [ - { - "topology_id": { - "context_id": { - "context_uuid": { - "uuid": "admin" - } - }, - "topology_uuid": { - "uuid": "admin" - } - } - } - ] - } \ No newline at end of file diff --git a/src/templates/ietfL2VPN_template.json b/src/templates/ietfL2VPN_template.json deleted file mode 100644 index 79037c2f7e423ce44b34bd90f35ca8fe74071f18..0000000000000000000000000000000000000000 --- a/src/templates/ietfL2VPN_template.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "l2vpn": { - "vpn-services": { - "vpn-service": [ - { - "vpn-id": 100, - "name": "VPN_L2_Example", - "vpn-type": "point-to-point", - "site": [ - { - "site-id": 1, - "site-role": "hub", - "site-location": "R4", - "site-network-access": { - "interface": { - "ip-address": "4.4.4.4", - "encapsulation": "ethernet" - } - } - }, - { - "site-id": 2, - "site-role": "spoke", - "site-location": "R5", - "site-network-access": { - "interface": { - "ip-address": "5.5.5.5", - "encapsulation": "ethernet" - } - } - } - ] - } - ] - } - } - } - \ No newline at end of file diff --git a/src/templates/ietfL2VPN_template_empty.json b/src/templates/ietfL2VPN_template_empty.json new file mode 100644 index 0000000000000000000000000000000000000000..d7d6be05fc6a78f2ac3e8acaebae9410fd97905a --- /dev/null +++ b/src/templates/ietfL2VPN_template_empty.json @@ -0,0 +1,32 @@ +{ + "ietf-l2vpn-svc:vpn-service": [ + { + "vpn-id": "", + "customer-name": "osm", + "vpn-svc-type": "vpws", + "svc-topo": "any-to-any", + "site": [ + { + "site-id": "", + "site-location": "", + "site-network-access": { + "interface": { + "ip-address": "", + "encapsulation": "ethernet" + } + } + }, + { + "site-id": "", + "site-location": "", + "site-network-access": { + "interface": { + "ip-address": "", + "encapsulation": "ethernet" + } + } + } + ] + } + ] +} diff --git a/src/templates/ietfL3VPN_template.json b/src/templates/ietfL3VPN_template.json deleted file mode 100644 index 07ffbe91b29addee98b3ac390076a581916038d5..0000000000000000000000000000000000000000 --- a/src/templates/ietfL3VPN_template.json +++ /dev/null @@ -1,184 +0,0 @@ -{ - "ietf-l3vpn-svc:l3vpn-svc": { - "sites": { - "site": [ - { - "devices": { - "device": [ - { - "device-id": "4.4.4.4", - "location": "router4" - } - ] - }, - "locations": { - "location": [ - { - "location-id": "router4" - } - ] - }, - "management": { - "type": "ietf-l3vpn-svc:provider-managed" - }, - "routing-protocols": { - "routing-protocol": [ - { - "static": { - "cascaded-lan-prefixes": { - "ipv4-lan-prefixes": [ - { - "lan": "4.4.4.4/24", - "lan-tag": "100", - "next-hop": "2.2.2.2" - } - ] - } - }, - "type": "ietf-l3vpn-svc:static" - } - ] - }, - "site-id": "site_router4", - "site-network-accesses": { - "site-network-access": [ - { - "device-reference": "4.4.4.4", - "ip-connection": { - "ipv4": { - "address-allocation-type": "ietf-l3vpn-svc:static-address", - "addresses": { - "customer-address": "2.2.2.2", - "prefix-length": "24", - "provider-address": "4.4.4.4" - } - } - }, - "service": { - "qos": { - "qos-profile": { - "classes": { - "class": [ - { - "bandwidth": { - "guaranteed-bw-percent": 100 - }, - "class-id": "qos-realtime", - "direction": "ietf-l3vpn-svc:both", - "latency": { - "latency-boundary": 20 - } - } - ] - } - } - }, - "svc-input-bandwidth": 5000000000, - "svc-mtu": 1500, - "svc-output-bandwidth": 1000000000 - }, - "site-network-access-type": "ietf-l3vpn-svc:multipoint", - "vpn-attachment": { - "site-role": "ietf-l3vpn-svc:hub-role", - "vpn-id": "vpn-example" - } - } - ] - } - }, - { - "devices": { - "device": [ - { - "device-id": "5.5.5.5", - "location": "router5" - } - ] - }, - "locations": { - "location": [ - { - "location-id": "router5" - } - ] - }, - "management": { - "type": "ietf-l3vpn-svc:provider-managed" - }, - "routing-protocols": { - "routing-protocol": [ - { - "static": { - "cascaded-lan-prefixes": { - "ipv4-lan-prefixes": [ - { - "lan": "5.5.5.5/24", - "lan-tag": "200", - "next-hop": "2.2.2.2" - } - ] - } - }, - "type": "ietf-l3vpn-svc:static" - } - ] - }, - "site-id": "site_router5", - "site-network-accesses": { - "site-network-access": [ - { - "device-reference": "5.5.5.5", - "ip-connection": { - "ipv4": { - "address-allocation-type": "ietf-l3vpn-svc:static-address", - "addresses": { - "customer-address": "2.2.2.2", - "prefix-length": "24", - "provider-address": "5.5.5.5" - } - } - }, - "service": { - "qos": { - "qos-profile": { - "classes": { - "class": [ - { - "bandwidth": { - "guaranteed-bw-percent": 100 - }, - "class-id": "qos-realtime", - "direction": "ietf-l3vpn-svc:both", - "latency": { - "latency-boundary": 10 - } - } - ] - } - } - }, - "svc-input-bandwidth": 1000000000, - "svc-mtu": 1500, - "svc-output-bandwidth": 5000000000 - }, - "site-network-access-type": "ietf-l3vpn-svc:multipoint", - "vpn-attachment": { - "site-role": "ietf-l3vpn-svc:spoke-role", - "vpn-id": "vpn-example" - } - } - ] - } - } - ] - }, - "vpn-services": { - "vpn-service": [ - { - "vpn-id": "vpn-example" - } - ] - } - } - } - \ No newline at end of file diff --git a/src/templates/ietfL3VPN_template_empty.json b/src/templates/ietfL3VPN_template_empty.json new file mode 100644 index 0000000000000000000000000000000000000000..628abcbe200fb58dbdb6638081c4a3087116e7fc --- /dev/null +++ b/src/templates/ietfL3VPN_template_empty.json @@ -0,0 +1,83 @@ +{ + "ietf-l3vpn-svc:l3vpn-svc": { + "vpn-services": {"vpn-service": [{"vpn-id": ""}]}, + "sites": { + "site": [ + { + "site-id": "", + "management": {"type": "ietf-l3vpn-svc:provider-managed"}, + "locations": {"location": [{"location-id": ""}]}, + "devices": {"device": [{"device-id": "", "location": ""}]}, + "site-network-accesses": { + "site-network-access": [ + { + "site-network-access-id": "", + "site-network-access-type": "ietf-l3vpn-svc:multipoint", + "device-reference": "", + "vpn-attachment": {"vpn-id": "", "site-role": "ietf-l3vpn-svc:spoke-role"}, + "ip-connection": { + "ipv4": { + "address-allocation-type": "ietf-l3vpn-svc:static-address", + "addresses": { + "provider-address": "192.168.1.1", + "customer-address": "192.168.1.10", + "prefix-length": 24 + } + } + }, + "service": { + "svc-mtu": 1500, + "svc-input-bandwidth": 1, + "svc-output-bandwidth": 1, + "qos": {"qos-profile": {"classes": {"class": [{ + "class-id": "qos-realtime", + "direction": "ietf-l3vpn-svc:both", + "latency": {"latency-boundary": 100}, + "bandwidth": {"guaranteed-bw-percent": 100} + }]}}} + } + } + ] + } + }, + { + "site-id": "", + "management": {"type": "ietf-l3vpn-svc:provider-managed"}, + "locations": {"location": [{"location-id": ""}]}, + "devices": {"device": [{"device-id": "", "location": ""}]}, + "site-network-accesses": { + "site-network-access": [ + { + "site-network-access-id": "", + "site-network-access-type": "ietf-l3vpn-svc:multipoint", + "device-reference": "", + "vpn-attachment": {"vpn-id": "", "site-role": "ietf-l3vpn-svc:hub-role"}, + "ip-connection": { + "ipv4": { + "address-allocation-type": "ietf-l3vpn-svc:static-address", + "addresses": { + "provider-address": "192.168.2.1", + "customer-address": "192.168.2.10", + "prefix-length": 24 + } + } + }, + "service": { + "svc-mtu": 1500, + "svc-input-bandwidth": 1, + "svc-output-bandwidth": 1, + "qos": {"qos-profile": {"classes": {"class": [{ + "class-id": "qos-realtime", + "direction": "ietf-l3vpn-svc:both", + "latency": {"latency-boundary": 100}, + "bandwidth": {"guaranteed-bw-percent": 100} + }]}}} + } + } + ] + } + } + ] + } + } +} diff --git a/src/templates/ietf_template_empty.json b/src/templates/ietf_template_empty.json index b4fb81f6d61100bfa0dcdb17fa0165eb03bd9ed8..cdaf66cdad3fbd7f01c09a7987cf8729600952b0 100644 --- a/src/templates/ietf_template_empty.json +++ b/src/templates/ietf_template_empty.json @@ -7,16 +7,6 @@ "description":"", "slo-policy":{ "metric-bound":[ - { - "metric-type":"one-way-bandwidth", - "metric-unit":"kbps", - "bound":"" - }, - { - "metric-type":"one-way-delay-maximum", - "metric-unit":"milliseconds", - "bound":"" - } ] }, "sle-policy":{ @@ -53,7 +43,7 @@ "sdps":{ "sdp":[ { - "id":"01", + "id": "", "geo-location":"", "node-id":"", "sdp-ip-address":"", @@ -100,7 +90,7 @@ "sdp-monitoring":"" }, { - "id":"02", + "id":"", "geo-location":"", "node-id":"", "sdp-ip-address":"", diff --git a/src/templates/ietf_template_example.json b/src/templates/ietf_template_example.json deleted file mode 100644 index 82782208df2489ba0aba0a27c121f90a71c34d4d..0000000000000000000000000000000000000000 --- a/src/templates/ietf_template_example.json +++ /dev/null @@ -1,158 +0,0 @@ -{ - "ietf-network-slice-service:network-slice-services": { - "slo-sle-templates": { - "slo-sle-template": [ - { - "id": "A", - "description": "", - "slo-policy": { - "metric-bound": [ - { - "metric-type": "one-way-bandwidth", - "metric-unit": "kbps", - "bound": 2 - }, - { - "metric-type": "one-way-delay-maximum", - "metric-unit": "milliseconds", - "bound": 20 - } - ] - }, - "sle-policy": { - "security": "", - "isolation": "", - "path-constraints": { - "service-functions": "", - "diversity": { - "diversity": { - "diversity-type": "" - } - } - } - } - } - ] - }, - "slice-service": [ - { - "id": "slice-service-366e05b7-34e6-4597-9e28-e580abaeda71", - "description": "Transport network slice mapped with 3GPP slice NetworkSlice1", - "service-tags": { - "tag-type": { - "tag-type": "", - "value": "" - } - }, - "slo-sle-policy": { - "slo-sle-template": "A" - }, - "status": {}, - "sdps": { - "sdp": [ - { - "id": "01", - "geo-location": "", - "node-id": "CU-N2", - "sdp-ip-address": "10.60.60.105", - "tp-ref": "", - "service-match-criteria": { - "match-criterion": [ - { - "index": 1, - "match-type": "VLAN", - "value": "100", - "target-connection-group-id": "CU-N2_AMF-N2" - } - ] - }, - "incoming-qos-policy": "", - "outgoing-qos-policy": "", - "sdp-peering": { - "peer-sap-id": "", - "protocols": "" - }, - "ac-svc-ref": [], - "attachment-circuits": { - "attachment-circuit": [ - { - "id": "100", - "ac-ipv4-address": "10.60.60.105", - "ac-ipv4-prefix-length": 0, - "sdp-peering": { - "peer-sap-id": "5.5.5.5" - }, - "status": {} - } - ] - }, - "status": {}, - "sdp-monitoring": "" - }, - { - "id": "02", - "geo-location": "", - "node-id": "AMF-N2", - "sdp-ip-address": "10.60.11.3", - "tp-ref": "", - "service-match-criteria": { - "match-criterion": [ - { - "index": 1, - "match-type": "VLAN", - "value": "100", - "target-connection-group-id": "CU-N2_AMF-N2" - } - ] - }, - "incoming-qos-policy": "", - "outgoing-qos-policy": "", - "sdp-peering": { - "peer-sap-id": "", - "protocols": "" - }, - "ac-svc-ref": [], - "attachment-circuits": { - "attachment-circuit": [ - { - "id": "200", - "ac-ipv4-address": "10.60.11.3", - "ac-ipv4-prefix-length": 0, - "sdp-peering": { - "peer-sap-id": "4.4.4.4" - }, - "status": {} - } - ] - }, - "status": {}, - "sdp-monitoring": "" - } - ] - }, - "connection-groups": { - "connection-group": [ - { - "id": "CU-N2_AMF-N2", - "connectivity-type": "ietf-vpn-common:any-to-any", - "connectivity-construct": [ - { - "id": 1, - "a2a-sdp": [ - { - "sdp-id": "01" - }, - { - "sdp-id": "02" - } - ] - } - ], - "status": {} - } - ] - } - } - ] - } -} \ No newline at end of file diff --git a/src/templates/ietf_template_filled.json b/src/templates/ietf_template_filled.json deleted file mode 100644 index e7a525e096c027323a4feb63ff8407f9385a2ee0..0000000000000000000000000000000000000000 --- a/src/templates/ietf_template_filled.json +++ /dev/null @@ -1,152 +0,0 @@ -{ - "ietf-network-slice-service:network-slice-services":{ - "slo-sle-templates":{ - "slo-sle-template":[ - { - "id":"MidhaulId", - "slo-policy":{ - "metric-bound":[ - { - "metric-type":"one-way-bandwidth", - "metric-unit":"kbps", - "bound":300 - }, - { - "metric-type":"one-way-delay-maximum", - "metric-unit":"milliseconds", - "bound":1 - } - ] - }, - "sle-policy":{ - "security":[ - - ], - "isolation":[ - - ], - "steering-constraints":{ - "path-constraints":"", - "service-function":"" - } - } - } - ] - }, - "slice-service":[ - { - "id":"5GSliceMapping", - "description":"example 5G Slice mapping", - "slo-sle-template":"MidhaulId", - "status":{ - - }, - "sdps":{ - "sdp":[ - { - "id":"01", - "node-id":"DU1", - "sdp-ip-address":"1.1.1.2", - "service-match-criteria":{ - "match-criterion":[ - { - "index":1, - "match-type":"vlan-match", - "value":[ - "100" - ], - "target-connection-group-id":"DU-CU" - } - ] - }, - "sdp-peering":{ - "peer-sap-id":"", - "protocols":"" - }, - "ac-svc-name":[ - - ], - "attachment-circuits":{ - "attachment-circuit":[ - { - "id":"100", - "ac-ipv4-address":"1.1.1.1", - "ac-ipv4-prefix-length":0, - "sdp-peering":{ - "peer-sap-id":"1.1.1.254" - }, - "status":{ - - } - } - ] - }, - "status":{ - - } - }, - { - "id":"02", - "node-id":"CU-UP1", - "sdp-ip-address":"100.1.1.2", - "service-match-criteria":{ - "match-criterion":[ - { - "index":1, - "match-type":"vlan-match", - "value":[ - "100" - ], - "target-connection-group-id":"DU-CU" - } - ] - }, - "attachment-circuits":{ - "attachment-circuit":[ - { - "id":"200", - "ac-ipv4-address":"100.1.1.1", - "ac-ipv4-prefix-length":0, - "sdp-peering":{ - "peer-sap-id":"100.1.1.254" - }, - "status":{ - - } - } - ] - }, - "status":{ - - } - } - ] - }, - "connection-groups":{ - "connection-group":[ - { - "id":"DU-CU", - "connectivity-type":"ietf-vpn-common:any-to-any", - "connectivity-construct":[ - { - "id":1, - "a2a-sdp":[ - { - "sdp-id":"01" - }, - { - "sdp-id":"02" - } - ] - } - ], - "status":{ - - } - } - ] - } - } - ] - } -} \ No newline at end of file diff --git a/src/templates/ips.json b/src/templates/ips.json deleted file mode 100644 index c041c4c41f46e678598ae13d0743923e2998a114..0000000000000000000000000000000000000000 --- a/src/templates/ips.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "CU":[ - {"prefix":"100.1.1.2", "node-name":"CU-UP1" }, - {"prefix":"100.1.2.2", "node-name":"CU-UP2" } - ], - "DU":[ - {"prefix":"1.1.1.2", "node-name":"DU1" }, - {"prefix":"1.1.2.2", "node-name":"DU2" }, - {"prefix":"1.1.3.2", "node-name":"DU3" } - ], - "public-prefixes":[ - {"prefix":"10.95.90.125", "node-name":"HL5-2-2" }, - {"prefix":"10.95.90.126", "node-name":"HL5-1-2" }, - {"prefix":"10.95.86.167", "node-name":"HL5-3-2" }, - {"prefix":"10.95.86.107", "node-name":"HL4-1-2" }, - {"prefix":"10.95.90.85", "node-name":"HL4-2-2" } - ] -} diff --git a/src/templates/test_service.json b/src/templates/test_service.json deleted file mode 100644 index bd956b7281afce8f3626bfa08be5dc9471e63e8b..0000000000000000000000000000000000000000 --- a/src/templates/test_service.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "services": [ - { - "service_id": { - "context_id": { - "context_uuid": { - "uuid": "admin" - } - }, - "service_uuid": { - "uuid": "l2-acl-svc-17387469754519430" - } - }, - "service_type": 2, - "service_status": { - "service_status": 1 - }, - "service_endpoint_ids": [ - { - "device_id": { - "device_uuid": { - "uuid": "172.16.185.31" - } - }, - "endpoint_uuid": { - "uuid": "eth-1/0/22" - } - }, - { - "device_id": { - "device_uuid": { - "uuid": "172.16.185.32" - } - }, - "endpoint_uuid": { - "uuid": "eth-1/0/6" - } - } - ], - "service_constraints": [ - { - "custom": { - "constraint_type": "bandwidth[kbps]", - "constraint_value": "20" - } - }, - { - "custom": { - "constraint_type": "latency[ms]", - "constraint_value": "20" - } - } - ], - "service_config": { - "config_rules": [ - { - "action": 1, - "custom": { - "resource_key": "/settings", - "resource_value": {} - } - }, - { - "action": 1, - "custom": { - "resource_key": "/device[172.16.185.31]/endpoint[eth-1/0/22]/settings", - "resource_value": { - "sub_interface_index": 0, - "vlan_id": 100, - "circuit_id": "100", - "remote_router": "172.16.185.32", - "ni_name": "ELAN100" - } - } - }, - { - "action": 1, - "custom": { - "resource_key": "/device[172.16.185.32]/endpoint[eth-1/0/6]/settings", - "resource_value": { - "sub_interface_index": 0, - "vlan_id": 100, - "circuit_id": "100", - "remote_router": "172.16.185.31", - "ni_name": "ELAN100" - } - } - } - ] - } - } - ] - } \ No newline at end of file diff --git a/src/webui/gui.py b/src/webui/gui.py new file mode 100644 index 0000000000000000000000000000000000000000..1afb831c6410b8a58d51c1b077a86c4a665db33d --- /dev/null +++ b/src/webui/gui.py @@ -0,0 +1,475 @@ +# 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. + +# This file is an original contribution from Telefonica Innovación Digital S.L. + +import json, logging, uuid +import requests +import os +import pandas as pd +from flask import Flask, render_template, request, jsonify, redirect, url_for, session, Blueprint +from collections import OrderedDict +from src.Constants import SRC_PATH, NSC_PORT, TEMPLATES_PATH, DUMMY_MODE +from src.realizers.ixia.NEII_V4 import NEII_controller + +# app =Flask(__name__) +gui_bp = Blueprint('gui', __name__, template_folder=os.path.join(SRC_PATH, 'webui', 'templates'), static_folder=os.path.join(SRC_PATH, 'webui', 'static'), static_url_path='/webui/static') + +#Variables for dev accessing +USERNAME = 'admin' +PASSWORD = 'admin' +enter=False + +def __safe_int(value): + try: + if isinstance(value, str): + value = value.strip().replace(',', '.') + number = float(value) + return int(number) if number.is_integer() else number + except (ValueError, TypeError, AttributeError): + return None + +def __build_request_ietf(src_node_ip=None, dst_node_ip=None, vlan_id=None, bandwidth=None, latency=None, tolerance=0, latency_version=None, reliability=None): + ''' + Work: Build the IETF template for the intent + ''' + # Open and read the template file + with open(os.path.join(TEMPLATES_PATH, 'ietf_template_empty.json'), 'r') as source: + # Clean up the JSON template + template = source.read().replace('\t', '').replace('\n', '').replace("'", '"').strip() + request = json.loads(template) + + request["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["id"] = f"qos-profile-{uuid.uuid4()}" + + # Generate unique slice service ID and description + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["id"] = f"slice-service-{uuid.uuid4()}" + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["slo-sle-policy"]["slo-sle-template"] = request["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["id"] + + # Configure Source SDP + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["node-id"] = "source-node" #Pendiente de rellenar + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["sdp-ip-address"] = src_node_ip + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["service-match-criteria"]["match-criterion"][0]["match-type"] = "VLAN" + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["service-match-criteria"]["match-criterion"][0]["value"] = vlan_id + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["attachment-circuits"]["attachment-circuit"][0]["ac-ipv4-address"] = "" # Pendiente de rellenar + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["attachment-circuits"]["attachment-circuit"][0]["sdp-peering"]["peer-sap-id"] = src_node_ip + + # Configure Destination SDP + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][1]["node-id"] = "destination-node" + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][1]["sdp-ip-address"] = dst_node_ip + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][1]["service-match-criteria"]["match-criterion"][0]["match-type"] = "VLAN" + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][1]["service-match-criteria"]["match-criterion"][0]["value"] = vlan_id + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][1]["attachment-circuits"]["attachment-circuit"][0]["ac-ipv4-address"] = ""# Pendiente de rellenar + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][1]["attachment-circuits"]["attachment-circuit"][0]["sdp-peering"]["peer-sap-id"] = dst_node_ip + + # Configure Connection Group and match-criteria + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["connection-groups"]["connection-group"][0]["id"] = "source-node_destination-node" #Pendiente de rellenar + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["service-match-criteria"]["match-criterion"][0]["target-connection-group-id"] = "" #Pendiente de rellenar + request["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][1]["service-match-criteria"]["match-criterion"][0]["target-connection-group-id"] = "" #Pendiente de rellenar + + # Populate template with SLOs (currently supporting QoS profile, latency and bandwidth) + if bandwidth: + request["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"].append({ + "metric-type": "one-way-bandwidth", + "metric-unit": "Mbps", + "bound": __safe_int(bandwidth) + }) + if latency: + request["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"].append({ + "metric-type": "one-way-delay-maximum", + "metric-unit": "milliseconds", + "bound": __safe_int(latency) + }) + # Configure gaussian latency or internet if specified + if latency_version: + request["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["description"] = latency_version + if tolerance: + request["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"].append( { + "metric-type": "one-way-delay-variation-maximum", + "metric-unit": "milliseconds", + "bound": __safe_int(tolerance) + }) + if reliability: + request["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["sle-policy"]["reliability"] = __safe_int(reliability) + + return request + +def __build_request(ip_version=None, src_node_ip=None, dst_node_ip=None, src_node_ipv6=None, dst_node_ipv6=None, + vlan_id=None, bandwidth=None, latency=None, tolerance=0, latency_version=None, + reliability=None, packet_reorder=None, num_pack=None, pack_reorder=None, num_reorder=None, + max_reorder=None, desv_reorder=None, drop_version=None, packets_drop=None, + drops=None, desv_drop=None): + ''' + Work: Build the template for the IXIA NEII + ''' + json_data = { + "ip_version": ip_version, + "src_node_ip": src_node_ip, + "dst_node_ip": dst_node_ip, + "src_node_ipv6": src_node_ipv6, + "dst_node_ipv6": dst_node_ipv6, + "vlan_id": vlan_id, + "bandwidth": bandwidth, + "latency": latency, + "tolerance": tolerance, + "latency_version": latency_version, + "reliability": reliability, + "packet_reorder": packet_reorder, + "num_pack": num_pack, + "pack_reorder": pack_reorder, + "num_reorder": num_reorder, + "max_reorder": max_reorder, + "desv_reorder": desv_reorder, + "drop_version": drop_version, + "packets_drop": packets_drop, + "drops": drops, + "desv_drop": desv_drop + } + return json_data + +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"] + for dest_ip, dest_info in source_info["destination"].items(): + row ={ + "Source IP": source_ip, + "Destiny IP": dest_ip, + "VLAN": vlan, + "attributes": dest_info["attributes"] + } + rows.append(row) + dataframe =pd.DataFrame(rows) + except FileNotFoundError: + dataframe =pd.DataFrame() + except ValueError as e: + dataframe =pd.DataFrame() + return dataframe + +@gui_bp.route('/webui') +def home(): + session['enter'] = False + # Leer las IPs actuales del archivo de configuración + try: + with open(os.path.join(SRC_PATH, 'IPs.json')) as f: + ips = json.load(f) + tfs_ip = ips.get('TFS_IP', 'No configurada') + ixia_ip = ips.get('IXIA_IP', 'No configurada') + except Exception: + tfs_ip = 'No configurada' + ixia_ip = 'No configurada' + return render_template('welcome.html', tfs_ip=tfs_ip, ixia_ip=ixia_ip) + +@gui_bp.route('/webui/generate/tfs', methods=['POST','GET']) +def generate_tfs(): + session['enter']=False + if request.method =='POST': + src_node_ip =request.form['src_node_ip'] + dst_node_ip =request.form['dst_node_ip'] + vlan_id =request.form['vlan_id'] + if vlan_id == '': + vlan_id = None + latency =request.form['latency_intent'] + bandwidth =request.form['bandwidth_intent'] + + slice_request = __build_request_ietf(src_node_ip=src_node_ip, dst_node_ip=dst_node_ip, vlan_id=vlan_id, latency=latency, bandwidth=bandwidth) + + # Si 'request' es un diccionario, conviértelo a JSON + json_data = json.dumps(slice_request) + files = { + 'file': ('ietf_template_example.json', json_data, 'application/json') + } + + response = requests.post( + f'http://localhost:{NSC_PORT}/tfs/slice', + headers={ + 'accept': 'application/json' + }, + files=files + ) + response.raise_for_status() + + if response.ok: + return redirect(url_for('gui.generate_tfs', src_node_ip=src_node_ip, dst_node_ip=dst_node_ip, vlan_id=vlan_id, latency=latency, bandwidth=bandwidth)) + else: + return render_template('index.html', error="Error al generar el intent") + + src_node_ip =request.args.get('src_node_ip', '') + dst_node_ip =request.args.get('dst_node_ip', '') + vlan_id =request.args.get('vlan_id', '') + latency =request.args.get('latency', '') + bandwidth =request.args.get('bandwidth', '') + reliability=request.args.get('reliability', '') + + return render_template('index.html', src_node_ip=src_node_ip, dst_node_ip=dst_node_ip, vlan_id=vlan_id, latency=latency, bandwidth=bandwidth, reliability=reliability) + +@gui_bp.route('/webui/generate/ixia', methods=['GET','POST']) +def generate_ixia(): + session['enter']=False + if request.method =='POST': + src_node_ip =request.form['src_node_ip'] + dst_node_ip =request.form['dst_node_ip'] + vlan_id =request.form['vlan_id'] + latency =request.form['latency_intent'] + bandwidth =request.form['bandwidth_intent'] + latency_version="internet" + tolerance= request.form['tolerance_intent'] + reliability=request.form['reliability'] + + if int(reliability)==100: reliability=None + slice_request = __build_request_ietf(src_node_ip=src_node_ip, dst_node_ip=dst_node_ip, vlan_id=vlan_id, bandwidth=bandwidth, latency=latency, latency_version=latency_version, tolerance=tolerance, reliability=reliability) + # Si 'request' es un diccionario, conviértelo a JSON + json_data = json.dumps(slice_request) + files = { + 'file': ('ietf_template_example.json', json_data, 'application/json') + } + + try: + response = requests.post( + f'http://localhost:{NSC_PORT}/ixia/slice', + headers={'accept': 'application/json'}, + files=files + ) + response.raise_for_status() + if response.ok: + return redirect(url_for('gui.generate_ixia', src_node_ip=src_node_ip, dst_node_ip=dst_node_ip, vlan_id=vlan_id, latency=latency, tolerance=tolerance,bandwidth=bandwidth,reliability=reliability)) + except requests.RequestException as e: + print("HTTP error:", e) + return render_template('ixia.html', error="Intent Generation Error") + + src_node_ip =request.args.get('src_node_ip', '') + dst_node_ip =request.args.get('dst_node_ip', '') + vlan_id =request.args.get('vlan_id', '') + latency =request.args.get('latency', '') + tolerance=request.args.get('tolerance', '') + bandwidth =request.args.get('bandwidth', '') + reliability=request.args.get('reliability','') + + return render_template('ixia.html', src_node_ip=src_node_ip, dst_node_ip=dst_node_ip, vlan_id=vlan_id, latency=latency, tolerance=tolerance, bandwidth=bandwidth, reliability=reliability) + + +@gui_bp.route('/webui/dev', methods=['GET', 'POST']) +def develop(): + print('Session content:', dict(session)) + if 'enter' not in session or session['enter'] is False: + return redirect(url_for('gui.login')) + + if request.method == 'POST': + ip_version = request.form.get('ip_version', '') + src_node_ipv4 = request.form.get('src_node_ipv4', '') + dst_node_ipv4 = request.form.get('dst_node_ipv4', '') + src_node_ipv6 = request.form.get('src_node_ipv6', '') + dst_node_ipv6 = request.form.get('dst_node_ipv6', '') + vlan_id = request.form.get('vlan_id', '') + bandwidth = request.form.get('bandwidth_intent', '') + latency = request.form.get('latency_intent', '') + latency_version = request.form.get('delay_statistic', '') + tolerance = request.form.get('max_delay', '') + packet_reorder = request.form.get('packet_options', '') + num_pack = request.form.get('numPack', '') + pack_reorder = request.form.get('packReod', '') + num_reorder = request.form.get('numReod', '') + max_reorder = request.form.get('num_maxReod', '') + desv_reorder = request.form.get('desv_reord', '') + drop_version = request.form.get('object_options', '') + packets_drop = request.form.get('packets', '') + drops = request.form.get('drop', '') + desv_drop = request.form.get('desv_drop', '') + + json_data = __build_request(ip_version=ip_version, src_node_ip=src_node_ipv4, dst_node_ip=dst_node_ipv4, src_node_ipv6=src_node_ipv6, dst_node_ipv6=dst_node_ipv6, vlan_id=vlan_id, latency=latency, bandwidth=bandwidth, latency_version=latency_version, tolerance=tolerance, packet_reorder=packet_reorder, num_pack=num_pack, pack_reorder=pack_reorder, num_reorder=num_reorder, max_reorder=max_reorder, desv_reorder=desv_reorder, drop_version=drop_version, packets_drop=packets_drop, drops=drops, desv_drop=desv_drop) + logging.debug("Generated JSON data: %s", json_data) + if not DUMMY_MODE: + NEII_controller().nscNEII(json_data) + + session['enter'] = True + return render_template('dev.html', + json_data=json_data, + src_node_ip=src_node_ipv4 or src_node_ipv6, + dst_node_ip=dst_node_ipv4 or dst_node_ipv6, + vlan_id=vlan_id, + latency=latency, + bandwidth=bandwidth, + latency_version=latency_version, + tolerance=tolerance, + packet_reorder=packet_reorder, + num_pack=num_pack, + pack_reorder=pack_reorder, + num_reorder=num_reorder, + max_reorder=max_reorder, + desv_reorder=desv_reorder, + packets_drop=packets_drop, + drops=drops, + desv_drop=desv_drop + ) + + return render_template('dev.html', + src_node_ip=request.args.get('src_node_ip', ''), + dst_node_ip=request.args.get('dst_node_ip', ''), + vlan_id=request.args.get('vlan_id', ''), + latency=request.args.get('latency', ''), + bandwidth=request.args.get('bandwidth', ''), + latency_version=request.args.get('latency_version', ''), + tolerance=request.args.get('max_latency', ''), + packet_reorder=request.args.get('packet_reorder', ''), + num_pack=request.args.get('num_pack', ''), + pack_reorder=request.args.get('pack_reorder', ''), + num_reorder=request.args.get('num_reorder', ''), + max_reorder=request.args.get('max_reorder', ''), + desv_reorder=request.args.get('desv', ''), + packets_drop=request.args.get('packets_drop', ''), + drops=request.args.get('drop', ''), + desv_drop=request.args.get('desv_drop', ''), + json_data=None + ) + +@gui_bp.route('/webui/search', methods=['GET', 'POST']) +def search(): + + session['enter'] = False + + try: + response = requests.get(f"http://localhost:{NSC_PORT}/tfs/slice", headers={"accept": "application/json"}) + response.raise_for_status() + tfs_slices = response.json() + + response = requests.get(f"http://localhost:{NSC_PORT}/ixia/slice", headers={"accept": "application/json"}) + response.raise_for_status() + ixia_slices = response.json() + + # Combinar los slices de TFS e IXIA + slices = tfs_slices + ixia_slices + + except requests.RequestException as e: + logging.error("Error fetching slices: %s", e) + return render_template('search.html', error="No se pudieron obtener los slices.", dataframe_html="") + + # Extraer datos relevantes y construir un DataFrame + rows = [] + for item in slices: + try: + slice_service = item["intent"]["ietf-network-slice-service:network-slice-services"]["slice-service"][0] + sdp = slice_service["sdps"]["sdp"] + metric_bound = item["intent"]["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"] + + source_ip = sdp[0]["sdp-ip-address"] + dest_ip = sdp[1]["sdp-ip-address"] + vlan = sdp[0]["service-match-criteria"]["match-criterion"][0]["value"] + controller = item["controller"] + + # Construir atributos dinámicamente + attributes = [] + for metric in metric_bound: + if metric.get("metric-type", "") == "one-way-bandwidth": + metric_type = "bandwidth" + elif metric.get("metric-type", "") == "one-way-delay-maximum": + metric_type = "latency" + elif metric.get("metric-type", "") == "one-way-delay-variation-maximum": + metric_type = "tolerance" + bound = metric.get("bound") + unit = metric.get("metric-unit", "") + if bound is not None: + attributes.append(f"{metric_type}: {bound} {unit}") + + rows.append({ + "Source IP": source_ip, + "Destiny IP": dest_ip, + "Controller": controller, + "VLAN": vlan, + "attributes": attributes + }) + except Exception as e: + print(f"Error procesando slice: {e}") + + + import pandas as pd + dataframe = pd.DataFrame(rows) + + def format_attributes(attributes): + formatted_attrs = [] + for attr in attributes: + formatted_attrs.append(attr) + if formatted_attrs: + return formatted_attrs + else: + return None + + dataframe['attributes'] = dataframe['attributes'].apply([format_attributes]) + + if request.method == 'POST': + search_option = request.form.get('search_option') + search_value = request.form.get('search_value') + if search_option == 'Source IP': + results = dataframe[dataframe['Source IP'] == search_value] + elif search_option == 'Destiny IP': + results = dataframe[dataframe['Destiny IP'] == search_value] + elif search_option == 'Controller': + results = dataframe[dataframe['Controller'] == search_value] + elif search_option == 'VLAN': + results = dataframe[dataframe['VLAN'] == search_value] + else: + results = dataframe + result_html = results.to_html(classes='table table-striped') + return jsonify({'result': result_html}) + + dataframe_html = dataframe.to_html(classes='table table-striped') + return render_template('search.html', dataframe_html=dataframe_html) + +@gui_bp.route('/webui/login', methods=['GET', 'POST']) +def login(): + global enter + if request.method == 'POST': + username = request.form['username'] + password = request.form['password'] + if username == USERNAME and password == PASSWORD: + session['enter']=True + return redirect(url_for('gui.develop')) + else: + return render_template('login.html', error="Credenciales incorrectas") + + return render_template('login.html') + +@gui_bp.route('/webui/reset', methods=['POST']) +def reset(): + dataframe=__datos_json() + dataframe_html =dataframe.to_html(classes='table table-striped') + return jsonify({'result': dataframe_html}) + +@gui_bp.route('/webui/update_ips', methods=['POST']) +def update_ips(): + data = request.get_json() + tfs_ip = data.get('tfs_ip') + ixia_ip = data.get('ixia_ip') + + # Cargar datos existentes si el archivo existe + config_path = os.path.join(SRC_PATH, 'IPs.json') + if os.path.exists(config_path): + with open(config_path) as f: + ips = json.load(f) + else: + ips = {"TFS_IP": "", "IXIA_IP": ""} + + # Actualizar solo los campos recibidos + if tfs_ip: + ips['TFS_IP'] = tfs_ip + if ixia_ip: + ips['IXIA_IP'] = ixia_ip + + # Guardar de nuevo el archivo con los valores actualizados + with open(config_path, 'w') as f: + json.dump(ips, f, indent=4) + + return '', 200 \ No newline at end of file diff --git a/src/webui/static/img/MiniLogo.png b/src/webui/static/img/MiniLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..97ebca3d17c0fe8e41cbe1159ed479b26c549359 Binary files /dev/null and b/src/webui/static/img/MiniLogo.png differ diff --git a/src/webui/static/img/TelefonicaLogo.png b/src/webui/static/img/TelefonicaLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..36a8be0e95a62016a680722ced4b392a9dd24f1d Binary files /dev/null and b/src/webui/static/img/TelefonicaLogo.png differ diff --git a/src/webui/static/img/banner.png b/src/webui/static/img/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..9fee130dcd0aca7550c5101855bf2de91fc469a8 Binary files /dev/null and b/src/webui/static/img/banner.png differ diff --git a/src/webui/templates/dev.html b/src/webui/templates/dev.html new file mode 100644 index 0000000000000000000000000000000000000000..7a18ecc9c9577eea29ec69a80cdc2142b07b7704 --- /dev/null +++ b/src/webui/templates/dev.html @@ -0,0 +1,474 @@ + + + + + + + + + + + + + + + + + + + + + + Intent Generation + + + + + +
+ + + + +
+
+

Intent Generation:

+ +
+
+
+ +
+
+ + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+ + +
+
+ + +
+
+ +
+ + +
+ + +
+ + +
+
+ + +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/src/webui/templates/index.html b/src/webui/templates/index.html new file mode 100644 index 0000000000000000000000000000000000000000..bef6b7ac3f4b3df673bce0751d5259e236b06262 --- /dev/null +++ b/src/webui/templates/index.html @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + Slice Creation + + + + +
+ + + + + +
+

Slice Creation

+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+ + +
+ + {% if error %} +
{{ error }}
+ {% endif %} + + {% if src_node_ip and dst_node_ip %} +
+

Intent Generated:

+
+

Source IP: {{ src_node_ip }}

+

Destiny IP: {{ dst_node_ip }}

+

VLAN ID: {{ vlan_id }}

+

Latency [ms]: {{ latency }}

+

Bandwidth [Mbps]: {{ bandwidth }}

+
+
+ {% endif %} +
+
+ + + + + + + diff --git a/src/webui/templates/ixia.html b/src/webui/templates/ixia.html new file mode 100644 index 0000000000000000000000000000000000000000..f9821e81bfe3c9c5098155fdacfeeae449b77d85 --- /dev/null +++ b/src/webui/templates/ixia.html @@ -0,0 +1,264 @@ + + + + + + + + + + + + + + + + + + + + + IXIA: Slice Creation + + + + +
+ + + +
+

IXIA: Slice Creation

+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + + (Activar) +
+ +
+ El valor debe estar entre 51 y 100. +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+ + {% if error %} +
{{ error }}
+ {% endif %} + + {% if src_node_ip and dst_node_ip %} +
+

Intent Generated:

+
+

Source IP: {{ src_node_ip }}

+

Destiny IP: {{ dst_node_ip }}

+

VLAN ID: {{ vlan_id }}

+

Latency [ms]: {{ latency }}

+

Tolerance [ms]: {{ tolerance }}

+

Bandwidth [Mbps]: {{ bandwidth }}

+

Reliability: {{ reliability or 100 }}

+
+
+ {% endif %} +
+ +
+ + + + + + + + + diff --git a/src/webui/templates/login.html b/src/webui/templates/login.html new file mode 100644 index 0000000000000000000000000000000000000000..5dd54b61e4303b3502cafdc0c4b020ed536fab8d --- /dev/null +++ b/src/webui/templates/login.html @@ -0,0 +1,207 @@ + + + + + + + + + + + + + + + + + + + + + Login + + + + +
+ + + + +
+ +
+
+ + + + diff --git a/src/webui/templates/search.html b/src/webui/templates/search.html new file mode 100644 index 0000000000000000000000000000000000000000..6ace2c126f20e95d73bf9fe480bb80a357676b2b --- /dev/null +++ b/src/webui/templates/search.html @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + Search Slice Data + + + + +
+ + + +

Search Slice Data

+

Fill in the fields below to search for data in the table:

+
+
+ + +
+
+ + +
+ + +
+
+
+ {{ dataframe_html|safe }} +
+
+
+ + + + + + diff --git a/src/webui/templates/welcome.html b/src/webui/templates/welcome.html new file mode 100644 index 0000000000000000000000000000000000000000..3fa27b2355a99e3f5c2250e5ecf156670874882c --- /dev/null +++ b/src/webui/templates/welcome.html @@ -0,0 +1,189 @@ + + + + + + + + + + + + + + + + + + + + + NSC WebUI + + + + + +
+ + +
+

Welcome to the NSC WebUI

+

Please, choose the controller you would like to use:

+
+ + {{ tfs_ip }} + WebUI +
+
+ + {{ ixia_ip }} + WebUI +
+
+
+ + + + \ No newline at end of file diff --git a/swagger/ixia_namespace.py b/swagger/ixia_namespace.py new file mode 100644 index 0000000000000000000000000000000000000000..6a14ffe995ad0fb2228c2d8deaf6dd91060ea510 --- /dev/null +++ b/swagger/ixia_namespace.py @@ -0,0 +1,112 @@ +from flask import request +from flask_restx import Namespace, Resource, fields, reqparse +from src.network_slice_controller import NSController +import json +from swagger.models.create_models import create_gpp_nrm_28541_model, create_ietf_network_slice_nbi_yang_model + +ixia_ns = Namespace( + "ixia", + description="Operations related to transport network slices with IXIA NEII" +) + +# 3GPP NRM TS28.541 Data models +gpp_network_slice_request_model = create_gpp_nrm_28541_model(ixia_ns) + +# IETF draft-ietf-teas-ietf-network-slice-nbi-yang Data models + +slice_ddbb_model, slice_response_model = create_ietf_network_slice_nbi_yang_model(ixia_ns) + +upload_parser = reqparse.RequestParser() +upload_parser.add_argument('file', location='files', type='FileStorage', help="Archivo a subir") +upload_parser.add_argument('json_data', location='form', help="Datos JSON en formato string") + +# Namespace Controllers +@ixia_ns.route("/slice") +class IxiaSliceList(Resource): + @ixia_ns.doc(summary="Return all transport network slices", description="Returns all transport network slices from the slice controller.") + @ixia_ns.response(200, "Slices returned", slice_ddbb_model) + @ixia_ns.response(404, "Transport network slices not found") + @ixia_ns.response(500, "Internal server error") + def get(self): + """Retrieve all slices""" + controller = NSController(controller_type="IXIA") + return controller.get_flows() + + @ixia_ns.doc(summary="Submit a transport network slice request", description="This endpoint allows clients to submit transport network slice requests using a JSON payload.") + @ixia_ns.response(200, "Slice request successfully processed", slice_response_model) + @ixia_ns.response(400, "Invalid request format") + @ixia_ns.response(500, "Internal server error") + @ixia_ns.expect(upload_parser) + def post(self): + """Submit a new slice request with a file""" + + json_data = None + + # Try to get the JSON data from the uploaded file + uploaded_file = request.files.get('file') + if uploaded_file: + if not uploaded_file.filename.endswith('.json'): + return {"error": "Only JSON files allowed"}, 400 + + try: + json_data = json.load(uploaded_file) # Convert file to JSON + except json.JSONDecodeError: + return {"error": "JSON file not valid"}, 400 + + # If no file was uploaded, try to get the JSON data from the form + if json_data is None: + raw_json = request.form.get('json_data') + if raw_json: + try: + json_data = json.loads(raw_json) # Convert string to JSON + except json.JSONDecodeError: + return {"error": "JSON file not valid"}, 400 + + # If no JSON data was found, return an error + if json_data is None: + return {"error": "No data sent"}, 400 + + # Process the JSON data with the NSController + controller = NSController(controller_type="IXIA") + return controller.add_flow(json_data) + + @ixia_ns.doc(summary="Delete all transport network slices", description="Deletes all transport network slices from the slice controller.") + @ixia_ns.response(200, "All transport network slices deleted successfully.") + @ixia_ns.response(500, "Internal server error") + def delete(self): + """Delete all slices""" + controller = NSController(controller_type="IXIA") + return controller.delete_flows() + + +@ixia_ns.route("/slice/") +@ixia_ns.doc(params={"slice_id": "The ID of the slice to retrieve or modify"}) +class IxiaSlice(Resource): + @ixia_ns.doc(summary="Return a specific transport network slice", description="Returns specific information related to a slice by providing its id") + @ixia_ns.response(200, "Slice returned", slice_ddbb_model) + @ixia_ns.response(404, "Transport network slice not found.") + @ixia_ns.response(500, "Internal server error") + def get(self, slice_id): + """Retrieve a specific slice""" + controller = NSController(controller_type="IXIA") + return controller.get_flows(slice_id) + + @ixia_ns.doc(summary="Delete a specific transport network slice", description="Deletes a specific transport network slice from the slice controller based on the provided `slice_id`.") + @ixia_ns.response(200, "Transport network slice deleted successfully.") + @ixia_ns.response(404, "Transport network slice not found.") + @ixia_ns.response(500, "Internal server error") + def delete(self, slice_id): + """Delete a slice""" + controller = NSController(controller_type="IXIA") + return controller.delete_flows(slice_id) + + @ixia_ns.expect(slice_ddbb_model, validate=True) + @ixia_ns.doc(summary="Modify a specific transport network slice", description="Returns a specific slice that has been modified") + @ixia_ns.response(200, "Slice modified", slice_ddbb_model) + @ixia_ns.response(404, "Transport network slice not found.") + @ixia_ns.response(500, "Internal server error") + def put(self, slice_id): + """Modify a slice""" + json_data = request.get_json() + controller = NSController(controller_type="IXIA") + return controller.modify_flow(slice_id, json_data) \ No newline at end of file diff --git a/swagger/slice_namespace.py b/swagger/tfs_namespace.py similarity index 52% rename from swagger/slice_namespace.py rename to swagger/tfs_namespace.py index 0f629f97e1a8ecbf4550f3e5a24e5ecca46c15ae..c9c3e07f591d13390df92712a746843a8d2326bd 100644 --- a/swagger/slice_namespace.py +++ b/swagger/tfs_namespace.py @@ -20,39 +20,39 @@ from src.network_slice_controller import NSController import json from swagger.models.create_models import create_gpp_nrm_28541_model, create_ietf_network_slice_nbi_yang_model -slice_ns = Namespace( - "slice", - description="Operations related to transport network slices" +tfs_ns = Namespace( + "tfs", + description="Operations related to transport network slices with TeraflowSDN (TFS) controller" ) # 3GPP NRM TS28.541 Data models -gpp_network_slice_request_model = create_gpp_nrm_28541_model(slice_ns) +gpp_network_slice_request_model = create_gpp_nrm_28541_model(tfs_ns) # IETF draft-ietf-teas-ietf-network-slice-nbi-yang Data models -slice_ddbb_model, slice_response_model = create_ietf_network_slice_nbi_yang_model(slice_ns) +slice_ddbb_model, slice_response_model = create_ietf_network_slice_nbi_yang_model(tfs_ns) upload_parser = reqparse.RequestParser() upload_parser.add_argument('file', location='files', type='FileStorage', help="Archivo a subir") upload_parser.add_argument('json_data', location='form', help="Datos JSON en formato string") # Namespace Controllers -@slice_ns.route("/") -class SliceList(Resource): - @slice_ns.doc(summary="Return all transport network slices", description="Returns all transport network slices from the slice controller.") - @slice_ns.response(200, "Slices returned", slice_ddbb_model) - @slice_ns.response(404, "Transport network slices not found") - @slice_ns.response(500, "Internal server error") +@tfs_ns.route("/slice") +class TfsSliceList(Resource): + @tfs_ns.doc(summary="Return all transport network slices", description="Returns all transport network slices from the slice controller.") + @tfs_ns.response(200, "Slices returned", slice_ddbb_model) + @tfs_ns.response(404, "Transport network slices not found") + @tfs_ns.response(500, "Internal server error") def get(self): """Retrieve all slices""" - controller = NSController() + controller = NSController(controller_type="TFS") return controller.get_flows() - @slice_ns.doc(summary="Submit a transport network slice request", description="This endpoint allows clients to submit transport network slice requests using a JSON payload.") - @slice_ns.response(200, "Slice request successfully processed", slice_response_model) - @slice_ns.response(400, "Invalid request format") - @slice_ns.response(500, "Internal server error") - @slice_ns.expect(upload_parser) + @tfs_ns.doc(summary="Submit a transport network slice request", description="This endpoint allows clients to submit transport network slice requests using a JSON payload.") + @tfs_ns.response(200, "Slice request successfully processed", slice_response_model) + @tfs_ns.response(400, "Invalid request format") + @tfs_ns.response(500, "Internal server error") + @tfs_ns.expect(upload_parser) def post(self): """Submit a new slice request with a file""" @@ -83,46 +83,48 @@ class SliceList(Resource): return {"error": "No data sent"}, 400 # Process the JSON data with the NSController - controller = NSController() + controller = NSController(controller_type="TFS") return controller.add_flow(json_data) - @slice_ns.doc(summary="Delete all transport network slices", description="Deletes all transport network slices from the slice controller.") - @slice_ns.response(200, "All transport network slices deleted successfully.") - @slice_ns.response(500, "Internal server error") + @tfs_ns.doc(summary="Delete all transport network slices", description="Deletes all transport network slices from the slice controller.") + @tfs_ns.response(200, "All transport network slices deleted successfully.") + @tfs_ns.response(500, "Internal server error") def delete(self): """Delete all slices""" - controller = NSController() + controller = NSController(controller_type="TFS") return controller.delete_flows() -@slice_ns.route("/") -@slice_ns.doc(params={"slice_id": "The ID of the slice to retrieve or modify"}) -class Slice(Resource): - @slice_ns.doc(summary="Return a specific transport network slice", description="Returns specific information related to a slice by providing its id") - @slice_ns.response(200, "Slice returned", slice_ddbb_model) - @slice_ns.response(404, "Transport network slice not found.") - @slice_ns.response(500, "Internal server error") +@tfs_ns.route("/slice/") +@tfs_ns.doc(params={"slice_id": "The ID of the slice to retrieve or modify"}) +class TfsSlice(Resource): + @tfs_ns.doc(summary="Return a specific transport network slice", description="Returns specific information related to a slice by providing its id") + @tfs_ns.response(200, "Slice returned", slice_ddbb_model) + @tfs_ns.response(404, "Transport network slice not found.") + @tfs_ns.response(500, "Internal server error") def get(self, slice_id): """Retrieve a specific slice""" - controller = NSController() + controller = NSController(controller_type="TFS") return controller.get_flows(slice_id) - @slice_ns.doc(summary="Delete a specific transport network slice", description="Deletes a specific transport network slice from the slice controller based on the provided `slice_id`.") - @slice_ns.response(200, "Transport network slice deleted successfully.") - @slice_ns.response(404, "Transport network slice not found.") - @slice_ns.response(500, "Internal server error") + @tfs_ns.doc(summary="Delete a specific transport network slice", description="Deletes a specific transport network slice from the slice controller based on the provided `slice_id`.") + @tfs_ns.response(200, "Transport network slice deleted successfully.") + @tfs_ns.response(404, "Transport network slice not found.") + @tfs_ns.response(500, "Internal server error") def delete(self, slice_id): """Delete a slice""" - controller = NSController() + controller = NSController(controller_type="TFS") return controller.delete_flows(slice_id) - @slice_ns.expect(slice_ddbb_model, validate=True) - @slice_ns.doc(summary="Modify a specific transport network slice", description="Returns a specific slice that has been modified") - @slice_ns.response(200, "Slice modified", slice_ddbb_model) - @slice_ns.response(404, "Transport network slice not found.") - @slice_ns.response(500, "Internal server error") + @tfs_ns.expect(slice_ddbb_model, validate=True) + @tfs_ns.doc(summary="Modify a specific transport network slice", description="Returns a specific slice that has been modified") + @tfs_ns.response(200, "Slice modified", slice_ddbb_model) + @tfs_ns.response(404, "Transport network slice not found.") + @tfs_ns.response(500, "Internal server error") def put(self, slice_id): """Modify a slice""" json_data = request.get_json() - controller = NSController() + controller = NSController(controller_type="TFS") return controller.modify_flow(slice_id, json_data) + +