VXLAN test with dot1q tagging.
[csit.git] / resources / libraries / python / topology.py
index 1034160..0f26d2c 100644 (file)
 
 """Defines nodes and topology structure."""
 
-from resources.libraries.python.parsers.JsonParser import JsonParser
-from resources.libraries.python.VatExecutor import VatExecutor
-from resources.libraries.python.ssh import SSH
-from resources.libraries.python.InterfaceSetup import InterfaceSetup
 from robot.api import logger
 from robot.libraries.BuiltIn import BuiltIn
 from robot.api.deco import keyword
@@ -26,7 +22,7 @@ __all__ = ["DICT__nodes", 'Topology']
 
 
 def load_topo_from_yaml():
-    """Loads topology from file defined in "${TOPOLOGY_PATH}" variable
+    """Load topology from file defined in "${TOPOLOGY_PATH}" variable
 
     :return: nodes from loaded topology
     """
@@ -42,13 +38,16 @@ class NodeType(object):
     DUT = 'DUT'
     # Traffic Generator (this node has traffic generator on it)
     TG = 'TG'
+    # Virtual Machine (this node running on DUT node)
+    VM = 'VM'
+
 
 class NodeSubTypeTG(object):
     #T-Rex traffic generator
     TREX = 'TREX'
     # Moongen
     MOONGEN = 'MOONGEN'
-    #IxNetwork
+    # IxNetwork
     IXNET = 'IXNET'
 
 DICT__nodes = load_topo_from_yaml()
@@ -61,9 +60,6 @@ class Topology(object):
     the used topology.
     """
 
