released to pypi nepi-3.2-pypi
authorThierry Parmentelat <thierry.parmentelat@inria.fr>
Thu, 9 Apr 2015 10:29:10 +0000 (12:29 +0200)
committerThierry Parmentelat <thierry.parmentelat@inria.fr>
Thu, 9 Apr 2015 10:29:10 +0000 (12:29 +0200)
Makefile
README [new file with mode: 0644]
VERSION [new file with mode: 0644]
setup.py
src/nepi/resources/linux/node.py

index 01a1d3b..118c778 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -64,3 +64,18 @@ dist: MANIFEST
        ./setup.py sdist
 
 .PHONY: all clean distclean dist test coverage install MANIFEST
        ./setup.py sdist
 
 .PHONY: all clean distclean dist test coverage install MANIFEST
+
+########## for uploading onto pypi
+# use pypitest instead for tests (both entries need to be defined in your .pypirc)
+PYPI_TARGET=pypi
+PYPI_TARBALL_HOST=root@build.onelab.eu
+PYPI_TARBALL_TOPDIR=/build/nepi
+
+VERSIONTAG=$(shell cat VERSION)
+
+# run this only once the sources are in on the right tag
+pypi: 
+       setup.py sdist upload -r $(PYPI_TARGET)
+       ssh $(PYPI_TARBALL_HOST) mkdir -p $(PYPI_TARBALL_TOPDIR)/$(VERSIONTAG)
+       rsync -av dist/nepi-$(VERSIONTAG).tar.gz $(PYPI_TARBALL_HOST):$(PYPI_TARBALL_TOPDIR)/
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..aede580
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+NEPI is a Python-based library to model and run network experiments on a variety of network evaluation platforms, including PlanetLab, OMF wireless testbeds, ns-3 simulators, and others. It allows to specify resources to use in an experiment, to define experiment workflow constraints and to automate deployment, resource control and result collection.       
diff --git a/VERSION b/VERSION
new file mode 100644 (file)
index 0000000..a3ec5a4
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+3.2
index 7037c19..988b4bc 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -3,41 +3,52 @@
 from distutils.core import setup
 import sys
 
 from distutils.core import setup
 import sys
 
+
+with open('VERSION') as f:
+    version_tag = f.read().strip()
+with open("COPYING") as f:
+    license = f.read()
+with open("README") as f:
+    long_description = f.read()
+
 setup(
 setup(
-        name        = "nepi",
-        version     = "nepi-3-dev",
-        description = "Network Experiment Management Framework",
-        author      = "Alina Quereilhac, Julien Tribino, Lucia Guevgeozian",
-        url         = "http://nepi.inria.fr",
-        license     = "GPLv2",
-        platforms   = "Linux, OSX",
-        packages    = [
-            "nepi",
-            "nepi.execution",
-            "nepi.resources",
-            "nepi.resources.all",
-            "nepi.resources.linux",
-            "nepi.resources.linux.ccn",
-            "nepi.resources.linux.ns3",
-            "nepi.resources.linux.ns3.ccn",
-            "nepi.resources.linux.netns",
-            "nepi.resources.netns",
-            "nepi.resources.ns3",
-            "nepi.resources.ns3.classes",
-            "nepi.resources.omf",
-            "nepi.resources.planetlab",
-            "nepi.resources.planetlab.ns3",
-            "nepi.resources.planetlab.openvswitch",
-            "nepi.util",
-            "nepi.util.parsers",
-            "nepi.data",
-            "nepi.data.processing",
-            "nepi.data.processing.ccn",
-            "nepi.data.processing.ping"],
-        package_dir = {"": "src"},
-        package_data = {
-            "nepi.resources.planetlab" : [ "scripts/*.py" ],
-            "nepi.resources.linux" : [ "scripts/*.py" ],
-            "nepi.resources.linux.ns3" : [ "dependencies/*.tar.gz" ]
-            }
-    )
+    name             = "nepi",
+    version          = version_tag,
+    description      = "Network Experiment Management Framework",
+    long_description = long_description,
+    license          = license,
+    author           = "Alina Quereilhac",
+    author_email     = "alina.quereilhac@inria.fr",
+    download_url     = "http://build.onelab.eu/nepi/nepi-{v}.tar.gz".format(v=version_tag),
+    url              = "http://nepi.inria.fr/",
+    platforms        = "Linux, OSX",
+    package_dir      = {"": "src"},
+    packages         = [
+        "nepi",
+        "nepi.execution",
+        "nepi.resources",
+        "nepi.resources.all",
+        "nepi.resources.linux",
+        "nepi.resources.linux.ccn",
+        "nepi.resources.linux.ns3",
+        "nepi.resources.linux.ns3.ccn",
+        "nepi.resources.linux.netns",
+        "nepi.resources.netns",
+        "nepi.resources.ns3",
+        "nepi.resources.ns3.classes",
+        "nepi.resources.omf",
+        "nepi.resources.planetlab",
+        "nepi.resources.planetlab.ns3",
+        "nepi.resources.planetlab.openvswitch",
+        "nepi.util",
+        "nepi.util.parsers",
+        "nepi.data",
+        "nepi.data.processing",
+        "nepi.data.processing.ccn",
+        "nepi.data.processing.ping"],
+    package_data     = {
+        "nepi.resources.planetlab" : [ "scripts/*.py" ],
+        "nepi.resources.linux" : [ "scripts/*.py" ],
+        "nepi.resources.linux.ns3" : [ "dependencies/*.tar.gz" ]
+    }
+)
index b0d63c9..0abbf8f 100644 (file)
@@ -17,8 +17,8 @@
 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
 
 from nepi.execution.attribute import Attribute, Flags, Types
 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
 
 from nepi.execution.attribute import Attribute, Flags, Types
