diff options
author | Marco Capitani <m.capitani@nextworks.it> | 2017-06-13 10:09:54 +0200 |
---|---|---|
committer | Marco Capitani <m.capitani@nextworks.it> | 2017-06-13 10:09:54 +0200 |
commit | 457977f337a47caddf8788e1d4e1d1736f2a6ccb (patch) | |
tree | 12fa2a2be0f57be3ea2acd3623b01f55c8de1092 /rumba | |
parent | 3081d070cda223afd548645143142e1104b07d83 (diff) | |
parent | 53602860e17d650f9ab850cf9a206de6a8712c15 (diff) | |
download | rumba-457977f337a47caddf8788e1d4e1d1736f2a6ccb.tar.gz rumba-457977f337a47caddf8788e1d4e1d1736f2a6ccb.zip |
Merge branch 'master' into policies
Diffstat (limited to 'rumba')
-rw-r--r-- | rumba/model.py | 234 | ||||
-rwxr-xr-x | rumba/prototypes/enroll.py | 8 | ||||
-rw-r--r-- | rumba/prototypes/irati.py | 52 | ||||
-rw-r--r-- | rumba/prototypes/ouroboros.py | 28 | ||||
-rw-r--r-- | rumba/prototypes/rlite.py | 35 | ||||
-rw-r--r-- | rumba/ssh_support.py | 63 | ||||
-rw-r--r-- | rumba/testbeds/jfed.py | 51 | ||||
-rw-r--r-- | rumba/testbeds/qemu.py | 31 |
8 files changed, 366 insertions, 136 deletions
diff --git a/rumba/model.py b/rumba/model.py index 442933c..e0f1dcc 100644 --- a/rumba/model.py +++ b/rumba/model.py @@ -20,6 +20,9 @@ # MA 02110-1301 USA import abc +import random + +import time import rumba.log as log @@ -35,11 +38,18 @@ logger = log.get_logger(__name__) # @exp_name [string] experiment name # class Testbed: - def __init__(self, exp_name, username, password, proj_name): + def __init__(self, + exp_name, + username, + password, + proj_name, + http_proxy=None): self.username = username self.password = password self.proj_name = proj_name self.exp_name = exp_name + self.http_proxy = http_proxy + self.flags = {'no_vlan_offload': False} @abc.abstractmethod def swap_in(self, experiment): @@ -152,13 +162,12 @@ class SSHConfig: # # @difs: DIFs the node will have an IPCP in # @dif_registrations: Which DIF is registered in which DIF -# @registrations: Registrations of names in DIFs -# @bindings: Binding of names on the processing system # @policies: dict of dif -> policy dict to apply for that dif in this node # +# class Node: def __init__(self, name, difs=None, dif_registrations=None, - registrations=None, bindings=None, policies=None): + client=False, policies=None): self.name = name if difs is None: difs = list() @@ -168,12 +177,6 @@ class Node: if dif_registrations is None: dif_registrations = dict() self.dif_registrations = dif_registrations - if registrations is None: - registrations = dict() - self.registrations = registrations - if bindings is None: - bindings = dict() - self.bindings = bindings self.ssh_config = SSHConfig(name) self.ipcps = [] if policies is None: @@ -183,6 +186,7 @@ class Node: if hasattr(dif, 'policy'): self.policies[dif] = \ Policy(dif, self, policies.get(dif.name, {})) + self.client = client self._validate() @@ -197,18 +201,14 @@ class Node: "to be part of DIF %s" % (self.name, dif.name)) def _validate(self): - # Check that DIFs referenced in self.dif_registrations and - # in self.registrations are part of self.difs + # Check that DIFs referenced in self.dif_registrations + # are part of self.difs for upper in self.dif_registrations: self._undeclared_dif(upper) for lower in self.dif_registrations[upper]: self._undeclared_dif(lower) - for appl in self.registrations: - for dif in self.registrations[appl]: - self._undeclared_dif(dif) - - def __repr__(self): # TODO add policies in repr? + def __repr__(self): # TODO add policies in repr s = "Node " + self.name + ":\n" s += " DIFs: [ " @@ -226,19 +226,6 @@ class Node: s += ", ".join(rl) s += " ]\n" - s += " Name registrations: [ " - for name in self.registrations: - difs = self.registrations[name] - s += "%s => [ " % name - s += ", ".join([dif.name for dif in difs]) - s += " ]" - s += " ]\n" - - s += " Bindings: [ " - s += ", ".join(["'%s' => '%s'" % (ap, self.bindings[ap]) - for ap in self.bindings]) - s += " ]\n" - return s def __hash__(self): @@ -275,22 +262,6 @@ class Node: self.dif_registrations[upper].remove(lower) self._validate() - def add_registration(self, name, dif): - self.dif_registrations[name].append(dif) - self._validate() - - def del_registration(self, name, dif): - self.dif_registrations[name].remove(dif) - self._validate() - - def add_binding(self, name, ap): - self.bindings[name] = ap - self._validate() - - def del_binding(self, name): - del self.bindings[name] - self._validate() - def add_policy(self, dif, component_name, policy_name, **parameters): self.policies[dif].add_policy(component_name, policy_name, **parameters) @@ -311,7 +282,7 @@ class IPCP: self.dif = dif self.registrations = [] - # Is this node the first in the DIF, so that it does not need + # Is this IPCP the first in its DIF, so that it does not need # to enroll to anyone ? self.dif_bootstrapper = False @@ -424,6 +395,10 @@ class Experiment: difsdeps_inc = dict() for node in self.nodes: + for dif in node.difs: + if dif not in difsdeps_adj: + difsdeps_adj[dif] = set() + for upper in node.dif_registrations: for lower in node.dif_registrations[upper]: if upper not in difsdeps_inc: @@ -445,6 +420,14 @@ class Experiment: difsdeps_inc_cnt[dif] = len(difsdeps_inc[dif]) del difsdeps_inc + # Init difsdeps_inc_cnt for those DIFs that do not + # act as lower IPCPs nor upper IPCPs for registration + # operations + for node in self.nodes: + for dif in node.difs: + if dif not in difsdeps_inc_cnt: + difsdeps_inc_cnt[dif] = 0 + # Run Kahn's algorithm to compute topological # ordering on the DIFs graph. frontier = set() @@ -576,6 +559,7 @@ class Experiment: if dif not in node.difs: continue + # Create an instance of the required IPCP class ipcp = dif.get_ipcp_class()( name='%s.%s' % (dif.name, node.name), node=node, dif=dif) @@ -584,23 +568,34 @@ class Experiment: for lower in node.dif_registrations[dif]: ipcp.registrations.append(lower) + node.ipcps.append(ipcp) + dif.ipcps.append(ipcp) + + def compute_bootstrappers(self): + for node in self.nodes: + for ipcp in node.ipcps: ipcp.dif_bootstrapper = True for el in self.enrollments: for e in el: - if e['dif'] != dif: + if e['dif'] != ipcp.dif: # Skip this DIF break - if e['enrollee'] == node: + if e['enrollee'] == ipcp: ipcp.dif_bootstrapper = False # Exit the loops break if not ipcp.dif_bootstrapper: break - node.ipcps.append(ipcp) - dif.ipcps.append(ipcp) - - logger.info("IPCP for node %s: %s", node.name, node.ipcps) + def dump_ssh_info(self): + f = open('ssh_info', 'w') + for node in self.nodes: + f.write("%s;%s;%s;%s;%s\n" % (node.name, + self.testbed.username, + node.ssh_config.hostname, + node.ssh_config.port, + node.ssh_config.proxycommand)) + f.close() # Examine the nodes and DIFs, compute the registration and enrollment # order, the list of IPCPs to create, registrations, ... @@ -608,19 +603,148 @@ class Experiment: self.compute_dif_ordering() self.compute_ipcps() self.compute_enrollments() + self.compute_bootstrappers() + for node in self.nodes: + logger.info("IPCPs for node %s: %s", node.name, node.ipcps) @abc.abstractmethod def install_prototype(self): - raise Exception('run_prototype() method not implemented') + raise Exception('install_prototype() method not implemented') @abc.abstractmethod def bootstrap_prototype(self): - raise Exception('run_prototype() method not implemented') + raise Exception('bootstrap_prototype() method not implemented') + + @abc.abstractmethod + def prototype_name(self): + raise Exception('prototype_name() method not implemented') def swap_in(self): # Realize the experiment testbed (testbed-specific) self.testbed.swap_in(self) + self.dump_ssh_info() def swap_out(self): # Undo the testbed (testbed-specific) self.testbed.swap_out(self) + + +# Base class for client programs +# +# @ap: Application Process binary +# @options: Options to pass to the binary +# +class Client(object): + def __init__(self, ap, options=None): + self.ap = ap + self.options = options + + def start_process(self, node, duration, start_time): + return ClientProcess(self.ap, node, duration, start_time, self.options) + + +# Base class for client processes +# +# @ap: Application Process binary +# @node: The node on which this process should run +# @duration: The time (in seconds) this process should run +# @start_time: The time at which this process is started. +# @options: Options to pass to the binary +# +class ClientProcess(Client): + def __init__(self, ap, node, duration, start_time, options=None): + super(ClientProcess, self).__init__(ap, options=options) + self.node = node + self.duration = duration + self.start_time = start_time + self.run() + self.running = True + + def run(self): + pass # TODO to be implemented + + def stop(self): + pass # TODO to be implemented + + def check(self, now): + if not self.running: + return + if now - self.start_time >= self.duration: + self.stop() + + +# Base class for server programs +# +# @ap: Application Process binary +# @arrival_rate: Average requests/s to be received by this server +# @mean_duration: Average duration of a client connection (in seconds) +# @options: Options to pass to the binary +# @max_clients: Maximum number of clients to serve +# @clients: Client binaries that will use this server +# @nodes: Specific nodes to start this server on +# +class Server: + def __init__(self, ap, arrival_rate, mean_duration, + options=None, max_clients=None, + clients=None, nodes=None): + self.ap = ap + self.options = options + self.max_clients = max_clients + if clients is None: + clients = list() + self.clients = clients + self.nodes = nodes + self.arrival_rate = arrival_rate # mean requests/s + self.mean_duration = mean_duration # in seconds + + def add_client(self, client): + self.clients.append(client) + + def del_client(self, client): + self.clients.remove(client) + + def add_node(self, node): + self.nodes.append(node) + + def del_node(self, node): + self.nodes.remove(node) + + def get_new_clients(self, interval): + """ + Returns a list of clients of size appropriate to the server's rate. + + The list's size should be a sample from Poisson(arrival_rate) over + interval seconds. + Hence, the average size should be interval * arrival_rate. + """ + pass + + def make_client_process(self): + """Returns a client of this server""" + if len(self.clients) == 0: + raise Exception("Server %s has empty client list," % (self,)) + pass # TODO should return a ClientProcess + + +# Base class for ARCFIRE storyboards +# +# @experiment: Experiment to use as input +# @duration: Duration of the whole storyboard +# @servers: App servers available in the network +# +class StoryBoard: + def __init__(self, experiment, duration, servers=None): + self.experiment = experiment + self.duration = duration + if servers is None: + servers = list() + self.servers = servers + + def add_server(self, server): + self.servers.append(server) + + def del_server(self, server): + self.servers.remove(server) + + def start(self): + pass diff --git a/rumba/prototypes/enroll.py b/rumba/prototypes/enroll.py index 458736a..99b49a6 100755 --- a/rumba/prototypes/enroll.py +++ b/rumba/prototypes/enroll.py @@ -78,8 +78,8 @@ if connected: get_response(s) # Send the IPCP list command - cmd = 'list-ipcps\n' - s.sendall(bytes(cmd, 'ascii')) + cmd = u'list-ipcps\n' + s.sendall(cmd.encode('ascii')) # Get the list of IPCPs and parse it to look for the enroller ID print('Looking up identifier for IPCP %s' % args.enrollee_name) @@ -98,11 +98,11 @@ if connected: raise Exception() # Send the enroll command - cmd = 'enroll-to-dif %s %s %s %s 1\n' \ + cmd = u'enroll-to-dif %s %s %s %s 1\n' \ % (enrollee_id, args.dif, args.lower_dif, args.enroller_name) print(cmd) - s.sendall(bytes(cmd, 'ascii')) + s.sendall(cmd.encode('ascii')) # Get the enroll command answer lines = get_response(s) diff --git a/rumba/prototypes/irati.py b/rumba/prototypes/irati.py index b2f54d9..42afe3b 100644 --- a/rumba/prototypes/irati.py +++ b/rumba/prototypes/irati.py @@ -21,8 +21,6 @@ import copy import json -import subprocess - import os import time @@ -38,6 +36,9 @@ logger = log.get_logger(__name__) # An experiment over the IRATI implementation class Experiment(mod.Experiment): + def prototype_name(self): + return 'irati' + @staticmethod def real_sudo(s): return 'sudo ' + s @@ -69,25 +70,24 @@ class Experiment(mod.Experiment): def install(self): """Installs IRATI on the nodes.""" - cmds = list() - - cmds.append("sudo apt-get update") - cmds.append("sudo apt-get install g++ gcc " - "protobuf-compiler libprotobuf-dev git --yes") - cmds.append("sudo rm -rf ~/irati") - cmds.append("cd && git clone https://github.com/IRATI/stack irati") - cmds.append("cd ~/irati && sudo ./install-from-scratch") + cmds = [self.sudo("apt-get update"), + "export https_proxy=\"https://proxy.atlantis.ugent.be:8080\"; " + + self.sudo("apt-get install g++ gcc " + "protobuf-compiler libprotobuf-dev git --yes " + "pkg-config " + "libnl-3-dev libnl-genl-3-dev"), + self.sudo("rm -rf ~/irati"), + "cd ~; " + "export https_proxy=\"https://proxy.atlantis.ugent.be:8080\"; " + + "git clone https://github.com/IRATI/stack irati", + "cd ~/irati && git checkout arcfire", + "cd ~/irati && " + + self.sudo("./install-from-scratch")] for node in self.nodes: - ssh.execute_commands(self.testbed, node.ssh_config, + ssh.execute_proxy_commands(self.testbed, node.ssh_config, cmds, time_out=None) - def setup(self): - for node in self.nodes: - ssh.execute_command(self.testbed, node.ssh_config, - "sudo nohup ipcm &> ipcm.log &", - time_out=None) - def bootstrap_network(self): """Creates the network by enrolling and configuring the nodes""" for node in self.nodes: @@ -101,8 +101,6 @@ class Experiment(mod.Experiment): def bootstrap_prototype(self): logger.info("setting up") - self.setup() - logger.info("software initialized on all nodes") self.conf_files = self.write_conf() logger.info("configuration files generated for all nodes") self.bootstrap_network() @@ -144,7 +142,6 @@ class Experiment(mod.Experiment): 'genfiles': gen_files, 'genfilesconf': ' '.join(gen_files_conf), 'genfilesbin': gen_files_bin, - 'installpath': '/usr', 'verb': 'DBG', 'ipcmcomps': ipcm_components} @@ -155,13 +152,16 @@ class Experiment(mod.Experiment): '') cmds = [self.sudo('hostname %(name)s' % format_args), + self.sudo('modprobe rina-irati-core'), self.sudo('chmod a+rw /dev/irati'), self.sudo('mv %(genfilesconf)s /etc' % format_args), self.sudo('mv %(genfilesbin)s /usr/bin') % format_args, self.sudo('chmod a+x /usr/bin/enroll.py') % format_args] cmds += [self.sudo('modprobe rina-default-plugin'), - self.sudo('%(installpath)s/bin/ipcm -a \"%(ipcmcomps)s\" ' + self.sudo('modprobe shim-eth-vlan'), + self.sudo('modprobe normal-ipcp'), + self.sudo('ipcm -a \"%(ipcmcomps)s\" ' '-c /etc/%(name)s.ipcm.conf -l %(verb)s &> log &' % format_args)] @@ -170,6 +170,8 @@ class Experiment(mod.Experiment): def enroll_nodes(self): """Runs the enrollments one by one, respecting dependencies""" + logger.info("Waiting 5 seconds for the ipcm to start.") + time.sleep(5) for enrollment_list in self.enrollments: for e in enrollment_list: logger.info( @@ -225,16 +227,10 @@ class Experiment(mod.Experiment): next_vlan += 10 self.shim2vlan[dif.name] = vlan - # TODO: what format are the mappings registered in? Is this ok? - app_mappings = [] - for node in self.nodes: - app_mappings += [{'name': app, 'dif': self.dif_name(dif)} - for app in node.registrations - for dif in node.registrations[app]] - # If some app directives were specified, use those to build da.map. # Otherwise, assume the standard applications are to be mapped in # the DIF with the highest rank. + app_mappings = [] if len(app_mappings) == 0: if len(self.dif_ordering) > 0: for adm in \ diff --git a/rumba/prototypes/ouroboros.py b/rumba/prototypes/ouroboros.py index 9c164e7..9ac1425 100644 --- a/rumba/prototypes/ouroboros.py +++ b/rumba/prototypes/ouroboros.py @@ -32,6 +32,9 @@ class Experiment(mod.Experiment): def __init__(self, testbed, nodes=None): mod.Experiment.__init__(self, testbed, nodes) + def prototype_name(self): + return 'ouroboros' + def setup_ouroboros(self): for node in self.nodes: ssh.execute_command(self.testbed, node.ssh_config, @@ -50,27 +53,6 @@ class Experiment(mod.Experiment): ssh.execute_commands(self.testbed, node.ssh_config, cmds, time_out=None) - def bind_names(self): - for node in self.nodes: - cmds = list() - for name, ap in node.bindings.items(): - cmds.append("irm b ap " + ap + " n " + name) - - ssh.execute_commands(self.testbed, node.ssh_config, - cmds, time_out=None) - - def reg_names(self): - for node in self.nodes: - cmds = list() - for name, difs in node.registrations.items(): - cmd = "irm r n " + name - for dif in difs: - cmd += " dif " + dif.name - cmds.append(cmd) - - ssh.execute_commands(self.testbed, node.ssh_config, cmds, - time_out=None) - def create_ipcps(self): for node in self.nodes: cmds = list() @@ -147,12 +129,8 @@ class Experiment(mod.Experiment): def bootstrap_prototype(self): logger.info("Starting IRMd on all nodes...") self.setup_ouroboros() - logger.info("Binding names...") - self.bind_names() logger.info("Creating IPCPs") self.create_ipcps() logger.info("Enrolling IPCPs...") self.enroll_ipcps() - logger.info("Registering names...") - self.reg_names() logger.info("All done, have fun!") diff --git a/rumba/prototypes/rlite.py b/rumba/prototypes/rlite.py index 8a06b44..cc38255 100644 --- a/rumba/prototypes/rlite.py +++ b/rumba/prototypes/rlite.py @@ -34,21 +34,32 @@ class Experiment(mod.Experiment): def __init__(self, testbed, nodes=None): mod.Experiment.__init__(self, testbed, nodes) + def prototype_name(self): + return 'rlite' + def execute_commands(self, node, cmds): ssh.execute_commands(self.testbed, node.ssh_config, cmds, time_out=None) + def execute_proxy_commands(self, node, cmds): + ssh.execute_proxy_commands(self.testbed, node.ssh_config, + cmds, time_out=None) + + # Prepend sudo to all commands if the user is not 'root' + def may_sudo(self, cmds): + if self.testbed.username != 'root': + for i in range(len(cmds)): + cmds[i] = "sudo %s" % cmds[i] + def init_nodes(self): + # Load kernel modules and start the uipcps daemon cmds = ["modprobe rlite", "modprobe rlite-normal", "modprobe rlite-shim-eth", "modprobe rlite-shim-udp4", "modprobe rlite-shim-loopback", "rlite-uipcps -v DBG -k 0 &> uipcp.log &"] - - # Load kernel modules - - # Start the uipcps daemon + self.may_sudo(cmds) for node in self.nodes: self.execute_commands(node, cmds) @@ -80,6 +91,7 @@ class Experiment(mod.Experiment): cmds.append("rlite-ctl ipcp-config %s netdev %s" % (ipcp.name, ipcp.ifname)) + self.may_sudo(cmds) self.execute_commands(node, cmds) def register_ipcps(self): @@ -91,6 +103,7 @@ class Experiment(mod.Experiment): cmds.append("rlite-ctl ipcp-register %s %s" % (ipcp.name, lower.name)) + self.may_sudo(cmds) self.execute_commands(node, cmds) def enroll_ipcps(self): @@ -103,21 +116,25 @@ class Experiment(mod.Experiment): } cmd = "rlite-ctl ipcp-enroll %(enrollee)s %(dif)s "\ "%(lower_dif)s %(enroller)s" % d - self.execute_commands(e['enrollee'].node, [cmd]) + cmds = [cmd] + self.may_sudo(cmds) + self.execute_commands(e['enrollee'].node, cmds) time.sleep(1) def install_prototype(self): logger.info("installing rlite on all nodes") - cmds = ["apt-get update", - "apt-get install g++ gcc cmake " + cmds = ["sudo apt-get update", + "sudo -E apt-get install g++ gcc cmake " "linux-headers-$(uname -r) " "protobuf-compiler libprotobuf-dev git --yes", "rm -rf ~/rlite", "cd ~; git clone https://github.com/vmaffione/rlite", - "cd ~/rlite && ./configure && make && sudo make install"] + "cd ~/rlite && ./configure && make && sudo make install", + "cd ~/rlite && sudo make depmod" + ] for node in self.nodes: - self.execute_commands(node, cmds) + self.execute_proxy_commands(node, cmds) logger.info("installation complete") def bootstrap_prototype(self): diff --git a/rumba/ssh_support.py b/rumba/ssh_support.py index 26d64fb..a1e1ba4 100644 --- a/rumba/ssh_support.py +++ b/rumba/ssh_support.py @@ -43,6 +43,51 @@ def _print_stream(stream): return o +def execute_proxy_commands(testbed, ssh_config, commands, time_out=3): + """ + Remote execution of a list of shell command on hostname, using the + http and https proxy specified by the testbed. By + default this function will exit (timeout) after 3 seconds. + + @param testbed: testbed info + @param ssh_config: ssh config of the node + @param commands: *nix shell command + @param time_out: time_out value in seconds, error will be generated if + no result received in given number of seconds, the value None can + be used when no timeout is needed + """ + new_commands = [] + for command in commands: + proxy = testbed.http_proxy + if proxy is not None: + proxy_command = 'export http_proxy=' + proxy + '; ' \ + + 'export https_proxy=' + proxy + ';' + new_commands.append(proxy_command + ' ' + command) + else: + new_commands.append(command) + return execute_commands(testbed, ssh_config, new_commands, time_out) + + +def execute_proxy_command(testbed, ssh_config, command, time_out=3): + """ + Remote execution of a list of shell command on hostname, using + a proxy http and https. + By default this function will exit (timeout) after 3 seconds. + + @param testbed: testbed info + @param ssh_config: ssh config of the node + @param command: *nix shell command + @param time_out: time_out value in seconds, error will be generated if + no result received in given number of seconds, the value None can + be used when no timeout is needed + + @return: stdout resulting from the command + """ + o = execute_proxy_commands(testbed, ssh_config, [command], time_out) + if o is not None: + return o + + def execute_commands(testbed, ssh_config, commands, time_out=3): """ Remote execution of a list of shell command on hostname. By @@ -160,6 +205,11 @@ def copy_paths_to_testbed(testbed, ssh_config, paths, destination): """ ssh_client = get_ssh_client() + if ssh_config.proxycommand is not None: + proxy = paramiko.ProxyCommand(ssh_config.proxycommand) + else: + proxy = None + if destination is not '' and not destination.endswith('/'): destination = destination + '/' @@ -167,7 +217,8 @@ def copy_paths_to_testbed(testbed, ssh_config, paths, destination): ssh_client.connect(ssh_config.hostname, ssh_config.port, testbed.username, testbed.password, - look_for_keys=True) + look_for_keys=True, + sock=proxy) sftp_client = ssh_client.open_sftp() @@ -224,9 +275,9 @@ def setup_vlan(testbed, node, vlan_id, int_name): % args), sudo("ifconfig %(ifname)s.%(vlan)s up" % args)] - # TODO: is ethtool needed? Should install or check if it is present. - # cmds += [sudo("ethtool -K %(ifname)s rxvlan off" - # % args), - # sudo("ethtool -K %(ifname)s txvlan off" - # % args)] + if testbed.flags['no_vlan_offload']: + cmds += [sudo("ethtool -K %(ifname)s rxvlan off" + % args), + sudo("ethtool -K %(ifname)s txvlan off" + % args)] execute_commands(testbed, node.ssh_config, cmds) diff --git a/rumba/testbeds/jfed.py b/rumba/testbeds/jfed.py index 5394146..83fbce7 100644 --- a/rumba/testbeds/jfed.py +++ b/rumba/testbeds/jfed.py @@ -27,7 +27,7 @@ import tarfile import rumba.model as mod import rumba.log as log - +from rumba import ssh_support logger = log.get_logger(__name__) @@ -38,7 +38,12 @@ class Testbed(mod.Testbed): proj_name="ARCFIRE", authority="wall2.ilabt.iminds.be", image=None): passwd = getpass.getpass(prompt="Password for certificate file: ") - mod.Testbed.__init__(self, exp_name, username, passwd, proj_name) + mod.Testbed.__init__(self, + exp_name, + username, + passwd, + proj_name, + http_proxy="https://proxy.atlantis.ugent.be:8080") self.authority = "urn:publicid:IDN+" + authority + "+authority+cm" self.auth_name = authority self.cert_file = cert_file @@ -49,7 +54,7 @@ class Testbed(mod.Testbed): self.jfed_jar = "jfed_cli/experimenter-cli.jar" if image is not None: self.image = "urn:publicid:IDN+" + authority + \ - "+image+GeniSlices:" + image + "+image+wall2-ilabt-iminds-be:" + image else: self.image = None @@ -63,6 +68,7 @@ class Testbed(mod.Testbed): tar.close() logger.info("Extracted in current directory") os.remove(tarball) + self.flags['no_vlan_offload'] = True def create_rspec(self, experiment): impl = xml.getDOMImplementation() @@ -164,22 +170,55 @@ class Testbed(mod.Testbed): rspec = xml.parse(self.manifest) xml_nodes = rspec.getElementsByTagName("node") + dir_path = os.path.dirname(os.path.abspath(__file__)) + # Complete details of the nodes after swapin for xml_node in xml_nodes: n_name = xml_node.getAttribute("client_id") intfs = xml_node.getElementsByTagName("interface") + got = False for node in experiment.nodes: if node.name == n_name: node_n = node + got = True + if not got: + logger.error("Not found node %s", n_name) for intf in intfs: + aux_mac_address = intf.getAttribute("mac_address") + mac = ":".join( + [aux_mac_address[i:i+2] for i in range(0, 12, 2)] + ) + command = ( + 'echo "mac=\\"\$1\\"; cd / && ./sbin/ifconfig -a | ' + 'awk \'/^[a-z]/ { if ( \\"\'\\"\$mac\\"\'\\" == \$5 )' + ' print \$1}\'" > mac2ifname.sh') + ssh_support.execute_command(self, node_n.ssh_config, command) + + # ssh_support.copy_path_to_testbed( + # self, + # node_n.ssh_config, + # os.path.join(dir_path, 'mac2ifname.sh'), + # '') + ssh_support.execute_command( + self, + node_n.ssh_config, + 'cd ~ && chmod a+x mac2ifname.sh') + ifname = ssh_support.execute_command( + self, + node_n.ssh_config, + './mac2ifname.sh ' + mac + ) i_name = intf.getAttribute("client_id") for ipcp in node_n.ipcps: if isinstance(ipcp, mod.ShimEthIPCP): if self.if_id[ipcp] == i_name: - comp_id = intf.getAttribute("component_id") - comp_arr = comp_id.split(":") - ipcp.ifname = comp_arr[-1] + ipcp.ifname = ifname + logger.debug("Node %s interface %s has name %s." + % (node_n.name, mac, ifname)) + # comp_id = intf.getAttribute("component_id") + # comp_arr = comp_id.split(":") + # ipcp.ifname = comp_arr[-1] # xml_ip = intf.getElementsByTagName("ip") # interface.ip = xml_ip[0].getAttribute("address") diff --git a/rumba/testbeds/qemu.py b/rumba/testbeds/qemu.py index a916525..df02ab6 100644 --- a/rumba/testbeds/qemu.py +++ b/rumba/testbeds/qemu.py @@ -26,24 +26,25 @@ import os import rumba.model as mod import rumba.log as log import rumba.ssh_support as ssh_support +import wget logger = log.get_logger(__name__) class Testbed(mod.Testbed): - def __init__(self, exp_name, bzimage, initramfs, proj_name="ARCFIRE", + def __init__(self, exp_name, bzimage=None, initramfs=None, proj_name="ARCFIRE", password="root", username="root", 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_logs_dir = os.getcwd() if qemu_logs_dir is None \ else qemu_logs_dir self.boot_processes = [] + self.bzimage = bzimage + self.initramfs = initramfs @staticmethod def _run_command_chain(commands, results_queue, @@ -110,10 +111,34 @@ class Testbed(mod.Testbed): if os.geteuid() != 0: try: subprocess.check_call(["sudo", "-v"]) + if not os.access("/dev/vhost-net", os.R_OK) \ + or not os.access("/dev/vhost-net", os.W_OK) \ + or not os.access("/dev/kvm", os.R_OK) \ + or not os.access("/dev/kvm", os.W_OK): + raise Exception('Cannot open vhost device. Make sure it is' + 'available and you have rw permissions ' + 'on /dev/vhost-net') except subprocess.CalledProcessError: raise Exception('Not authenticated') logger.info("swapping in") + + # Download the proper buildroot images, if the user did not specify + # local images + url_prefix = "https://bitbucket.org/vmaffione/rina-images/downloads/" + if not self.bzimage: + self.bzimage = '%s.bzImage' % (experiment.prototype_name()) + if not os.path.exists(self.bzimage): + logger.info("Downloading %s" % (url_prefix + self.bzimage)) + wget.download(url_prefix + self.bzimage) + print("\n") + if not self.initramfs: + self.initramfs = '%s.rootfs.cpio' % (experiment.prototype_name()) + if not os.path.exists(self.initramfs): + logger.info("Downloading %s" % (url_prefix + self.initramfs)) + wget.download(url_prefix + self.initramfs) + print("\n") + logger.info('Setting up interfaces.') # Building bridges and taps |