On 05/21/2012 06:10 PM, Jiri Pirko wrote:
Mon, May 21, 2012 at 11:40:20AM CEST, rpazdera(a)redhat.com wrote:
> From: Radek Pazdera<rpazdera(a)redhat.com>
>
> 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" />
>
> Signed-off-by: Radek Pazdera<rpazdera(a)redhat.com>
This is looking very good to me. Only thing I can think of now is that
some proc files does not give on read the same value as they accept on
write. That would make restoring probably impossible.
For example /sys/block/sda/queue/scheduler behaves this way.
Maybe the partial solution would be an attribute that would tell LNST
not to restore the value...
What do you think?
Thanks!
Jirka
Ah, I was not aware of that ...
I think that the solution you propose is good. It would be very hard
to implement and maintain workarounds for each option, that behaves
this way.
Additionally, your proposal solves a possible problem with the effect
of config settings (they're cleared at the end of each command sequence).
If we add, say option persistent="1", it will be possible to have
"global options" like this:
<command_sequence>
<command type="system_config" option="/sys/fs" value="5"
persistent="1" />
</command_sequence>
<command_sequence source="external.xml" />
<command_sequence>
<command type="system_config" option="/sys/fs" value="0"
persistent="1" />
</command_sequence>
Thanks for the review! I'll fix that and repost the patch.
Radek
> ---
> NetTest/NetTestCommand.py | 45 +++++++++++++++++++++++++++++++++++++++
> NetTest/NetTestController.py | 48 +++++++++++++++++++++++++++++++++++++++--
> NetTest/NetTestParse.py | 12 +++++++--
> 3 files changed, 99 insertions(+), 6 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..b76bd5f 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,18 @@ 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"])
> + 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,7 +207,16 @@ 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
>
> @@ -207,3 +225,27 @@ class NetTestController:
> value = eval("self._recipe%s" % expr)
> print "Evaluated expression \"%s\": \"%s\"" %
(expr, value)
> return True
> +
> + def _update_system_config(self, machine_id, res_data):
> + info = self._get_machineinfo(machine_id)
> + system_config = info["system_config"]
> + for option, values in res_data.iteritems():
> + 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"] = {}
> + 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..6b20d22 100644
> --- a/NetTest/NetTestParse.py
> +++ b/NetTest/NetTestParse.py
> @@ -185,6 +185,11 @@ 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)
> +
> dom_options_grp = dom_command.getElementsByTagName("options")
> options = {}
> for dom_options_item in dom_options_grp:
> @@ -233,17 +238,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:
> --
> 1.7.7.6
>
> _______________________________________________
> LNST-developers mailing list
> LNST-developers(a)lists.fedorahosted.org
>
https://fedorahosted.org/mailman/listinfo/lnst-developers