Commit df9f3483 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

SIMAP Connector:

- Implemented provisional mocks for testing
- Code styling
parent 642f4202
Loading
Loading
Loading
Loading
+143 −0
Original line number Diff line number Diff line
# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import logging
from .SimapClient import SimapClient


LOGGER = logging.getLogger(__name__)


def set_simap_e2e_net(simap_client : SimapClient) -> None:
    simap = simap_client.network('simap-e2e')
    simap.create(supporting_network_ids=['admin', 'simap-aggnet'])

    node_a = simap.node('sdp1')
    node_a.create(supporting_node_ids=[('admin', 'ONT1')])
    node_a.termination_point('200').create(supporting_termination_point_ids=[('admin', 'ONT1', '200')])
    node_a.termination_point('500').create(supporting_termination_point_ids=[('admin', 'ONT1', '500')])

    node_b = simap.node('sdp2')
    node_b.create(supporting_node_ids=[('admin', 'POP2')])
    node_b.termination_point('200').create(supporting_termination_point_ids=[('admin', 'POP2', '200')])
    node_b.termination_point('201').create(supporting_termination_point_ids=[('admin', 'POP2', '201')])
    node_b.termination_point('500').create(supporting_termination_point_ids=[('admin', 'POP2', '500')])

    link = simap.link('E2E-L1')
    link.create(
        'sdp1', '500', 'sdp2', '500',
        supporting_link_ids=[
            ('admin', 'L1'), ('admin', 'L3'), ('simap-aggnet', 'AggNet-L1')
        ]
    )


def delete_simap_e2e_net(simap_client : SimapClient) -> None:
    simap = simap_client.network('simap-e2e')
    simap.create(supporting_network_ids=['admin', 'simap-aggnet'])

    link = simap.link('E2E-L1')
    link.delete()


def set_simap_agg_net(simap_client : SimapClient) -> None:
    simap = simap_client.network('simap-aggnet')
    simap.create(supporting_network_ids=['admin', 'simap-trans'])

    node_a = simap.node('sdp1')
    node_a.create(supporting_node_ids=[('admin', 'OLT')])
    node_a.termination_point('200').create(supporting_termination_point_ids=[('admin', 'OLT', '200')])
    node_a.termination_point('201').create(supporting_termination_point_ids=[('admin', 'OLT', '201')])
    node_a.termination_point('500').create(supporting_termination_point_ids=[('admin', 'OLT', '500')])
    node_a.termination_point('501').create(supporting_termination_point_ids=[('admin', 'OLT', '501')])

    node_b = simap.node('sdp2')
    node_b.create(supporting_node_ids=[('admin', 'POP2')])
    node_b.termination_point('200').create(supporting_termination_point_ids=[('admin', 'POP2', '200')])
    node_b.termination_point('201').create(supporting_termination_point_ids=[('admin', 'POP2', '201')])
    node_b.termination_point('500').create(supporting_termination_point_ids=[('admin', 'POP2', '500')])

    link = simap.link('AggNet-L1')
    link.create(
        'sdp1', '500', 'sdp2', '500',
        supporting_link_ids=[
            ('simap-trans-pkt', 'Trans-L1'), ('admin', 'L13')
        ]
    )


def delete_simap_agg_net(simap_client : SimapClient) -> None:
    simap = simap_client.network('simap-aggnet')
    simap.create(supporting_network_ids=['admin', 'simap-trans'])

    link = simap.link('AggNet-L1')
    link.delete()


def set_simap_trans_pkt(simap_client : SimapClient) -> None:
    simap = simap_client.network('simap-trans-pkt')
    simap.update(supporting_network_ids=['admin'])

    node_a = simap.node('site1')
    node_a.update(supporting_node_ids=[('admin', 'P-PE1')])
    node_a.termination_point('200').update(supporting_termination_point_ids=[('admin', 'P-PE1', '200')])
    node_a.termination_point('500').update(supporting_termination_point_ids=[('admin', 'P-PE1', '500')])
    node_a.termination_point('501').update(supporting_termination_point_ids=[('admin', 'P-PE1', '501')])

    node_b = simap.node('site2')
    node_b.update(supporting_node_ids=[('admin', 'P-PE2')])
    node_b.termination_point('200').update(supporting_termination_point_ids=[('admin', 'P-PE2', '200')])
    node_b.termination_point('500').update(supporting_termination_point_ids=[('admin', 'P-PE2', '500')])
    node_b.termination_point('501').update(supporting_termination_point_ids=[('admin', 'P-PE2', '501')])

    link = simap.link('Trans-L1')
    link.update(
        'site1', '500', 'site2', '500',
        supporting_link_ids=[
            ('admin', 'L5'), ('admin', 'L9')
        ]
    )


