|
|
@@ -8,8 +8,10 @@ import io
|
|
|
import os
|
|
|
import posixpath
|
|
|
import pwd
|
|
|
+import socket
|
|
|
import subprocess
|
|
|
import threading
|
|
|
+import time
|
|
|
|
|
|
from .config import Task, yaml_load
|
|
|
from .utils import (ByrdException, LocalException, ObjectDict, RemoteException,
|
|
|
@@ -53,6 +55,8 @@ def get_sudo_passwd():
|
|
|
|
|
|
CONNECTION_CACHE = {}
|
|
|
|
|
|
+SUDO_PW_CACHE = {}
|
|
|
+
|
|
|
|
|
|
def connect(host, auth):
|
|
|
if host in CONNECTION_CACHE:
|
|
|
@@ -181,6 +185,15 @@ def log_stream(stream, buff):
|
|
|
t.start()
|
|
|
return t
|
|
|
|
|
|
+def read_channel(channel, wait_time):
|
|
|
+ t = time.time()
|
|
|
+ received = b''
|
|
|
+ channel.settimeout(wait_time)
|
|
|
+ while (time.time() - t) < wait_time:
|
|
|
+ try:
|
|
|
+ received += channel.recv(1024)
|
|
|
+ except socket.timeout:
|
|
|
+ return received
|
|
|
|
|
|
def run_helper(client, cmd, env=None, in_buff=None, sudo=False):
|
|
|
'''
|
|
|
@@ -198,20 +211,19 @@ def run_helper(client, cmd, env=None, in_buff=None, sudo=False):
|
|
|
else:
|
|
|
sudo_cmd = 'sudo -s'
|
|
|
chan.exec_command(sudo_cmd)
|
|
|
- msg = chan.recv(1024)
|
|
|
+ msg = read_channel(chan, 0.1)
|
|
|
while msg and b'[sudo] password for' in msg:
|
|
|
- pw = getpass(msg.decode())
|
|
|
+ pw = SUDO_PW_CACHE[client] if client in SUDO_PW_CACHE else getpass(msg.decode())
|
|
|
chan.send(pw + '\n')
|
|
|
- msg = chan.recv(1024)
|
|
|
- msg += chan.recv(1024)
|
|
|
+ msg = read_channel(chan, 0.1)
|
|
|
if b'root@' in msg:
|
|
|
+ SUDO_PW_CACHE[client] = pw
|
|
|
break
|
|
|
else:
|
|
|
+ msg += read_channel(chan, 2)
|
|
|
if b'sudo: 3 incorrect password attempts' in msg:
|
|
|
raise RemoteException(msg)
|
|
|
- if b'Sorry' in msg: # Failure message in in two parts in bash on Debian anyway.
|
|
|
- msg += chan.recv(1024)
|
|
|
-
|
|
|
+ chan.settimeout(None)
|
|
|
in_buff = cmd
|
|
|
|
|
|
stdin = chan.makefile('wb')
|
|
|
@@ -227,8 +239,11 @@ def run_helper(client, cmd, env=None, in_buff=None, sudo=False):
|
|
|
|
|
|
if in_buff:
|
|
|
# XXX use a real buff (not a simple str) ?
|
|
|
- stdin.write(in_buff.replace('\n', '') + ' && exit $?\n')
|
|
|
+ stdin.write(in_buff if in_buff[-1] == '\n' else in_buff + '\n')
|
|
|
stdin.flush()
|
|
|
+ if sudo:
|
|
|
+ stdin.write('exit $?\n')
|
|
|
+ stdin.flush()
|
|
|
stdin.close()
|
|
|
chan.shutdown_write()
|
|
|
|