On Fri, Jan 18, 2019 at 06:56:10PM +0100, csfakian(a)redhat.com wrote:
From: Christos Sfakianakis <csfakian(a)redhat.com>
Add/edit methods in PingTestAndEvaluate to handle parallel scenarios:
a) added "ping_init" to initiate a Tests.Ping instance for all
scenarios
b) edited "ping_test" to split between default and parallel
scenarios
c) added "parallel_ping_evaluate_and_report" as the analogous of
"ping_evaluate_and_report" for the parallel case
d) added "single_ping_evaluate_and_report" to report which ip's
are used each time in the parallel case
In lnst.Recipes.BaseEnrtRecipe, allow the user to specify ping
interval, count, packet size. Include additional parameters for
specifying parallel scenarios, as well as bidirectional cases.
Modify "generate_ping_configurations" method to account for parallel
scenarios. Assume "ip_versions" and the 2 endpoints are compatible
in that the latter share equal numbers of corresponding ip's and
output error otherwise. Filter off link-local ipv6 addresses.
Generate a list of ping configurations for each ip version specified
in a parallel scenario, or the content of a single-element list in the
default, non-parallel case.
Signed-off-by: Christos Sfakianakis <csfakian(a)redhat.com>
---
lnst/RecipeCommon/Ping.py | 57 ++++++++++++++++++++++++--
lnst/Recipes/ENRT/BaseEnrtRecipe.py | 62 +++++++++++++++++++++++------
2 files changed, 103 insertions(+), 16 deletions(-)
diff --git a/lnst/RecipeCommon/Ping.py b/lnst/RecipeCommon/Ping.py
index f5cd652..194d984 100644
--- a/lnst/RecipeCommon/Ping.py
+++ b/lnst/RecipeCommon/Ping.py
@@ -1,5 +1,8 @@
+from copy import copy
+
from lnst.Controller.Recipe import BaseRecipe
from lnst.Tests import Ping
+from lnst.Controller.RecipeResults import ResultLevel
class PingConf(object):
def __init__(self,
@@ -44,22 +47,68 @@ class PingConf(object):
class PingTestAndEvaluate(BaseRecipe):
def ping_test(self, ping_config):
One more time :)
you can just do this:
if not isinstance(ping_config, list):
ping_config = [ping_config]
and the rest of the implementation is "as if this is a parallel
scenario".
+ #parallel scenario
+ if isinstance(ping_config, list):
+ results = {}
+
+ running_ping_array = []
+ for pingconf in ping_config:
+ ping, client = self.ping_init(pingconf)
+ running_ping = client.prepare_job(ping)
+ running_ping.start(bg = True)
+ running_ping_array.append((pingconf, running_ping))
+
+ for _, pingjob in running_ping_array:
+ try:
+ pingjob.wait()
+ finally:
+ pingjob.kill()
+
+ for pingconf, pingjob in running_ping_array:
+ result = pingjob.result
+ results[pingconf] = result
+
+ return results
+
+ #non-parallel scenario
+ ping, client = self.ping_init(ping_config)
+ ping_job = client.run(ping)
+ return ping_job.result
+
+ def ping_init(self, ping_config):
client = ping_config.client
destination = ping_config.destination
-
kwargs = self._generate_ping_kwargs(ping_config)
ping = Ping(**kwargs)
-
- ping_job = client.run(ping)
- return ping_job.result
+ return (ping, client)
def ping_evaluate_and_report(self, ping_config, results):
This is the same situation as with the ping_test method. Just
if not isinstance(ping_config, list):
ping_config = [ping_config]
and continue with the assumtion that it's always a parallel scenario and
merge this method with the "parallel_ping_evaluate_and_report" method.
And you then don't need the "non-parallel" evaluation because it will
automatically be handled by the single_ping_evaluate_and_report method.
+ if isinstance(ping_config, list):
+ self.parallel_ping_evaluate_and_report(results)
+ return
# do we want to use the "perf" measurements (store a baseline etc...)
as well?
if results["rate"] > 50:
self.add_result(True, "Ping succesful", results)
else:
self.add_result(False, "Ping unsuccesful", results)
+ #parallel version of ping_evaluate_and_report
+ def parallel_ping_evaluate_and_report(self, results):
+ for pingconf, result in results.items():
+ self.single_ping_evaluate_and_report(pingconf, result)
+
+ #clarify source/destination in reporting for parallel scenarios
+ def single_ping_evaluate_and_report(self, ping_config, results):
+ fmt = "From: <{0.client.hostid} ({0.client_bind})> To: " \
+ "<{0.destination.hostid} ({0.destination_address})>"
+ description = fmt.format(ping_config)
+ if results["rate"] > 50:
+ message = "Ping successful --- " + description
+ self.add_result(True, message, results)
+ else:
+ message = "Ping unsuccessful --- " + description
+ self.add_result(False, message, results)
+
def _generate_ping_kwargs(self, ping_config):
kwargs = dict(dst=ping_config.destination_address,
interface=ping_config.client_bind)
diff --git a/lnst/Recipes/ENRT/BaseEnrtRecipe.py b/lnst/Recipes/ENRT/BaseEnrtRecipe.py
index d7d1aec..cbab341 100644
--- a/lnst/Recipes/ENRT/BaseEnrtRecipe.py
+++ b/lnst/Recipes/ENRT/BaseEnrtRecipe.py
@@ -65,6 +65,13 @@ class EnrtSubConfiguration(object):
class BaseEnrtRecipe(PingTestAndEvaluate, PerfRecipe):
ip_versions = Param(default=("ipv4", "ipv6"))
+
+ ping_parallel = BoolParam(default=False)
+ ping_bidirect = BoolParam(default=False)
+ ping_count = IntParam(default = 100)
+ ping_interval = StrParam(default = 0.2)
+ ping_psize = IntParam(default = None)
+
perf_tests = Param(default=("tcp_stream", "udp_stream",
"sctp_stream"))
offload_combinations = Param(default=(
@@ -158,22 +165,53 @@ class BaseEnrtRecipe(PingTestAndEvaluate, PerfRecipe):
def generate_ping_configurations(self, main_config, sub_config):
client_nic = main_config.endpoint1
server_nic = main_config.endpoint2
- client_netns = client_nic.netns
- server_netns = server_nic.netns
+
+ count = self.params.ping_count
+ interval = self.params.ping_interval
+ size = self.params.ping_psize
+ common_args = {'count' : count, 'interval' : interval,
'size' : size}
for ipv in self.params.ip_versions:
+ kwargs = {}
if ipv == "ipv4":
- family = AF_INET
+ kwargs.update(family = AF_INET)
elif ipv == "ipv6":
- family = AF_INET6
-
- client_bind = client_nic.ips_filter(family=family)[0]
- server_bind = server_nic.ips_filter(family=family)[0]
-
- yield PingConf(client = client_netns,
- client_bind = client_bind,
- destination = server_netns,
- destination_address = server_bind)
+ kwargs.update(family = AF_INET6)
+ kwargs.update(link_local = False)
+
+ client_ips = client_nic.ips_filter(**kwargs)
+ server_ips = server_nic.ips_filter(**kwargs)
+
+ if len(client_ips) != len(server_ips) or len(client_ips) * len(server_ips)
== 0:
+ raise LnstError("Source/destination ip lists are of different size
or empty.")
+
+ number_of_ips = len(client_ips)
+ ping_conf_list = []
+ client_nic.valid_ips = client_ips
+ server_nic.valid_ips = server_ips
The client_nic and server_nic objects are RemoteDevice objects,
assigning to an attribute is supposed to mean that you configure
something on the Slave, assigning to an undefined attribute is not
defined and even if it works right now it might change and either stop
working or start working differently and cause issues.
I think you're only assigning to valid_ips so you can reverse the
source/destinations? In that case I think you can just do:
for e1_ip, e2_ip in zip(client_ips, server_ips):
PingConf(e1_ip, e2_ip)
PingConf(e2_ip, e1_ip)
with reversed host objects... Also it might be easier to just drop the
client/server nomenclature in this method and just use something like
endpoints or pair split into source/destination. It might make it easier
to think about this bidirectionality where the client/server changes.
+ for n in range(number_of_ips):
+ for client_nic, server_nic in [(client_nic, server_nic), (server_nic,
client_nic)]:
+ client_bind = client_nic.valid_ips[n]
+ server_bind = server_nic.valid_ips[n]
+
+ pconf = PingConf(client = client_nic.netns,
+ client_bind = client_bind,
+ destination = server_nic.netns,
+ destination_address = server_bind,
+ **common_args)
+
+ ping_conf_list.append(pconf)
+
+ if not self.params.ping_bidirect:
+ break
+
+ if not self.params.ping_parallel:
+ break
You doubled the checks here? Turning the switches to False will only
generate a list of a single PingConf so why split the yield into two
cases in the lines below?
Sorry, this is the first time I reviewed this part since the last time
it was messed up due to tabs/spaces and weird copy paste errors...
-Ondrej
> +
> + if not self.params.ping_bidirect and not self.params.ping_parallel:
> + yield ping_conf_list[0]
> + else:
> + yield ping_conf_list
>
> def generate_perf_configurations(self, main_config, sub_config):
> client_nic = main_config.endpoint1
> --
> 2.17.1
> _______________________________________________
> LNST-developers mailing list -- lnst-developers(a)lists.fedorahosted.org
> To unsubscribe send an email to lnst-developers-leave(a)lists.fedorahosted.org
> Fedora Code of Conduct:
https://getfedora.org/code-of-conduct.html
> List Guidelines:
https://fedoraproject.org/wiki/Mailing_list_guidelines
> List Archives:
https://lists.fedorahosted.org/archives/list/lnst-developers@lists.fedora...