-from nepi.execution.resource import ResourceManager, clsinit_copy, \
-        ResourceState
+from nepi.execution.resource import (ResourceManager, clsinit_copy, 
+                                     ResourceState)
 from nepi.resources.linux import rpmfuncs, debfuncs 
 from nepi.util import sshfuncs, execfuncs
 from nepi.util.sshfuncs import ProcStatus
 from nepi.resources.linux import rpmfuncs, debfuncs 
 from nepi.util import sshfuncs, execfuncs
 from nepi.util.sshfuncs import ProcStatus
@@ -147,77 +147,81 @@ class LinuxNode(ResourceManager):
 
     @classmethod
     def _register_attributes(cls):
 
     @classmethod
     def _register_attributes(cls):
-        hostname = Attribute("hostname", "Hostname of the machine",
-                flags = Flags.Design)
+        cls._register_attribute(Attribute(
+            "hostname", "Hostname of the machine",
+            flags = Flags.Design))
 
 
-        username = Attribute("username", "Local account username", 
-                flags = Flags.Credential)
+        cls._register_attribute(Attribute(
+            "username", "Local account username", 
+            flags = Flags.Credential))
 
 
-        port = Attribute("port", "SSH port", flags = Flags.Design)
+        cls._register_attribute(Attribute(
+            "port", "SSH port",
+            flags = Flags.Design))
         
         
-        home = Attribute("home",
-                "Experiment home directory to store all experiment related files",
-                flags = Flags.Design)
+        cls._register_attribute(Attribute(
+            "home",
+            "Experiment home directory to store all experiment related files",
+            flags = Flags.Design))
         
         
-        identity = Attribute("identity", "SSH identity file",
-                flags = Flags.Credential)
+        cls._register_attribute(Attribute(
+            "identity", "SSH identity file",
+            flags = Flags.Credential))
         
         
-        server_key = Attribute("serverKey", "Server public key", 
-                flags = Flags.Design)
+        cls._register_attribute(Attribute(
+            "serverKey", "Server public key", 
+            flags = Flags.Design))
         
         
-        clean_home = Attribute("cleanHome", "Remove all nepi files and directories "
-                " from node home folder before starting experiment", 
-                type = Types.Bool,
-                default = False,
-                flags = Flags.Design)
-
-        clean_experiment = Attribute("cleanExperiment", "Remove all files and directories " 
-                " from a previous same experiment, before the new experiment starts", 
-                type = Types.Bool,
-                default = False,
-                flags = Flags.Design)
+        cls._register_attribute(Attribute(
+            "cleanHome",
+            "Remove all nepi files and directories "
+            " from node home folder before starting experiment", 
+            type = Types.Bool,
+            default = False,
+            flags = Flags.Design))
+
+        cls._register_attribute(Attribute(
+            "cleanExperiment", "Remove all files and directories " 
+            " from a previous same experiment, before the new experiment starts", 
+            type = Types.Bool,
+            default = False,
+            flags = Flags.Design))
         
         
-        clean_processes = Attribute("cleanProcesses", 
-                "Kill all running processes before starting experiment",
-                type = Types.Bool,
-                default = False,
-                flags = Flags.Design)
+        cls._register_attribute(Attribute(
+            "cleanProcesses", 
+            "Kill all running processes before starting experiment",
+            type = Types.Bool,
+            default = False,
+            flags = Flags.Design))
         
         
-        clean_processes_after = Attribute("cleanProcessesAfter", 
-                """Kill all running processes after starting experiment
-This might be dangerous when using user root""",
-                type = Types.Bool,
-                default = True,
-                flags = Flags.Design)
+        cls._register_attribute(Attribute(
+            "cleanProcessesAfter", 
+            """Kill all running processes after starting experiment
+            This might be dangerous when using user root""",
+            type = Types.Bool,
+            default = True,
+            flags = Flags.Design))
         
         
-        tear_down = Attribute("tearDown", "Bash script to be executed before " + \
-                "releasing the resource",
-                flags = Flags.Design)
-
-        gateway_user = Attribute("gatewayUser", "Gateway account username",
-                flags = Flags.Design)
-
-        gateway = Attribute("gateway", "Hostname of the gateway machine",
-                flags = Flags.Design)
-
-        ip = Attribute("ip", "Linux host public IP address. "
-                   "Must not be modified by the user unless hostname is 'localhost'",
-                    flags = Flags.Design)
-
-        cls._register_attribute(hostname)
-        cls._register_attribute(username)
-        cls._register_attribute(port)
-        cls._register_attribute(home)
-        cls._register_attribute(identity)
-        cls._register_attribute(server_key)
-        cls._register_attribute(clean_home)
-        cls._register_attribute(clean_experiment)
-        cls._register_attribute(clean_processes)
-        cls._register_attribute(clean_processes_after)
-        cls._register_attribute(tear_down)
-        cls._register_attribute(gateway_user)
-        cls._register_attribute(gateway)
-        cls._register_attribute(ip)
+        cls._register_attribute(Attribute(
+            "tearDown",
+            "Bash script to be executed before releasing the resource",
+            flags = Flags.Design))
+
+        cls._register_attribute(Attribute(
+            "gatewayUser",
+            "Gateway account username",
+            flags = Flags.Design))
+
+        cls._register_attribute(Attribute(
+            "gateway",
+            "Hostname of the gateway machine",
+            flags = Flags.Design))
+
+        cls._register_attribute(Attribute(
+            "ip",
+            "Linux host public IP address. "
+            "Must not be modified by the user unless hostname is 'localhost'",
+            flags = Flags.Design))
 
     def __init__(self, ec, guid):
         super(LinuxNode, self).__init__(ec, guid)
 
     def __init__(self, ec, guid):
         super(LinuxNode, self).__init__(ec, guid)
