使用 Paramiko invoke_shell/send/recv 读取命令输出永远不会完成
Reading command output with Paramiko invoke_shell/send/recv never finishes
我正在尝试在 Paramiko 中使用 send
/recv
函数。据我所见,该行抛出超时异常
Evaluating: self.shell.recv(1024) did not finish after 3.00 seconds.
tmp = shell.recv(1024)
函数实现有什么问题?
我的 while True
退出条件是异常,如何更改为无异常退出?
完整代码:
self.shell = self.SSHConnect(ip, username, password)
def SSHConnect(self, ip, username, passowrd):
ssh = paramiko.SSHClient()
LOGGER.debug(msg="Open SSH Client to :" + str(ip))
try:
ssh.set_missing_host_key_policy(policy=paramiko.AutoAddPolicy())
ssh.connect(ip, port=22, username=username, password=passowrd, allow_agent=False, look_for_keys=True)
if self.device_type != 'linux_host':
session = ssh.invoke_shell()
return session
except Exception as ex:
LOGGER.critical(msg="SSH Client wasn't established! Device name : " + str(self.device_name))
return None
LOGGER.info(msg="Open SSH Client to :" + str(ip) + " established!")
return ssh
def run_command(self,cmd):
# New run command without throwing exception at the end:
LOGGER.debug('Start new Run command with cmd = ' + str(cmd))
try:
#Check the shell is activated before sending command:
LOGGER.debug('Check the shell is activated before sending command: ' + cmd)
if self.shell.get_transport().active:
LOGGER.debug('Shell is Activated ! Running the command ')
if self.device_type == 'linux_host':
stdin, stdout, stderr = self.shell.exec_command(cmd)
else:
try:
#Command for switch of UFMAPL
LOGGER.debug('Sending command to UFMAPL/Switch with send()')
out = ''
self.shell.send(cmd)
while not self.shell.recv_ready():
time.sleep(3)
counter = 1
print('\ncommand is : ' + cmd + '\n' )
while True:
try:
print('iteration number is : #' + str(counter))
tmp = self.shell.recv(1024)
counter = counter + 1
if not tmp:
break
except Exception as e:
break
out += tmp.decode("utf-8")
print('After iteration #' + str(counter) + ' out = ' + out + '\n\n')
ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
out = ansi_escape.sub('', out)
print('Printing final value before return : ' + str(out +'\n'))
return out
except Exception as e:
LOGGER.error('Exception in send() : ' +str(e) )
return None
else:
LOGGER.critical('Shell is not activated !')
return ""
if stderr.read():
LOGGER.critical('stderr is not empty which means the last command was failed, the command might not exist on host/switch ' )
return stderr.read().decode('utf-8')
out = stdout.read()
if out:
return out.decode("utf-8")
else:
LOGGER.critical('Run command sucussfully but return empty...')
return out.decode("utf-8")
except Exception as e:
LOGGER.error('Exception received in run command : ' + str(e))
日志(打印到屏幕):
IM HEREEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
command is : enable
iteration number is : #1
After iteration #2 out =
UFM Appliance
UFM is configured as standalone.
UFM mode: Management.
RAID state is: Degraded ( DRIVE1:Online,SpunUp, DRIVE2:Failed )
smg-ib-apl008-gen2 [ mgmt-sa ] >
iteration number is : #2
After iteration #3 out =
UFM Appliance
UFM is configured as standalone.
UFM mode: Management.
RAID state is: Degraded ( DRIVE1:Online,SpunUp, DRIVE2:Failed )
smg-ib-apl008-gen2 [ mgmt-sa ] > e
iteration number is : #3
After iteration #4 out =
UFM Appliance
UFM is configured as standalone.
UFM mode: Management.
RAID state is: Degraded ( DRIVE1:Online,SpunUp, DRIVE2:Failed )
smg-ib-apl008-gen2 [ mgmt-sa ] > enable
smg-ib-a
iteration number is : #4
After iteration #5 out =
UFM Appliance
UFM is configured as standalone.
UFM mode: Management.
RAID state is: Degraded ( DRIVE1:Online,SpunUp, DRIVE2:Failed )
smg-ib-apl008-gen2 [ mgmt-sa ] > enable
smg-ib-apl00
iteration number is : #5
After iteration #6 out =
UFM Appliance
UFM is configured as standalone.
UFM mode: Management.
RAID state is: Degraded ( DRIVE1:Online,SpunUp, DRIVE2:Failed )
smg-ib-apl008-gen2 [ mgmt-sa ] > enable
smg-ib-apl008-gen2 [ mgmt-sa ] #
iteration number is : #6
如您所见,调试器卡在 iteration #6
(冻结)。
为什么它会冻结并且不发送输出?
环境详细信息:
- Windows 10
- Eclipse 最新
如有任何帮助,我将不胜感激。如果您需要更多详细信息,请告诉我。
您的代码到了服务器停止等待另一个输入的地步。同时你等待服务器输出一些东西。它永远不会。这叫做 deadlock.
您可能已经预料到第一个命令执行已完成的某种信号。没有这样的信号。您正在使用“shell”(SSHClient.invoke_shell
)。 shell 是一个带有输入和输出的黑盒子。除了输出之外没有其他信号,wihhc 你已经在阅读了。
“shell”不应用于自动执行命令。对于命令自动化,有“exec”通道(Paramiko 中的SSHClient.exec_command
)。
虽然我知道对于某些特殊设备,您的服务器似乎是什么,您可能没有任何其他选择(请参阅 )。此外,我不确定 enable
命令是如何工作的。是否已经完成的命令,或者是否开始了一种新的 shell,它仍然是 运行,正在等待子命令。
所以最后你所能做的就是解析输出,等待命令提示符(smg-ib-apl008-gen2 [ mgmt-sa ] #
)。
是的,它很丑。您正在尝试自动化一些不适合自动化的东西。也许您的服务器有更好的 API 然后 enable
shell 命令,这将更好地实现自动化。但这是另一个问题。从 SSH/Python/Paramiko 的角度来看,没有更好的解决方案,如果您需要坚持在 shell.
中执行 enable
命令
相关问题:
尽管它们是关于更常规的服务器,例如 Linux。所以他们不会真的帮忙。我将它们链接起来只是为了提供更广泛的图片和上下文。
我正在尝试在 Paramiko 中使用 send
/recv
函数。据我所见,该行抛出超时异常
Evaluating: self.shell.recv(1024) did not finish after 3.00 seconds.
tmp = shell.recv(1024)
函数实现有什么问题?
我的 while True
退出条件是异常,如何更改为无异常退出?
完整代码:
self.shell = self.SSHConnect(ip, username, password)
def SSHConnect(self, ip, username, passowrd):
ssh = paramiko.SSHClient()
LOGGER.debug(msg="Open SSH Client to :" + str(ip))
try:
ssh.set_missing_host_key_policy(policy=paramiko.AutoAddPolicy())
ssh.connect(ip, port=22, username=username, password=passowrd, allow_agent=False, look_for_keys=True)
if self.device_type != 'linux_host':
session = ssh.invoke_shell()
return session
except Exception as ex:
LOGGER.critical(msg="SSH Client wasn't established! Device name : " + str(self.device_name))
return None
LOGGER.info(msg="Open SSH Client to :" + str(ip) + " established!")
return ssh
def run_command(self,cmd):
# New run command without throwing exception at the end:
LOGGER.debug('Start new Run command with cmd = ' + str(cmd))
try:
#Check the shell is activated before sending command:
LOGGER.debug('Check the shell is activated before sending command: ' + cmd)
if self.shell.get_transport().active:
LOGGER.debug('Shell is Activated ! Running the command ')
if self.device_type == 'linux_host':
stdin, stdout, stderr = self.shell.exec_command(cmd)
else:
try:
#Command for switch of UFMAPL
LOGGER.debug('Sending command to UFMAPL/Switch with send()')
out = ''
self.shell.send(cmd)
while not self.shell.recv_ready():
time.sleep(3)
counter = 1
print('\ncommand is : ' + cmd + '\n' )
while True:
try:
print('iteration number is : #' + str(counter))
tmp = self.shell.recv(1024)
counter = counter + 1
if not tmp:
break
except Exception as e:
break
out += tmp.decode("utf-8")
print('After iteration #' + str(counter) + ' out = ' + out + '\n\n')
ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
out = ansi_escape.sub('', out)
print('Printing final value before return : ' + str(out +'\n'))
return out
except Exception as e:
LOGGER.error('Exception in send() : ' +str(e) )
return None
else:
LOGGER.critical('Shell is not activated !')
return ""
if stderr.read():
LOGGER.critical('stderr is not empty which means the last command was failed, the command might not exist on host/switch ' )
return stderr.read().decode('utf-8')
out = stdout.read()
if out:
return out.decode("utf-8")
else:
LOGGER.critical('Run command sucussfully but return empty...')
return out.decode("utf-8")
except Exception as e:
LOGGER.error('Exception received in run command : ' + str(e))
日志(打印到屏幕):
IM HEREEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
command is : enable
iteration number is : #1
After iteration #2 out =
UFM Appliance
UFM is configured as standalone.
UFM mode: Management.
RAID state is: Degraded ( DRIVE1:Online,SpunUp, DRIVE2:Failed )
smg-ib-apl008-gen2 [ mgmt-sa ] >
iteration number is : #2
After iteration #3 out =
UFM Appliance
UFM is configured as standalone.
UFM mode: Management.
RAID state is: Degraded ( DRIVE1:Online,SpunUp, DRIVE2:Failed )
smg-ib-apl008-gen2 [ mgmt-sa ] > e
iteration number is : #3
After iteration #4 out =
UFM Appliance
UFM is configured as standalone.
UFM mode: Management.
RAID state is: Degraded ( DRIVE1:Online,SpunUp, DRIVE2:Failed )
smg-ib-apl008-gen2 [ mgmt-sa ] > enable
smg-ib-a
iteration number is : #4
After iteration #5 out =
UFM Appliance
UFM is configured as standalone.
UFM mode: Management.
RAID state is: Degraded ( DRIVE1:Online,SpunUp, DRIVE2:Failed )
smg-ib-apl008-gen2 [ mgmt-sa ] > enable
smg-ib-apl00
iteration number is : #5
After iteration #6 out =
UFM Appliance
UFM is configured as standalone.
UFM mode: Management.
RAID state is: Degraded ( DRIVE1:Online,SpunUp, DRIVE2:Failed )
smg-ib-apl008-gen2 [ mgmt-sa ] > enable
smg-ib-apl008-gen2 [ mgmt-sa ] #
iteration number is : #6
如您所见,调试器卡在 iteration #6
(冻结)。
为什么它会冻结并且不发送输出?
环境详细信息:
- Windows 10
- Eclipse 最新
如有任何帮助,我将不胜感激。如果您需要更多详细信息,请告诉我。
您的代码到了服务器停止等待另一个输入的地步。同时你等待服务器输出一些东西。它永远不会。这叫做 deadlock.
您可能已经预料到第一个命令执行已完成的某种信号。没有这样的信号。您正在使用“shell”(SSHClient.invoke_shell
)。 shell 是一个带有输入和输出的黑盒子。除了输出之外没有其他信号,wihhc 你已经在阅读了。
“shell”不应用于自动执行命令。对于命令自动化,有“exec”通道(Paramiko 中的SSHClient.exec_command
)。
虽然我知道对于某些特殊设备,您的服务器似乎是什么,您可能没有任何其他选择(请参阅 enable
命令是如何工作的。是否已经完成的命令,或者是否开始了一种新的 shell,它仍然是 运行,正在等待子命令。
所以最后你所能做的就是解析输出,等待命令提示符(smg-ib-apl008-gen2 [ mgmt-sa ] #
)。
是的,它很丑。您正在尝试自动化一些不适合自动化的东西。也许您的服务器有更好的 API 然后 enable
shell 命令,这将更好地实现自动化。但这是另一个问题。从 SSH/Python/Paramiko 的角度来看,没有更好的解决方案,如果您需要坚持在 shell.
enable
命令
相关问题:
尽管它们是关于更常规的服务器,例如 Linux。所以他们不会真的帮忙。我将它们链接起来只是为了提供更广泛的图片和上下文。