aboutsummaryrefslogtreecommitdiffstats
path: root/resources
diff options
context:
space:
mode:
Diffstat (limited to 'resources')
-rw-r--r--resources/libraries/python/Classify.py30
-rw-r--r--resources/libraries/python/DUTSetup.py14
-rw-r--r--resources/libraries/python/IPv4Setup.py39
-rw-r--r--resources/libraries/python/IPv4Util.py35
-rw-r--r--resources/libraries/python/IPv6Util.py8
-rw-r--r--resources/libraries/python/LispSetup.py8
-rw-r--r--resources/libraries/python/Namespaces.py14
-rw-r--r--resources/libraries/python/PacketVerifier.py17
-rw-r--r--resources/libraries/python/QemuUtils.py42
-rw-r--r--resources/libraries/python/Routing.py18
-rw-r--r--resources/libraries/python/SetupFramework.py6
-rw-r--r--resources/libraries/python/VatExecutor.py21
-rw-r--r--resources/libraries/python/VatJsonUtil.py2
-rw-r--r--resources/libraries/python/ssh.py37
-rw-r--r--resources/libraries/python/topology.py2
-rwxr-xr-xresources/tools/topology/update_topology.py2
16 files changed, 206 insertions, 89 deletions
diff --git a/resources/libraries/python/Classify.py b/resources/libraries/python/Classify.py
index 8dbe3fb25f..c781bbbd14 100644
--- a/resources/libraries/python/Classify.py
+++ b/resources/libraries/python/Classify.py
@@ -11,12 +11,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+"""Classify utilities library."""
from robot.api import logger
from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
+# pylint: disable=too-many-arguments, invalid-name
+
class Classify(object):
"""Classify utilities."""
@@ -117,9 +120,9 @@ class Classify(object):
return table_index, skip_n, match_n
@staticmethod
- def vpp_configures_classify_session_l3(node, acl_method, table_index, skip_n,
- match_n, ip_version, direction,
- address):
+ def vpp_configures_classify_session_l3(node, acl_method, table_index,
+ skip_n, match_n, ip_version,
+ direction, address):
"""Configuration of classify session for IP address filtering.
:param node: VPP node to setup classify session.
@@ -150,8 +153,8 @@ class Classify(object):
address=address)
@staticmethod
- def vpp_configures_classify_session_l2(node, acl_method, table_index, skip_n,
- match_n, direction, address):
+ def vpp_configures_classify_session_l2(node, acl_method, table_index,
+ skip_n, match_n, direction, address):
"""Configuration of classify session for MAC address filtering.
:param node: VPP node to setup classify session.
@@ -170,17 +173,18 @@ class Classify(object):
:type address: str
"""
with VatTerminal(node) as vat:
- vat.vat_terminal_exec_cmd_from_template("classify_add_session_l2.vat",
- acl_method=acl_method,
- table_index=table_index,
- skip_n=skip_n,
- match_n=match_n,
- direction=direction,
- address=address)
+ vat.vat_terminal_exec_cmd_from_template(
+ "classify_add_session_l2.vat",
+ acl_method=acl_method,
+ table_index=table_index,
+ skip_n=skip_n,
+ match_n=match_n,
+ direction=direction,
+ address=address)
@staticmethod
def vpp_configures_classify_session_hex(node, acl_method, table_index,
- skip_n, match_n, hex_value):
+ skip_n, match_n, hex_value):
"""Configuration of classify session with hex value.
:param node: VPP node to setup classify session.
diff --git a/resources/libraries/python/DUTSetup.py b/resources/libraries/python/DUTSetup.py
index e2d183fe4e..e176dd704a 100644
--- a/resources/libraries/python/DUTSetup.py
+++ b/resources/libraries/python/DUTSetup.py
@@ -11,6 +11,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+"""DUT setup library."""
+
from robot.api import logger
from resources.libraries.python.topology import NodeType
@@ -20,6 +22,7 @@ from resources.libraries.python.VatExecutor import VatExecutor
class DUTSetup(object):
+ """Contains methods for setting up DUTs."""
@staticmethod
def start_vpp_service_on_all_duts(nodes):
"""Start up the VPP service on all nodes."""
@@ -29,7 +32,7 @@ class DUTSetup(object):
ssh.connect(node)
(ret_code, stdout, stderr) = \
ssh.exec_command_sudo('service vpp restart')
- if 0 != int(ret_code):
+ if int(ret_code) != 0:
logger.debug('stdout: {0}'.format(stdout))
logger.debug('stderr: {0}'.format(stderr))
raise Exception('DUT {0} failed to start VPP service'.
@@ -74,6 +77,13 @@ class DUTSetup(object):
@staticmethod
def setup_dut(node):
+ """Run script over SSH to setup the DUT node.
+
+ :param node: DUT node to set up.
+ :type node: dict
+
+ :raises Exception: If the DUT setup fails.
+ """
ssh = SSH()
ssh.connect(node)
@@ -82,7 +92,7 @@ class DUTSetup(object):
Constants.REMOTE_FW_DIR, Constants.RESOURCES_LIB_SH))
logger.trace(stdout)
logger.trace(stderr)
- if 0 != int(ret_code):
+ if int(ret_code) != 0:
logger.debug('DUT {0} setup script failed: "{1}"'.
format(node['host'], stdout + stderr))
raise Exception('DUT test setup script failed at node {}'.
diff --git a/resources/libraries/python/IPv4Setup.py b/resources/libraries/python/IPv4Setup.py
index d4be4c602a..07089025b0 100644
--- a/resources/libraries/python/IPv4Setup.py
+++ b/resources/libraries/python/IPv4Setup.py
@@ -34,6 +34,15 @@ class IPv4Node(object):
@staticmethod
def _get_netmask(prefix_length):
+ """Convert IPv4 network prefix length into IPV4 network mask.
+
+ :param prefix_length: Length of network prefix.
+ :type prefix_length: int
+
+ :return: Network mask.
+ :rtype: str
+ """
+
bits = 0xffffffff ^ (1 << 32 - prefix_length) - 1
return inet_ntoa(pack('>I', bits))
@@ -112,9 +121,25 @@ class Tg(IPv4Node):
super(Tg, self).__init__(node_info)
def _execute(self, cmd):
+ """Executes the specified command on TG using SSH.
+
+ :param cmd: Command to be executed.
+ :type cmd: str
+
+ :return: Content of stdout and stderr returned by command.
+ :rtype: tuple
+ """
return exec_cmd_no_error(self.node_info, cmd)
def _sudo_execute(self, cmd):
+ """Executes the specified command with sudo on TG using SSH.
+
+ :param cmd: Command to be executed.
+ :type cmd: str
+
+ :return: Content of stdout and stderr returned by command.
+ :rtype: tuple
+ """
return exec_cmd_no_error(self.node_info, cmd, sudo=True)
def set_ip(self, interface, address, prefix_length):
@@ -135,6 +160,13 @@ class Tg(IPv4Node):
format(network, prefix_length))
def arp_ping(self, destination_address, source_interface):
+ """Execute 'arping' command to send one ARP packet from the TG node.
+
+ :param destination_address: Destination IP address for the ARP packet.
+ :param source_interface: Name of an interface to send ARP packet from.
+ :type destination_address: str
+ :type source_interface: str
+ """
self._sudo_execute('arping -c 1 -I {} {}'.format(source_interface,
destination_address))
@@ -207,6 +239,7 @@ class Dut(IPv4Node):
sw_if_index=self.get_sw_if_index(interface))
def arp_ping(self, destination_address, source_interface):
+ """Does nothing."""
pass
def flush_ip_addresses(self, interface):
@@ -286,9 +319,9 @@ class IPv4Setup(object):
host = port.get('node')
dev = port.get('if')
if host == node['host'] and dev == interface:
- ip = port.get('addr')
- if ip is not None:
- return ip
+ ip_addr = port.get('addr')
+ if ip_addr is not None:
+ return ip_addr
else:
raise Exception(
'Node {n} port {p} IPv4 address is not set'.format(
diff --git a/resources/libraries/python/IPv4Util.py b/resources/libraries/python/IPv4Util.py
index ca5a1b571f..96572f5e1d 100644
--- a/resources/libraries/python/IPv4Util.py
+++ b/resources/libraries/python/IPv4Util.py
@@ -28,6 +28,15 @@ class IPv4Util(object):
@keyword('From node "${node}" interface "${port}" ARP-ping '
'IPv4 address "${ip_address}"')
def arp_ping(node, interface, ip_address):
+ """Send an ARP ping from the specified node.
+
+ :param node: Node in topology.
+ :param ip_address: Destination IP address for the ARP packet.
+ :param interface: Name of an interface to send the ARP packet from.
+ :type node: dict
+ :type ip_address: str
+ :type interface: str
+ """
log.debug('From node {} interface {} ARP-ping IPv4 address {}'.
format(Topology.get_node_hostname(node),
interface, ip_address))
@@ -89,8 +98,8 @@ class IPv4Util(object):
:rtype: int
"""
for net in nodes_addr.values():
- for p in net['ports'].values():
- if p['node'] == node['host'] and p['if'] == port:
+ for net_port in net['ports'].values():
+ if net_port['node'] == node['host'] and net_port['if'] == port:
return net['prefix']
raise Exception('Subnet not found for node {n} port {p}'.
@@ -112,8 +121,8 @@ class IPv4Util(object):
:rtype: str
"""
for net in nodes_addr.values():
- for p in net['ports'].values():
- if p['node'] == node['host'] and p['if'] == port:
+ for net_port in net['ports'].values():
+ if net_port['node'] == node['host'] and net_port['if'] == port:
return net['net_addr']
raise Exception('Subnet not found for node {n} port {p}'.
@@ -189,32 +198,32 @@ class IPv4Util(object):
interface, ping_count, destination)
else:
cmd = 'ping -c{0} {1}'.format(ping_count, destination)
- rc, stdout, stderr = exec_cmd(node, cmd, sudo=True)
- if rc != 0:
+ ret_code, _, _ = exec_cmd(node, cmd, sudo=True)
+ if ret_code != 0:
raise RuntimeError("Ping Not Successful")
@staticmethod
- def set_linux_interface_arp(node, interface, ip, mac, namespace=None):
+ def set_linux_interface_arp(node, interface, ip_addr, mac, namespace=None):
"""Set arp on interface in linux.
:param node: Node where to execute command.
:param interface: Interface in namespace.
- :param ip: IP for arp.
+ :param ip_addr: IP address for ARP entry.
:param mac: MAC address.
:param namespace: Execute command in namespace. Optional
:type node: dict
:type interface: str
- :type ip: str
+ :type ip_addr: str
:type mac: str
:type namespace: str
:raises RuntimeError: Could not set ARP properly.
"""
if namespace is not None:
cmd = 'ip netns exec {} arp -i {} -s {} {}'.format(
- namespace, interface, ip, mac)
+ namespace, interface, ip_addr, mac)
else:
- cmd = 'arp -i {} -s {} {}'.format(interface, ip, mac)
- rc, _, stderr = exec_cmd(node, cmd, sudo=True)
- if rc != 0:
+ cmd = 'arp -i {} -s {} {}'.format(interface, ip_addr, mac)
+ ret_code, _, stderr = exec_cmd(node, cmd, sudo=True)
+ if ret_code != 0:
raise RuntimeError("Arp set not successful, reason:{}".
format(stderr))
diff --git a/resources/libraries/python/IPv6Util.py b/resources/libraries/python/IPv6Util.py
index 54196ebf52..2a4704dff2 100644
--- a/resources/libraries/python/IPv6Util.py
+++ b/resources/libraries/python/IPv6Util.py
@@ -46,7 +46,7 @@ class IPv6Util(object):
cmd = "ping6 -c {c} -s {s} -W {W} {dst}".format(c=count, s=data_size,
W=timeout,
dst=dst_addr)
- (ret_code, stdout, _) = ssh.exec_command(cmd)
+ (_, stdout, _) = ssh.exec_command(cmd)
regex = re.compile(r'(\d+) packets transmitted, (\d+) received')
match = regex.search(stdout)
@@ -99,9 +99,9 @@ class IPv6Util(object):
host = port.get('node')
dev = port.get('if')
if host == node['host'] and dev == interface:
- ip = port.get('addr')
- if ip is not None:
- return ip
+ ip_addr = port.get('addr')
+ if ip_addr is not None:
+ return ip_addr
else:
raise Exception(
'Node {n} port {p} IPv6 address is not set'.format(
diff --git a/resources/libraries/python/LispSetup.py b/resources/libraries/python/LispSetup.py
index ee2ae5d8a3..99e3de8f74 100644
--- a/resources/libraries/python/LispSetup.py
+++ b/resources/libraries/python/LispSetup.py
@@ -103,6 +103,8 @@ class LispRemoteMapping(object):
seid=seid,
seid_prefix=seid_prefix,
rloc=rloc)
+
+
class LispAdjacency(object):
"""Class for lisp adjacency API."""
@@ -117,7 +119,7 @@ class LispAdjacency(object):
:param node: VPP node.
:param vni: Vni.
:param deid: Destination eid address.
- :param deid_predix: Destination eid address prefix_len.
+ :param deid_prefix: Destination eid address prefix_len.
:param seid: Source eid address.
:param seid_prefix: Source eid address prefix_len.
:type node: dict
@@ -144,7 +146,7 @@ class LispAdjacency(object):
:param node: VPP node.
:param vni: Vni.
:param deid: Destination eid address.
- :param deid_predix: Destination eid address prefix_len.
+ :param deid_prefix: Destination eid address prefix_len.
:param seid: Source eid address.
:param seid_prefix: Source eid address prefix_len.
:type node: dict
@@ -216,11 +218,13 @@ class LispGpeForwardEntry(object):
@staticmethod
def add_lisp_gpe_forward_entry(node, *args):
+ """Not implemented"""
# TODO: Implement when VPP-334 is fixed.
pass
@staticmethod
def del_lisp_gpe_forward_entry(node, *args):
+ """Not implemented"""
# TODO: Implement when VPP-334 is fixed.
pass
diff --git a/resources/libraries/python/Namespaces.py b/resources/libraries/python/Namespaces.py
index d92dfd7e26..00d615350e 100644
--- a/resources/libraries/python/Namespaces.py
+++ b/resources/libraries/python/Namespaces.py
@@ -13,7 +13,7 @@
"""Linux namespace utilities library."""
-from resources.libraries.python.ssh import exec_cmd_no_error, exec_cmd, SSH
+from resources.libraries.python.ssh import exec_cmd_no_error, exec_cmd
class Namespaces(object):
@@ -46,14 +46,14 @@ class Namespaces(object):
:raises RuntimeError: Interface could not be attached.
"""
cmd = 'ip link set {0} netns {1}'.format(interface, namespace)
- (rc, _, stderr) = exec_cmd(node, cmd, timeout=5, sudo=True)
- if rc != 0:
+ (ret_code, _, stderr) = exec_cmd(node, cmd, timeout=5, sudo=True)
+ if ret_code != 0:
raise RuntimeError(
'Could not attach interface, reason:{}'.format(stderr))
cmd = 'ip netns exec {} ip link set {} up'.format(
namespace, interface)
- (rc, _, stderr) = exec_cmd(node, cmd, timeout=5, sudo=True)
- if rc != 0:
+ (ret_code, _, stderr) = exec_cmd(node, cmd, timeout=5, sudo=True)
+ if ret_code != 0:
raise RuntimeError(
'Could not set interface state, reason:{}'.format(stderr))
@@ -91,6 +91,6 @@ class Namespaces(object):
for namespace in self._namespaces:
print "Cleaning namespace {}".format(namespace)
cmd = 'ip netns delete {}'.format(namespace)
- (rc, stdout, stderr) = exec_cmd(node, cmd, timeout=5, sudo=True)
- if rc != 0:
+ (ret_code, _, _) = exec_cmd(node, cmd, timeout=5, sudo=True)
+ if ret_code != 0:
raise RuntimeError('Could not delete namespace')
diff --git a/resources/libraries/python/PacketVerifier.py b/resources/libraries/python/PacketVerifier.py
index 59ea2db5a3..bbfdfe8688 100644
--- a/resources/libraries/python/PacketVerifier.py
+++ b/resources/libraries/python/PacketVerifier.py
@@ -68,7 +68,7 @@ import socket
import select
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.all import Ether, ARP
from scapy.layers.inet6 import IPv6
__all__ = ['RxQueue', 'TxQueue', 'Interface', 'create_gratuitous_arp_request',
@@ -276,17 +276,32 @@ class TxQueue(PacketVerifier):
class Interface(object):
+ """Class for network interfaces. Contains methods for sending and receiving
+ packets."""
def __init__(self, if_name):
+ """Initialize the interface class.
+
+ :param if_name: Name of the interface.
+ :type if_name: str
+ """
self.if_name = if_name
self.sent_packets = []
self.rxq = RxQueue(if_name)
self.txq = TxQueue(if_name)
def send_pkt(self, pkt):
+ """Send the provided packet out the interface."""
self.sent_packets.append(pkt)
self.txq.send(pkt)
def recv_pkt(self, timeout=3):
+ """Read one packet from the interface's receive queue.
+
+ :param timeout: Timeout value in seconds.
+ :type timeout: int
+ :return: Ether() initialized object from packet data.
+ :rtype: scapy.Ether
+ """
return self.rxq.recv(timeout, self.sent_packets)
diff --git a/resources/libraries/python/QemuUtils.py b/resources/libraries/python/QemuUtils.py
index bc854350dd..aa149da185 100644
--- a/resources/libraries/python/QemuUtils.py
+++ b/resources/libraries/python/QemuUtils.py
@@ -215,10 +215,10 @@ class QemuUtils(object):
'{ \\"execute\\": \\"' + cmd + '\\" }" | sudo -S nc -U ' + \
self.__QMP_SOCK
(ret_code, stdout, stderr) = self._ssh.exec_command(qmp_cmd)
- if 0 != int(ret_code):
+ if int(ret_code) != 0:
logger.debug('QMP execute failed {0}'.format(stderr))
- raise RuntimeError('QMP execute "{0}" failed on {1}'.format(cmd,
- self._node['host']))
+ raise RuntimeError('QMP execute "{0}"'
+ ' failed on {1}'.format(cmd, self._node['host']))
logger.trace(stdout)
# Skip capabilities negotiation messages.
out_list = stdout.splitlines()
@@ -233,10 +233,10 @@ class QemuUtils(object):
qga_cmd = 'printf "\xFF" | sudo -S nc ' \
'-q 1 -U ' + self.__QGA_SOCK
(ret_code, stdout, stderr) = self._ssh.exec_command(qga_cmd)
- if 0 != int(ret_code):
+ if int(ret_code) != 0:
logger.debug('QGA execute failed {0}'.format(stderr))
- raise RuntimeError('QGA execute "{0}" failed on {1}'.format(cmd,
- self._node['host']))
+ raise RuntimeError('QGA execute "{0}" '
+ 'failed on {1}'.format(cmd, self._node['host']))
logger.trace(stdout)
if not stdout:
return {}
@@ -253,10 +253,10 @@ class QemuUtils(object):
qga_cmd = 'echo "{ \\"execute\\": \\"' + cmd + '\\" }" | sudo -S nc ' \
'-q 1 -U ' + self.__QGA_SOCK
(ret_code, stdout, stderr) = self._ssh.exec_command(qga_cmd)
- if 0 != int(ret_code):
+ if int(ret_code) != 0:
logger.debug('QGA execute failed {0}'.format(stderr))
- raise RuntimeError('QGA execute "{0}" failed on {1}'.format(cmd,
- self._node['host']))
+ raise RuntimeError('QGA execute "{0}"'
+ ' failed on {1}'.format(cmd, self._node['host']))
logger.trace(stdout)
if not stdout:
return {}
@@ -353,8 +353,10 @@ class QemuUtils(object):
self._node['host']))
# If we do not want to allocate dynamicaly end with error
else:
- raise RuntimeError('Not enough free huge pages: {0}, '
- '{1} MB'.format(huge_free, huge_free * huge_size))
+ raise RuntimeError(
+ 'Not enough free huge pages: {0}, '
+ '{1} MB'.format(huge_free, huge_free * huge_size)
+ )
# Check if huge pages mount point exist
has_huge_mnt = False
(_, output, _) = self._ssh.exec_command('cat /proc/mounts')
@@ -395,7 +397,7 @@ class QemuUtils(object):
# Memory and huge pages
mem = '-object memory-backend-file,id=mem,size={0}M,mem-path={1},' \
'share=on -m {0} -numa node,memdev=mem'.format(
- self._qemu_opt.get('mem_size'), self._qemu_opt.get('huge_mnt'))
+ self._qemu_opt.get('mem_size'), self._qemu_opt.get('huge_mnt'))
# By default check only if hugepages are availbale.
# If 'huge_allocate' is set to true try to allocate as well.
@@ -406,7 +408,7 @@ class QemuUtils(object):
# Setup serial console
serial = '-chardev socket,host=127.0.0.1,port={0},id=gnc0,server,' \
'nowait -device isa-serial,chardev=gnc0'.format(
- self._qemu_opt.get('serial_port'))
+ self._qemu_opt.get('serial_port'))
# Setup QGA via chardev (unix socket) and isa-serial channel
qga = '-chardev socket,path=/tmp/qga.sock,server,nowait,id=qga0 ' \
'-device isa-serial,chardev=qga0'
@@ -443,15 +445,18 @@ class QemuUtils(object):
out = self._qemu_qmp_exec('system_powerdown')
err = out.get('error')
if err is not None:
- raise RuntimeError('QEMU system powerdown failed on {0}, '
- 'error: {1}'.format(self._node['host'], json.dumps(err)))
+ raise RuntimeError(
+ 'QEMU system powerdown failed on {0}, '
+ 'error: {1}'.format(self._node['host'], json.dumps(err))
+ )
def qemu_system_reset(self):
"""Reset the system."""
out = self._qemu_qmp_exec('system_reset')
err = out.get('error')
if err is not None:
- raise RuntimeError('QEMU system reset failed on {0}, '
+ raise RuntimeError(
+ 'QEMU system reset failed on {0}, '
'error: {1}'.format(self._node['host'], json.dumps(err)))
def qemu_kill(self):
@@ -501,7 +506,8 @@ class QemuUtils(object):
return ret.get('status')
else:
err = out.get('error')
- raise RuntimeError('QEMU query-status failed on {0}, '
+ raise RuntimeError(
+ 'QEMU query-status failed on {0}, '
'error: {1}'.format(self._node['host'], json.dumps(err)))
@staticmethod
@@ -518,6 +524,6 @@ class QemuUtils(object):
ssh.exec_command('sudo -Sn bash {0}/{1}/qemu_build.sh'.format(
Constants.REMOTE_FW_DIR, Constants.RESOURCES_LIB_SH), 1000)
logger.trace(stdout)
- if 0 != int(ret_code):
+ if int(ret_code) != 0:
logger.debug('QEMU build failed {0}'.format(stderr))
raise RuntimeError('QEMU build failed on {0}'.format(node['host']))
diff --git a/resources/libraries/python/Routing.py b/resources/libraries/python/Routing.py
index fbe7b60183..ff675f39a9 100644
--- a/resources/libraries/python/Routing.py
+++ b/resources/libraries/python/Routing.py
@@ -17,10 +17,12 @@ from resources.libraries.python.VatExecutor import VatTerminal
from resources.libraries.python.topology import Topology
from resources.libraries.python.ssh import exec_cmd_no_error
+
class Routing(object):
"""Routing utilities."""
+ # pylint: disable=too-many-arguments
@staticmethod
def vpp_route_add(node, network, prefix_len, gateway=None,
interface=None, use_sw_index=True, resolve_attempts=10,
@@ -101,23 +103,23 @@ class Routing(object):
where=place)
@staticmethod
- def add_route(node, ip, prefix, gw, namespace=None):
+ def add_route(node, ip_addr, prefix, gateway, namespace=None):
"""Add route in namespace.
:param node: Node where to execute command.
- :param ip: Route destination IP.
+ :param ip_addr: Route destination IP address.
:param prefix: IP prefix.
- :param namespace: Execute command in namespace. Optional
- :param gw: Gateway.
+ :param namespace: Execute command in namespace. Optional.
+ :param gateway: Gateway address.
:type node: dict
- :type ip: str
+ :type ip_addr: str
:type prefix: int
- :type gw: str
+ :type gateway: str
:type namespace: str
"""
if namespace is not None:
cmd = 'ip netns exec {} ip route add {}/{} via {}'.format(
- namespace, ip, prefix, gw)
+ namespace, ip_addr, prefix, gateway)
else:
- cmd = 'ip route add {}/{} via {}'.format(ip, prefix, gw)
+ cmd = 'ip route add {}/{} via {}'.format(ip_addr, prefix, gateway)
exec_cmd_no_error(node, cmd, sudo=True)
diff --git a/resources/libraries/python/SetupFramework.py b/resources/libraries/python/SetupFramework.py
index 1a1e991b3b..d0059ebed8 100644
--- a/resources/libraries/python/SetupFramework.py
+++ b/resources/libraries/python/SetupFramework.py
@@ -58,7 +58,7 @@ def pack_framework_dir():
logger.debug(stderr)
return_code = proc.wait()
- if 0 != return_code:
+ if return_code != 0:
raise Exception("Could not pack testing framework.")
return file_name
@@ -99,7 +99,7 @@ def extract_tarball_at_node(tarball, node):
cmd = 'sudo rm -rf {1}; mkdir {1} ; tar -zxf {0} -C {1}; ' \
'rm -f {0}'.format(tarball, con.REMOTE_FW_DIR)
(ret_code, _, stderr) = ssh.exec_command(cmd, timeout=30)
- if 0 != ret_code:
+ if ret_code != 0:
logger.error('Unpack error: {0}'.format(stderr))
raise Exception('Failed to unpack {0} at node {1}'.format(
tarball, node['host']))
@@ -116,7 +116,7 @@ def create_env_directory_at_node(node):
'. env/bin/activate && '
'pip install -r requirements.txt'
.format(con.REMOTE_FW_DIR), timeout=100)
- if 0 != ret_code:
+ if ret_code != 0:
logger.error('Virtualenv creation error: {0}'.format(stdout + stderr))
raise Exception('Virtualenv setup failed')
else:
diff --git a/resources/libraries/python/VatExecutor.py b/resources/libraries/python/VatExecutor.py
index a0f9634d8c..03b7321020 100644
--- a/resources/libraries/python/VatExecutor.py
+++ b/resources/libraries/python/VatExecutor.py
@@ -11,6 +11,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+"""VAT executor library."""
+
import json
from robot.api import logger
@@ -39,6 +41,7 @@ def cleanup_vat_json_output(json_output):
class VatExecutor(object):
+ """Contains methods for executing VAT commands on DUTs."""
def __init__(self):
self._stdout = None
self._stderr = None
@@ -62,7 +65,7 @@ class VatExecutor(object):
Constants.RESOURCES_TPL_VAT,
vat_name)
# TODO this overwrites the output if the vat script has been used twice
- remote_file_out = remote_file_path + ".out"
+ # remote_file_out = remote_file_path + ".out"
cmd = "sudo -S {vat} {json} < {input}".format(
vat=Constants.VAT_BIN_NAME,
@@ -81,17 +84,29 @@ class VatExecutor(object):
# self._delete_files(node, remote_file_path, remote_file_out)
def execute_script_json_out(self, vat_name, node, timeout=10):
+ """Pass all arguments to 'execute_script' method, then cleanup returned
+ json output."""
self.execute_script(vat_name, node, timeout, json_out=True)
self._stdout = cleanup_vat_json_output(self._stdout)
@staticmethod
def _delete_files(node, *files):
+ """Use SSH to delete the specified files on node.
+
+ :param node: Node in topology.
+ :param files: Files to delete.
+ :type node: dict
+ :type files: iterable
+ """
+
ssh = SSH()
ssh.connect(node)
files = " ".join([str(x) for x in files])
ssh.exec_command("rm {0}".format(files))
def script_should_have_failed(self):
+ """Read return code from last executed script and raise exception if the
+ script didn't fail."""
if self._ret_code is None:
raise Exception("First execute the script!")
if self._ret_code == 0:
@@ -99,6 +114,8 @@ class VatExecutor(object):
"Script execution passed, but failure was expected")
def script_should_have_passed(self):
+ """Read return code from last executed script and raise exception if the
+ script failed."""
if self._ret_code is None:
raise Exception("First execute the script!")
if self._ret_code != 0:
@@ -106,9 +123,11 @@ class VatExecutor(object):
"Script execution failed, but success was expected")
def get_script_stdout(self):
+ """Returns value of stdout from last executed script."""
return self._stdout
def get_script_stderr(self):
+ """Returns value of stderr from last executed script."""
return self._stderr
@staticmethod
diff --git a/resources/libraries/python/VatJsonUtil.py b/resources/libraries/python/VatJsonUtil.py
index 1cafff0d27..6445d8c387 100644
--- a/resources/libraries/python/VatJsonUtil.py
+++ b/resources/libraries/python/VatJsonUtil.py
@@ -173,7 +173,7 @@ class VatJsonUtil(object):
:type err_msg: str
:raises RuntimeError: If VAT command return value is incorrect.
"""
- if type(vat_out) is dict:
+ if isinstance(vat_out, dict):
retval = vat_out.get('retval')
if retval is not None:
if retval != exp_retval:
diff --git a/resources/libraries/python/ssh.py b/resources/libraries/python/ssh.py
index b470e86ccc..287ad31d65 100644
--- a/resources/libraries/python/ssh.py
+++ b/resources/libraries/python/ssh.py
@@ -11,6 +11,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+"""Library for SSH connection management."""
+
import StringIO
from time import time, sleep
@@ -19,7 +21,7 @@ import paramiko
from paramiko import RSAKey
from paramiko.ssh_exception import SSHException
from scp import SCPClient
-from interruptingcow import timeout
+from interruptingcow import timeout as icTimeout
from robot.api import logger
from robot.utils.asserts import assert_equal
@@ -29,6 +31,7 @@ __all__ = ["exec_cmd", "exec_cmd_no_error"]
class SSH(object):
+ """Contains methods for managing and using SSH connections."""
__MAX_RECV_BUF = 10*1024*1024
__existing_connections = {}
@@ -39,6 +42,14 @@ class SSH(object):
@staticmethod
def _node_hash(node):
+ """Get IP address and port hash from node dictionary.
+
+ :param node: Node in topology.
+ :type node: dict
+ :return: IP address and port for the specified node.
+ :rtype: int
+ """
+
return hash(frozenset([node['host'], node['port']]))
def connect(self, node):
@@ -56,7 +67,7 @@ class SSH(object):
pkey = None
if 'priv_key' in node:
pkey = RSAKey.from_private_key(
- StringIO.StringIO(node['priv_key']))
+ StringIO.StringIO(node['priv_key']))
self._ssh = paramiko.SSHClient()
self._ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
@@ -90,6 +101,8 @@ class SSH(object):
ssh.close()
def _reconnect(self):
+ """Close the SSH connection and open it again."""
+
node = self._node
self.disconnect(node)
self.connect(node)
@@ -100,8 +113,8 @@ class SSH(object):
"""Execute SSH command on a new channel on the connected Node.
:param cmd: Command to run on the Node.
- :param timeout: Maximal time in seconds to wait while the command is
- done. If is None then wait forever.
+ :param timeout: Maximal time in seconds to wait until the command is
+ done. If set to None then wait forever.
:type cmd: str
:type timeout: int
:return return_code, stdout, stderr
@@ -203,7 +216,7 @@ class SSH(object):
buf = ''
try:
- with timeout(time_out, exception=RuntimeError):
+ with icTimeout(time_out, exception=RuntimeError):
while not buf.endswith(':~$ '):
if chan.recv_ready():
buf = chan.recv(4096)
@@ -235,7 +248,7 @@ class SSH(object):
chan.sendall('{c}\n'.format(c=cmd))
buf = ''
try:
- with timeout(time_out, exception=RuntimeError):
+ with icTimeout(time_out, exception=RuntimeError):
while not buf.endswith(prompt):
if chan.recv_ready():
buf += chan.recv(4096)
@@ -283,8 +296,8 @@ def exec_cmd(node, cmd, timeout=600, sudo=False):
ssh = SSH()
try:
ssh.connect(node)
- except Exception, e:
- logger.error("Failed to connect to node" + str(e))
+ except Exception as err:
+ logger.error("Failed to connect to node" + str(err))
return None, None, None
try:
@@ -293,8 +306,8 @@ def exec_cmd(node, cmd, timeout=600, sudo=False):
else:
(ret_code, stdout, stderr) = ssh.exec_command_sudo(cmd,
timeout=timeout)
- except Exception, e:
- logger.error(e)
+ except Exception as err:
+ logger.error(err)
return None, None, None
return ret_code, stdout, stderr
@@ -307,7 +320,7 @@ def exec_cmd_no_error(node, cmd, timeout=600, sudo=False):
Returns (stdout, stderr).
"""
- (rc, stdout, stderr) = exec_cmd(node, cmd, timeout=timeout, sudo=sudo)
- assert_equal(rc, 0, 'Command execution failed: "{}"\n{}'.
+ (ret_code, stdout, stderr) = exec_cmd(node, cmd, timeout=timeout, sudo=sudo)
+ assert_equal(ret_code, 0, 'Command execution failed: "{}"\n{}'.
format(cmd, stderr))
return stdout, stderr
diff --git a/resources/libraries/python/topology.py b/resources/libraries/python/topology.py
index c02991fbde..02f326a1df 100644
--- a/resources/libraries/python/topology.py
+++ b/resources/libraries/python/topology.py
@@ -34,6 +34,7 @@ def load_topo_from_yaml():
with open(topo_path) as work_file:
return load(work_file.read())['nodes']
+
# pylint: disable=invalid-name
class NodeType(object):
"""Defines node types used in topology dictionaries."""
@@ -46,6 +47,7 @@ class NodeType(object):
class NodeSubTypeTG(object):
+ """Defines node sub-type TG - traffic generator."""
# T-Rex traffic generator
TREX = 'TREX'
# Moongen
diff --git a/resources/tools/topology/update_topology.py b/resources/tools/topology/update_topology.py
index a5711d0922..f60fdf1653 100755
--- a/resources/tools/topology/update_topology.py
+++ b/resources/tools/topology/update_topology.py
@@ -59,7 +59,7 @@ def ssh_no_error(ssh, cmd):
:rtype: str
"""
ret, stdo, stde = ssh.exec_command(cmd)
- if 0 != ret:
+ if ret != 0:
print 'Command execution failed: "{}"'.format(cmd)
print 'stdout: {0}'.format(stdo)
print 'stderr: {0}'.format(stde)