@@ -233,17 +237,17 @@ This might be dangerous when using user root""",
         # of a file or folder prior to its creation, and another 
         # application creating the same file or folder in between.
         self._node_lock = threading.Lock()
         # of a file or folder prior to its creation, and another 
         # application creating the same file or folder in between.
         self._node_lock = threading.Lock()
-    
+        
     def log_message(self, msg):
     def log_message(self, msg):
-        return " guid %d - host %s - %s " % (self.guid, 
-                self.get("hostname"), msg)
+        return " guid {} - host {} - {} "\
+            .format(self.guid, self.get("hostname"), msg)
 
     @property
     def home_dir(self):
         home = self.get("home") or ""
         if not home.startswith("/"):
 
     @property
     def home_dir(self):
         home = self.get("home") or ""
         if not home.startswith("/"):
-           home = os.path.join(self._home_dir, home) 
-        return home
+            home = os.path.join(self._home_dir, home) 
+            return home
 
     @property
     def nepi_home(self):
 
     @property
     def nepi_home(self):
@@ -279,7 +283,7 @@ This might be dangerous when using user root""",
 
     @property
     def node_home(self):
 
     @property
     def node_home(self):
-        return os.path.join(self.exp_home, "node-%d" % self.guid)
+        return os.path.join(self.exp_home, "node-{}".format(self.guid))
 
     @property
     def run_home(self):
 
     @property
     def run_home(self):
@@ -312,7 +316,7 @@ This might be dangerous when using user root""",
         else:
             msg = "Unsupported OS"
             self.error(msg, out)
         else:
             msg = "Unsupported OS"
             self.error(msg, out)
-            raise RuntimeError, "%s - %s " %( msg, out )
+            raise RuntimeError("{} - {} ".format(msg, out))
 
         return self._os
 
 
         return self._os
 
@@ -324,13 +328,13 @@ This might be dangerous when using user root""",
         out = ""
         try:
             (out, err), proc = self.execute("cat /etc/issue", 
         out = ""
         try:
             (out, err), proc = self.execute("cat /etc/issue", 
-                    with_lock = True,
-                    blocking = True)
+                                            with_lock = True,
+                                            blocking = True)
         except:
             trace = traceback.format_exc()
         except:
             trace = traceback.format_exc()
-            msg = "Error detecting OS: %s " % trace
+            msg = "Error detecting OS: {} ".format(trace)
             self.error(msg, out, err)
             self.error(msg, out, err)
-        
+    
         return out
 
     @property
         return out
 
     @property
@@ -348,7 +352,7 @@ This might be dangerous when using user root""",
     def do_provision(self):
         # check if host is alive
         if not self.is_alive():
     def do_provision(self):
         # check if host is alive
         if not self.is_alive():
-            msg = "Deploy failed. Unresponsive node %s" % self.get("hostname")
+            msg = "Deploy failed. Unresponsive node {}".format(self.get("hostname"))
             self.error(msg)
             raise RuntimeError, msg
 
             self.error(msg)
             raise RuntimeError, msg
 
@@ -359,16 +363,16 @@ This might be dangerous when using user root""",
 
         if self.get("cleanHome"):
             self.clean_home()
 
         if self.get("cleanHome"):
             self.clean_home()
+            
         if self.get("cleanExperiment"):
             self.clean_experiment()
         if self.get("cleanExperiment"):
             self.clean_experiment()
-    
+            
         # Create shared directory structure and node home directory
         paths = [self.lib_dir, 
         # Create shared directory structure and node home directory
         paths = [self.lib_dir, 
-            self.bin_dir, 
-            self.src_dir, 
-            self.share_dir, 
-            self.node_home]
+                 self.bin_dir, 
+                 self.src_dir, 
+                 self.share_dir, 
+                 self.node_home]
 
         self.mkdir(paths)
 
 
         self.mkdir(paths)
 
@@ -379,7 +383,7 @@ This might be dangerous when using user root""",
                 self.set("ip", ip)
             except:
                 if self.get("gateway") is None:
                 self.set("ip", ip)
             except:
                 if self.get("gateway") is None:
-                    msg = "Local DNS can not resolve hostname %s" % self.get("hostname") 
+                    msg = "Local DNS can not resolve hostname {}".format(self.get("hostname"))
                     self.error(msg)
 
         super(LinuxNode, self).do_provision()
                     self.error(msg)
 
         super(LinuxNode, self).do_provision()
@@ -431,8 +435,8 @@ This might be dangerous when using user root""",
         
         if self.get("username") != 'root':
             cmd = ("sudo -S killall tcpdump || /bin/true ; " +
         
         if self.get("username") != 'root':
             cmd = ("sudo -S killall tcpdump || /bin/true ; " +
-                "sudo -S kill -9 $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; " +
-                "sudo -S killall -u %s || /bin/true ; " % self.get("username"))
+                   "sudo -S kill -9 $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; " +
+                   "sudo -S killall -u {} || /bin/true ; ".format(self.get("username")))
         else:
             if self.state >= ResourceState.READY:
                 import pickle
         else:
             if self.state >= ResourceState.READY:
                 import pickle