-    def __init__(self):
-        pass
-
     @staticmethod
     def get_node_by_hostname(nodes, hostname):
         """Get node from nodes of the topology by hostname.
@@ -102,7 +98,7 @@ class Topology(object):
 
     @staticmethod
     def _get_interface_by_key_value(node, key, value):
-        """ Return node interface name according to key and value
+        """Return node interface name according to key and value
 
         :param node: :param node: the node dictionary
         :param key: key by which to select the interface.
@@ -137,8 +133,6 @@ class Topology(object):
 
         This method returns the interface names asociated with given links
         for a given node.
-        The resulting dictionary can be then used to with VatConfigGenerator
-        to generate a VAT script with proper interface names.
         :param link_names: list of names of the link that a interface is
         connected to.
         :param node: the node topology directory
@@ -169,190 +163,40 @@ class Topology(object):
         return self._get_interface_by_key_value(node, "vpp_sw_index", sw_index)
 
     @staticmethod
-    def convert_mac_to_number_list(mac_address):
-        """Convert mac address string to list of decimal numbers.
-
-        Converts a : separated mac address to decimal number list as used
-        in json interface dump.
-        :param mac_address: string mac address
-        :return: list representation of mac address
-        """
-
-        list_mac = []
-        for num in mac_address.split(":"):
-            list_mac.append(int(num, 16))
-        return list_mac
-
-    def _extract_vpp_interface_by_mac(self, interfaces_list, mac_address):
-        """Returns interface dictionary from interface_list by mac address.
-
-        Extracts interface dictionary from all of the interfaces in interfaces
-        list parsed from json according to mac_address of the interface
-        :param interfaces_list: dictionary of all interfaces parsed from json
-        :param mac_address: string mac address of interface we are looking for
-        :return: interface dictionary from json
-        """
-
-        interface_dict = {}
-        list_mac_address = self.convert_mac_to_number_list(mac_address)
-        logger.trace(str(list_mac_address))
-        for interface in interfaces_list:
-            # TODO: create vat json integrity checking and move there
-            if "l2_address" not in interface:
-                raise KeyError(
-                    "key l2_address not found in interface dict."
-                    "Probably input list is not parsed from correct VAT "
-                    "json output.")
-            if "l2_address_length" not in interface:
-                raise KeyError(
-                    "key l2_address_length not found in interface "
-                    "dict. Probably input list is not parsed from correct "
-                    "VAT json output.")
-            mac_from_json = interface["l2_address"][:6]
-            if mac_from_json == list_mac_address:
-                if interface["l2_address_length"] != 6:
-                    raise ValueError("l2_address_length value is not 6.")
-                interface_dict = interface
-                break
-        return interface_dict
-
-    def vpp_interface_name_from_json_by_mac(self, json_data, mac_address):
-        """Return vpp interface name string from VAT interface dump json output
-
-        Extracts the name given to an interface by VPP.
-        These interface names differ from what you would see if you
-        used the ipconfig or similar command.
-        Required json data can be obtained by calling :
-        VatExecutor.execute_script_json_out("dump_interfaces.vat", node)
-        :param json_data: string json data from sw_interface_dump VAT command
-        :param mac_address: string containing mac address of interface
-        whose vpp name we wish to discover.
-        :return: string vpp interface name
-        """
-
-        interfaces_list = JsonParser().parse_data(json_data)
-        # TODO: checking if json data is parsed correctly
-        interface_dict = self._extract_vpp_interface_by_mac(interfaces_list,
-                                                            mac_address)
-        interface_name = interface_dict["interface_name"]
-        return interface_name
-
-    def _update_node_interface_data_from_json(self, node, interface_dump_json):
-        """ Update node vpp data in node__DICT from json interface dump.
-
-        This method updates vpp interface names and sw indexexs according to
-        interface mac addresses found in interface_dump_json
-        :param node: node dictionary
-        :param interface_dump_json: json output from dump_interface_list VAT
-        command
-        """
-
-        interface_list = JsonParser().parse_data(interface_dump_json)
-        for ifc in node['interfaces'].values():
-            if 'link' not in ifc:
-                continue
-            if_mac = ifc['mac_address']
-            interface_dict = self._extract_vpp_interface_by_mac(interface_list,
-                                                                if_mac)
-            if not interface_dict:
-                raise Exception('Interface {0} not found by MAC {1}'.
-                        format(ifc, if_mac))
-            ifc['name'] = interface_dict["interface_name"]
-            ifc['vpp_sw_index'] = interface_dict["sw_if_index"]
-
-    def update_vpp_interface_data_on_node(self, node):
-        """Update vpp generated interface data for a given node in DICT__nodes
-
-        Updates interface names, software index numbers and any other details
-        generated specifically by vpp that are unknown before testcase run.
-        :param node: Node selected from DICT__nodes
-        """
-
-        vat_executor = VatExecutor()
-        vat_executor.execute_script_json_out("dump_interfaces.vat", node)
-        interface_dump_json = vat_executor.get_script_stdout()
-        self._update_node_interface_data_from_json(node,
-                                                   interface_dump_json)
-
-    @staticmethod
-    def update_tg_interface_data_on_node(node):
-        """Update interface name for TG/linux node in DICT__nodes
+    def get_interface_sw_index(node, interface):
+        """Get VPP sw_if_index for the interface.
 
-        :param node: Node selected from DICT__nodes.
+        :param node: Node to get interface sw_if_index on.
+        :param interface: Interface identifier.
         :type node: dict
-
-        .. note::
-            # for dev in `ls /sys/class/net/`;
-            > do echo "\"`cat /sys/class/net/$dev/address`\": \"$dev\""; done
-            "52:54:00:9f:82:63": "eth0"
-            "52:54:00:77:ae:a9": "eth1"
-            "52:54:00:e1:8a:0f": "eth2"
-            "00:00:00:00:00:00": "lo"
-
-        .. todo:: parse lshw -json instead
-        """
-        # First setup interface driver specified in yaml file
-        InterfaceSetup.tg_set_interfaces_default_driver(node)
-
-        # Get interface names
-        ssh = SSH()
-        ssh.connect(node)
-
-        cmd = 'for dev in `ls /sys/class/net/`; do echo "\\"`cat ' \
-              '/sys/class/net/$dev/address`\\": \\"$dev\\""; done;'
-
-        (ret_code, stdout, _) = ssh.exec_command(cmd)
-        if int(ret_code) != 0:
-            raise Exception('Get interface name and MAC failed')
-        tmp = "{" + stdout.rstrip().replace('\n', ',') + "}"
-        interfaces = JsonParser().parse_data(tmp)
-        for if_k, if_v in node['interfaces'].items():
-            if if_k == 'mgmt':
-                continue
-            name = interfaces.get(if_v['mac_address'])
-            if name is None:
-                continue
-            if_v['name'] = name
-
-        # Set udev rules for interfaces
-        InterfaceSetup.tg_set_interfaces_udev_rules(node)
-
-    def update_all_interface_data_on_all_nodes(self, nodes):
-        """ Update interface names on all nodes in DICT__nodes
-
-        :param nodes: Nodes in the topology.
-        :type nodes: dict
-
-        This method updates the topology dictionary by querying interface lists
-        of all nodes mentioned in the topology dictionary.
-        It does this by dumping interface list to json output from all devices
-        using vpp_api_test, and pairing known information from topology
-        (mac address/pci address of interface) to state from VPP.
-        For TG/linux nodes add interface name only.
+        :type interface: str or int
+        :return: Return sw_if_index or None if not found.
         """
