X-Git-Url: https://gerrit.fd.io/r/gitweb?p=csit.git;a=blobdiff_plain;f=resources%2Flibraries%2Fpython%2Ftopology.py;h=4ff68ec43df07be95a53c7ed0f90e5603e387b25;hp=c02991fbde33ceb6b64194020920500e1f01350c;hb=7bfb36dfd9284bbca10881e31e14108c7d468b7c;hpb=19c91adadd57bfc4e7514993b2a711a826d52e04 diff --git a/resources/libraries/python/topology.py b/resources/libraries/python/topology.py index c02991fbde..4ff68ec43d 100644 --- a/resources/libraries/python/topology.py +++ b/resources/libraries/python/topology.py @@ -18,7 +18,7 @@ from collections import Counter from yaml import load from robot.api import logger -from robot.libraries.BuiltIn import BuiltIn +from robot.libraries.BuiltIn import BuiltIn, RobotNotRunningError from robot.api.deco import keyword __all__ = ["DICT__nodes", 'Topology'] @@ -27,14 +27,19 @@ __all__ = ["DICT__nodes", 'Topology'] def load_topo_from_yaml(): """Load topology from file defined in "${TOPOLOGY_PATH}" variable. - :return: Nodes from loaded topology. + :returns: Nodes from loaded topology. """ - topo_path = BuiltIn().get_variable_value("${TOPOLOGY_PATH}") + try: + topo_path = BuiltIn().get_variable_value("${TOPOLOGY_PATH}") + except RobotNotRunningError: + return '' with open(topo_path) as work_file: return load(work_file.read())['nodes'] + # pylint: disable=invalid-name + class NodeType(object): """Defines node types used in topology dictionaries.""" # Device Under Test (this node has VPP running on it) @@ -46,6 +51,7 @@ class NodeType(object): class NodeSubTypeTG(object): + """Defines node sub-type TG - traffic generator.""" # T-Rex traffic generator TREX = 'TREX' # Moongen @@ -81,7 +87,7 @@ class Topology(object): :param ptype: Port type, used as key prefix. :type node: dict :type ptype: str - :return: Port key or None + :returns: Port key or None :rtype: string or None """ max_ports = 1000000 @@ -93,6 +99,21 @@ class Topology(object): break return iface + @staticmethod + def remove_port(node, iface_key): + """Remove required port from active topology. + + :param node: Node to remove port on. + :param: iface_key: Topology key of the interface. + :type node: dict + :type iface_key: str + :returns: Nothing + """ + try: + node['interfaces'].pop(iface_key) + except KeyError: + pass + @staticmethod def remove_all_ports(node, ptype): """Remove all ports with ptype as prefix. @@ -101,12 +122,28 @@ class Topology(object): :param: ptype: Port type, used as key prefix. :type node: dict :type ptype: str - :return: Nothing + :returns: Nothing """ for if_key in list(node['interfaces']): if if_key.startswith(str(ptype)): node['interfaces'].pop(if_key) + @staticmethod + def remove_all_added_ports_on_all_duts_from_topology(nodes): + """Remove all added ports on all DUT nodes in the topology. + + :param nodes: Nodes in the topology. + :type nodes: dict + :returns: Nothing + """ + port_types = ('subinterface', 'vlan_subif', 'memif', 'tap', 'vhost', + 'loopback', 'gre_tunnel', 'vxlan_tunnel') + + for node_data in nodes.values(): + if node_data['type'] == NodeType.DUT: + for ptype in port_types: + Topology.remove_all_ports(node_data, ptype) + @staticmethod def update_interface_sw_if_index(node, iface_key, sw_if_index): """Update sw_if_index on the interface from the node. @@ -120,6 +157,19 @@ class Topology(object): """ node['interfaces'][iface_key]['vpp_sw_index'] = int(sw_if_index) + @staticmethod + def update_interface_name(node, iface_key, name): + """Update name on the interface from the node. + + :param node: Node to update name on. + :param iface_key: Topology key of the interface. + :param name: Interface name to store. + :type node: dict + :type iface_key: str + :type name: str + """ + node['interfaces'][iface_key]['name'] = str(name) + @staticmethod def update_interface_mac_address(node, iface_key, mac_address): """Update mac_address on the interface from the node. @@ -146,6 +196,59 @@ class Topology(object): """ node['interfaces'][iface_key]['vhost_socket'] = str(vhost_socket) + @staticmethod + def update_interface_memif_socket(node, iface_key, memif_socket): + """Update memif socket name on the interface from the node. + + :param node: Node to update socket name on. + :param iface_key: Topology key of the interface. + :param memif_socket: Path to named socket on node. + :type node: dict + :type iface_key: str + :type memif_socket: str + """ + node['interfaces'][iface_key]['memif_socket'] = str(memif_socket) + + @staticmethod + def update_interface_memif_id(node, iface_key, memif_id): + """Update memif ID on the interface from the node. + + :param node: Node to update memif ID on. + :param iface_key: Topology key of the interface. + :param memif_id: Memif interface ID. + :type node: dict + :type iface_key: str + :type memif_id: str + """ + node['interfaces'][iface_key]['memif_id'] = str(memif_id) + + @staticmethod + def update_interface_memif_role(node, iface_key, memif_role): + """Update memif role on the interface from the node. + + :param node: Node to update memif role on. + :param iface_key: Topology key of the interface. + :param memif_role: Memif role. + :type node: dict + :type iface_key: str + :type memif_role: str + """ + node['interfaces'][iface_key]['memif_role'] = str(memif_role) + + @staticmethod + def update_interface_tap_dev_name(node, iface_key, dev_name): + """Update device name on the tap interface from the node. + + :param node: Node to update tap device name on. + :param iface_key: Topology key of the interface. + :param dev_name: Device name of the tap interface. + :type node: dict + :type iface_key: str + :type dev_name: str + :returns: Nothing + """ + node['interfaces'][iface_key]['dev_name'] = str(dev_name) + @staticmethod def get_node_by_hostname(nodes, hostname): """Get node from nodes of the topology by hostname. @@ -154,7 +257,7 @@ class Topology(object): :param hostname: Host name. :type nodes: dict :type hostname: str - :return: Node dictionary or None if not found. + :returns: Node dictionary or None if not found. """ for node in nodes.values(): if node['host'] == hostname: @@ -168,7 +271,7 @@ class Topology(object): :param nodes: Nodes of the test topology. :type nodes: dict - :return: Links in the topology. + :returns: Links in the topology. :rtype: list """ links = [] @@ -193,7 +296,7 @@ class Topology(object): :type node: dict :type key: string :type value: string - :return: Interface key from topology file + :returns: Interface key from topology file :rtype: string """ interfaces = node['interfaces'] @@ -217,7 +320,7 @@ class Topology(object): :param iface_name: Interface name (string form). :type node: dict :type iface_name: string - :return: Interface key. + :returns: Interface key. :rtype: str """ return Topology._get_interface_by_key_value(node, "name", iface_name) @@ -233,7 +336,7 @@ class Topology(object): :param link_name: Name of the link that a interface is connected to. :type node: dict :type link_name: string - :return: Interface key of the interface connected to the given link. + :returns: Interface key of the interface connected to the given link. :rtype: str """ return Topology._get_interface_by_key_value(node, "link", link_name) @@ -249,7 +352,7 @@ class Topology(object): connected to. :type node: dict :type link_names: list - :return: Dictionary of interface names that are connected to the given + :returns: Dictionary of interface names that are connected to the given links. :rtype: dict """ @@ -275,7 +378,7 @@ class Topology(object): :param sw_index: Sw_index of the link that a interface is connected to. :type node: dict :type sw_index: int - :return: Interface name of the interface connected to the given link. + :returns: Interface name of the interface connected to the given link. :rtype: str """ return Topology._get_interface_by_key_value(node, "vpp_sw_index", @@ -289,12 +392,12 @@ class Topology(object): :param iface_key: Interface key from topology file, or sw_index. :type node: dict :type iface_key: str/int - :return: Return sw_if_index or None if not found. + :returns: Return sw_if_index or None if not found. """ try: if isinstance(iface_key, basestring): return node['interfaces'][iface_key].get('vpp_sw_index') - #FIXME: use only iface_key, do not use integer + # TODO: use only iface_key, do not use integer else: return int(iface_key) except (KeyError, ValueError): @@ -308,7 +411,7 @@ class Topology(object): :param iface_name: Interface name. :type node: dict :type iface_name: str - :return: Return sw_if_index or None if not found. + :returns: Return sw_if_index or None if not found. :raises TypeError: If provided interface name is not a string. """ try: @@ -329,7 +432,7 @@ class Topology(object): :param iface_key: Interface key from topology file. :type node: dict :type iface_key: str - :return: MTU or None if not found. + :returns: MTU or None if not found. :rtype: int """ try: @@ -346,14 +449,91 @@ class Topology(object): :param iface_key: Interface key from topology file. :type node: dict :type iface_key: str - :return: Interface name or None if not found. - :rtype: int + :returns: Interface name or None if not found. + :rtype: str """ try: return node['interfaces'][iface_key].get('name') except KeyError: return None + @staticmethod + def convert_interface_reference_to_key(node, interface): + """Takes interface reference in any format + (name, link name, interface key or sw_if_index) + and converts to interface key using Topology methods. + + :param node: Node in topology. + :param interface: Name, sw_if_index, link name or key of an interface + on the node. + Valid formats are: sw_if_index, key, name. + :type node: dict + :type interface: str or int + + :returns: Interface key. + :rtype: str + + :raises TypeError: If provided with invalid interface argument. + :raises RuntimeError: If the interface does not exist in topology. + """ + + if isinstance(interface, int): + key = Topology.get_interface_by_sw_index(node, interface) + if key is None: + raise RuntimeError("Interface with sw_if_index={0} does not " + "exist in topology.".format(interface)) + elif interface in Topology.get_node_interfaces(node): + key = interface + elif interface in Topology.get_links({"dut": node}): + key = Topology.get_interface_by_link_name(node, interface) + elif isinstance(interface, basestring): + key = Topology.get_interface_by_name(node, interface) + if key is None: + raise RuntimeError("Interface with key, name or link name " + "\"{0}\" does not exist in topology." + .format(interface)) + else: + raise TypeError("Type of interface argument must be integer" + " or string.") + return key + + @staticmethod + def convert_interface_reference(node, interface, wanted_format): + """Takes interface reference in any format + (name, link name, topology key or sw_if_index) and returns + its equivalent in the desired format. + + :param node: Node in topology. + :param interface: Name, sw_if_index, link name or key of an interface + on the node. + :param wanted_format: Format of return value wanted. + Valid options are: sw_if_index, key, name. + :type node: dict + :type interface: str or int + :type wanted_format: str + + :returns: Interface name, interface key or sw_if_index. + :rtype: str or int + + :raises TypeError, ValueError: If provided with invalid arguments. + :raises RuntimeError: If the interface does not exist in topology. + """ + + key = Topology.convert_interface_reference_to_key(node, interface) + + conversions = { + "key": lambda x, y: y, + "name": Topology.get_interface_name, + "sw_if_index": Topology.get_interface_sw_index + } + + try: + return conversions[wanted_format](node, key) + except KeyError: + raise ValueError("Unrecognized return value wanted: {0}." + "Valid options are key, name, sw_if_index" + .format(wanted_format)) + @staticmethod def get_interface_numa_node(node, iface_key): """Get interface numa node. @@ -364,7 +544,7 @@ class Topology(object): :param iface_key: Interface key from topology file. :type node: dict :type iface_key: str - :return: numa node id, None if not available. + :returns: numa node id, None if not available. :rtype: int """ try: @@ -412,7 +592,7 @@ class Topology(object): :param iface_key: Interface key from topology file. :type node: dict :type iface_key: str - :return: Return MAC or None if not found. + :returns: Return MAC or None if not found. """ try: return node['interfaces'][iface_key].get('mac_address') @@ -431,7 +611,7 @@ class Topology(object): :type nodes_info: dict :type node: dict :type iface_key: str - :return: Return (node, interface_key) tuple or None if not found. + :returns: Return (node, interface_key) tuple or None if not found. :rtype: (dict, str) """ link_name = None @@ -466,7 +646,7 @@ class Topology(object): :param iface_key: Interface key from topology file. :type node: dict :type iface_key: str - :return: Return PCI address or None if not found. + :returns: Return PCI address or None if not found. """ try: return node['interfaces'][iface_key].get('pci_address') @@ -481,7 +661,7 @@ class Topology(object): :param iface_key: Interface key from topology file. :type node: dict :type iface_key: str - :return: Return interface driver or None if not found. + :returns: Return interface driver or None if not found. """ try: return node['interfaces'][iface_key].get('driver') @@ -494,7 +674,7 @@ class Topology(object): :param node: Node to get list of interfaces from. :type node: dict - :return: Return list of keys of all interfaces. + :returns: Return list of keys of all interfaces. :rtype: list """ return node['interfaces'].keys() @@ -507,7 +687,7 @@ class Topology(object): :param link_name: Link name. :type node: dict :type link_name: str - :return: MAC address string. + :returns: MAC address string. :rtype: str """ for port in node['interfaces'].values(): @@ -523,7 +703,7 @@ class Topology(object): :param filter_list: Link filter criteria. :type node: dict :type filter_list: list of strings - :return: List of strings that represent link names occupied by the node. + :returns: List of strings representing link names occupied by the node. :rtype: list """ interfaces = node['interfaces'] @@ -535,7 +715,7 @@ class Topology(object): if filt == interface['model']: link_names.append(interface['link']) elif (filter_list is not None) and ('model' not in interface): - logger.trace("Cannot apply filter on interface: {}" + logger.trace('Cannot apply filter on interface: {}' .format(str(interface))) else: link_names.append(interface['link']) @@ -557,7 +737,7 @@ class Topology(object): :type node2: dict :type filter_list_node1: list of strings :type filter_list_node2: list of strings - :return: List of strings that represent connecting link names. + :returns: List of strings that represent connecting link names. :rtype: list """ @@ -589,7 +769,7 @@ class Topology(object): :param node2: Connected node. :type node1: dict :type node2: dict - :return: Name of link connecting the two nodes together. + :returns: Name of link connecting the two nodes together. :rtype: str :raises: RuntimeError """ @@ -608,7 +788,7 @@ class Topology(object): :param node2: Second node. :type node1: dict :type node2: dict - :return: Egress interfaces. + :returns: Egress interfaces. :rtype: list """ interfaces = [] @@ -636,7 +816,7 @@ class Topology(object): :param node2: Second node. :type node1: dict :type node2: dict - :return: Egress interface name. + :returns: Egress interface name. :rtype: str """ interfaces = self.get_egress_interfaces_name_for_nodes(node1, node2) @@ -669,7 +849,7 @@ class Topology(object): :type tgen: dict :type dut1: dict :type dut2: dict - :return: Dictionary of possible link combinations. + :returns: Dictionary of possible link combinations. :rtype: dict """ # TODO: replace with generic function. @@ -693,7 +873,7 @@ class Topology(object): :param node: Node to examine. :type node: dict - :return: True if node is type of TG, otherwise False. + :returns: True if node is type of TG, otherwise False. :rtype: bool """ return node['type'] == NodeType.TG @@ -704,11 +884,39 @@ class Topology(object): :param node: Node created from topology. :type node: dict - :return: Hostname or IP address. + :returns: Hostname or IP address. :rtype: str """ return node['host'] + @staticmethod + def get_cryptodev(node): + """Return Crytodev configuration of the node. + + :param node: Node created from topology. + :type node: dict + :returns: Cryptodev configuration string. + :rtype: str + """ + try: + return node['cryptodev'] + except KeyError: + return None + + @staticmethod + def get_uio_driver(node): + """Return uio-driver configuration of the node. + + :param node: Node created from topology. + :type node: dict + :returns: uio-driver configuration string. + :rtype: str + """ + try: + return node['uio_driver'] + except KeyError: + return None + @staticmethod def set_interface_numa_node(node, iface_key, numa_node_id): """Set interface numa_node location. @@ -717,7 +925,7 @@ class Topology(object): :param iface_key: Interface key from topology file. :type node: dict :type iface_key: str - :return: Return iface_key or None if not found. + :returns: Return iface_key or None if not found. """ try: node['interfaces'][iface_key]['numa_node'] = numa_node_id