From 97b16ada2b710cfe88c3bc6bf9e0dc42a943fca5 Mon Sep 17 00:00:00 2001 From: Dimitri Staessens Date: Sun, 18 Jul 2021 21:13:43 +0200 Subject: exp: Add metrics and prototype update commands This adds a couple of commands to start/stop metrics exporter, set link rate on virtual wall, and updating the prototype from git, which is useful in interactive mode. --- rumba/elements/experimentation.py | 88 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 6 deletions(-) (limited to 'rumba/elements/experimentation.py') diff --git a/rumba/elements/experimentation.py b/rumba/elements/experimentation.py index bbb3310..03d90bb 100644 --- a/rumba/elements/experimentation.py +++ b/rumba/elements/experimentation.py @@ -112,7 +112,7 @@ class Experiment(object): git_repo=None, git_branch=None, build_options=None, - add_packages=[], + add_packages=None, log_dir=None, prototype_logs=None, enrollment_strategy='minimal', @@ -128,13 +128,16 @@ class Experiment(object): :param log_dir: Where to log output of the experiment. :param prototype_logs: Where the prototype logs its output. :param enrollment_strategy: Can be 'full-mesh', 'minimal' or 'manual'. - :param dt_strategy: For data flows, 'full-mesh', 'minimal' or 'manual'. + :param flows_strategy: For data flows, 'full-mesh', 'minimal' or 'manual'. :param server_decorator: a decorator function which will be applied to storyboard.server instances when using this prototype """ if nodes is None: nodes = list() + if add_packages is None: + add_packages = list() + self.nodes = nodes if server_decorator is None: def server_decorator(server): @@ -157,10 +160,10 @@ class Experiment(object): if self.enrollment_strategy not in ['full-mesh', 'minimal', 'manual']: raise Exception('Unknown enrollment strategy "%s"' - % self.enrollment_strategy) + % self.enrollment_strategy) if self.flows_strategy not in ['full-mesh', 'minimal', 'manual']: raise Exception('Unknown flows strategy "%s"' - % self.flows_strategy) + % self.flows_strategy) # Determine log directory if log_dir is None: @@ -476,6 +479,35 @@ class Experiment(object): end = time.time() logger.info("Bootstrap took %.2f seconds", end - start) + def update_prototype(self, branch=None): + """ + Updates from branch and reinstalls and rebootstraps the prototype + """ + start = time.time() + self._terminate_prototype(force=True) + self._update_prototype(branch) + self._bootstrap_prototype() + end = time.time() + logger.info("Prototype update took %.2f seconds", end - start) + + def start_metrics_exporter(self, nodes=None, interval=100): + """ + Start the metrics exporter for the prototype on nodes exporting data every interval ms + """ + start = time.time() + self._start_metrics_exporter(nodes, interval) + end = time.time() + logger.info("Starting metrics exporters took %.2f seconds", end - start) + + def stop_metrics_exporter(self, nodes=None): + """ + Stop the metrics exporters for the prototype on nodes exporting data every interval ms + """ + start = time.time() + self._stop_metrics_exporter(nodes) + end = time.time() + logger.info("Stopping metrics exporters took %.2f seconds", end - start) + @abc.abstractmethod def destroy_dif(self, dif): raise Exception('destroy_dif() method not implemented') @@ -488,14 +520,57 @@ class Experiment(object): def _bootstrap_prototype(self): raise Exception('bootstrap_prototype() method not implemented') + @abc.abstractmethod + def _update_prototype(self, branch): + raise Exception('update_prototype() method not implemented') + @abc.abstractmethod def prototype_name(self): raise Exception('prototype_name() method not implemented') @abc.abstractmethod - def _terminate_prototype(self, force=False): + def _terminate_prototype(self, force): raise Exception('terminate_prototype() method not implemented') + @abc.abstractmethod + def _start_metrics_exporter(self, nodes, interval): + raise Exception('start_metrics_exporter() method not implemented') + + @abc.abstractmethod + def _stop_metrics_exporter(self, nodes): + raise Exception('start_metrics_exporter() method not implemented') + + def set_eth_link_rate_to(self, src, dst, megabit): + """ + Sets the link rate on src NIC towards dst with ethtool + Fixme: This should be moved to the testbed class + Fixme: Test if testbed is a physical Linux server + """ + + if megabit not in [10, 100, 1000]: + return + + self.run_command(src, "route | grep $(ping server -c 1 | head -n1 | cut -f3 -d' ' | head -c -3 | tail -c +2) | " + "grep -o '[^ ]*$' > iface ".format(dst)) + self.run_command(src, "sudo ethtool -s $(cat iface) speed {} duplex full autoneg off".format(megabit)) + self.run_command(src, "sudo ip link set $(cat iface) down") + self.run_command(src, "sudo ip link set $(cat iface) up && sleep 10") + self.run_command(src, "sudo ethtool $(cat iface) | grep '{}Mb/s'".format(megabit)) + self.run_command(src, "rm iface") + self.run_command(src, "while ! ping -c 1 {}; do sleep 1; done".format(dst)) + + def set_eth_link_rate_between(self, src, dst, megabit): + """ + Sets the link rate with ethtool + Fixme: This should be moved to the testbed class + Fixme: Test if testbed is a physical Linux server + """ + if megabit not in [10, 100, 1000]: + return + + self.set_eth_link_rate_to(src, dst, megabit) + self.set_eth_link_rate_to(dst, src, megabit) + def swap_in(self): """ Swap the experiment in on the testbed. @@ -525,7 +600,7 @@ class Experiment(object): """ Terminate the prototype in the experiment. """ - self._terminate_prototype() + self._terminate_prototype(force=force) def reboot_nodes(self): """ @@ -673,6 +748,7 @@ class Experiment(object): logger.error('Warning: pydot module not installed, ' 'cannot produce DIF graph images') + class Executor: __metaclass__ = abc.ABCMeta -- cgit v1.2.3