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

Merge branch 'develop' of https://labs.etsi.org/rep/tfs/controller into develop

parents e9e294e3 19e30211
Loading
Loading
Loading
Loading
+45 −59
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@

import grpc, json, logging
from typing import List, Tuple, Union
from bgpls_speaker.service.tools.DiscoveredDBManager import  DiscoveredDBManager, GetContextDevices
from bgpls_speaker.service.tools.DiscoveredDBManager import  DiscoveredDBManager, GetContextDevices, getEndpointFromIpInterface
from bgpls_speaker.service.tools.GrpcServer import GrpcServer
from common.method_wrappers.Decorator import MetricsPool, safe_and_metered_rpc_method
from common.proto.context_pb2 import DeviceId, Empty, EndPointId, Link, LinkId, Uuid
@@ -25,19 +25,6 @@ from common.proto.bgpls_pb2 import (
)
from common.proto.bgpls_pb2_grpc import BgplsServiceServicer

def json_to_list(json_str : str) -> List[Union[str, Tuple[str, str]]]:
    try:
        data = json.loads(json_str)
    except: # pylint: disable=bare-except
        return [('item', str(json_str))]

    if isinstance(data, dict):
        return [('kv', (key, value)) for key, value in data.items()]
    elif isinstance(data, list):
        return [('item', ', '.join(data))]
    else:
        return [('item', str(data))]
    
LOGGER = logging.getLogger(__name__)

METRICS_POOL = MetricsPool('Service', 'RPC')
@@ -121,12 +108,14 @@ class BgplsServiceServicerImpl(BgplsServiceServicer):
        """
        When a node is added to context via bgpls module this function checks if there are other nodes in the
        topology connected by links discovered via bgpls. Then, if the link exist adds it to the context.
        TODO: get endpoints from pce module
        """
        node_name=request.nodeName
        node_igp=self.discoveredDB.GetIgpIdFromNodeName(node_name)
        LOGGER.debug("(NotifyAddNodeToContext) Find links to nodes ")
        nodes_conected=self.discoveredDB.FindConnectedNodes(node_igp)
        LOGGER.debug("(NotifyAddNodeToContext) Find links to nodes %s:%s",node_name,node_igp)
        # Get nodes connected and links were the igpID appears
        nodes_conected, links_local, links_remote=self.discoveredDB.FindConnectedNodes(node_igp)
        o=[LOGGER.debug("(NotifyAddNodeToContext) Links local: %s %s",link_local.local_id, link_local.remote_id) for link_local in links_local]
        o=[LOGGER.debug("(NotifyAddNodeToContext) Links remote: %s %s",links_remote.local_id,links_remote.remote_id) for links_remote in links_remote]
        # Check if nodes are in context
        context_client=ContextClient()
        context_client.connect()
@@ -138,26 +127,41 @@ class BgplsServiceServicerImpl(BgplsServiceServicer):
        LOGGER.debug("(NotifyAddNodeToContext) nodes_conected_in_context: %s", nodes_conected_in_context)
        # TODO: next to function
        for remote_node in nodes_conected_in_context:

            # TODO: get endpoints connected to remote ip (pce¿)
            end_point1="eth-1/0/20"
            end_point2="eth-1/0/20"
            end_point_uuid1=Uuid(uuid=end_point1)
            end_point_uuid2=Uuid(uuid=end_point2)
            
            link_name_src_dest=node_name+"/"+end_point1+"=="+remote_node+"/"+end_point2
            LOGGER.info("(NotifyAddNodeToContext) creating link to...: %s", remote_node)
            remote_igp=self.discoveredDB.GetIgpIdFromNodeName(remote_node)
            # Get source device from name
            device_uuid_src=DeviceId(device_uuid=Uuid(uuid=node_name))
            device_src=context_client.GetDevice(device_uuid_src)

            link_name_dest_src=remote_node+"/"+end_point2+"=="+node_name+"/"+end_point1
            # Get destination device from name
            device_uuid_dest=DeviceId(device_uuid=Uuid(uuid=remote_node))
            device_dest=context_client.GetDevice(device_uuid_dest)
            
            self.getEndpointFromIpInterface(device_src,link.local_ipv4_id)
            self.getEndpointFromIpInterface(device_dest,link.remote_ipv4_id)
            # LOGGER.debug("(NotifyAddNodeToContext) Source: %s Destination: %s", device_src,device_dest)
            # Here I assume one link will always have same link in other direction
            # First direction for link
            # Get endpoints associated to link between devices
            for link_local in links_local:
                LOGGER.debug("(NotifyAddNodeToContext) local: %s %s", link_local.local_id,link_local.remote_id)
                LOGGER.debug("(NotifyAddNodeToContext) matches: %s %s", node_igp,remote_igp)
                if link_local.local_id == node_igp and link_local.remote_id == remote_igp:
                    LOGGER.debug("(NotifyAddNodeToContext) local_ipv4_id: %s", link_local.local_ipv4_id)
                    end_point1,ip_1=getEndpointFromIpInterface(device_src,link_local.local_ipv4_id)
                    LOGGER.debug("(NotifyAddNodeToContext) end_point1: %s", end_point1)

                    LOGGER.debug("(NotifyAddNodeToContext) remote_ipv4_id: %s", link_local.remote_ipv4_id)
                    end_point2,ip_2=getEndpointFromIpInterface(device_dest,link_local.remote_ipv4_id)
                    LOGGER.debug("(NotifyAddNodeToContext) end_point2: %s", end_point2)
                # LOGGER.debug("(NotifyAddNodeToContext) Source: %s Destination: %s", end_point1,end_point2)
                    
                    link_name_src_dest=node_name+"/"+end_point1+"=="+remote_node+"/"+end_point2

                    end_point_uuid1=Uuid(uuid=end_point1)
                    end_point_uuid2=Uuid(uuid=end_point2)

                    end_point_id1=EndPointId(endpoint_uuid=end_point_uuid1,device_id=device_uuid_src)

                    link_name_dest_src=remote_node+"/"+end_point2+"=="+node_name+"/"+end_point1

                    end_point_id2=EndPointId(endpoint_uuid=end_point_uuid2,device_id=device_uuid_dest)

                    end_point_ids_src_dest=[end_point_id1,end_point_id2]
