systematic use of context managers for dealing with files instead of open()/close...
[nepi.git] / src / nepi / util / sshfuncs.py
index 83e2d7e..cfb9908 100644 (file)
@@ -38,13 +38,11 @@ _re_inet = re.compile("\d+:\s+(?P<name>[a-z0-9_-]+)\s+inet6?\s+(?P<inet>[a-f0-9.
 
 logger = logging.getLogger("sshfuncs")
 
-def log(msg, level, out = None, err = None):
+def log(msg, level = logging.DEBUG, out = None, err = None):
     if out:
         msg += " - OUT: %s " % out
-
     if err:
         msg += " - ERROR: %s " % err
-
     logger.log(level, msg)
 
 if hasattr(os, "devnull"):
@@ -59,6 +57,7 @@ class STDOUT:
     Special value that when given to rspawn in stderr causes stderr to 
     redirect to whatever stdout was redirected to.
     """
+    pass
 
 class ProcStatus:
     """
@@ -80,8 +79,12 @@ def resolve_hostname(host):
     ip = None
 
     if host in ["localhost", "127.0.0.1", "::1"]:
-        p = subprocess.Popen("ip -o addr list", shell=True,
-                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        p = subprocess.Popen(
+            "ip -o addr list",
+            shell=True,
+            stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE,
+        )
         stdout, stderr = p.communicate()
         m = _re_inet.findall(stdout)
         ip = m[0][1].split("/")[0]
@@ -117,12 +120,15 @@ def openssh_has_persist():
     """
     global OPENSSH_HAS_PERSIST
     if OPENSSH_HAS_PERSIST is None:
-        proc = subprocess.Popen(["ssh","-v"],
-            stdout = subprocess.PIPE,
-            stderr = subprocess.STDOUT,
-            stdin = open("/dev/null","r") )
-        out,err = proc.communicate()
-        proc.wait()
+        with open("/dev/null") as null:
+            proc = subprocess.Popen(
+                ["ssh", "-v"],
+                stdout = subprocess.PIPE,
+                stderr = subprocess.STDOUT,
+                stdin = null,
+            )
+            out,err = proc.communicate()
+            proc.wait()
         
         vre = re.compile(r'OpenSSH_(?:[6-9]|5[.][8-9]|5[.][1-9][0-9]|[1-9][0-9]).*', re.I)
         OPENSSH_HAS_PERSIST = bool(vre.match(out))
@@ -160,9 +166,8 @@ def make_server_key_args(server_key, host, port):
     if os.environ.get('NEPI_STRICT_AUTH_MODE',"").lower() not in ('1','true','on'):
         user_hosts_path = '%s/.ssh/known_hosts' % (os.environ.get('HOME',""),)
         if os.access(user_hosts_path, os.R_OK):
-            f = open(user_hosts_path, "r")
-            tmp_known_hosts.write(f.read())
-            f.close()
+            with open(user_hosts_path, "r") as f:
+                tmp_known_hosts.write(f.read())
         
     tmp_known_hosts.flush()
     
@@ -189,12 +194,12 @@ def shell_escape(s):
         return s
     else:
         # unsafe string - escape
-        def escp(c):
+        def escape(c):
             if (32 <= ord(c) < 127 or c in ('\r','\n','\t')) and c not in ("'",'"'):
                 return c
             else:
                 return "'$'\\x%02x''" % (ord(c),)
-        s = ''.join(map(escp,s))
+        s = ''.join(map(escape, s))
         return "'%s'" % (s,)
 
 def eintr_retry(func):
@@ -303,13 +308,13 @@ def rexec(command, host, user,
         stdout = stderr = stdin = None
 
     return _retry_rexec(args, log_msg, 
-            stderr = stderr,
-            stdin = stdin,
-            stdout = stdout,
-            env = env, 
-            retry = retry, 
-            tmp_known_hosts = tmp_known_hosts,
-            blocking = blocking)
+                        stderr = stderr,
+                        stdin = stdin,
+                        stdout = stdout,
+                        env = env, 
+                        retry = retry, 
+                        tmp_known_hosts = tmp_known_hosts,
+                        blocking = blocking)
 
 def rcopy(source, dest,
         port = None,
@@ -344,9 +349,13 @@ def rcopy(source, dest,
     tmp_known_hosts = None
 
     args = ['scp', '-q', '-p', '-C',
+            # 2015-06-01 Thierry: I am commenting off blowfish
+            # as this is not available on a plain ubuntu 15.04 install
+            # this IMHO is too fragile, shoud be something the user
+            # decides explicitly (so he is at least aware of that dependency)
             # Speed up transfer using blowfish cypher specification which is 
             # faster than the default one (3des)
-            '-c', 'blowfish',
+            '-c', 'blowfish',
             # Don't bother with localhost. Makes test easier
             '-o', 'NoHostAuthenticationForLocalhost=yes',
             '-o', 'ConnectTimeout=60',
@@ -399,22 +408,22 @@ def rcopy(source, dest,
             blocking = True)
 
 def rspawn(command, pidfile, 
-        stdout = '/dev/null', 
-        stderr = STDOUT, 
-        stdin = '/dev/null',
-        home = None, 
-        create_home = False, 
-        sudo = False,
-        host = None, 
-        port = None, 
-        user = None, 
-        gwuser = None,
-        gw = None,
-        agent = None, 
-        identity = None, 
-        server_key = None,
-        tty = False,
-        strict_host_checking = True):
+           stdout = '/dev/null', 
+           stderr = STDOUT, 
+           stdin = '/dev/null',
+           home = None, 
+           create_home = False, 
+           sudo = False,
+           host = None, 
+           port = None, 
+           user = None, 
+           gwuser = None,
+           gw = None,
+           agent = None, 
+           identity = None, 
+           server_key = None,
+           tty = False,
+           strict_host_checking = True):
     """
     Spawn a remote command such that it will continue working asynchronously in 
     background. 
@@ -500,15 +509,15 @@ def rspawn(command, pidfile,
 
 @eintr_retry
 def rgetpid(pidfile,
-        host = None, 
-        port = None, 
-        user = None, 
-        gwuser = None,
-        gw = None,
-        agent = None, 
-        identity = None,
-        server_key = None,
-        strict_host_checking = True):
+            host = None, 
+            port = None, 
+            user = None, 
+            gwuser = None,
+            gw = None,
+            agent = None, 
+            identity = None,
+            server_key = None,
+            strict_host_checking = True):
     """
     Returns the pid and ppid of a process from a remote file where the 
     information was stored.
@@ -679,23 +688,27 @@ fi
     return (out, err), proc
 
 def _retry_rexec(args,
-        log_msg,
-        stdout = subprocess.PIPE,
-        stdin = subprocess.PIPE, 
-        stderr = subprocess.PIPE,
-        env = None,
-        retry = 3,
-        tmp_known_hosts = None,
-        blocking = True):
+                 log_msg,
+                 stdout = subprocess.PIPE,
+                 stdin = subprocess.PIPE, 
+                 stderr = subprocess.PIPE,
+                 env = None,
+                 retry = 3,
+                 tmp_known_hosts = None,
+                 blocking = True):
 
     for x in xrange(retry):
+        # display command actually invoked when debug is turned on
+        message = " ".join( [ "'{}'".format(arg) for arg in args ] )
+        log("sshfuncs: invoking {}".format(message), logging.DEBUG)
         # connects to the remote host and starts a remote connection
-        proc = subprocess.Popen(args,
-                env = env,
-                stdout = stdout,
-                stdin = stdin, 
-                stderr = stderr)
-        
+        proc = subprocess.Popen(
+            args,
+            env = env,
+            stdout = stdout,
+            stdin = stdin, 
+            stderr = stderr,
+        )        
         # attach tempfile object to the process, to make sure the file stays
         # alive until the process is finished with it
         proc._known_hosts = tmp_known_hosts