Loading proto/context.proto +1 −1 Original line number Diff line number Diff line Loading @@ -555,7 +555,7 @@ message ConfigRule_IPOWDM { message ConfigRule_TAPI_LSP { EndPointId endpoint_id = 1; tapi_lsp.TapiLspRuleSet rule_set = 2; repeated tapi_lsp.TapiLspRuleSet rule_set = 2; } message ConfigRule { Loading proto/tapi_lsp.proto +6 −2 Original line number Diff line number Diff line Loading @@ -16,8 +16,8 @@ syntax = "proto3"; package tapi_lsp; message TapiLspRuleSet { string src = 1; string dst = 2; string input_sip = 1; string output_sip = 2; string uuid = 3; string bw = 4; string tenant_uuid = 5; Loading @@ -29,4 +29,8 @@ message TapiLspRuleSet { string granularity = 11; string grid_type = 12; string direction = 13; string capacity_unit = 14; string capacity_value = 15; string route_objective_function = 16; string url = 17; } No newline at end of file src/device/service/drivers/ietf_l3vpn/IetfL3VpnDriver.py +9 −1 Original line number Diff line number Diff line Loading @@ -23,7 +23,7 @@ from device.service.driver_api.ImportTopologyEnum import ImportTopologyEnum, get from .Constants import SPECIAL_RESOURCE_MAPPINGS from .TfsApiClient import TfsApiClient from .Tools import compose_resource_endpoint from .templates.tools import create_request from .templates.tools import create_request, tapi_tequest LOGGER = logging.getLogger(__name__) Loading Loading @@ -187,6 +187,14 @@ class IetfL3VpnDriver(_Driver): except Exception as e: MSG = 'Invalid resource_value type: expected dict, got {:s}' results.append((resource, e)) elif "tapi_lsp" in str(resources): for resource in resources: try: tapi_tequest(resource) results.append((resource, True)) except Exception as e: MSG = "Invalid resource_value type: expected dict, got {:s}" results.append((resource, e)) else: for resource in resources: resource_key, resource_value = resource Loading src/device/service/drivers/ietf_l3vpn/templates/tools.py +102 −2 Original line number Diff line number Diff line Loading @@ -13,7 +13,9 @@ # limitations under the License. import json import logging import os import requests from concurrent.futures import ThreadPoolExecutor LOGGER = logging.getLogger(__name__) Loading @@ -22,6 +24,8 @@ HEADERS = { "Content-Type": "application/yang-data+json" } executor = ThreadPoolExecutor() site_template = { "site-id": "", "devices": { Loading Loading @@ -153,3 +157,99 @@ def patch_optical_channel_frequency(data, DEVICE_ID): headers=HEADERS) assert response.status_code == 200 return response def process_uuid(service, url): headers = { "Content-Type": "application/json", "Accept": "application/json" } LOGGER.info(f"Processing service {service} to URL: {url}") try: response = 200 # requests.post(url = url, json=service, headers=headers, timeout=300) LOGGER.info("Response Status code: %s", response) except requests.exceptions.RequestException as e: LOGGER.info(f"ERROR equest to {service} failed: {e}") def tapi_tequest(resource_value): services, urls = build_tapi_connectivity(resource_value) for service, url in zip(services, urls): LOGGER.info(f"Services to be processed: {json.dumps(service, indent=2)}") LOGGER.info(f"URL to be used: {url}") executor.submit(process_uuid, service, url) def build_tapi_connectivity(service_data): logging.info(f"Building TAPI connectivity for services data: {service_data}") outputs = [] urls = [] rules_set = service_data[1]["rule_set"] for rule_set in rules_set: direction = rule_set["direction"] layer_name = rule_set["layer_protocol_name"] layer_qualifier = rule_set["layer_protocol_qualifier"] urls.append(rule_set["url"]) cs = { "uuid": rule_set["tenant_uuid"], "connectivity-direction": direction, "layer-protocol-name": layer_name, "layer-protocol-qualifier": layer_qualifier, "end-point": [] } endpoints = [] if direction == "UNIDIRECTIONAL": endpoints.append({ "layer-protocol-name": layer_name, "layer-protocol-qualifier": layer_qualifier, "service-interface-point": {"service-interface-point-uuid": rule_set["src"]}, "direction:": "INPUT", "local-id": rule_set["src"] }) endpoints.append({ "layer-protocol-name": layer_name, "layer-protocol-qualifier": layer_qualifier, "service-interface-point": {"service-interface-point-uuid": rule_set["dst"]}, "direction:": "OUTPUT", "local-id": rule_set["dst"] }) else: for point in [rule_set["src"], rule_set["dst"]]: ep = { "layer-protocol-name": layer_name, "layer-protocol-qualifier": layer_qualifier, "service-interface-point": {"service-interface-point-uuid": point}, "direction:": "BIDIRECTIONAL", "local-id": point } if rule_set.get("lower_frequency_mhz") != "NONE": ep["tapi-photonic-media:media-channel-connectivity-service-end-point-spec"] = { "mc-config": { "spectrum": { "frequency-constraint": { "adjustment-granularity": rule_set.get("granularity", "NONE"), "grid-type": rule_set.get("grid_type", "NONE") }, "lower-frequency": rule_set["lower_frequency_mhz"], "upper-frequency": rule_set["upper_frequency_mhz"] } } } endpoints.append(ep) cs["end-point"] = endpoints route_obj = rule_set.get("route_objective_function", "UNSPECIFIED") cs["route-objective-function"] = route_obj if route_obj != "NONE" else "10000" capacity = rule_set.get("capacity", "NONE") if capacity != "NONE": parts = capacity.split("-") value = parts[0] unit = parts[1] if len(parts) > 1 else "" cs["requested-capacity"] = { "total-size": {"value": value, "unit": unit} } outputs.append({"tapi-connectivity:connectivity-service": [cs]}) return outputs, urls src/nbi/service/e2e_services/Resources.py +29 −1 Original line number Diff line number Diff line Loading @@ -20,6 +20,9 @@ from flask_restful import Resource from common.Constants import DEFAULT_CONTEXT_NAME from service.client.ServiceClient import ServiceClient from .Tools import grpc_service_id from concurrent.futures import ThreadPoolExecutor import requests import threading LOGGER = logging.getLogger(__name__) Loading @@ -29,6 +32,10 @@ HEADERS = { "Content-Type": "application/yang-data+json" } headers = { "Content-Type": "application/json", "Expect": "" } class E2EInfoDelete(Resource): def __init__(self): super().__init__() Loading Loading @@ -58,7 +65,18 @@ class E2EInfoDelete(Resource): LOGGER.debug(f"NODE DATA: \n{name}:{device}") response = test_patch_optical_channel_frequency(device, name) LOGGER.debug(f"RESPONSE :\n {response}") elif 'tapi_lsp' in allocationId: service_id = str(allocationId.split('=')[1]) service_id_list = [s.strip() for s in service_id.split(',')] service_id = service_id_list[0] LOGGER.info("Service ID list: %s", service_id_list) executor = ThreadPoolExecutor(max_workers=len(service_id_list)) for key in service_id_list: executor.submit(delete_slice, key, headers) threading.Thread(target=executor.shutdown, kwargs={'wait': True}).start() else: LOGGER.error("Unknown service type for allocationId: %s", allocationId) return { Loading @@ -74,6 +92,16 @@ class E2EInfoDelete(Resource): 'allocationId': allocationId, }, 200 def delete_slice(key, headers): url_delete_slice = f'http://172.24.36.54:4900/restconf/data/tapi-common:context/tapi-connectivity:connectivity-context/connectivity-service={key}' try: # response = requests.delete(url=url_delete_slice, headers=headers, timeout=300) LOGGER.info("Key: %s", key) # LOGGER.info("Response Status code: %s", response.status_code) # LOGGER.info("Response Text: %s", response.text) except requests.exceptions.RequestException as e: LOGGER.info(f"ERROR request to delete slice {key} failed: {e}") def test_patch_optical_channel_frequency(data, DEVICE_ID): """Test PATCH to update optical channel frequency.""" # Use simple path with / and encode manually for component name Loading Loading
proto/context.proto +1 −1 Original line number Diff line number Diff line Loading @@ -555,7 +555,7 @@ message ConfigRule_IPOWDM { message ConfigRule_TAPI_LSP { EndPointId endpoint_id = 1; tapi_lsp.TapiLspRuleSet rule_set = 2; repeated tapi_lsp.TapiLspRuleSet rule_set = 2; } message ConfigRule { Loading
proto/tapi_lsp.proto +6 −2 Original line number Diff line number Diff line Loading @@ -16,8 +16,8 @@ syntax = "proto3"; package tapi_lsp; message TapiLspRuleSet { string src = 1; string dst = 2; string input_sip = 1; string output_sip = 2; string uuid = 3; string bw = 4; string tenant_uuid = 5; Loading @@ -29,4 +29,8 @@ message TapiLspRuleSet { string granularity = 11; string grid_type = 12; string direction = 13; string capacity_unit = 14; string capacity_value = 15; string route_objective_function = 16; string url = 17; } No newline at end of file
src/device/service/drivers/ietf_l3vpn/IetfL3VpnDriver.py +9 −1 Original line number Diff line number Diff line Loading @@ -23,7 +23,7 @@ from device.service.driver_api.ImportTopologyEnum import ImportTopologyEnum, get from .Constants import SPECIAL_RESOURCE_MAPPINGS from .TfsApiClient import TfsApiClient from .Tools import compose_resource_endpoint from .templates.tools import create_request from .templates.tools import create_request, tapi_tequest LOGGER = logging.getLogger(__name__) Loading Loading @@ -187,6 +187,14 @@ class IetfL3VpnDriver(_Driver): except Exception as e: MSG = 'Invalid resource_value type: expected dict, got {:s}' results.append((resource, e)) elif "tapi_lsp" in str(resources): for resource in resources: try: tapi_tequest(resource) results.append((resource, True)) except Exception as e: MSG = "Invalid resource_value type: expected dict, got {:s}" results.append((resource, e)) else: for resource in resources: resource_key, resource_value = resource Loading
src/device/service/drivers/ietf_l3vpn/templates/tools.py +102 −2 Original line number Diff line number Diff line Loading @@ -13,7 +13,9 @@ # limitations under the License. import json import logging import os import requests from concurrent.futures import ThreadPoolExecutor LOGGER = logging.getLogger(__name__) Loading @@ -22,6 +24,8 @@ HEADERS = { "Content-Type": "application/yang-data+json" } executor = ThreadPoolExecutor() site_template = { "site-id": "", "devices": { Loading Loading @@ -153,3 +157,99 @@ def patch_optical_channel_frequency(data, DEVICE_ID): headers=HEADERS) assert response.status_code == 200 return response def process_uuid(service, url): headers = { "Content-Type": "application/json", "Accept": "application/json" } LOGGER.info(f"Processing service {service} to URL: {url}") try: response = 200 # requests.post(url = url, json=service, headers=headers, timeout=300) LOGGER.info("Response Status code: %s", response) except requests.exceptions.RequestException as e: LOGGER.info(f"ERROR equest to {service} failed: {e}") def tapi_tequest(resource_value): services, urls = build_tapi_connectivity(resource_value) for service, url in zip(services, urls): LOGGER.info(f"Services to be processed: {json.dumps(service, indent=2)}") LOGGER.info(f"URL to be used: {url}") executor.submit(process_uuid, service, url) def build_tapi_connectivity(service_data): logging.info(f"Building TAPI connectivity for services data: {service_data}") outputs = [] urls = [] rules_set = service_data[1]["rule_set"] for rule_set in rules_set: direction = rule_set["direction"] layer_name = rule_set["layer_protocol_name"] layer_qualifier = rule_set["layer_protocol_qualifier"] urls.append(rule_set["url"]) cs = { "uuid": rule_set["tenant_uuid"], "connectivity-direction": direction, "layer-protocol-name": layer_name, "layer-protocol-qualifier": layer_qualifier, "end-point": [] } endpoints = [] if direction == "UNIDIRECTIONAL": endpoints.append({ "layer-protocol-name": layer_name, "layer-protocol-qualifier": layer_qualifier, "service-interface-point": {"service-interface-point-uuid": rule_set["src"]}, "direction:": "INPUT", "local-id": rule_set["src"] }) endpoints.append({ "layer-protocol-name": layer_name, "layer-protocol-qualifier": layer_qualifier, "service-interface-point": {"service-interface-point-uuid": rule_set["dst"]}, "direction:": "OUTPUT", "local-id": rule_set["dst"] }) else: for point in [rule_set["src"], rule_set["dst"]]: ep = { "layer-protocol-name": layer_name, "layer-protocol-qualifier": layer_qualifier, "service-interface-point": {"service-interface-point-uuid": point}, "direction:": "BIDIRECTIONAL", "local-id": point } if rule_set.get("lower_frequency_mhz") != "NONE": ep["tapi-photonic-media:media-channel-connectivity-service-end-point-spec"] = { "mc-config": { "spectrum": { "frequency-constraint": { "adjustment-granularity": rule_set.get("granularity", "NONE"), "grid-type": rule_set.get("grid_type", "NONE") }, "lower-frequency": rule_set["lower_frequency_mhz"], "upper-frequency": rule_set["upper_frequency_mhz"] } } } endpoints.append(ep) cs["end-point"] = endpoints route_obj = rule_set.get("route_objective_function", "UNSPECIFIED") cs["route-objective-function"] = route_obj if route_obj != "NONE" else "10000" capacity = rule_set.get("capacity", "NONE") if capacity != "NONE": parts = capacity.split("-") value = parts[0] unit = parts[1] if len(parts) > 1 else "" cs["requested-capacity"] = { "total-size": {"value": value, "unit": unit} } outputs.append({"tapi-connectivity:connectivity-service": [cs]}) return outputs, urls
src/nbi/service/e2e_services/Resources.py +29 −1 Original line number Diff line number Diff line Loading @@ -20,6 +20,9 @@ from flask_restful import Resource from common.Constants import DEFAULT_CONTEXT_NAME from service.client.ServiceClient import ServiceClient from .Tools import grpc_service_id from concurrent.futures import ThreadPoolExecutor import requests import threading LOGGER = logging.getLogger(__name__) Loading @@ -29,6 +32,10 @@ HEADERS = { "Content-Type": "application/yang-data+json" } headers = { "Content-Type": "application/json", "Expect": "" } class E2EInfoDelete(Resource): def __init__(self): super().__init__() Loading Loading @@ -58,7 +65,18 @@ class E2EInfoDelete(Resource): LOGGER.debug(f"NODE DATA: \n{name}:{device}") response = test_patch_optical_channel_frequency(device, name) LOGGER.debug(f"RESPONSE :\n {response}") elif 'tapi_lsp' in allocationId: service_id = str(allocationId.split('=')[1]) service_id_list = [s.strip() for s in service_id.split(',')] service_id = service_id_list[0] LOGGER.info("Service ID list: %s", service_id_list) executor = ThreadPoolExecutor(max_workers=len(service_id_list)) for key in service_id_list: executor.submit(delete_slice, key, headers) threading.Thread(target=executor.shutdown, kwargs={'wait': True}).start() else: LOGGER.error("Unknown service type for allocationId: %s", allocationId) return { Loading @@ -74,6 +92,16 @@ class E2EInfoDelete(Resource): 'allocationId': allocationId, }, 200 def delete_slice(key, headers): url_delete_slice = f'http://172.24.36.54:4900/restconf/data/tapi-common:context/tapi-connectivity:connectivity-context/connectivity-service={key}' try: # response = requests.delete(url=url_delete_slice, headers=headers, timeout=300) LOGGER.info("Key: %s", key) # LOGGER.info("Response Status code: %s", response.status_code) # LOGGER.info("Response Text: %s", response.text) except requests.exceptions.RequestException as e: LOGGER.info(f"ERROR request to delete slice {key} failed: {e}") def test_patch_optical_channel_frequency(data, DEVICE_ID): """Test PATCH to update optical channel frequency.""" # Use simple path with / and encode manually for component name Loading