diff --git a/src/interdomain/service/topology_abstractor/AbstractDevice.py b/src/interdomain/service/topology_abstractor/AbstractDevice.py index c3b1b89eee18a47cd61f075e2421d37eaddbf7ad..2e62f6215f0da174ef72ad22163d502d3c3ab106 100644 --- a/src/interdomain/service/topology_abstractor/AbstractDevice.py +++ b/src/interdomain/service/topology_abstractor/AbstractDevice.py @@ -14,13 +14,14 @@ import copy, logging from typing import Dict, Optional -from common.Constants import DEFAULT_CONTEXT_NAME, INTERDOMAIN_TOPOLOGY_NAME +from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME, INTERDOMAIN_TOPOLOGY_NAME from common.DeviceTypes import DeviceTypeEnum -from common.proto.context_pb2 import Device, DeviceDriverEnum, DeviceOperationalStatusEnum, EndPoint +from common.proto.context_pb2 import ContextId, Device, DeviceDriverEnum, DeviceOperationalStatusEnum, EndPoint from common.tools.context_queries.CheckType import ( device_type_is_datacenter, device_type_is_network, endpoint_type_is_border) -from common.tools.context_queries.Device import get_device +from common.tools.context_queries.Device import add_device_to_topology, get_device from common.tools.grpc.Tools import grpc_message_to_json +from common.tools.object_factory.Context import json_context_id from common.tools.object_factory.Device import json_device from context.client.ContextClient import ContextClient from .Tools import replace_device_uuids_by_names @@ -55,7 +56,13 @@ class AbstractDevice: 'device_name' : self.__device_name, 'device_type' : self.__device_type, 'device' : grpc_message_to_json(self.__device), - 'device_endpoint_to_abstract' : self.__device_endpoint_to_abstract, + 'device_endpoint_to_abstract' : { + device_name : { + endpoint_name : grpc_message_to_json(endpoint) + for endpoint_name, endpoint in endpoints.items() + } + for device_name, endpoints in self.__device_endpoint_to_abstract.items() + }, 'abstract_endpoint_to_device' : self.__abstract_endpoint_to_device, } @@ -81,16 +88,13 @@ class AbstractDevice: else: self._load_existing(local_interdomain_device) - #is_datacenter = device_type_is_datacenter(self.__device_type) - #is_network = device_type_is_network(self.__device_type) - #if is_datacenter or is_network: - # # Add abstract device to topologies [INTERDOMAIN_TOPOLOGY_NAME] - # admin_context_id = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) - # topology_uuids = [INTERDOMAIN_TOPOLOGY_NAME] - # for topology_uuid in topology_uuids: - # # This action is done automatically; commented out by now. - # add_device_to_topology( - # self.__context_client, admin_context_id, topology_uuid, self.__device_name) + is_datacenter = device_type_is_datacenter(self.__device_type) + is_network = device_type_is_network(self.__device_type) + if is_datacenter or is_network: + # Add abstract device to INTERDOMAIN_TOPOLOGY_NAME topology + admin_context_id = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) + topology_name = INTERDOMAIN_TOPOLOGY_NAME + add_device_to_topology(self.__context_client, admin_context_id, topology_name, self.__device_name) # seems not needed; to be removed in future releases #if is_datacenter and create_abstract_device: @@ -164,7 +168,7 @@ class AbstractDevice: def _add_endpoint(self, device_name : str, endpoint_name : str, endpoint_type : str) -> EndPoint: interdomain_endpoint = self.__device.device_endpoints.add() - interdomain_endpoint.endpoint_id.topology_id.topology_uuid.uuid = INTERDOMAIN_TOPOLOGY_NAME + interdomain_endpoint.endpoint_id.topology_id.topology_uuid.uuid = DEFAULT_TOPOLOGY_NAME interdomain_endpoint.endpoint_id.topology_id.context_id.context_uuid.uuid = DEFAULT_CONTEXT_NAME interdomain_endpoint.endpoint_id.device_id.device_uuid.uuid = self.__device.name interdomain_endpoint.endpoint_id.endpoint_uuid.uuid = endpoint_name diff --git a/src/interdomain/service/topology_abstractor/AbstractLink.py b/src/interdomain/service/topology_abstractor/AbstractLink.py index baeb0f94dcba330ea4d815ba811bd6addad4e5d4..bb1a02334c45b0606c090ccd951f8d3cc8b9ba65 100644 --- a/src/interdomain/service/topology_abstractor/AbstractLink.py +++ b/src/interdomain/service/topology_abstractor/AbstractLink.py @@ -15,8 +15,10 @@ import copy, logging from typing import Dict, List, Optional, Tuple from common.Constants import DEFAULT_CONTEXT_NAME, INTERDOMAIN_TOPOLOGY_NAME -from common.proto.context_pb2 import EndPointId, Link -from common.tools.context_queries.Link import get_link +from common.proto.context_pb2 import ContextId, EndPointId, Link +from common.tools.context_queries.Link import add_link_to_topology, get_link +from common.tools.grpc.Tools import grpc_message_to_json +from common.tools.object_factory.Context import json_context_id from common.tools.object_factory.Link import json_link from context.client.ContextClient import ContextClient from .Tools import replace_link_uuids_by_names @@ -39,14 +41,20 @@ class AbstractLink: self.__link_name : str = link_name self.__link : Optional[Link] = None - # Dict[(device_name, endpoint_name), abstract EndPointId] - self.__device_endpoint_to_abstract : Dict[Tuple[str, str], EndPointId] = dict() + # Dict[device_name, Dict[endpoint_name, abstract EndPointId]] + self.__device_endpoint_to_abstract : Dict[str, Dict[str, EndPointId]] = dict() def to_json(self) -> Dict: return { 'link_name' : self.__link_name, - 'link' : self.__link, - 'device_endpoint_to_abstract' : self.__device_endpoint_to_abstract, + 'link' : grpc_message_to_json(self.__link), + 'device_endpoint_to_abstract' : { + device_name : { + endpoint_name : grpc_message_to_json(endpoint_id) + for endpoint_name, endpoint_id in endpoint_ids.items() + } + for device_name, endpoint_ids in self.__device_endpoint_to_abstract.items() + }, } @property @@ -80,13 +88,10 @@ class AbstractLink: else: self._load_existing(local_interdomain_link) - ## Add abstract link to topologies [INTERDOMAIN_TOPOLOGY_NAME] - #admin_context_id = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) - #topology_uuids = [INTERDOMAIN_TOPOLOGY_NAME] - #for topology_uuid in topology_uuids: - # # This action is done automatically; commented out by now. - # add_link_to_topology( - # self.__context_client, admin_context_id, topology_uuid, self.__link_name) + # Add abstract link to INTERDOMAIN_TOPOLOGY_NAME topology + admin_context_id = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) + topology_name = INTERDOMAIN_TOPOLOGY_NAME + add_link_to_topology(self.__context_client, admin_context_id, topology_name, self.__link_name) return create_abstract_link @@ -106,7 +111,8 @@ class AbstractLink: for endpoint_id in self.__link.link_endpoint_ids: device_name = endpoint_id.device_id.device_uuid.uuid endpoint_name = endpoint_id.endpoint_uuid.uuid - self.__device_endpoint_to_abstract.setdefault((device_name, endpoint_name), endpoint_id) + endpoints = self.__device_endpoint_to_abstract.setdefault(device_name, dict()) + endpoints.setdefault(endpoint_name, endpoint_id) def _add_endpoint(self, device_name : str, endpoint_name : str) -> None: endpoint_id = self.__link.link_endpoint_ids.add() @@ -114,7 +120,8 @@ class AbstractLink: endpoint_id.topology_id.context_id.context_uuid.uuid = DEFAULT_CONTEXT_NAME endpoint_id.device_id.device_uuid.uuid = device_name endpoint_id.endpoint_uuid.uuid = endpoint_name - self.__device_endpoint_to_abstract.setdefault((device_name, endpoint_name), endpoint_id) + endpoints = self.__device_endpoint_to_abstract.setdefault(device_name, dict()) + endpoints.setdefault(endpoint_name, endpoint_id) def _remove_endpoint(self, device_name : str, endpoint_name : str) -> None: device_endpoint_to_abstract = self.__device_endpoint_to_abstract.get(device_name, {}) @@ -126,16 +133,20 @@ class AbstractLink: # for each endpoint in abstract link that is not in link; remove from abstract link device_endpoint_to_abstract = copy.deepcopy(self.__device_endpoint_to_abstract) - for device_name, endpoint_name in device_endpoint_to_abstract.keys(): - if (device_name, endpoint_name) in link_endpoint_names: continue - # remove endpoint_id that is not in link - self._remove_endpoint(device_name, endpoint_name) - updated = True + for device_name, endpoints in device_endpoint_to_abstract.items(): + for endpoint_name in endpoints.keys(): + if (device_name, endpoint_name) in link_endpoint_names: continue + # remove endpoint_id that is not in link + self._remove_endpoint(device_name, endpoint_name) + updated = True # for each endpoint in link that is not in abstract link; add to abstract link for device_name, endpoint_name in link_endpoint_names: # if already added; just check endpoint type is not modified - if (device_name, endpoint_name) in self.__device_endpoint_to_abstract: continue + endpoints = self.__device_endpoint_to_abstract.get(device_name, {}) + endpoint = endpoints.get(endpoint_name) + if endpoint is not None: continue + # otherwise, add it to the abstract device self._add_endpoint(device_name, endpoint_name) updated = True diff --git a/src/interdomain/service/topology_abstractor/TopologyAbstractor.py b/src/interdomain/service/topology_abstractor/TopologyAbstractor.py index 357b300a7ac9405ad81259e543f7179a86f8bd9d..c22c3ec2f6e3e5492625a75a4252e4982e73c19c 100644 --- a/src/interdomain/service/topology_abstractor/TopologyAbstractor.py +++ b/src/interdomain/service/topology_abstractor/TopologyAbstractor.py @@ -253,7 +253,7 @@ class TopologyAbstractor(threading.Thread): } str_interdomain_devices = { interdomain_device_name : grpc_message_to_json(interdomain_device) - for interdomain_device_name,interdomain_device in interdomain_devices + for interdomain_device_name,interdomain_device in interdomain_devices.items() } LOGGER.info('[_infer_abstract_links] interdomain_devices={:s}'.format(str(str_interdomain_devices))) @@ -266,8 +266,7 @@ class TopologyAbstractor(threading.Thread): abstract_link_name = AbstractLink.compose_name(device_name, endpoint_name, endpoint_name, device_name) LOGGER.info('[_infer_abstract_links] abstract_link_name={:s}'.format(str(abstract_link_name))) LOGGER.info('[_infer_abstract_links] abstract_links={:s}'.format(str({ - abstract_link_name : abstract_link_obj.to_json() - for abstract_link_name, abstract_link_obj in self.abstract_links.items() + al_name : al_obj.to_json() for al_name, al_obj in self.abstract_links.items() }))) if abstract_link_name in self.abstract_links: continue @@ -320,7 +319,7 @@ class TopologyAbstractor(threading.Thread): if dlt_connector_client is not None: dlt_connector_client.close() def _process_event_topology(self, event : TopologyEvent, dlt_record_sender : DltRecordSender) -> None: - LOGGER.debug('Processing TopologyEvent({:s})'.format(grpc_message_to_json_string(event))) + LOGGER.info('Processing TopologyEvent({:s})'.format(grpc_message_to_json_string(event))) topology_id = event.topology_id topology_uuid = topology_id.topology_uuid.uuid context_uuid = topology_id.context_id.context_uuid.uuid @@ -359,7 +358,7 @@ class TopologyAbstractor(threading.Thread): LOGGER.info(' topology_name={:s}'.format(str(topology_name))) LOGGER.info(' topology_uuids={:s}'.format(str(topology_uuids))) if (topology_uuid in topology_uuids) or (topology_name in topology_uuids): - MSG = 'Ignoring ({:s}/{:s})({:s}/{:s}) TopologyEvent({:s})... Not a domain topology' + MSG = 'Ignoring ({:s}/{:s})({:s}/{:s}) TopologyEvent({:s})... Not a domain/interdomain topology' args = context_uuid, context_name, topology_uuid, topology_name, grpc_message_to_json_string(event) LOGGER.warning(MSG.format(*args)) return @@ -385,7 +384,7 @@ class TopologyAbstractor(threading.Thread): self._infer_abstract_links(device, dlt_record_sender) def _process_event_device(self, event : DeviceEvent, dlt_record_sender : DltRecordSender) -> None: - LOGGER.debug('Processing DeviceEvent({:s})'.format(grpc_message_to_json_string(event))) + LOGGER.info('Processing DeviceEvent({:s})'.format(grpc_message_to_json_string(event))) device_uuid = event.device_id.device_uuid.uuid device = get_device( @@ -407,16 +406,16 @@ class TopologyAbstractor(threading.Thread): if abstract_device_name is None: MSG = 'Ignoring DeviceEvent({:s}). Abstract Device not found' LOGGER.warning(MSG.format(grpc_message_to_json_string(event))) - return - - abstract_topology_id = self.abstract_device_to_topology_id[abstract_device_name] - self._update_abstract_device( - device, dlt_record_sender, abstract_topology_id, abstract_device_name=abstract_device_name) + else: + abstract_topology_id = self.abstract_device_to_topology_id[abstract_device_name] + self._update_abstract_device( + device, dlt_record_sender, abstract_topology_id, abstract_device_name=abstract_device_name) - self._infer_abstract_links(device, dlt_record_sender) + if abstract_device_name is not None or device_name in self.abstract_device_to_topology_id: + self._infer_abstract_links(device, dlt_record_sender) def _process_event_link(self, event : LinkEvent, dlt_record_sender : DltRecordSender) -> None: - LOGGER.debug('Processing LinkEvent({:s})'.format(grpc_message_to_json_string(event))) + LOGGER.info('Processing LinkEvent({:s})'.format(grpc_message_to_json_string(event))) link_uuid = event.link_id.link_uuid.uuid link = get_link(self.context_client, link_uuid, rw_copy=True)