commit 627c366824d04ed8ad8f78ed2151648540e31a8a
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Fri Oct 17 16:16:00 2014 +0200
lnst-ctl: add multi match option
This patch adds a new option [-u|--multi-match] to lnst-ctl that makes
each recipe run with every possible pool match. This can be usefull for
writing recipes that specify a small set of requirements - these can
then be run in many different machine setups by just adding this one
argument.
The patch also modifies the NetTestResultSerializer so that these
matches are logged properly, and the result summary contains information
about the match.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst-ctl | 80 +++++++++++++++++++---------
lnst/Controller/NetTestResultSerializer.py | 25 ++++++++-
2 files changed, 77 insertions(+), 28 deletions(-)
---
diff --git a/lnst-ctl b/lnst-ctl
index 0f1f46e..6a0e924 100755
--- a/lnst-ctl
+++ b/lnst-ctl
@@ -22,6 +22,7 @@ from lnst.Common.Config import lnst_config
from lnst.Common.Colours import load_presets_from_config
from lnst.Common.Utils import mkdir_p
from lnst.Controller.NetTestController import NetTestController, NetTestError
+from lnst.Controller.NetTestController import NoMatchError
from lnst.Controller.NetTestResultSerializer import NetTestResultSerializer
RETVAL_PASS = 0
@@ -53,6 +54,8 @@ def usage(retval=0):
"be used when transforming the xml result file, only useful "\
"when -t is used as well"
print " -t, --html=FILE generate a formatted result html"
+ print " -u, --multi-match run each recipe with every "\
+ "pool match possible"
print " -x, --result=FILE file to write xml_result"
sys.exit(retval)
@@ -81,11 +84,7 @@ def exec_action(action, nettestctl):
def get_recipe_result(action, file_path, log_ctl, res_serializer,
pool_checks, packet_capture,
defined_aliases, overriden_aliases,
- reduce_sync):
- res_serializer.add_recipe(file_path)
- log_ctl.set_recipe(file_path)
- recipe_head_log_entry(file_path)
-
+ reduce_sync, multi_match):
retval = RETVAL_PASS
nettestctl = NetTestController(file_path, log_ctl,
@@ -95,26 +94,53 @@ def get_recipe_result(action, file_path, log_ctl, res_serializer,
defined_aliases=defined_aliases,
overriden_aliases=overriden_aliases,
reduce_sync=reduce_sync)
- res = {}
- try:
- res = exec_action(action, nettestctl)
- except Exception as err:
- log_exc_traceback()
- logging.error(err)
- res["passed"] = False
- res["err_msg"] = str(err)
- retval = RETVAL_ERR
-
- res_serializer.set_recipe_result(res)
-
- # The test failed, but don't override erro
- if not res["passed"] and retval < RETVAL_FAIL:
- retval = RETVAL_FAIL
+ matches = 1
+ no_match = False
+ while True:
+ res = {}
+ try:
+ nettestctl.provision_machines()
+ log_ctl.set_recipe(file_path, expand="match_%d" % matches)
+ recipe_head_log_entry(file_path, matches)
+ nettestctl.print_match_description()
+ res_serializer.add_recipe(file_path, matches)
+ res = exec_action(action, nettestctl)
+ except NoMatchError as err:
+ no_match = True
+ if matches == 1:
+ res["passed"] = False
+ retval = RETVAL_ERR
+ raise err
+ else:
+ log_ctl.unset_recipe()
+ logging.warning("Match %d not possible." % matches)
+ except Exception as err:
+ no_match = True
+ log_exc_traceback()
+ logging.error(err)
+ res["passed"] = False
+ res["err_msg"] = str(err)
+ retval = RETVAL_ERR
+
+ if no_match and matches > 1:
+ break
+
+ res_serializer.set_recipe_pool_match(nettestctl.get_pool_match())
+ res_serializer.set_recipe_result(res)
+
+ # The test failed, but don't override erro
+ if not res["passed"] and retval < RETVAL_FAIL:
+ retval = RETVAL_FAIL
+
+ if not multi_match or no_match:
+ break
+ matches += 1
return retval
-def recipe_head_log_entry(filename):
- head_str = "\nProcessing recipe file \"%s\"\n" % filename
+def recipe_head_log_entry(filename, match_num=1):
+ head_str = "\nTrying recipe file \"%s\" match %d\n" % (filename,
+ match_num)
logging.info("-" * len(head_str.strip())
+ head_str
+ "-" * len(head_str.strip()))
@@ -126,7 +152,7 @@ def main():
try:
opts, args = getopt.getopt(
sys.argv[1:],
- "A:a:c:dhmoprs:t:x:",
+ "A:a:c:dhmoprs:t:ux:",
[
"override_alias",
"define_alias",
@@ -138,7 +164,8 @@ def main():
"packet-capture",
"reduce-sync",
"xslt-url",
- "html"
+ "html",
+ "multi-match",
"result=",
]
)
@@ -178,6 +205,7 @@ def main():
defined_aliases = {}
overriden_aliases = {}
reduce_sync = False
+ multi_match = False
for opt, arg in opts:
if opt in ("-d", "--debug"):
debug += 1
@@ -203,6 +231,8 @@ def main():
reduce_sync = True
elif opt in ("-s", "--xslt-url"):
xslt_url = arg
+ elif opt in ("-u", "--multi-match"):
+ multi_match = True
if config_path is not None:
if not os.path.isfile(config_path):
@@ -264,7 +294,7 @@ def main():
rv = get_recipe_result(action, recipe_file, log_ctl, res_serializer,
pool_checks, packet_capture,
defined_aliases, overriden_aliases,
- reduce_sync)
+ reduce_sync, multi_match)
if rv > retval:
retval = rv
diff --git a/lnst/Controller/NetTestResultSerializer.py
b/lnst/Controller/NetTestResultSerializer.py
index b36894e..ae8bc7e 100644
--- a/lnst/Controller/NetTestResultSerializer.py
+++ b/lnst/Controller/NetTestResultSerializer.py
@@ -53,12 +53,17 @@ class NetTestResultSerializer:
def __init__(self):
self._results = []
- def add_recipe(self, name):
+ def add_recipe(self, name, match_num):
recipe_result = {"name": name,
"result": "FAIL",
- "tasks": []}
+ "tasks": [],
+ "pool_match": {},
+ "match_num": match_num}
self._results.append(recipe_result)
+ def set_recipe_pool_match(self, match):
+ self._results[-1]["pool_match"] = match
+
def set_recipe_result(self, result):
if result and result["passed"]:
self._results[-1]["result"] = "PASS"
@@ -78,7 +83,21 @@ class NetTestResultSerializer:
output_pairs = []
for recipe in self._results:
- output_pairs.append((recipe["name"], recipe["result"]))
+ recipe_head = "%s match: %d" % (recipe["name"],
recipe["match_num"])
+ output_pairs.append((recipe_head, recipe["result"]))
+
+ output_pairs.append((4*" " + "Pool match description:",
""))
+ match = recipe["pool_match"]
+ if "virtual" in match and match["virtual"]:
+ output_pairs.append((4*" " + "Setup is using virtual
machines.",
+ ""))
+ for m_id, m in match["machines"].iteritems():
+ output_pairs.append((4*" " + "host \"%s\" uses
\"%s\"" %\
+ (m_id, m["target"]), ""))
+ for if_id, pool_id in m["interfaces"].iteritems():
+ output_pairs.append((6*" " + "interface
\"%s\" "\
+ "matched to \"%s\""
%\
+ (if_id, pool_id), ""))
if recipe["result"] == "FAIL" and \
"err_msg" in recipe and recipe["err_msg"] !=
"":