diff options
-rw-r--r-- | doc/conf.py | 25 | ||||
-rw-r--r-- | doc/docker.rst | 2 | ||||
-rw-r--r-- | doc/emulab.rst | 2 | ||||
-rw-r--r-- | doc/irati.rst | 2 | ||||
-rw-r--r-- | doc/jfed.rst | 2 | ||||
-rw-r--r-- | doc/local.rst | 2 | ||||
-rw-r--r-- | doc/ouroboros.rst | 2 | ||||
-rw-r--r-- | doc/qemu.rst | 2 | ||||
-rw-r--r-- | doc/rlite.rst | 2 | ||||
-rw-r--r-- | rumba/model.py | 304 |
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() |