aboutsummaryrefslogtreecommitdiffstats
path: root/resources
diff options
context:
space:
mode:
Diffstat (limited to 'resources')
-rw-r--r--resources/libraries/python/DUTSetup.py27
-rw-r--r--resources/libraries/python/DropRateSearch.py9
-rw-r--r--resources/libraries/python/HTTPRequest.py4
-rw-r--r--resources/libraries/python/HoneycombUtil.py4
-rw-r--r--resources/libraries/python/IPUtil.py17
-rw-r--r--resources/libraries/python/IPv4NodeAddress.py26
-rw-r--r--resources/libraries/python/IPv4Setup.py91
-rw-r--r--resources/libraries/python/IPv4Util.py51
-rw-r--r--resources/libraries/python/IPv6NodesAddr.py22
-rw-r--r--resources/libraries/python/IPv6Setup.py142
-rw-r--r--resources/libraries/python/IPv6Util.py69
-rw-r--r--resources/libraries/python/InterfaceUtil.py21
-rw-r--r--resources/libraries/python/L2Util.py55
-rw-r--r--resources/libraries/python/NodePath.py13
-rw-r--r--resources/libraries/python/PacketVerifier.py34
-rw-r--r--resources/libraries/python/QemuUtils.py8
-rw-r--r--resources/libraries/python/Routing.py4
-rw-r--r--resources/libraries/python/SetupFramework.py39
-rw-r--r--resources/libraries/python/TGSetup.py4
-rw-r--r--resources/libraries/python/Trace.py1
-rw-r--r--resources/libraries/python/TrafficGenerator.py90
-rw-r--r--resources/libraries/python/TrafficScriptArg.py2
-rw-r--r--resources/libraries/python/TrafficScriptExecutor.py63
-rw-r--r--resources/libraries/python/VatExecutor.py83
-rw-r--r--resources/libraries/python/VatJsonUtil.py4
-rw-r--r--resources/libraries/python/VppConfigGenerator.py155
-rw-r--r--resources/libraries/python/VppCounters.py52
-rw-r--r--resources/libraries/python/parsers/JsonParser.py33
-rw-r--r--resources/libraries/python/ssh.py102
-rw-r--r--resources/libraries/python/topology.py131
-rw-r--r--resources/libraries/robot/ipv6.robot6
-rw-r--r--resources/libraries/robot/performance.robot2
-rwxr-xr-xresources/tools/topology/update_topology.py41
33 files changed, 722 insertions, 683 deletions
diff --git a/resources/libraries/python/DUTSetup.py b/resources/libraries/python/DUTSetup.py
index d5ebf9a069..a0a48708b7 100644
--- a/resources/libraries/python/DUTSetup.py
+++ b/resources/libraries/python/DUTSetup.py
@@ -12,34 +12,37 @@
# limitations under the License.
from robot.api import logger
-from topology import NodeType
-from ssh import SSH
-from constants import Constants
+from resources.libraries.python.topology import NodeType
+from resources.libraries.python.ssh import SSH
+from resources.libraries.python.constants import Constants
-class DUTSetup(object):
- def start_vpp_service_on_all_duts(self, nodes):
+class DUTSetup(object):
+ @staticmethod
+ def start_vpp_service_on_all_duts(nodes):
"""Start up the VPP service on all nodes."""
ssh = SSH()
for node in nodes.values():
if node['type'] == NodeType.DUT:
ssh.connect(node)
(ret_code, stdout, stderr) = \
- ssh.exec_command_sudo('service vpp restart')
+ ssh.exec_command_sudo('service vpp restart')
if 0 != int(ret_code):
logger.debug('stdout: {0}'.format(stdout))
logger.debug('stderr: {0}'.format(stderr))
raise Exception('DUT {0} failed to start VPP service'.
- format(node['host']))
+ format(node['host']))
- def setup_all_duts(self, nodes):
+ @staticmethod
+ def setup_all_duts(nodes):
"""Prepare all DUTs in given topology for test execution."""
for node in nodes.values():
if node['type'] == NodeType.DUT:
- self.setup_dut(node)
+ DUTSetup.setup_dut(node)
- def setup_dut(self, node):
+ @staticmethod
+ def setup_dut(node):
ssh = SSH()
ssh.connect(node)
@@ -50,6 +53,6 @@ class DUTSetup(object):
logger.trace(stderr)
if 0 != int(ret_code):
logger.debug('DUT {0} setup script failed: "{1}"'.
- format(node['host'], stdout + stderr))
+ format(node['host'], stdout + stderr))
raise Exception('DUT test setup script failed at node {}'.
- format(node['host']))
+ format(node['host']))
diff --git a/resources/libraries/python/DropRateSearch.py b/resources/libraries/python/DropRateSearch.py
index c25f34fcf6..ceaebd57c3 100644
--- a/resources/libraries/python/DropRateSearch.py
+++ b/resources/libraries/python/DropRateSearch.py
@@ -320,14 +320,13 @@ class DropRateSearch(object):
else:
raise ValueError("Unknown search result type")
-
def linear_search(self, start_rate, traffic_type):
"""Linear search of rate with loss below acceptance criteria.
:param start_rate: Initial rate.
:param traffic_type: Traffic profile.
:type start_rate: float
- :param traffic_type: str
+ :type traffic_type: str
:return: nothing
"""
@@ -350,7 +349,7 @@ class DropRateSearch(object):
res = self._get_res_based_on_search_type(res)
if self._search_linear_direction == SearchDirection.BOTTOM_UP:
- # loss occured and it was above acceptance criteria
+ # loss occurred and it was above acceptance criteria
if not res:
# if this is first run then we didn't find drop rate
if prev_rate is None:
@@ -381,7 +380,7 @@ class DropRateSearch(object):
raise RuntimeError("Unknown search result")
elif self._search_linear_direction == SearchDirection.TOP_DOWN:
- # loss occured, decrease rate
+ # loss occurred, decrease rate
if not res:
prev_rate = rate
rate -= self._rate_linear_step
@@ -464,7 +463,7 @@ class DropRateSearch(object):
res = self._get_res_based_on_search_type(res)
- # loss occured and it was above acceptance criteria
+ # loss occurred and it was above acceptance criteria
if not res:
self.binary_search(b_min, rate, traffic_type)
# there was no loss / loss below acceptance criteria
diff --git a/resources/libraries/python/HTTPRequest.py b/resources/libraries/python/HTTPRequest.py
index fd2925cec4..f94318d3a4 100644
--- a/resources/libraries/python/HTTPRequest.py
+++ b/resources/libraries/python/HTTPRequest.py
@@ -108,7 +108,7 @@ class HTTPRequest(object):
:type ip_addr: str
:type port: str or int
:type path: str
- :return: full url
+ :return: Full url.
:rtype: str
"""
return "http://{ip}:{port}{path}".format(ip=ip_addr, port=port,
@@ -155,7 +155,7 @@ class HTTPRequest(object):
:type path: str
:type enable_logging: bool
:type kwargs: dict
- :return: Status code and content of response
+ :return: Status code and content of response.
:rtype: tuple
:raises HTTPRequestError: If
1. it is not possible to connect,
diff --git a/resources/libraries/python/HoneycombUtil.py b/resources/libraries/python/HoneycombUtil.py
index 86c25adc38..92b545d1fc 100644
--- a/resources/libraries/python/HoneycombUtil.py
+++ b/resources/libraries/python/HoneycombUtil.py
@@ -51,7 +51,7 @@ class HoneycombError(Exception):
with keywords like "Wait until keyword succeeds". So you can disable
logging by setting enable_logging to False.
- :param msg: Message to be displayed and logged
+ :param msg: Message to be displayed and logged.
:param enable_logging: When True, logging is enabled, otherwise
logging is disabled.
:type msg: str
@@ -117,7 +117,7 @@ class HoneycombUtil(object):
:param response: JSON formatted string.
:param path: Path to navigate down the data structure.
- :type response: string
+ :type response: str
:type path: tuple
:return: JSON dictionary/list tree.
:rtype: list
diff --git a/resources/libraries/python/IPUtil.py b/resources/libraries/python/IPUtil.py
index 3e002b3495..8ad01c491b 100644
--- a/resources/libraries/python/IPUtil.py
+++ b/resources/libraries/python/IPUtil.py
@@ -13,24 +13,23 @@
"""Common IP utilities library."""
-from ssh import SSH
-from constants import Constants
+from resources.libraries.python.ssh import SSH
+from resources.libraries.python.constants import Constants
class IPUtil(object):
"""Common IP utilities"""
- def __init__(self):
- pass
-
@staticmethod
def vpp_ip_probe(node, interface, addr):
"""Run ip probe on VPP node.
- Args:
- node (Dict): VPP node.
- interface (str): Interface name
- addr (str): IPv4/IPv6 address
+ :param node: VPP node.
+ :param interface: Interface name.
+ :param addr: IPv4/IPv6 address.
+ :type node: dict
+ :type interface: str
+ :type addr: str
"""
ssh = SSH()
ssh.connect(node)
diff --git a/resources/libraries/python/IPv4NodeAddress.py b/resources/libraries/python/IPv4NodeAddress.py
index 67599359c8..25179a3119 100644
--- a/resources/libraries/python/IPv4NodeAddress.py
+++ b/resources/libraries/python/IPv4NodeAddress.py
@@ -13,9 +13,10 @@
"""Robot framework variable file.
- Create dictionary variable nodes_ipv4_addr of IPv4 addresses from
- available networks.
+Create dictionary variable nodes_ipv4_addr of IPv4 addresses from
+available networks.
"""
+
from ipaddress import IPv4Network
from resources.libraries.python.topology import Topology
@@ -28,8 +29,9 @@ class IPv4NetworkGenerator(object):
"""IPv4 network generator."""
def __init__(self, networks):
"""
- :param networks: list of strings containing IPv4 subnet
- with prefix length
+ :param networks: List of strings containing IPv4 subnet
+ with prefix length.
+ :type networks: list
"""
self._networks = list()
for network in networks:
@@ -40,7 +42,7 @@ class IPv4NetworkGenerator(object):
def next_network(self):
"""
- :return: next network in form (IPv4Network, subnet)
+ :return: Next network in form (IPv4Network, subnet).
:raises: StopIteration if there are no more elements.
"""
if len(self._networks):
@@ -51,15 +53,15 @@ class IPv4NetworkGenerator(object):
def get_variables(nodes, networks=IPV4_NETWORKS[:]):
"""Special robot framework method that returns dictionary nodes_ipv4_addr,
- mapping of node and interface name to IPv4 adddress.
+ mapping of node and interface name to IPv4 address.
- :param nodes: Nodes of the test topology.
- :param networks: list of available IPv4 networks
- :type nodes: dict
- :type networks: list
+ :param nodes: Nodes of the test topology.
+ :param networks: List of available IPv4 networks.
+ :type nodes: dict
+ :type networks: list
- .. note::
- Robot framework calls it automatically.
+ .. note::
+ Robot framework calls it automatically.
"""
topo = Topology()
links = topo.get_links(nodes)
diff --git a/resources/libraries/python/IPv4Setup.py b/resources/libraries/python/IPv4Setup.py
index a9d9caa51c..14179c3105 100644
--- a/resources/libraries/python/IPv4Setup.py
+++ b/resources/libraries/python/IPv4Setup.py
@@ -16,11 +16,11 @@
from socket import inet_ntoa
from struct import pack
from abc import ABCMeta, abstractmethod
+
from robot.api.deco import keyword
-import resources.libraries.python.ssh as ssh
+from resources.libraries.python.ssh import exec_cmd_no_error
from resources.libraries.python.Routing import Routing
-from resources.libraries.python.InterfaceUtil import InterfaceUtil
from resources.libraries.python.topology import NodeType, Topology
from resources.libraries.python.VatExecutor import VatExecutor
@@ -39,11 +39,11 @@ class IPv4Node(object):
@abstractmethod
def set_ip(self, interface, address, prefix_length):
- """Configure IPv4 address on interface
+ """Configure IPv4 address on interface.
- :param interface: interface name
- :param address:
- :param prefix_length:
+ :param interface: Interface name.
+ :param address: IPv4 address.
+ :param prefix_length: IPv4 prefix length.
:type interface: str
:type address: str
:type prefix_length: int
@@ -53,12 +53,12 @@ class IPv4Node(object):
@abstractmethod
def set_route(self, network, prefix_length, gateway, interface):
- """Configure IPv4 route
+ """Configure IPv4 route.
- :param network: network IPv4 address
- :param prefix_length: mask length
- :param gateway: IPv4 address of the gateway
- :param interface: interface name
+ :param network: Network IPv4 address.
+ :param prefix_length: IPv4 prefix length.
+ :param gateway: IPv4 address of the gateway.
+ :param interface: Interface name.
:type network: str
:type prefix_length: int
:type gateway: str
@@ -69,12 +69,12 @@ class IPv4Node(object):
@abstractmethod
def unset_route(self, network, prefix_length, gateway, interface):
- """Remove specified IPv4 route
+ """Remove specified IPv4 route.
- :param network: network IPv4 address
- :param prefix_length: mask length
- :param gateway: IPv4 address of the gateway
- :param interface: interface name
+ :param network: Network IPv4 address.
+ :param prefix_length: IPv4 prefix length.
+ :param gateway: IPv4 address of the gateway.
+ :param interface: Interface name.
:type network: str
:type prefix_length: int
:type gateway: str
@@ -85,9 +85,9 @@ class IPv4Node(object):
@abstractmethod
def flush_ip_addresses(self, interface):
- """Flush all IPv4 addresses from specified interface
+ """Flush all IPv4 addresses from specified interface.
- :param interface: interface name
+ :param interface: Interface name.
:type interface: str
:return: nothing
"""
@@ -95,10 +95,10 @@ class IPv4Node(object):
@abstractmethod
def ping(self, destination_address, source_interface):
- """Send an ICMP request to destination node
+ """Send an ICMP request to destination node.
- :param destination_address: address to send the ICMP request
- :param source_interface:
+ :param destination_address: Address to send the ICMP request.
+ :param source_interface: Source interface name.
:type destination_address: str
:type source_interface: str
:return: nothing
@@ -112,10 +112,10 @@ class Tg(IPv4Node):
super(Tg, self).__init__(node_info)
def _execute(self, cmd):
- return ssh.exec_cmd_no_error(self.node_info, cmd)
+ return exec_cmd_no_error(self.node_info, cmd)
def _sudo_execute(self, cmd):
- return ssh.exec_cmd_no_error(self.node_info, cmd, sudo=True)
+ return exec_cmd_no_error(self.node_info, cmd, sudo=True)
def set_ip(self, interface, address, prefix_length):
cmd = 'ip -4 addr flush dev {}'.format(interface)
@@ -152,19 +152,20 @@ class Dut(IPv4Node):
super(Dut, self).__init__(node_info)
def get_sw_if_index(self, interface):
- """Get sw_if_index of specified interface from current node
+ """Get sw_if_index of specified interface from current node.
- :param interface: interface name
+ :param interface: Interface name.
:type interface: str
- :return: sw_if_index of 'int' type
+ :return: sw_if_index of the interface or None.
+ :rtype: int
"""
return Topology().get_interface_sw_index(self.node_info, interface)
def exec_vat(self, script, **args):
"""Wrapper for VAT executor.
- :param script: script to execute
- :param args: parameters to the script
+ :param script: Script to execute.
+ :param args: Parameters to the script.
:type script: str
:type args: dict
:return: nothing
@@ -193,8 +194,8 @@ class Dut(IPv4Node):
def set_route(self, network, prefix_length, gateway, interface):
Routing.vpp_route_add(self.node_info,
- network=network, prefix_len=prefix_length,
- gateway=gateway, interface=interface)
+ network=network, prefix_len=prefix_length,
+ gateway=gateway, interface=interface)
def unset_route(self, network, prefix_length, gateway, interface):
self.exec_vat('del_route.vat', network=network,
@@ -215,8 +216,9 @@ class Dut(IPv4Node):
def get_node(node_info):
"""Creates a class instance derived from Node based on type.
- :param node_info: dictionary containing information on nodes in topology
- :return: Class instance that is derived from Node
+ :param node_info: Dictionary containing information on nodes in topology.
+ :type node_info: dict
+ :return: Class instance that is derived from Node.
"""
if node_info['type'] == NodeType.TG:
return Tg(node_info)
@@ -234,14 +236,13 @@ class IPv4Setup(object):
def vpp_nodes_set_ipv4_addresses(nodes, nodes_addr):
"""Set IPv4 addresses on all VPP nodes in topology.
- :param nodes: Nodes of the test topology.
- :param nodes_addr: Available nodes IPv4 adresses.
- :type nodes: dict
- :type nodes_addr: dict
- :return: affected interfaces as list of (node, interface) tuples
- :rtype: list
+ :param nodes: Nodes of the test topology.
+ :param nodes_addr: Available nodes IPv4 addresses.
+ :type nodes: dict
+ :type nodes_addr: dict
+ :return: Affected interfaces as list of (node, interface) tuples.
+ :rtype: list
"""
-
interfaces = []
for net in nodes_addr.values():
for port in net['ports'].values():
@@ -264,13 +265,15 @@ class IPv4Setup(object):
'from "${nodes_addr}"')
def get_ip_addr(node, interface, nodes_addr):
"""Return IPv4 address of the node port.
+
:param node: Node in the topology.
:param interface: Interface name of the node.
- :param nodes_addr: Nodes IPv4 adresses.
+ :param nodes_addr: Nodes IPv4 addresses.
:type node: dict
:type interface: str
:type nodes_addr: dict
- :return: IPv4 address string
+ :return: IPv4 address.
+ :rtype: str
"""
for net in nodes_addr.values():
for port in net['ports'].values():
@@ -295,7 +298,7 @@ class IPv4Setup(object):
:param nodes_info: Dictionary containing information on all nodes
in topology.
- :param nodes_addr: Nodes IPv4 adresses.
+ :param nodes_addr: Nodes IPv4 addresses.
:type nodes_info: dict
:type nodes_addr: dict
"""
@@ -303,8 +306,6 @@ class IPv4Setup(object):
if node['type'] == NodeType.TG:
continue
for interface, interface_data in node['interfaces'].iteritems():
- if interface == 'mgmt':
- continue
interface_name = interface_data['name']
adj_node, adj_int = Topology.\
get_adjacent_node_and_interface(nodes_info, node,
@@ -312,4 +313,4 @@ class IPv4Setup(object):
ip_address = IPv4Setup.get_ip_addr(adj_node, adj_int['name'],
nodes_addr)
mac_address = adj_int['mac_address']
- get_node(node).set_arp(interface_name, ip_address, mac_address) \ No newline at end of file
+ get_node(node).set_arp(interface_name, ip_address, mac_address)
diff --git a/resources/libraries/python/IPv4Util.py b/resources/libraries/python/IPv4Util.py
index b7035f272c..31e6bf13f6 100644
--- a/resources/libraries/python/IPv4Util.py
+++ b/resources/libraries/python/IPv4Util.py
@@ -17,9 +17,6 @@ from robot.api import logger as log
from robot.api.deco import keyword
from resources.libraries.python.topology import Topology
-from resources.libraries.python.topology import NodeType
-from resources.libraries.python.TrafficScriptExecutor\
- import TrafficScriptExecutor
from resources.libraries.python.IPv4Setup import get_node
@@ -36,22 +33,22 @@ class IPv4Util(object):
get_node(node).arp_ping(ip_address, interface)
@staticmethod
- def set_interface_address(node, interface, address, length):
+ def set_interface_address(node, interface, address, prefix_length):
"""See IPv4Node.set_ip for more information.
:param node: Node where IP address should be set to.
- :param interface: Interface name
- :param address: IP address
- :param length: prefix length
+ :param interface: Interface name.
+ :param address: IP address.
+ :param prefix_length: Prefix length.
:type node: dict
:type interface: str
:type address: str
- :type length: int
+ :type prefix_length: int
"""
log.debug('Node {} interface {} has IPv4 address {} with prefix '
'length {}'.format(Topology.get_node_hostname(node),
- interface, address, length))
- get_node(node).set_ip(interface, address, int(length))
+ interface, address, prefix_length))
+ get_node(node).set_ip(interface, address, int(prefix_length))
@staticmethod
@keyword('Node "${node}" routes to IPv4 network "${network}" with prefix '
@@ -60,12 +57,16 @@ class IPv4Util(object):
def set_route(node, network, prefix_length, interface, gateway):
"""See IPv4Node.set_route for more information.
- :param node:
- :param network:
- :param prefix_length:
- :param interface:
- :param gateway:
- :return:
+ :param node: Node where IP address should be set to.
+ :param network: IP network.
+ :param prefix_length: Prefix length.
+ :param interface: Interface name.
+ :param gateway: Gateway.
+ :type node: dict
+ :type network: str
+ :type prefix_length: int
+ :type interface: str
+ :type gateway: str
"""
log.debug('Node {} routes to network {} with prefix length {} '
'via {} interface {}'.format(Topology.get_node_hostname(node),
@@ -82,7 +83,12 @@ class IPv4Util(object):
:param node: Node dictionary.
:param port: Interface name.
- :return: IPv4 prefix length
+ :param nodes_addr: Available nodes IPv4 addresses.
+ :type node: dict
+ :type port: str
+ :type nodes_addr: dict
+ :return: IPv4 prefix length.
+ :rtype: int
"""
for net in nodes_addr.values():
for p in net['ports'].values():
@@ -100,7 +106,12 @@ class IPv4Util(object):
:param node: Node dictionary.
:param port: Interface name.
- :return: IPv4 subnet of 'str' type
+ :param nodes_addr: Available nodes IPv4 addresses.
+ :type node: dict
+ :type port: int
+ :type nodes_addr: dict
+ :return: IPv4 subnet.
+ :rtype: str
"""
for net in nodes_addr.values():
for p in net['ports'].values():
@@ -126,7 +137,7 @@ class IPv4Util(object):
"""Get link IPv4 address.
:param link: Link name.
- :param nodes_addr: Available nodes IPv4 adresses.
+ :param nodes_addr: Available nodes IPv4 addresses.
:type link: str
:type nodes_addr: dict
:return: Link IPv4 address.
@@ -142,7 +153,7 @@ class IPv4Util(object):
"""Get link IPv4 address prefix.
:param link: Link name.
- :param nodes_addr: Available nodes IPv4 adresses.
+ :param nodes_addr: Available nodes IPv4 addresses.
:type link: str
:type nodes_addr: dict
:return: Link IPv4 address prefix.
diff --git a/resources/libraries/python/IPv6NodesAddr.py b/resources/libraries/python/IPv6NodesAddr.py
index 6bd28ca05c..133c861b27 100644
--- a/resources/libraries/python/IPv6NodesAddr.py
+++ b/resources/libraries/python/IPv6NodesAddr.py
@@ -13,12 +13,12 @@
"""Robot framework variable file.
- Create dictionary variable nodes_ipv6_addr with IPv6 adresses from available
- networks.
+Create dictionary variable nodes_ipv6_addr with IPv6 addresses from available
+networks.
"""
-from IPv6Setup import IPv6Networks
-from topology import Topology
+from resources.libraries.python.IPv6Setup import IPv6Networks
+from resources.libraries.python.topology import Topology
# Default list of available IPv6 networks
IPV6_NETWORKS = ['3ffe:{0:04x}::/64'.format(i) for i in range(1, 100)]
@@ -26,15 +26,15 @@ IPV6_NETWORKS = ['3ffe:{0:04x}::/64'.format(i) for i in range(1, 100)]
def get_variables(nodes, networks=IPV6_NETWORKS):
"""Special robot framework method that returns dictionary nodes_ipv6_addr,
- mapping of node and interface name to IPv6 adddress.
+ mapping of node and interface name to IPv6 address.
- :param nodes: Nodes of the test topology.
- :param networks: list of available IPv6 networks
- :type nodes: dict
- :type networks: list
+ :param nodes: Nodes of the test topology.
+ :param networks: List of available IPv6 networks.
+ :type nodes: dict
+ :type networks: list
- .. note::
- Robot framework calls it automatically.
+ .. note::
+ Robot framework calls it automatically.
"""
topo = Topology()
links = topo.get_links(nodes)
diff --git a/resources/libraries/python/IPv6Setup.py b/resources/libraries/python/IPv6Setup.py
index 598905735a..c016423f32 100644
--- a/resources/libraries/python/IPv6Setup.py
+++ b/resources/libraries/python/IPv6Setup.py
@@ -13,19 +13,20 @@
"""Library to set up IPv6 in topology."""
-from ssh import SSH
-from ipaddress import IPv6Network
-from topology import NodeType, Topology
-from constants import Constants
-from VatExecutor import VatTerminal, VatExecutor
from robot.api import logger
+from ipaddress import IPv6Network
+
+from resources.libraries.python.ssh import SSH
+from resources.libraries.python.topology import NodeType, Topology
+from resources.libraries.python.constants import Constants
+from resources.libraries.python.VatExecutor import VatTerminal, VatExecutor
class IPv6Networks(object):
"""IPv6 network iterator.
- :param networks: List of the available IPv6 networks.
- :type networks: list
+ :param networks: List of the available IPv6 networks.
+ :type networks: list
"""
def __init__(self, networks):
self._networks = list()
@@ -37,11 +38,11 @@ class IPv6Networks(object):
raise Exception('No IPv6 networks')
def next_network(self):
- """Get the next elemnt of the iterator.
+ """Get the next element of the iterator.
- :return: IPv6 network.
- :rtype: IPv6Network object
- :raises: StopIteration if there is no more elements.
+ :return: IPv6 network.
+ :rtype: IPv6Network object
+ :raises: StopIteration if there is no more elements.
"""
if len(self._networks):
return self._networks.pop()
@@ -58,14 +59,13 @@ class IPv6Setup(object):
def nodes_set_ipv6_addresses(self, nodes, nodes_addr):
"""Set IPv6 addresses on all VPP nodes in topology.
- :param nodes: Nodes of the test topology.
- :param nodes_addr: Available nodes IPv6 adresses.
- :type nodes: dict
- :type nodes_addr: dict
- :return: affected interfaces as list of (node, interface) tuples
- :rtype: list
+ :param nodes: Nodes of the test topology.
+ :param nodes_addr: Available nodes IPv6 addresses.
+ :type nodes: dict
+ :type nodes_addr: dict
+ :return: Affected interfaces as list of (node, interface) tuples.
+ :rtype: list
"""
-
interfaces = []
for net in nodes_addr.values():
@@ -82,16 +82,16 @@ class IPv6Setup(object):
net['prefix'])
interfaces.append((node, port['if']))
-
return interfaces
+
def nodes_clear_ipv6_addresses(self, nodes, nodes_addr):
"""Remove IPv6 addresses from all VPP nodes in topology.
- :param nodes: Nodes of the test topology.
- :param nodes_addr: Available nodes IPv6 adresses.
- :type nodes: dict
- :type nodes_addr: dict
- """
+ :param nodes: Nodes of the test topology.
+ :param nodes_addr: Available nodes IPv6 addresses.
+ :type nodes: dict
+ :type nodes_addr: dict
+ """
for net in nodes_addr.values():
for port in net['ports'].values():
host = port.get('node')
@@ -109,14 +109,14 @@ class IPv6Setup(object):
def linux_set_if_ipv6_addr(node, interface, addr, prefix):
"""Set IPv6 address on linux host.
- :param node: Linux node.
- :param interface: Node interface.
- :param addr: IPv6 address.
- :param prefix: IPv6 address prefix.
- :type node: dict
- :type interface: str
- :type addr: str
- :type prefix: str
+ :param node: Linux node.
+ :param interface: Node interface.
+ :param addr: IPv6 address.
+ :param prefix: IPv6 address prefix.
+ :type node: dict
+ :type interface: str
+ :type addr: str
+ :type prefix: str
"""
ssh = SSH()
ssh.connect(node)
@@ -131,14 +131,14 @@ class IPv6Setup(object):
def linux_del_if_ipv6_addr(node, interface, addr, prefix):
"""Delete IPv6 address on linux host.
- :param node: Linux node.
- :param interface: Node interface.
- :param addr: IPv6 address.
- :param prefix: IPv6 address prefix.
- :type node: dict
- :type interface: str
- :type addr: str
- :type prefix: str
+ :param node: Linux node.
+ :param interface: Node interface.
+ :param addr: IPv6 address.
+ :param prefix: IPv6 address prefix.
+ :type node: dict
+ :type interface: str
+ :type addr: str
+ :type prefix: str
"""
ssh = SSH()
ssh.connect(node)
@@ -159,14 +159,14 @@ class IPv6Setup(object):
def vpp_set_if_ipv6_addr(node, interface, addr, prefix):
"""Set IPv6 address on VPP.
- :param node: VPP node.
- :param interface: Node interface.
- :param addr: IPv6 address.
- :param prefix: IPv6 address prefix.
- :type node: dict
- :type interface: str
- :type addr: str
- :type prefix: str
+ :param node: VPP node.
+ :param interface: Node interface.
+ :param addr: IPv6 address.
+ :param prefix: IPv6 address prefix.
+ :type node: dict
+ :type interface: str
+ :type addr: str
+ :type prefix: str
"""
sw_if_index = Topology.get_interface_sw_index(node, interface)
with VatTerminal(node) as vat:
@@ -191,14 +191,14 @@ class IPv6Setup(object):
def vpp_del_if_ipv6_addr(node, interface, addr, prefix):
"""Delete IPv6 address on VPP.
- :param node: VPP node.
- :param interface: Node interface.
- :param addr: IPv6 address.
- :param prefix: IPv6 address prefix.
- :type node: dict
- :type interface: str
- :type addr: str
- :type prefix: str
+ :param node: VPP node.
+ :param interface: Node interface.
+ :param addr: IPv6 address.
+ :param prefix: IPv6 address prefix.
+ :type node: dict
+ :type interface: str
+ :type addr: str
+ :type prefix: str
"""
sw_if_index = Topology.get_interface_sw_index(node, interface)
with VatTerminal(node) as vat:
@@ -211,13 +211,13 @@ class IPv6Setup(object):
state='admin-down')
@staticmethod
- def vpp_ra_supress_link_layer(node, interface):
- """Supress ICMPv6 router advertisement message for link scope address
+ def vpp_ra_suppress_link_layer(node, interface):
+ """Suppress ICMPv6 router advertisement message for link scope address.
- :param node: VPP node.
- :param interface: Interface name.
- :type node: dict
- :type interface: str
+ :param node: VPP node.
+ :param interface: Interface name.
+ :type node: dict
+ :type interface: str
"""
sw_if_index = Topology.get_interface_sw_index(node, interface)
VatExecutor.cmd_from_template(node,
@@ -225,30 +225,28 @@ class IPv6Setup(object):
sw_if_id=sw_if_index,
param='surpress')
- def vpp_all_ra_supress_link_layer(self, nodes):
- """Supress ICMPv6 router advertisement message for link scope address
- on all VPP nodes in the topology
+ def vpp_all_ra_suppress_link_layer(self, nodes):
+ """Suppress ICMPv6 router advertisement message for link scope address
+ on all VPP nodes in the topology.
- :param nodes: Nodes of the test topology.
- :type nodes: dict
+ :param nodes: Nodes of the test topology.
+ :type nodes: dict
"""
for node in nodes.values():
if node['type'] == NodeType.TG:
continue
for port_k, port_v in node['interfaces'].items():
- if port_k == 'mgmt':
- continue
if_name = port_v.get('name')
if if_name is None:
continue
- self.vpp_ra_supress_link_layer(node, if_name)
+ self.vpp_ra_suppress_link_layer(node, if_name)
@staticmethod
def get_link_address(link, nodes_addr):
"""Get link IPv6 address.
:param link: Link name.
- :param nodes_addr: Available nodes IPv6 adresses.
+ :param nodes_addr: Available nodes IPv6 addresses.
:type link: str
:type nodes_addr: dict
:return: Link IPv6 address.
@@ -264,7 +262,7 @@ class IPv6Setup(object):
"""Get link IPv6 address prefix.
:param link: Link name.
- :param nodes_addr: Available nodes IPv6 adresses.
+ :param nodes_addr: Available nodes IPv6 addresses.
:type link: str
:type nodes_addr: dict
:return: Link IPv6 address prefix.
diff --git a/resources/libraries/python/IPv6Util.py b/resources/libraries/python/IPv6Util.py
index a96683b164..519026beae 100644
--- a/resources/libraries/python/IPv6Util.py
+++ b/resources/libraries/python/IPv6Util.py
@@ -14,28 +14,29 @@
"""IPv6 utilities library."""
import re
-from ssh import SSH
+
+from resources.libraries.python.ssh import SSH
class IPv6Util(object):
"""IPv6 utilities"""
- def __init__(self):
- pass
-
@staticmethod
def ipv6_ping(src_node, dst_addr, count=3, data_size=56, timeout=1):
"""IPv6 ping.
- Args:
- src_node (Dict): Node where ping run.
- dst_addr (str): Destination IPv6 address.
- count (Optional[int]): Number of echo requests.
- data_size (Optional[int]): Number of the data bytes.
- timeout (Optional[int]): Time to wait for a response, in seconds.
-
- Returns:
- Number of lost packets.
+ :param src_node: Node where ping run.
+ :param dst_addr: Destination IPv6 address.
+ :param count: Number of echo requests. (Optional)
+ :param data_size: Number of the data bytes. (Optional)
+ :param timeout: Time to wait for a response, in seconds. (Optional)
+ :type src_node: dict
+ :type dst_addr: str
+ :type count: int
+ :type data_size: int
+ :type timeout: int
+ :return: Number of lost packets.
+ :rtype: int
"""
ssh = SSH()
ssh.connect(src_node)
@@ -57,17 +58,22 @@ class IPv6Util(object):
size=56, timeout=1):
"""Send IPv6 ping to the node port.
- Args:
- nodes_ip (Dict): Nodes IPv6 adresses.
- src_node (Dict): Node where ping run.
- dst_node (Dict): Destination node.
- port (str): Port on the destination node.
- cnt (Optional[int]): Number of echo requests.
- size (Optional[int]): Number of the data bytes.
- timeout (Optional[int]): Time to wait for a response, in seconds.
-
- Returns:
- Number of lost packets.
+ :param nodes_ip: Nodes IPv6 addresses.
+ :param src_node: Node where ping run.
+ :param dst_node: Destination node.
+ :param port: Port on the destination node.
+ :param cnt: Number of echo requests. (Optional)
+ :param size: Number of the data bytes. (Optional)
+ :param timeout: Time to wait for a response, in seconds. (Optional)
+ :type nodes_ip: dict
+ :type src_node: dict
+ :type dst_node: dict
+ :type port: str
+ :type cnt: int
+ :type size: int
+ :type timeout: int
+ :return: Number of lost packets.
+ :rtype: int
"""
dst_ip = IPv6Util.get_node_port_ipv6_address(dst_node, port, nodes_ip)
return IPv6Util.ipv6_ping(src_node, dst_ip, cnt, size, timeout)
@@ -76,13 +82,14 @@ class IPv6Util(object):
def get_node_port_ipv6_address(node, interface, nodes_addr):
"""Return IPv6 address of the node port.
- Args:
- node (Dict): Node in the topology.
- interface (str): Interface name of the node.
- nodes_addr (Dict): Nodes IPv6 adresses.
-
- Returns:
- IPv6 address string.
+ :param node: Node in the topology.
+ :param interface: Interface name of the node.
+ :param nodes_addr: Nodes IPv6 addresses.
+ :type node: dict
+ :type interface: str
+ :type nodes_addr: dict
+ :return: IPv6 address string.
+ :rtype: str
"""
for net in nodes_addr.values():
for port in net['ports'].values():
diff --git a/resources/libraries/python/InterfaceUtil.py b/resources/libraries/python/InterfaceUtil.py
index 6526fe83ca..bf1ba1e8aa 100644
--- a/resources/libraries/python/InterfaceUtil.py
+++ b/resources/libraries/python/InterfaceUtil.py
@@ -36,9 +36,9 @@ class InterfaceUtil(object):
Function can be used for DUTs as well as for TGs.
- :param node: node where the interface is
- :param interface: interface name or sw_if_index
- :param state: one of 'up' or 'down'
+ :param node: Node where the interface is.
+ :param interface: Interface name or sw_if_index.
+ :param state: One of 'up' or 'down'.
:type node: dict
:type interface: str or int
:type state: str
@@ -73,9 +73,9 @@ class InterfaceUtil(object):
Function can be used only for TGs.
- :param node: node where the interface is
- :param interface: interface name
- :param mtu: MTU to set
+ :param node: Node where the interface is.
+ :param interface: Interface name.
+ :param mtu: MTU to set.
:type node: dict
:type interface: str
:type mtu: int
@@ -97,7 +97,7 @@ class InterfaceUtil(object):
Function can be used only for TGs.
- :param node: node where to set default MTU
+ :param node: Node where to set default MTU.
:type node: dict
:return: nothing
"""
@@ -109,7 +109,7 @@ class InterfaceUtil(object):
"""Wait until all interfaces with admin-up are in link-up state.
:param node: Node to wait on.
- :param timeout: Waiting timeout in seconds (optional, default 10s)
+ :param timeout: Waiting timeout in seconds (optional, default 10s).
:type node: dict
:type timeout: int
:raises: RuntimeError if the timeout period value has elapsed.
@@ -172,6 +172,7 @@ class InterfaceUtil(object):
"""Get all interface data from a VPP node. If a name or
sw_interface_index is provided, return only data for the matching
interface.
+
:param node: VPP node to get interface data from.
:param interface: Numeric index or name string of a specific interface.
:type node: dict
@@ -325,7 +326,7 @@ class InterfaceUtil(object):
@staticmethod
def update_vpp_interface_data_on_node(node):
- """Update vpp generated interface data for a given node in DICT__nodes
+ """Update vpp generated interface data for a given node in DICT__nodes.
Updates interface names, software if index numbers and any other details
generated specifically by vpp that are unknown before testcase run.
@@ -333,7 +334,7 @@ class InterfaceUtil(object):
devices using vpp_api_test, and pairing known information from topology
(mac address/pci address of interface) to state from VPP.
- :param node: Node selected from DICT__nodes
+ :param node: Node selected from DICT__nodes.
:type node: dict
"""
vat_executor = VatExecutor()
diff --git a/resources/libraries/python/L2Util.py b/resources/libraries/python/L2Util.py
index 724ec0cdce..e0824598b4 100644
--- a/resources/libraries/python/L2Util.py
+++ b/resources/libraries/python/L2Util.py
@@ -14,6 +14,7 @@
"""L2 Utilities Library."""
from robot.api.deco import keyword
+
from resources.libraries.python.topology import Topology
from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
from resources.libraries.python.ssh import exec_cmd_no_error
@@ -52,13 +53,13 @@ class L2Util(object):
forward {forward} learn {learn} arp-term {arp_term}" VAT command on
the node.
- :param node: node where we wish to crate the l2 bridge domain
- :param bd_id: bridge domain index number
- :param flood: enable flooding
- :param uu_flood: enable uu_flood
- :param forward: enable forwarding
- :param learn: enable mac address learning to fib
- :param arp_term: enable arp_termination
+ :param node: Node where we wish to crate the l2 bridge domain.
+ :param bd_id: Bridge domain index number.
+ :param flood: Enable flooding.
+ :param uu_flood: Enable uu_flood.
+ :param forward: Enable forwarding.
+ :param learn: Enable mac address learning to fib.
+ :param arp_term: Enable arp_termination.
:type node: dict
:type bd_id: int
:type flood: bool
@@ -78,10 +79,10 @@ class L2Util(object):
Get SW IF ID and add it to the bridge domain.
- :param node: node where we want to execute the command that does this
- :param interface: interface name
- :param bd_id: bridge domain index number to add Interface name to
- :param shg: split horizon group
+ :param node: Node where we want to execute the command that does this.
+ :param interface: Interface name.
+ :param bd_id: Bridge domain index number to add Interface name to.
+ :param shg: Split horizon group.
:type node: dict
:type interface: str
:type bd_id: int
@@ -97,10 +98,10 @@ class L2Util(object):
Execute the "sw_interface_set_l2_bridge sw_if_index {sw_if_index}
bd_id {bd_id} shg {shg} enable" VAT command on the given node.
- :param node: node where we want to execute the command that does this
- :param sw_if_index: interface index
- :param bd_id: bridge domain index number to add SW IF ID to
- :param shg: split horizon group
+ :param node: Node where we want to execute the command that does this.
+ :param sw_if_index: Interface index.
+ :param bd_id: Bridge domain index number to add SW IF ID to.
+ :param shg: Split horizon group.
:type node: dict
:type sw_if_index: int
:type bd_id: int
@@ -117,18 +118,20 @@ class L2Util(object):
def create_bridge_domain_vat_dict(node, link_names, bd_id):
"""Create dictionary that can be used in l2 bridge domain template.
- :param node: node data dictionary
- :param link_names: list of names of links the bridge domain should be
- connecting
- :param bd_id: bridge domain index number
- :type node: dict
- :type link_names: list
- :return: dictionary used to generate l2 bridge domain VAT configuration
- from template file
The resulting dictionary looks like this:
'interface1': interface name of first interface
'interface2': interface name of second interface
'bd_id': bridge domain index
+
+ :param node: Node data dictionary.
+ :param link_names: List of names of links the bridge domain should be
+ connecting.
+ :param bd_id: Bridge domain index number.
+ :type node: dict
+ :type link_names: list
+ :return: Dictionary used to generate l2 bridge domain VAT configuration
+ from template file.
+ :rtype: dict
"""
bd_dict = Topology().get_interfaces_by_link_names(node, link_names)
bd_dict['bd_id'] = bd_id
@@ -162,9 +165,9 @@ class L2Util(object):
def vpp_setup_bidirectional_cross_connect(node, interface1, interface2):
"""Create bidirectional cross-connect between 2 interfaces on vpp node.
- :param node: Node to add bidirectional cross-connect
- :param interface1: first interface name or sw_if_index
- :param interface2: second interface name or sw_if_index
+ :param node: Node to add bidirectional cross-connect.
+ :param interface1: First interface name or sw_if_index.
+ :param interface2: Second interface name or sw_if_index.
:type node: dict
:type interface1: str or int
:type interface2: str or int
diff --git a/resources/libraries/python/NodePath.py b/resources/libraries/python/NodePath.py
index 51808c3edf..bbc6d31811 100644
--- a/resources/libraries/python/NodePath.py
+++ b/resources/libraries/python/NodePath.py
@@ -13,7 +13,7 @@
"""Path utilities library for nodes in the topology."""
-from topology import Topology
+from resources.libraries.python.topology import Topology
class NodePath(object):
@@ -89,8 +89,8 @@ class NodePath(object):
"""Compute path for added nodes.
:param always_same_link: If True use always same link between two nodes
- in path. If False use different link (if available) between two
- nodes if one link was used before.
+ in path. If False use different link (if available) between two
+ nodes if one link was used before.
:type always_same_link: bool
.. note:: First add at least two nodes to the topology.
@@ -108,16 +108,13 @@ class NodePath(object):
raise RuntimeError('No link between {0} and {1}'.format(
node1['host'], node2['host']))
- link = None
- l_set = set()
-
if always_same_link:
l_set = set(links).intersection(self._links)
else:
l_set = set(links).difference(self._links)
if not l_set:
raise RuntimeError(
- 'No free link between {0} and {1}, all links already ' \
+ 'No free link between {0} and {1}, all links already '
'used'.format(node1['host'], node2['host']))
if not l_set:
@@ -143,7 +140,7 @@ class NodePath(object):
.. note:: Call compute_path before.
"""
if not self._path_iter:
- return (None, None)
+ return None, None
else:
return self._path_iter.pop()
diff --git a/resources/libraries/python/PacketVerifier.py b/resources/libraries/python/PacketVerifier.py
index 45fab6a7c6..78c3670135 100644
--- a/resources/libraries/python/PacketVerifier.py
+++ b/resources/libraries/python/PacketVerifier.py
@@ -63,11 +63,10 @@
"""
+import os
import socket
import select
-import os
-import time
-from multiprocessing import Queue, Process
+
from scapy.all import ETH_P_IP, ETH_P_IPV6, ETH_P_ALL, ETH_P_ARP
from scapy.all import Ether, ARP, Packet
from scapy.layers.inet6 import IPv6
@@ -77,6 +76,7 @@ __all__ = ['RxQueue', 'TxQueue', 'Interface', 'create_gratuitous_arp_request',
# TODO: http://stackoverflow.com/questions/320232/ensuring-subprocesses-are-dead-on-exiting-python-program
+
class PacketVerifier(object):
"""Base class for TX and RX queue objects for packet verifier."""
def __init__(self, interface_name):
@@ -95,10 +95,10 @@ def extract_one_packet(buf):
Takes string as input and looks for first whole packet in it.
If it finds one, it returns substring from the buf parameter.
- :param buf: string representation of incoming packet buffer.
- :type buf: string
+ :param buf: String representation of incoming packet buffer.
+ :type buf: str
:return: String representation of first packet in buf.
- :rtype: string
+ :rtype: str
"""
pkt_len = 0
@@ -178,9 +178,9 @@ def packet_reader(interface_name, queue):
This function is meant to be run in separate subprocess and is in tight
loop reading raw packets from interface passed as parameter.
- :param interace_name: Name of interface to read packets from.
+ :param interface_name: Name of interface to read packets from.
:param queue: Queue in which this function will push incoming packets.
- :type interface_name: string
+ :type interface_name: str
:type queue: multiprocessing.Queue
:return: None
"""
@@ -199,19 +199,11 @@ class RxQueue(PacketVerifier):
function to access them.
:param interface_name: Which interface to bind to.
- :type interface_name: string
+ :type interface_name: str
"""
-
def __init__(self, interface_name):
PacketVerifier.__init__(self, interface_name)
- #self._queue = Queue()
- #self._proc = Process(target=packet_reader, args=(interface_name,
- # self._queue))
- #self._proc.daemon = True
- #self._proc.start()
- #time.sleep(2)
-
def recv(self, timeout=3, ignore=None):
"""Read next received packet.
@@ -220,13 +212,13 @@ class RxQueue(PacketVerifier):
arrives in given timeout queue.Empty exception will be risen.
:param timeout: How many seconds to wait for next packet.
+ :param ignore: Packet list that should be ignored.
:type timeout: int
+ :type ignore: list
:return: Ether() initialized object from packet data.
:rtype: scapy.Ether
"""
-
- #pkt = self._queue.get(True, timeout=timeout)
(rlist, _, _) = select.select([self._sock], [], [], timeout)
if self._sock not in rlist:
return None
@@ -257,7 +249,7 @@ class TxQueue(PacketVerifier):
This object is used to send packets over RAW socket on a interface.
:param interface_name: Which interface to send packets from.
- :type interface_name: string
+ :type interface_name: str
"""
def __init__(self, interface_name):
PacketVerifier.__init__(self, interface_name)
@@ -293,7 +285,7 @@ class Interface(object):
def create_gratuitous_arp_request(src_mac, src_ip):
- """Creates scapy representation of gratuitous ARP request"""
+ """Creates scapy representation of gratuitous ARP request."""
return (Ether(src=src_mac, dst='ff:ff:ff:ff:ff:ff') /
ARP(psrc=src_ip, hwsrc=src_mac, pdst=src_ip))
diff --git a/resources/libraries/python/QemuUtils.py b/resources/libraries/python/QemuUtils.py
index 7f74106177..6658c07df9 100644
--- a/resources/libraries/python/QemuUtils.py
+++ b/resources/libraries/python/QemuUtils.py
@@ -13,10 +13,12 @@
"""QEMU utilities library."""
+from time import time, sleep
import json
import re
-from time import time, sleep
+
from robot.api import logger
+
from resources.libraries.python.ssh import SSH
from resources.libraries.python.constants import Constants
from resources.libraries.python.topology import NodeType
@@ -122,7 +124,7 @@ class QemuUtils(object):
"""Set node to run QEMU on.
:param node: Node to run QEMU on.
- :param node: dict
+ :type node: dict
"""
self._node = node
self._ssh = SSH()
@@ -303,7 +305,7 @@ class QemuUtils(object):
def qemu_start(self):
"""Start QEMU and wait until VM boot.
- :return: VM node info
+ :return: VM node info.
:rtype: dict
.. note:: First set at least node to run QEMU on.
.. warning:: Starts only one VM on the node.
diff --git a/resources/libraries/python/Routing.py b/resources/libraries/python/Routing.py
index 7795e3ffcc..1cbbf6b822 100644
--- a/resources/libraries/python/Routing.py
+++ b/resources/libraries/python/Routing.py
@@ -13,8 +13,8 @@
"""Routing utilities library."""
-from VatExecutor import VatTerminal
-from topology import Topology
+from resources.libraries.python.VatExecutor import VatTerminal
+from resources.libraries.python.topology import Topology
class Routing(object):
diff --git a/resources/libraries/python/SetupFramework.py b/resources/libraries/python/SetupFramework.py
index b3df489685..ddc5514c4a 100644
--- a/resources/libraries/python/SetupFramework.py
+++ b/resources/libraries/python/SetupFramework.py
@@ -16,7 +16,7 @@ nodes. All tasks required to be run before the actual tests are started is
supposed to end up here.
"""
-import shlex
+from shlex import split
from subprocess import Popen, PIPE, call
from multiprocessing import Pool
from tempfile import NamedTemporaryFile
@@ -31,6 +31,7 @@ from resources.libraries.python.topology import NodeType
__all__ = ["SetupFramework"]
+
def pack_framework_dir():
"""Pack the testing WS into temp file, return its name."""
@@ -39,7 +40,7 @@ def pack_framework_dir():
tmpfile.close()
proc = Popen(
- shlex.split("tar --exclude-vcs -zcf {0} .".format(file_name)),
+ split("tar --exclude-vcs -zcf {0} .".format(file_name)),
stdout=PIPE, stderr=PIPE)
(stdout, stderr) = proc.communicate()
@@ -56,9 +57,9 @@ def pack_framework_dir():
def copy_tarball_to_node(tarball, node):
"""Copy tarball file from local host to remote node.
- :param tarball: path to tarball to upload
- :param node: dictionary created from topology
- :type tarball: string
+ :param tarball: Path to tarball to upload.
+ :param node: Dictionary created from topology.
+ :type tarball: str
:type node: dict
:return: nothing
"""
@@ -74,9 +75,9 @@ def extract_tarball_at_node(tarball, node):
Extracts tarball using tar on given node to specific CSIT loocation.
- :param tarball: path to tarball to upload
- :param node: dictionary created from topology
- :type tarball: string
+ :param tarball: Path to tarball to upload.
+ :param node: Dictionary created from topology.
+ :type tarball: str
:type node: dict
:return: nothing
"""
@@ -102,21 +103,22 @@ def create_env_directory_at_node(node):
ssh.connect(node)
(ret_code, stdout, stderr) = ssh.exec_command(
'cd {0} && rm -rf env && virtualenv env && . env/bin/activate && '
- 'pip install -r requirements.txt'.format(con.REMOTE_FW_DIR),
- timeout=100)
+ 'pip install -r requirements.txt'
+ .format(con.REMOTE_FW_DIR), timeout=100)
if 0 != ret_code:
logger.error('Virtualenv creation error: {0}'.format(stdout + stderr))
raise Exception('Virtualenv setup failed')
else:
logger.console('Virtualenv created on {0}'.format(node['host']))
+
def setup_node(args):
"""Run all set-up methods for a node.
This method is used as map_async parameter. It receives tuple with all
parameters as passed to map_async function.
- :param args: all parameters needed to setup one node
+ :param args: All parameters needed to setup one node.
:type args: tuple
:return: nothing
"""
@@ -127,14 +129,16 @@ def setup_node(args):
create_env_directory_at_node(node)
logger.console('Setup of node {0} done'.format(node['host']))
+
def delete_local_tarball(tarball):
"""Delete local tarball to prevent disk pollution.
- :param tarball: path to tarball to upload
- :type tarball: string
+ :param tarball: Path to tarball to upload.
+ :type tarball: str
:return: nothing
"""
- call(shlex.split('sh -c "rm {0} > /dev/null 2>&1"'.format(tarball)))
+ call(split('sh -c "rm {0} > /dev/null 2>&1"'.format(tarball)))
+
class SetupFramework(object): # pylint: disable=too-few-public-methods
"""Setup suite run on topology nodes.
@@ -144,9 +148,6 @@ class SetupFramework(object): # pylint: disable=too-few-public-methods
to all nodes in topology under /tmp/
"""
- def __init__(self):
- pass
-
@staticmethod
def setup_framework(nodes):
"""Pack the whole directory and extract in temp on each node."""
@@ -157,7 +158,7 @@ class SetupFramework(object): # pylint: disable=too-few-public-methods
logger.trace(msg)
remote_tarball = "/tmp/{0}".format(basename(tarball))
- # Turn off loggining since we use multiprocessing
+ # Turn off logging since we use multiprocessing
log_level = BuiltIn().set_log_level('NONE')
params = ((tarball, remote_tarball, node) for node in nodes.values())
pool = Pool(processes=len(nodes))
@@ -171,7 +172,7 @@ class SetupFramework(object): # pylint: disable=too-few-public-methods
logger.info('Results: {0}'.format(result.get()))
- # Turn on loggining
+ # Turn on logging
BuiltIn().set_log_level(log_level)
logger.trace('Test framework copied to all topology nodes')
delete_local_tarball(tarball)
diff --git a/resources/libraries/python/TGSetup.py b/resources/libraries/python/TGSetup.py
index 05c8b1d177..7c05e55503 100644
--- a/resources/libraries/python/TGSetup.py
+++ b/resources/libraries/python/TGSetup.py
@@ -13,8 +13,8 @@
"""TG Setup library."""
-from topology import NodeType
-from InterfaceUtil import InterfaceUtil
+from resources.libraries.python.topology import NodeType
+from resources.libraries.python.InterfaceUtil import InterfaceUtil
class TGSetup(object):
diff --git a/resources/libraries/python/Trace.py b/resources/libraries/python/Trace.py
index 8168b909ea..1a251a61b6 100644
--- a/resources/libraries/python/Trace.py
+++ b/resources/libraries/python/Trace.py
@@ -14,6 +14,7 @@
from resources.libraries.python.VatExecutor import VatExecutor
from resources.libraries.python.topology import NodeType
+
class Trace(object):
@staticmethod
diff --git a/resources/libraries/python/TrafficGenerator.py b/resources/libraries/python/TrafficGenerator.py
index c3af0863be..39f8287481 100644
--- a/resources/libraries/python/TrafficGenerator.py
+++ b/resources/libraries/python/TrafficGenerator.py
@@ -15,7 +15,6 @@
from robot.api import logger
from robot.libraries.BuiltIn import BuiltIn
-from robot.api.deco import keyword
from resources.libraries.python.ssh import SSH
from resources.libraries.python.topology import NodeType
@@ -25,8 +24,9 @@ from resources.libraries.python.DropRateSearch import DropRateSearch
__all__ = ['TrafficGenerator', 'TGDropRateSearchImpl']
+
class TGDropRateSearchImpl(DropRateSearch):
- """Drop Rate Search implementation"""
+ """Drop Rate Search implementation."""
def __init__(self):
super(TGDropRateSearchImpl, self).__init__()
@@ -34,19 +34,22 @@ class TGDropRateSearchImpl(DropRateSearch):
def measure_loss(self, rate, frame_size, loss_acceptance,
loss_acceptance_type, traffic_type):
- #we need instance of TrafficGenerator instantiated by Robot Framework
- #to be able to use trex_stateless_remote_exec method
- tg_instance = BuiltIn().get_library_instance('resources.libraries.python.TrafficGenerator')
+ # we need instance of TrafficGenerator instantiated by Robot Framework
+ # to be able to use trex_stateless_remote_exec method
+ tg_instance = BuiltIn().get_library_instance(
+ 'resources.libraries.python.TrafficGenerator')
if tg_instance._node['subtype'] is None:
raise Exception('TG subtype not defined')
elif tg_instance._node['subtype'] == NodeSubTypeTG.TREX:
unit_rate = str(rate) + self.get_rate_type_str()
- tg_instance.trex_stateless_remote_exec(self.get_duration(), unit_rate,
- frame_size, traffic_type)
+ tg_instance.trex_stateless_remote_exec(self.get_duration(),
+ unit_rate, frame_size,
+ traffic_type)
- #TODO:getters for tg_instance and loss_acceptance_type
- logger.trace("comparing: {} < {} ".format(tg_instance._loss, loss_acceptance))
+ # TODO: getters for tg_instance and loss_acceptance_type
+ logger.trace("comparing: {} < {} ".format(tg_instance._loss,
+ loss_acceptance))
if float(tg_instance._loss) > float(loss_acceptance):
return False
else:
@@ -54,10 +57,11 @@ class TGDropRateSearchImpl(DropRateSearch):
else:
raise NotImplementedError("TG subtype not supported")
+
class TrafficGenerator(object):
- """Traffic Generator"""
+ """Traffic Generator."""
- #use one instance of TrafficGenerator for all tests in test suite
+ # use one instance of TrafficGenerator for all tests in test suite
ROBOT_LIBRARY_SCOPE = 'TEST SUITE'
def __init__(self):
@@ -66,24 +70,25 @@ class TrafficGenerator(object):
self._sent = None
self._received = None
self._node = None
- #T-REX interface order mapping
+ # T-REX interface order mapping
self._ifaces_reordered = 0
def initialize_traffic_generator(self, tg_node, tg_if1, tg_if2,
dut1_node, dut1_if1, dut1_if2,
dut2_node, dut2_if1, dut2_if2,
test_type):
- """TG initialization
- :param tg_node: Traffic generator node
- :param tg_if1: TG - name of first interface
- :param tg_if2: TG - name of second interface
- :param dut1_node: DUT1 node
- :param dut1_if1: DUT1 - name of first interface
- :param dut1_if2: DUT1 - name of second interface
- :param dut2_node: DUT2 node
- :param dut2_if1: DUT2 - name of first interface
- :param dut2_if2: DUT2 - name of second interface
- :test_type: 'L2' or 'L3' - src/dst MAC address
+ """TG initialization.
+
+ :param tg_node: Traffic generator node.
+ :param tg_if1: TG - name of first interface.
+ :param tg_if2: TG - name of second interface.
+ :param dut1_node: DUT1 node.
+ :param dut1_if1: DUT1 - name of first interface.
+ :param dut1_if2: DUT1 - name of second interface.
+ :param dut2_node: DUT2 node.
+ :param dut2_if1: DUT2 - name of first interface.
+ :param dut2_if2: DUT2 - name of second interface.
+ :test_type: 'L2' or 'L3' - src/dst MAC address.
:type tg_node: dict
:type tg_if1: str
:type tg_if2: str
@@ -96,7 +101,6 @@ class TrafficGenerator(object):
:type test_type: str
:return: nothing
"""
-
trex_path = "/opt/trex-core-1.91"
topo = Topology()
@@ -172,12 +176,12 @@ class TrafficGenerator(object):
@staticmethod
def teardown_traffic_generator(node):
- """TG teardown
- :param node: Traffic generator node
+ """TG teardown.
+
+ :param node: Traffic generator node.
:type node: dict
:return: nothing
"""
-
if node['type'] != NodeType.TG:
raise Exception('Node type is not a TG')
if node['subtype'] == NodeSubTypeTG.TREX:
@@ -191,11 +195,9 @@ class TrafficGenerator(object):
def trex_stateless_remote_exec(self, duration, rate, framesize,
traffic_type):
- """Execute stateless script on remote node over ssh
+ """Execute stateless script on remote node over ssh.
- :param node: remote node
- :param traffic_type: Traffic profile
- :type node: dict
+ :param traffic_type: Traffic profile.
:type traffic_type: str
"""
ssh = SSH()
@@ -240,7 +242,7 @@ class TrafficGenerator(object):
logger.trace(stdout)
logger.trace(stderr)
- #last line from console output
+ # last line from console output
line = stdout.splitlines()[-1]
self._result = line
@@ -252,21 +254,21 @@ class TrafficGenerator(object):
def send_traffic_on(self, node, duration, rate,
framesize, traffic_type):
- """Send traffic from all configured interfaces on TG
- :param node: Dictionary containing TG information
- :param duration: Duration of test traffic generation in seconds
- :param rate: Offered load per interface (e.g. 1%, 3gbps, 4mpps, ...)
- :param framesize: Frame size (L2) in Bytes
- :param traffic_type: Traffic profile
+ """Send traffic from all configured interfaces on TG.
+
+ :param node: Dictionary containing TG information.
+ :param duration: Duration of test traffic generation in seconds.
+ :param rate: Offered load per interface (e.g. 1%, 3gbps, 4mpps, ...).
+ :param framesize: Frame size (L2) in Bytes.
+ :param traffic_type: Traffic profile.
:type node: dict
:type duration: str
:type rate: str
:type framesize: str
:type traffic_type: str
- :return: TG output
+ :return: TG output.
:rtype: str
"""
-
if node['type'] != NodeType.TG:
raise Exception('Node type is not a TG')
@@ -280,12 +282,12 @@ class TrafficGenerator(object):
return self._result
- def no_traffic_loss_occured(self):
- """Fail is loss occured in traffic run
+ def no_traffic_loss_occurred(self):
+ """Fail is loss occurred in traffic run.
+
:return: nothing
"""
-
if self._loss is None:
raise Exception('The traffic generation has not been issued')
if self._loss != '0':
- raise Exception('Traffic loss occured: {0}'.format(self._loss))
+ raise Exception('Traffic loss occurred: {0}'.format(self._loss))
diff --git a/resources/libraries/python/TrafficScriptArg.py b/resources/libraries/python/TrafficScriptArg.py
index ab76f29b8e..e05341dacf 100644
--- a/resources/libraries/python/TrafficScriptArg.py
+++ b/resources/libraries/python/TrafficScriptArg.py
@@ -23,7 +23,7 @@ class TrafficScriptArg(object):
and '--rx_if'. You can provide more arguments. All arguments have string
representation of the value.
- :param more_args: List of aditional arguments (optional).
+ :param more_args: List of additional arguments (optional).
:type more_args: list
:Example:
diff --git a/resources/libraries/python/TrafficScriptExecutor.py b/resources/libraries/python/TrafficScriptExecutor.py
index ee29695812..89362c5a56 100644
--- a/resources/libraries/python/TrafficScriptExecutor.py
+++ b/resources/libraries/python/TrafficScriptExecutor.py
@@ -13,10 +13,11 @@
"""Traffic script executor library."""
-from constants import Constants
-from ssh import SSH
from robot.api import logger
+from resources.libraries.python.constants import Constants
+from resources.libraries.python.ssh import SSH
+
__all__ = ['TrafficScriptExecutor']
@@ -27,10 +28,10 @@ class TrafficScriptExecutor(object):
def _escape(string):
"""Escape quotation mark and dollar mark for shell command.
- :param string: String to escape.
- :type string: str
- :return: Escaped string.
- :rtype: str
+ :param string: String to escape.
+ :type string: str
+ :return: Escaped string.
+ :rtype: str
"""
return string.replace('"', '\\"').replace("$", "\\$")
@@ -39,14 +40,14 @@ class TrafficScriptExecutor(object):
timeout=10):
"""Run traffic script on the TG node.
- :param script_file_name: Traffic script name
- :param node: Node to run traffic script on.
- :param script_args: Traffic scripts arguments.
- :param timeout: Timeout (optional).
- :type script_file_name: str
- :type node: dict
- :type script_args: str
- :type timeout: int
+ :param script_file_name: Traffic script name.
+ :param node: Node to run traffic script on.
+ :param script_args: Traffic scripts arguments.
+ :param timeout: Timeout (optional).
+ :type script_file_name: str
+ :type node: dict
+ :type script_args: str
+ :type timeout: int
"""
logger.trace("{}".format(timeout))
ssh = SSH()
@@ -70,22 +71,22 @@ class TrafficScriptExecutor(object):
def traffic_script_gen_arg(rx_if, tx_if, src_mac, dst_mac, src_ip, dst_ip):
"""Generate traffic script basic arguments string.
- :param rx_if: Interface that receives traffic.
- :param tx_if: Interface that sends traffic.
- :param src_mac: Source MAC address.
- :param dst_mac: Destination MAC address.
- :param src_ip: Source IP address.
- :param dst_ip: Destination IP address.
- :type rx_if: str
- :type tx_if: str
- :type src_mac: str
- :type dst_mac: str
- :type src_ip: str
- :type dst_ip: str
- :return: Traffic script arguments string.
- :rtype: str
+ :param rx_if: Interface that receives traffic.
+ :param tx_if: Interface that sends traffic.
+ :param src_mac: Source MAC address.
+ :param dst_mac: Destination MAC address.
+ :param src_ip: Source IP address.
+ :param dst_ip: Destination IP address.
+ :type rx_if: str
+ :type tx_if: str
+ :type src_mac: str
+ :type dst_mac: str
+ :type src_ip: str
+ :type dst_ip: str
+ :return: Traffic script arguments string.
+ :rtype: str
"""
- args = '--rx_if {0} --tx_if {1} --src_mac {2} --dst_mac {3} --src_ip' \
- ' {4} --dst_ip {5}'.format(rx_if, tx_if, src_mac, dst_mac, src_ip,
- dst_ip)
+ args = ('--rx_if {0} --tx_if {1} --src_mac {2} --dst_mac {3} --src_ip'
+ ' {4} --dst_ip {5}').format(rx_if, tx_if, src_mac, dst_mac,
+ src_ip, dst_ip)
return args
diff --git a/resources/libraries/python/VatExecutor.py b/resources/libraries/python/VatExecutor.py
index fd1d8db232..f0e28a1ae1 100644
--- a/resources/libraries/python/VatExecutor.py
+++ b/resources/libraries/python/VatExecutor.py
@@ -10,20 +10,25 @@
# 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.
-from ssh import SSH
-from robot.api import logger
-from constants import Constants
+
import json
+from robot.api import logger
+
+from resources.libraries.python.ssh import SSH
+from resources.libraries.python.constants import Constants
+
+
__all__ = ['VatExecutor']
def cleanup_vat_json_output(json_output):
- """Return VAT json output cleaned from VAT clutter.
+ """Return VAT JSON output cleaned from VAT clutter.
+
+ Clean up VAT JSON output from clutter like vat# prompts and such.
- Clean up VAT json output from clutter like vat# prompts and such
- :param json_output: cluttered json output.
- :return: cleaned up output json string
+ :param json_output: Cluttered JSON output.
+ :return: Cleaned up output JSON string.
"""
retval = json_output
@@ -42,12 +47,11 @@ class VatExecutor(object):
def execute_script(self, vat_name, node, timeout=10, json_out=True):
"""Copy local_path script to node, execute it and return result.
- :param vat_name: name of the vat script file. Only the file name of
- the script is required, the resources path is prepended
- automatically.
- :param node: node to execute the VAT script on.
- :param timeout: seconds to allow the script to run.
- :param json_out: require json output.
+ :param vat_name: Name of the vat script file. Only the file name of
+ the script is required, the resources path is prepended automatically.
+ :param node: Node to execute the VAT script on.
+ :param timeout: Seconds to allow the script to run.
+ :param json_out: Require JSON output.
:return: (rc, stdout, stderr) tuple.
"""
@@ -110,42 +114,26 @@ class VatExecutor(object):
@staticmethod
def cmd_from_template(node, vat_template_file, **vat_args):
"""Execute VAT script on specified node. This method supports
- script templates with parameters
- :param node: node in topology on witch the script is executed
- :param vat_template_file: template file of VAT script
- :param vat_args: arguments to the template file
- :return: list of json objects returned by VAT
+ script templates with parameters.
+
+ :param node: Node in topology on witch the script is executed.
+ :param vat_template_file: Template file of VAT script.
+ :param vat_args: Arguments to the template file.
+ :return: List of JSON objects returned by VAT.
"""
with VatTerminal(node) as vat:
return vat.vat_terminal_exec_cmd_from_template(vat_template_file,
**vat_args)
- @staticmethod
- def copy_config_to_remote(node, local_path, remote_path):
- # TODO: will be removed once v4 is merged to master.
- """Copies vat configuration file to node
-
- :param node: Remote node on which to copy the VAT configuration file
- :param local_path: path of the VAT script on local device that launches
- test cases.
- :param remote_path: path on remote node where to copy the VAT
- configuration script file
- """
- ssh = SSH()
- ssh.connect(node)
- logger.trace("Removing old file {}".format(remote_path))
- ssh.exec_command_sudo("rm -f {}".format(remote_path))
- ssh.scp(local_path, remote_path)
-
class VatTerminal(object):
- """VAT interactive terminal
+ """VAT interactive terminal.
- :param node: Node to open VAT terminal on.
- :param json_param: Defines if outputs from VAT are in JSON format.
- Default is True.
- :type node: dict
- :type json_param: bool
+ :param node: Node to open VAT terminal on.
+ :param json_param: Defines if outputs from VAT are in JSON format.
+ Default is True.
+ :type node: dict
+ :type json_param: bool
"""
@@ -172,10 +160,10 @@ class VatTerminal(object):
def vat_terminal_exec_cmd(self, cmd):
"""Execute command on the opened VAT terminal.
- :param cmd: Command to be executed.
+ :param cmd: Command to be executed.
- :return: Command output in python representation of JSON format or
- None if not in JSON mode.
+ :return: Command output in python representation of JSON format or
+ None if not in JSON mode.
"""
logger.debug("Executing command in VAT terminal: {}".format(cmd))
out = self._ssh.interactive_terminal_exec_command(self._tty,
@@ -212,9 +200,10 @@ class VatTerminal(object):
def vat_terminal_exec_cmd_from_template(self, vat_template_file, **args):
"""Execute VAT script from a file.
- :param vat_template_file: template file name of a VAT script
- :param args: dictionary of parameters for VAT script
- :return: list of json objects returned by VAT
+
+ :param vat_template_file: Template file name of a VAT script.
+ :param args: Dictionary of parameters for VAT script.
+ :return: List of JSON objects returned by VAT.
"""
file_path = '{}/{}'.format(Constants.RESOURCES_TPL_VAT,
vat_template_file)
diff --git a/resources/libraries/python/VatJsonUtil.py b/resources/libraries/python/VatJsonUtil.py
index c1a9e4b8de..05c93a1d06 100644
--- a/resources/libraries/python/VatJsonUtil.py
+++ b/resources/libraries/python/VatJsonUtil.py
@@ -43,7 +43,7 @@ class VatJsonUtil(object):
"""Return 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.
+ list parsed from JSON according to mac_address of the interface.
:param interfaces_list: Interfaces parsed from JSON.
:param mac_address: MAC address of interface we are looking for.
@@ -78,7 +78,7 @@ class VatJsonUtil(object):
@staticmethod
def update_vpp_interface_data_from_json(node, interface_dump_json):
- """Update vpp node data in node__DICT from json interface dump.
+ """Update vpp node data in node__DICT from JSON interface dump.
This method updates vpp interface names and sw if indexes according to
interface MAC addresses found in interface_dump_json.
diff --git a/resources/libraries/python/VppConfigGenerator.py b/resources/libraries/python/VppConfigGenerator.py
index 6085882e8e..53ae6ac8cc 100644
--- a/resources/libraries/python/VppConfigGenerator.py
+++ b/resources/libraries/python/VppConfigGenerator.py
@@ -13,15 +13,15 @@
"""VPP Configuration File Generator library"""
+import re
+import time
+
from robot.api import logger
from resources.libraries.python.ssh import SSH
from resources.libraries.python.topology import NodeType
from resources.libraries.python.topology import Topology
-import re
-import time
-
__all__ = ['VppConfigGenerator']
#
@@ -68,12 +68,12 @@ class VppConfigGenerator(object):
def add_pci_device(self, node, pci_device=None):
"""Add PCI device configuration for node.
- :param node: DUT node
+ :param node: DUT node.
:param pci_device: PCI device (format 0000:00:00.0 or 00:00.0).
If none given, all PCI devices for this node as per topology will be
added.
:type node: dict
- :type pci_device: string
+ :type pci_device: str
:return: nothing
"""
if node['type'] != NodeType.DUT:
@@ -90,84 +90,85 @@ class VppConfigGenerator(object):
# Specific device was given.
hostname = Topology.get_node_hostname(node)
- pattern = re.compile("^[0-9A-Fa-f]{4}:[0-9A-Fa-f]{2}:"\
- "[0-9A-Fa-f]{2}\\.[0-9A-Fa-f]$")
+ pattern = re.compile("^[0-9A-Fa-f]{4}:[0-9A-Fa-f]{2}:"
+ "[0-9A-Fa-f]{2}\\.[0-9A-Fa-f]$")
if not pattern.match(pci_device):
- raise ValueError('PCI address {} to be added to host {} '\
- 'is not in valid format xxxx:xx:xx.x'.\
- format(pci_device, hostname))
+ raise ValueError('PCI address {} to be added to host {} '
+ 'is not in valid format xxxx:xx:xx.x'.
+ format(pci_device, hostname))
- if not hostname in self._nodeconfig:
+ if hostname not in self._nodeconfig:
self._nodeconfig[hostname] = {}
- if not 'pci_addrs' in self._nodeconfig[hostname]:
+ if 'pci_addrs' not in self._nodeconfig[hostname]:
self._nodeconfig[hostname]['pci_addrs'] = []
self._nodeconfig[hostname]['pci_addrs'].append(pci_device)
- logger.debug('Adding PCI device {1} to {0}'.format(hostname,\
- pci_device))
+ logger.debug('Adding PCI device {1} to {0}'.format(hostname,
+ pci_device))
def add_cpu_config(self, node, cpu_config):
"""Add CPU configuration for node.
- :param node: DUT node
- :param cpu_config: CPU configuration option, as a string
+ :param node: DUT node.
+ :param cpu_config: CPU configuration option, as a string.
:type node: dict
- :type cpu_config: string
+ :type cpu_config: str
:return: nothing
"""
if node['type'] != NodeType.DUT:
raise ValueError('Node type is not a DUT')
hostname = Topology.get_node_hostname(node)
- if not hostname in self._nodeconfig:
+ if hostname not in self._nodeconfig:
self._nodeconfig[hostname] = {}
- if not 'cpu_config' in self._nodeconfig[hostname]:
+ if 'cpu_config' not in self._nodeconfig[hostname]:
self._nodeconfig[hostname]['cpu_config'] = []
self._nodeconfig[hostname]['cpu_config'].append(cpu_config)
- logger.debug('Adding {} to hostname {} CPU config'.format(hostname, \
- cpu_config))
+ logger.debug('Adding {} to hostname {} CPU config'.format(hostname,
+ cpu_config))
def add_socketmem_config(self, node, socketmem_config):
"""Add Socket Memory configuration for node.
- :param node: DUT node
- :param socketmem_config: Socket Memory configuration option, as a string
+ :param node: DUT node.
+ :param socketmem_config: Socket Memory configuration option,
+ as a string.
:type node: dict
- :type cpu_config: string
+ :type socketmem_config: str
:return: nothing
"""
if node['type'] != NodeType.DUT:
raise ValueError('Node type is not a DUT')
hostname = Topology.get_node_hostname(node)
- if not hostname in self._nodeconfig:
+ if hostname not in self._nodeconfig:
self._nodeconfig[hostname] = {}
self._nodeconfig[hostname]['socketmem_config'] = socketmem_config
- logger.debug('Setting hostname {} Socket Memory config to {}'.\
- format(hostname, socketmem_config))
+ logger.debug('Setting hostname {} Socket Memory config to {}'.
+ format(hostname, socketmem_config))
def add_heapsize_config(self, node, heapsize_config):
"""Add Heap Size configuration for node.
- :param node: DUT node
- :param heapsize_config: Heap Size configuration, as a string
+ :param node: DUT node.
+ :param heapsize_config: Heap Size configuration, as a string.
:type node: dict
- :type cpu_config: string
+ :type heapsize_config: str
:return: nothing
"""
if node['type'] != NodeType.DUT:
raise ValueError('Node type is not a DUT')
hostname = Topology.get_node_hostname(node)
- if not hostname in self._nodeconfig:
+ if hostname not in self._nodeconfig:
self._nodeconfig[hostname] = {}
self._nodeconfig[hostname]['heapsize_config'] = heapsize_config
- logger.debug('Setting hostname {} Heap Size config to {}'.\
- format(hostname, heapsize_config))
+ logger.debug('Setting hostname {} Heap Size config to {}'.
+ format(hostname, heapsize_config))
def add_rss_config(self, node, rss_config):
"""Add RSS configuration for node.
- :param node: DUT node
- :param rss_config: RSS configuration, as a string
+ :param node: DUT node.
+ :param rss_config: RSS configuration, as a string.
:type node: dict
- :type rss_config: string
+ :type rss_config: str
:return: nothing
"""
if node['type'] != NodeType.DUT:
@@ -184,8 +185,8 @@ class VppConfigGenerator(object):
def remove_all_pci_devices(self, node):
"""Remove PCI device configuration from node.
- :param node: DUT node
- :type: node: dict
+ :param node: DUT node.
+ :type node: dict
:return: nothing
"""
if node['type'] != NodeType.DUT:
@@ -193,14 +194,14 @@ class VppConfigGenerator(object):
hostname = Topology.get_node_hostname(node)
if hostname in self._nodeconfig:
self._nodeconfig[hostname]['pci_addrs'] = []
- logger.debug('Clearing all PCI devices for hostname {}.'.\
- format(hostname))
+ logger.debug('Clearing all PCI devices for hostname {}.'.
+ format(hostname))
def remove_all_cpu_config(self, node):
"""Remove CPU configuration from node.
- :param node: DUT node
- :type: node: dict
+ :param node: DUT node.
+ :type node: dict
:return: nothing
"""
if node['type'] != NodeType.DUT:
@@ -208,14 +209,14 @@ class VppConfigGenerator(object):
hostname = Topology.get_node_hostname(node)
if hostname in self._nodeconfig:
self._nodeconfig[hostname]['cpu_config'] = []
- logger.debug('Clearing all CPU config for hostname {}.'.\
- format(hostname))
+ logger.debug('Clearing all CPU config for hostname {}.'.
+ format(hostname))
def remove_socketmem_config(self, node):
"""Remove Socket Memory configuration from node.
- :param node: DUT node
- :type: node: dict
+ :param node: DUT node.
+ :type node: dict
:return: nothing
"""
if node['type'] != NodeType.DUT:
@@ -223,14 +224,14 @@ class VppConfigGenerator(object):
hostname = Topology.get_node_hostname(node)
if hostname in self._nodeconfig:
self._nodeconfig[hostname].pop('socketmem_config', None)
- logger.debug('Clearing Socket Memory config for hostname {}.'.\
- format(hostname))
+ logger.debug('Clearing Socket Memory config for hostname {}.'.
+ format(hostname))
def remove_heapsize_config(self, node):
"""Remove Heap Size configuration from node.
- :param node: DUT node
- :type: node: dict
+ :param node: DUT node.
+ :type node: dict
:return: nothing
"""
if node['type'] != NodeType.DUT:
@@ -238,14 +239,14 @@ class VppConfigGenerator(object):
hostname = Topology.get_node_hostname(node)
if hostname in self._nodeconfig:
self._nodeconfig[hostname].pop('heapsize_config', None)
- logger.debug('Clearing Heap Size config for hostname {}.'.\
- format(hostname))
+ logger.debug('Clearing Heap Size config for hostname {}.'.
+ format(hostname))
def remove_rss_config(self, node):
"""Remove RSS configuration from node.
- :param node: DUT node
- :type: node: dict
+ :param node: DUT node.
+ :type node: dict
:return: nothing
"""
if node['type'] != NodeType.DUT:
@@ -262,9 +263,9 @@ class VppConfigGenerator(object):
Use data from calls to this class to form a startup.conf file and
replace /etc/vpp/startup.conf with it on node.
- :param node: DUT node
- :param waittime: time to wait for VPP to restart (default 5 seconds)
- :param retries: number of times (default 12) to re-try waiting
+ :param node: DUT node.
+ :param waittime: Time to wait for VPP to restart (default 5 seconds).
+ :param retries: Number of times (default 12) to re-try waiting.
:type node: dict
:type waittime: int
:type retries: int
@@ -304,8 +305,8 @@ class VppConfigGenerator(object):
heapsizeconfig=heapsizeconfig,
rssconfig=rssconfig)
- logger.debug('Writing VPP config to host {}: "{}"'.format(hostname,\
- vppconfig))
+ logger.debug('Writing VPP config to host {}: "{}"'.format(hostname,
+ vppconfig))
ssh = SSH()
ssh.connect(node)
@@ -314,16 +315,16 @@ class VppConfigGenerator(object):
# a sudo'd outut ("sudo echo xxx > /path/to/file") does not
# work on most platforms...
(ret, stdout, stderr) = \
- ssh.exec_command('echo "{0}" | sudo tee {1}'.\
- format(vppconfig, VPP_CONFIG_FILENAME))
+ ssh.exec_command('echo "{0}" | sudo tee {1}'.
+ format(vppconfig, VPP_CONFIG_FILENAME))
if ret != 0:
- logger.debug('Writing config file failed to node {}'.\
- format(hostname))
+ logger.debug('Writing config file failed to node {}'.
+ format(hostname))
logger.debug('stdout: {}'.format(stdout))
logger.debug('stderr: {}'.format(stderr))
- raise RuntimeError('Writing config file failed to node {}'.\
- format(hostname))
+ raise RuntimeError('Writing config file failed to node {}'.
+ format(hostname))
# Instead of restarting, we'll do separate start and stop
# actions. This way we don't care whether VPP was running
@@ -332,12 +333,12 @@ class VppConfigGenerator(object):
(ret, stdout, stderr) = \
ssh.exec_command('sudo initctl start {}'.format(VPP_SERVICE_NAME))
if ret != 0:
- logger.debug('Restarting VPP failed on node {}'.\
- format(hostname))
+ logger.debug('Restarting VPP failed on node {}'.
+ format(hostname))
logger.debug('stdout: {}'.format(stdout))
logger.debug('stderr: {}'.format(stderr))
- raise RuntimeError('Restarting VPP failed on node {}'.\
- format(hostname))
+ raise RuntimeError('Restarting VPP failed on node {}'.
+ format(hostname))
# Sleep <waittime> seconds, up to <retry> times,
# and verify if VPP is running.
@@ -357,16 +358,16 @@ class VppConfigGenerator(object):
# healthy or not, or a call that waits (up to a defined length
# of time) and returns immediately if VPP is or becomes healthy.
(ret, stdout, stderr) = \
- ssh.exec_command('echo show hardware-interfaces | '\
- 'nc 0 5002')
+ ssh.exec_command('echo show hardware-interfaces | '
+ 'nc 0 5002')
if ret == 0:
vpp_is_running = True
else:
- logger.debug('VPP not yet running, {} retries left'.\
- format(retries_left))
+ logger.debug('VPP not yet running, {} retries left'.
+ format(retries_left))
if retries_left == 0:
- raise RuntimeError('VPP failed to restart on node {}'.\
- format(hostname))
- logger.debug('VPP interfaces found on node {}'.\
- format(stdout))
+ raise RuntimeError('VPP failed to restart on node {}'.
+ format(hostname))
+ logger.debug('VPP interfaces found on node {}'.
+ format(stdout))
diff --git a/resources/libraries/python/VppCounters.py b/resources/libraries/python/VppCounters.py
index caae06c495..375bdfb519 100644
--- a/resources/libraries/python/VppCounters.py
+++ b/resources/libraries/python/VppCounters.py
@@ -14,10 +14,12 @@
"""VPP counters utilities library."""
import time
-from topology import NodeType, Topology
-from VatExecutor import VatExecutor, VatTerminal
+
from robot.api import logger
+from resources.libraries.python.topology import NodeType, Topology
+from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
+
class VppCounters(object):
"""VPP counters utilities."""
@@ -28,8 +30,8 @@ class VppCounters(object):
def vpp_nodes_clear_interface_counters(self, nodes):
"""Clear interface counters on all VPP nodes in topology.
- :param nodes: Nodes in topology.
- :type nodes: dict
+ :param nodes: Nodes in topology.
+ :type nodes: dict
"""
for node in nodes.values():
if node['type'] == NodeType.DUT:
@@ -37,9 +39,9 @@ class VppCounters(object):
@staticmethod
def vpp_show_errors_verbose(node):
- """Run "show errors verbose" debug CLI command
+ """Run "show errors verbose" debug CLI command.
- :param node: Node to run command on
+ :param node: Node to run command on.
:type node: dict
"""
vat = VatExecutor()
@@ -47,9 +49,9 @@ class VppCounters(object):
@staticmethod
def vpp_show_runtime_verbose(node):
- """Run "show runtime" debug CLI command
+ """Run "show runtime" debug CLI command.
- :param node: Node to run command on
+ :param node: Node to run command on.
:type node: dict
"""
vat = VatExecutor()
@@ -57,9 +59,9 @@ class VppCounters(object):
@staticmethod
def vpp_show_hardware_detail(node):
- """Run "show hardware-interfaces detail" debug CLI command
+ """Run "show hardware-interfaces detail" debug CLI command.
- :param node: Node to run command on
+ :param node: Node to run command on.
:type node: dict
"""
vat = VatExecutor()
@@ -69,8 +71,8 @@ class VppCounters(object):
def vpp_clear_interface_counters(node):
"""Clear interface counters on VPP node.
- :param node: Node to clear interface counters on.
- :type node: dict
+ :param node: Node to clear interface counters on.
+ :type node: dict
"""
vat = VatExecutor()
vat.execute_script('clear_interface.vat', node)
@@ -79,9 +81,9 @@ class VppCounters(object):
def vpp_dump_stats_table(self, node):
"""Dump stats table on VPP node.
- :param node: Node to dump stats table on.
- :type node: dict
- :return: Stats table.
+ :param node: Node to dump stats table on.
+ :type node: dict
+ :return: Stats table.
"""
with VatTerminal(node) as vat:
vat.vat_terminal_exec_cmd('want_stats enable')
@@ -101,16 +103,16 @@ class VppCounters(object):
return self.vpp_get_ipv46_interface_counter(node, interface, True)
def vpp_get_ipv46_interface_counter(self, node, interface, is_ipv6=True):
- """Return interface IPv4/IPv6 counter
-
- :param node: Node to get interface IPv4/IPv6 counter on.
- :param interface: Interface name.
- :type node: dict
- :type interface: str
- :return: Interface IPv4/IPv6 counter.
- :param is_ipv6: specify IP version
- :type is_ipv6: bool
- :rtype: int
+ """Return interface IPv4/IPv6 counter.
+
+ :param node: Node to get interface IPv4/IPv6 counter on.
+ :param interface: Interface name.
+ :param is_ipv6: Specify IP version.
+ :type node: dict
+ :type interface: str
+ :type is_ipv6: bool
+ :return: Interface IPv4/IPv6 counter.
+ :rtype: int
"""
version = 'ip6' if is_ipv6 else 'ip4'
topo = Topology()
diff --git a/resources/libraries/python/parsers/JsonParser.py b/resources/libraries/python/parsers/JsonParser.py
index 1d177670ff..50a920bee0 100644
--- a/resources/libraries/python/parsers/JsonParser.py
+++ b/resources/libraries/python/parsers/JsonParser.py
@@ -11,35 +11,42 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""Used to parse Json files or Json data strings to dictionaries"""
+"""Used to parse JSON files or JSON data strings to dictionaries"""
import json
class JsonParser(object):
- """Parses Json data string or files containing Json data strings"""
+ """Parses JSON data string or files containing JSON data strings"""
def __init__(self):
pass
@staticmethod
def parse_data(json_data):
- """Return list parsed from json data string.
+ """Return list parsed from JSON data string.
- Translates json data into list of values/dictionaries/lists
- :param json_data: data in json format
- :return: json data parsed as python list
+ Translates JSON data into list of values/dictionaries/lists.
+
+ :param json_data: Data in JSON format.
+ :type json_data: str
+ :return: JSON data parsed as python list.
+ :rtype: list
"""
parsed_data = json.loads(json_data)
return parsed_data
- def parse_file(self, json_file):
- """Return list parsed from file containing json string.
+ @staticmethod
+ def parse_file(json_file):
+ """Return list parsed from file containing JSON string.
+
+ Translates JSON data found in file into list of
+ values/dictionaries/lists.
- Translates json data found in file into list of
- values/dictionaries/lists
- :param json_file: file with json type data
- :return: json data parsed as python list
+ :param json_file: File with JSON type data.
+ :type json_file: str
+ :return: JSON data parsed as python list.
+ :rtype: list
"""
input_data = open(json_file).read()
- parsed_data = self.parse_data(input_data)
+ parsed_data = JsonParser.parse_data(input_data)
return parsed_data
diff --git a/resources/libraries/python/ssh.py b/resources/libraries/python/ssh.py
index 6914d528d6..67193c11e2 100644
--- a/resources/libraries/python/ssh.py
+++ b/resources/libraries/python/ssh.py
@@ -10,15 +10,17 @@
# 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 StringIO
+from time import time
+
import socket
import paramiko
from paramiko import RSAKey
-import StringIO
from scp import SCPClient
-from time import time
-from robot.api import logger
from interruptingcow import timeout
-from robot.utils.asserts import assert_equal, assert_not_equal
+from robot.api import logger
+from robot.utils.asserts import assert_equal
__all__ = ["exec_cmd", "exec_cmd_no_error"]
@@ -31,9 +33,10 @@ class SSH(object):
__existing_connections = {}
def __init__(self):
- pass
+ self._ssh = None
- def _node_hash(self, node):
+ @staticmethod
+ def _node_hash(node):
return hash(frozenset([node['host'], node['port']]))
def connect(self, node):
@@ -65,7 +68,7 @@ class SSH(object):
logger.debug('new ssh: {0}'.format(self._ssh))
logger.debug('Connect peer: {0}'.
- format(self._ssh.get_transport().getpeername()))
+ format(self._ssh.get_transport().getpeername()))
logger.debug('Connections: {0}'.format(str(SSH.__existing_connections)))
def disconnect(self, node):
@@ -107,7 +110,6 @@ class SSH(object):
'of buffer: {0}'.format(stdout))
raise
-
stderr = ""
while True:
buf = chan.recv_stderr(self.__MAX_RECV_BUF)
@@ -126,20 +128,20 @@ class SSH(object):
def exec_command_sudo(self, cmd, cmd_input=None, timeout=10):
"""Execute SSH command with sudo on a new channel on the connected Node.
- :param cmd: Command to be executed.
- :param cmd_input: Input redirected to the command.
- :param timeout: Timeout.
- :return: return_code, stdout, stderr
+ :param cmd: Command to be executed.
+ :param cmd_input: Input redirected to the command.
+ :param timeout: Timeout.
+ :return: return_code, stdout, stderr
- :Example:
+ :Example:
- >>> from ssh import SSH
- >>> ssh = SSH()
- >>> ssh.connect(node)
- >>> #Execute command without input (sudo -S cmd)
- >>> ssh.exec_command_sudo("ifconfig eth0 down")
- >>> #Execute command with input (sudo -S cmd <<< "input")
- >>> ssh.exec_command_sudo("vpp_api_test", "dump_interface_table")
+ >>> from ssh import SSH
+ >>> ssh = SSH()
+ >>> ssh.connect(node)
+ >>> # Execute command without input (sudo -S cmd)
+ >>> ssh.exec_command_sudo("ifconfig eth0 down")
+ >>> # Execute command with input (sudo -S cmd <<< "input")
+ >>> ssh.exec_command_sudo("vpp_api_test", "dump_interface_table")
"""
if cmd_input is None:
command = 'sudo -S {c}'.format(c=cmd)
@@ -150,15 +152,15 @@ class SSH(object):
def interactive_terminal_open(self, time_out=10):
"""Open interactive terminal on a new channel on the connected Node.
- :param time_out: Timeout in seconds.
- :return: SSH channel with opened terminal.
+ :param time_out: Timeout in seconds.
+ :return: SSH channel with opened terminal.
- .. warning:: Interruptingcow is used here, and it uses
- signal(SIGALRM) to let the operating system interrupt program
- execution. This has the following limitations: Python signal
- handlers only apply to the main thread, so you cannot use this
- from other threads. You must not use this in a program that
- uses SIGALRM itself (this includes certain profilers)
+ .. warning:: Interruptingcow is used here, and it uses
+ signal(SIGALRM) to let the operating system interrupt program
+ execution. This has the following limitations: Python signal
+ handlers only apply to the main thread, so you cannot use this
+ from other threads. You must not use this in a program that
+ uses SIGALRM itself (this includes certain profilers)
"""
chan = self._ssh.get_transport().open_session()
chan.get_pty()
@@ -175,25 +177,26 @@ class SSH(object):
raise Exception('Open interactive terminal timeout.')
return chan
- def interactive_terminal_exec_command(self, chan, cmd, prompt,
+ @staticmethod
+ def interactive_terminal_exec_command(chan, cmd, prompt,
time_out=10):
"""Execute command on interactive terminal.
- interactive_terminal_open() method has to be called first!
-
- :param chan: SSH channel with opened terminal.
- :param cmd: Command to be executed.
- :param prompt: Command prompt, sequence of characters used to
- indicate readiness to accept commands.
- :param time_out: Timeout in seconds.
- :return: Command output.
-
- .. warning:: Interruptingcow is used here, and it uses
- signal(SIGALRM) to let the operating system interrupt program
- execution. This has the following limitations: Python signal
- handlers only apply to the main thread, so you cannot use this
- from other threads. You must not use this in a program that
- uses SIGALRM itself (this includes certain profilers)
+ interactive_terminal_open() method has to be called first!
+
+ :param chan: SSH channel with opened terminal.
+ :param cmd: Command to be executed.
+ :param prompt: Command prompt, sequence of characters used to
+ indicate readiness to accept commands.
+ :param time_out: Timeout in seconds.
+ :return: Command output.
+
+ .. warning:: Interruptingcow is used here, and it uses
+ signal(SIGALRM) to let the operating system interrupt program
+ execution. This has the following limitations: Python signal
+ handlers only apply to the main thread, so you cannot use this
+ from other threads. You must not use this in a program that
+ uses SIGALRM itself (this includes certain profilers)
"""
chan.sendall('{c}\n'.format(c=cmd))
buf = ''
@@ -207,10 +210,11 @@ class SSH(object):
tmp = buf.replace(cmd.replace('\n', ''), '')
return tmp.replace(prompt, '')
- def interactive_terminal_close(self, chan):
+ @staticmethod
+ def interactive_terminal_close(chan):
"""Close interactive terminal SSH channel.
- :param: chan: SSH channel to be closed.
+ :param: chan: SSH channel to be closed.
"""
chan.close()
@@ -259,10 +263,12 @@ def exec_cmd(node, cmd, timeout=None, sudo=False):
logger.error(e)
return None
- return (ret_code, stdout, stderr)
+ return ret_code, stdout, stderr
+
def exec_cmd_no_error(node, cmd, timeout=None, sudo=False):
"""Convenience function to ssh/exec/return out & err.
+
Verifies that return code is zero.
Returns (stdout, stderr).
@@ -270,4 +276,4 @@ def exec_cmd_no_error(node, cmd, timeout=None, sudo=False):
(rc, stdout, stderr) = exec_cmd(node, cmd, timeout=timeout, sudo=sudo)
assert_equal(rc, 0, 'Command execution failed: "{}"\n{}'.
format(cmd, stderr))
- return (stdout, stderr)
+ return stdout, stderr
diff --git a/resources/libraries/python/topology.py b/resources/libraries/python/topology.py
index 0f26d2c6e9..20745eb0a2 100644
--- a/resources/libraries/python/topology.py
+++ b/resources/libraries/python/topology.py
@@ -13,18 +13,19 @@
"""Defines nodes and topology structure."""
+from yaml import load
+
from robot.api import logger
from robot.libraries.BuiltIn import BuiltIn
from robot.api.deco import keyword
-from yaml import load
__all__ = ["DICT__nodes", 'Topology']
def load_topo_from_yaml():
- """Load topology from file defined in "${TOPOLOGY_PATH}" variable
+ """Load topology from file defined in "${TOPOLOGY_PATH}" variable.
- :return: nodes from loaded topology
+ :return: Nodes from loaded topology.
"""
topo_path = BuiltIn().get_variable_value("${TOPOLOGY_PATH}")
@@ -33,7 +34,7 @@ def load_topo_from_yaml():
class NodeType(object):
- """Defines node types used in topology dictionaries"""
+ """Defines node types used in topology dictionaries."""
# Device Under Test (this node has VPP running on it)
DUT = 'DUT'
# Traffic Generator (this node has traffic generator on it)
@@ -43,7 +44,7 @@ class NodeType(object):
class NodeSubTypeTG(object):
- #T-Rex traffic generator
+ # T-Rex traffic generator
TREX = 'TREX'
# Moongen
MOONGEN = 'MOONGEN'
@@ -54,7 +55,7 @@ DICT__nodes = load_topo_from_yaml()
class Topology(object):
- """Topology data manipulation and extraction methods
+ """Topology data manipulation and extraction methods.
Defines methods used for manipulation and extraction of data from
the used topology.
@@ -98,14 +99,13 @@ 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.
- :param value: value that should be found using the key.
+ :param node: The node dictionary.
+ :param key: Key by which to select the interface.
+ :param value: Value that should be found using the key.
:return:
"""
-
interfaces = node['interfaces']
retval = None
for interface in interfaces.values():
@@ -119,27 +119,29 @@ class Topology(object):
def get_interface_by_link_name(self, node, link_name):
"""Return interface name of link on node.
- This method returns the interface name asociated with a given link
+ This method returns the interface name associated with a given link
for a given node.
- :param link_name: name of the link that a interface is connected to.
- :param node: the node topology dictionary
- :return: interface name of the interface connected to the given link
- """
+ :param link_name: Name of the link that a interface is connected to.
+ :param node: The node topology dictionary.
+ :return: Interface name of the interface connected to the given link.
+ :rtype: str
+ """
return self._get_interface_by_key_value(node, "link", link_name)
def get_interfaces_by_link_names(self, node, link_names):
- """Return dictionary of dicitonaries {"interfaceN", interface name}.
+ """Return dictionary of dictionaries {"interfaceN", interface name}.
- This method returns the interface names asociated with given links
+ This method returns the interface names associated with given links
for a given node.
- :param link_names: list of names of the link that a interface is
+
+ :param link_names: List of names of the link that a interface is
connected to.
- :param node: the node topology directory
- :return: dictionary of interface names that are connected to the given
- links
+ :param node: The node topology directory.
+ :return: Dictionary of interface names that are connected to the given
+ links.
+ :rtype: dict
"""
-
retval = {}
interface_key_tpl = "interface{}"
interface_number = 1
@@ -153,13 +155,14 @@ class Topology(object):
def get_interface_by_sw_index(self, node, sw_index):
"""Return interface name of link on node.
- This method returns the interface name asociated with a software index
- assigned to the interface by vpp for a given node.
- :param sw_index: sw_index of the link that a interface is connected to.
- :param node: the node topology dictionary
- :return: interface name of the interface connected to the given link
- """
+ This method returns the interface name associated with a software
+ interface index assigned to the interface by vpp for a given node.
+ :param sw_index: Sw_index of the link that a interface is connected to.
+ :param node: The node topology dictionary.
+ :return: Interface name of the interface connected to the given link.
+ :rtype: str
+ """
return self._get_interface_by_key_value(node, "vpp_sw_index", sw_index)
@staticmethod
@@ -257,7 +260,7 @@ class Topology(object):
link_name = port_data['link']
break
- if link_name is None:
+ if link_name is None:
return None
# find link
@@ -290,8 +293,6 @@ class Topology(object):
link_name = None
# get link name where the interface belongs to
for port_name, port_data in node['interfaces'].iteritems():
- if port_name == 'mgmt':
- continue
if port_data['name'] == interface_name:
link_name = port_data['link']
break
@@ -343,13 +344,14 @@ class Topology(object):
@staticmethod
def get_node_link_mac(node, link_name):
- """Return interface mac address by link name
+ """Return interface mac address by link name.
- :param node: Node to get interface sw_index on
- :param link_name: link name
+ :param node: Node to get interface sw_index on.
+ :param link_name: Link name.
:type node: dict
- :type link_name: string
- :return: mac address string
+ :type link_name: str
+ :return: MAC address string.
+ :rtype: str
"""
for port in node['interfaces'].values():
if port.get('link') == link_name:
@@ -358,10 +360,11 @@ class Topology(object):
@staticmethod
def _get_node_active_link_names(node):
- """Return 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
+ :param node: Node topology dictionary.
+ :return: List of strings that represent link names occupied by the node.
+ :rtype: list
"""
interfaces = node['interfaces']
link_names = []
@@ -374,11 +377,14 @@ class Topology(object):
@keyword('Get active links connecting "${node1}" and "${node2}"')
def get_active_connecting_links(self, node1, node2):
- """Return 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
- :return: list of strings that represent connecting link names
+ :param node1: Node topology dictionary.
+ :param node2: Node topology dictionary.
+ :type node1: dict
+ :type node2: dict
+ :return: List of strings that represent connecting link names.
+ :rtype: list
"""
logger.trace("node1: {}".format(str(node1)))
@@ -394,14 +400,14 @@ class Topology(object):
def get_first_active_connecting_link(self, node1, node2):
"""
- :param node1: Connected node
+ :param node1: Connected node.
+ :param node2: Connected node.
:type node1: dict
- :param node2: Connected node
:type node2: dict
- :return: name of link connecting the two nodes together
+ :return: Name of link connecting the two nodes together.
+ :rtype: str
:raises: RuntimeError
"""
-
connecting_links = self.get_active_connecting_links(node1, node2)
if len(connecting_links) == 0:
raise RuntimeError("No links connecting the nodes were found")
@@ -459,14 +465,7 @@ class Topology(object):
For the time being it returns links from the Node path:
TG->DUT1->DUT2->TG
- :param tgen: traffic generator node data
- :param dut1: DUT1 node data
- :param dut2: DUT2 node data
- :type tgen: dict
- :type dut1: dict
- :type dut2: dict
- :return: dictionary of possible link combinations
- the naming convention until changed to something more general is
+ The naming convention until changed to something more general is
implemented is this:
DUT1_DUT2_LINK: link name between DUT! and DUT2
DUT1_TG_LINK: link name between DUT1 and TG
@@ -477,6 +476,15 @@ class Topology(object):
domain on DUT1
DUT2_BD_LINKS: list of link names that will be connected by the bridge
domain on DUT2
+
+ :param tgen: Traffic generator node data.
+ :param dut1: DUT1 node data.
+ :param dut2: DUT2 node data.
+ :type tgen: dict
+ :type dut1: dict
+ :type dut2: dict
+ :return: Dictionary of possible link combinations.
+ :rtype: dict
"""
# TODO: replace with generic function.
dut1_dut2_link = self.get_first_active_connecting_link(dut1, dut2)
@@ -495,10 +503,12 @@ class Topology(object):
@staticmethod
def is_tg_node(node):
- """Find out whether the node is TG
+ """Find out whether the node is TG.
- :param node: node to examine
- :return: True if node is type of TG; False otherwise
+ :param node: Node to examine.
+ :type node: dict
+ :return: True if node is type of TG, otherwise False.
+ :rtype: bool
"""
return node['type'] == NodeType.TG
@@ -508,6 +518,7 @@ class Topology(object):
:param node: Node created from topology.
:type node: dict
- :return: host as 'str' type
+ :return: Hostname or IP address.
+ :rtype: str
"""
return node['host']
diff --git a/resources/libraries/robot/ipv6.robot b/resources/libraries/robot/ipv6.robot
index 17ab14274f..ef0b79f657 100644
--- a/resources/libraries/robot/ipv6.robot
+++ b/resources/libraries/robot/ipv6.robot
@@ -162,10 +162,10 @@
| | [Arguments] | ${nodes} | ${nodes_addr}
| | Nodes Clear Ipv6 Addresses | ${nodes} | ${nodes_addr}
-| Vpp nodes ra supress link layer
-| | [Documentation] | Supress ICMPv6 router advertisement message for link scope address
+| Vpp nodes ra suppress link layer
+| | [Documentation] | Suppress ICMPv6 router advertisement message for link scope address
| | [Arguments] | ${nodes}
-| | Vpp All Ra Supress Link Layer | ${nodes}
+| | Vpp All Ra Suppress Link Layer | ${nodes}
| Vpp nodes setup ipv6 routing
| | [Documentation] | Setup routing on all VPP nodes required for IPv6 tests
diff --git a/resources/libraries/robot/performance.robot b/resources/libraries/robot/performance.robot
index e8a56adc0e..804b6433d3 100644
--- a/resources/libraries/robot/performance.robot
+++ b/resources/libraries/robot/performance.robot
@@ -145,4 +145,4 @@
| | [Arguments] | ${duration} | ${rate} | ${framesize} | ${topology_type}
| | Send traffic on | ${tg} | ${duration}
| | ... | ${rate} | ${framesize} | ${topology_type}
-| | No traffic loss occured
+| | No traffic loss occurred
diff --git a/resources/tools/topology/update_topology.py b/resources/tools/topology/update_topology.py
index d7a3929643..a5711d0922 100755
--- a/resources/tools/topology/update_topology.py
+++ b/resources/tools/topology/update_topology.py
@@ -26,12 +26,13 @@ import yaml
from resources.libraries.python.ssh import SSH
+
def load_topology(args):
"""Load topology file referenced to by parameter passed to this script.
- :param args: arguments parsed from commandline
+ :param args: Arguments parsed from commandline.
:type args: ArgumentParser().parse_args()
- :return: Python representation of topology yaml
+ :return: Python representation of topology YAML.
:rtype: dict
"""
data = None
@@ -45,15 +46,16 @@ def load_topology(args):
return data
+
def ssh_no_error(ssh, cmd):
"""Execute a command over ssh channel, and log and exit if the command
- fials.
+ fails.
- :param ssh: SSH() object connected to a node
- :param cmd: Command line to execute on remote node
+ :param ssh: SSH() object connected to a node.
+ :param cmd: Command line to execute on remote node.
:type ssh: SSH() object
:type cmd: str
- :return: stdout from the SSH command
+ :return: stdout from the SSH command.
:rtype: str
"""
ret, stdo, stde = ssh.exec_command(cmd)
@@ -65,6 +67,7 @@ def ssh_no_error(ssh, cmd):
return stdo
+
def update_mac_addresses_for_node(node):
"""For given node loop over all ports with PCI address and look for its MAC
address.
@@ -73,12 +76,13 @@ def update_mac_addresses_for_node(node):
and binds it to linux kernel driver. After the device is bound to specific
linux kernel driver the MAC address is extracted from /sys/bus/pci location
and stored within the node dictionary that was passed to this function.
- :param node: Node from topology
+
+ :param node: Node from topology.
:type node: dict
:return: None
"""
for port_name, port in node['interfaces'].items():
- if not port.has_key('driver'):
+ if 'driver' not in port:
err_msg = '{0} port {1} has no driver element, exiting'.format(
node['host'], port_name)
raise RuntimeError(err_msg)
@@ -101,7 +105,7 @@ def update_mac_addresses_for_node(node):
# Then bind to the 'driver' from topology for given port
cmd = 'echo {0} | sudo tee /sys/bus/pci/drivers/{1}/bind'.\
- format(port['pci_address'], port['driver'])
+ format(port['pci_address'], port['driver'])
ssh_no_error(ssh, cmd)
# Then extract the mac address and store it in the topology
@@ -111,35 +115,35 @@ def update_mac_addresses_for_node(node):
pattern = re.compile("^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$")
if not pattern.match(mac):
raise RuntimeError('MAC address read from host {0} {1} is in '
- 'bad format "{2}"'.format(node['host'],
- port['pci_address'], mac))
+ 'bad format "{2}"'
+ .format(node['host'], port['pci_address'], mac))
print '{0}: Found MAC address of PCI device {1}: {2}'.format(
node['host'], port['pci_address'], mac)
port['mac_address'] = mac
+
def update_nodes_mac_addresses(topology):
"""Loop over nodes in topology and get mac addresses for all listed ports
based on PCI addresses.
- :param topology: Topology information with nodes
+ :param topology: Topology information with nodes.
:type topology: dict
:return: None
"""
-
for node in topology['nodes'].values():
update_mac_addresses_for_node(node)
+
def dump_updated_topology(topology, args):
"""Writes or prints out updated topology file.
- :param topology: Topology information with nodes
- :param args: arguments parsed from command line
+ :param topology: Topology information with nodes.
+ :param args: Arguments parsed from command line.
:type topology: dict
:type args: ArgumentParser().parse_args()
- :return: 1 if error occured, 0 if successful
+ :return: 1 if error occurred, 0 if successful.
:rtype: int
"""
-
if args.output_file:
if not args.force:
if os.path.isfile(args.output_file):
@@ -153,6 +157,7 @@ def dump_updated_topology(topology, args):
print yaml.dump(topology, default_flow_style=False)
return 0
+
def main():
"""Main function"""
parser = ArgumentParser()
@@ -172,5 +177,3 @@ def main():
if __name__ == "__main__":
sys.exit(main())
-
-