Python SSH Paramiko set_keepalive не работает в Linux
Я пытаюсь написать код, который использует канал Paramiko для выполнения на сетевом устройстве CISCO и закройте/завершите сеанс SSH, как только в стандартном выводе встретится определенная строка (указывающая, что коммутатор начал перезагрузку).
Основное использование этого кода — запуск обновления прошивки на сетевом коммутаторе. В конце коммутатор перезагружается, не закрывая сначала сеанс SSH, поэтому команда, выполняемая через SSHClient.exec_command(), зависает/блокируется до тех пор, пока не истечет время ожидания основного сеанса TCP (может занять много минут). Установка поддержки активности на транспорте не сильно помогает, так как в Paramiko нет функциональности, аналогичной -o ServerAliveCountMax OpenSSH.
Однако у меня есть проблемы с разработкой такого кода.
Код, который я написал ( упрощенно):
Код: Выделить всё
import paramiko
from time import sleep
HOST = "host"
USERNAME = "user"
PASSWORD = "password"
COMMAND = "NX-OS command"
READSIZE = 1024
ABORT_STRING = "switch rebooting"
client = paramiko.SSHClient()
client.connect(HOST, username=USERNAME, password=PASSWORD)
transport = client.get_transport()
channel = transport.open_session()
channel.exec_command(COMMAND)
stdout_output = ""
stderr_output = ""
while True:
if channel.recv_ready():
stdout_output += channel.recv(READSIZE).decode()
if ABORT_STRING in stdout_output:
channel.close()
break
if channel.recv_stderr_ready():
stderr_output +=channel.recv_stderr(READSIZE).decode()
#sleep(1)
if channel.exit_status_ready():
break
client.close()
И этот код работает только, скажем, в 8 из 10 случаев - тогда он содержит все содержимое вывода stdout в stdout_output.
В одном из 10 случаев stdout содержит только часть вывода, а в оставшийся регистр stderr_output пуст, когда цикл заканчивается.
Если я добавлю задержку в одну секунду (где комментируется сон), то в 10 из 10 случаев stdout_output будет пустым после выхода из цикла.
После тестирования/отладки кажется, что то, что возвращает Channel.exit_status_ready(), совершенно не зависит от того, были ли данные, возвращенные выполненной командой, полностью (или вообще) прочитаны или нет.
Такое может случиться. что Recv_ready() возвращает False (данные еще не поступили из Channel.exec_command()), а несколькими строками позже Channel.exit_status_ready() уже возвращает True, поэтому цикл завершается без чтения (или части данных) из канала.Я пытался улучшить этот цикл следующим образом:
Код: Выделить всё
while True:
some_stdout_read = False
if channel.recv_ready():
stdout_output += channel.recv(READSIZE).decode()
some_stdout_read = True
if ABORT_STRING in stdout_output:
channel.close()
break
if channel.recv_stderr_ready():
stderr_output +=channel.recv_stderr(READSIZE).decode()
if some_stdout_read:
continue
#sleep(1)
if channel.exit_status_ready():
break
client.close()
Но все же есть случаи, когда данные отсутствуют был прочитан вообще, и цикл завершился в Channel.exit_status_ready().
Я думал о том, чтобы не допустить, чтобы цикл достигал Channel.exit_status_ready(), если данные вообще не были прочитаны из стандартного вывода. Но тогда код не работает (зависает) с командами переключения, которые не возвращают данных (просто возвращаются к приглашению).
Как это можно улучшить?
Подробнее здесь: https://stackoverflow.com/questions/790 ... ta-from-it