Как правильно использовать каналы Python Paramiko для чтения из них данных ⇐ Python

Программы на Python
Anonymous
Как правильно использовать каналы Python Paramiko для чтения из них данных

Сообщение Anonymous »

Это относится к моему предыдущему вопросу:
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

Вернуться в «Python»