RemoteCmd/LocalCmd: various fixes
- allow executing in background - less logs - no use of split() - common implementation of legacy command()
This commit is contained in:
+33
-35
@@ -32,10 +32,17 @@ import os
|
|||||||
import paramiko
|
import paramiko
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
# helper that returns either LocalCmd or RemoteCmd based on passed host name
|
||||||
|
def getConnection(host, d=None):
|
||||||
|
if host is None or host.lower() in ["", "none", "localhost"]:
|
||||||
|
return LocalCmd(d=d)
|
||||||
|
else:
|
||||||
|
return RemoteCmd(host, d=d)
|
||||||
|
|
||||||
# provides a partial interface for the legacy SSHconnection class (getBefore(), command())
|
# provides a partial interface for the legacy SSHconnection class (getBefore(), command())
|
||||||
class Cmd(metaclass=abc.ABCMeta):
|
class Cmd(metaclass=abc.ABCMeta):
|
||||||
def cd(self, d, silent=False):
|
def cd(self, d, silent=False):
|
||||||
if d == None or d == '' or d == []:
|
if d == None or d == '':
|
||||||
self.cwd = None
|
self.cwd = None
|
||||||
elif d[0] == '/':
|
elif d[0] == '/':
|
||||||
self.cwd = d
|
self.cwd = d
|
||||||
@@ -51,9 +58,13 @@ class Cmd(metaclass=abc.ABCMeta):
|
|||||||
def run(self, line, timeout=300, silent=False):
|
def run(self, line, timeout=300, silent=False):
|
||||||
return
|
return
|
||||||
|
|
||||||
@abc.abstractmethod
|
def command(self, commandline, expectedline=None, timeout=300, silent=False, resync=False):
|
||||||
def command(self, commandline, expectedline, timeout, silent=False, resync=False):
|
splitted = commandline.split(' ')
|
||||||
return
|
if splitted[0] == 'cd':
|
||||||
|
self.cd(' '.join(splitted[1:]), silent)
|
||||||
|
else:
|
||||||
|
self.run(commandline, timeout, silent)
|
||||||
|
return 0
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def close(self):
|
def close(self):
|
||||||
@@ -82,7 +93,12 @@ class LocalCmd(Cmd):
|
|||||||
if not silent:
|
if not silent:
|
||||||
logging.info(line)
|
logging.info(line)
|
||||||
try:
|
try:
|
||||||
ret = sp.run(line, shell=True, cwd=self.cwd, stdout=sp.PIPE, stderr=sp.STDOUT, timeout=timeout)
|
if line.strip().endswith('&'):
|
||||||
|
# if we wait for stdout, subprocess does not return before the end of the command
|
||||||
|
# however, we don't want to wait for commands with &, so just return fake command
|
||||||
|
ret = sp.run(line, shell=True, cwd=self.cwd, timeout=5)
|
||||||
|
else:
|
||||||
|
ret = sp.run(line, shell=True, cwd=self.cwd, stdout=sp.PIPE, stderr=sp.STDOUT, timeout=timeout)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ret = sp.CompletedProcess(args=line, returncode=255, stdout=f'Exception: {str(e)}'.encode('utf-8'))
|
ret = sp.CompletedProcess(args=line, returncode=255, stdout=f'Exception: {str(e)}'.encode('utf-8'))
|
||||||
if ret.stdout is None:
|
if ret.stdout is None:
|
||||||
@@ -93,14 +109,6 @@ class LocalCmd(Cmd):
|
|||||||
self.cp = ret
|
self.cp = ret
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def command(self, commandline, expectedline=None, timeout=300, silent=False, resync=False):
|
|
||||||
line = [s for s in commandline.split(' ') if len(s) > 0]
|
|
||||||
if line[0] == 'cd':
|
|
||||||
self.cd(line[1], silent)
|
|
||||||
else:
|
|
||||||
self.run(line, timeout, silent)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -108,16 +116,14 @@ class LocalCmd(Cmd):
|
|||||||
return self.cp.stdout
|
return self.cp.stdout
|
||||||
|
|
||||||
def copyin(self, scpIp, scpUser, scpPw, src, tgt):
|
def copyin(self, scpIp, scpUser, scpPw, src, tgt):
|
||||||
logging.warning("LocalCmd emulating sshconnection.copyin() function")
|
|
||||||
self.run(f'cp -r {src} {tgt}')
|
self.run(f'cp -r {src} {tgt}')
|
||||||
|
|
||||||
def copyout(self, scpIp, scpUser, scpPw, src, tgt):
|
def copyout(self, scpIp, scpUser, scpPw, src, tgt):
|
||||||
logging.warning("LocalCmd emulating sshconnection.copyout() function")
|
|
||||||
self.run(f'cp -r {src} {tgt}')
|
self.run(f'cp -r {src} {tgt}')
|
||||||
|
|
||||||
class RemoteCmd(Cmd):
|
class RemoteCmd(Cmd):
|
||||||
def __init__(self, hostname, d=None):
|
def __init__(self, hostname, d=None):
|
||||||
logging.getLogger('paramiko').setLevel(logging.INFO) # prevent spamming through Paramiko
|
logging.getLogger('paramiko').setLevel(logging.ERROR) # prevent spamming through Paramiko
|
||||||
self.client = paramiko.SSHClient()
|
self.client = paramiko.SSHClient()
|
||||||
self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
cfg = RemoteCmd._lookup_ssh_config(hostname)
|
cfg = RemoteCmd._lookup_ssh_config(hostname)
|
||||||
@@ -146,33 +152,27 @@ class RemoteCmd(Cmd):
|
|||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
def run(self, line, timeout=300, silent=False, reportNonZero=True):
|
def run(self, line, timeout=300, silent=False, reportNonZero=True):
|
||||||
if type(line) is list:
|
|
||||||
line = ' '.join(line)
|
|
||||||
if not silent:
|
if not silent:
|
||||||
logging.debug(line)
|
logging.info(line)
|
||||||
if self.cwd:
|
if self.cwd:
|
||||||
line = f"cd {self.cwd} && {line}"
|
line = f"cd {self.cwd} && {line}"
|
||||||
args = line.split(' ')
|
|
||||||
try:
|
try:
|
||||||
stdin, stdout, stderr = self.client.exec_command(line, timeout=timeout)
|
if line.strip().endswith('&'):
|
||||||
ret = sp.CompletedProcess(args=args, returncode=stdout.channel.recv_exit_status(), stdout=stdout.read(size=None) + stderr.read(size=None))
|
# if we wait for stdout, Paramiko does not return before the end of the command
|
||||||
|
# however, we don't want to wait for commands with &, so just return fake command
|
||||||
|
self.client.exec_command(line, timeout = 5)
|
||||||
|
ret = sp.CompletedProcess(args=line, returncode=0, stdout=b'')
|
||||||
|
else:
|
||||||
|
stdin, stdout, stderr = self.client.exec_command(line, timeout=timeout)
|
||||||
|
ret = sp.CompletedProcess(args=line, returncode=stdout.channel.recv_exit_status(), stdout=stdout.read(size=None) + stderr.read(size=None))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ret = sp.CompletedProcess(args=args, returncode=255, stdout=f'Exception: {str(e)}'.encode('utf-8'))
|
ret = sp.CompletedProcess(args=line, returncode=255, stdout=f'Exception: {str(e)}'.encode('utf-8'))
|
||||||
ret.stdout = ret.stdout.decode('utf-8').strip()
|
ret.stdout = ret.stdout.decode('utf-8').strip()
|
||||||
if reportNonZero and ret.returncode != 0:
|
if reportNonZero and ret.returncode != 0:
|
||||||
cmd = ' '.join(ret.args)
|
logging.warning(f'command "{line}" returned non-zero returncode {ret.returncode}: output:\n{ret.stdout}')
|
||||||
logging.warning(f'command "{cmd}" returned non-zero returncode {ret.returncode}: output:\n{ret.stdout}')
|
|
||||||
self.cp = ret
|
self.cp = ret
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def command(self, commandline, expectedline=None, timeout=300, silent=False, resync=False):
|
|
||||||
line = [s for s in commandline.split(' ') if len(s) > 0]
|
|
||||||
if line[0] == 'cd':
|
|
||||||
self.cd(line[1], silent)
|
|
||||||
else:
|
|
||||||
self.run(line, timeout, silent)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.client.close()
|
self.client.close()
|
||||||
|
|
||||||
@@ -180,7 +180,6 @@ class RemoteCmd(Cmd):
|
|||||||
return self.cp.stdout
|
return self.cp.stdout
|
||||||
|
|
||||||
def copyout(self, src, tgt, recursive=False):
|
def copyout(self, src, tgt, recursive=False):
|
||||||
logging.warning("RemoteCmd emulating sshconnection.copyout() function, ignoring scpIp")
|
|
||||||
logging.debug(f"copyout: local:{src} -> remote:{tgt}")
|
logging.debug(f"copyout: local:{src} -> remote:{tgt}")
|
||||||
if recursive:
|
if recursive:
|
||||||
tmpfile = f"{uuid.uuid4()}.tar"
|
tmpfile = f"{uuid.uuid4()}.tar"
|
||||||
@@ -198,7 +197,6 @@ class RemoteCmd(Cmd):
|
|||||||
sftp.close()
|
sftp.close()
|
||||||
|
|
||||||
def copyin(self, src, tgt, recursive=False):
|
def copyin(self, src, tgt, recursive=False):
|
||||||
logging.warning("RemoteCmd emulating sshconnection.copyout() function")
|
|
||||||
logging.debug(f"copyin: remote:{src} -> local:{tgt}")
|
logging.debug(f"copyin: remote:{src} -> local:{tgt}")
|
||||||
if recursive:
|
if recursive:
|
||||||
tmpfile = f"{uuid.uuid4()}.tar"
|
tmpfile = f"{uuid.uuid4()}.tar"
|
||||||
|
|||||||
Reference in New Issue
Block a user