使用Paramiko invoke_shell/send/recv读取阅读命令输出永远不会完成

jdg4fx2g  于 2023-10-23  发布在  Shell
关注(0)|答案(1)|浏览(711)

我尝试在Paramiko中使用send/recv函数。根据我所看到的,该行抛出超时异常
正在评估:self.shell.recv(1024)在3.00秒后未完成。

  1. tmp = shell.recv(1024)

函数实现有什么问题?我从while True的退出条件是一个异常,我如何改变它以无异常地退出?

完整代码:

  1. self.shell = self.SSHConnect(ip, username, password)
  2. def SSHConnect(self, ip, username, passowrd):
  3. ssh = paramiko.SSHClient()
  4. LOGGER.debug(msg="Open SSH Client to :" + str(ip))
  5. try:
  6. ssh.set_missing_host_key_policy(policy=paramiko.AutoAddPolicy())
  7. ssh.connect(ip, port=22, username=username, password=passowrd, allow_agent=False, look_for_keys=True)
  8. if self.device_type != 'linux_host':
  9. session = ssh.invoke_shell()
  10. return session
  11. except Exception as ex:
  12. LOGGER.critical(msg="SSH Client wasn't established! Device name : " + str(self.device_name))
  13. return None
  14. LOGGER.info(msg="Open SSH Client to :" + str(ip) + " established!")
  15. return ssh
  16. def run_command(self,cmd):
  17. # New run command without throwing exception at the end:
  18. LOGGER.debug('Start new Run command with cmd = ' + str(cmd))
  19. try:
  20. #Check the shell is activated before sending command:
  21. LOGGER.debug('Check the shell is activated before sending command: ' + cmd)
  22. if self.shell.get_transport().active:
  23. LOGGER.debug('Shell is Activated ! Running the command ')
  24. if self.device_type == 'linux_host':
  25. stdin, stdout, stderr = self.shell.exec_command(cmd)
  26. else:
  27. try:
  28. #Command for switch of UFMAPL
  29. LOGGER.debug('Sending command to UFMAPL/Switch with send()')
  30. out = ''
  31. self.shell.send(cmd)
  32. while not self.shell.recv_ready():
  33. time.sleep(3)
  34. counter = 1
  35. print('\ncommand is : ' + cmd + '\n' )
  36. while True:
  37. try:
  38. print('iteration number is : #' + str(counter))
  39. tmp = self.shell.recv(1024)
  40. counter = counter + 1
  41. if not tmp:
  42. break
  43. except Exception as e:
  44. break
  45. out += tmp.decode("utf-8")
  46. print('After iteration #' + str(counter) + ' out = ' + out + '\n\n')
  47. ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
  48. out = ansi_escape.sub('', out)
  49. print('Printing final value before return : ' + str(out +'\n'))
  50. return out
  51. except Exception as e:
  52. LOGGER.error('Exception in send() : ' +str(e) )
  53. return None
  54. else:
  55. LOGGER.critical('Shell is not activated !')
  56. return ""
  57. if stderr.read():
  58. LOGGER.critical('stderr is not empty which means the last command was failed, the command might not exist on host/switch ' )
  59. return stderr.read().decode('utf-8')
  60. out = stdout.read()
  61. if out:
  62. return out.decode("utf-8")
  63. else:
  64. LOGGER.critical('Run command sucussfully but return empty...')
  65. return out.decode("utf-8")
  66. except Exception as e:
  67. LOGGER.error('Exception received in run command : ' + str(e))
  • 打印到屏幕:*
  1. IM HEREEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  2. command is : enable
  3. iteration number is : #1
  4. After iteration #2 out =
  5. UFM Appliance
  6. UFM is configured as standalone.
  7. UFM mode: Management.
  8. RAID state is: Degraded ( DRIVE1:Online,SpunUp, DRIVE2:Failed )
  9. smg-ib-apl008-gen2 [ mgmt-sa ] >
  10. iteration number is : #2
  11. After iteration #3 out =
  12. UFM Appliance
  13. UFM is configured as standalone.
  14. UFM mode: Management.
  15. RAID state is: Degraded ( DRIVE1:Online,SpunUp, DRIVE2:Failed )
  16. smg-ib-apl008-gen2 [ mgmt-sa ] > e
  17. iteration number is : #3
  18. After iteration #4 out =
  19. UFM Appliance
  20. UFM is configured as standalone.
  21. UFM mode: Management.
  22. RAID state is: Degraded ( DRIVE1:Online,SpunUp, DRIVE2:Failed )
  23. smg-ib-apl008-gen2 [ mgmt-sa ] > enable
  24. smg-ib-a
  25. iteration number is : #4
  26. After iteration #5 out =
  27. UFM Appliance
  28. UFM is configured as standalone.
  29. UFM mode: Management.
  30. RAID state is: Degraded ( DRIVE1:Online,SpunUp, DRIVE2:Failed )
  31. smg-ib-apl008-gen2 [ mgmt-sa ] > enable
  32. smg-ib-apl00
  33. iteration number is : #5
  34. After iteration #6 out =
  35. UFM Appliance
  36. UFM is configured as standalone.
  37. UFM mode: Management.
  38. RAID state is: Degraded ( DRIVE1:Online,SpunUp, DRIVE2:Failed )
  39. smg-ib-apl008-gen2 [ mgmt-sa ] > enable
  40. smg-ib-apl008-gen2 [ mgmt-sa ] #
  41. iteration number is : #6

正如你所看到的,调试器在iteration #6上卡住了(冻结)。为什么它冻结并且不发送输出?

  • 环境详情:*
  • Windows 10
  • Eclipse最新

我会很感激任何帮助。如果你需要更多的细节就告诉我。

j2cgzkjk

j2cgzkjk1#

您的代码到达服务器停止等待另一个输入的点。同时等待服务器输出一些东西。永远不会发生的事这就是所谓的deadlock
您可能期望得到某种信号,表明第一个命令执行已经完成。没有这样的信号。您正在使用“shell”(SSHClient.invoke_shell)。shell是一个有输入和输出的黑盒子。除了您已经在阅读的输出之外,没有其他信号。
“shell”不应用于自动执行命令。对于命令自动化,有“exec”通道(Paramiko中的SSHClient.exec_command)。
虽然我知道,对于一些特殊的设备,你的服务器似乎是什么,你可能没有任何其他选择(见Executing command using Paramiko exec_command on device is not working)。此外,我不确定enable命令是如何工作的。无论是一个已经完成的命令,还是一个新的shell,它仍然在运行并等待子命令。
所以最后你所能做的就是解析输出,等待命令提示符(smg-ib-apl008-gen2 [ mgmt-sa ] #)。基本上,当检测到命令完成时,当交互地使用shell/终端时,您需要实现您自己(作为一个人)使用的“智能”。
是的,很丑。你正在尝试自动化一些本来不打算自动化的东西。也许你的服务器有一个更好的API,然后enable shell命令,这将是更好的自动化。但那是另一个问题。从SSH/Python/Paramiko的Angular 来看,如果您需要坚持在shell中执行enable命令,那么没有更好的解决方案。
相关问题:

虽然它们是关于更常规的服务器,如Linux。所以他们帮不上忙。我把它们联系起来只是为了提供更广泛的画面和背景。

相关问题