@@ -172,21 +176,3 @@ class BgplsServiceServicerImpl(BgplsServiceServicer):
            LOGGER.debug("(NotifyAddNodeToContext) Link set id src--->dst: %s", link_id_src)
        context_client.close()
        return Empty()

    def getEndpointFromIpInterface(self,device,ipv4):
        """
        Get TFS endpoint from interface IPv4.
        """
        for config in device.device_config.config_rules:
            if config.WhichOneof('config_rule') == 'custom':
                for item_type, item in json_to_list(config.custom.resource_value):
                    if item_type == 'kv':
                        # LOGGER.debug("(getEndpointFromIpInterface) item: %s",item)
                        endpoint=item
                LOGGER.debug("(getEndpointFromIpInterface) config: %s",config.custom.resource_key)
                if "/interface" in config.custom.resource_key:
                    interface=config.custom.resource_key.split("/interface")[1].strip("[]")
                    LOGGER.debug("(getEndpointFromIpInterface) interface: %s",interface)
                    if ipv4 in config.custom.resource_value:
                        LOGGER.debug("(getEndpointFromIpInterface) value: %s",config.custom.resource_value)
        return endpoint
 No newline at end of file
+4 −4
Original line number Diff line number Diff line
@@ -97,16 +97,16 @@ public class grpcClient {
				strIgpL=link.getLocalNodeIGPId().toString();
			}
			String ipv4R;
			if(link.getiPv4RouterIDNeighborNodeLATLV()==null) 
			if(link.getiPv4RouterIDLocalNodeLATLV()==null) 
				ipv4R="-";
			else {
				ipv4R=link.getiPv4RouterIDNeighborNodeLATLV();
				ipv4R=link.getiPv4RouterIDLocalNodeLATLV();
			}
			String ipv4L;
			if(link.getiPv4RouterIDLocalNodeLATLV()==null) 
			if(link.getiPv4RouterIDNeighborNodeLATLV()==null) 
				ipv4L="-";
			else {
				ipv4L=link.getiPv4RouterIDLocalNodeLATLV();
				ipv4L=link.getiPv4RouterIDNeighborNodeLATLV();
			}
					
//			Build link for grpc message. need non null values in some cases
+59 −6
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import List
from typing import List, Tuple, Union
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
@@ -20,9 +20,22 @@ 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
import logging,json
LOGGER = logging.getLogger(__name__)

def json_to_list(json_str : str) -> List[Union[str, Tuple[str, str]]]:
    try:
        data = json.loads(json_str)
    except: # pylint: disable=bare-except
        return [('item', str(json_str))]

    if isinstance(data, dict):
        return [('kv', (key, value)) for key, value in data.items()]
    elif isinstance(data, list):
        return [('item', ', '.join(data))]
    else:
        return [('item', str(data))]
    
class DiscoveredDBManager:
    def __init__(self):
        self.discoveredDB=[]
@@ -37,15 +50,16 @@ class DiscoveredDBManager:
        # Check if node info message
        if(self.checkIfNodeInUpdate(update_request)):
            # Check if node exists
            to_add=True
            node_count=len(update_request.nodes)
            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
                    update_request.nodes.remove(node)
                    node_count=node_count-1
                else:
                    LOGGER.debug("(AddToDB) Node NOT in DB!!!")
            if(to_add):
            if(node_count>0):
                self.discoveredDB.append(update_request)
        else:
            # is a link