@@ -448,14 +452,14 @@ This might be dangerous when using user root""",
                     kill_pids = ' '.join(dict(kill_pids).keys())
 
                     cmd = ("killall tcpdump || /bin/true ; " +
                     kill_pids = ' '.join(dict(kill_pids).keys())
 
                     cmd = ("killall tcpdump || /bin/true ; " +
-                        "kill $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; " +
-                        "kill %s || /bin/true ; " % kill_pids)
+                           "kill $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; " +
+                           "kill {} || /bin/true ; ".format(kill_pids))
                 else:
                     cmd = ("killall tcpdump || /bin/true ; " +
                 else:
                     cmd = ("killall tcpdump || /bin/true ; " +
-                        "kill $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; ")
+                           "kill $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; ")
             else:
                 cmd = ("killall tcpdump || /bin/true ; " +
             else:
                 cmd = ("killall tcpdump || /bin/true ; " +
-                    "kill $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; ")
+                       "kill $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; ")
 
         (out, err), proc = self.execute(cmd, retry = 1, with_lock = True)
 
 
         (out, err), proc = self.execute(cmd, retry = 1, with_lock = True)
 
@@ -464,8 +468,8 @@ This might be dangerous when using user root""",
         """
         self.info("Cleaning up home")
         
         """
         self.info("Cleaning up home")
         
-        cmd = "cd %s ; find . -maxdepth 1 -name \.nepi -execdir rm -rf {} + " % (
-                self.home_dir )
+        cmd = "cd {} ; find . -maxdepth 1 -name \.nepi -execdir rm -rf {} + "\
+              .format(self.home_dir)
 
         return self.execute(cmd, with_lock = True)
 
 
         return self.execute(cmd, with_lock = True)
 
@@ -476,33 +480,33 @@ This might be dangerous when using user root""",
         """
         self.info("Cleaning up experiment files")
         
         """
         self.info("Cleaning up experiment files")
         
-        cmd = "cd %s ; find . -maxdepth 1 -name '%s' -execdir rm -rf {} + " % (
-                self.exp_dir,
-                self.ec.exp_id )
-            
+        cmd = "cd {} ; find . -maxdepth 1 -name '{}' -execdir rm -rf {} + "\
+              .format(self.exp_dir, self.ec.exp_id)
+        
         return self.execute(cmd, with_lock = True)
 
     def execute(self, command,
         return self.execute(cmd, with_lock = True)
 
     def execute(self, command,
-            sudo = False,
-            env = None,
-            tty = False,
-            forward_x11 = False,
-            retry = 3,
-            connect_timeout = 30,
-            strict_host_checking = False,
-            persistent = True,
-            blocking = True,
-            with_lock = False
-            ):
+                sudo = False,
+                env = None,
+                tty = False,
+                forward_x11 = False,
+                retry = 3,
+                connect_timeout = 30,
+                strict_host_checking = False,
+                persistent = True,
+                blocking = True,
+                with_lock = False
+    ):
         """ Notice that this invocation will block until the
         execution finishes. If this is not the desired behavior,
         use 'run' instead."""
 
         if self.localhost:
         """ Notice that this invocation will block until the
         execution finishes. If this is not the desired behavior,
         use 'run' instead."""
 
         if self.localhost:
-            (out, err), proc = execfuncs.lexec(command, 
-                    user = self.get("username"), # still problem with localhost
-                    sudo = sudo,
-                    env = env)
+            (out, err), proc = execfuncs.lexec(
+                command, 
+                user = self.get("username"), # still problem with localhost
+                sudo = sudo,
+                env = env)
         else:
             if with_lock:
                 # If the execute command is blocking, we don't want to keep
         else:
             if with_lock:
                 # If the execute command is blocking, we don't want to keep
@@ -529,7 +533,7 @@ This might be dangerous when using user root""",
                         persistent = persistent,
                         blocking = blocking, 
                         strict_host_checking = strict_host_checking
                         persistent = persistent,
                         blocking = blocking, 
                         strict_host_checking = strict_host_checking
-                        )
+                    )
             else:
                 (out, err), proc = sshfuncs.rexec(
                     command, 
             else:
                 (out, err), proc = sshfuncs.rexec(
                     command, 
@@ -550,7 +554,7 @@ This might be dangerous when using user root""",
                     persistent = persistent,
                     blocking = blocking, 
                     strict_host_checking = strict_host_checking
                     persistent = persistent,
                     blocking = blocking, 
                     strict_host_checking = strict_host_checking
-                    )
+                )
 
         return (out, err), proc
 
 
         return (out, err), proc
 
@@ -564,16 +568,17 @@ This might be dangerous when using user root""",
             tty = False,
             strict_host_checking = False):
         
             tty = False,
             strict_host_checking = False):
         
-        self.debug("Running command '%s'" % command)
+        self.debug("Running command '{}'".format(command))
         
         if self.localhost:
         
         if self.localhost:
