[lnst] ensure correct team cleanup
by Jiří Pírko
commit 46e03e6884b0817a962b414beff25c1eb2e1af5f
Author: Jiri Pirko <jiri(a)resnulli.us>
Date: Thu Aug 16 13:35:01 2012 +0200
ensure correct team cleanup
Killall teamd eventualy removes all team devices from the system.
However it may happen after lnst does netdev rescan and therefore lnst
may still see it. Resolve this by waiting for all kmod users to
disappear and, just to be save, remove all team kmods.
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
Common/Utils.py | 18 ++++++++++++++++++
NetConfig/NetConfigDevice.py | 20 ++++++++------------
2 files changed, 26 insertions(+), 12 deletions(-)
---
diff --git a/Common/Utils.py b/Common/Utils.py
index f6ba201..5f3f251 100644
--- a/Common/Utils.py
+++ b/Common/Utils.py
@@ -11,6 +11,7 @@ jzupka(a)redhat.com (Jiri Zupka)
"""
import logging
import time
+import re
def die_when_parent_die():
try:
@@ -52,3 +53,20 @@ def wait_for(func, timeout, first=0.0, step=1.0, text=None):
logging.debug("Timeout elapsed")
return None
+
+def kmod_in_use(modulename, tries = 1):
+ tries -= 1
+ ret = False
+ mod_file = "/proc/modules"
+ handle = open(mod_file, "r")
+ for line in handle:
+ match = re.match(r'^(\S+)\s\d+\s(\d+).*$', line)
+ if not match or not match.groups()[0] in re.split('\s+', modulename):
+ continue
+ if int(match.groups()[1]) != 0:
+ ret = True
+ break
+ handle.close()
+ if (ret and tries):
+ return kmod_in_use(modulename, tries)
+ return ret
diff --git a/NetConfig/NetConfigDevice.py b/NetConfig/NetConfigDevice.py
index 1e8a9aa..534e914 100644
--- a/NetConfig/NetConfigDevice.py
+++ b/NetConfig/NetConfigDevice.py
@@ -16,6 +16,7 @@ import re
import sys
from Common.ExecCmd import exec_cmd
from NetConfigCommon import get_slaves, get_option
+from Common.Utils import kmod_in_use
class NetConfigDeviceGeneric:
'''
@@ -23,6 +24,7 @@ class NetConfigDeviceGeneric:
extend this one.
'''
_modulename = ""
+ _moduleload = True
_moduleparams = ""
_cleanupcmd = ""
@@ -58,24 +60,16 @@ class NetConfigDeviceGeneric:
@classmethod
def type_init(self):
- if self._modulename:
+ if self._modulename and self._moduleload:
exec_cmd("modprobe %s %s" % (self._modulename, self._moduleparams))
@classmethod
- def _module_check(self):
- if self._modulename:
- output = exec_cmd("modinfo -F filename %s" % self._modulename, die_on_err=False)[0]
- for line in output.split("\n"):
- if re.match(r'^.*\/%s\.ko$' % self._modulename, line):
- return True
- False
-
- @classmethod
def type_cleanup(self):
- if self._modulename and self._module_check():
- exec_cmd("modprobe -r %s" % self._modulename, die_on_err=False)
if self._cleanupcmd:
exec_cmd(self._cleanupcmd, die_on_err=False)
+ if self._modulename:
+ kmod_in_use(self._modulename, 300)
+ exec_cmd("modprobe -r %s" % self._modulename, die_on_err=False)
class NetConfigDeviceEth(NetConfigDeviceGeneric):
def configure(self):
@@ -217,6 +211,8 @@ class NetConfigDeviceVlan(NetConfigDeviceGeneric):
class NetConfigDeviceTeam(NetConfigDeviceGeneric):
_pidfile = None
+ _modulename = "team_mode_roundrobin team_mode_activebackup team_mode_broadcast team_mode_loadbalance team"
+ _moduleload = False
_cleanupcmd = "killall -q teamd"
def configure(self):
11 years, 3 months
[PATCH] TCPListen and TCPConnect test set added
by Jan Tluka
Set of these tests provides possibility to test multiple TCP connections
within two LNST commands. Data sent are random and every connection
behaves differently in sense that number of packets is random as well.
Following are two examples of commands in command sequence.
<define>
<alias name="my_range" value="10000-10100" />
</define>
<command machine_id="1" type="test" value="TCPListen" bg_id="1">
<options>
<option name="addr" value="{ip(1,1)}"/>
<option name="port_range" value="{$my_range}"/>
</options>
</command>
<command type="exec" value="sleep 5" />
<command machine_id="2" type="test" value="TCPConnect" bg_id="2">
<options>
<option name="addr" value="{ip(1,1)}"/>
<option name="port_range" value="{$my_range}"/>
<option name="sleep" value="0.5" />
</options>
</command>
<command machine_id="2" type="wait" value="2" />
<command machine_id="1" type="wait" value="1" />
Repeated generation of connections can be achieved using following
command (see 'cont' option):
<define>
<alias name="my_range" value="10000-10100" />
</define>
<command machine_id="1" type="test" value="TCPListen" bg_id="1">
<options>
<option name="addr" value="{ip(1,1)}"/>
<option name="port_range" value="{$my_range}"/>
<option name="cont" value="yes" />
</options>
</command>
<command type="exec" value="sleep 5" />
<command machine_id="2" type="test" value="TCPConnect" bg_id="2">
<options>
<option name="addr" value="{ip(1,1)}"/>
<option name="port_range" value="{$my_range}"/>
<option name="sleep" value="0.5" />
<option name="cont" value="yes" />
</options>
</command>
<command type="exec" value="sleep 60" />
<command machine_id="2" type="intr" value="2" />
<command machine_id="1" type="kill" value="1" />
---
Tests/TestTCPConnect.py | 167 +++++++++++++++++++++++++++++++++++++++++++++++
Tests/TestTCPListen.py | 127 +++++++++++++++++++++++++++++++++++
2 files changed, 294 insertions(+), 0 deletions(-)
create mode 100644 Tests/TestTCPConnect.py
create mode 100644 Tests/TestTCPListen.py
diff --git a/Tests/TestTCPConnect.py b/Tests/TestTCPConnect.py
new file mode 100644
index 0000000..05579c2
--- /dev/null
+++ b/Tests/TestTCPConnect.py
@@ -0,0 +1,167 @@
+"""
+This module defines TCPConnect module
+"""
+
+__author__ = """
+jtluka(a)redhat.com (Jan Tluka)
+"""
+
+import sys
+import socket
+import errno
+from multiprocessing import Process, Lock
+from signal import signal, SIGINT
+from time import sleep
+from random import randrange, sample
+import logging
+import re
+from Common.TestsCommon import TestGeneric
+
+"""
+Test description:
+ Test spawns client(s) connecting to TCP port(s) defined by port or
+ port_range option. When connected, the client sends random bursts of
+ random data to server. If cont option is set the connections are initiated
+ again and data is sent to server until interrupted by the controller.
+
+Parameters:
+ addr ... mandatory, address to connect to
+ port ... mandatory, port to send data
+ sleep ... optional, sleep time between bursts, if undefined, the bursts
+ are immediate
+ cont ... optional, sets continuous mode of connecting, if set connections
+ are infinitely re-spawned when closed
+"""
+
+class ConnectionWorker():
+ def __init__(self, host, port, sleep_time = None, continuous = None):
+ self._tlock = Lock()
+ self._terminate = 0
+ self._host = host
+ self._port = port
+ self._sleep_time = sleep_time
+ self._cont = continuous
+ self._ascii = [chr(i) for i in range(0,255)]
+
+ def terminate(self):
+ self._tlock.acquire()
+ self._terminate=1
+ self._tlock.release()
+
+ def run(self):
+ loop = True
+
+ while loop:
+ loop = (self._cont is not None)
+ logging.debug("Starting connection to (%s) port %s " % (self._host,
+ self._port))
+
+ try:
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.connect((self._host, self._port))
+ except socket.error, msg:
+ s.close()
+ s = None
+ logging.error(msg)
+ return
+
+ for txs in range(10, randrange(20,100)):
+ self._tlock.acquire()
+ if self._terminate:
+ self._tlock.release()
+ logging.debug("Terminating connection on port %s" %
+ self._port)
+ loop = False
+ break
+ else:
+ self._tlock.release()
+
+ rnd_str = "".join(sample(self._ascii, len(self._ascii)))
+ data = s.sendall(rnd_str)
+ if (self._sleep_time):
+ sleep(self._sleep_time)
+
+ s.close()
+
+
+class TestTCPConnect(TestGeneric):
+ def _parse_options(self):
+ addr = self.get_mopt("addr")
+ if addr:
+ self._host = addr
+
+ # either port or port_range should be set
+ port = self.get_opt("port")
+ if port:
+ self._port = port
+ else:
+ port_range = self.get_opt("port_range")
+ if port_range:
+ self._port_range = port_range
+ else:
+ e = TestOptionMissing()
+ raise e
+
+ sleep_time = float(self.get_opt("sleep"))
+ if sleep_time:
+ self._sleep_time = sleep_time
+
+ cont = self.get_opt("cont")
+ if cont:
+ self._cont = cont
+
+ def parse_port_range(self):
+ if self._port_range == None:
+ return []
+
+ for c in [',','-']:
+ s = self._port_range.split(c)
+ if len(s) == 2:
+ break
+
+ if len(s) != 2:
+ logging.error("Port range malformed! ", self._port_range)
+
+ low = int(s[0])
+ high = int(s[1]) + 1
+
+ return range(low, high)
+
+ def _close_connections(self, signum, frame):
+ logging.debug("Termination signal delivered ...")
+ for cw in self._cw_instances:
+ cw.terminate()
+
+ def _set_interrupt_handler(self):
+ signal(SIGINT, self._close_connections)
+
+ def run(self):
+ self._terminate = 0
+ self._host = None
+ self._port = None
+ self._cont = None
+ self._cw_instances = []
+
+ self._set_interrupt_handler()
+
+ self._parse_options()
+
+ ports = []
+ if self._port:
+ ports.extend(self._port)
+ else:
+ r = self.parse_port_range()
+ ports.extend(r)
+
+ workers = []
+ for p in ports:
+ cw = ConnectionWorker(self._host, p, self._sleep_time, self._cont)
+ self._cw_instances.append(cw)
+
+ w = Process(target=cw.run)
+ w.start()
+ workers.append(w)
+
+ logging.debug("Waiting for workers ...")
+ for w in workers:
+ w.join()
diff --git a/Tests/TestTCPListen.py b/Tests/TestTCPListen.py
new file mode 100644
index 0000000..c9492f1
--- /dev/null
+++ b/Tests/TestTCPListen.py
@@ -0,0 +1,127 @@
+"""
+This module defines TCPListen module
+"""
+
+__author__ = """
+jtluka(a)redhat.com (Jan Tluka)
+"""
+
+import sys
+import socket
+import errno
+import logging
+import re
+from multiprocessing import Process
+from Common.TestsCommon import TestGeneric
+
+"""
+Test description:
+ Test spawns server(s) listening for TCP connection(s) on port(s) defined by
+ port or port_range options. When client connects to the port, server reads
+ the data sent and close the connection when no more data is available.
+ If cont option is set the connection is reopened and server reads data
+ again.
+
+Parameters:
+ addr ... optional, address to bind to, if undefined listen on all ifaces
+ port ... mandatory, port to listen on
+ cont ... optional, if set the listening port is reopened when the c
+ onnection is closed
+"""
+
+class TestTCPListen(TestGeneric):
+ def __init__(self, command):
+ self._addr = None
+ self._port = None
+ self._cont = None
+ TestGeneric.__init__(self, command)
+
+ def _parse_options(self):
+ addr = self.get_opt("addr")
+ if addr:
+ self._addr = addr
+
+ # either port or port_range should be set
+ port = self.get_opt("port")
+ if port:
+ self._port = port
+ else:
+ port_range = self.get_opt("port_range")
+ if port_range:
+ self._port_range = port_range
+ else:
+ e = TestOptionMissing()
+ raise e
+
+ cont = self.get_opt("cont")
+ if cont:
+ self._cont = cont
+
+ def _worker(self, host, port):
+ logging.debug("Starting listener (%s) on port %s " % (host, port))
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+ try:
+ s.bind((host, port))
+ s.listen(1)
+ except socket.error, msg:
+ s.close()
+ s = None
+ logging.error(msg)
+ return
+
+ loop = 1
+
+ while loop or self._cont:
+ conn, addr = s.accept()
+ logging.debug('Connected from ' + addr[0] + ' port:' +
+ str(addr[1]))
+
+ while 1:
+ data = conn.recv(1024)
+ if not data:
+ logging.debug('Client disconnected: ' + addr[0] +
+ ' port:' + str(addr[1]))
+ break
+
+ conn.close()
+ loop = 0
+
+ def _parse_port_range(self):
+ if self._port_range == None:
+ return []
+
+ for c in [',','-']:
+ s = self._port_range.split(c)
+ if len(s) == 2:
+ break
+
+ if len(s) != 2:
+ logging.error("Port range malformed! ", self._port_range)
+
+ low = int(s[0])
+ high = int(s[1]) + 1
+
+ return range(low, high)
+
+ def run(self):
+ self._parse_options()
+
+ ports = []
+ if self._port:
+ ports.extend(self._port)
+ else:
+ r = self._parse_port_range()
+ ports.extend(r)
+
+ workers = []
+
+ for p in ports:
+ w = Process(target=self._worker, args=(self._addr, p))
+ w.start()
+ workers.append(w)
+
+
+ logging.debug("Waiting for workers ...")
+ for w in workers:
+ w.join()
--
1.7.6.5
11 years, 3 months
[PATCH] system_config: Multiple values for single option support
by Radek Pazdera
This commit fixes bug (trac #3) in system config code, namely the
NetTestCommandSystemConfig class.
In cases when value was assigned to a same option multiple times
within a single system_config command, only the first value was
used. The remaining ones were discarded.
Now the option is set one by one to all the values as they are
specified in the command.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
---
NetTest/NetTestCommand.py | 11 +++++++----
NetTest/NetTestParse.py | 5 ++++-
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/NetTest/NetTestCommand.py b/NetTest/NetTestCommand.py
index 8c0ef82..ae1297f 100644
--- a/NetTest/NetTestCommand.py
+++ b/NetTest/NetTestCommand.py
@@ -147,8 +147,10 @@ class NetTestCommandSystemConfig(NetTestCommandGeneric):
val = [{"value": self._command["value"]}]
self._command["options"] = {opt: val}
- for option, values in self._command["options"].iteritems():
- new_val = values[0]["value"]
+ for option, opt_data in self._command["options"].iteritems():
+ new_values = []
+ for record in opt_data:
+ new_values.append(record["value"])
option_abspath = os.path.abspath(option)
if option_abspath[0:5] != "/sys/" and \
@@ -159,12 +161,13 @@ class NetTestCommandSystemConfig(NetTestCommandGeneric):
try:
prev_val = self._retrive_option(option)
- self._set_option(option, new_val)
+ for new_val in new_values:
+ self._set_option(option, new_val)
except ExecCmdFail:
self.set_fail("Unable to set %s config option!" % option)
return
- res_data[option] = {"current_val": new_val,
+ res_data[option] = {"current_val": new_values[-1],
"previous_val": prev_val}
res = {"passed": True}
diff --git a/NetTest/NetTestParse.py b/NetTest/NetTestParse.py
index fbe5adc..ce1d7a6 100644
--- a/NetTest/NetTestParse.py
+++ b/NetTest/NetTestParse.py
@@ -391,7 +391,10 @@ class CommandParse(RecipeParser):
command["machine_id"] = machine_id
command["type"] = self._get_attribute(node, "type")
- command["value"] = self._get_attribute(node, "value")
+
+ command["value"] = None
+ if self._has_attribute(node, "value"):
+ command["value"] = self._get_attribute(node, "value")
if self._has_attribute(node, "timeout"):
command["timeout"] = self._get_attribute(node, "timeout", int)
--
1.7.7.6
11 years, 3 months
[lnst] add recipes dir and simple team recipe
by Jiří Pírko
commit 4ff72f696aa397b4a1b3a9a43c9fc5febc3f3c33
Author: Jiri Pirko <jiri(a)resnulli.us>
Date: Thu Aug 16 13:44:32 2012 +0200
add recipes dir and simple team recipe
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
recipes/team/netconfig-test1_001.xml | 20 ++++++++++++++++++++
recipes/team/netconfig-test2_001.xml | 20 ++++++++++++++++++++
recipes/team/netmachineconfig-test1.xml | 7 +++++++
recipes/team/netmachineconfig-test2.xml | 7 +++++++
recipes/team/recipe_001.xml | 13 +++++++++++++
recipes/team/sequence_ping_simple.xml | 11 +++++++++++
6 files changed, 78 insertions(+), 0 deletions(-)
---
diff --git a/recipes/team/netconfig-test1_001.xml b/recipes/team/netconfig-test1_001.xml
new file mode 100644
index 0000000..6d12db0
--- /dev/null
+++ b/recipes/team/netconfig-test1_001.xml
@@ -0,0 +1,20 @@
+<netconfig>
+ <interface id="1" phys_id="1" type="eth"/>
+ <interface id="2" phys_id="2" type="eth"/>
+ <interface id="3" type="team">
+ <options>
+ <option name="teamd_config">
+ {
+ "runner": {"name": "roundrobin"}
+ }
+ </option>
+ </options>
+ <slaves>
+ <slave id="1"/>
+ <slave id="2"/>
+ </slaves>
+ <addresses>
+ <address value="192.168.111.1/24"/>
+ </addresses>
+ </interface>
+</netconfig>
diff --git a/recipes/team/netconfig-test2_001.xml b/recipes/team/netconfig-test2_001.xml
new file mode 100644
index 0000000..0a406c5
--- /dev/null
+++ b/recipes/team/netconfig-test2_001.xml
@@ -0,0 +1,20 @@
+<netconfig>
+ <interface id="1" phys_id="1" type="eth"/>
+ <interface id="2" phys_id="2" type="eth"/>
+ <interface id="3" type="team">
+ <options>
+ <option name="teamd_config">
+ {
+ "runner": {"name": "roundrobin"}
+ }
+ </option>
+ </options>
+ <slaves>
+ <slave id="1"/>
+ <slave id="2"/>
+ </slaves>
+ <addresses>
+ <address value="192.168.111.2/24"/>
+ </addresses>
+ </interface>
+</netconfig>
diff --git a/recipes/team/netmachineconfig-test1.xml b/recipes/team/netmachineconfig-test1.xml
new file mode 100644
index 0000000..dc01321
--- /dev/null
+++ b/recipes/team/netmachineconfig-test1.xml
@@ -0,0 +1,7 @@
+<netmachineconfig>
+ <info hostname="192.168.122.182" rootpass="aaa"/>
+ <netdevices>
+ <netdevice type="eth" phys_id="1" hwaddr="52:54:00:3d:c7:6d" network="testing"/>
+ <netdevice type="eth" phys_id="2" hwaddr="52:54:00:73:15:c2" network="testing"/>
+ </netdevices>
+</netmachineconfig>
diff --git a/recipes/team/netmachineconfig-test2.xml b/recipes/team/netmachineconfig-test2.xml
new file mode 100644
index 0000000..5272314
--- /dev/null
+++ b/recipes/team/netmachineconfig-test2.xml
@@ -0,0 +1,7 @@
+<netmachineconfig>
+ <info hostname="192.168.122.223" rootpass="aaa"/>
+ <netdevices>
+ <netdevice type="eth" phys_id="1" hwaddr="52:54:00:99:bb:27" network="testing"/>
+ <netdevice type="eth" phys_id="2" hwaddr="52:54:00:b7:cc:fb" network="testing"/>
+ </netdevices>
+</netmachineconfig>
diff --git a/recipes/team/recipe_001.xml b/recipes/team/recipe_001.xml
new file mode 100644
index 0000000..50276e3
--- /dev/null
+++ b/recipes/team/recipe_001.xml
@@ -0,0 +1,13 @@
+<nettestrecipe>
+ <machines>
+ <machine id="1">
+ <netmachineconfig source="netmachineconfig-test1.xml"/>
+ <netconfig source="netconfig-test1_001.xml"/>
+ </machine>
+ <machine id="2">
+ <netmachineconfig source="netmachineconfig-test2.xml"/>
+ <netconfig source="netconfig-test2_001.xml"/>
+ </machine>
+ </machines>
+ <command_sequence source="sequence_ping_simple.xml"/>
+</nettestrecipe>
diff --git a/recipes/team/sequence_ping_simple.xml b/recipes/team/sequence_ping_simple.xml
new file mode 100644
index 0000000..d4d2adf
--- /dev/null
+++ b/recipes/team/sequence_ping_simple.xml
@@ -0,0 +1,11 @@
+<command_sequence>
+ <command type="exec" value="sleep 4"/>
+ <command machine_id="1" timeout="30" type="test" value="IcmpPing">
+ <options>
+ <option name="addr" value="{$recipe['machines'][2]['netconfig'][3]['addresses'][0]}"/>
+ <option name="count" value="40"/>
+ <option name="interval" value="0.2"/>
+ <option name="limit_rate" value="95"/>
+ </options>
+ </command>
+</command_sequence>
11 years, 3 months
[lnst] add team port not by config, but by <slave> element
by Jiří Pírko
commit 9db0071c45951cdbfa31601f4e4164a998c56062
Author: Jiri Pirko <jiri(a)resnulli.us>
Date: Wed Aug 15 18:50:54 2012 +0200
add team port not by config, but by <slave> element
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
NetConfig/NetConfigDevice.py | 30 +++++++++++++++++-------------
1 files changed, 17 insertions(+), 13 deletions(-)
---
diff --git a/NetConfig/NetConfigDevice.py b/NetConfig/NetConfigDevice.py
index af343b2..1e8a9aa 100644
--- a/NetConfig/NetConfigDevice.py
+++ b/NetConfig/NetConfigDevice.py
@@ -219,19 +219,7 @@ class NetConfigDeviceTeam(NetConfigDeviceGeneric):
_pidfile = None
_cleanupcmd = "killall -q teamd"
- def _slaves_up(self):
- for slaveid in get_slaves(self._netdev):
- slavenetdev = self._config[slaveid]
- NetConfigDevice(slavenetdev, self._config).up()
-
- def _slaves_down(self):
- for slaveid in get_slaves(self._netdev):
- slavenetdev = self._config[slaveid]
- NetConfigDevice(slavenetdev, self._config).down()
-
def configure(self):
- self._slaves_down()
-
teamd_config = get_option(self._netdev, "teamd_config")
teamd_config = teamd_config.replace('"', '\\"')
@@ -242,12 +230,28 @@ class NetConfigDeviceTeam(NetConfigDeviceGeneric):
self._pidfile = pidfile
+ for slave_id in get_slaves(self._netdev):
+ self.slave_add(slave_id)
+
def deconfigure(self):
+ for slave_id in get_slaves(self._netdev):
+ self.slave_del(slave_id)
+
dev_name = self._netdev["name"]
pidfile = "/var/run/teamd_%s.pid" % dev_name
exec_cmd("teamd -k -p %s" % pidfile)
- self._slaves_up()
+
+ def slave_add(self, slaveid):
+ dev_name = self._netdev["name"]
+ port_netdev = self._config[slaveid]
+ port_name = port_netdev["name"]
+ NetConfigDevice(port_netdev, self._config).down()
+ exec_cmd("ip link set dev %s master %s" % (port_name, dev_name))
+
+ def slave_del(self, slaveid):
+ port_name = self._config[slaveid]["name"]
+ exec_cmd("ip link set dev %s nomaster" % (port_name))
type_class_mapping = {
"eth": NetConfigDeviceEth,
11 years, 3 months
[lnst] allow to specify cleanup command for device types
by Jiří Pírko
commit af668d80d0c473943db85d0046ac65e8073d2204
Author: Jiri Pirko <jiri(a)resnulli.us>
Date: Wed Aug 15 14:07:58 2012 +0200
allow to specify cleanup command for device types
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
NetConfig/NetConfigDevice.py | 19 +++++++++++--------
1 files changed, 11 insertions(+), 8 deletions(-)
---
diff --git a/NetConfig/NetConfigDevice.py b/NetConfig/NetConfigDevice.py
index 6a81495..af343b2 100644
--- a/NetConfig/NetConfigDevice.py
+++ b/NetConfig/NetConfigDevice.py
@@ -24,6 +24,7 @@ class NetConfigDeviceGeneric:
'''
_modulename = ""
_moduleparams = ""
+ _cleanupcmd = ""
def __init__(self, netdev, config):
self._netdev = netdev
@@ -61,12 +62,7 @@ class NetConfigDeviceGeneric:
exec_cmd("modprobe %s %s" % (self._modulename, self._moduleparams))
@classmethod
- def type_cleanup(self):
- if self._modulename:
- exec_cmd("modprobe -r %s" % self._modulename, die_on_err=False)
-
- @classmethod
- def type_check(self):
+ def _module_check(self):
if self._modulename:
output = exec_cmd("modinfo -F filename %s" % self._modulename, die_on_err=False)[0]
for line in output.split("\n"):
@@ -74,6 +70,13 @@ class NetConfigDeviceGeneric:
return True
False
+ @classmethod
+ def type_cleanup(self):
+ if self._modulename and self._module_check():
+ exec_cmd("modprobe -r %s" % self._modulename, die_on_err=False)
+ if self._cleanupcmd:
+ exec_cmd(self._cleanupcmd, die_on_err=False)
+
class NetConfigDeviceEth(NetConfigDeviceGeneric):
def configure(self):
netdev = self._netdev
@@ -214,6 +217,7 @@ class NetConfigDeviceVlan(NetConfigDeviceGeneric):
class NetConfigDeviceTeam(NetConfigDeviceGeneric):
_pidfile = None
+ _cleanupcmd = "killall -q teamd"
def _slaves_up(self):
for slaveid in get_slaves(self._netdev):
@@ -268,5 +272,4 @@ def NetConfigDeviceType(dev_type):
def NetConfigDeviceAllCleanup():
for dev_type in type_class_mapping:
- if NetConfigDeviceType(dev_type).type_check():
- NetConfigDeviceType(dev_type).type_cleanup()
+ NetConfigDeviceType(dev_type).type_cleanup()
11 years, 3 months
[lnst] Stop executing command sequences on demand
by Jiří Pírko
commit 92dac8553d5b23eb826b83d4c5345b3c9ac8716e
Author: Jan Tluka <jtluka(a)redhat.com>
Date: Wed Aug 15 14:59:01 2012 +0200
Stop executing command sequences on demand
Signed-off-by: Jan Tluka <jtluka(a)redhat.com>
NetTest/NetTestController.py | 10 +++++++---
1 files changed, 7 insertions(+), 3 deletions(-)
---
diff --git a/NetTest/NetTestController.py b/NetTest/NetTestController.py
index 05d7261..c70e252 100644
--- a/NetTest/NetTestController.py
+++ b/NetTest/NetTestController.py
@@ -382,17 +382,21 @@ class NetTestController:
raise err
def _run_recipe(self):
+ overall_res = True
+
for sequence in self._recipe["sequences"]:
res = self._run_command_sequence(sequence)
for machine_id in self._recipe["machines"]:
self._restore_system_config(machine_id)
- # stop when sequence fails
+ # sequence failed, check if we should quit_on_fail
if not res:
- break
+ overall_res = False
+ if sequence["quit_on_fail"] == "yes":
+ break
- return res
+ return overall_res
def _start_packet_capture(self):
logging.info("Starting packet capture")
11 years, 3 months
[lnst] Introduce quit_on_fail command_sequence attribute
by Jiří Pírko
commit e52dca0bbe080dc7be4cd6260213f17df66cc99b
Author: Jan Tluka <jtluka(a)redhat.com>
Date: Wed Aug 15 14:58:49 2012 +0200
Introduce quit_on_fail command_sequence attribute
Signed-off-by: Jan Tluka <jtluka(a)redhat.com>
NetTest/NetTestParse.py | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
---
diff --git a/NetTest/NetTestParse.py b/NetTest/NetTestParse.py
index 93e7782..6439c4d 100644
--- a/NetTest/NetTestParse.py
+++ b/NetTest/NetTestParse.py
@@ -330,6 +330,12 @@ class CommandSequenceParse(RecipeParser):
self._seq_num = seq_num
self._seq_node = node
+ if self._has_attribute(node, "quit_on_fail"):
+ quit_on_fail = self._get_attribute(node, "quit_on_fail")
+ sequences[seq_num]["quit_on_fail"] = quit_on_fail
+ else:
+ sequences[seq_num]["quit_on_fail"] = "no"
+
scheme = {"command": self._command}
self._process_child_nodes(node, scheme)
11 years, 3 months
[lnst] Preserve original node attributes for sourced xml bits
by Jiří Pírko
commit 8874632a971bea298cc6cb02c5aebf68762f4948
Author: Jan Tluka <jtluka(a)redhat.com>
Date: Wed Aug 15 14:58:41 2012 +0200
Preserve original node attributes for sourced xml bits
Signed-off-by: Jan Tluka <jtluka(a)redhat.com>
Common/XmlProcessing.py | 15 +++++++++++++++
1 files changed, 15 insertions(+), 0 deletions(-)
---
diff --git a/Common/XmlProcessing.py b/Common/XmlProcessing.py
index a76364e..8d92e83 100644
--- a/Common/XmlProcessing.py
+++ b/Common/XmlProcessing.py
@@ -191,6 +191,13 @@ class XmlParser(object):
text = str(''.join(content).strip())
return self._convert_string(node, text, conversion_cb)
+ def _get_all_attributes(self, node):
+ res = {}
+ for i in range(0, node.attributes.length):
+ attr = node.attributes.item(i)
+ res[attr.name] = attr.value
+
+ return res
class RecipeParser(XmlParser):
""" Enhanced XmlParser
@@ -294,10 +301,18 @@ class RecipeParser(XmlParser):
% (node.nodeName, file_path))
raise XmlProcessingError(msg, node)
+ old_attrs = self._get_all_attributes(node)
+
parent = node.parentNode
parent.replaceChild(loaded_node, node)
node = loaded_node
+ # copy all of the original attributes to the sourced node
+ for name, value in old_attrs.iteritems():
+ # do not overwrite sourced attributes
+ if not node.hasAttribute(name):
+ node.setAttribute(name, value)
+
parent = super(RecipeParser, self)
parent._process_node(node, handler, params)
11 years, 3 months