-
-        for node_data in nodes.values():
-            if node_data['type'] == NodeType.DUT:
-                self.update_vpp_interface_data_on_node(node_data)
-            elif node_data['type'] == NodeType.TG:
-                self.update_tg_interface_data_on_node(node_data)
+        try:
+            return int(interface)
+        except ValueError:
+            for port in node['interfaces'].values():
+                port_name = port.get('name')
+                if port_name == interface:
+                    return port.get('vpp_sw_index')
+            return None
 
     @staticmethod
-    def get_interface_sw_index(node, interface):
-        """Get VPP sw_index for the interface.
+    def get_interface_mtu(node, interface):
+        """Get interface MTU.
 
-        :param node: Node to get interface sw_index on.
+        Returns physical layer MTU (max. size of Ethernet frame).
+        :param node: Node to get interface MTU on.
         :param interface: Interface name.
         :type node: dict
         :type interface: str
-        :return: Return sw_index or None if not found.
+        :return: MTU or None if not found.
+        :rtype: int
         """
         for port in node['interfaces'].values():
             port_name = port.get('name')
-            if port_name is None:
-                continue
             if port_name == interface:
-                return port.get('vpp_sw_index')
+                return port.get('mtu')
 
         return None
 
@@ -384,8 +228,6 @@ class Topology(object):
         """
         for port in node['interfaces'].values():
             port_name = port.get('name')
-            if port_name is None:
-                continue
             if port_name == interface:
                 return port.get('mac_address')
 
@@ -407,7 +249,7 @@ class Topology(object):
         :rtype: (dict, dict)
         """
         link_name = None
-       # get link name where the interface belongs to
+        # get link name where the interface belongs to
         for port_name, port_data in node['interfaces'].iteritems():
             if port_name == 'mgmt':
                 continue
@@ -516,7 +358,7 @@ class Topology(object):
 
     @staticmethod
     def _get_node_active_link_names(node):
-        """Returns list of link names that are other than mgmt links
+        """Return list of link names that are other than mgmt links
 
         :param node: node topology dictionary
         :return: list of strings that represent link names occupied by the node
@@ -532,7 +374,7 @@ class Topology(object):
 
     @keyword('Get active links connecting "${node1}" and "${node2}"')
     def get_active_connecting_links(self, node1, node2):
-        """Returns list of link names that connect together node1 and node2
+        """Return list of link names that connect together node1 and node2
 
         :param node1: node topology dictionary
         :param node2: node topology dictionary
@@ -574,7 +416,7 @@ class Topology(object):
         :param node2: Second node.
         :type node1: dict
         :type node2: dict
-        :return: Engress interfaces.
+        :return: Egress interfaces.
         :rtype: list
         """
         interfaces = []
@@ -602,25 +444,25 @@ class Topology(object):
         :param node2: Second node.
         :type node1: dict
         :type node2: dict
-        :return: Engress interface.
+        :return: Egress interface.
         :rtype: str
         """
         interfaces = self.get_egress_interfaces_for_nodes(node1, node2)
         if not interfaces:
-            raise RuntimeError('No engress interface for nodes')
+            raise RuntimeError('No egress interface for nodes')
         return interfaces[0]
 
     @keyword('Get link data useful in circular topology test from tg "${tgen}"'
              ' dut1 "${dut1}" dut2 "${dut2}"')
     def get_links_dict_from_nodes(self, tgen, dut1, dut2):
-        """Returns link combinations used in tests in circular topology.
+        """Return link combinations used in tests in circular topology.
 
         For the time being it returns links from the Node path:
         TG->DUT1->DUT2->TG
-        :param tg: traffic generator node data
+        :param tgen: traffic generator node data
         :param dut1: DUT1 node data
         :param dut2: DUT2 node data
-        :type tg: dict
+        :type tgen: dict
         :type dut1: dict
         :type dut2: dict
         :return: dictionary of possible link combinations
@@ -662,8 +504,10 @@ class Topology(object):
 
     @staticmethod
     def get_node_hostname(node):
+        """Return host (hostname/ip address) of the node.
+
+        :param node: Node created from topology.
+        :type node: dict
+        :return: host as 'str' type
         """
-        :param node: node dictionary
-        :return: host name as 'str' type
-        """
-        return node['host']
\ No newline at end of file
+        return node['host']