DiscoveredDBManager.py 10.6 KB
Newer Older
Pablo Armingol's avatar
Pablo Armingol committed
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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.
Pablo Armingol's avatar
Pablo Armingol committed

from typing import List
from bgpls_speaker.service.tools.Tools import UpdateRequest,NodeInfo,LinkInfo
from common.proto.bgpls_pb2 import NodeDescriptors
from common.proto.context_pb2 import ContextId, ContextList,Topology,TopologyId,Device,DeviceDriverEnum,ContextId,Empty, TopologyList
from common.Constants import DEFAULT_CONTEXT_NAME
from common.tools.object_factory.Context import json_context_id
from context.client.ContextClient import ContextClient

import logging
LOGGER = logging.getLogger(__name__)

class DiscoveredDBManager:
    def __init__(self):
        self.discoveredDB=[]
        # Añadir topoDB

    def AddToDB(self,update_request : UpdateRequest):
        """
        Add BGP Update message to discoveredDB. Checks if node exists in discoveredDB.
        TODO: check if node exists in context
        """
        # TODO: with self.lock
        # Check if node info message
        if(self.checkIfNodeInUpdate(update_request)):
            # Check if node exists
            to_add=True
            for node in update_request.nodes:
                if(self.CheckIfNodeNameInDb(node) or CheckIfNodeInContext(node.node_name)):
                    # Replace info from node if exists
                    LOGGER.debug("(AddToDB) Node already in DB!!!")
                    to_add=False
                else:
                    LOGGER.debug("(AddToDB) Node NOT in DB!!!")
            if(to_add):
                self.discoveredDB.append(update_request)
        else:
            # is a link
            # Compare and update
            self.discoveredDB.append(update_request)
Pablo Armingol's avatar
Pablo Armingol committed
            LOGGER.debug("(AddToDB) Actual DB: ")
            LOGGER.debug("%s", [up.toString() for up in self.discoveredDB])
Pablo Armingol's avatar
Pablo Armingol committed
        return True
    
    def GetDiscoveredDB(self):
        return self.discoveredDB
    
    def checkIfNodeInUpdate(self,update_request : UpdateRequest):
        """
        Returns true if the update message contains a node info type .
        """
        if(update_request.nodes):
            return True
        return False
    
    
    def CheckIfNodeNameInDb(self,new_node : NodeInfo) -> bool:
        """
        Returns true if new node is in the discovered data base already
        """
        for update in self.discoveredDB:
            for node in update.nodes:
                if(node.igp_id==new_node.igp_id):
                    return True
        return False
    
    def GetNodeNamesFromDiscoveredDB(self):
        """
        Return a list of node_names from the current discovered devices
        saved in the discoveredDB
        """
        node_list =[update_request.nodes for update_request in self.discoveredDB if update_request.nodes]
        # LOGGER.info("nodes (GetNodeNamesFromDiscoveredDB) %s",node_list )
        # Inside an update there is a list of nodes , TODO posible FIX:
        node_info= [node for nodes in node_list for node in nodes]
        return [node.node_name for node in node_info]
    
    def GetNodesFromDiscoveredDB(self):
        """
        Return a list of nodes of class type: tools.NodeInfo from the current discovered devices
        saved in the discoveredDB. Skips the ones already addded to context.
        """

        node_list =[update_request.nodes for update_request in self.discoveredDB if update_request.nodes]
        return [node for nodes in node_list for node in nodes if (not CheckIfNodeInContext(node.node_name))]
    
    def GetLinksFromDiscoveredDB(self):
        """
        Return a list of links of class type: tools.LinkInfo from the current discovered links
        saved in the discoveredDB
        """
        link_list= [update_request.links for update_request in self.discoveredDB if update_request.links]
        return [link for links in link_list for link in links]
    
    def UpdateDiscoveredDBWithContext(self):
        """
        Check if device discovered by bgpls is already in the topology.
        """
        # device_names,device_ips=AddContextDevices(context_client)
        return True
    
    def GetNodeNameFromLinkId(self,link_igpid):
        """
        Return the node name given an igp id if exists in the discoveredDB.   
        """
        for update in self.discoveredDB:
            for node in update.nodes:
                if(node.igp_id==link_igpid):
                    return node.node_name
        return None
    
    def UpdateNodeNameInLink(self):
        """
        Check if the igp id has a node name asigned in the discoveredDB and
        assign it to the NodeDescriptor name.
        """
        for update in self.discoveredDB:
            for link in update.links:
Pablo Armingol's avatar
Pablo Armingol committed
                if(self.GetNodeNameFromLinkId(link.localID) is not None):
                    LOGGER.info("(UpdateNodeNameInLink) local %s:  %s",link.localID, self.GetNodeNameFromLinkId(link.localID))
                    link.local.node_name=self.GetNodeNameFromLinkId(link.localID)
Pablo Armingol's avatar
Pablo Armingol committed
                else:
