Commit 6161b92a authored by Shayan Hajipour's avatar Shayan Hajipour
Browse files

debug/refactor:

- sub service creation code changed to avoid new sub service creation
  when multi-domain services are updated
- sub service creation code refactored with dataclass addition
parent c2a65dc4
Loading
Loading
Loading
Loading
+46 −30
Original line number Diff line number Diff line
@@ -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