当 paramiko 抛出 'No existing session' 异常时,标准输入流挂起
Standard Input Stream hangs when paramiko throws 'No existing session' exception
我正在使用 java 使用以下方法启动 python 脚本:
private String[] runScript(String args) {
ArrayList<String> lines = new ArrayList<String>();
try {
String cmd = "python py/grabber/backdoor.py " + args;
System.out.println(cmd);
Runtime run = Runtime.getRuntime();
Process pr = run.exec(cmd);
InputStream stdout = pr.getInputStream();
BufferedReader stdInput = new BufferedReader(new InputStreamReader(stdout, StandardCharsets.UTF_8));
String line;
System.out.println("Starting to read output:");
while ((line = stdInput.readLine()) != null) {
if(!pr.isAlive()) {
break;
}
System.out.println("" + line);
lines.add(line);
}
stdInput.close();
} catch (Exception e) {
System.out.println("Exception in reading output" + e.toString());
}
return lines.toArray(new String[lines.size()]);
}
python 脚本开始为每个设备的新子线程上的设备列表执行以下方法:
def run_command(device, retry):
try:
if(retry != 0):
save_log('Retrying '+device['ip']+'...')
SSHClient = netmiko.ssh_dispatcher("cisco_ios")
ssh_connection = SSHClient(**device)
ruckus = ("ruckus" in str(device['device_type']))
output = ssh_connection.send_command('show run | inc hostname')
if(not ruckus):
output = output.split('\n')[0]
hostname = output.split(' ')[1] + '-' + today
else:
hostname = output.split(' ')[1] + '-' + today
msg = (''+device['ip']+':Retry Success! Hostname:'+hostname+'\n',''+device['ip']+':hostname: ' + hostname + '\n')[retry == 0]
save_log(msg)
return True
except Exception as e:
if("Authentication" in str(e)):
if(config.exe_i):
save_log('\nAuthentication failed! Consider resetting credentials\n')
if(not config.using_gui):
val = input("Continue with list? [y]/[n]: ")
if("n" in val):
return False
else:
return True
else:
msg = '\nSwitch: ' + device['ip'] + '\nLogin Failure'
save_error(msg)
return True
elif("SSH protocol banner" in str(e) and retry <= 3):
retry += 1
save_log('\nSwitch: ' + device['ip'] + ' - SSH Banner.. Attempt: '+str(retry))
return run_command(device, retry=retry)
elif("conn_timeout" in str(e) and retry <= 3):
retry += 1
save_log('\nSwitch: ' + device['ip'] + ' - Connection Timeout.. Attempt: '+str(retry))
return run_command(device, retry=retry)
error = 'error @ switch: ' + device['ip'] + ' with error: \n' + str(e)
save_error(error)
return True
当 python 脚本获得此特定异常时,
Paramiko: 'No existing session' error: try increasing 'conn_timeout' to 10 seconds or larger.
脚本将简单地重试连接并按预期正常进行,但是 java 程序开始挂起在 while 循环中,尽管 python 脚本已成功完成执行。为什么抛出这个异常后while循环中的标准输入流就开始挂了?
附加信息:
1.) 当从场景中取出线程时,如果抛出 'no existing session' 异常,while 循环仍将挂起。
2.) 导致重试 ssh 尝试的另一个常见异常“SSH 协议标语”不会导致 while 循环挂起。因此,我得出结论,问题不在于我的程序堆栈中处理异常本身的方式。
问题出在Java段,解决方案是不仅要读取输入流,还要读取输出流,因为如果两者都不清空,进程就会挂起。为了正确地做到这一点,每个流都需要在一个单独的线程上读取。 ProcessBuilder 是一个更好的选择,因为它允许您将输入和输出流合并为一个,然后只需要主线程。
这个堆栈 post 是对这个概念的更规范问题的引用:
Java Process with Input/Output Stream
我正在使用 java 使用以下方法启动 python 脚本:
private String[] runScript(String args) {
ArrayList<String> lines = new ArrayList<String>();
try {
String cmd = "python py/grabber/backdoor.py " + args;
System.out.println(cmd);
Runtime run = Runtime.getRuntime();
Process pr = run.exec(cmd);
InputStream stdout = pr.getInputStream();
BufferedReader stdInput = new BufferedReader(new InputStreamReader(stdout, StandardCharsets.UTF_8));
String line;
System.out.println("Starting to read output:");
while ((line = stdInput.readLine()) != null) {
if(!pr.isAlive()) {
break;
}
System.out.println("" + line);
lines.add(line);
}
stdInput.close();
} catch (Exception e) {
System.out.println("Exception in reading output" + e.toString());
}
return lines.toArray(new String[lines.size()]);
}
python 脚本开始为每个设备的新子线程上的设备列表执行以下方法:
def run_command(device, retry):
try:
if(retry != 0):
save_log('Retrying '+device['ip']+'...')
SSHClient = netmiko.ssh_dispatcher("cisco_ios")
ssh_connection = SSHClient(**device)
ruckus = ("ruckus" in str(device['device_type']))
output = ssh_connection.send_command('show run | inc hostname')
if(not ruckus):
output = output.split('\n')[0]
hostname = output.split(' ')[1] + '-' + today
else:
hostname = output.split(' ')[1] + '-' + today
msg = (''+device['ip']+':Retry Success! Hostname:'+hostname+'\n',''+device['ip']+':hostname: ' + hostname + '\n')[retry == 0]
save_log(msg)
return True
except Exception as e:
if("Authentication" in str(e)):
if(config.exe_i):
save_log('\nAuthentication failed! Consider resetting credentials\n')
if(not config.using_gui):
val = input("Continue with list? [y]/[n]: ")
if("n" in val):
return False
else:
return True
else:
msg = '\nSwitch: ' + device['ip'] + '\nLogin Failure'
save_error(msg)
return True
elif("SSH protocol banner" in str(e) and retry <= 3):
retry += 1
save_log('\nSwitch: ' + device['ip'] + ' - SSH Banner.. Attempt: '+str(retry))
return run_command(device, retry=retry)
elif("conn_timeout" in str(e) and retry <= 3):
retry += 1
save_log('\nSwitch: ' + device['ip'] + ' - Connection Timeout.. Attempt: '+str(retry))
return run_command(device, retry=retry)
error = 'error @ switch: ' + device['ip'] + ' with error: \n' + str(e)
save_error(error)
return True
当 python 脚本获得此特定异常时,
Paramiko: 'No existing session' error: try increasing 'conn_timeout' to 10 seconds or larger.
脚本将简单地重试连接并按预期正常进行,但是 java 程序开始挂起在 while 循环中,尽管 python 脚本已成功完成执行。为什么抛出这个异常后while循环中的标准输入流就开始挂了?
附加信息:
1.) 当从场景中取出线程时,如果抛出 'no existing session' 异常,while 循环仍将挂起。
2.) 导致重试 ssh 尝试的另一个常见异常“SSH 协议标语”不会导致 while 循环挂起。因此,我得出结论,问题不在于我的程序堆栈中处理异常本身的方式。
问题出在Java段,解决方案是不仅要读取输入流,还要读取输出流,因为如果两者都不清空,进程就会挂起。为了正确地做到这一点,每个流都需要在一个单独的线程上读取。 ProcessBuilder 是一个更好的选择,因为它允许您将输入和输出流合并为一个,然后只需要主线程。
这个堆栈 post 是对这个概念的更规范问题的引用: Java Process with Input/Output Stream