diff --git a/manifests/e2eorchestratorservice.yaml b/manifests/e2eorchestratorservice.yaml index ba2e4fabddd89df539831ff5b68cc3c8fd77efdb..aefe554ce3375e3200c7ea1133fc9b489a6f386b 100644 --- a/manifests/e2eorchestratorservice.yaml +++ b/manifests/e2eorchestratorservice.yaml @@ -43,10 +43,10 @@ spec: key: REDIS_PASSWORD readinessProbe: exec: - command: ["/bin/grpc_health_probe", "-addr=:10009"] + command: ["/bin/grpc_health_probe", "-addr=:10040"] livenessProbe: exec: - command: ["/bin/grpc_health_probe", "-addr=:10009"] + command: ["/bin/grpc_health_probe", "-addr=:10040"] resources: requests: cpu: 250m diff --git a/proto/context.proto b/proto/context.proto index 4068bf1f85fc6d4fa74f08dab5434c4a97d2350f..9c2bbea21c5d0217929f6787293a18bf5096e5b9 100644 --- a/proto/context.proto +++ b/proto/context.proto @@ -201,6 +201,7 @@ enum DeviceDriverEnum { DEVICEDRIVER_XR = 6; DEVICEDRIVER_IETF_L2VPN = 7; DEVICEDRIVER_GNMI_OPENCONFIG = 8; + DEVICEDRIVER_FLEXSCALE = 9; } enum DeviceOperationalStatusEnum { diff --git a/src/context/service/database/models/enums/DeviceDriver.py b/src/context/service/database/models/enums/DeviceDriver.py index 66635decc5369c8b7601863da85f497626d70ac8..f8483360191dcea1a56cdc372b681ae2d03c9ef1 100644 --- a/src/context/service/database/models/enums/DeviceDriver.py +++ b/src/context/service/database/models/enums/DeviceDriver.py @@ -31,6 +31,7 @@ class ORM_DeviceDriverEnum(enum.Enum): XR = DeviceDriverEnum.DEVICEDRIVER_XR IETF_L2VPN = DeviceDriverEnum.DEVICEDRIVER_IETF_L2VPN GNMI_OPENCONFIG = DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG + FLEXSCALE = DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE grpc_to_enum__device_driver = functools.partial( grpc_to_enum, DeviceDriverEnum, ORM_DeviceDriverEnum) diff --git a/src/device/service/drivers/__init__.py b/src/device/service/drivers/__init__.py index 0d85e8ff9668c5715dfc9d830027a5ae1faed9b5..442acf839c8e4615237d338d7b485be297d1a4ff 100644 --- a/src/device/service/drivers/__init__.py +++ b/src/device/service/drivers/__init__.py @@ -148,3 +148,13 @@ if LOAD_ALL_DEVICE_DRIVERS: FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_XR, } ])) + +if LOAD_ALL_DEVICE_DRIVERS: + from .flexscale.FlexScaleDriver import FlexScaleDriver # pylint: disable=wrong-import-position + DRIVERS.append( + (FlexScaleDriver, [ + { + FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.OPEN_LINE_SYSTEM, + FilterFieldEnum.DRIVER: DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE, + } + ])) diff --git a/src/device/service/drivers/flexscale/FlexScaleDriver.py b/src/device/service/drivers/flexscale/FlexScaleDriver.py index 1733f504dcc0bca511a093c9b4b32a48127e8f47..23a7bc00631a5bbe1c3ce41f015d6df688c0e385 100644 --- a/src/device/service/drivers/flexscale/FlexScaleDriver.py +++ b/src/device/service/drivers/flexscale/FlexScaleDriver.py @@ -20,6 +20,9 @@ from common.type_checkers.Checkers import chk_string, chk_type from device.service.driver_api._Driver import _Driver from . import ALL_RESOURCE_KEYS from .Tools import find_key, add_lightpath, del_lightpath, get_lightpaths +from device.service.driver_api._Driver import _Driver, RESOURCE_ENDPOINTS +from device.service.drivers.ietf_l2vpn.TfsDebugApiClient import TfsDebugApiClient +from device.service.driver_api.ImportTopologyEnum import ImportTopologyEnum, get_import_topology LOGGER = logging.getLogger(__name__) @@ -37,9 +40,19 @@ class FlexScaleDriver(_Driver): password = self.settings.get('password') self.__auth = HTTPBasicAuth(username, password) if username is not None and password is not None else None scheme = self.settings.get('scheme', 'http') + self.dac = TfsDebugApiClient(self.address, int(self.port), scheme=scheme, username=username, password=password) self.__flexscale_root = '{:s}://{:s}:{:d}'.format(scheme, self.address, int(self.port)) self.__timeout = int(self.settings.get('timeout', 120)) + # Options are: + # disabled --> just import endpoints as usual + # devices --> imports sub-devices but not links connecting them. + # (a remotely-controlled transport domain might exist between them) + # topology --> imports sub-devices and links connecting them. + # (not supported by XR driver) + self.__import_topology = get_import_topology(self.settings, default=ImportTopologyEnum.TOPOLOGY) + + def Connect(self) -> bool: url = self.__flexscale_root + '/OpticalTFS/GetLightpaths' with self.__lock: @@ -75,8 +88,13 @@ class FlexScaleDriver(_Driver): for i, resource_key in enumerate(resource_keys): str_resource_name = 'resource_key[#{:d}]'.format(i) chk_string(str_resource_name, resource_key, allow_empty=False) - results.extend(get_lightpaths( - self.__flexscale_root, resource_key, timeout=self.__timeout, auth=self.__auth)) + + if resource_key == RESOURCE_ENDPOINTS: + # return endpoints through debug-api and list-devices method + results.extend(self.dac.get_devices_endpoints(self.__import_topology)) + + # results.extend(get_lightpaths( + # self.__flexscale_root, resource_key, timeout=self.__timeout, auth=self.__auth)) return results @metered_subclass_method(METRICS_POOL) @@ -88,12 +106,13 @@ class FlexScaleDriver(_Driver): for _, resource in resources: LOGGER.info('resource = {:s}'.format(str(resource))) - src_node = find_key(resource, 'src_node') - dst_node = find_key(resource, 'dst_node') - bitrate = find_key(resource, 'bitrate') + src_node = '1' # find_key(resource, 'src_node') + dst_node = '2' # find_key(resource, 'dst_node') + bitrate = '3' # find_key(resource, 'bitrate') response = add_lightpath(self.__flexscale_root, src_node, dst_node, bitrate, auth=self.__auth, timeout=self.__timeout) + results.extend(response) return results diff --git a/src/device/service/drivers/flexscale/Tools.py b/src/device/service/drivers/flexscale/Tools.py index 15b60d7656159b0a76fa9493de7af5d76f5aa076..1fffc20947bc4b79c37a9c026a1df1d298baf75b 100644 --- a/src/device/service/drivers/flexscale/Tools.py +++ b/src/device/service/drivers/flexscale/Tools.py @@ -26,6 +26,9 @@ HTTP_OK_CODES = { 204, # No Content } +def find_key(resource, key): + return json.loads(resource[1])[key] + def get_lightpaths(root_url : str, resource_key : str,auth : Optional[HTTPBasicAuth] = None, timeout : Optional[int] = None): headers = {'accept': 'application/json'} @@ -68,14 +71,61 @@ def add_lightpath(root_url, src_node, dst_node, bitrate, auth : Optional[HTTPBasicAuth] = None, timeout : Optional[int] = None): headers = {'accept': 'application/json'} - url = '{:s}/OpticalTFS/AddLightpath/{:s}/{:s}/{:s}'.format(root_url, src_node, dst_node, bitrate) + # url = '{:s}/OpticalTFS/AddLightpath/{:s}/{:s}/{:s}'.format(root_url, src_node, dst_node, bitrate) results = [] try: - response = requests.put(url=url, timeout=timeout, headers=headers, verify=False, auth=auth) - results.extend(response) LOGGER.info('Lightpath request: {:s} <-> {:s} with {:s} bitrate'.format( str(src_node), str(dst_node), str(bitrate))) + + device1= 'T1' + ep1= 'ep1' + device2= 'T2' + ep2= 'ep2' + context_uuid = 'admin' + service_uuid = 'T1-T2_service' + + data = { + "services": [ + { + "service_id": { + "context_id": {"context_uuid": {"uuid": context_uuid}}, "service_uuid": {"uuid": service_uuid} + }, + "service_type": 5, + } + ] + } + url = '{:s}'.format(root_url) + '/context/{:s}/service/{:s}'.format(context_uuid, service_uuid) + response = requests.post(url=url, timeout=timeout, headers=headers, verify=False, auth=auth, data=json.dumps(data)).json() + + + data = { + "services": [ + { + "service_id": { + "context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "service_uuid"} + }, + "service_type": 5, + "service_status": {"service_status": 1}, + "service_endpoint_ids": [ + {"device_id":{"device_uuid":{"uuid":device1}},"endpoint_uuid":{"uuid":ep1}}, + {"device_id":{"device_uuid":{"uuid":device2}},"endpoint_uuid":{"uuid":ep2}} + ], + "service_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "/settings", "resource_value": { + }} + } + ] + } + } + ] + } + url = '{:s}'.format(root_url) + '/context/{:s}/service/{:s}'.format(context_uuid, service_uuid) + response = requests.put(url=url, timeout=timeout, headers=headers, verify=False, auth=auth, data=json.dumps(data)) + + + #response = requests.put(url=url, timeout=timeout, headers=headers, verify=False, auth=auth) + results.append(response.json()) LOGGER.info('Response: {:s}'.format(str(response))) except Exception as e: # pylint: disable=broad-except LOGGER.exception('Exception requesting Lightpath: {:s} <-> {:s} with {:s} bitrate'.format( @@ -136,7 +186,7 @@ def get_topology(root_url : str, resource_key : str,auth : Optional[HTTPBasicAut return result # if resource_key == RESOURCE_ENDPOINTS: - for link in links: + #for link in links: # TODO # endpoint_url = '/flows/flow[{:s}]'.format(flow_id) diff --git a/src/device/service/drivers/ietf_l2vpn/TfsDebugApiClient.py b/src/device/service/drivers/ietf_l2vpn/TfsDebugApiClient.py index 2d3901695abc4c0124a7f443ffa59f825d4e13bf..24e91aa4c1603ea006ad7e2570ea55ff3197140d 100644 --- a/src/device/service/drivers/ietf_l2vpn/TfsDebugApiClient.py +++ b/src/device/service/drivers/ietf_l2vpn/TfsDebugApiClient.py @@ -44,6 +44,8 @@ MAPPING_DRIVER = { 'DEVICEDRIVER_XR' : 6, 'DEVICEDRIVER_IETF_L2VPN' : 7, 'DEVICEDRIVER_GNMI_OPENCONFIG' : 8, + 'DEVICEDRIVER_FLEXSCALE' : 9, + 'DEVICEDRIVER_OC' : 1, } MSG_ERROR = 'Could not retrieve devices in remote TeraFlowSDN instance({:s}). status_code={:s} reply={:s}' diff --git a/src/service/service/service_handler_api/FilterFields.py b/src/service/service/service_handler_api/FilterFields.py index 430e25938601d522187046b0ebd4cad6971261bb..35c45c99699b5bc640639cde3054ef72bbb6de50 100644 --- a/src/service/service/service_handler_api/FilterFields.py +++ b/src/service/service/service_handler_api/FilterFields.py @@ -25,6 +25,7 @@ SERVICE_TYPE_VALUES = { ServiceTypeEnum.SERVICETYPE_L2NM, ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE, ServiceTypeEnum.SERVICETYPE_TE, + ServiceTypeEnum.SERVICETYPE_E2E, } DEVICE_DRIVER_VALUES = { @@ -37,6 +38,7 @@ DEVICE_DRIVER_VALUES = { DeviceDriverEnum.DEVICEDRIVER_XR, DeviceDriverEnum.DEVICEDRIVER_IETF_L2VPN, DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG, + DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE, } # Map allowed filter fields to allowed values per Filter field. If no restriction (free text) None is specified diff --git a/src/service/service/service_handlers/__init__.py b/src/service/service/service_handlers/__init__.py index cb926e5b767ae56ea2024aad7cb9afa632f9d6bb..dd96db2af43c65673ea871f1da1ac371d39e8a11 100644 --- a/src/service/service/service_handlers/__init__.py +++ b/src/service/service/service_handlers/__init__.py @@ -24,6 +24,8 @@ from .microwave.MicrowaveServiceHandler import MicrowaveServiceHandler from .p4.p4_service_handler import P4ServiceHandler from .tapi_tapi.TapiServiceHandler import TapiServiceHandler from .tapi_xr.TapiXrServiceHandler import TapiXrServiceHandler +from .e2e_orch.E2EOrchestratorServiceHandler import E2EOrchestratorServiceHandler + SERVICE_HANDLERS = [ (L2NMEmulatedServiceHandler, [ @@ -86,4 +88,10 @@ SERVICE_HANDLERS = [ FilterFieldEnum.DEVICE_DRIVER : [DeviceDriverEnum.DEVICEDRIVER_IETF_L2VPN], } ]), + (E2EOrchestratorServiceHandler, [ + { + FilterFieldEnum.SERVICE_TYPE : ServiceTypeEnum.SERVICETYPE_E2E, + FilterFieldEnum.DEVICE_DRIVER : [DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE], + } + ]), ] diff --git a/src/service/service/service_handlers/2e2_orch/E2EOrchServiceHandler.py b/src/service/service/service_handlers/e2e_orch/E2EOrchestratorServiceHandler.py similarity index 99% rename from src/service/service/service_handlers/2e2_orch/E2EOrchServiceHandler.py rename to src/service/service/service_handlers/e2e_orch/E2EOrchestratorServiceHandler.py index 44272fee8b382cd1f44d22fe4195c3e3273bcbb7..5a068bb515793179e5f4c9169fb00dc0ce292384 100644 --- a/src/service/service/service_handlers/2e2_orch/E2EOrchServiceHandler.py +++ b/src/service/service/service_handlers/e2e_orch/E2EOrchestratorServiceHandler.py @@ -16,7 +16,7 @@ import json, logging from typing import Any, Dict, List, Optional, Tuple, Union from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method from common.proto.context_pb2 import ConfigRule, DeviceId, Service -from common.tools.object_factory.ConfigRule import json_config_rule_delete, json_config_rule_set +from common.tools.object_factory.ConfigRule import json_config_rule_set from common.tools.object_factory.Device import json_device_id from common.type_checkers.Checkers import chk_type from service.service.service_handler_api.Tools import get_device_endpoint_uuids @@ -28,7 +28,7 @@ LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Service', 'Handler', labels={'handler': 'e2e_orch'}) -class E2EOrchServiceHandler(_ServiceHandler): +class E2EOrchestratorServiceHandler(_ServiceHandler): def __init__( # pylint: disable=super-init-not-called self, service : Service, task_executor : TaskExecutor, **settings ) -> None: diff --git a/src/service/service/service_handlers/2e2_orch/__init__.py b/src/service/service/service_handlers/e2e_orch/__init__.py similarity index 100% rename from src/service/service/service_handlers/2e2_orch/__init__.py rename to src/service/service/service_handlers/e2e_orch/__init__.py diff --git a/src/tests/tools/mock_flexscale_opt_ctrl/MockFlexscaleOptCtrl.py b/src/tests/tools/mock_flexscale_opt_ctrl/MockFlexscaleOptCtrl.py index 09e1de99548d7f5c2cc173e3131bb9eddeaea25c..c4cc2b69911b99600c79b61d3634427268827b66 100644 --- a/src/tests/tools/mock_flexscale_opt_ctrl/MockFlexscaleOptCtrl.py +++ b/src/tests/tools/mock_flexscale_opt_ctrl/MockFlexscaleOptCtrl.py @@ -35,11 +35,11 @@ def log_request(logger : logging.Logger, response): return response class AddLightpath(Resource): - def put(self): + def put(self, src_node: str, dst_node: str, bitrate: int): return make_response(jsonify(ADDLIGHTPATH_REPLY), 200) class DelLightpath(Resource): - def delete(self): + def delete(self, flow_id: str, src_node: str, dst_node: str, bitrate: int): return make_response(jsonify({}), 200) class GetLightpaths(Resource): diff --git a/src/tests/tools/mock_flexscale_opt_ctrl/data.py b/src/tests/tools/mock_flexscale_opt_ctrl/data.py index e89abeb3a99460b52dc55463df29ae8755079fc4..20a0340165e56b71d6fdf016246fe59b1a9ddc71 100644 --- a/src/tests/tools/mock_flexscale_opt_ctrl/data.py +++ b/src/tests/tools/mock_flexscale_opt_ctrl/data.py @@ -13,7 +13,7 @@ # limitations under the License. -ADDLIGHTPATH_REPLY = """{ +ADDLIGHTPATH_REPLY = { "flow_id": 1, "src": "t1", "dst": "t2", @@ -93,6 +93,6 @@ ADDLIGHTPATH_REPLY = """{ ], "band": 50, "freq": 192031.25, - "is_active": true + "is_active": True } -""" +