def delete_simap_trans_pkt(simap_client : SimapClient) -> None:
    simap = simap_client.network('simap-trans-pkt')
    simap.update(supporting_network_ids=['admin'])

    link = simap.link('Trans-L1')
    link.delete()


def set_mock_simap(simap_client : SimapClient, domain_name : str) -> None:
    if domain_name == 'trans-pkt':
        set_simap_trans_pkt(simap_client)
    elif domain_name == 'agg-net':
        set_simap_agg_net(simap_client)
    elif domain_name == 'e2e-net':
        set_simap_e2e_net(simap_client)
    else:
        MSG = 'Unsupported Topology({:s}) to set SIMAP'
        LOGGER.warning(MSG.format(str(domain_name)))


def delete_mock_simap(simap_client : SimapClient, domain_name : str) -> None:
    if domain_name == 'trans-pkt':
        delete_simap_trans_pkt(simap_client)
    elif domain_name == 'agg-net':
        delete_simap_agg_net(simap_client)
    elif domain_name == 'e2e-net':
        delete_simap_e2e_net(simap_client)
    else:
        MSG = 'Unsupported Topology({:s}) to delete SIMAP'
        LOGGER.warning(MSG.format(str(domain_name)))
+120 −102
Original line number Diff line number Diff line
@@ -17,7 +17,9 @@ import logging, queue, threading, uuid
from typing import Any, Optional, Set
from common.Constants import DEFAULT_TOPOLOGY_NAME
from common.DeviceTypes import DeviceTypeEnum
from common.proto.context_pb2 import ContextEvent, DeviceEvent, Empty, LinkEvent, ServiceEvent, SliceEvent, TopologyEvent
from common.proto.context_pb2 import (
    ContextEvent, DeviceEvent, Empty, LinkEvent, ServiceEvent, SliceEvent, TopologyEvent
)
from common.tools.grpc.BaseEventCollector import BaseEventCollector
from common.tools.grpc.BaseEventDispatcher import BaseEventDispatcher
from common.tools.grpc.Tools import grpc_message_to_json_string
@@ -27,7 +29,8 @@ from simap_connector.Config import (
    SIMAP_SERVER_SCHEME, SIMAP_SERVER_ADDRESS, SIMAP_SERVER_PORT,
    SIMAP_SERVER_USERNAME, SIMAP_SERVER_PASSWORD,
)
from .simap_client.SimapClient import SimapClient
from simap_connector.service.simap_updater.MockSimaps import delete_mock_simap, set_mock_simap
from .SimapClient import SimapClient
from .ObjectCache import CachedEntities, ObjectCache
from .Tools import get_device_endpoint, get_link_endpoint, get_service_endpoint

@@ -427,21 +430,21 @@ class EventDispatcher(BaseEventDispatcher):
        except: # pylint: disable=bare-except
            pass

        topology_uuid, endpoint_uuids = get_service_endpoint(service)
        #topology_uuid, endpoint_uuids = get_service_endpoint(service)

        if topology_uuid is None:
            MSG = 'ServiceEvent({:s}) skipped, no endpoint_ids to identify topology: {:s}'
            str_service_event = grpc_message_to_json_string(service_event)
            str_service = grpc_message_to_json_string(service)
            LOGGER.warning(MSG.format(str_service_event, str_service))
            return False
        #if topology_uuid is None:
        #    MSG = 'ServiceEvent({:s}) skipped, no endpoint_ids to identify topology: {:s}'
        #    str_service_event = grpc_message_to_json_string(service_event)
        #    str_service = grpc_message_to_json_string(service)
        #    LOGGER.warning(MSG.format(str_service_event, str_service))
        #    return False

        if len(endpoint_uuids) < 2:
            MSG = 'ServiceEvent({:s}) skipped, not enough endpoint_ids to compose link: {:s}'
            str_service_event = grpc_message_to_json_string(service_event)
            str_service = grpc_message_to_json_string(service)
            LOGGER.warning(MSG.format(str_service_event, str_service))
            return False
        #if len(endpoint_uuids) < 2:
        #    MSG = 'ServiceEvent({:s}) skipped, not enough endpoint_ids to compose link: {:s}'
        #    str_service_event = grpc_message_to_json_string(service_event)
        #    str_service = grpc_message_to_json_string(service)
        #    LOGGER.warning(MSG.format(str_service_event, str_service))
        #    return False

        topologies = self._object_cache.get_all(CachedEntities.TOPOLOGY, fresh=False)
        topology_names = {t.name for t in topologies}