-            (out, err), proc = execfuncs.lspawn(command, pidfile,
-                    home = home, 
-                    create_home = create_home, 
-                    stdin = stdin or '/dev/null',
-                    stdout = stdout or '/dev/null',
-                    stderr = stderr or '/dev/null',
-                    sudo = sudo) 
+            (out, err), proc = execfuncs.lspawn(
+                command, pidfile,
+                home = home, 
+                create_home = create_home, 
+                stdin = stdin or '/dev/null',
+                stdout = stdout or '/dev/null',
+                stderr = stderr or '/dev/null',
+                sudo = sudo) 
         else:
             with self._node_lock:
                 (out, err), proc = sshfuncs.rspawn(
         else:
             with self._node_lock:
                 (out, err), proc = sshfuncs.rspawn(
@@ -595,7 +600,7 @@ This might be dangerous when using user root""",
                     server_key = self.get("serverKey"),
                     tty = tty,
                     strict_host_checking = strict_host_checking
                     server_key = self.get("serverKey"),
                     tty = tty,
                     strict_host_checking = strict_host_checking
-                    )
+                )
 
         return (out, err), proc
 
 
         return (out, err), proc
 
@@ -615,7 +620,7 @@ This might be dangerous when using user root""",
                     identity = self.get("identity"),
                     server_key = self.get("serverKey"),
                     strict_host_checking = False
                     identity = self.get("identity"),
                     server_key = self.get("serverKey"),
                     strict_host_checking = False
-                    )
+                )
         
         return pidtuple
 
         
         return pidtuple
 
@@ -625,17 +630,17 @@ This might be dangerous when using user root""",
         else:
             with self._node_lock:
                 status = sshfuncs.rstatus(
         else:
             with self._node_lock:
                 status = sshfuncs.rstatus(
-                        pid, ppid,
-                        host = self.get("hostname"),
-                        user = self.get("username"),
-                        port = self.get("port"),
-                        gwuser = self.get("gatewayUser"),
-                        gw = self.get("gateway"),
-                        agent = True,
-                        identity = self.get("identity"),
-                        server_key = self.get("serverKey"),
-                        strict_host_checking = False
-                        )
+                    pid, ppid,
+                    host = self.get("hostname"),
+                    user = self.get("username"),
+                    port = self.get("port"),
+                    gwuser = self.get("gatewayUser"),
+                    gw = self.get("gateway"),
+                    agent = True,
+                    identity = self.get("identity"),
+                    server_key = self.get("serverKey"),
+                    strict_host_checking = False
+                )
            
         return status
     
            
         return status
     
@@ -661,14 +666,15 @@ This might be dangerous when using user root""",
                         identity = self.get("identity"),
                         server_key = self.get("serverKey"),
                         strict_host_checking = False
                         identity = self.get("identity"),
                         server_key = self.get("serverKey"),
                         strict_host_checking = False
-                        )
+                    )
 
         return (out, err), proc
 
     def copy(self, src, dst):
         if self.localhost:
 
         return (out, err), proc
 
     def copy(self, src, dst):
         if self.localhost:
