[lnst] NetTestParse: Renaming to RecipeParse
by Jiří Pírko
commit 2105e49e2915981433141bdacdb5def470e706ac
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Thu Apr 18 19:51:46 2013 +0200
NetTestParse: Renaming to RecipeParse
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
lnst/Controller/NetTestController.py | 4 ++--
.../Controller/{NetTestParse.py => RecipeParse.py} | 6 +++---
lnst/Controller/SlaveMachineParse.py | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
---
diff --git a/lnst/Controller/NetTestController.py b/lnst/Controller/NetTestController.py
index 94ed7f5..def5258 100644
--- a/lnst/Controller/NetTestController.py
+++ b/lnst/Controller/NetTestController.py
@@ -28,7 +28,7 @@ from lnst.Common.Utils import wait_for, md5sum, dir_md5sum, create_tar_archive
from lnst.Common.Utils import check_process_running
from lnst.Common.NetTestCommand import NetTestCommandContext, NetTestCommand
from lnst.Common.NetTestCommand import str_command, CommandException
-from lnst.Controller.NetTestParse import NetTestParse
+from lnst.Controller.RecipeParse import RecipeParse
from lnst.Controller.SlavePool import SlavePool
from lnst.Common.ConnectionHandler import send_data, recv_data
from lnst.Common.ConnectionHandler import ConnectionHandler
@@ -64,7 +64,7 @@ class NetTestController:
self._mac_pool = MacPool(mac_pool_range[0],
mac_pool_range[1])
- ntparse = NetTestParse(recipe_path)
+ ntparse = RecipeParse(recipe_path)
ntparse.set_target(self._recipe)
ntparse.register_event_handler("provisioning_requirements_ready",
diff --git a/lnst/Controller/NetTestParse.py b/lnst/Controller/RecipeParse.py
similarity index 99%
rename from lnst/Controller/NetTestParse.py
rename to lnst/Controller/RecipeParse.py
index dab542a..2981099 100644
--- a/lnst/Controller/NetTestParse.py
+++ b/lnst/Controller/RecipeParse.py
@@ -1,5 +1,5 @@
"""
-This module defines NetTestParse class useful to parse xml recipes
+This module defines RecipeParse class useful to parse xml recipes
Copyright 2011 Red Hat, Inc.
Licensed under the GNU General Public License, version 2 as
@@ -20,9 +20,9 @@ from lnst.Common.NetUtils import normalize_hwaddr
from lnst.Common.Utils import bool_it
from lnst.Common.RecipePath import RecipePath
-class NetTestParse(LnstParser):
+class RecipeParse(LnstParser):
def __init__(self, recipe_filepath):
- super(NetTestParse, self).__init__()
+ super(RecipeParse, self).__init__()
self._filepath = recipe_filepath
self._rp = RecipePath(None, self._filepath)
diff --git a/lnst/Controller/SlaveMachineParse.py b/lnst/Controller/SlaveMachineParse.py
index d1de806..8c0a090 100644
--- a/lnst/Controller/SlaveMachineParse.py
+++ b/lnst/Controller/SlaveMachineParse.py
@@ -18,7 +18,7 @@ from lnst.Common.XmlProcessing import LnstParser
from lnst.Common.XmlProcessing import XmlDomTreeInit
from lnst.Common.XmlProcessing import XmlProcessingError
from lnst.Common.NetUtils import normalize_hwaddr
-from lnst.Controller.NetTestParse import ParamsParse
+from lnst.Controller.RecipeParse import ParamsParse
class SlaveMachineParse(LnstParser):
_machine_id = None
10 years, 11 months
[lnst] SlaveMachineParse: Moving from NetTestParse
by Jiří Pírko
commit a4b4c8d371c284dc0c4bb597a00255626b786614
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Thu Apr 18 19:51:45 2013 +0200
SlaveMachineParse: Moving from NetTestParse
This commit separates the SlaveMachineParser class to its separate
module as it is not related to parsing recipes.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
lnst/Controller/NetTestParse.py | 94 ---------------------------
lnst/Controller/SlaveMachineParse.py | 115 ++++++++++++++++++++++++++++++++++
lnst/Controller/SlavePool.py | 2 +-
3 files changed, 116 insertions(+), 95 deletions(-)
---
diff --git a/lnst/Controller/NetTestParse.py b/lnst/Controller/NetTestParse.py
index ed4a72e..dab542a 100644
--- a/lnst/Controller/NetTestParse.py
+++ b/lnst/Controller/NetTestParse.py
@@ -239,100 +239,6 @@ class RequirementsParse(LnstParser):
dev["hwaddr"] = normalize_hwaddr(dev["params"]["hwaddr"])
-class SlaveMachineParse(LnstParser):
- _machine_id = None
- _machine = None
-
- def set_machine(self, machine_id, machine):
- self._machine_id = machine_id
- self._machine = machine
-
- def parse(self, node):
- scheme = {"params": self._params,
- "netdevices": self._netdevices}
- params = {"target": self._machine["params"]}
- self._process_child_nodes(node, scheme, params)
-
- self._machine["params"]["skip_cleanup"] = False
- mandatory_params = ["hostname"]
- for mandatory in mandatory_params:
- if mandatory not in self._machine["params"]:
- msg = "Missing required parameter '%s'" % mandatory
- raise XmlProcessingError(msg, node)
-
- def _params(self, node, params):
- subparser = ParamsParse(self)
- subparser.set_params_dict(params["target"])
- subparser.parse(node)
-
- def _netdevices(self, node, params):
- scheme = {"netdevice": self._netdevice,
- "libvirt_create": self._libvirt_create}
-
- new_params = {"create": None}
- self._process_child_nodes(node, scheme, new_params)
-
- def _libvirt_create(self, node, params):
- scheme = {"netdevice": self._netdevice}
-
- new_params = {"create": "libvirt"}
- self._process_child_nodes(node, scheme, new_params)
-
- def _netdevice(self, node, params):
- machine = self._machine
- phys_id = self._get_attribute(node, "phys_id")
-
- dev = machine["netdevices"][phys_id] = {}
- dev["create"] = params["create"]
- dev["network"] = self._get_attribute(node, "network")
- dev["params"] = {}
-
- # parse device parameters
- scheme = {"params": self._params}
- params = {"target": dev["params"]}
- self._process_child_nodes(node, scheme, params)
-
- if "type" in dev["params"]:
- dev["type"] = dev["params"]["type"]
- else:
- msg = "Missing required parameter 'type'"
- raise XmlProcessingError(msg, node)
-
- # hwaddr parameter is optional for dynamic devices,
- # but it is required by non-dynamic devices
- if dev["create"] and "hwaddr" in dev["params"]:
- dev["hwaddr"] = normalize_hwaddr(dev["params"]["hwaddr"])
- else:
- if "hwaddr" in dev["params"]:
- dev["hwaddr"] = normalize_hwaddr(dev["params"]["hwaddr"])
- else:
- msg = "Missing required parameter 'hwaddr'"
- raise XmlProcessingError(msg, node)
-
- # name parameter is only valid when the device is not dynamic
- if "name" in dev["params"]:
- if dev["create"]:
- msg = "'name' parameter is not valid with dynamic devices"
- raise XmlProcessingError(msg, node)
- else:
- dev["name"] = dev["params"]["name"]
-
- # bridge parameter is valid only when the device is dynamic
- if "libvirt_bridge" in dev["params"]:
- if dev["create"] == "libvirt":
- dev["libvirt_bridge"] = dev["params"]["libvirt_bridge"]
- else:
- msg = "'libvirt_bridge' parameter is not valid with" \
- "dynamic devices"
- raise XmlProcessingError(msg, node)
-
- try:
- self._trigger_event("netdevice_ready",
- {"machine_id": self._machine_id, "dev_id": phys_id})
- except Exception as exc:
- logging.error(XmlProcessingError(str(exc), node))
- raise
-
class NetConfigParse(LnstParser):
_machine_id = None
_machine = None
diff --git a/lnst/Controller/SlaveMachineParse.py b/lnst/Controller/SlaveMachineParse.py
new file mode 100644
index 0000000..d1de806
--- /dev/null
+++ b/lnst/Controller/SlaveMachineParse.py
@@ -0,0 +1,115 @@
+"""
+This module defines SlaveMachineParse class useful to parse XML machine
+descriptions for the slave pool
+
+Copyright 2013 Red Hat, Inc.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+rpazdera(a)redhat.com (Radek Pazdera)
+"""
+
+import logging
+import os
+import re
+from lnst.Common.XmlProcessing import LnstParser
+from lnst.Common.XmlProcessing import XmlDomTreeInit
+from lnst.Common.XmlProcessing import XmlProcessingError
+from lnst.Common.NetUtils import normalize_hwaddr
+from lnst.Controller.NetTestParse import ParamsParse
+
+class SlaveMachineParse(LnstParser):
+ _machine_id = None
+ _machine = None
+
+ def set_machine(self, machine_id, machine):
+ self._machine_id = machine_id
+ self._machine = machine
+
+ def parse(self, node):
+ scheme = {"params": self._params,
+ "netdevices": self._netdevices}
+ params = {"target": self._machine["params"]}
+ self._process_child_nodes(node, scheme, params)
+
+ self._machine["params"]["skip_cleanup"] = False
+ mandatory_params = ["hostname"]
+ for mandatory in mandatory_params:
+ if mandatory not in self._machine["params"]:
+ msg = "Missing required parameter '%s'" % mandatory
+ raise XmlProcessingError(msg, node)
+
+ def _params(self, node, params):
+ subparser = ParamsParse(self)
+ subparser.set_params_dict(params["target"])
+ subparser.parse(node)
+
+ def _netdevices(self, node, params):
+ scheme = {"netdevice": self._netdevice,
+ "libvirt_create": self._libvirt_create}
+
+ new_params = {"create": None}
+ self._process_child_nodes(node, scheme, new_params)
+
+ def _libvirt_create(self, node, params):
+ scheme = {"netdevice": self._netdevice}
+
+ new_params = {"create": "libvirt"}
+ self._process_child_nodes(node, scheme, new_params)
+
+ def _netdevice(self, node, params):
+ machine = self._machine
+ phys_id = self._get_attribute(node, "phys_id")
+
+ dev = machine["netdevices"][phys_id] = {}
+ dev["create"] = params["create"]
+ dev["network"] = self._get_attribute(node, "network")
+ dev["params"] = {}
+
+ # parse device parameters
+ scheme = {"params": self._params}
+ params = {"target": dev["params"]}
+ self._process_child_nodes(node, scheme, params)
+
+ if "type" in dev["params"]:
+ dev["type"] = dev["params"]["type"]
+ else:
+ msg = "Missing required parameter 'type'"
+ raise XmlProcessingError(msg, node)
+
+ # hwaddr parameter is optional for dynamic devices,
+ # but it is required by non-dynamic devices
+ if dev["create"] and "hwaddr" in dev["params"]:
+ dev["hwaddr"] = normalize_hwaddr(dev["params"]["hwaddr"])
+ else:
+ if "hwaddr" in dev["params"]:
+ dev["hwaddr"] = normalize_hwaddr(dev["params"]["hwaddr"])
+ else:
+ msg = "Missing required parameter 'hwaddr'"
+ raise XmlProcessingError(msg, node)
+
+ # name parameter is only valid when the device is not dynamic
+ if "name" in dev["params"]:
+ if dev["create"]:
+ msg = "'name' parameter is not valid with dynamic devices"
+ raise XmlProcessingError(msg, node)
+ else:
+ dev["name"] = dev["params"]["name"]
+
+ # bridge parameter is valid only when the device is dynamic
+ if "libvirt_bridge" in dev["params"]:
+ if dev["create"] == "libvirt":
+ dev["libvirt_bridge"] = dev["params"]["libvirt_bridge"]
+ else:
+ msg = "'libvirt_bridge' parameter is not valid with" \
+ "dynamic devices"
+ raise XmlProcessingError(msg, node)
+
+ try:
+ self._trigger_event("netdevice_ready",
+ {"machine_id": self._machine_id, "dev_id": phys_id})
+ except Exception as exc:
+ logging.error(XmlProcessingError(str(exc), node))
+ raise
diff --git a/lnst/Controller/SlavePool.py b/lnst/Controller/SlavePool.py
index c98bb24..d884c05 100644
--- a/lnst/Controller/SlavePool.py
+++ b/lnst/Controller/SlavePool.py
@@ -20,7 +20,7 @@ import copy
from xml.dom import minidom
from lnst.Common.XmlProcessing import XmlDomTreeInit
from lnst.Common.NetUtils import test_tcp_connection
-from lnst.Controller.NetTestParse import SlaveMachineParse
+from lnst.Controller.SlaveMachineParse import SlaveMachineParse
class SlavePool:
"""
10 years, 11 months
[lnst] XmlProcessing: Renaming RecipeParser to LnstParser
by Jiří Pírko
commit 359718249b20e230856b4f9e9de1fb586b971c87
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Thu Apr 18 19:51:44 2013 +0200
XmlProcessing: Renaming RecipeParser to LnstParser
The name RecipeParser is ambiguous, because the class is used as base
for both recipe parsers and also slave machine config files.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
lnst/Common/XmlProcessing.py | 28 ++++++++++++----------
lnst/Controller/NetTestController.py | 2 +-
lnst/Controller/NetTestParse.py | 42 +++++++++++++++++-----------------
3 files changed, 37 insertions(+), 35 deletions(-)
---
diff --git a/lnst/Common/XmlProcessing.py b/lnst/Common/XmlProcessing.py
index 80e9aca..83bd630 100644
--- a/lnst/Common/XmlProcessing.py
+++ b/lnst/Common/XmlProcessing.py
@@ -205,39 +205,41 @@ class XmlParser(object):
return res
-class RecipeParser(XmlParser):
+class LnstParser(XmlParser):
""" Enhanced XmlParser
This class enhances XmlParser with advanced features that are
- used in parsing XML recipe files. All recipe (sub)parsers should
+ used in parsing LNST XML files. All (sub)parsers should
use this as their base class.
"""
- _recipe = None
+ _data = None
_template_proc = None
_include_root = None
_events_enabled = None
_event_handlers = None
def __init__(self, parent=None):
- super(RecipeParser, self).__init__()
+ super(LnstParser, self).__init__()
if parent:
- self._recipe = parent._recipe
+ self._data = parent._data
self._template_proc = parent._template_proc
self._include_root = parent._include_root
self._events_enabled = parent._events_enabled
self._event_handlers = parent._event_handlers
else:
- self._recipe = {}
+ self._data = {}
self._template_proc = XmlTemplates()
self._include_root = os.getcwd()
self._events_enabled = True
self._event_handlers = {}
- def set_recipe(self, recipe):
- self._recipe = recipe
- self._template_proc.set_machines(recipe["machines"])
+ def set_target(self, data_dict):
+ self._data = data_dict
+ # TODO: This should be removed and done differently after we
+ # figure out the new design of template functions
+ self._template_proc.set_machines(data_dict["machines"])
def set_definitions(self, defs):
self._template_proc.set_definitions(defs)
@@ -276,7 +278,7 @@ class RecipeParser(XmlParser):
if new_ns_level:
self._template_proc.add_namespace_level()
- parent = super(RecipeParser, self)
+ parent = super(LnstParser, self)
result = parent._process_child_nodes(node, scheme, params,
default_handler)
@@ -324,14 +326,14 @@ class RecipeParser(XmlParser):
if not node.hasAttribute(name):
node.setAttribute(name, value)
- parent = super(RecipeParser, self)
+ parent = super(LnstParser, self)
parent._process_node(node, handler, params)
if old_include_root:
self._include_root = old_include_root
def _get_attribute(self, node, attr_name, conversion_cb=None):
- parent = super(RecipeParser, self)
+ parent = super(LnstParser, self)
raw_attr_val = parent._get_attribute(node, attr_name)
try:
@@ -342,7 +344,7 @@ class RecipeParser(XmlParser):
return self._convert_string(node, attr_val, conversion_cb)
def _get_text_content(self, node, conversion_cb=None):
- parent = super(RecipeParser, self)
+ parent = super(LnstParser, self)
raw_content = parent._get_text_content(node)
try:
diff --git a/lnst/Controller/NetTestController.py b/lnst/Controller/NetTestController.py
index ffa2bf8..94ed7f5 100644
--- a/lnst/Controller/NetTestController.py
+++ b/lnst/Controller/NetTestController.py
@@ -65,7 +65,7 @@ class NetTestController:
mac_pool_range[1])
ntparse = NetTestParse(recipe_path)
- ntparse.set_recipe(self._recipe)
+ ntparse.set_target(self._recipe)
ntparse.register_event_handler("provisioning_requirements_ready",
self._prepare_provisioning)
diff --git a/lnst/Controller/NetTestParse.py b/lnst/Controller/NetTestParse.py
index caa15a0..ed4a72e 100644
--- a/lnst/Controller/NetTestParse.py
+++ b/lnst/Controller/NetTestParse.py
@@ -13,14 +13,14 @@ jpirko(a)redhat.com (Jiri Pirko)
import logging
import os
import re
-from lnst.Common.XmlProcessing import RecipeParser
+from lnst.Common.XmlProcessing import LnstParser
from lnst.Common.XmlProcessing import XmlDomTreeInit
from lnst.Common.XmlProcessing import XmlProcessingError
from lnst.Common.NetUtils import normalize_hwaddr
from lnst.Common.Utils import bool_it
from lnst.Common.RecipePath import RecipePath
-class NetTestParse(RecipeParser):
+class NetTestParse(LnstParser):
def __init__(self, recipe_filepath):
super(NetTestParse, self).__init__()
@@ -42,7 +42,7 @@ class NetTestParse(RecipeParser):
second_pass.parse(xml_dom)
-class FirstPass(RecipeParser):
+class FirstPass(LnstParser):
"""
Purpose of the first pass through the recipe is to detect
machine requirements for provisioning.
@@ -52,7 +52,7 @@ class FirstPass(RecipeParser):
"""
def parse(self, node):
- self._recipe["provisioning"]["setup_requirements"] = {}
+ self._data["provisioning"]["setup_requirements"] = {}
if node.nodeType == node.DOCUMENT_NODE:
scheme = {"lnstrecipe": self._lnstrecipe}
@@ -80,7 +80,7 @@ class FirstPass(RecipeParser):
default_handler=self._ignore_tag)
def _requirements(self, node, params):
- machine_req = self._recipe["provisioning"]["setup_requirements"]
+ machine_req = self._data["provisioning"]["setup_requirements"]
m_id = params["id"]
template = {}
template["netdevices"] = {}
@@ -94,10 +94,10 @@ class FirstPass(RecipeParser):
pass
-class SecondPass(RecipeParser):
+class SecondPass(LnstParser):
"""
Second pass makes sure all recognized values from the recipe
- are properly saved into the self._recipe.
+ are properly saved into the self._data.
This is where the real parsing is done.
"""
@@ -134,14 +134,14 @@ class SecondPass(RecipeParser):
subparser.parse(node)
def _command_sequence(self, node, params):
- if not "sequences" in self._recipe:
- self._recipe["sequences"] = []
+ if not "sequences" in self._data:
+ self._data["sequences"] = []
subparser = CommandSequenceParse(self)
subparser.parse(node)
-class MachineParse(RecipeParser):
+class MachineParse(LnstParser):
_target = "machines"
def set_type(self, machine_type):
@@ -155,7 +155,7 @@ class MachineParse(RecipeParser):
def parse(self, node):
self._id = self._get_attribute(node, "id")
- recipe = self._recipe
+ recipe = self._data
self._machine = recipe["machines"][self._id]
self._machine["netconfig"] = {}
@@ -175,7 +175,7 @@ class MachineParse(RecipeParser):
logging.error(XmlProcessingError(str(exc), node))
raise
-class ParamsParse(RecipeParser):
+class ParamsParse(LnstParser):
_params = None
def set_params_dict(self, target):
@@ -195,7 +195,7 @@ class ParamsParse(RecipeParser):
self._params[name] = value
-class RequirementsParse(RecipeParser):
+class RequirementsParse(LnstParser):
_requirements = None
def set_template(self, tmp_dict):
@@ -239,7 +239,7 @@ class RequirementsParse(RecipeParser):
dev["hwaddr"] = normalize_hwaddr(dev["params"]["hwaddr"])
-class SlaveMachineParse(RecipeParser):
+class SlaveMachineParse(LnstParser):
_machine_id = None
_machine = None
@@ -333,7 +333,7 @@ class SlaveMachineParse(RecipeParser):
logging.error(XmlProcessingError(str(exc), node))
raise
-class NetConfigParse(RecipeParser):
+class NetConfigParse(LnstParser):
_machine_id = None
_machine = None
@@ -467,9 +467,9 @@ class NetConfigParse(RecipeParser):
self._process_child_nodes(node, scheme, params)
-class CommandSequenceParse(RecipeParser):
+class CommandSequenceParse(LnstParser):
def parse(self, node):
- sequences = self._recipe["sequences"]
+ sequences = self._data["sequences"]
sequences.append({})
seq_num = len(sequences) - 1
sequences[seq_num]["commands"] = []
@@ -532,7 +532,7 @@ class CommandSequenceParse(RecipeParser):
raise XmlProcessingError(msg, self._seq_node)
-class CommandParse(RecipeParser):
+class CommandParse(LnstParser):
_seq_num = None
_cmd_num = None
@@ -540,7 +540,7 @@ class CommandParse(RecipeParser):
self._seq_num = num
def parse(self, node):
- recipe = self._recipe
+ recipe = self._data
command = {}
recipe["sequences"][self._seq_num]["commands"].append(command)
self._cmd_num = len(recipe["sequences"][self._seq_num]["commands"]) - 1
@@ -607,7 +607,7 @@ class CommandParse(RecipeParser):
def _options(self, node, params):
seq = self._seq_num
cmd = self._cmd_num
- self._recipe["sequences"][seq]["commands"][cmd]["options"] = {}
+ self._data["sequences"][seq]["commands"][cmd]["options"] = {}
scheme = {"option": self._option}
self._process_child_nodes(node, scheme)
@@ -615,7 +615,7 @@ class CommandParse(RecipeParser):
def _option(self, node, params):
seq = self._seq_num
cmd = self._cmd_num
- options = self._recipe["sequences"][seq]["commands"][cmd]["options"]
+ options = self._data["sequences"][seq]["commands"][cmd]["options"]
name = self._get_attribute(node, "name")
if not name in options:
10 years, 11 months
[PATCH] lnst-ctl: Allow only eth interfaces in pool
by Radek Pazdera
This patch restricts putting any other interfaces than eth to the pool
configuration files.
These change required some changes in the error handling. The exceptions
are now logged in the lnst-ctl file directly, so all exceptions comming
from the NetTestController class will be caught.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
---
lnst-ctl | 9 +++++----
lnst/Controller/NetTestController.py | 31 +++++++++++--------------------
lnst/Controller/SlaveMachineParse.py | 11 ++++++++---
3 files changed, 24 insertions(+), 27 deletions(-)
diff --git a/lnst-ctl b/lnst-ctl
index 17ce6cd..26b15e1 100755
--- a/lnst-ctl
+++ b/lnst-ctl
@@ -17,7 +17,7 @@ import logging
import os
import re
import datetime
-from lnst.Common.Logs import LoggingCtl
+from lnst.Common.Logs import LoggingCtl, log_exc_traceback
from lnst.Common.Config import Config
from lnst.Controller.NetTestController import NetTestController, NetTestError
from lnst.Controller.NetTestResultSerializer import NetTestResultSerializer
@@ -72,9 +72,10 @@ def get_recipe_result(args, file_path, cleanup,
res = None
try:
- res = process_recipe(args, file_path, cleanup,
- res_serializer, packet_capture, config, log_ctl)
- except NetTestError as err:
+ res = process_recipe(args, file_path, cleanup, res_serializer,
+ packet_capture, config, log_ctl)
+ except Exception as err:
+ log_exc_traceback()
logging.error(err)
return ((file_path, res))
diff --git a/lnst/Controller/NetTestController.py b/lnst/Controller/NetTestController.py
index bf80fbe..8adde13 100644
--- a/lnst/Controller/NetTestController.py
+++ b/lnst/Controller/NetTestController.py
@@ -20,7 +20,6 @@ import tempfile
from time import sleep
from xmlrpclib import Binary
from pprint import pprint, pformat
-from lnst.Common.Logs import log_exc_traceback
from lnst.Common.XmlRpc import ServerProxy, ServerException
from lnst.Common.NetUtils import MacPool
from lnst.Common.VirtUtils import VirtNetCtl, VirtDomainCtl, BridgeCtl
@@ -179,11 +178,10 @@ class NetTestController:
try:
self._parser.parse_recipe()
except Exception as exc:
- logging.debug("Exception raised during recipe parsing. "\
- "Deconfiguring machines.")
- log_exc_traceback()
+ logging.error("Exception raised during recipe parsing. "\
+ "Deconfiguring machines.")
self._cleanup_slaves()
- raise NetTestError(exc)
+ raise
def _run_command(self, command):
if "desc" in command:
@@ -237,23 +235,16 @@ class NetTestController:
err = None
try:
res = self._run_recipe()
- except ServerException as exc:
- err = NetTestError(exc)
except Exception as exc:
- logging.info("Recipe execution terminated by unexpected exception")
- log_exc_traceback()
- err = exc
-
- if packet_capture:
- self._stop_packet_capture()
- self._gather_capture_files()
-
- self._cleanup_slaves()
+ logging.error("Recipe execution terminated by unexpected exception")
+ raise
+ finally:
+ if packet_capture:
+ self._stop_packet_capture()
+ self._gather_capture_files()
+ self._cleanup_slaves()
- if not err:
- return res
- else:
- raise err
+ return res
def _run_recipe(self):
overall_res = True
diff --git a/lnst/Controller/SlaveMachineParse.py b/lnst/Controller/SlaveMachineParse.py
index 0be18d6..20915c4 100644
--- a/lnst/Controller/SlaveMachineParse.py
+++ b/lnst/Controller/SlaveMachineParse.py
@@ -73,12 +73,17 @@ class SlaveMachineParse(LnstParser):
params = {"target": iface["params"]}
self._process_child_nodes(node, scheme, params)
- if "type" in iface["params"]:
- iface["type"] = iface["params"]["type"]
- else:
+ if "type" not in iface["params"]:
msg = "Missing required parameter 'type'"
raise XmlProcessingError(msg, node)
+ iface["type"] = iface["params"]["type"]
+ if iface["type"] not in ["eth"]:
+ msg = "Interface type '%s' is not allowed here. " \
+ "Interface types other than 'eth' mus be configured " \
+ "in LNST recipes directly." % iface["type"]
+ raise XmlProcessingError(msg, node)
+
# hwaddr parameter is optional for dynamic interface,
# but it is required by non-dynamic interfaces
if iface["create"] and "hwaddr" in iface["params"]:
--
1.7.7.6
10 years, 11 months
[PATCH] Machine: Fixing copy-paste error
by Radek Pazdera
This patch fixes a copy-paste error in the factory method of Machine
for unused interfaces. The parameters were swapped.
Reported-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
---
lnst/Controller/Machine.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/lnst/Controller/Machine.py b/lnst/Controller/Machine.py
index ef716ec..7abb484 100644
--- a/lnst/Controller/Machine.py
+++ b/lnst/Controller/Machine.py
@@ -76,7 +76,7 @@ class Machine(object):
return self._add_interface(if_id, if_type, StaticInterface)
def new_unused_interface(self, if_type):
- return self._add_interface(if_type, None, UnusedInterface)
+ return self._add_interface(None, if_type, UnusedInterface)
def new_virtual_interface(self, if_id, if_type):
return self._add_interface(if_id, if_type, VirtualInterface)
--
1.7.7.6
10 years, 11 months
[PATCH] SlavePool: libvirt_domain attribute bugfix
by Radek Pazdera
I forgot to add a condition while reading the libvirt_domain argument
from the SlavePool XML and therefore an exception was raised in case
the argument was missing.
This should fix the problem
Reported-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
---
lnst/Controller/SlavePool.py | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/lnst/Controller/SlavePool.py b/lnst/Controller/SlavePool.py
index 9674fb7..dc13f23 100644
--- a/lnst/Controller/SlavePool.py
+++ b/lnst/Controller/SlavePool.py
@@ -138,7 +138,10 @@ class SlavePool:
pm = self._pool[pm_id]
hostname = pm["params"]["hostname"]
- libvirt_domain = pm["params"]["libvirt_domain"]
+
+ libvirt_domain = None
+ if "libvirt_domain" in pm["params"]:
+ libvirt_domain = pm["params"]["libvirt_domain"]
machine = Machine(tm_id, hostname, libvirt_domain)
--
1.7.7.6
10 years, 11 months
[lnst trac] #68: Regression: Recipe sets don't work
by fedora-badges
#68: Regression: Recipe sets don't work
----------------------+-----------------------------
Reporter: rpazdera | Owner:
Type: defect | Status: new
Priority: major | Milestone: Stable Release
Component: lnst-ctl | Version: git
Keywords: | Blocked By:
Blocking: |
----------------------+-----------------------------
lnst-ctl crashes after the first recipe in the set.
This bug is easily reproducible using the smoke tests in git.
--
Ticket URL: <https://fedorahosted.org/lnst/ticket/68>
lnst <https://fedorahosted.org/lnst/>
Linux Network Stack Test
10 years, 11 months
[lnst] Reimplementing TCPConnect and TCPListen test as a test tool in C
by Jiří Pírko
commit 18b1a53fd09b02cab0117b08ab91e8881a8e0e7d
Author: Jan Tluka <jtluka(a)redhat.com>
Date: Fri Apr 12 13:04:18 2013 +0200
Reimplementing TCPConnect and TCPListen test as a test tool in C
The TCPConnect and TCPListen written in Python had issues that were hard
to debug. The main problem was with the test hangs during tests. Another
issue is that these tests are using threads. Since the mixing of fork and
threading is strongly discouraged in Python I rewrote these tests as test
tools tcp_connect and tcp_listen under tcp_conn directory in C language
using direct system calls for networking routines and using processes for
handling connections.
Example usage:
<command_sequence>
<define>
<alias name="my_range" value="10000-10050" />
</define>
<command machine_id="testmachine2" type="exec" from="tcp_conn"
value="./tcp_listen -p {$my_range} -a {ip(testmachine2,testifc1)} -c"
bg_id="1"/>
<command type="ctl_wait" value="3" />
<command machine_id="testmachine1" type="exec" from="tcp_conn"
value="./tcp_connect -p {$my_range} -a {ip(testmachine2,testifc1)} -c"
bg_id="2"/>
<command machine_id="testmachine1" type="exec" from="tcp_conn"
value="./tcp_listen -p {$my_range} -a {ip(testmachine1,testifc1)} -c"
bg_id="3"/>
<command type="ctl_wait" value="3" />
<command machine_id="testmachine2" type="exec" from="tcp_conn"
value="./tcp_connect -p {$my_range} -a {ip(testmachine1,testifc1)} -c"
bg_id="4"/>
<command type="ctl_wait" value="100" />
<command machine_id="testmachine1" type="intr" value="2" />
<command machine_id="testmachine2" type="intr" value="1" />
<command machine_id="testmachine2" type="intr" value="4" />
<command machine_id="testmachine1" type="intr" value="3" />
</command_sequence>
Options are common both for server and client part:
-p port_range ... specifies the range of ports to use under test
-c ... use continuous mode otherwise just do a single
connection and end
-d ... turn on debug output, use with caution since this
produces a lot of data
Signed-off-by: Jan Tluka <jtluka(a)redhat.com>
test_modules/TestTCPConnect.py | 205 ---------------------------------
test_modules/TestTCPListen.py | 198 --------------------------------
test_tools/tcp_conn/Makefile | 12 ++
test_tools/tcp_conn/lnst-setup.sh | 3 +
test_tools/tcp_conn/tcp_connect.c | 202 ++++++++++++++++++++++++++++++++
test_tools/tcp_conn/tcp_listen.c | 229 +++++++++++++++++++++++++++++++++++++
6 files changed, 446 insertions(+), 403 deletions(-)
---
diff --git a/test_tools/tcp_conn/Makefile b/test_tools/tcp_conn/Makefile
new file mode 100644
index 0000000..2e8f5e6
--- /dev/null
+++ b/test_tools/tcp_conn/Makefile
@@ -0,0 +1,12 @@
+CC=gcc
+
+all: tcp_listen tcp_connect
+
+tcp_listen: tcp_listen.c
+ $(CC) -o tcp_listen tcp_listen.c
+
+tcp_connect: tcp_connect.c
+ $(CC) -o tcp_connect tcp_connect.c
+
+clean:
+ rm -f tcp_connect tcp_listen
diff --git a/test_tools/tcp_conn/lnst-setup.sh b/test_tools/tcp_conn/lnst-setup.sh
new file mode 100755
index 0000000..2aad486
--- /dev/null
+++ b/test_tools/tcp_conn/lnst-setup.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+make
diff --git a/test_tools/tcp_conn/tcp_connect.c b/test_tools/tcp_conn/tcp_connect.c
new file mode 100644
index 0000000..598ac80
--- /dev/null
+++ b/test_tools/tcp_conn/tcp_connect.c
@@ -0,0 +1,202 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include <errno.h>
+#include <signal.h>
+
+
+int connection_handlers[1024];
+int handlers_count;
+
+int debug_on = 0;
+int cont = 0;
+
+int usage()
+{
+ printf("./tcp_connect -p [port_range] -a [ipaddr]\n");
+ return 0;
+}
+
+#define MSG_MAX 256
+char msg[MSG_MAX];
+
+int debug(char* msg)
+{
+ if (debug_on)
+ {
+ printf("Debug: %s\n", msg);
+ }
+}
+
+void terminate_connections(int p)
+{
+ int cc;
+
+ debug("signalled");
+ for (cc=0; cc < handlers_count; cc++)
+ {
+ snprintf(msg, MSG_MAX, "killing process %i", connection_handlers[cc]);
+ debug(msg);
+ kill(connection_handlers[cc], SIGKILL);
+ }
+}
+
+int handle_connections(char* host, int port)
+{
+ int conn_sock;
+ int remote_sock;
+ struct sockaddr_in my_addr;
+ struct sockaddr remote;
+ int end_loop = 0;
+ char data[] = "abcdefghijklmnopqrstuvwxyz0123456789";
+ char buf[21*10*strlen(data)+1];
+
+ snprintf(msg, MSG_MAX, "Starting connection on %s port %i", host, port);
+ debug(msg);
+
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_port = htons(port);
+ if (inet_aton(host, &(my_addr.sin_addr)) == 0)
+ {
+ printf("failed on inet_aton()\n");
+ return 1;
+ }
+
+ do
+ {
+ conn_sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (conn_sock == -1)
+ {
+ perror("fail on socket()");
+ return 1;
+ }
+
+ if (connect(conn_sock, (struct sockaddr*) &my_addr, sizeof(struct sockaddr_in)) == -1)
+ {
+ perror("fail on connect");
+ return 1;
+ }
+
+ int bursts = 5*(random() % 10) + 1;
+ int b;
+ int sum = 0;
+
+ for (b=0; b < bursts; b++)
+ {
+ int parts = 20*(random() % 10) + 1;
+ int j;
+
+ sum += parts*strlen(data);
+ for (j = 0; j < parts; j++)
+ {
+ strncpy(buf + (j*strlen(data)), data, strlen(data));
+ }
+
+ int wr_rc = write(conn_sock, buf, parts * strlen(data));
+ usleep(100*(random()%100));
+ }
+
+ snprintf(msg, MSG_MAX, "sent %i bytes (bursts: %i)", sum, bursts);
+ debug(msg);
+ snprintf(msg, MSG_MAX, "closing connection on port %i", port);
+ debug(msg);
+
+ close(conn_sock);
+ } while (cont);
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int rc;
+ int p;
+ char port_str[256];
+ char str_port_start[128];
+ char str_port_end[128];
+ char host_str[16] = "\0";
+ int start_port;
+ int end_port;
+ int opt;
+ char *delimiter;
+ struct sigaction sa;
+
+ sa.sa_handler = &terminate_connections;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ handlers_count = 0;
+
+ /* collect program args */
+ while ((opt = getopt(argc, argv, "p:a:dc")) != -1) {
+ switch (opt) {
+ case 'p':
+ strncpy(port_str, optarg, 256);
+ port_str[256-1]='\0';
+ delimiter = strchr(port_str, '-');
+ if (delimiter == NULL)
+ {
+ usage();
+ }
+ strncpy(str_port_start, port_str, delimiter - port_str);
+ str_port_start[delimiter - port_str] = '\0';
+ strncpy(str_port_end, delimiter+1, strlen(port_str) - (delimiter+1-port_str));
+ start_port = atoi(str_port_start);
+ end_port = atoi(str_port_end);
+ break;
+ case 'a':
+ strncpy(host_str, optarg, 64);
+ host_str[16-1] = '\0';
+ break;
+ case 'd':
+ debug_on = 1;
+ break;
+ case 'c':
+ cont = 1;
+ break;
+ }
+ }
+
+ if (strlen(host_str) == 0)
+ {
+ usage();
+ return 1;
+ }
+
+ /* spawn process to handle every port specified */
+ for (p = start_port; p < end_port; p++){
+ if ((rc = fork()) > 0)
+ {
+ /* parent, add pid to the list */
+ connection_handlers[handlers_count++] = rc;
+ }
+ else if (rc == 0)
+ {
+ /* child */
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ handle_connections(host_str, p);
+ return 0;
+ }
+ }
+
+ /* gather children */
+ int child_status;
+ int i;
+ for (i=0; i < handlers_count; i++)
+ {
+ wait(&child_status);
+ debug("worker finished");
+ }
+
+ debug("tcp_connect finished");
+
+ return 0;
+}
diff --git a/test_tools/tcp_conn/tcp_listen.c b/test_tools/tcp_conn/tcp_listen.c
new file mode 100644
index 0000000..df07f69
--- /dev/null
+++ b/test_tools/tcp_conn/tcp_listen.c
@@ -0,0 +1,229 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include <errno.h>
+#include <signal.h>
+
+int listener_count;
+int listeners[1024];
+
+int connection_count;
+int debug_on = 0;
+int cont = 0;
+
+int usage()
+{
+ printf("./tcp_listen -p [port_range] -a [ipaddr]\n");
+ return 0;
+}
+
+int debug(char* msg)
+{
+ if (debug_on)
+ {
+ printf("Debug: %s\n", msg);
+ }
+}
+
+#define MSG_MAX 256
+char msg[MSG_MAX];
+
+void terminate_connections(int p)
+{
+ int l;
+
+ debug("signal received, killing servers");
+ for (l=0; l < listener_count; l++)
+ {
+ snprintf(msg, MSG_MAX, "killing process %i", listeners[l]);
+ debug(msg);
+ kill(listeners[l], SIGKILL);
+ }
+}
+
+void connection_counter(int p)
+{
+ debug("increase counter");
+ connection_count += 1;
+}
+
+int handle_connections(char* host, int port)
+{
+ int listen_sock;
+ struct sockaddr_in my_addr;
+ socklen_t my_addr_size = sizeof(my_addr);
+ int remote_sock;
+ struct sockaddr_in remote;
+ socklen_t remote_size = sizeof(remote);
+ char data[256];
+
+ snprintf(msg, MSG_MAX, "Starting listener on %s port %i", host, port);
+ debug(msg);
+
+ bzero(&my_addr, my_addr_size);
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_port = htons(port);
+ if (inet_aton(host, &(my_addr.sin_addr)) == 0)
+ {
+ printf("failed on inet_aton()\n");
+ return 1;
+ }
+
+ if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ perror("fail on socket creation");
+ return 1;
+ }
+
+ if (bind(listen_sock, (struct sockaddr*) &my_addr, sizeof(struct sockaddr_in)))
+ {
+ perror("fail on bind");
+ return 1;
+ }
+
+ if (listen(listen_sock, 0))
+ {
+ perror("fail on listen");
+ return 1;
+ }
+
+ do
+ {
+ struct in_addr ra = remote.sin_addr;
+ char host_address_str[256];
+ ssize_t read_rc;
+
+ /* handle single connection */
+ bzero(&remote, remote_size);
+ remote_sock = accept(listen_sock, (struct sockaddr*) &remote, &remote_size);
+ if (remote_sock == -1)
+ {
+ perror("failure on accept");
+ close(listen_sock);
+ return 1;
+ }
+
+ inet_ntop(AF_INET, &ra, host_address_str, 255);
+ snprintf(msg, MSG_MAX, "accepted connection from host %s port %i", host_address_str, port);
+ debug(msg);
+
+ int sum = 0;
+ while (read_rc = read(remote_sock, &data, 256))
+ {
+ sum += read_rc;
+ }
+
+ snprintf(msg, MSG_MAX, "connection closed, read %d bytes (%i)", sum, port);
+ debug(msg);
+ close(remote_sock);
+ kill(getppid(), SIGUSR1);
+ } while (cont);
+
+ close(listen_sock);
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int rc;
+ int p;
+ char port_str[256];
+ char str_port_start[128];
+ char str_port_end[128];
+ char host_str[16] = "\0";
+ int start_port;
+ int end_port;
+ int opt;
+ char *delimiter;
+ struct sigaction sa;
+ struct sigaction sa2;
+
+ sa.sa_handler = &terminate_connections;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ sa2.sa_handler = &connection_counter;
+ sigaction(SIGUSR1, &sa2, NULL);
+
+ /* collect program args */
+ while ((opt = getopt(argc, argv, "p:a:dc")) != -1) {
+ switch (opt) {
+ case 'p':
+ strncpy(port_str, optarg, 256);
+ port_str[256-1]='\0';
+ delimiter = strchr(port_str, '-');
+ if (delimiter == NULL)
+ {
+ usage();
+ }
+ strncpy(str_port_start, port_str, delimiter - port_str);
+ str_port_start[delimiter - port_str] = '\0';
+ strncpy(str_port_end, delimiter+1, strlen(port_str) - (delimiter+1-port_str));
+ start_port = atoi(str_port_start);
+ end_port = atoi(str_port_end);
+ break;
+ case 'a':
+ strncpy(host_str, optarg, 64);
+ host_str[16-1] = '\0';
+ break;
+ case 'd':
+ debug_on = 1;
+ break;
+ case 'c':
+ cont = 1;
+ }
+ }
+
+ if (strlen(host_str) == 0)
+ {
+ usage();
+ return 1;
+ }
+
+ listener_count = 0;
+ /* spawn process to handle every port specified */
+ for (p = start_port; p < end_port; p++){
+ if ((rc = fork()) > 0)
+ {
+ /* parent, add pid to the list */
+ listeners[listener_count++] = rc;
+ }
+ else if (rc == 0)
+ {
+ /* child */
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ /* run the main processing loop */
+ handle_connections(host_str, p);
+ return 0;
+ }
+ }
+
+ /* gather children */
+ int child_status;
+ int i;
+ for (i=0; i < listener_count; i++)
+ {
+ int rc = -1;
+ while (wait(&child_status) == -1 && errno == EINTR)
+ {
+ ;
+ }
+ debug("worker finished");
+ }
+
+ debug("tcp_listener finished");
+
+ printf("handled %i connections\n", connection_count);
+
+ return 0;
+}
10 years, 11 months