@@ -453,55 +456,57 @@ class EventDispatcher(BaseEventDispatcher):
            return False

        domain_name = topology_names.pop()  # trans-pkt/agg-net/e2e-net
        domain_topo = self._simap_client.network(domain_name)
        domain_topo.update()

        src_device   = self._object_cache.get(CachedEntities.DEVICE,   endpoint_uuids[0][0], auto_retrieve=False)
        src_endpoint = self._object_cache.get(CachedEntities.ENDPOINT, *(endpoint_uuids[0]), auto_retrieve=False)
        dst_device   = self._object_cache.get(CachedEntities.DEVICE,   endpoint_uuids[1][0], auto_retrieve=False)
        dst_endpoint = self._object_cache.get(CachedEntities.ENDPOINT, *(endpoint_uuids[1]), auto_retrieve=False)

        try:
            if src_device is None:
                MSG = 'Device({:s}) not found in cache'
                raise Exception(MSG.format(str(endpoint_uuids[0][0])))
            if src_endpoint is None:
                MSG = 'Endpoint({:s}) not found in cache'
                raise Exception(MSG.format(str(endpoint_uuids[0])))
            if dst_device is None:
                MSG = 'Device({:s}) not found in cache'
                raise Exception(MSG.format(str(endpoint_uuids[1][0])))
            if dst_endpoint is None:
                MSG = 'Endpoint({:s}) not found in cache'
                raise Exception(MSG.format(str(endpoint_uuids[1])))
        except Exception as e:
            MSG = '{:s} in Service({:s})'
            raise Exception(MSG.format(str(e), grpc_message_to_json_string(service))) from e

        src_dev_name = src_device.name
        src_ep_name  = src_endpoint.name
        dst_dev_name = dst_device.name
        dst_ep_name  = dst_endpoint.name

        parent_domain_name = DEFAULT_TOPOLOGY_NAME      # TODO: compute from service settings

        site_1_name = 'site1'                           # TODO: compute from service settings
        site_1 = domain_topo.node(site_1_name)
        site_1.update(supporting_node_ids=[(parent_domain_name, src_dev_name)])
        site_1_tp = site_1.termination_point(src_ep_name)
        site_1_tp.update(supporting_termination_point_ids=[(parent_domain_name, src_dev_name, src_ep_name)])

        site_2_name = 'site2'                           # TODO: compute from service settings
        site_2 = domain_topo.node(site_2_name)
        site_2.update(supporting_node_ids=[(parent_domain_name, dst_dev_name)])
        site_2_tp = site_2.termination_point(dst_ep_name)
        site_2_tp.update(supporting_termination_point_ids=[(parent_domain_name, dst_dev_name, dst_ep_name)])

        link_name = '{:s}:{:s}-{:s}=={:s}-{:s}'.format(
            service_name, src_dev_name, src_ep_name, dst_dev_name, dst_ep_name
        )
        dom_link = domain_topo.link(link_name)
        dom_link.update(src_dev_name, src_ep_name, dst_dev_name, dst_ep_name)
        set_mock_simap(self._simap_client, domain_name)

        #domain_topo = self._simap_client.network(domain_name)
        #domain_topo.update()

        #src_device   = self._object_cache.get(CachedEntities.DEVICE,   endpoint_uuids[0][0], auto_retrieve=False)
        #src_endpoint = self._object_cache.get(CachedEntities.ENDPOINT, *(endpoint_uuids[0]), auto_retrieve=False)
        #dst_device   = self._object_cache.get(CachedEntities.DEVICE,   endpoint_uuids[1][0], auto_retrieve=False)
        #dst_endpoint = self._object_cache.get(CachedEntities.ENDPOINT, *(endpoint_uuids[1]), auto_retrieve=False)

        #try:
        #    if src_device is None:
        #        MSG = 'Device({:s}) not found in cache'
        #        raise Exception(MSG.format(str(endpoint_uuids[0][0])))
        #    if src_endpoint is None:
        #        MSG = 'Endpoint({:s}) not found in cache'
        #        raise Exception(MSG.format(str(endpoint_uuids[0])))
        #    if dst_device is None:
        #        MSG = 'Device({:s}) not found in cache'
        #        raise Exception(MSG.format(str(endpoint_uuids[1][0])))
        #    if dst_endpoint is None:
        #        MSG = 'Endpoint({:s}) not found in cache'
        #        raise Exception(MSG.format(str(endpoint_uuids[1])))
        #except Exception as e:
        #    MSG = '{:s} in Service({:s})'
        #    raise Exception(MSG.format(str(e), grpc_message_to_json_string(service))) from e

        #src_dev_name = src_device.name
        #src_ep_name  = src_endpoint.name
        #dst_dev_name = dst_device.name
        #dst_ep_name  = dst_endpoint.name

        #parent_domain_name = DEFAULT_TOPOLOGY_NAME      # TODO: compute from service settings

        #site_1_name = 'site1'                           # TODO: compute from service settings
        #site_1 = domain_topo.node(site_1_name)
        #site_1.update(supporting_node_ids=[(parent_domain_name, src_dev_name)])
        #site_1_tp = site_1.termination_point(src_ep_name)
        #site_1_tp.update(supporting_termination_point_ids=[(parent_domain_name, src_dev_name, src_ep_name)])

        #site_2_name = 'site2'                           # TODO: compute from service settings
        #site_2 = domain_topo.node(site_2_name)
        #site_2.update(supporting_node_ids=[(parent_domain_name, dst_dev_name)])
        #site_2_tp = site_2.termination_point(dst_ep_name)
        #site_2_tp.update(supporting_termination_point_ids=[(parent_domain_name, dst_dev_name, dst_ep_name)])

        #link_name = '{:s}:{:s}-{:s}=={:s}-{:s}'.format(
        #    service_name, src_dev_name, src_ep_name, dst_dev_name, dst_ep_name
        #)
        #dom_link = domain_topo.link(link_name)
        #dom_link.update(src_dev_name, src_ep_name, dst_dev_name, dst_ep_name)
        return True


