From f1630941a0c47fdd025219340e5383cbaefcd85e Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 7 Apr 2017 19:40:12 +0200 Subject: rumba: simplify cooperation between prototype and testbed plugins --- README | 10 ++++------ rumba/model.py | 26 +++++++++++++++++++------- rumba/prototypes/irati.py | 3 +-- rumba/prototypes/ouroboros.py | 3 +-- rumba/prototypes/rlite.py | 3 +-- rumba/testbeds/emulab.py | 2 +- rumba/testbeds/faketestbed.py | 2 +- rumba/testbeds/jfed.py | 2 +- rumba/testbeds/qemu.py | 4 ++-- 9 files changed, 31 insertions(+), 24 deletions(-) diff --git a/README b/README index cb29f09..8471a93 100644 --- a/README +++ b/README @@ -16,15 +16,13 @@ Workflow, both external and internal: used by the plugins (4) user calls run() on the prototype.Experiment instance: - - First, run() calls Experiment.swap_in(), which - in turns calls Testbed.create_experiment(), passing the - nodes and links (?) - TODO: fix this interface: what should swap_in(), and - so create_experiment() return exactly? Current interface - seems broken + - First, run() calls Testbed.swap_in(), passing the + Experiment, and filling in the missing information - Second, run() calls a prototype-specific setup function, to create the required IPCPs, perform registrations, enrollments, etc. - Third, perform tests (TODO) + + - Fourth, run() calls Testbed.swap_out() diff --git a/rumba/model.py b/rumba/model.py index 25a1356..99bf5ed 100644 --- a/rumba/model.py +++ b/rumba/model.py @@ -37,8 +37,13 @@ class Testbed: self.exp_name = exp_name @abc.abstractmethod - def create_experiment(self, experiment): - raise Exception('create_experiment() not implemented') + def swap_in(self, experiment): + raise Exception('swap_in() not implemented') + + @abc.abstractmethod + def swap_out(self, experiment): + print("swap_out(): nothing to do") + # Base class for DIFs # @@ -605,10 +610,17 @@ class Experiment: self.compute_enrollments() self.compute_ipcps() - # Realize the experiment, using a testbed-specific setup - def swap_in(self): - self.testbed.create_experiment(self) - @abc.abstractmethod + def run_prototype(self): + raise Exception('run_prototype() method not implemented') + def run(self): - raise Exception('run() method not implemented') + # Realize the experiment testbed (testbed-specific) + self.testbed.swap_in(self) + + # Run the experiment using the prototype (prototype-specific) + self.run_prototype() + + # Undo the testbed (testbed-specific) + self.testbed.swap_out(self) + diff --git a/rumba/prototypes/irati.py b/rumba/prototypes/irati.py index 1babd57..37a6fbe 100644 --- a/rumba/prototypes/irati.py +++ b/rumba/prototypes/irati.py @@ -41,9 +41,8 @@ class Experiment(mod.Experiment): ssh.execute_commands(self.testbed, node.full_name, cmds, time_out=None) - def run(self): + def run_prototype(self): print("[IRATI experiment] start") - self.swap_in() print("Setting up IRATI on the nodes...") self.setup() print("[IRATI experiment] end") diff --git a/rumba/prototypes/ouroboros.py b/rumba/prototypes/ouroboros.py index 57358cf..4f78361 100644 --- a/rumba/prototypes/ouroboros.py +++ b/rumba/prototypes/ouroboros.py @@ -49,10 +49,9 @@ class Experiment(mod.Experiment): ssh.execute_commands(self.testbed, node.full_name, cmds, time_out=None) - def run(self): + def run_prototype(self): print("[Ouroboros experiment] start") print("Creating resources...") - self.swap_in() print("Setting up Ouroboros...") self.setup_ouroboros() print("Binding names...") diff --git a/rumba/prototypes/rlite.py b/rumba/prototypes/rlite.py index b175e92..8cb45ec 100644 --- a/rumba/prototypes/rlite.py +++ b/rumba/prototypes/rlite.py @@ -42,9 +42,8 @@ class Experiment(mod.Experiment): ssh.execute_commands(self.testbed, node.full_name, cmds, time_out=None) - def run(self): + def run_prototype(self): print("[RLITE experiment] start") - self.swap_in() print("Setting up rlite on the nodes...") self.setup() print("[RLITE experiment] end") diff --git a/rumba/testbeds/emulab.py b/rumba/testbeds/emulab.py index 134d344..c4dbe36 100644 --- a/rumba/testbeds/emulab.py +++ b/rumba/testbeds/emulab.py @@ -235,7 +235,7 @@ class Testbed(mod.Testbed): ipcp.ifname = item[0] node.full_name = self.full_name(node.name) - def create_experiment(self, experiment): + def swap_in(self, experiment): self._create_experiment(experiment) self.swap_exp_in() self.wait_until_nodes_up() diff --git a/rumba/testbeds/faketestbed.py b/rumba/testbeds/faketestbed.py index 4821aa8..85110b8 100644 --- a/rumba/testbeds/faketestbed.py +++ b/rumba/testbeds/faketestbed.py @@ -25,5 +25,5 @@ class Testbed(mod.Testbed): def __init__(self, exp_name, username, proj_name="ARCFIRE", password=""): mod.Testbed.__init__(self, exp_name, username, password, proj_name) - def create_experiment(self, experiment): + def swap_in(self, experiment): print("[Fake testbed] experiment swapped in") diff --git a/rumba/testbeds/jfed.py b/rumba/testbeds/jfed.py index e606846..f56e5ba 100644 --- a/rumba/testbeds/jfed.py +++ b/rumba/testbeds/jfed.py @@ -106,7 +106,7 @@ class Testbed(mod.Testbed): file.write(doc.toprettyxml()) file.close() - def create_experiment(self, experiment): + def swap_in(self, experiment): self.create_rspec(experiment) for node in experiment.nodes: diff --git a/rumba/testbeds/qemu.py b/rumba/testbeds/qemu.py index 7dae921..49bfcc2 100644 --- a/rumba/testbeds/qemu.py +++ b/rumba/testbeds/qemu.py @@ -64,7 +64,7 @@ class Testbed(mod.Testbed): except CalledProcessError as e: error_queue.put(str(e)) - def create_experiment(self, experiment): + def swap_in(self, experiment): """ :type experiment mod.Experiment :param experiment: The experiment running @@ -227,7 +227,7 @@ class Testbed(mod.Testbed): vmid += 1 - def __del__(self): + def swap_out(self): """ :rtype str :return: The script to tear down the experiment -- cgit v1.2.3 From d07592d34d1636a41be214e7df5c828c6d4aa3c2 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 8 Apr 2017 12:01:54 +0200 Subject: testbeds: qemu: port to python3, use explicit module names --- rumba/testbeds/qemu.py | 55 +++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/rumba/testbeds/qemu.py b/rumba/testbeds/qemu.py index 49bfcc2..8079f28 100644 --- a/rumba/testbeds/qemu.py +++ b/rumba/testbeds/qemu.py @@ -17,14 +17,13 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA -from Queue import Empty -from getpass import getpass, getuser -from multiprocessing import Process, Queue, cpu_count -from os import geteuid -from time import sleep +import getpass +import multiprocessing +import time +import subprocess +import os import rumba.model as mod -from subprocess import Popen, check_call, CalledProcessError class Testbed(mod.Testbed): @@ -58,10 +57,10 @@ class Testbed(mod.Testbed): if not error_queue.empty(): break print('DEBUG: executing >> {}'.format(command)) - check_call(command.split()) + subprocess.check_call(command.split()) results_queue.put("Command chain ran correctly.") - except CalledProcessError as e: + except subprocess.CalledProcessError as e: error_queue.put(str(e)) def swap_in(self, experiment): @@ -69,23 +68,23 @@ class Testbed(mod.Testbed): :type experiment mod.Experiment :param experiment: The experiment running """ - if geteuid() != 0: - pw = getpass('[sudo] password for {}:'.format(getuser())) + if os.geteuid() != 0: + pw = getpass.getpass('[sudo] password for {}:'.format(getpass.getuser())) if '"' in pw or "'" in pw: print('Illegal password: contains " or \'') raise Exception('Not authenticated') else: try: - check_call("sudo -v -p '{}'".format(pw).split()) - except CalledProcessError: + subprocess.check_call("sudo -v -p '{}'".format(pw).split()) + except subprocess.CalledProcessError: raise Exception('Not authenticated') print("[QEMU testbed] swapping in") # Building bridges and taps shim_processes = [] - r_queue = Queue() - e_queue = Queue() + r_queue = multiprocessing.Queue() + e_queue = multiprocessing.Queue() print(experiment.dif_ordering) for shim in experiment.dif_ordering: command_list = [] @@ -129,7 +128,7 @@ class Testbed(mod.Testbed): if not e_queue.empty(): break # Launch commands asynchronously - process = Process(target=self._run_command_chain, args=(command_list, r_queue, e_queue)) + process = multiprocessing.Process(target=self._run_command_chain, args=(command_list, r_queue, e_queue)) shim_processes.append(process) process.start() @@ -150,12 +149,12 @@ class Testbed(mod.Testbed): if result == "Command chain ran correctly.": over_processes += 1 print('DEBUG: %s of %s processes completed.' % (over_processes, total_processes)) - except Empty: + except: max_waiting_time -= 1 # Building vms - boot_batch_size = max(1, cpu_count() // 2) + boot_batch_size = max(1, multiprocessing.cpu_count() // 2) booting_budget = boot_batch_size boot_backoff = 12 base_port = 2222 @@ -217,17 +216,17 @@ class Testbed(mod.Testbed): booting_budget -= 1 if booting_budget <= 0: print('Sleeping for {} seconds to give the machines time to boot up.'.format(boot_backoff)) - sleep(boot_backoff) + time.sleep(boot_backoff) booting_budget = boot_batch_size with open(self.qemu_folder + '/qemu_out{}'.format(vmid), 'w') as out_file: print('DEBUG: executing >> {}'.format(command)) - self.boot_processes.append(Popen(command.split(), stdout=out_file)) + self.boot_processes.append(subprocess.Popen(command.split(), stdout=out_file)) pass vmid += 1 - def swap_out(self): + def swap_out(self, experiment): """ :rtype str :return: The script to tear down the experiment @@ -241,8 +240,8 @@ class Testbed(mod.Testbed): process.wait() port_processes = [] - error_queue = Queue() - results_queue = Queue() + error_queue = multiprocessing.Queue() + results_queue = multiprocessing.Queue() for vm_name, vm in self.vms.items(): for port in vm['ports']: tap = port['tap_id'] @@ -255,7 +254,7 @@ class Testbed(mod.Testbed): 'sudo ip tuntap del mode tap name %(tap)s' % {'tap': tap, 'br': shim.name} ).split('\n') - process = Process(target=self._run_command_chain, args=(commands, results_queue, error_queue)) + process = multiprocessing.Process(target=self._run_command_chain, args=(commands, results_queue, error_queue)) port_processes.append(process) process.start() @@ -274,11 +273,11 @@ class Testbed(mod.Testbed): if result == "Command chain ran correctly.": over_processes += 1 print('DEBUG: %s of %s tear-down port processes completed.' % (over_processes, total_processes)) - except Empty: + except: max_waiting_time -= 1 - error_queue = Queue() - results_queue = Queue() + error_queue = multiprocessing.Queue() + results_queue = multiprocessing.Queue() shim_processes = [] for shim in self.shims: @@ -287,7 +286,7 @@ class Testbed(mod.Testbed): 'sudo brctl delbr %(br)s' % {'br': shim.name} ).split('\n') - process = Process(target=self._run_command_chain, args=(commands, results_queue, error_queue)) + process = multiprocessing.Process(target=self._run_command_chain, args=(commands, results_queue, error_queue)) shim_processes.append(process) process.start() @@ -306,5 +305,5 @@ class Testbed(mod.Testbed): if result == "Command chain ran correctly.": over_processes += 1 print('DEBUG: %s of %s tear-down shim processes completed.' % (over_processes, total_processes)) - except Empty: + except: max_waiting_time -= 1 -- cgit v1.2.3 From 6818af98498a890bcca9cbc8034aaa1a733e6230 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 8 Apr 2017 12:36:51 +0200 Subject: testbeds: qemu: modify constructor arguments vm_img_folder --> bzimage, initramfs --- examples/example.py | 10 +++++----- examples/two-layers.py | 6 ++++-- rumba/prototypes/rlite.py | 2 ++ rumba/testbeds/qemu.py | 13 ++++++++----- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/examples/example.py b/examples/example.py index e173ef0..0d8fcd9 100755 --- a/examples/example.py +++ b/examples/example.py @@ -30,12 +30,12 @@ b = Node("b", difs = [e1, n1], dif_registrations = {n1 : [e1]}) -tb = jfed.Testbed(exp_name = "letest", - username = "sander", - cert_file = "cert.pem", - jfed_jar = "jfed_cli/experimenter-cli.jar") +tb = qemu.Testbed(exp_name = "example1", + username = "vmaffione", + bzimage = '/home/vmaffione/git/rlite/demo/buildroot/bzImage', + initramfs = '/home/vmaffione/git/rlite/demo/buildroot/rootfs.cpio') -exp = irati.Experiment(tb, nodes = [a, b]) +exp = rl.Experiment(tb, nodes = [a, b]) print(exp) diff --git a/examples/two-layers.py b/examples/two-layers.py index 29faebe..687c99f 100755 --- a/examples/two-layers.py +++ b/examples/two-layers.py @@ -43,9 +43,11 @@ d = Node("d", dif_registrations = {n3: [n2], n2 : [e3]}) tb = qemu.Testbed(exp_name = "twolayers", - username = "vmaffio") + username = "vmaffione", + bzimage = '/home/vmaffione/git/rlite/demo/buildroot/bzImage', + initramfs = '/home/vmaffione/git/rlite/demo/buildroot/rootfs.cpio') -exp = irati.Experiment(tb, nodes = [a, b, c, d]) +exp = rl.Experiment(tb, nodes = [a, b, c, d]) print(exp) diff --git a/rumba/prototypes/rlite.py b/rumba/prototypes/rlite.py index 8cb45ec..f4ff825 100644 --- a/rumba/prototypes/rlite.py +++ b/rumba/prototypes/rlite.py @@ -20,6 +20,7 @@ import rumba.ssh_support as ssh import rumba.model as mod +import time # An experiment over the RLITE implementation class Experiment(mod.Experiment): @@ -46,4 +47,5 @@ class Experiment(mod.Experiment): print("[RLITE experiment] start") print("Setting up rlite on the nodes...") self.setup() + time.sleep(20) print("[RLITE experiment] end") diff --git a/rumba/testbeds/qemu.py b/rumba/testbeds/qemu.py index 8079f28..82ad873 100644 --- a/rumba/testbeds/qemu.py +++ b/rumba/testbeds/qemu.py @@ -27,12 +27,13 @@ import rumba.model as mod class Testbed(mod.Testbed): - def __init__(self, exp_name, username, vm_img_folder, proj_name="ARCFIRE", password="", + def __init__(self, exp_name, username, bzimage, initramfs, proj_name="ARCFIRE", password="", use_vhost=True, qemu_out_folder=""): mod.Testbed.__init__(self, exp_name, username, password, proj_name) self.vms = {} self.shims = [] - self.vm_img_path = vm_img_folder + self.bzimage = bzimage + self.initramfs = initramfs self.vhost = use_vhost self.qemu_folder = qemu_out_folder self.boot_processes = [] @@ -173,7 +174,9 @@ class Testbed(mod.Testbed): vm['id'] = vmid vars_dict = {'fwdp': fwdp, 'id': vmid, 'mac': mac, - 'vmimgpath': self.vm_img_path, 'fwdc': fwdc, + 'bzimage': self.bzimage, + 'initramfs': self.initramfs, + 'fwdc': fwdc, 'memory': vm_memory, 'frontend': vm_frontend, 'vmname': name} @@ -182,9 +185,9 @@ class Testbed(mod.Testbed): command = 'qemu-system-x86_64 ' # TODO manage non default images - command += ('-kernel %(vmimgpath)s/bzImage ' + command += ('-kernel %(bzimage)s ' '-append "console=ttyS0" ' - '-initrd %(vmimgpath)s/rootfs.cpio ' + '-initrd %(initramfs)s ' % vars_dict) command += ('-nographic ' '-display none ' -- cgit v1.2.3 From 23ed7dceee1eecff9e80862b650824deb5bdb187 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 8 Apr 2017 12:43:43 +0200 Subject: testsbeds: qemu: qemu logs directory defaults to pwd --- rumba/testbeds/qemu.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rumba/testbeds/qemu.py b/rumba/testbeds/qemu.py index 82ad873..897af37 100644 --- a/rumba/testbeds/qemu.py +++ b/rumba/testbeds/qemu.py @@ -28,14 +28,14 @@ import rumba.model as mod class Testbed(mod.Testbed): def __init__(self, exp_name, username, bzimage, initramfs, proj_name="ARCFIRE", password="", - use_vhost=True, qemu_out_folder=""): + use_vhost=True, qemu_logs_dir=None): mod.Testbed.__init__(self, exp_name, username, password, proj_name) self.vms = {} self.shims = [] self.bzimage = bzimage self.initramfs = initramfs self.vhost = use_vhost - self.qemu_folder = qemu_out_folder + self.qemu_logs_dir = os.getcwd() if qemu_logs_dir is None else qemu_logs_dir self.boot_processes = [] @staticmethod @@ -222,7 +222,7 @@ class Testbed(mod.Testbed): time.sleep(boot_backoff) booting_budget = boot_batch_size - with open(self.qemu_folder + '/qemu_out{}'.format(vmid), 'w') as out_file: + with open('%s/qemu_out_%s' % (self.qemu_logs_dir, vmid), 'w') as out_file: print('DEBUG: executing >> {}'.format(command)) self.boot_processes.append(subprocess.Popen(command.split(), stdout=out_file)) pass -- cgit v1.2.3 From 8d4ba82ac3a598992ee3d8fbe7ea14375b7c0801 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 8 Apr 2017 12:55:15 +0200 Subject: testbeds: qemu: use % for formatting strings --- rumba/testbeds/qemu.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rumba/testbeds/qemu.py b/rumba/testbeds/qemu.py index 897af37..1830b37 100644 --- a/rumba/testbeds/qemu.py +++ b/rumba/testbeds/qemu.py @@ -57,7 +57,7 @@ class Testbed(mod.Testbed): for command in commands: if not error_queue.empty(): break - print('DEBUG: executing >> {}'.format(command)) + print('DEBUG: executing >> %s' % command) subprocess.check_call(command.split()) results_queue.put("Command chain ran correctly.") @@ -70,7 +70,7 @@ class Testbed(mod.Testbed): :param experiment: The experiment running """ if os.geteuid() != 0: - pw = getpass.getpass('[sudo] password for {}:'.format(getpass.getuser())) + pw = getpass.getpass('[sudo] password for %s:' % getpass.getuser()) if '"' in pw or "'" in pw: print('Illegal password: contains " or \'') raise Exception('Not authenticated') @@ -142,8 +142,8 @@ class Testbed(mod.Testbed): # Check for errors if not e_queue.empty(): error_str = str(e_queue.get()) - print('Testbed instantiation failed: {}'.format(error_str)) - raise Exception('Failure: {}'.format(error_str)) + print('Testbed instantiation failed: %s' % error_str) + raise Exception('Failure: %s' % error_str) try: # Check for results result = r_queue.get(timeout=1) @@ -218,12 +218,12 @@ class Testbed(mod.Testbed): booting_budget -= 1 if booting_budget <= 0: - print('Sleeping for {} seconds to give the machines time to boot up.'.format(boot_backoff)) + print('Sleeping for %s seconds to give the machines time to boot up.' % boot_backoff) time.sleep(boot_backoff) booting_budget = boot_batch_size with open('%s/qemu_out_%s' % (self.qemu_logs_dir, vmid), 'w') as out_file: - print('DEBUG: executing >> {}'.format(command)) + print('DEBUG: executing >> %s' % command) self.boot_processes.append(subprocess.Popen(command.split(), stdout=out_file)) pass @@ -268,7 +268,7 @@ class Testbed(mod.Testbed): while max_waiting_time > 0 and over_processes < total_processes: # Check for errors if not error_queue.empty(): - print('Failure while shutting down: {}'.format(str(error_queue.get()))) + print('Failure while shutting down: %s' % str(error_queue.get())) over_processes += 1 try: # Check for results @@ -300,7 +300,7 @@ class Testbed(mod.Testbed): while max_waiting_time > 0 and over_processes < total_processes: # Check for errors if not error_queue.empty(): - print('Failure while shutting down: {}'.format(str(error_queue.get()))) + print('Failure while shutting down: %s' % str(error_queue.get())) over_processes += 1 try: # Check for results -- cgit v1.2.3