aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md10
-rwxr-xr-xexamples/example.py7
-rw-r--r--rumba/log.py5
-rw-r--r--rumba/model.py133
-rw-r--r--rumba/prototypes/irati.py15
-rw-r--r--rumba/prototypes/irati_templates.py6
-rw-r--r--rumba/prototypes/ouroboros.py6
-rw-r--r--rumba/prototypes/rlite.py8
-rw-r--r--rumba/ssh_support.py2
-rw-r--r--rumba/testbeds/jfed.py14
-rw-r--r--rumba/testbeds/qemu.py11
-rwxr-xr-xsetup.py6
12 files changed, 174 insertions, 49 deletions
diff --git a/README.md b/README.md
index 25d79fd..db3211a 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-# Rumba: A framework to install, bootstrap a RINA network
+# Rumba: A framework to bootstrap a RINA network on a testbed
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
+Python which allows a 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, if the
user requests this, one of the supported RINA prototypes is
@@ -128,6 +128,9 @@ folder.
$ eval `ssh-agent`
$ ssh-add /home/morty/cert.pem
+ Pay attention to run your rumba script in the same terminal used for the
+ previous commands, without changing the user (e.g. using su or sudo).
+
## Accessing nodes after swap-in
To access a node once the experiment swapped in, use the following
@@ -135,4 +138,5 @@ folder.
$ rumba-access $NODE_NAME
- Where $NODE_NAME is the name of the node to access. \ No newline at end of file
+ Where $NODE_NAME is the name of the node to access.
+
diff --git a/examples/example.py b/examples/example.py
index 1acc883..567852f 100755
--- a/examples/example.py
+++ b/examples/example.py
@@ -19,8 +19,11 @@ import rumba.log as log
log.set_logging_level('DEBUG')
-n1 = NormalDIF("n1", policies = {"rmt.pff": "lfa",
- "security-manager": "passwd"})
+
+n1 = NormalDIF("n1")
+
+n1.add_policy("rmt.pff", "lfa")
+n1.add_policy("security-manager", "passwd")
e1 = ShimEthDIF("e1")
diff --git a/rumba/log.py b/rumba/log.py
index 987f03a..c509532 100644
--- a/rumba/log.py
+++ b/rumba/log.py
@@ -47,9 +47,8 @@ class RumbaFormatter(logging.Formatter):
def __init__(self):
super(RumbaFormatter, self).__init__(
- fmt='{asctime} | {levelname:3.3} | '
- '{name:11.11} | {message}',
- style='{',
+ fmt='%(asctime)s | %(levelname)3.3s | '
+ '%(name)11.11s | %(message)s',
datefmt='%H:%M:%S')
def format(self, record):
diff --git a/rumba/model.py b/rumba/model.py
index 5215065..46a2351 100644
--- a/rumba/model.py
+++ b/rumba/model.py
@@ -126,25 +126,30 @@ class ShimEthDIF(DIF):
# Normal DIF
#
-# @policies [dict] Policies of the normal DIF
+# @policies [dict] Policies of the normal DIF. Format:
+# dict( componentName: str --> comp_policy:
+# dict( policy_name: str --> parameters:
+# dict( name: str --> value: str )))
#
class NormalDIF(DIF):
- def __init__(self, name, members=None, policies=None):
+ def __init__(self, name, members=None, policy=None):
DIF.__init__(self, name, members)
- if policies is None:
- policies = dict()
- self.policies = policies
+ if policy is None:
+ policy = Policy(self)
+ self.policy = policy
- def add_policy(self, comp, pol):
- self.policies[comp] = pol
+ def add_policy(self, comp, pol, **params):
+ self.policy.add_policy(comp, pol, **params)
- def del_policy(self, comp):
- del self.policies[comp]
+ def del_policy(self, comp=None, policy_name=None):
+ self.policy.del_policy(comp, policy_name)
def show(self):
s = DIF.__repr__(self)
- for comp, pol in self.policies.items():
- s += "\n Component %s has policy %s" % (comp, pol)
+ for comp, pol_dict in self.policy.get_policies().items():
+ for pol, params in pol_dict.items():
+ s += "\n Component %s has policy %s with params %s" \
+ % (comp, pol, params)
return s
@@ -161,10 +166,12 @@ class SSHConfig:
#
# @difs: DIFs the node will have an IPCP in
# @dif_registrations: Which DIF is registered in which DIF
+# @policies: dict of dif -> policy to apply for that dif in this node
+#
#
class Node:
def __init__(self, name, difs=None, dif_registrations=None,
- client=False):
+ client=False, policies=None):
self.name = name
if difs is None:
difs = list()
@@ -176,6 +183,12 @@ class Node:
self.dif_registrations = dif_registrations
self.ssh_config = SSHConfig(name)
self.ipcps = []
+ self.policies = dict()
+ if policies is None:
+ policies = dict()
+ for dif in self.difs:
+ if hasattr(dif, 'policy'): # check if the dif supports policies
+ self.policies[dif] = policies.get(dif, Policy(dif, self))
self.client = client
self._validate()
@@ -216,6 +229,8 @@ class Node:
s += ", ".join(rl)
s += " ]\n"
+ s += " Policies: [ "
+
return s
def __hash__(self):
@@ -230,11 +245,18 @@ class Node:
def add_dif(self, dif):
self.difs.append(dif)
dif.add_member(self)
+ if hasattr(dif, 'policy'):
+ self.policies[dif] = Policy(dif, self)
self._validate()
def del_dif(self, dif):
self.difs.remove(dif)
dif.del_member(self)
+ try:
+ del self.policies[dif]
+ except KeyError:
+ # It was not in there, so nothing to do
+ pass
self._validate()
def add_dif_registration(self, upper, lower):
@@ -245,6 +267,15 @@ class Node:
self.dif_registrations[upper].remove(lower)
self._validate()
+ def add_policy(self, dif, component_name, policy_name, **parameters):
+ self.policies[dif].add_policy(component_name, policy_name, **parameters)
+
+ def del_policy(self, dif, component_name=None, policy_name=None):
+ self.policies[dif].del_policy(component_name, policy_name)
+
+ def get_policy(self, dif):
+ return self.policies[dif]
+
# Base class representing an IPC Process to be created in the experiment
#
@@ -293,6 +324,84 @@ class ShimUDPIPCP(IPCP):
# TODO: add IP and port
+# Class representing DIF and Node policies
+#
+# @dif: the dif this policy is applied to.
+# @node: the node
+#
+class Policy(object):
+ def __init__(self, dif, node=None, policies=None):
+ self.dif = dif # type: NormalDIF
+ self.node = node
+ if policies is None:
+ self._dict = dict()
+ else:
+ self._dict = policies
+
+ def add_policy(self, component_name, policy_name, **parameters):
+ self._dict.setdefault(component_name, dict())[policy_name] = parameters
+
+ #
+ # Fetches effective policy info
+ #
+ def get_policies(self, component_name=None, policy_name=None):
+ policy = self._superimpose()
+ if component_name is None:
+ return policy._dict
+ elif policy_name is None:
+ return policy._dict[component_name]
+ else:
+ return policy._dict[component_name][policy_name]
+
+ def del_policy(self, component_name=None, policy_name=None):
+ if component_name is None:
+ self._dict = dict()
+ elif policy_name is None:
+ del self._dict[component_name]
+ else:
+ del self._dict[component_name][policy_name]
+
+ #
+ # Merges this policy into that of its dif, obtaining
+ # the effective policy acting on self.node.
+ #
+ def _superimpose(self):
+ if self.node is None:
+ return self
+ other = self.dif.policy
+ base = dict(other._dict)
+ base.update(self._dict)
+ return Policy(self.dif, self.node, base)
+
+ def __eq__(self, other):
+ if not isinstance(other, Policy):
+ return False
+ else:
+ return other.dif == self.dif \
+ and other.node == self.node \
+ and other._dict == self._dict
+
+ def __str__(self):
+ node_str = (" Node: " + self.node) if self.node is not None else ""
+ return "Policy[Dif: %(dif)s,%(node_str)s Dict: %(dict)s]" \
+ % {"dif": self.dif, "node_str": node_str, "dict": self._dict}
+
+ def __repr__(self):
+ node_str = (" Node: " + self.node) if self.node is not None else ""
+ s = "Policy[ Dif: %(dif)s,%(node_str)s" \
+ % {"dif": self.dif, "node_str": node_str}
+ comps = []
+ for component in self._dict:
+ for policy in self._dict[component]:
+ comps.append("\n Component %s has policy %s with params %s"
+ % (component,
+ policy,
+ self._dict[component][policy]))
+ s += ",".join(comps)
+ s += "\n]\n"
+ return s
+
+
# Base class for ARCFIRE experiments
#
# @name [string] Name of the experiment
diff --git a/rumba/prototypes/irati.py b/rumba/prototypes/irati.py
index 42afe3b..c01e413 100644
--- a/rumba/prototypes/irati.py
+++ b/rumba/prototypes/irati.py
@@ -355,11 +355,16 @@ class Experiment(mod.Experiment):
"apName": "%s.%s.IPCP" % (dif.name, node_name),
"apInstance": "1",
"address": 16 + node2id_map[node_name]})
- for path, ps in dif.policies.items():
- # if policy['nodes'] == [] or vmname in policy['nodes']:
- # TODO: manage per-node-policies
- irati_templates.translate_policy(
- difconfs[dif.name][node_name], path, ps, parms=[])
+ policy_dict = node.get_policy(dif).get_policies()
+ for component in policy_dict:
+ for policy_name in policy_dict[component]:
+ params = policy_dict[component][policy_name].items()
+ irati_templates.translate_policy(
+ difconfs[dif.name][node_name],
+ component,
+ policy_name,
+ params
+ )
# Dump the DIF Allocator map
with open(self.conf_dir('da.map'), 'w') as da_map_file:
diff --git a/rumba/prototypes/irati_templates.py b/rumba/prototypes/irati_templates.py
index b8d9788..7d06c96 100644
--- a/rumba/prototypes/irati_templates.py
+++ b/rumba/prototypes/irati_templates.py
@@ -11,7 +11,7 @@ ipcmconf_base = {
"consoleSocket": "%(varpath)s/var/run/ipcm-console.sock" % env_dict,
"pluginsPaths": [
"%(installpath)s/lib/rinad/ipcp" % env_dict,
- "/lib/modules/4.1.33-irati/extra"
+ "/lib/modules/4.9.28-irati/extra"
]
},
@@ -238,7 +238,7 @@ def ps_set(d, k, v, parms):
if d[k]["name"] == v and "parameters" in d[k]:
cur_names = [p["name"] for p in d[k]["parameters"]]
for p in parms:
- name, value = p.split('=')
+ name, value = p
if name in cur_names:
for i in range(len(d[k]["parameters"])):
if d[k]["parameters"][i]["name"] == name:
@@ -249,7 +249,7 @@ def ps_set(d, k, v, parms):
elif len(parms) > 0:
d[k]["parameters"] = [
- {'name': p.split('=')[0], 'value': p.split('=')[1]}
+ {'name': p[0], 'value': p[1]}
for p in parms]
d[k]["name"] = v
diff --git a/rumba/prototypes/ouroboros.py b/rumba/prototypes/ouroboros.py
index 9ac1425..43cb1d5 100644
--- a/rumba/prototypes/ouroboros.py
+++ b/rumba/prototypes/ouroboros.py
@@ -63,13 +63,13 @@ class Experiment(mod.Experiment):
else:
cmd = "irm i c n " + ipcp.name
- if type(ipcp.dif) is mod.ShimEthDIF:
+ if isinstance(ipcp.dif, mod.ShimEthDIF):
# NOTE: Here to test with fake testbed
if ipcp.ifname is None:
ipcp.ifname = "eth0"
cmd += " type shim-eth-llc if_name " + ipcp.ifname
cmd += " dif " + ipcp.dif.name
- elif type(ipcp.dif) is mod.NormalDIF:
+ elif isinstance(ipcp.dif, mod.NormalDIF):
cmd += " type normal"
if ipcp.dif_bootstrapper:
cmd += " dif " + ipcp.dif.name
@@ -83,7 +83,7 @@ class Experiment(mod.Experiment):
for dif_b in node.dif_registrations[ipcp.dif]:
cmd2 += " dif " + dif_b.name
cmds2.append(cmd2)
- elif type(ipcp.dif) is mod.ShimUDPDIF:
+ elif isinstance(ipcp.dif, mod.ShimUDPDIF):
# FIXME: Will fail, since we don't keep IPs yet
cmd += " type shim-udp"
cmd += " dif " + ipcp.dif.name
diff --git a/rumba/prototypes/rlite.py b/rumba/prototypes/rlite.py
index cc38255..abab080 100644
--- a/rumba/prototypes/rlite.py
+++ b/rumba/prototypes/rlite.py
@@ -70,11 +70,11 @@ class Experiment(mod.Experiment):
for ipcp in node.ipcps:
# Generate the command to create the IPCP
- if type(ipcp.dif) is mod.NormalDIF:
+ if isinstance(ipcp.dif, mod.NormalDIF):
ipcp_type = 'normal'
- elif type(ipcp.dif) is mod.ShimEthDIF:
+ elif isinstance(ipcp.dif, mod.ShimEthDIF):
ipcp_type = 'shim-eth'
- elif type(ipcp.dif) is mod.ShimUDPDIF:
+ elif isinstance(ipcp.dif, mod.ShimUDPDIF):
ipcp_type = 'shim-udp4'
else:
logger.warning(
@@ -87,7 +87,7 @@ class Experiment(mod.Experiment):
# Generate the command to configure the interface
# name for the shim-eth
- if type(ipcp.dif) is mod.ShimEthDIF:
+ if isinstance(ipcp.dif, mod.ShimEthDIF):
cmds.append("rlite-ctl ipcp-config %s netdev %s"
% (ipcp.name, ipcp.ifname))
diff --git a/rumba/ssh_support.py b/rumba/ssh_support.py
index a1e1ba4..b0970e1 100644
--- a/rumba/ssh_support.py
+++ b/rumba/ssh_support.py
@@ -40,7 +40,7 @@ def _print_stream(stream):
o_array = o.split('\\n')
for oi in o_array:
logger.debug(oi)
- return o
+ return o.rstrip()
def execute_proxy_commands(testbed, ssh_config, commands, time_out=3):
diff --git a/rumba/testbeds/jfed.py b/rumba/testbeds/jfed.py
index 83fbce7..e158048 100644
--- a/rumba/testbeds/jfed.py
+++ b/rumba/testbeds/jfed.py
@@ -22,6 +22,8 @@ import subprocess
import getpass
import xml.dom.minidom as xml
import os.path
+
+import time
import wget
import tarfile
@@ -173,6 +175,9 @@ class Testbed(mod.Testbed):
dir_path = os.path.dirname(os.path.abspath(__file__))
# Complete details of the nodes after swapin
+ logger.info("Sleeping for two seconds to avoid contacting jfed nodes "
+ "too soon.")
+ time.sleep(2)
for xml_node in xml_nodes:
n_name = xml_node.getAttribute("client_id")
intfs = xml_node.getElementsByTagName("interface")
@@ -215,8 +220,13 @@ class Testbed(mod.Testbed):
if isinstance(ipcp, mod.ShimEthIPCP):
if self.if_id[ipcp] == i_name:
ipcp.ifname = ifname
- logger.debug("Node %s interface %s has name %s."
- % (node_n.name, mac, ifname))
+ if ifname is None:
+ logger.error("Could not determine name of node"
+ "%s interface %s"
+ % (node_n.name, mac))
+ else:
+ 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]
diff --git a/rumba/testbeds/qemu.py b/rumba/testbeds/qemu.py
index df02ab6..1d449dc 100644
--- a/rumba/testbeds/qemu.py
+++ b/rumba/testbeds/qemu.py
@@ -111,11 +111,12 @@ 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'
+ if self.vhost and \
+ (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:
diff --git a/setup.py b/setup.py
index 767313b..f00e934 100755
--- a/setup.py
+++ b/setup.py
@@ -4,11 +4,6 @@ from setuptools import setup
from codecs import open
from os import path
-here = path.abspath(path.dirname(__file__))
-
-with open(path.join(here, 'README.md'), encoding='utf-8') as f:
- long_description = f.read()
-
setup(
name="Rumba",
version="0.4",
@@ -18,7 +13,6 @@ setup(
author_email="sander.vrijders@intec.ugent.be",
license="LGPL",
description="Rumba measurement framework for RINA",
- long_description=long_description,
packages=["rumba", "rumba.testbeds", "rumba.prototypes"],
install_requires=["paramiko", "wheel", "wget"],
scripts = ['tools/rumba-access']