@@ -527,6 +532,17 @@ class EventDispatcher(BaseEventDispatcher):
        service = self._object_cache.get(CachedEntities.SERVICE, service_uuid)
        service_name = service.name

        try:
            uuid.UUID(hex=service_name)
            # skip it if properly parsed, means it is a service with a UUID-based name, i.e., a sub-service
            MSG = 'ServiceEvent({:s}) skipped, it is a subservice: {:s}'
            str_service_event = grpc_message_to_json_string(service_event)
            str_service = grpc_message_to_json_string(service)
            LOGGER.warning(MSG.format(str_service_event, str_service))
            return False
        except: # pylint: disable=bare-except
            pass

        topology_uuid, endpoint_uuids = get_service_endpoint(service)
        if topology_uuid is None:
            MSG = 'ServiceEvent({:s}) skipped, no endpoint_ids to identify topology: {:s}'
@@ -545,44 +561,46 @@ class EventDispatcher(BaseEventDispatcher):
            return

        domain_name = topology_names.pop()  # trans-pkt/agg-net/e2e-net
        domain_topo = self._simap_client.network(domain_name)
        domain_topo.update()

        src_device   = self._object_cache.get(CachedEntities.DEVICE,   endpoint_uuids[0][0], auto_retrieve=False)
        src_endpoint = self._object_cache.get(CachedEntities.ENDPOINT, *(endpoint_uuids[0]), auto_retrieve=False)
        dst_device   = self._object_cache.get(CachedEntities.DEVICE,   endpoint_uuids[1][0], auto_retrieve=False)
        dst_endpoint = self._object_cache.get(CachedEntities.ENDPOINT, *(endpoint_uuids[1]), auto_retrieve=False)

        try:
            if src_device is None:
                MSG = 'Device({:s}) not found in cache'
                raise Exception(MSG.format(str(endpoint_uuids[0][0])))
            if src_endpoint is None:
                MSG = 'Endpoint({:s}) not found in cache'
                raise Exception(MSG.format(str(endpoint_uuids[0])))
            if dst_device is None:
                MSG = 'Device({:s}) not found in cache'
                raise Exception(MSG.format(str(endpoint_uuids[1][0])))
            if dst_endpoint is None:
                MSG = 'Endpoint({:s}) not found in cache'
                raise Exception(MSG.format(str(endpoint_uuids[1])))
        except Exception as e:
            MSG = '{:s} in Service({:s})'
            raise Exception(MSG.format(str(e), grpc_message_to_json_string(service))) from e

        src_dev_name = src_device.name
        src_ep_name  = src_endpoint.name
        dst_dev_name = dst_device.name
        dst_ep_name  = dst_endpoint.name

        link_name = '{:s}:{:s}-{:s}=={:s}-{:s}'.format(
            service_name, src_dev_name, src_ep_name, dst_dev_name, dst_ep_name
        )
        te_link = domain_topo.link(link_name)
        te_link.delete()
        delete_mock_simap(self._simap_client, domain_name)

        #domain_topo = self._simap_client.network(domain_name)
        #domain_topo.update()

        #src_device   = self._object_cache.get(CachedEntities.DEVICE,   endpoint_uuids[0][0], auto_retrieve=False)
        #src_endpoint = self._object_cache.get(CachedEntities.ENDPOINT, *(endpoint_uuids[0]), auto_retrieve=False)
        #dst_device   = self._object_cache.get(CachedEntities.DEVICE,   endpoint_uuids[1][0], auto_retrieve=False)
        #dst_endpoint = self._object_cache.get(CachedEntities.ENDPOINT, *(endpoint_uuids[1]), auto_retrieve=False)

        #try:
        #    if src_device is None:
        #        MSG = 'Device({:s}) not found in cache'
        #        raise Exception(MSG.format(str(endpoint_uuids[0][0])))
        #    if src_endpoint is None:
        #        MSG = 'Endpoint({:s}) not found in cache'
        #        raise Exception(MSG.format(str(endpoint_uuids[0])))
        #    if dst_device is None:
        #        MSG = 'Device({:s}) not found in cache'
        #        raise Exception(MSG.format(str(endpoint_uuids[1][0])))
        #    if dst_endpoint is None:
        #        MSG = 'Endpoint({:s}) not found in cache'
        #        raise Exception(MSG.format(str(endpoint_uuids[1])))
        #except Exception as e:
        #    MSG = '{:s} in Service({:s})'
        #    raise Exception(MSG.format(str(e), grpc_message_to_json_string(service))) from e

        #src_dev_name = src_device.name
        #src_ep_name  = src_endpoint.name
        #dst_dev_name = dst_device.name
        #dst_ep_name  = dst_endpoint.name

        #link_name = '{:s}:{:s}-{:s}=={:s}-{:s}'.format(
        #    service_name, src_dev_name, src_ep_name, dst_dev_name, dst_ep_name
        #)
        #te_link = domain_topo.link(link_name)
        #te_link.delete()

        self._object_cache.delete(CachedEntities.SERVICE, service_uuid)
        self._object_cache.delete(CachedEntities.SERVICE, service_name)
        #self._object_cache.delete(CachedEntities.SERVICE, service_uuid)
        #self._object_cache.delete(CachedEntities.SERVICE, service_name)

        MSG = 'Logical Link Removed for Service: {:s}'
        LOGGER.info(MSG.format(grpc_message_to_json_string(service_event)))
+0 −14
Original line number Diff line number Diff line
# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+0 −128

File deleted.

Preview size limit exceeded, changes collapsed.