@@ -127,7 +141,9 @@ class DiscoveredDBManager:
        Return the IGP ID given a node name if exists in the discoveredDB.   
        """
        for update in self.discoveredDB:
            LOGGER.debug("(GetIgpIdFromNodeName)checking update: %s",update.toString())
            for node in update.nodes:
                LOGGER.debug("(GetIgpIdFromNodeName)checking nodes: %s",node.node_name)
                if(node.node_name==name):
                    return node.igp_id
        return None
@@ -165,6 +181,8 @@ class DiscoveredDBManager:
        # find links where the node appears
        links_to_node=[]
        nodes_conected=[]
        link_local=[]
        link_remote=[]
        for update in self.discoveredDB:
            for link in update.links:
                LOGGER.debug("(FindConnectedNodes) link in up:%s %s",
@@ -173,14 +191,16 @@ class DiscoveredDBManager:
                if(link.local_id == new_node):
                    links_to_node.append(link)
                    nodes_conected.append(link.remote.node_name)
                    link_local.append(link)
                if(link.remote_id == new_node):
                    links_to_node.append(link)
                    nodes_conected.append(link.local.node_name)
                    link_remote.append(link)
        
        if(nodes_conected):
            LOGGER.debug("(FindConnectedNodes) links to local node:%s",new_node)
            LOGGER.debug("(FindConnectedNodes) %s", nodes_conected)
            return nodes_conected
            return nodes_conected, link_local, link_remote
        LOGGER.debug("(FindConnectedNodes) NO LINKS TO OTHER NODES")
        return None

@@ -263,3 +283,36 @@ def CheckIfNodeInContext(node_name) -> bool:
            return True
    LOGGER.info("(CheckIfNodeInContext) Node NOT in context")
    return False

def getEndpointFromIpInterface(device,ipv4):
    """
    Get TFS endpoint uuid drom given device having the IPv4 interface.
    """
    for config in device.device_config.config_rules:
        if config.WhichOneof('config_rule') == 'custom':
            # for item_type, item in json_to_list(config.custom.resource_value):
            #     if item_type == 'kv':
            #         # LOGGER.debug("(getEndpointFromIpInterface) item: %s",item)
            #         endpoint_item=item
            # LOGGER.debug("(getEndpointFromIpInterface) config: %s",config.custom.resource_key)
            if "/interface" in config.custom.resource_key:
                iface=config.custom.resource_key.split("/interface")[1].strip("[]")
                LOGGER.debug("(getEndpointFromIpInterface) interface: %s",iface)
                if ipv4 in config.custom.resource_value:
                    LOGGER.debug("(getEndpointFromIpInterface) value: %s",config.custom.resource_value)
                    resource_dict=json.loads(config.custom.resource_value)
                    interface = resource_dict['name']
                    resource_ip=resource_dict['address_ip']
    # Search for endpoint uuid assigned to interface
    for config in device.device_config.config_rules:
        if config.WhichOneof('config_rule') == 'custom':
            if "/endpoints/endpoint" in config.custom.resource_key:
                key=config.custom.resource_key.split("/endpoints/endpoint")[1].strip("[]")
                LOGGER.debug("(getEndpointFromIpInterface) key: %s",key)
                if interface in key:
                    LOGGER.debug("(getEndpointFromIpInterface) value: %s",config.custom.resource_value)
                    endpoint=config.custom.resource_key.split("/endpoints/endpoint")[1].strip("[]")
                    resource_dict_endpoint=json.loads(config.custom.resource_value)
                    return resource_dict_endpoint['uuid'],resource_ip
                
    return None,ipv4
 No newline at end of file
+11 −2
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ class UpdateRequest:
      out+=self.as_path_segment

      for node in self.nodes:
          out+="name"
          out+=node.node_name
          out+=node.igp_id
          out+=str(node.bgpls_id)
@@ -84,6 +85,14 @@ class NodeInfo:
        self.bgpls_id = bgpls_id.strip("/")
        self.as_id = as_id
        self.learnt_from=learnt_from
    def toString(self):
        # Debug purposes
        out = "name"
        out+=self.node_name
        out+=self.igp_id
        out+=str(self.bgpls_id)
        out+=str(self.as_id)
        out+=self.learnt_from

    @classmethod
    def from_proto(cls, proto_node):
+2 −2
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@
                </tr>
            {% endif %}
        </tbody>
        <tbody>
        <!-- <tbody>
            {% if dislink %}
                {% for link in dislink %}
                <tr>
@@ -100,7 +100,7 @@
                    <td colspan="3">No devices found</td>
                </tr>
            {% endif %}
        </tbody>
        </tbody> -->
    </table>
        
    <script src="https://d3js.org/d3.v4.min.js"></script>