Following is the patch set that changes multi-sequence evaluation behavior.
Currently if any of the command sequence fails the whole recipe is aborted and the rest of the command sequences won't be executed.
The change is to execute all of the command sequences in recipe not depending on the previous sequence result. If user wants to specify some crucial sequence it's possible to set attribute quit_on_fail to value "yes" in the command_sequence tag.
Jan Tluka (4): Changing sequences to list of dictionaries Preserve original node attributes for sourced xml bits Introduce quit_on_fail command_sequence attribute Stop executing command sequences on demand
Common/XmlProcessing.py | 15 +++++++++++++++ NetTest/NetTestController.py | 12 ++++++++---- NetTest/NetTestParse.py | 19 +++++++++++++------ 3 files changed, 36 insertions(+), 10 deletions(-)
Signed-off-by: Jan Tluka jtluka@redhat.com --- NetTest/NetTestController.py | 2 +- NetTest/NetTestParse.py | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/NetTest/NetTestController.py b/NetTest/NetTestController.py index 296150d..27cf455 100644 --- a/NetTest/NetTestController.py +++ b/NetTest/NetTestController.py @@ -316,7 +316,7 @@ class NetTestController:
def _run_command_sequence(self, sequence): seq_passed = True - for command in sequence: + for command in sequence["commands"]: logging.info("Executing command: [%s]", str_command(command)) cmd_res = self._run_command(command) if self._res_serializer: diff --git a/NetTest/NetTestParse.py b/NetTest/NetTestParse.py index fbe5adc..2bfe3bf 100644 --- a/NetTest/NetTestParse.py +++ b/NetTest/NetTestParse.py @@ -314,8 +314,9 @@ class NetConfigParse(RecipeParser): class CommandSequenceParse(RecipeParser): def parse(self, node): sequences = self._recipe["sequences"] - sequences.append([]) + sequences.append({}) seq_num = len(sequences) - 1 + sequences[seq_num]["commands"] = []
self._seq_num = seq_num self._seq_node = node @@ -333,7 +334,7 @@ class CommandSequenceParse(RecipeParser): def _check_sequence(self, sequence): err = False bg_ids = {} - for i, command in enumerate(sequence): + for i, command in enumerate(sequence["commands"]): machine_id = command["machine_id"] if not machine_id in bg_ids: bg_ids[machine_id] = set() @@ -379,8 +380,8 @@ class CommandParse(RecipeParser): def parse(self, node): recipe = self._recipe command = {} - recipe["sequences"][self._seq_num].append(command) - self._cmd_num = len(recipe["sequences"][self._seq_num]) - 1 + recipe["sequences"][self._seq_num]["commands"].append(command) + self._cmd_num = len(recipe["sequences"][self._seq_num]["commands"]) - 1
if self._has_attribute(node, "machine_id"): machine_id = self._get_attribute(node, "machine_id", int) @@ -418,7 +419,7 @@ class CommandParse(RecipeParser): def _options(self, node, params): seq = self._seq_num cmd = self._cmd_num - self._recipe["sequences"][seq][cmd]["options"] = {} + self._recipe["sequences"][seq]["commands"][cmd]["options"] = {}
scheme = {"option": self._option} self._process_child_nodes(node, scheme) @@ -426,7 +427,7 @@ class CommandParse(RecipeParser): def _option(self, node, params): seq = self._seq_num cmd = self._cmd_num - options = self._recipe["sequences"][seq][cmd]["options"] + options = self._recipe["sequences"][seq]["commands"][cmd]["options"]
name = self._get_attribute(node, "name") if not name in options:
Signed-off-by: Jan Tluka jtluka@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)
Signed-off-by: Jan Tluka jtluka@redhat.com --- NetTest/NetTestParse.py | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/NetTest/NetTestParse.py b/NetTest/NetTestParse.py index 2bfe3bf..e16b3f5 100644 --- a/NetTest/NetTestParse.py +++ b/NetTest/NetTestParse.py @@ -321,6 +321,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)
Signed-off-by: Jan Tluka jtluka@redhat.com --- NetTest/NetTestController.py | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/NetTest/NetTestController.py b/NetTest/NetTestController.py index 27cf455..55c5b83 100644 --- a/NetTest/NetTestController.py +++ b/NetTest/NetTestController.py @@ -369,17 +369,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")
lnst-developers@lists.fedorahosted.org