diff options
-rw-r--r-- | README.md | 68 | ||||
-rw-r--r-- | examples/mouse.py | 105 | ||||
-rwxr-xr-x | examples/two-layers.py | 10 | ||||
-rw-r--r-- | rumba/model.py | 83 | ||||
-rw-r--r-- | rumba/prototypes/irati.py | 13 | ||||
-rw-r--r-- | rumba/prototypes/ouroboros.py | 28 | ||||
-rw-r--r-- | rumba/prototypes/rlite.py | 13 | ||||
-rw-r--r-- | rumba/ssh_support.py | 45 | ||||
-rw-r--r-- | rumba/testbeds/jfed.py | 7 | ||||
-rw-r--r-- | rumba/testbeds/qemu.py | 24 | ||||
-rwxr-xr-x | tools/rumba-access | 31 |
11 files changed, 312 insertions, 115 deletions
@@ -3,17 +3,20 @@ Rumba is part of ARCFIRE 2020, Work Package 3. It is a framework in Python which allows user to write a Python script to define a RINA network. The physical graph needed for this RINA network is then -calculated and realised on one of the supported testbeds. Next, one of -the supported RINA prototypes is installed. After installation, the -network is bootstrapped. For an example of such a Python script, have -a look at the examples/ folder. +calculated and realised on one of the supported testbeds. Next, if the +user requests this, one of the supported RINA prototypes is +installed. The network is then bootstrapped on the available +nodes. Finally, the experiment can be swapped out of the testbed. For +an example of such a Python script, have a look at the examples/ +folder. ## Workflow, both external and internal: 1. User defines the network graph, creating instances of model.Node - and model.DIF classes + and model.DIF classes - 2. User creates an instance of a Testbed class + 2. User creates an instance of a Testbed class. See below for + testbed specific configuration 3. User creates an instance of prototype.Experiment class, passing the testbed instance and a list of Node instances @@ -23,17 +26,19 @@ a look at the examples/ folder. per-node IPCPs, registrations and enrollment, ready to be used by the plugins - 4. User calls run() on the prototype.Experiment instance: + 4. User calls methods on the prototype.Experiment instance: - 1. run() calls Testbed.swap_in(), passing the Experiment, and - filling in the missing information + 1. swap_in() swaps the experiment in on the testbed, and fills in + the missing information in the model. - 2. run() calls a prototype-specific setup function, to create the - required IPCPs, perform registrations, enrollments, etc. + 2. install_prototype() installs the chosen prototype on the + testbed. Currently an Ubuntu image is assumed. - 3. Perform tests (TODO) + 3. bootstrap_prototype() calls a prototype-specific setup function, + to create the required IPCPs, perform registrations, + enrollments, etc. - 4. run() calls Testbed.swap_out() + 4. swap_out() swaps the experiment out of the testbed. ## Installation @@ -69,10 +74,30 @@ a look at the examples/ folder. * [QEMU](http://wiki.qemu-project.org/Main_Page) is a generic and open source machine emulator and virtualizer. + A minimal QEMU testbed is defined as follows: + + tb = qemu.Testbed(exp_name = "twolayers", + username = "root", + password = "root") + + A user can optionally also specify the path to a bzImage and to an + initramfs. If they are not specified, the latest buildroot image + for the specific prototype will be downloaded. (Around 40 MB in + size) The login to those images is root/root. + * [Emulab](https://www.emulab.net/) is a network testbed, giving researchers a wide range of environments in which to develop, debug, and evaluate their systems. + An emulab testbed instance is defined as follows: + + tb = emulab.Testbed(exp_name = "rochefort10", + username = "ricksanchez") + + A password can also be provided but is not necessary when an SSH + key has been added. Optionally, a project name, a different testbed + URL and a custom image can be specified. + * [jFed](http://jfed.iminds.be/) is a Java-based framework for testbed federation. @@ -89,7 +114,8 @@ a look at the examples/ folder. Here the experiment name is rochefort10, the user's name is ricksanchez, and the certificate can be found in - /home/morty/cert.pem. An absolute path must be used for cert_file. + /home/morty/cert.pem. An absolute path must be used for + cert_file. Optionally a custom image can be selected. Before running the rumba you must run an SSH agent in same terminal. This will also avoid you having to enter the passphrase for every @@ -102,15 +128,15 @@ a look at the examples/ folder. $ eval `ssh-agent` $ ssh-add /home/morty/cert.pem - To access a node once the experiment swapped in, use the following - command (in the same terminal where ssh-agent was run): + To access a node once the experiment swapped in, use the following + command (in the same terminal where ssh-agent was run): - $ ssh -A -oProxyCommand="ssh -i $CERTPATH + $ ssh -A -oProxyCommand="ssh -i $CERTPATH -o StrictHostKeyChecking=no $USER@bastion.test.iminds.be nc $NODENAME.$EXP.wall2-ilabt-iminds-be.wall2.ilabt.iminds.be 22" $USER@$NODENAME.$EXP.wall2-ilabt-iminds-be.wall2.ilabt.iminds.be - where $CERTPATH is the absolute path of the certificate (e.g. - /home/morty/cert.pem), $USER is the jFed username (e.g. "ricksanchez"), - $NODENAME is the name of the node you want to access (e.g. "a"), - and $EXP is the name of the experiment (e.g. "rochefort10"). + where $CERTPATH is the absolute path of the certificate (e.g. + /home/morty/cert.pem), $USER is the jFed username (e.g. "ricksanchez"), + $NODENAME is the name of the node you want to access (e.g. "a"), + and $EXP is the name of the experiment (e.g. "rochefort10"). diff --git a/examples/mouse.py b/examples/mouse.py new file mode 100644 index 0000000..25e2487 --- /dev/null +++ b/examples/mouse.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python + +# An example script using the rumba package + +from rumba.model import * + +# import testbed plugins +import rumba.testbeds.emulab as emulab +import rumba.testbeds.jfed as jfed +import rumba.testbeds.faketestbed as fake +import rumba.testbeds.qemu as qemu + +# import prototype plugins +import rumba.prototypes.ouroboros as our +import rumba.prototypes.rlite as rl +import rumba.prototypes.irati as irati + +n01 = NormalDIF("n01") + +e01 = ShimEthDIF("e01") +e02 = ShimEthDIF("e02") +e03 = ShimEthDIF("e03") +e04 = ShimEthDIF("e04") +e05 = ShimEthDIF("e05") +e06 = ShimEthDIF("e06") +e07 = ShimEthDIF("e07") +e08 = ShimEthDIF("e08") +e09 = ShimEthDIF("e09") +e10 = ShimEthDIF("e10") +e11 = ShimEthDIF("e11") +e12 = ShimEthDIF("e12") +e13 = ShimEthDIF("e13") +e14 = ShimEthDIF("e14") +e15 = ShimEthDIF("e15") +e16 = ShimEthDIF("e16") +e17 = ShimEthDIF("e17") + + +a = Node("a", + difs = [n01, e01, e06, e13 ], + dif_registrations = {n01 : [e01, e06, e13]}) + +b = Node("b", + difs = [n01, e01, e02, e04], + dif_registrations = {n01 : [e01, e02, e04]}) + +c = Node("c", + difs = [n01, e02, e03], + dif_registrations = {n01 : [e02, e03]}) + +d = Node("d", + difs = [n01, e03, e04, e05], + dif_registrations = {n01 : [e03, e04, e05]}) + +e = Node("e", + difs = [n01, e05, e06, e07], + dif_registrations = {n01 : [e05, e06, e07]}) + +f = Node("f", + difs = [n01, e07, e08], + dif_registrations = {n01 : [e07, e08]}) + +g = Node("g", + difs = [n01, e08, e09, e14], + dif_registrations = {n01 : [e08, e09, e14]}) + +h = Node("h", + difs = [n01, e09, e10, e15], + dif_registrations = {n01 : [e09, e10, e15]}) + +i = Node("i", + difs = [n01, e10, e11, e16], + dif_registrations = {n01 : [e10, e11, e16]}) + +j = Node("j", + difs = [n01, e11, e12], + dif_registrations = {n01 : [e11, e12]}) + +k = Node("k", + difs = [n01, e12, e13], + dif_registrations = {n01 : [e12, e13]}) + +l = Node("l", + difs = [n01, e14, e15], + dif_registrations = {n01 : [e14, e15]}) + +m = Node("m", + difs = [n01, e16, e17], + dif_registrations = {n01 : [e16, e17]}) + +n = Node("n", + difs = [n01, e17], + dif_registrations = {n01 : [e17]}) + +tb = jfed.Testbed(exp_name = "mouse2", + cert_file = "/home/sander/cert.pem", + username = "sander") + +exp = rl.Experiment(tb, nodes = [a, b, c, d, e, f, g, h, i, j, k, l, m, n]) + +print(exp) + +exp.swap_in() +exp.install_prototype() +exp.bootstrap_prototype() diff --git a/examples/two-layers.py b/examples/two-layers.py index 9d1a6b3..b3622fd 100755 --- a/examples/two-layers.py +++ b/examples/two-layers.py @@ -32,9 +32,7 @@ e3 = ShimEthDIF("e3") a = Node("a", difs = [n3, n4, n1, e1], - dif_registrations = {n4: [n1], n3: [n1], n1 : [e1]}, - registrations = {"rinaperf.server" : [n3]}, - bindings = {"rinaperf.server" : "/usr/bin/rinaperf"}) + dif_registrations = {n4: [n1], n3: [n1], n1 : [e1]}) b = Node("b", difs = [n1, e1, e2], @@ -50,11 +48,9 @@ d = Node("d", tb = qemu.Testbed(exp_name = "twolayers", username = "root", - password = "root", - bzimage = '/home/vmaffione/git/rlite/demo/buildroot/bzImage', - initramfs = '/home/vmaffione/git/rlite/demo/buildroot/rootfs.cpio') + password = "root") -exp = rl.Experiment(tb, nodes = [a, b, c, d]) +exp = irati.Experiment(tb, nodes = [a, b, c, d]) print(exp) diff --git a/rumba/model.py b/rumba/model.py index 285d937..941cba8 100644 --- a/rumba/model.py +++ b/rumba/model.py @@ -38,11 +38,17 @@ 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 @abc.abstractmethod def swap_in(self, experiment): @@ -150,12 +156,10 @@ 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 # class Node: def __init__(self, name, difs=None, dif_registrations=None, - registrations=None, bindings=None, client=False): + client=False): self.name = name if difs is None: difs = list() @@ -165,12 +169,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 = [] self.client = client @@ -188,17 +186,13 @@ 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): s = "Node " + self.name + ":\n" @@ -217,19 +211,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): @@ -259,22 +240,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() - # Base class representing an IPC Process to be created in the experiment # @@ -363,6 +328,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: @@ -384,6 +353,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() @@ -543,6 +520,13 @@ class Experiment: if not ipcp.dif_bootstrapper: break + def dump_ssh_info(self): + f = open('ssh_info', 'w') + for node in self.nodes: + f.write("%s %s %s %s\n" % (node.name, self.testbed.username, + node.ssh_config.hostname, node.ssh_config.port)) + f.close() + # Examine the nodes and DIFs, compute the registration and enrollment # order, the list of IPCPs to create, registrations, ... def generate(self): @@ -555,15 +539,20 @@ class Experiment: @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) diff --git a/rumba/prototypes/irati.py b/rumba/prototypes/irati.py index c47d0d2..1e75efc 100644 --- a/rumba/prototypes/irati.py +++ b/rumba/prototypes/irati.py @@ -36,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 @@ -82,7 +85,7 @@ class Experiment(mod.Experiment): + 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): @@ -230,16 +233,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 625668d..cc38255 100644 --- a/rumba/prototypes/rlite.py +++ b/rumba/prototypes/rlite.py @@ -34,10 +34,17 @@ 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': @@ -117,17 +124,17 @@ class Experiment(mod.Experiment): def install_prototype(self): logger.info("installing rlite on all nodes") cmds = ["sudo apt-get update", - "export https_proxy=\"https://proxy.atlantis.ugent.be:8080\"; sudo -E apt-get install g++ gcc cmake " + "sudo -E apt-get install g++ gcc cmake " "linux-headers-$(uname -r) " "protobuf-compiler libprotobuf-dev git --yes", "rm -rf ~/rlite", - "cd ~; export https_proxy=\"https://proxy.atlantis.ugent.be:8080\"; git clone https://github.com/vmaffione/rlite", + "cd ~; git clone https://github.com/vmaffione/rlite", "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 cb36910..f8ba03b 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 diff --git a/rumba/testbeds/jfed.py b/rumba/testbeds/jfed.py index 54ad860..1e1c732 100644 --- a/rumba/testbeds/jfed.py +++ b/rumba/testbeds/jfed.py @@ -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 diff --git a/rumba/testbeds/qemu.py b/rumba/testbeds/qemu.py index a916525..b7ebef9 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, @@ -114,6 +115,23 @@ class Testbed(mod.Testbed): 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 diff --git a/tools/rumba-access b/tools/rumba-access new file mode 100755 index 0000000..06b0a02 --- /dev/null +++ b/tools/rumba-access @@ -0,0 +1,31 @@ +#!/bin/bash + +FILE=ssh_info + +MACHINE_ID=$1 +if [ "$MACHINE_ID" == "" ]; then + echo "usage: $0 NODE_NAME" + exit 255 +fi + +USER=$(grep "\<${MACHINE_ID}\>" ${FILE} | awk '{print $2}') +if [ "$USER" == "" ]; then + echo "Error: Node ${MACHINE_ID} unknown" + exit 255 +fi + +HOST=$(grep "\<${MACHINE_ID}\>" ${FILE} | awk '{print $3}') +if [ "$HOST" == "" ]; then + echo "Error: Node ${MACHINE_ID} unknown" + exit 255 +fi + +SSH_PORT=$(grep "\<${MACHINE_ID}\>" ${FILE} | awk '{print $4}') +if [ "$SSH_PORT" == "" ]; then + echo "Error: Node ${MACHINE_ID} unknown" + exit 255 +fi + +echo "Accessing Rumba node ${MACHINE_ID}" +# -o IdentityFile=buildroot/irati_rsa +ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p ${SSH_PORT} ${USER}@${HOST} |