aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/conf.py25
-rw-r--r--doc/docker.rst2
-rw-r--r--doc/emulab.rst2
-rw-r--r--doc/irati.rst2
-rw-r--r--doc/jfed.rst2
-rw-r--r--doc/local.rst2
-rw-r--r--doc/ouroboros.rst2
-rw-r--r--doc/qemu.rst2
-rw-r--r--doc/rlite.rst2
-rw-r--r--rumba/model.py304
10 files changed, 250 insertions, 95 deletions
diff --git a/doc/conf.py b/doc/conf.py
index 0424dc7..988dbf7 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -1,24 +1,7 @@
from datetime import datetime
-import alabaster
-
-
-html_theme_path = [alabaster.get_path()]
-extensions = ['alabaster']
-html_theme = 'alabaster'
-
-html_theme_options = {
- 'description': "Rumba: A framework to bootstrap a " +
- "recursive internet network on a testbed."
-}
-
-html_sidebars = {
- '**': [
- 'about.html',
- 'navigation.html',
- 'searchbox.html'
- ]
-}
+html_theme = "agogo"
+extensions = []
project = 'Rumba'
year = datetime.now().year
@@ -30,7 +13,9 @@ default_role = 'obj'
language = None
extensions.extend(['sphinx.ext.autodoc'])
-autodoc_default_flags = ['members', 'special-members']
+autodoc_default_flags = ['members']
+
+autoclass_content = 'both'
_locals = {}
with open('../rumba/_version.py') as fp:
diff --git a/doc/docker.rst b/doc/docker.rst
index 004240d..c82d40c 100644
--- a/doc/docker.rst
+++ b/doc/docker.rst
@@ -11,3 +11,5 @@ see `Install Docker <https://docs.docker.com/install/>`_ and complete
.. automodule:: rumba.testbeds.dockertb
:member-order: bysource
+ :show-inheritance:
+ :inherited-members:
diff --git a/doc/emulab.rst b/doc/emulab.rst
index 376f07d..77ac3d0 100644
--- a/doc/emulab.rst
+++ b/doc/emulab.rst
@@ -14,3 +14,5 @@ a workaround is to start an ssh-agent and add the public key there. ::
.. automodule:: rumba.testbeds.emulab
:member-order: bysource
+ :show-inheritance:
+ :inherited-members:
diff --git a/doc/irati.rst b/doc/irati.rst
index c07feb1..0ad496a 100644
--- a/doc/irati.rst
+++ b/doc/irati.rst
@@ -7,3 +7,5 @@ system, initially developed by the FP7-IRATI project.
.. automodule:: rumba.prototypes.irati
:member-order: bysource
+ :show-inheritance:
+ :inherited-members:
diff --git a/doc/jfed.rst b/doc/jfed.rst
index 7ed9e88..3d06c09 100644
--- a/doc/jfed.rst
+++ b/doc/jfed.rst
@@ -28,3 +28,5 @@ or sudo).
.. automodule:: rumba.testbeds.jfed
:member-order: bysource
+ :show-inheritance:
+ :inherited-members:
diff --git a/doc/local.rst b/doc/local.rst
index c55a275..6d1ee1d 100644
--- a/doc/local.rst
+++ b/doc/local.rst
@@ -3,3 +3,5 @@ Local
.. automodule:: rumba.testbeds.local
:member-order: bysource
+ :show-inheritance:
+ :inherited-members:
diff --git a/doc/ouroboros.rst b/doc/ouroboros.rst
index 785bf92..2b83531 100644
--- a/doc/ouroboros.rst
+++ b/doc/ouroboros.rst
@@ -7,3 +7,5 @@ works on any POSIX.1-2001 enabled system.
.. automodule:: rumba.prototypes.ouroboros
:member-order: bysource
+ :show-inheritance:
+ :inherited-members:
diff --git a/doc/qemu.rst b/doc/qemu.rst
index ff1ede3..375ab55 100644
--- a/doc/qemu.rst
+++ b/doc/qemu.rst
@@ -11,3 +11,5 @@ bridge-utils packages on which the testbed depends: ::
.. automodule:: rumba.testbeds.qemu
:member-order: bysource
+ :show-inheritance:
+ :inherited-members:
diff --git a/doc/rlite.rst b/doc/rlite.rst
index f58a16a..418bf3a 100644
--- a/doc/rlite.rst
+++ b/doc/rlite.rst
@@ -7,3 +7,5 @@ Architecture (RINA) for GNU/Linux operating systems.
.. automodule:: rumba.prototypes.rlite
:member-order: bysource
+ :show-inheritance:
+ :inherited-members:
diff --git a/rumba/model.py b/rumba/model.py
index d05e7fe..f9a0d3c 100644
--- a/rumba/model.py
+++ b/rumba/model.py
@@ -59,14 +59,11 @@ except OSError:
pass
-# Represents generic testbed info
-#
-# @username [string] user name
-# @password [string] password
-# @proj_name [string] project name
-# @exp_name [string] experiment name
-#
+
class Testbed(object):
+ """
+ Base class for every testbed plugin.
+ """
def __init__(self,
exp_name,
username,
@@ -74,6 +71,15 @@ class Testbed(object):
proj_name,
http_proxy=None,
system_logs=None):
+ """
+ :param exp_name: The experiment name.
+ :param username: The username.
+ :param password: The password.
+ :param proj_name: The project name.
+ :param http_proxy: HTTP proxy used by the testbed.
+ :param system_logs: Location of the system logs of
+ images of the testbed.
+ """
self.username = username
self.password = password
self.proj_name = proj_name
@@ -89,7 +95,7 @@ class Testbed(object):
def swap_in(self, experiment):
"""
- Swaps experiment in
+ Swaps experiment in on the testbed.
:param experiment: The experiment.
"""
@@ -108,7 +114,7 @@ class Testbed(object):
def swap_out(self, experiment):
"""
- Swaps experiment out
+ Swaps experiment out of the testbed.
:param experiment: The experiment.
"""
@@ -118,12 +124,15 @@ class Testbed(object):
def _swap_out(self, experiment):
logger.info("swap_out(): nothing to do")
-# Base class for DIFs
-#
-# @name [string] DIF name
-#
class DIF(object):
+ """
+ Base class for DIFs.
+ """
def __init__(self, name, members=None):
+ """
+ :param name: Name of the DIF.
+ :param members: List of nodes that are members of the DIF.
+ """
self.name = name
if members is None:
members = list()
@@ -156,7 +165,14 @@ class DIF(object):
# Shim over UDP
#
class ShimUDPDIF(DIF):
+ """
+ Shim over UDP.
+ """
def __init__(self, name, members=None):
+ """
+ :param name: Name of the DIF.
+ :param members: List of members of the DIF.
+ """
DIF.__init__(self, name, members)
def get_ipcp_class(self):
@@ -168,11 +184,18 @@ class ShimUDPDIF(DIF):
# @link_speed [int] Speed of the Ethernet network, in Mbps
#
class ShimEthDIF(DIF):
-
+ """
+ Shim over Ethernet.
+ """
def get_e_id(self):
return "ShimEthDIF." + self.name
def __init__(self, name, members=None, link_quality=None):
+ """
+ :param name: Name of the DIF.
+ :param members: List of members of the DIF.
+ :param link_quality: Quality of the link.
+ """
DIF.__init__(self, name, members)
self._link_quality = link_quality if link_quality is not None else LinkQuality()
@@ -209,6 +232,7 @@ class ShimEthDIF(DIF):
"""
Set the delay parameters of the underlying link.
Parameters as in :py:meth:`.Delay.__init__`
+
:param delay: average delay in ms
:type delay: :py:class:`int`
:param jitter: jitter in ms
@@ -216,7 +240,7 @@ class ShimEthDIF(DIF):
:param correlation: correlation in %
:type correlation: :py:class:`int`
:param distribution: delay distribution, defaults to a Normal
- distribution
+ distribution
:type distribution: :py:class:`.Distribution`
"""
new_delay = Delay(delay, jitter, correlation, distribution)
@@ -229,6 +253,7 @@ class ShimEthDIF(DIF):
"""
Set the loss parameter of the underlying link.
Parameters as in :py:meth:`.Loss.__init__`
+
:param loss: loss in percentage
:type loss: :py:class:`int` or :py:class:`float`
:param correlation: correlation in percentage
@@ -241,6 +266,7 @@ class ShimEthDIF(DIF):
def set_rate(self, rate=None):
"""
Set the rate parameter of the underlying link.
+
:param rate: The desired rate in mbps
:type rate: :py:class:`int`
"""
@@ -250,7 +276,8 @@ class ShimEthDIF(DIF):
def set_quality(self, delay, loss, rate):
"""
Configure the basic quality parameters of the
- underlying link
+ underlying link.
+
:param delay: the link delay, in ms
:type delay: :py:class:`int`
:param loss: the link loss, as a percentage
@@ -262,27 +289,44 @@ class ShimEthDIF(DIF):
self.link_quality = new_quality
-# 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):
+ """
+ Normal DIF.
+ """
def __init__(self, name, members=None, policy=None):
+ """
+ :param name: The name of the DIF.
+ :param members: The list of members.
+ :param policy: Policies of the normal DIF.
+ """
DIF.__init__(self, name, members)
if policy is None:
policy = Policy(self)
self.policy = policy
def add_policy(self, comp, pol, **params):
+ """
+ Adds a policy to the DIF.
+
+ :param comp: Component name.
+ :param pol: Policy name
+ :param params: Parameters of the policy.
+ """
self.policy.add_policy(comp, pol, **params)
- def del_policy(self, comp=None, policy_name=None):
+ def del_policy(self, comp=None, pol=None):
+ """
+ Deletes a policy from the DIF.
+
+ :param comp: Component name.
+ :param pol: Policy name
+ """
self.policy.del_policy(comp, policy_name)
def show(self):
+ """
+ :return: A string of the policies in the DIF.
+ """
s = DIF.__repr__(self)
for comp, pol_dict in self.policy.get_policies().items():
for pol, params in pol_dict.items():
@@ -292,16 +336,23 @@ class NormalDIF(DIF):
class Distribution(Enum):
+ """
+ An enum holding different statistical distributions.
+ """
NORMAL = 1
PARETO = 2
PARETONORMAL = 3
class Delay(object):
+ """
+ A class representing delay of a link.
+ """
def __init__(self, delay=0, jitter=None, correlation=None,
distribution=None):
"""
- Configure link delay
+ Configure link delay.
+
:param delay: average delay in ms
:type delay: :py:class:`int`
:param jitter: jitter in ms
@@ -309,7 +360,7 @@ class Delay(object):
:param correlation: correlation in %
:type correlation: :py:class:`int`
:param distribution: delay distribution, defaults to a Normal
- distribution
+ distribution
:type distribution: :py:class:`.Distribution`
"""
@@ -362,9 +413,13 @@ class Delay(object):
class Loss(object):
+ """
+ A class representing loss on a link.
+ """
def __init__(self, loss, correlation=None):
"""
- Configure link loss
+ Configure link loss.
+
:param loss: loss in percentage
:type loss: :py:class:`int` or :py:class:`float`
:param correlation: correlation in percentage
@@ -397,13 +452,16 @@ class Loss(object):
class LinkQuality(object):
+ """
+ A class representing the link quality.
+ """
_active = set()
@classmethod
def clone(cls, old_quality, delay=None, loss=None, rate=None):
"""
Clone old_quality, updating it with the provided parameters
- if present
+ if present.
:param old_quality: A :py:class`.LinkQuality` instance to
use as a base
@@ -416,8 +474,8 @@ class LinkQuality(object):
:type loss: :py:class:`.Loss` or :py:class:`float`
:param rate: The rate of the link in mbit
:type rate: :py:class:`int`
- :return: a new :py:class`.LinkQuality` instance
- :rtype :py:class`LinkQuality`
+ :return: a new :py:class`.LinkQuality` instance.
+ :rtype: py:class`LinkQuality`
"""
if delay is None:
delay = old_quality.delay
@@ -429,7 +487,8 @@ class LinkQuality(object):
def __init__(self, delay=None, loss=None, rate=None):
"""
- Link quality configuration
+ Link quality configuration.
+
:param delay: Delay object holding delay configuration
or number corresponding to delay in ms
:type delay: :py:class:`.Delay` or :py:class:`int`
@@ -509,9 +568,6 @@ class LinkQuality(object):
"netem" % ipcp.ifname, as_root=True)
LinkQuality._active.remove(ipcp)
-
-# SSH Configuration
-#
class SSHConfig(object):
def __init__(self, hostname, port=22, proxy_server=None):
self.username = None
@@ -532,21 +588,22 @@ class SSHConfig(object):
def set_http_proxy(self, proxy):
self.http_proxy = proxy
-
-# A node in the experiment
-#
-# @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(object):
-
+ """
+ A node in the experiment.
+ """
def get_e_id(self):
return "Node." + self.name
def __init__(self, name, difs=None, dif_registrations=None,
policies=None, machine_type=None):
+ """
+ :param name: Name of the node.
+ :param difs: A list of DIFs the node is in.
+ :param dif_registrations: How the DIFs are stacked.
+ :param policies: Policies of a DIF specific to the node.
+ :param machine_type: Type of machine to use, physical or virtual.
+ """
self.name = name
if difs is None:
difs = list()
@@ -573,6 +630,10 @@ class Node(object):
self._validate()
def get_ipcp_by_dif(self, dif):
+ """
+ :param dif: The DIF to get the IPCP of.
+ :return: The IPCP of the node that is in the DIF.
+ """
for ipcp in self.ipcps:
if ipcp.dif == dif:
return ipcp
@@ -620,6 +681,11 @@ class Node(object):
return not self == other
def add_dif(self, dif):
+ """
+ Adds a DIF to the list.
+
+ :param dif: Name of the DIF to add.
+ """
self.difs.append(dif)
dif.add_member(self)
if hasattr(dif, 'policy'):
@@ -627,6 +693,11 @@ class Node(object):
self._validate()
def del_dif(self, dif):
+ """
+ Adds a DIF to the list.
+
+ :param dif: Name of the DIF to add.
+ """
self.difs.remove(dif)
dif.del_member(self)
try:
@@ -637,63 +708,126 @@ class Node(object):
self._validate()
def add_dif_registration(self, upper, lower):
+ """
+ Adds a DIF registration.
+
+ :param upper: Name of the DIF that is requesting IPC.
+ :param lower: Name of the DIF providing IPC.
+ """
self.dif_registrations[upper].append(lower)
self._validate()
def del_dif_registration(self, upper, lower):
+ """
+ Removes a DIF registration.
+
+ :param upper: Name of the DIF that is requesting IPC.
+ :param lower: Name of the DIF providing IPC.
+ """
self.dif_registrations[upper].remove(lower)
self._validate()
def add_policy(self, dif, component_name, policy_name, **parameters):
+ """
+ Adds a policy.
+
+ :param dif: The name of the DIF.
+ :param component_name: Name of the component.
+ :param policy_name: Name of the policy.
+ :param parameters: Parameters of the policy.
+ """
self.policies[dif].add_policy(component_name, policy_name, **parameters)
def del_policy(self, dif, component_name=None, policy_name=None):
+ """
+ Removes a policy.
+
+ :param component_name: Name of the component.
+ :param policy_name: Name of the policy.
+ """
self.policies[dif].del_policy(component_name, policy_name)
def get_policy(self, dif):
+ """
+ :param dif: The DIF to get the policy of.
+ :return: Returns the policy.
+ """
return self.policies[dif]
def execute_commands(self, commands, as_root=False, time_out=3,
use_proxy=False):
+ """
+ Execute a list of a commands on the node.
+
+ :param commands: A list of commands.
+ :param as_root: Execute as root?
+ :param time_out: Seconds before timing out.
+ :param use_proxy: Use a proxy to execute the commands?
+ """
return self.executor.execute_commands(self, commands, as_root, time_out)
def execute_command(self, command, as_root=False, time_out=3,
use_proxy=False):
- return self.executor.execute_command(self, command, as_root, time_out)
+ """
+ Execute a single command on a node.
- def write_text_to_file(self, text, file_name):
- # ssh_support.write_text_to_file(
- # self.ssh_config,
- # self.ssh_config,
- # text,
- # file_name
- # )
- return
+ :param command: A command.
+ :param as_root: Execute as root?
+ :param time_out: Seconds before timing out.
+ :param use_proxy: Use a proxy to execute the commands?
+ :return: The stdout of the command.
+ """
+ return self.executor.execute_command(self, command, as_root, time_out)
def copy_file(self, path, destination):
+ """
+ Copy file to node.
+
+ :param path: Local location of the file.
+ :param destination: Destination location of the file.
+ """
self.executor.copy_file(self, path, destination)
def copy_files(self, paths, destination):
- self.executor.copy_files(self, paths, destination)
+ """
+ Copy files to node.
- def fetch_files(self, paths, destination, sudo=False):
- self.executor.fetch_files(self, paths, destination, sudo)
+ :param paths: Local location of the files.
+ :param destination: Destination location of the files.
+ """
+ self.executor.copy_files(self, paths, destination)
def fetch_file(self, path, destination, sudo=False):
+ """
+ Fetch file from the node.
+
+ :param paths: Location of the files on the node.
+ :param destination: Destination location of the files.
+ :param sudo: The file is owned by root on the node?
+ """
self.executor.fetch_file(self, path, destination, sudo)
+ def fetch_files(self, paths, destination, sudo=False):
+ """
+ Fetch files from the node.
+
+ :param paths: Location of the files on the node.
+ :param destination: Destination location of the files.
+ :param sudo: The file is owned by root on the node?
+ """
+ self.executor.fetch_files(self, paths, destination, sudo)
+
def set_link_state(self, dif, state):
+ """
+ Change the state of a link on the node.
+
+ :param dif: The name of the shim Ethernet DIF.
+ :param state: Up or down.
+ """
ipcp = self.get_ipcp_by_dif(dif)
self.execute_command('ip link set dev ' + ipcp.ifname + ' ' + state,
as_root=True)
-
-# Base class representing an IPC Process to be created in the experiment
-#
-# @name [string]: IPCP name
-# @node: Node where the IPCP gets created
-# @dif: the DIF the IPCP belongs to
-#
class IPCP(object):
def __init__(self, name, node, dif):
self.name = name
@@ -734,12 +868,6 @@ class ShimUDPIPCP(IPCP):
IPCP.__init__(self, name, node, dif)
# 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
@@ -812,13 +940,10 @@ class Policy(object):
s += "\n]\n"
return s
-
-# Base class for ARCFIRE experiments
-#
-# @name [string] Name of the experiment
-# @nodes: Nodes in the experiment
-#
class Experiment(object):
+ """
+ Base class for experiments.
+ """
__metaclass__ = abc.ABCMeta
def __init__(self, testbed,
@@ -827,6 +952,14 @@ class Experiment(object):
git_branch=None,
log_dir=None,
prototype_logs=None):
+ """
+ :param testbed: The testbed of the experiment.
+ :param nodes: The list of nodes in the experiment.
+ :param git_repo: The git repository of the prototype.
+ :param git_branch: The git branch of the repository.
+ :param log_dir: Where to log output of the experiment.
+ :param prototype_logs: Where the prototype logs its output.
+ """
if nodes is None:
nodes = list()
self.nodes = nodes
@@ -871,10 +1004,20 @@ class Experiment(object):
return s
def add_node(self, node):
+ """
+ Adds a node to the experiment.
+
+ :param node: A node.
+ """
self.nodes.append(node)
self.generate()
def del_node(self, node):
+ """
+ Deletes a node from the experiment.
+
+ :param node: A node.
+ """
self.nodes.remove(node)
self.generate()
@@ -1136,6 +1279,9 @@ class Experiment(object):
logger.info("Layer ordering computation took %.2f seconds", end - start)
def install_prototype(self):
+ """
+ Installs the prototype on the nodes.
+ """
start = time.time()
self._install_prototype()
end = time.time()
@@ -1146,6 +1292,9 @@ class Experiment(object):
node.startup_command = command
def bootstrap_prototype(self):
+ """
+ Bootstraps the prototype on the nodes.
+ """
start = time.time()
self._bootstrap_prototype()
end = time.time()
@@ -1168,7 +1317,9 @@ class Experiment(object):
raise Exception('terminate_prototype() method not implemented')
def swap_in(self):
- # Realize the experiment testbed (testbed-specific)
+ """
+ Swap the experiment in on the testbed.
+ """
start = time.time()
self.testbed.swap_in(self)
self.dump_ssh_info()
@@ -1176,6 +1327,9 @@ class Experiment(object):
logger.info("Swap-in took %.2f seconds", end - start)
def swap_out(self):
+ """
+ Swap the experiment out of the testbed.
+ """
start = time.time()
# Terminate prototype gracefully
self._terminate_prototype()