[lnst] example_recipes/jpirko_test: add nic
by Jiří Pírko
commit 6d6d8610ea54ae86728e4158c5adb0139b7d5dbf
Author: Jiri Pirko <jpirko(a)redhat.com>
Date: Thu Jun 30 14:14:49 2011 +0200
example_recipes/jpirko_test: add nic
Signed-off-by: Jiri Pirko <jpirko(a)redhat.com>
.../jpirko_test/machine_configs/config-junkbox.xml | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
---
diff --git a/example_recipes/jpirko_test/machine_configs/config-junkbox.xml b/example_recipes/jpirko_test/machine_configs/config-junkbox.xml
index 8a5ce90..d2f658e 100644
--- a/example_recipes/jpirko_test/machine_configs/config-junkbox.xml
+++ b/example_recipes/jpirko_test/machine_configs/config-junkbox.xml
@@ -1,4 +1,5 @@
<netmachineconfig>
<info hostname="junkbox.lab.eng.brq.redhat.com"/>
<netdevice type="eth" phys_id="1" hwaddr="00:10:18:61:35:9B"/>
+ <netdevice type="eth" phys_id="2" hwaddr="00:10:18:48:15:FA"/>
</netmachineconfig>
12 years, 5 months
[lnst] NetTest: introduce result XML serialization
by Jiří Pírko
commit 28f087c9ed39f0813ed9ef0e6e2783b9bb14da98
Author: Jiri Pirko <jpirko(a)redhat.com>
Date: Thu Jun 30 14:05:52 2011 +0200
NetTest: introduce result XML serialization
Signed-off-by: Jiri Pirko <jpirko(a)redhat.com>
NetTest/NetTestCommand.py | 6 +-
NetTest/NetTestController.py | 8 +++-
NetTest/NetTestResultSerializer.py | 75 ++++++++++++++++++++++++++++++++++++
nettestctl.py | 31 +++++++++++----
4 files changed, 107 insertions(+), 13 deletions(-)
---
diff --git a/NetTest/NetTestCommand.py b/NetTest/NetTestCommand.py
index a6dca5b..0c9bc54 100644
--- a/NetTest/NetTestCommand.py
+++ b/NetTest/NetTestCommand.py
@@ -19,12 +19,12 @@ import pickle, traceback
from Common.ExecCmd import exec_cmd, ExecCmdFail
def str_command(command):
- out = ("type \"%s\", machine_id \"%d\", value \"%s\""
+ out = ("type (%s), machine_id (%d), value (%s)"
% (command["type"], command["machine_id"], command["value"]))
if "timeout" in command:
- out += ", timeout \"%d\"" % command["timeout"]
+ out += ", timeout (%d)" % command["timeout"]
if "bg_id" in command:
- out += ", bg_id \"%d\"" % command["bg_id"]
+ out += ", bg_id (%d)" % command["bg_id"]
return out
class CommandException(Exception):
diff --git a/NetTest/NetTestController.py b/NetTest/NetTestController.py
index 7161fd7..b0480e4 100644
--- a/NetTest/NetTestController.py
+++ b/NetTest/NetTestController.py
@@ -1,5 +1,5 @@
"""
-This module defines NetConfigController class which does the controlling
+This module defines NetTestController class which does the controlling
part of network testing.
Copyright 2011 Red Hat, Inc.
@@ -23,13 +23,15 @@ from NetTestCommand import NetTestCommand, str_command
from Common.LoggingServer import LoggingServer
class NetTestController:
- def __init__(self, recipe_path, remoteexec=False, cleanup=False):
+ def __init__(self, recipe_path, remoteexec=False, cleanup=False,
+ res_serializer=None):
ntparse = NetTestParse(recipe_path)
ntparse.parse_recipe()
self._recipe = ntparse.get_recipe()
self._ntparse = ntparse
self._remoteexec = remoteexec
self._docleanup = cleanup
+ self._res_serializer = res_serializer
def _get_machineinfo(self, machine_id):
return self._recipe["machines"][machine_id]["info"]
@@ -162,6 +164,8 @@ class NetTestController:
for command in sequence:
logging.info("Executing command: [%s]" % str_command(command))
cmd_res = self._run_command(command)
+ if self._res_serializer:
+ self._res_serializer.add_cmd_result(command, cmd_res)
logging.debug("Result: %s" % str(cmd_res))
if "res_data" in cmd_res:
res_data = pformat(cmd_res["res_data"])
diff --git a/NetTest/NetTestResultSerializer.py b/NetTest/NetTestResultSerializer.py
new file mode 100644
index 0000000..c5e7d1a
--- /dev/null
+++ b/NetTest/NetTestResultSerializer.py
@@ -0,0 +1,75 @@
+"""
+This module defines NetTestResultSerializer class which serves for serializing
+results of command sequence to XML
+
+Copyright 2011 Red Hat, Inc.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jpirko(a)redhat.com (Jiri Pirko)
+"""
+
+from NetTestCommand import str_command
+from xml.dom.minidom import getDOMImplementation
+
+def serialize_obj(obj, dom, el, upper_name="unnamed"):
+ if isinstance(obj, dict):
+ for key in obj:
+ new_el = dom.createElement(key)
+ el.appendChild(new_el)
+ serialize_obj(obj[key], dom, new_el, upper_name=key)
+ elif isinstance(obj, list):
+ for one in obj:
+ new_el = dom.createElement("%s_item" % upper_name)
+ el.appendChild(new_el)
+ serialize_obj(one, dom, new_el)
+ else:
+ text = dom.createTextNode(str(obj))
+ el.appendChild(text)
+
+class NetTestResultSerializer:
+ def __init__(self):
+ impl = getDOMImplementation()
+ self._dom = impl.createDocument(None, "results", None)
+ self._top_el = self._dom.documentElement
+ self._cur_recipe_el = None
+
+ def __str__(self):
+ return self._dom.toprettyxml()
+
+ def add_recipe(self, name):
+ recipe_el = self._dom.createElement("recipe")
+ recipe_el.setAttribute("name", name)
+ self._top_el.appendChild(recipe_el)
+ self._cur_recipe_el = recipe_el
+
+ def add_cmd_result(self, command, cmd_res):
+ command_el = self._dom.createElement("command")
+ self._cur_recipe_el.appendChild(command_el)
+
+ for key in command:
+ if key == "options":
+ continue
+ command_el.setAttribute(key, str(command[key]))
+
+ result_el = self._dom.createElement("result")
+ command_el.appendChild(result_el)
+
+ if cmd_res["passed"]:
+ res = "PASS"
+ else:
+ res = "FAIL"
+ result_el.setAttribute("result", res)
+
+ if "err_msg" in cmd_res:
+ err_el = self._dom.createElement("error_message")
+ err_text = self._dom.createTextNode(cmd_res["err_msg"])
+ err_el.appendChild(err_text)
+ result_el.appendChild(err_el)
+
+ if "res_data" in cmd_res:
+ res_data_el = self._dom.createElement("result_data")
+ serialize_obj(cmd_res["res_data"], self._dom, res_data_el)
+ command_el.appendChild(res_data_el)
diff --git a/nettestctl.py b/nettestctl.py
index 1d49f37..614f2fc 100755
--- a/nettestctl.py
+++ b/nettestctl.py
@@ -17,6 +17,7 @@ import logging
import os
import re
from NetTest.NetTestController import NetTestController
+from NetTest.NetTestResultSerializer import NetTestResultSerializer
from Common.Logs import Logs
from Common.LoggingServer import LoggingServer
import Common.ProcessManager
@@ -37,11 +38,13 @@ def usage():
" application on slaves"
print " -c, --cleanup perform config cleanup\n" \
" machines"
+ print " -x, --result=FILE file to write xml_result"
sys.exit()
-def process_recipe(args, file_path, remoteexec, cleanup):
+def process_recipe(args, file_path, remoteexec, cleanup, res_serializer):
nettestctl = NetTestController(os.path.realpath(file_path),
- remoteexec=remoteexec, cleanup=cleanup)
+ remoteexec=remoteexec, cleanup=cleanup,
+ res_serializer=res_serializer)
action = args[0]
if action == "run":
return nettestctl.run_recipe()
@@ -70,11 +73,12 @@ def print_summary(summary):
logging.info("*%s* %s" % (res, recipe_file))
logging.info("=====================================================")
-def get_recipe_result(args, file_path, remoteexec, cleanup):
+def get_recipe_result(args, file_path, remoteexec, cleanup, res_serializer):
+ res_serializer.add_recipe(file_path)
Logs.set_logging_root_path(file_path)
loggingServer = LoggingServer(LoggingServer.DEFAULT_PORT, Logs.root_path, Logs.debug)
loggingServer.start()
- res = process_recipe(args, file_path, remoteexec, cleanup)
+ res = process_recipe(args, file_path, remoteexec, cleanup, res_serializer)
loggingServer.stop()
return ((file_path, res))
@@ -85,8 +89,8 @@ def main():
try:
opts, args = getopt.getopt(
sys.argv[1:],
- "dhr:ec",
- ["debug", "help", "recipe=", "remoteexec", "cleanup"]
+ "dhr:ecx:",
+ ["debug", "help", "recipe=", "remoteexec", "cleanup", "result"]
)
except getopt.GetoptError, err:
print str(err)
@@ -97,6 +101,7 @@ def main():
recipe_path = None
remoteexec = False
cleanup = False
+ result_path = None
for opt, arg in opts:
if opt in ("-d", "--debug"):
debug += 1
@@ -108,6 +113,8 @@ def main():
remoteexec = True
elif opt in ("-c", "--cleanup"):
cleanup = True
+ elif opt in ("-x", "--result"):
+ result_path = arg
Logs(debug)
@@ -121,6 +128,7 @@ def main():
summary = []
+ res_serializer = NetTestResultSerializer()
if os.path.isdir(recipe_path):
all_files = []
for root, dirs, files in os.walk(recipe_path):
@@ -133,13 +141,20 @@ def main():
if re.match(r'^.*\.xml$', recipe_file):
logging.info("Processing recipe file \"%s\"" % recipe_file)
summary.append(get_recipe_result(args, recipe_file,
- remoteexec, cleanup))
+ remoteexec, cleanup,
+ res_serializer))
else:
summary.append(get_recipe_result(args, recipe_path,
- remoteexec, cleanup))
+ remoteexec, cleanup, res_serializer))
Logs.set_logging_root_path(clean=False)
print_summary(summary)
+ if result_path:
+ result_path = os.path.expanduser(result_path)
+ handle = open(result_path, "w")
+ handle.write(str(res_serializer))
+ handle.close()
+
if __name__ == "__main__":
main()
12 years, 5 months
[lnst] TestIcmpPing: pass result rate in result data
by Jiří Pírko
commit 0b8c477de528a182ede3223870dbf187e305560a
Author: Jiri Pirko <jpirko(a)redhat.com>
Date: Thu Jun 30 10:26:36 2011 +0200
TestIcmpPing: pass result rate in result data
Signed-off-by: Jiri Pirko <jpirko(a)redhat.com>
Tests/TestIcmpPing.py | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
---
diff --git a/Tests/TestIcmpPing.py b/Tests/TestIcmpPing.py
index f806fe7..5b6b3ea 100644
--- a/Tests/TestIcmpPing.py
+++ b/Tests/TestIcmpPing.py
@@ -52,6 +52,6 @@ class TestIcmpPing(TestGeneric):
"mdev \"%.3f\"" % (tmin, tavg, tmax, tmdev))
if rate < limit_rate:
- return self.set_fail("rate is lower that limit")
+ return self.set_fail("rate is lower that limit", res_data={"rate": rate})
- return self.set_pass()
+ return self.set_pass(res_data={"rate": rate})
12 years, 5 months
[lnst] NetTestController: print command result data if any
by Jiří Pírko
commit 134c4da1b3591f606ca4a0c635e67ccd49f241ec
Author: Jiri Pirko <jpirko(a)redhat.com>
Date: Thu Jun 30 10:25:52 2011 +0200
NetTestController: print command result data if any
Signed-off-by: Jiri Pirko <jpirko(a)redhat.com>
NetTest/NetTestController.py | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
---
diff --git a/NetTest/NetTestController.py b/NetTest/NetTestController.py
index b0b2437..7161fd7 100644
--- a/NetTest/NetTestController.py
+++ b/NetTest/NetTestController.py
@@ -13,7 +13,7 @@ jpirko(a)redhat.com (Jiri Pirko)
import logging
import socket
-from pprint import pprint
+from pprint import pprint, pformat
from Common.XmlRpc import ServerProxy
from NetTestParse import NetTestParse
from Common.SlaveUtils import prepare_client_session
@@ -163,6 +163,9 @@ class NetTestController:
logging.info("Executing command: [%s]" % str_command(command))
cmd_res = self._run_command(command)
logging.debug("Result: %s" % str(cmd_res))
+ if "res_data" in cmd_res:
+ res_data = pformat(cmd_res["res_data"])
+ logging.info("Result data: %s" % (res_data))
if not cmd_res["passed"]:
logging.error("Command failed - command: [%s], "
"Error message: \"%s\""
12 years, 5 months
[lnst] TestDummyFailing: remove constructor
by Jiří Pírko
commit 75f38f85bdb82c461918db7daef02f72932aa562
Author: Jiri Pirko <jpirko(a)redhat.com>
Date: Thu Jun 30 10:10:16 2011 +0200
TestDummyFailing: remove constructor
Did nothing, only caused a traceback. So remove it so superior
constructor can be called.
Signed-off-by: Jiri Pirko <jpirko(a)redhat.com>
Tests/TestDummyFailing.py | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)
---
diff --git a/Tests/TestDummyFailing.py b/Tests/TestDummyFailing.py
index d7a47f5..4ccce56 100644
--- a/Tests/TestDummyFailing.py
+++ b/Tests/TestDummyFailing.py
@@ -14,8 +14,5 @@ import logging
from Common.TestsCommon import TestGeneric
class TestDummyFailing(TestGeneric):
- def __init__(self, command):
- pass
-
def run(self):
return self.set_fail("what else did you expect?")
12 years, 5 months
[lnst] TestPktgenTx: add multi-dev multi-thread support
by Jiří Pírko
commit e91b935a75b8e92052441b553dc19d223061385f
Author: Jiri Pirko <jpirko(a)redhat.com>
Date: Wed Jun 29 17:33:08 2011 +0200
TestPktgenTx: add multi-dev multi-thread support
Signed-off-by: Jiri Pirko <jpirko(a)redhat.com>
Tests/TestPktgenTx.py | 54 +++++++++++++++++++++++++++++++++++++-----------
1 files changed, 41 insertions(+), 13 deletions(-)
---
diff --git a/Tests/TestPktgenTx.py b/Tests/TestPktgenTx.py
index 5d68062..5e48f2c 100644
--- a/Tests/TestPktgenTx.py
+++ b/Tests/TestPktgenTx.py
@@ -12,6 +12,7 @@ jpirko(a)redhat.com (Jiri Pirko)
import logging
import re
+import os
from Common.TestsCommon import TestGeneric
from Common.ExecCmd import exec_cmd, ExecCmdFail
@@ -22,9 +23,37 @@ class Pktgen:
def set(self, val):
exec_cmd("echo \"%s\" > %s" % (val, self._dev))
+class PktgenWorkers:
+ def __init__(self):
+ self._current = 0
+ self._cpunum = int(os.sysconf('SC_NPROCESSORS_ONLN'))
+ self._wrkrs = {}
+
+ def _init_current_wrkr(self):
+ num = self._current
+ wrkr = Pktgen("/proc/net/pktgen/kpktgend_%d" % (num))
+ wrkr.set("rem_device_all")
+ wrkr.set("max_before_softirq 5000")
+ self._wrkrs[num] = wrkr
+
+ def _get_wrkr(self):
+ num = self._current
+ if not num in self._wrkrs:
+ self._init_current_wrkr()
+ wrkr = self._wrkrs[num]
+ num += 1
+ if num == self._cpunum:
+ num = 0
+ self._current = num
+ return wrkr
+
+ def add_device(self, dev_name):
+ wrkr = self._get_wrkr()
+ wrkr.set("add_device %s" % dev_name)
+
class TestPktgenTx(TestGeneric):
def run(self):
- dev_name = self.get_mopt("netdev_name")
+ dev_names = self.get_multi_mopt("netdev_name")
addr = self.get_mopt("addr", opt_type="addr")
hwaddr = self.get_mopt("hwaddr")
vlan_tci = self.get_opt("vlan_tci", default=0)
@@ -32,20 +61,19 @@ class TestPktgenTx(TestGeneric):
exec_cmd("modprobe pktgen")
pgctl = Pktgen("/proc/net/pktgen/pgctrl")
- pgwrkr = Pktgen("/proc/net/pktgen/kpktgend_0")
- pg = Pktgen("/proc/net/pktgen/%s" % dev_name)
+ pgwrkr = PktgenWorkers()
try:
- pgwrkr.set("rem_device_all")
- pgwrkr.set("add_device %s" % dev_name)
- pgwrkr.set("max_before_softirq 5000")
- pg.set("clone_skb 100000")
- pg.set("pkt_size 60")
- pg.set("dst %s" % addr)
- pg.set("dst_mac %s" % hwaddr)
- if vlan_tci:
- pg.set("vlan_id %d" % vlan_tci)
- pg.set("count 10000000")
+ for dev_name in dev_names:
+ pgwrkr.add_device(dev_name)
+ pg = Pktgen("/proc/net/pktgen/%s" % dev_name)
+ pg.set("clone_skb 100000")
+ pg.set("pkt_size 60")
+ pg.set("dst %s" % addr)
+ pg.set("dst_mac %s" % hwaddr)
+ if vlan_tci:
+ pg.set("vlan_id %d" % vlan_tci)
+ pg.set("count 10000000")
pgctl.set("start")
except ExecCmdFail:
return self.set_fail("pktgen failed")
12 years, 5 months
[lnst] TestGeneric: Implement multi-value options
by Jiří Pírko
commit 967ca0eaf660f18955bdd06f7a77ebbffd088a32
Author: Jiri Pirko <jpirko(a)redhat.com>
Date: Wed Jun 29 16:08:48 2011 +0200
TestGeneric: Implement multi-value options
Might become handy. Just repeat the option in xml with different values
and you can get them all in particular test.
Signed-off-by: Jiri Pirko <jpirko(a)redhat.com>
Common/TestsCommon.py | 47 ++++++++++++++++++++++++++++++++++++-----------
NetTest/NetTestParse.py | 4 +++-
2 files changed, 39 insertions(+), 12 deletions(-)
---
diff --git a/Common/TestsCommon.py b/Common/TestsCommon.py
index f9beaf2..197bb62 100644
--- a/Common/TestsCommon.py
+++ b/Common/TestsCommon.py
@@ -70,27 +70,39 @@ class TestGeneric(NetTestCommandGeneric):
self.set_result(res)
return res
- def get_opt(self, name, mandatory=False, opt_type="", default=None):
- try:
- option = self._command["options"][name]
- except KeyError:
- if mandatory:
- raise TestOptionMissing
- return default
-
- value = option["value"]
+ def _get_val(self, value, opt_type, default):
if opt_type == "addr":
'''
If address type is specified do "slashcut"
'''
- value = re.sub(r'/.*', r'', value)
+ return re.sub(r'/.*', r'', value)
if default != None:
'''
In case a default value is passed, retype value
by the default value type.
'''
- value = (type(default))(value)
+ return (type(default))(value)
+
+ return value
+
+ def get_opt(self, name, multi=False, mandatory=False, opt_type="", default=None):
+ try:
+ option = self._command["options"][name]
+ except KeyError:
+ if mandatory:
+ raise TestOptionMissing
+ if multi:
+ return [default]
+ else:
+ return default
+
+ if multi:
+ value = []
+ for op in option:
+ value.append(self._get_val(op["value"], opt_type, default))
+ else:
+ value = self._get_val(option[0]["value"], opt_type, default)
return value
@@ -99,3 +111,16 @@ class TestGeneric(NetTestCommandGeneric):
This should be used to get mandatory options
'''
return self.get_opt(name, mandatory=True, opt_type=opt_type)
+
+ def get_multi_opt(self, name, mandatory=False, opt_type="", default=None):
+ '''
+ This should be used to get multi options (array of values)
+ '''
+ return self.get_opt(name, multi=True, mandatory=mandatory,
+ opt_type=opt_type, default=default)
+
+ def get_multi_mopt(self, name, opt_type=""):
+ '''
+ This should be used to get mandatory multi options (array of values)
+ '''
+ return self.get_multi_opt(name, mandatory=True, opt_type=opt_type)
diff --git a/NetTest/NetTestParse.py b/NetTest/NetTestParse.py
index 414bc40..f0be155 100644
--- a/NetTest/NetTestParse.py
+++ b/NetTest/NetTestParse.py
@@ -113,7 +113,9 @@ class NetTestParse:
option["type"] = option_type
if orig_value:
option["orig_value"] = orig_value
- options[name] = option
+ if not name in options:
+ options[name] = []
+ options[name].append(option)
def _parse_command(self, dom_command):
logging.debug("Parsing command")
12 years, 5 months
FYI: Autonomously testing bonding through TAP/VDE-switches
by Kirill Smelkov
Hello up there,
I was studying netconf2011 slides and saw there is an LNST effort to
automatically test net, bonding, vlan, etc..., so I'd like to say thanks
and also I think I have something to share on the topic:
When I was working on bonding some time ago, it turned out that with the
help of TAP devices, virtual VDE switches and route-based send-to-self,
it is possible to create virtual nets on non-virtualized host and then
see/test how e.g. bonding works over such network.
Attached is a sample script which creates two virtual ethernet segments,
and bonds them together.
Hope it will be somewhat useful idea/sample and thanks,
Kirill
---- 8< ----
#!/bin/bash -e
# Handy program to prepare environment for testing etherdup:
#
# - setup tap interfaces and switches and plug cables between them;
# - setup bonding interfaces above taps;
# - setup routing so that send-to-self works;
# - for convenience, screen sessions with switch/cables control (yes, you can
# break and restore cables) and tcpdump's are started;
# - everything is cleaned up on exit.
#
#
# tap0 --- switch0 --- tap1
# / 1.10 1.11 \
# bond0 -- -- bond1
# 4.10 \ / 4.11
# tap2 --- switch1 --- tap3
# 2.10 2.11
# die <msg>...
die() {
echo 1>&2 $@
exit 1
}
verbose=
# trace <msg>
trace() {
test -z "$verbose" || echo $@
}
# lower priority of kernel local table from 0 to 500
# (so that we can install our own rules before it)
ip rule del pref 0 lookup local 2>/dev/null || :
ip rule del pref 500 lookup local 2>/dev/null || :
ip rule add pref 500 lookup local
# ifcfg_tap <tap-name>
ifcfg_tap() {
tap=$1
trace ifcfg_tap $tap
# reset interface
ip link del $tap 2>/dev/null || :
# create interface
vde_tunctl -t $tap
}
# xifup <ifname> <ip>
xifup() {
xif=$1
ip=$2
trace xifup $xif $ip
# assign IP address
ip addr add $ip/24 dev $xif
# put if up
ip link set $xif up
}
# if_get_ipaddr <iface>
if_get_ipaddr() {
iface=$1
ip=$(ip -4 addr show $iface | tail -1 | awk '{print $2}')
ip=${ip%/*} # 192.168.1.10/24 -> 192.168.1.10
echo $ip
}
# if_get_n <iface>
# tap<n> -- n
# bond<n> -- 10+n
if_get_n() {
ifx=$1
case $ifx in
tap*)
n=${ifx#tap}
;;
bond*)
n=${ifx#bond}
n=$((10+$n))
;;
*)
die "unsupported iface $ifx"
;;
esac
echo $n
}
# rt_setup_loop <if1> <if2>
# setup routing loop between two interfaces
# http://marc.info/?l=linux-netdev&m=129500124207256&w=2
rt_setup_loop() {
if1=$1
if2=$2
trace rt_setup_loop $if1 $if2
n1=`if_get_n $if1`
n2=`if_get_n $if2`
ip1=`if_get_ipaddr $if1`
ip2=`if_get_ipaddr $if2`
# on rx side handle packets by local table, so we can receive them
echo 1 >/proc/sys/net/ipv4/conf/$if1/accept_local
echo 1 >/proc/sys/net/ipv4/conf/$if2/accept_local
ip rule del pref $((0+$n1)) 2>/dev/null || :
ip rule del pref $((0+$n2)) 2>/dev/null || :
ip rule add pref $((0+$n1)) iif $if1 lookup local
ip rule add pref $((0+$n2)) iif $if2 lookup local
# tx
ip rule del pref $((100+$n1)) 2>/dev/null || :
ip rule del pref $((100+$n2)) 2>/dev/null || :
ip rule add pref $((100+$n1)) to $ip1 lookup $((100+$n1)) # if1 <- if2
ip rule add pref $((100+$n2)) to $ip2 lookup $((100+$n2)) # if2 <- if1
ip route flush table $((100+$n1))
ip route flush table $((100+$n2))
ip route add default dev $if2 table $((100+$n1))
ip route add default dev $if1 table $((100+$n2))
}
# ifcfg_bond <bond-name> <slave1> <slave2>
ifcfg_bond() {
bond=$1
slave1=$2
slave2=$3
trace ifcfg_bond $bond $slave1 $slave2
# FIXME bonding wants slave to be initially down, why?
ip link set $slave1 down
ip link set $slave2 down
echo -$bond >/sys/class/net/bonding_masters 2>/dev/null || :
echo +$bond >/sys/class/net/bonding_masters
echo broadcast >/sys/class/net/$bond/bonding/mode
echo +$slave1 >/sys/class/net/$bond/bonding/slaves
echo +$slave2 >/sys/class/net/$bond/bonding/slaves
}
ifcfg_tap tap0 && xifup tap0 192.168.1.10
ifcfg_tap tap1 && xifup tap1 192.168.1.11
ifcfg_tap tap2 && xifup tap2 192.168.2.10
ifcfg_tap tap3 && xifup tap3 192.168.2.11
rt_setup_loop tap0 tap1
rt_setup_loop tap2 tap3
ifcfg_bond bond0 tap0 tap2 && xifup bond0 192.168.4.10
ifcfg_bond bond1 tap1 tap3 && xifup bond1 192.168.4.11
rt_setup_loop bond0 bond1
# kill unnneeded routes from 'table main' set by `ip addr add`
for ifx in tap0 tap1 tap2 tap3 bond0 bond1 ; do
ip route del `ip route list table main | grep $ifx`
done
# ensure (visually) we've set up it ok
echo
echo " >>> rules:"
ip rule
echo
echo " >>> tap/bond routing table:"
routel | grep '\<\(tap\|bond\).\>'
#ip route show table all | grep '\<\(tap\|bond\).\>'
# tx path
echo
echo " >>> checking routing for tx path:"
ip route get 192.168.1.10 connected
ip route get 192.168.1.11 connected
echo
ip route get 192.168.2.10 connected
ip route get 192.168.2.11 connected
echo
ip route get 192.168.4.10 connected
ip route get 192.168.4.11 connected
# rx path
echo
echo " >>> checking routing for rx path:"
ip route get from 192.168.1.10 to 192.168.1.11 iif tap1
ip route get from 192.168.1.11 to 192.168.1.10 iif tap0
echo
ip route get from 192.168.2.10 to 192.168.2.11 iif tap3
ip route get from 192.168.2.11 to 192.168.2.10 iif tap2
echo
ip route get from 192.168.4.10 to 192.168.4.11 iif bond1
ip route get from 192.168.4.11 to 192.168.4.10 iif bond0
echo
echo " >>> ready to start switches, connect wires, etc ..."
read
S() {
screen -S switches -X $@
}
screen -d -m -S switches -t S0 vde_switch -s switch0
S zombie qr
S verbose on
sleep 0.2
S screen -t 'S0-tap0' vde_plug2tap -s switch0 tap0
S screen -t 'S0-tap1' vde_plug2tap -s switch0 tap1
S screen -t 'S1' vde_switch -s switch1
sleep 0.2
S screen -t 'S1-tap2' vde_plug2tap -s switch1 tap2
S screen -t 'S1-tap3' vde_plug2tap -s switch1 tap3
S() {
screen -S dumps -X $@
sleep 0.01 # :( or else it can miss some commands
}
screen -d -m -S dumps -t tap0 tcpdump -i tap0 -n -t -e
S zombie qr
S verbose on
S screen -t tap1 tcpdump -i tap1 -n -t -e
S screen -t tap2 tcpdump -i tap2 -n -t -e
S screen -t tap3 tcpdump -i tap3 -n -t -e
S screen -t bond0 tcpdump -i bond0 -n -t -e
S screen -t bond1 tcpdump -i bond1 -n -t -e
XTERM="xterm -fn -misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1"
$XTERM -T "tap/bond dumps" -e screen -r dumps &
$XTERM -T "tap/bond switches" -e screen -r switches &
# wait for xterm with `screen -r dumps` started
sleep 1
# layout dumps as follows
# tap0 tap1
# tap2 tap3
# bond0 bond1
S select -
S split
S focus down
S split
S focus up
S split -v
S select tap0
S focus down
S select tap1
S focus down
S split -v
S select tap2
S focus down
S select tap3
S focus down
S split -v
S select bond0
S focus down
S select bond1
wait
# cleanup
echo " >>> cleanup..."
for ifx in bond0 bond1 tap0 tap1 tap2 tap3 ; do
# kill 'to <if-ip>' rule
ip rule del to `if_get_ipaddr $ifx`
# kill 'iif <if>' rule
ip rule del iif $ifx
# kills interfaces and routes
ip link del $ifx
done
echo done
12 years, 5 months
[PATCH 1/2] Repair test path error on client side.
by Jiří Župka
Signed-off-by: Jiří Župka <jzupka(a)redhat.com>
---
Common/Logs.py | 2 +-
Common/SlaveUtils.py | 27 ++++++++++++++++++---------
NetTest/NetTestController.py | 5 ++---
3 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/Common/Logs.py b/Common/Logs.py
index 34dae3e..44d4f98 100644
--- a/Common/Logs.py
+++ b/Common/Logs.py
@@ -194,7 +194,7 @@ class Logs:
':%(lineno)4.4d| %(levelname)s: '
'%(message)s', '%d/%m %H:%M:%S', " "*4)
cls.log_root = log_root
- cls.logFolder = find_test_root(__file__, "nettest")
+ cls.logFolder = os.path.dirname(sys.argv[0])
cls.logger = logger
cls.debug = debug
cls.date = datetime.datetime.now().strftime("%Y-%m-%d_%H:%M:%S")
diff --git a/Common/SlaveUtils.py b/Common/SlaveUtils.py
index c9e24d0..d8db772 100644
--- a/Common/SlaveUtils.py
+++ b/Common/SlaveUtils.py
@@ -11,23 +11,32 @@ from Common.ShellProcess import ShellProcess
def prepare_client_session(host, port, login, passwd=None, command=None,
- prompt=None):
+ prompt=None, install_path=None, test_dir=None):
"""
Copy nettest to client start client part
and create session with client part.
- @param command: Command which is started after login to guest.
- @param prompt: Prompt in guest side which means that guest side stared correctly.
+ @param command: Command which is started after login to guest, in root
+ path of installed test.
+ @param prompt: Prompt in guest side which means that guest side stared
+ correctly.
+ @param test_dir: Path in install_path where is installed testing framework.
+ @param install_path: Path to create and install test_dir folder.
"""
- s = ShellProcess("tar -cvzf nettest.tar.gz --exclude *.pyc --exclude 'Logs/*' *")
+ if install_path is None:
+ install_path = "/tmp"
+ if test_dir is None:
+ test_dir = "lnst"
+ s = ShellProcess("tar -cjf lnst.tar.bz2 --exclude *.pyc --exclude 'Logs/*' *")
s.wait()
scp_to_remote(host, port, login, passwd,
- "nettest.tar.gz","/tmp/")
+ "lnst.tar.bz2","/%s/" % (install_path))
wait_for_login(host, port, login, passwd, "PASS:",
- command = "mkdir -p /tmp/nettest && tar -xvzf "
- "/tmp/nettest.tar.gz -C /tmp/nettest/ && echo PASS:",
- timeout=60)
+ command = "mkdir -p /%(ip)s/%(td)s && tar -xvjf "
+ "/%(ip)s/lnst.tar.bz2 -C /%(ip)s/%(td)s && echo PASS:" %
+ {"td":test_dir, "ip":install_path} , timeout=60)
if prompt is None:
prompt = "Started"
+ command = "/%s/%s/%s" % (install_path, test_dir, command)
return wait_for_login(host, port, login, passwd, prompt,
- command=command, timeout=10)
+ command=command, timeout=10)
\ No newline at end of file
diff --git a/NetTest/NetTestController.py b/NetTest/NetTestController.py
index 7626157..b0b2437 100644
--- a/NetTest/NetTestController.py
+++ b/NetTest/NetTestController.py
@@ -52,9 +52,8 @@ class NetTestController:
passwd = info["rootpass"]
else:
passwd = None
- session = prepare_client_session(hostname, port,
- login, passwd,
- "/tmp/nettest/nettestslave.py")
+ session = prepare_client_session(hostname, port, login, passwd,
+ "nettestslave.py")
session.add_kill_handler(self._session_die)
info["session"] = session
--
1.7.4.4
12 years, 5 months
[lnst] Change ProcessManager structure.
by Jiří Pírko
commit 40be567c6c6aaff75e52ad4105527b44affb993c
Author: Jiří Župka <jzupka(a)redhat.com>
Date: Wed Jun 8 14:54:23 2011 +0200
Change ProcessManager structure.
Compatibility problem with python 2.4.
Example:
1) Create process.
2) Get process pid.
3) ProcessManager.register_pid(pid, handler)
handler can be None.
4) When the process ends ProcessManager calls handler.
Handler is called in separate thread.
4.1) If in handler raise exception then ProcessManager
ends nettest.
5) For waiting on end of process can be use os.waitpid.
Signed-off-by: Jiří Župka <jzupka(a)redhat.com>
Common/ProcessManager.py | 110 +++++++++++++++++++++++++++------------------
1 files changed, 66 insertions(+), 44 deletions(-)
---
diff --git a/Common/ProcessManager.py b/Common/ProcessManager.py
index 86d7b4b..1995d15 100644
--- a/Common/ProcessManager.py
+++ b/Common/ProcessManager.py
@@ -9,64 +9,86 @@ published by the Free Software Foundation; see COPYING for details.
__autor__ = """
jzupka(a)redhat.com (Jiri Zupka)
"""
-import os, signal
+import os, signal, thread, logging
class ProcessManager:
+ class SubProcess:
+ def __init__(self, pid, handler):
+ self.pid = pid
+ self.lock = thread.allocate_lock()
+ self.lock.acquire()
+ self.handler = handler
+ self.enabled = True
+ self.status = None
+ thread.start_new_thread(self.waitpid, (self.pid, self.lock,
+ self.handler))
+
+ def isAlive(self):
+ return self.lock.locked()
+
+ def kill(self):
+ os.kill(self.pid, signal.SIGTERM)
+
+ def waitpid(self, pid, lock, handler):
+ _pid, status = ProcessManager.std_waitpid(pid, 0)
+ self.status = status
+ status = os.WEXITSTATUS(status)
+ lock.release()
+ if self.enabled:
+ ProcessManager.lock.acquire()
+ if handler is not None:
+ try:
+ handler(status)
+ except:
+ import sys, traceback
+ type, value, tb = sys.exc_info()
+ logging.error(''.join(traceback.format_exception(type, value, tb)))
+ os.kill(os.getpid(), signal.SIGTERM)
+ else:
+ print "Process pid %s exit with exitcode %s" % (pid, status)
+ ProcessManager.lock.release()
+ thread.exit()
+
pids = {}
- signals = 0
+ lock = thread.allocate_lock()
+ std_waitpid = None
@classmethod
def register_pid(cls, pid, handler=None):
- cls.pids[pid] = handler
+ cls.pids[pid] = ProcessManager.SubProcess(pid, handler)
@classmethod
def remove_pid(cls, pid):
if pid in cls.pids:
- del (cls.pids[pid])
+ cls.pids[pid].enabled = False
@classmethod
- def check_pids(cls):
- finished = {}
- pid_tr = []
-
+ def kill_all(cls):
for pid in cls.pids:
- _pid = 0
- status = None
- try:
- _pid, status = os.waitpid(pid, os.WNOHANG)
- except OSError, e:
- if e.errno != 10:
- raise
- else:
- finished[pid] = (None, cls.pids[pid])
- pid_tr.append(pid)
- else:
- if pid == _pid:
- finished[pid] = (os.WEXITSTATUS(status), cls.pids[pid])
- pid_tr.append(pid)
-
- for pid in pid_tr:
- cls.remove_pid(pid)
- return finished
+ cls.pids[pid].kill()
@classmethod
- def handler(cls, signum, frame):
- if (signum == signal.SIGCHLD):
- cls.signals += 1
- if cls.signals == 1:
- while cls.signals > 0:
- finished = ProcessManager.check_pids()
- for pid in finished:
- status, handler = finished[pid]
- if handler is None:
- print("Process %d finish with status %s." % (pid, status))
- else:
- handler(status)
- if cls.signals > 1:
- cls.signals = 1
- else:
- cls.signals = 0
+ def waitpid(cls, pid, wait):
+ if pid not in cls.pids:
+ return ProcessManager.std_waitpid(pid, wait)
+ if not wait:
+ cls.pids[pid].lock.acquire()
+ cls.pids[pid].lock.release()
+ status = cls.pids[pid].status
+ del cls.pids[pid]
+ return pid, status
+ else:
+ status = cls.pids[pid].status
+ if status is not None:
+ del cls.pids[pid]
+ else:
+ pid = 0
+ return pid, status
-signal.siginterrupt(signal.SIGCHLD, False)
-signal.signal(signal.SIGCHLD, ProcessManager.handler)
+lock = thread.allocate_lock()
+lock.acquire()
+if os.waitpid != ProcessManager.waitpid:
+ ProcessManager.std_waitpid = os.waitpid
+ os.waitpid = ProcessManager.waitpid
+lock.release()
\ No newline at end of file
12 years, 5 months