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"):
Special value that when given to rspawn in stderr causes stderr to
redirect to whatever stdout was redirected to.
"""
+ pass
class ProcStatus:
"""
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,
+ universal_newlines = True,
+ )
stdout, stderr = p.communicate()
m = _re_inet.findall(stdout)
ip = m[0][1].split("/")[0]
"""
global OPENSSH_HAS_PERSIST
if OPENSSH_HAS_PERSIST is None:
- proc = subprocess.Popen(["ssh","-v"],
+ proc = subprocess.Popen(
+ ["ssh", "-v"],
stdout = subprocess.PIPE,
stderr = subprocess.STDOUT,
- stdin = open("/dev/null","r") )
+ stdin = subprocess.DEVNULL,
+ universal_newlines = True,
+ )
out,err = proc.communicate()
proc.wait()
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):
@functools.wraps(func)
def rv(*p, **kw):
retry = kw.pop("_retry", False)
- for i in xrange(0 if retry else 4):
+ for i in range(0 if retry else 4):
try:
return func(*p, **kw)
- except (select.error, socket.error), args:
+ except (select.error, socket.error) as args:
if args[0] == errno.EINTR:
continue
else:
raise
- except OSError, e:
+ except OSError as e:
if e.errno == errno.EINTR:
continue
else:
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,
elif isinstance(source, str) and ':' in source:
remspec, path = source.split(':',1)
else:
- raise ValueError, "Both endpoints cannot be local"
+ raise ValueError("Both endpoints cannot be local")
user,host = remspec.rsplit('@',1)
# plain scp
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',
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.
)
if proc.wait():
- raise RuntimeError, "Failed to set up application on host %s: %s %s" % (host, out,err,)
+ raise RuntimeError("Failed to set up application on host %s: %s %s" % (host, out,err,))
return ((out, err), proc)
@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.
if out:
try:
- return map(int,out.strip().split(' ',1))
+ return [ int(x) for x in out.strip().split(' ',1)) ]
except:
# Ignore, many ways to fail that don't matter that much
return None
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):
-
- for x in xrange(retry):
+ log_msg,
+ stdout = subprocess.PIPE,
+ stdin = subprocess.PIPE,
+ stderr = subprocess.PIPE,
+ env = None,
+ retry = 3,
+ tmp_known_hosts = None,
+ blocking = True):
+
+ for x in range(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,
+ universal_newlines = True,
+ )
# 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
# The method communicate was re implemented for performance issues
# when using python subprocess communicate method the ssh commands
# last one minute each
+ #log("BEFORE communicate", level=logging.INFO); import time; beg=time.time()
out, err = _communicate(proc, input=None)
+ #log("AFTER communicate - {}s".format(time.time()-beg), level=logging.INFO)
elif stdout:
out = proc.stdout.read()
time.sleep(t)
continue
break
- except RuntimeError, e:
+ except RuntimeError as e:
msg = " rexec EXCEPTION - TIMEOUT -> %s \n %s" % ( e.args, log_msg )
log(msg, logging.DEBUG, out, err)
try:
rlist, wlist, xlist = select.select(read_set, write_set, [], select_timeout)
- except select.error,e:
+ except select.error as e:
if e[0] != 4:
raise
else:
write_set.remove(proc.stdin)
if proc.stdout in rlist:
- data = os.read(proc.stdout.fileno(), 1024)
- if data == "":
+ # python2 version used to do this
+ # data = os.read(proc.stdout.fileno(), 1024)
+ # however this always returned bytes...
+ data = proc.stdout.read()
+ log('we have read {}'.format(data))
+ # data should be str and not bytes because we use
+ # universal_lines = True, but to be clean
+ # instead of saying data != ""
+ if not data:
+ log('closing stdout')
proc.stdout.close()
read_set.remove(proc.stdout)
stdout.append(data)
if proc.stderr in rlist:
- data = os.read(proc.stderr.fileno(), 1024)
- if data == "":
+ # likewise (see above)
+ # data = os.read(proc.stderr.fileno(), 1024)
+ data = proc.stderr.read()
+ if not data:
proc.stderr.close()
read_set.remove(proc.stderr)
stderr.append(data)
if stderr is not None:
stderr = ''.join(stderr)
- # Translate newlines, if requested. We cannot let the file
- # object do the translation: It is based on stdio, which is
- # impossible to combine with select (unless forcing no
- # buffering).
- if proc.universal_newlines and hasattr(file, 'newlines'):
- if stdout:
- stdout = proc._translate_newlines(stdout)
- if stderr:
- stderr = proc._translate_newlines(stderr)
+# # Translate newlines, if requested. We cannot let the file
+# # object do the translation: It is based on stdio, which is
+# # impossible to combine with select (unless forcing no
+# # buffering).
+# if proc.universal_newlines and hasattr(file, 'newlines'):
+# if stdout:
+# stdout = proc._translate_newlines(stdout)
+# if stderr:
+# stderr = proc._translate_newlines(stderr)
if killed and err_on_timeout:
errcode = proc.poll()
- raise RuntimeError, ("Operation timed out", errcode, stdout, stderr)
+ raise RuntimeError("Operation timed out", errcode, stdout, stderr)
else:
if killed:
proc.poll()