-            (out, err), proc = execfuncs.lcopy(src, dst, 
-                    recursive = True)
+            (out, err), proc = execfuncs.lcopy(
+                src, dst, 
+                recursive = True)
         else:
             with self._node_lock:
                 (out, err), proc = sshfuncs.rcopy(
         else:
             with self._node_lock:
                 (out, err), proc = sshfuncs.rcopy(
@@ -684,7 +690,7 @@ This might be dangerous when using user root""",
         return (out, err), proc
 
     def upload(self, src, dst, text = False, overwrite = True,
         return (out, err), proc
 
     def upload(self, src, dst, text = False, overwrite = True,
-            raise_on_error = True):
+               raise_on_error = True):
         """ Copy content to destination
 
         src  string with the content to copy. Can be:
         """ Copy content to destination
 
         src  string with the content to copy. Can be:
@@ -721,7 +727,7 @@ This might be dangerous when using user root""",
 
         if not self.localhost:
             # Build destination as <user>@<server>:<path>
 
         if not self.localhost:
             # Build destination as <user>@<server>:<path>
-            dst = "%s@%s:%s" % (self.get("username"), self.get("hostname"), dst)
+            dst = "{}@{}:{}".format(self.get("username"), self.get("hostname"), dst)
 
         ((out, err), proc) = self.copy(src, dst)
 
 
         ((out, err), proc) = self.copy(src, dst)
 
@@ -730,10 +736,10 @@ This might be dangerous when using user root""",
             os.remove(f.name)
 
         if err:
             os.remove(f.name)
 
         if err:
-            msg = " Failed to upload files - src: %s dst: %s" %  (";".join(src), dst) 
+            msg = " Failed to upload files - src: {} dst: {}".format(";".join(src), dst)
             self.error(msg, out, err)
             
             self.error(msg, out, err)
             
-            msg = "%s out: %s err: %s" % (msg, out, err)
+            msg = "{} out: {} err: {}".format(msg, out, err)
             if raise_on_error:
                 raise RuntimeError, msg
 
             if raise_on_error:
                 raise RuntimeError, msg
 
@@ -742,12 +748,12 @@ This might be dangerous when using user root""",
     def download(self, src, dst, raise_on_error = True):
         if not self.localhost:
             # Build destination as <user>@<server>:<path>
     def download(self, src, dst, raise_on_error = True):
         if not self.localhost:
             # Build destination as <user>@<server>:<path>
-            src = "%s@%s:%s" % (self.get("username"), self.get("hostname"), src)
+            src = "{}@{}:{}".format(self.get("username"), self.get("hostname"), src)
 
         ((out, err), proc) = self.copy(src, dst)
 
         if err:
 
         ((out, err), proc) = self.copy(src, dst)
 
         if err:
-            msg = " Failed to download files - src: %s dst: %s" %  (";".join(src), dst) 
+            msg = " Failed to download files - src: {} dst: {}".format(";".join(src), dst) 
             self.error(msg, out, err)
 
             if raise_on_error:
             self.error(msg, out, err)
 
             if raise_on_error:
@@ -768,8 +774,9 @@ This might be dangerous when using user root""",
 
         return command
 
 
         return command
 
-    def install_packages(self, packages, home, run_home = None,
-            raise_on_error = True):
+    def install_packages(self, packages, home,
+                         run_home = None,
+                         raise_on_error = True):
         """ Install packages in the Linux host.
 
         'home' is the directory to upload the package installation script.
         """ Install packages in the Linux host.
 
         'home' is the directory to upload the package installation script.
@@ -780,18 +787,18 @@ This might be dangerous when using user root""",
         run_home = run_home or home
 
         (out, err), proc = self.run_and_wait(command, run_home, 
         run_home = run_home or home
 
         (out, err), proc = self.run_and_wait(command, run_home, 
-            shfile = os.path.join(home, "instpkg.sh"),
-            pidfile = "instpkg_pidfile",
-            ecodefile = "instpkg_exitcode",
-            stdout = "instpkg_stdout", 
-            stderr = "instpkg_stderr",
-            overwrite = False,
-            raise_on_error = raise_on_error)
+                                             shfile = os.path.join(home, "instpkg.sh"),
+                                             pidfile = "instpkg_pidfile",
+                                             ecodefile = "instpkg_exitcode",
+                                             stdout = "instpkg_stdout", 
+                                             stderr = "instpkg_stderr",
+                                             overwrite = False,
+                                             raise_on_error = raise_on_error)
 
         return (out, err), proc 
 
     def remove_packages(self, packages, home, run_home = None,
 
         return (out, err), proc 
 
     def remove_packages(self, packages, home, run_home = None,
-            raise_on_error = True):
+                        raise_on_error = True):
         """ Uninstall packages from the Linux host.
 
         'home' is the directory to upload the package un-installation script.
         """ Uninstall packages from the Linux host.
 
         'home' is the directory to upload the package un-installation script.
@@ -809,14 +816,14 @@ This might be dangerous when using user root""",
         run_home = run_home or home
 
         (out, err), proc = self.run_and_wait(command, run_home, 
         run_home = run_home or home
 
         (out, err), proc = self.run_and_wait(command, run_home, 
-            shfile = os.path.join(home, "rmpkg.sh"),
-            pidfile = "rmpkg_pidfile",
-            ecodefile = "rmpkg_exitcode",
-            stdout = "rmpkg_stdout", 
-            stderr = "rmpkg_stderr",
-            overwrite = False,
-            raise_on_error = raise_on_error)
-         
+                                             shfile = os.path.join(home, "rmpkg.sh"),
+                                             pidfile = "rmpkg_pidfile",
+                                             ecodefile = "rmpkg_exitcode",
+                                             stdout = "rmpkg_stdout", 
+                                             stderr = "rmpkg_stderr",
+                                             overwrite = False,
+                                             raise_on_error = raise_on_error)
+        
         return (out, err), proc 
 
     def mkdir(self, paths, clean = False):
         return (out, err), proc 
 
     def mkdir(self, paths, clean = False):
@@ -829,7 +836,7 @@ This might be dangerous when using user root""",
         if isinstance(paths, str):
             paths = [paths]
 
         if isinstance(paths, str):
             paths = [paths]
 
-        cmd = " ; ".join(map(lambda path: "mkdir -p %s" % path, paths))
+        cmd = " ; ".join(["mkdir -p {}".format(path) for path in paths])
 
         return self.execute(cmd, with_lock = True)
 
 
         return self.execute(cmd, with_lock = True)
 
@@ -841,23 +848,23 @@ This might be dangerous when using user root""",
         if isinstance(paths, str):
             paths = [paths]
 
         if isinstance(paths, str):
             paths = [paths]
 
-        cmd = " ; ".join(map(lambda path: "rm -rf %s" % path, paths))
+        cmd = " ; ".join(map(lambda path: "rm -rf {}".format(path), paths))
 
         return self.execute(cmd, with_lock = True)
 
         return self.execute(cmd, with_lock = True)
-        
+    
     def run_and_wait(self, command, home, 
     def run_and_wait(self, command, home, 
-            shfile="cmd.sh",
-            env=None,
-            overwrite=True,
-            wait_run=True,
-            pidfile="pidfile", 
-            ecodefile="exitcode", 
-            stdin=None, 
-            stdout="stdout", 
-            stderr="stderr", 
-            sudo=False,
-            tty=False,
-            raise_on_error=True):
+                     shfile="cmd.sh",
+                     env=None,
+                     overwrite=True,
+                     wait_run=True,
+                     pidfile="pidfile", 
+                     ecodefile="exitcode", 
+                     stdin=None, 
+                     stdout="stdout", 
+                     stderr="stderr", 
+                     sudo=False,
+                     tty=False,
+                     raise_on_error=True):
         """
         Uploads the 'command' to a bash script in the host.
         Then runs the script detached in background in the host, and
         """
         Uploads the 'command' to a bash script in the host.
         Then runs the script detached in background in the host, and
@@ -868,45 +875,45 @@ This might be dangerous when using user root""",
             shfile = os.path.join(home, shfile)
 
         self.upload_command(command, 
             shfile = os.path.join(home, shfile)
 
         self.upload_command(command, 
-            shfile = shfile, 
-            ecodefile = ecodefile, 
-            env = env,
-            overwrite = overwrite)
+                            shfile = shfile, 
+                            ecodefile = ecodefile, 
+                            env = env,
+                            overwrite = overwrite)
 
 
-        command = "bash %s" % shfile
+        command = "bash {}".format(shfile)
         # run command in background in remote host
         (out, err), proc = self.run(command, home, 
         # run command in background in remote host
         (out, err), proc = self.run(command, home, 
-                pidfile = pidfile,
-                stdin = stdin, 
-                stdout = stdout, 
-                stderr = stderr, 
-                sudo = sudo,
-                tty = tty)
+                                    pidfile = pidfile,
+                                    stdin = stdin, 
+                                    stdout = stdout, 
+                                    stderr = stderr, 
+                                    sudo = sudo,
+                                    tty = tty)
 
         # check no errors occurred
         if proc.poll():
 
         # check no errors occurred
         if proc.poll():
-            msg = " Failed to run command '%s' " % command
+            msg = " Failed to run command '{}' ".format(command)
             self.error(msg, out, err)
             if raise_on_error:
                 raise RuntimeError, msg
 
         # Wait for pid file to be generated
         pid, ppid = self.wait_pid(
             self.error(msg, out, err)
             if raise_on_error:
                 raise RuntimeError, msg
 
         # Wait for pid file to be generated
         pid, ppid = self.wait_pid(
-                home = home, 
-                pidfile = pidfile, 
-                raise_on_error = raise_on_error)
+            home = home, 
+            pidfile = pidfile, 
+            raise_on_error = raise_on_error)
 
         if wait_run:
             # wait until command finishes to execute
             self.wait_run(pid, ppid)
 
         if wait_run:
             # wait until command finishes to execute
             self.wait_run(pid, ppid)
-          
+            
             (eout, err), proc = self.check_errors(home,
             (eout, err), proc = self.check_errors(home,
-                ecodefile = ecodefile,
-                stderr = stderr)
+                                                  ecodefile = ecodefile,
+                                                  stderr = stderr)
 
             # Out is what was written in the stderr file
             if err:
 
             # Out is what was written in the stderr file
             if err:
-                msg = " Failed to run command '%s' " % command
+                msg = " Failed to run command '{}' ".format(command)
                 self.error(msg, eout, err)
 
                 if raise_on_error:
                 self.error(msg, eout, err)
 
                 if raise_on_error:
@@ -939,22 +946,20 @@ This might be dangerous when using user root""",
         return ExitCode.ERROR
 
     def upload_command(self, command, 
         return ExitCode.ERROR
 
     def upload_command(self, command, 
-            shfile="cmd.sh",
-            ecodefile="exitcode",
-            overwrite=True,
-            env=None):
+                       shfile="cmd.sh",
+                       ecodefile="exitcode",
+                       overwrite=True,
+                       env=None):
         """ Saves the command as a bash script file in the remote host, and
         forces to save the exit code of the command execution to the ecodefile
         """
 
         if not (command.strip().endswith(";") or command.strip().endswith("&")):
             command += ";"
         """ Saves the command as a bash script file in the remote host, and
         forces to save the exit code of the command execution to the ecodefile
         """
 
         if not (command.strip().endswith(";") or command.strip().endswith("&")):
             command += ";"
-      
+            
         # The exit code of the command will be stored in ecodefile
         # The exit code of the command will be stored in ecodefile
-        command = " { %(command)s } ; echo $? > %(ecodefile)s ;" % {
-                'command': command,
-                'ecodefile': ecodefile,
-                } 
+        command = " {{ {command} }} ; echo $? > {ecodefile} ;"\
+                  .format(command=command, ecodefile=ecodefile)
 
         # Export environment
         environ = self.format_environment(env)
 
         # Export environment
         environ = self.format_environment(env)
@@ -976,11 +981,11 @@ This might be dangerous when using user root""",
         env = re.sub(r'\s+', ' ', env.strip())
 
         sep = ";" if inline else "\n"
         env = re.sub(r'\s+', ' ', env.strip())
 
         sep = ";" if inline else "\n"
-        return sep.join(map(lambda e: " export %s" % e, env.split(" "))) + sep 
+        return sep.join([" export {}".format(e) for e in env.split(" ")]) + sep 
 
     def check_errors(self, home, 
 
     def check_errors(self, home, 
-            ecodefile = "exitcode", 
-            stderr = "stderr"):
+                     ecodefile = "exitcode", 
+                     stderr = "stderr"):
         """ Checks whether errors occurred while running a command.
         It first checks the exit code for the command, and only if the
         exit code is an error one it returns the error output.
         """ Checks whether errors occurred while running a command.
         It first checks the exit code for the command, and only if the
         exit code is an error one it returns the error output.
@@ -993,7 +998,7 @@ This might be dangerous when using user root""",
         ecode = self.exitcode(home, ecodefile)
 
         if ecode in [ ExitCode.CORRUPTFILE, ExitCode.ERROR ]:
         ecode = self.exitcode(home, ecodefile)
 
         if ecode in [ ExitCode.CORRUPTFILE, ExitCode.ERROR ]:
-            err = "Error retrieving exit code status from file %s/%s" % (home, ecodefile)
+            err = "Error retrieving exit code status from file {}/{}".format(home, ecodefile)
         elif ecode > 0 or ecode == ExitCode.FILENOTFOUND:
             # The process returned an error code or didn't exist. 
             # Check standard error.
         elif ecode > 0 or ecode == ExitCode.FILENOTFOUND:
             # The process returned an error code or didn't exist. 
             # Check standard error.
@@ -1004,9 +1009,9 @@ This might be dangerous when using user root""",
             # (cat returns 1 for error "No such file or directory")
             if ecode == ExitCode.FILENOTFOUND and proc.poll() == 1: 
                 err = "" 
             # (cat returns 1 for error "No such file or directory")
             if ecode == ExitCode.FILENOTFOUND and proc.poll() == 1: 
                 err = "" 
-            
+                
         return ("", err), proc
         return ("", err), proc
+    
     def wait_pid(self, home, pidfile = "pidfile", raise_on_error = False):
         """ Waits until the pid file for the command is generated, 
             and returns the pid and ppid of the process """
     def wait_pid(self, home, pidfile = "pidfile", raise_on_error = False):
         """ Waits until the pid file for the command is generated, 
             and returns the pid and ppid of the process """
@@ -1023,10 +1028,9 @@ This might be dangerous when using user root""",
                 time.sleep(delay)
                 delay = delay * 1.5
         else:
                 time.sleep(delay)
                 delay = delay * 1.5
         else:
-            msg = " Failed to get pid for pidfile %s/%s " % (
-                    home, pidfile )
+            msg = " Failed to get pid for pidfile {}/{} ".format(home, pidfile )
             self.error(msg)
             self.error(msg)
-            
+    
             if raise_on_error:
                 raise RuntimeError, msg
 
             if raise_on_error:
                 raise RuntimeError, msg
 
@@ -1054,8 +1058,8 @@ This might be dangerous when using user root""",
 
     def check_output(self, home, filename):
         """ Retrives content of file """
 
     def check_output(self, home, filename):
         """ Retrives content of file """
-        (out, err), proc = self.execute("cat %s" % 
-            os.path.join(home, filename), retry = 1, with_lock = True)
+        (out, err), proc = self.execute(
+            "cat {}".format(os.path.join(home, filename)), retry = 1, with_lock = True)
         return (out, err), proc
 
     def is_alive(self):
         return (out, err), proc
 
     def is_alive(self):
@@ -1073,20 +1077,21 @@ This might be dangerous when using user root""",
         # until the result is not empty string
         try:
             (out, err), proc = self.execute("echo 'ALIVE'",
         # until the result is not empty string
         try:
             (out, err), proc = self.execute("echo 'ALIVE'",
-                    blocking = True,
-                    with_lock = True)
-    
+                                            blocking = True,
+                                            with_lock = True)
+            
             if out.find("ALIVE") > -1:
                 return True
         except:
             trace = traceback.format_exc()
             if out.find("ALIVE") > -1:
                 return True
         except:
             trace = traceback.format_exc()
-            msg = "Unresponsive host. Error reaching host: %s " % trace
+            msg = "Unresponsive host. Error reaching host: {} ".format(trace)
 
         self.error(msg, out, err)
         return False
 
     def find_home(self):
 
         self.error(msg, out, err)
         return False
 
     def find_home(self):
-        """ Retrieves host home directory
+        """ 
+        Retrieves host home directory
         """
         # The underlying SSH layer will sometimes return an empty
         # output (even if the command was executed without errors).
         """
         # The underlying SSH layer will sometimes return an empty
         # output (even if the command was executed without errors).
@@ -1095,14 +1100,14 @@ This might be dangerous when using user root""",
         msg = "Impossible to retrieve HOME directory"
         try:
             (out, err), proc = self.execute("echo ${HOME}",
         msg = "Impossible to retrieve HOME directory"
         try:
             (out, err), proc = self.execute("echo ${HOME}",
-                    blocking = True,
-                    with_lock = True)
-    
+                                            blocking = True,
+                                            with_lock = True)
+            
             if out.strip() != "":
                 self._home_dir =  out.strip()
         except:
             trace = traceback.format_exc()
             if out.strip() != "":
                 self._home_dir =  out.strip()
         except:
             trace = traceback.format_exc()
-            msg = "Impossible to retrieve HOME directory %s" % trace
+            msg = "Impossible to retrieve HOME directory {}".format(trace)
 
         if not self._home_dir:
             self.error(msg)
 
         if not self._home_dir:
             self.error(msg)
@@ -1112,17 +1117,17 @@ This might be dangerous when using user root""",
         """ Removes files that already exist in the Linux host from src list
         """
         # construct a dictionary with { dst: src }
         """ Removes files that already exist in the Linux host from src list
         """
         # construct a dictionary with { dst: src }
-        dests = dict(map(lambda s: (os.path.join(dst, os.path.basename(s)), s), src)) \
-                    if len(src) > 1 else dict({dst: src[0]})
+        dests = { os.path.join(dst, os.path.basename(s)) : s for s in src } \
+                if len(src) > 1 else {dst: src[0]}
 
         command = []
         for d in dests.keys():
 
         command = []
         for d in dests.keys():
-            command.append(" [ -f %(dst)s ] && echo '%(dst)s' " % {'dst' : d} )
+            command.append(" [ -f {dst} ] && echo '{dst}' ".format(dst=d) )
 
         command = ";".join(command)
 
         (out, err), proc = self.execute(command, retry = 1, with_lock = True)
 
         command = ";".join(command)
 
         (out, err), proc = self.execute(command, retry = 1, with_lock = True)
-    
+        
         for d in dests.keys():
             if out.find(d) > -1:
                 del dests[d]
         for d in dests.keys():
             if out.find(d) > -1:
                 del dests[d]