Pablo Armingol's avatar
Pablo Armingol committed
                     link.local.node_name=link.localID
                if(self.GetNodeNameFromLinkId(link.remoteID) is not None):
                    LOGGER.info("(UpdateNodeNameInLink) remote %s:  %s",link.remoteID, self.GetNodeNameFromLinkId(link.remoteID))
                    link.remote.node_name=self.GetNodeNameFromLinkId(link.remoteID)
Pablo Armingol's avatar
Pablo Armingol committed
                else:
Pablo Armingol's avatar
Pablo Armingol committed
                    link.remote.node_name=link.remoteID
Pablo Armingol's avatar
Pablo Armingol committed
        return True

    def RemoveLinkFromDB(self):
        """
        Removes a link from the DB if matches the source and the destination.
        """
        return True
    
    def FindConnectedNodes(self,new_node):
        """
        Returns a list of nodes connected to the actual node using the discovered 
        link list. Returns None in case there are no connections.
        """
        # find links where the node appears
        links_to_node=[]
        nodes_conected=[]
        for update in self.discoveredDB:
            for link in update.links:
                if(link.local.node_name == new_node):
                    links_to_node.append(link)
                    nodes_conected.append(link.remote.node_name)
                if(link.remote.node_name == new_node):
                    links_to_node.append(link)
                    nodes_conected.append(link.local.node_name)
        
        if(nodes_conected):
            LOGGER.debug("(FindConnectedNodes) links to local node:%s",new_node)
            LOGGER.debug("(FindConnectedNodes) %s", nodes_conected)
            return nodes_conected
        LOGGER.debug("(FindConnectedNodes) NO LINKS TO OTHER NODES")
        return None

    def DeleteNodeFromDiscoveredDB(self, node_name) -> bool:
        """
        Deletes a node from de DiscoveredDB given the node name. TODO: igpid¿
        """
        LOGGER.info("(DeleteNodeFromDiscoveredDB)")
        
        for i,update in enumerate(self.discoveredDB):
            for node in update.nodes:
                if(node_name==node.node_name):
                    del self.discoveredDB[i]
        return True

def AddContextDevicesFull(context_client : ContextClient) -> bool:
    """
    debug purposes
    """
    LOGGER.info("(AddContextDevices)")
    contexts : ContextList = context_client.ListContexts(Empty())
    for context_ in contexts.contexts:
        context_uuid : str = context_.context_id.context_uuid.uuid
        context_name : str = context_.name
        topologies : TopologyList = context_client.ListTopologies(context_.context_id)
    # topologies : TopologyList=context_client.ListTopologies(context_client)
        for topology_ in topologies.topologies:
            #topology_uuid : str = topology_.topology_id.topology_uuid.uuid
            topology_name : str = topology_.name
            context_topology_name  = 'Context({:s}):Topology({:s})'.format(context_name, topology_name)
            # Topos=context.GetTopology(list_topo.topology_id)
            LOGGER.debug("topo (AddContextDevices) %s",topology_)
            # details=context_client.GetTopologyDetails(topology_.topology_id)
            # LOGGER.info("details (AddContextDevices) %s",details)
            devices=context_client.ListDevices(Empty())
            # LOGGER.info("devices (driverSettings) %s",devices)
            device_names=[]
            device_ips=[]
            for device_ in devices.devices:
                LOGGER.info("device_ (AddContextDevices) %s",device_.name)
                device_names.append(device_.name)
                for config_rule_ in device_.device_config.config_rules:
                    if config_rule_.custom.resource_key == "_connect/address":
                        LOGGER.info("device_.resource_value-addr (driverSettings) %s",
                        config_rule_.custom.resource_value)
                        device_ips=config_rule_.custom.resource_value
                        
        return device_names,device_ips

def GetContextDevices(context_client : ContextClient) -> bool:
    """
    Returns de device name and its corresponding device_ip existing in context.
    """
    LOGGER.info("(AddContextDevices)")
    devices=context_client.ListDevices(Empty())
    device_names=[]
    device_ips=[]
    for device_ in devices.devices:
        LOGGER.debug("device_ (AddContextDevices) %s",device_.name)
        device_names.append(device_.name)
        for config_rule_ in device_.device_config.config_rules:
            if config_rule_.custom.resource_key == "_connect/address":
                LOGGER.info("device_.resource_value-addr (driverSettings) %s",
                config_rule_.custom.resource_value)
                device_ips=config_rule_.custom.resource_value
                    
    return device_names,device_ips

def CheckIfNodeInContext(node_name) -> bool:
    """
    Returns true if the node exists in the context.
    """
    context_client=ContextClient()
    context_client.connect()
    device_names,device_ips=GetContextDevices(context_client)
    LOGGER.info("(CheckIfNodeInContext) device_names: %s nodena %s",device_names,node_name)
    for node in device_names:
        if(node==node_name):
            LOGGER.info("(CheckIfNodeInContext) Node already in context")
            return True
    LOGGER.info("(CheckIfNodeInContext) Node NOT in context")
    return False