Таймаут Python Paramiko с длительным выполнением, требуется полный вывод

Есть много тем, затрагивающих часть названия, но ничего, что вполне удовлетворяет всему. Я отправляю команду на удаленный сервер и мне нужен полный вывод после долгого времени выполнения, скажем, 5 минут или около того. Используя канал, я смог установить таймаут, но когда я прочитал обратно стандартный вывод, я получил лишь небольшую часть выходных данных. Казалось бы, решение состоит в том, чтобы ждать channel.exit_status_ready (). Это сработало при успешном вызове, но неудачный вызов никогда не вызовет тайм-аут канала. Изучив документы, я предполагаю, что это связано с тем, что тайм-аут работает только на операции чтения, а ожидание статуса выхода не подходит. Вот эта попытка:

channel = ssh.get_transport().open_session()
channel.settimeout(timeout)
channel.exec_command(cmd)  # return on this is not reliable
while True:
    try:
        if channel.exit_status_ready():
            if channel.recv_ready():  # so use recv instead...
                output = channel.recv(1048576)
                break
        if channel.recv_stderr_ready():  # then check error
            error = channel.recv_stderr(1048576)
            break
    except socket.timeout:
        print("SSH channel timeout exceeded.")
        break
    except Exception:
        traceback.print_exc()
        break

Довольно, не правда ли? Жаль, что это не сработало.

Моя первая попытка найти решение было использовать time.time () для начала, а затем проверить start - time.time ()> timeout. Это кажется простым, но в моей нынешней версии я вывожу start - time.time () с фиксированным тайм-аутом, который должен вызывать перерыв ... и вижу различия, которые удваивают и утраивают время ожидания без перерыва. Чтобы сэкономить место, я упомяну свою третью попытку, которую я свернул с этой. Я читал здесь об использовании select.select для ожидания вывода и отметил в документации, что там также есть тайм-аут. Как вы увидите из приведенного ниже кода, я смешал все три метода - тайм-аут канала, тайм-аут time.time и выбор тайм-аута - но все же придется убить процесс. Вот франкод:

channel = ssh.get_transport().open_session()
channel.settimeout(timeout)
channel.exec_command(cmd)  # return on this is not reliable
print("{0}".format(cmd))
start = time.time()
while True:
    try:
        rlist, wlist, elist = select([channel], [], [],
            float(timeout))
        print("{0}, {1}, {2}".format(rlist, wlist, elist))
        if rlist is not None and len(rlist) > 0:
            if channel.exit_status_ready():
                if channel.recv_ready():  # so use recv instead...
                    output = channel.recv(1048576)
                    break
        elif elist is not None and len(elist) > 0:
            if channel.recv_stderr_ready():  # then check error
                error = channel.recv_stderr(1048576)
                break
        print("{0} - {1} = {2}".format(
            time.time(), start, time.time() - start))
        if time.time() - start > timeout:
            break
    except socket.timeout:
        print("SSH channel timeout exceeded.")
        break
    except Exception:
        traceback.print_exc()
        break

Вот некоторые типичные результаты:

[<paramiko.Channel 3 (open) window=515488 -> <paramiko.Transport at 0x888414cL (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>], [], []
1352494558.42 - 1352494554.69 = 3.73274183273

Верхняя строка - это [rlist, wlist, elist] из выбора, нижняя строка - time.time () - start = (time.time () - start). Я получил этот прогон, чтобы разбить, посчитав итерации и разбив в нижней части попытки после цикла 1000 раз. Тайм-аут был установлен на 3 при пробном прогоне. Что доказывает, что мы справляемся с попыткой, но, очевидно, ни один из трех способов, которые следует использовать для тайм-аута, не работает.

Не стесняйтесь копировать код, если я что-то неправильно понял. Я хотел бы, чтобы это было супер-Pythonic и все еще учусь.

Ответы на вопрос(3)

Ваш ответ на вопрос