diff --git a/src/pathcomp/frontend/service/algorithms/tools/ComputeSubServices.py b/src/pathcomp/frontend/service/algorithms/tools/ComputeSubServices.py index dfcd1156b78cebee7da84033cbc9943aaabdb14d..728bb58c8a8f09df4a26a792d204a9e9753481e3 100644 --- a/src/pathcomp/frontend/service/algorithms/tools/ComputeSubServices.py +++ b/src/pathcomp/frontend/service/algorithms/tools/ComputeSubServices.py @@ -45,24 +45,39 @@ # ], [UUID('c2e57966-5d82-4705-a5fe-44cf6487219e')]) # ] -import logging, queue, uuid +import logging, queue +from dataclasses import dataclass, field from typing import Dict, List, Optional, Tuple from common.DeviceTypes import DeviceTypeEnum from common.proto.context_pb2 import Device, ServiceTypeEnum +from common.tools.context_queries.Slice import get_uuid_from_string from .ResourceGroups import IGNORED_DEVICE_TYPES, REMOTEDOMAIN_DEVICE_TYPES, get_resource_classification from .ServiceTypes import get_service_type LOGGER = logging.getLogger(__name__) +@dataclass +class ConnectionEntry: + uuid: str = '' + service_type : ServiceTypeEnum = ServiceTypeEnum.SERVICETYPE_UNKNOWN + path_hops : List[Dict] = field(default_factory=list) + dependencies : List[str] = field(default_factory=list) + + def __post_init__(self) -> None: + if self.uuid != '': + return + composed_string = '-'.join(f'{path_hop["device"]}/{path_hop["ingress_ep"]}/{path_hop["egress_ep"]}' for path_hop in self.path_hops) + self.sub_service_uuid = get_uuid_from_string(composed_string) + def convert_explicit_path_hops_to_connections( path_hops : List[Dict], device_dict : Dict[str, Tuple[Dict, Device]], main_service_uuid : str, main_service_type : ServiceTypeEnum -) -> List[Tuple[str, int, List[str], List[str]]]: +) -> List[Tuple[str, int, List[Dict], List[str]]]: LOGGER.debug('path_hops={:s}'.format(str(path_hops))) connection_stack = queue.LifoQueue() - connections : List[Tuple[str, int, List[str], List[str]]] = list() + connections : List[ConnectionEntry] = list() prv_device_uuid = None prv_res_class : Tuple[Optional[int], Optional[DeviceTypeEnum], Optional[str]] = None, None, None @@ -85,82 +100,83 @@ def convert_explicit_path_hops_to_connections( LOGGER.debug(' create and terminate underlying connection') # create underlying connection - sub_service_uuid = str(uuid.uuid4()) - prv_service_type = connection_stack.queue[-1][1] + prv_service_type = connection_stack.queue[-1].service_type service_type = get_service_type(res_class[1], prv_service_type) - connection_stack.put((sub_service_uuid, service_type, [path_hop], [])) + connection_entry = ConnectionEntry(service_type=service_type, path_hops=[path_hop]) + connection_stack.put(connection_entry) # underlying connection ended - connection = connection_stack.get() + connection: ConnectionEntry = connection_stack.get() connections.append(connection) - connection_stack.queue[-1][3].append(connection[0]) + connection_stack.queue[-1].dependencies.append(connection.uuid) #connection_stack.queue[-1][2].append(path_hop) elif prv_res_class[2] is None and res_class[2] is not None: # entering domain of a device controller, create underlying connection LOGGER.debug(' entering domain of a device controller, create underlying connection') - sub_service_uuid = str(uuid.uuid4()) - prv_service_type = connection_stack.queue[-1][1] + prv_service_type = connection_stack.queue[-1].service_type service_type = get_service_type(res_class[1], prv_service_type) - connection_stack.put((sub_service_uuid, service_type, [path_hop], [])) + connection_entry = ConnectionEntry(service_type=service_type, path_hops=[path_hop]) + connection_stack.put(connection_entry) elif prv_res_class[2] is not None and res_class[2] is None: # leaving domain of a device controller, terminate underlying connection LOGGER.debug(' leaving domain of a device controller, terminate underlying connection') connection = connection_stack.get() connections.append(connection) - connection_stack.queue[-1][3].append(connection[0]) - connection_stack.queue[-1][2].append(path_hop) + connection_stack.queue[-1].dependencies.append(connection.uuid) + connection_stack.queue[-1].path_hops.append(path_hop) elif prv_res_class[2] is not None and res_class[2] is not None: if prv_res_class[2] == res_class[2]: # stay in domain of a device controller, connection continues LOGGER.debug(' stay in domain of a device controller, connection continues') - connection_stack.queue[-1][2].append(path_hop) + connection_stack.queue[-1].path_hops.append(path_hop) else: # switching to different device controller, chain connections LOGGER.debug(' switching to different device controller, chain connections') connection = connection_stack.get() connections.append(connection) - connection_stack.queue[-1][3].append(connection[0]) + connection_stack.queue[-1].dependencies.append(connection.uuid) - sub_service_uuid = str(uuid.uuid4()) - prv_service_type = connection_stack.queue[-1][1] + prv_service_type = connection_stack.queue[-1].service_type service_type = get_service_type(res_class[1], prv_service_type) - connection_stack.put((sub_service_uuid, service_type, [path_hop], [])) + connection_entry = ConnectionEntry(service_type=service_type, path_hops=[path_hop]) + connection_stack.put(connection_entry) elif prv_res_class[0] is None: # path ingress LOGGER.debug(' path ingress') - connection_stack.put((main_service_uuid, main_service_type, [path_hop], [])) + connection_entry = ConnectionEntry(uuid=main_service_uuid, service_type=main_service_type, path_hops=[path_hop]) + connection_stack.put(connection_entry) elif prv_res_class[0] > res_class[0]: # create underlying connection LOGGER.debug(' create underlying connection') - sub_service_uuid = str(uuid.uuid4()) - prv_service_type = connection_stack.queue[-1][1] + prv_service_type = connection_stack.queue[-1].service_type service_type = get_service_type(res_class[1], prv_service_type) - connection_stack.put((sub_service_uuid, service_type, [path_hop], [])) + connection_entry = ConnectionEntry(service_type=service_type, path_hops=[path_hop]) + connection_stack.put(connection_entry) elif prv_res_class[0] == res_class[0]: # same resource group kind LOGGER.debug(' same resource group kind') if prv_res_class[1] == res_class[1] and prv_res_class[2] == res_class[2]: # same device type and device controller: connection continues LOGGER.debug(' connection continues') - connection_stack.queue[-1][2].append(path_hop) + connection_stack.queue[-1].path_hops.append(path_hop) else: # different device type or device controller: chain connections LOGGER.debug(' chain connections') connection = connection_stack.get() connections.append(connection) - connection_stack.queue[-1][3].append(connection[0]) + connection_stack.queue[-1].dependencies.append(connection.uuid) - sub_service_uuid = str(uuid.uuid4()) - prv_service_type = connection_stack.queue[-1][1] + prv_service_type = connection_stack.queue[-1].service_type service_type = get_service_type(res_class[1], prv_service_type) - connection_stack.put((sub_service_uuid, service_type, [path_hop], [])) + connection_entry = ConnectionEntry(service_type=service_type, path_hops=[path_hop]) + connection_stack.put(connection_entry) elif prv_res_class[0] < res_class[0]: # underlying connection ended LOGGER.debug(' underlying connection ended') connection = connection_stack.get() connections.append(connection) - connection_stack.queue[-1][3].append(connection[0]) - connection_stack.queue[-1][2].append(path_hop) + connection_stack.queue[-1].dependencies.append(connection.uuid) + connection_stack.queue[-1].path_hops.append(path_hop) else: raise Exception('Uncontrolled condition') @@ -172,7 +188,7 @@ def convert_explicit_path_hops_to_connections( connections.append(connection_stack.get()) LOGGER.debug('connections={:s}'.format(str(connections))) assert connection_stack.empty() - return connections + return [(c.uuid, c.service_type, c.path_hops, c.dependencies) for c in connections] def convert_explicit_path_hops_to_plain_connection( path_hops : List[Dict], main_service_uuid : str, main_service_type : ServiceTypeEnum