commit 223c8e2d97f75ebb967db0944e45de4864a83411
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Tue May 22 13:26:58 2012 +0200
NetTest: Adding new command type 'system_config'
This commit introduces a new command type 'system_config', that can be
used in the command sequences. Using this command you can change system
configuration through /proc and /sys filesystems.
There are two different syntax options:
a) inline
<command type="system_config"
option="/proc/sys/net/option"
value="2" machine_id="1" />
b) multiline
<command type="system_config" machine_id="1">
<options>
<option name="/proc/sys/net/option" value="1"
/>
<option name="/sys/class/net/option" value="2"
/>
</options>
</command>
You can set multiple options at once using the multiline version.
LNST does all the error checking and it also saves the original values
and restores them upon finishing each command sequence. For instance
<command_sequence>
<command type="system_config" ... />
...
<!-- Cleanup occurs HERE -->
</command_sequence>
<!-- System is configured with default values when it
executes the following sequence -->
<command_sequence source="max_groups.xml" />
The command also has a bool option that makes the setting permanent
and the former value is not restored. For instance
<command type="system_config"
option="/proc/sys/net/option"
value="2" persistent="true" machine_id="1"
/>
<command type="system_config" persistent="1"
machine_id="1">
<options>
<option name="/proc/sys/net/option" value="1"
/>
<option name="/sys/class/net/option" value="2"
/>
</options>
</command>
When omitted, persistent is set to "false" by default (values are
restored).
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
NetTest/NetTestCommand.py | 45 +++++++++++++++++++++++++++++++++
NetTest/NetTestController.py | 56 +++++++++++++++++++++++++++++++++++++++---
NetTest/NetTestParse.py | 36 ++++++++++++++++++++++++---
3 files changed, 129 insertions(+), 8 deletions(-)
---
diff --git a/NetTest/NetTestCommand.py b/NetTest/NetTestCommand.py
index ca28abf..1dbd2a2 100644
--- a/NetTest/NetTestCommand.py
+++ b/NetTest/NetTestCommand.py
@@ -111,6 +111,49 @@ class NetTestCommandExec(NetTestCommandGeneric):
else:
self.set_fail("Command failed to execute")
+class NetTestCommandSystemConfig(NetTestCommandGeneric):
+ def _retrive_option(self, option):
+ cmd_str = "cat %s" % option
+ (stdout, stderr) = exec_cmd(cmd_str)
+ return stdout.strip()
+
+ def _set_option(self, option, value):
+ cmd_str = "echo \"%s\" >%s" % (value, option)
+ (stdout, stderr) = exec_cmd(cmd_str)
+
+ def run(self):
+ res_data = {}
+
+ # inline version
+ if "option" in self._command:
+ opt = self._command["option"]
+ val = [{"value": self._command["value"]}]
+ self._command["options"] = {opt: val}
+
+ for option, values in self._command["options"].iteritems():
+ new_val = values[0]["value"]
+
+ option_abspath = os.path.abspath(option)
+ if option_abspath[0:5] != "/sys/" and \
+ option_abspath[0:6] != "/proc/":
+ err = "Wrong config option %s. Only /proc or /sys paths are
allowed." % option
+ self.set_fail(err)
+ return
+
+ try:
+ prev_val = self._retrive_option(option)
+ 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,
+ "previous_val": prev_val}
+
+ res = {"passed": True}
+ res["res_data"] = res_data
+ self.set_result(res)
+
class BgProcessException(Exception):
"""Base class for client errors."""
def __init__(self, str):
@@ -170,6 +213,8 @@ def get_command_class(command):
return NetTestCommandIntr(command)
elif cmd_type == "kill":
return NetTestCommandKill(command)
+ elif cmd_type == "system_config":
+ return NetTestCommandSystemConfig(command)
else:
logging.error("Unknown comamnd type \"%s\"" % cmd_type)
raise Exception("Unknown command type \"%s\"" % cmd_type)
diff --git a/NetTest/NetTestController.py b/NetTest/NetTestController.py
index f2efbaa..12a871d 100644
--- a/NetTest/NetTestController.py
+++ b/NetTest/NetTestController.py
@@ -58,6 +58,7 @@ class NetTestController:
"nettestslave.py")
session.add_kill_handler(self._session_die)
info["session"] = session
+ info["system_config"] = {}
def _cleanup_slaves(self):
for machine_id in self._recipe["machines"]:
@@ -163,10 +164,19 @@ class NetTestController:
if "timeout" in command:
logging.debug("Setting socket timeout to default value")
socket.setdefaulttimeout(None)
+
+ if command["type"] == "system_config":
+ if cmd_res["passed"]:
+ self._update_system_config(machine_id, cmd_res["res_data"],
+ command["persistent"])
+ else:
+ err = "Error occured while setting system configuration (%s)"
\
+ % cmd_res["err_msg"]
+ logging.error(err)
+
return cmd_res
- def _run_command_sequence(self):
- sequence = self._recipe["sequence"]
+ def _run_command_sequence(self, sequence):
for command in sequence:
logging.info("Executing command: [%s]" % str_command(command))
cmd_res = self._run_command(command)
@@ -198,12 +208,50 @@ class NetTestController:
def run_recipe(self):
self._prepare()
- res = self._run_command_sequence()
+ 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
+ if not res:
+ break
+
self._cleanup()
return res
def eval_expression_recipe(self, expr):
self._prepare()
value = eval("self._recipe%s" % expr)
- print "Evaluated expression \"%s\": \"%s\"" %
(expr, value)
return True
+
+ def _update_system_config(self, machine_id, res_data, persistent=False):
+ info = self._get_machineinfo(machine_id)
+ system_config = info["system_config"]
+ for option, values in res_data.iteritems():
+ if persistent:
+ if option in system_config:
+ del system_config[option]
+ else:
+ if not option in system_config:
+ system_config[option] = {"initial_val":
values["previous_val"]}
+ system_config[option]["current_val"] =
values["current_val"]
+
+
+ def _restore_system_config(self, machine_id):
+ info = self._get_machineinfo(machine_id)
+ system_config = info["system_config"]
+
+ if len(system_config) > 0:
+ command = {}
+ command["machine_id"] = machine_id
+ command["type"] = "system_config"
+ command["value"] = ""
+ command["options"] = {}
+ command["persistent"] = True
+ for option, values in system_config.iteritems():
+ command["options"][option] = [{"value":
values["initial_val"]}]
+
+ self._run_command_sequence([command])
+ info["system_config"] = {}
diff --git a/NetTest/NetTestParse.py b/NetTest/NetTestParse.py
index c1493b5..69833b1 100644
--- a/NetTest/NetTestParse.py
+++ b/NetTest/NetTestParse.py
@@ -128,11 +128,27 @@ class NetTestParse:
try:
return str(eval("self._recipe%s" % eval_data))
except (KeyError, IndexError):
- print self._recipe
logging.error("Wrong recipe_eval value \"%s\" passed"
% eval_data)
raise Exception
+ @classmethod
+ def _int_it(cls, val):
+ try:
+ num = int(val)
+ except ValueError:
+ num = 0
+ return num
+
+ @classmethod
+ def _bool_it(cls, val):
+ if isinstance(val, str):
+ if re.match("^\s*(?i)(true)", val):
+ return True
+ elif re.match("^\s*(?i)(false)", val):
+ return False
+ return True if cls._int_it(val) else False
+
def _parse_command_option(self, dom_option, options):
logging.debug("Parsing command option")
option_type = str(dom_option.getAttribute("type"))
@@ -185,6 +201,17 @@ class NetTestParse:
command["desc"] = str(tmp)
logging.debug("Parsed command: [%s]" % str_command(command))
+ if cmd_type == "system_config":
+ tmp = dom_command.getAttribute("option")
+ if tmp:
+ command["option"] = str(tmp)
+
+ tmp = dom_command.getAttribute("persistent")
+ if tmp:
+ command["persistent"] = self._bool_it(tmp)
+ else:
+ command["persistent"] = False
+
dom_options_grp = dom_command.getElementsByTagName("options")
options = {}
for dom_options_item in dom_options_grp:
@@ -233,17 +260,18 @@ class NetTestParse:
raise WrongCommandSequenceException
def parse_recipe_command_sequence(self):
- sequence = []
dom_sequences =
self._dom_nettestrecipe.getElementsByTagName("command_sequence")
self._expand_group(dom_sequences, recipe_eval=True)
+ self._recipe["sequences"] = []
for dom_sequence in dom_sequences:
+ sequence = []
dom_commands = dom_sequence.getElementsByTagName("command")
for dom_command in dom_commands:
sequence.append(self._parse_command(dom_command))
- self._check_sequence(sequence)
- self._recipe["sequence"] = sequence
+ self._check_sequence(sequence)
+ self._recipe["sequences"].append(sequence)
def _expand(self, node, recipe_eval=False):
if node.nodeType == node.ELEMENT_NODE: