Проблема с вызовами функций pexpect и chained - PullRequest
0 голосов
/ 13 ноября 2009

Класс ниже предназначен для управления интерфейсом устройства, подобным cisco, с целью выполнения команд и обновления элементов конфигурации.

В текущем состоянии я могу создать экземпляр класса, сделать вызов функции ssh_to_aos_expsh и получить верный вывод (например, получить конфигурацию, когда команда 'show running-config'). Однако, когда я вызываю функцию ssh_to_aos_config (которая вызывает функцию ssh_to_aos_expsh), я получаю ошибку времени ожидания pexpect.

Я сравнил объект pexpect ('child' в _ssh_connect, ssh_to_aos_expsh и ssh_to_aos_config), возвращаемый _ssh_connect до ssh_to_aos_expsh, с объектом, возвращаемым ssh_to_aos_expsh к ssh_toaos_config и кажется, что он находится в той же ячейке памяти, поэтому мне непонятно, почему я не могу продолжать манипулировать объектом с pexpect.

Я не самый опытный программист на Python, поэтому, возможно, я допустил какую-то непреднамеренную ошибку, пытаясь передать объект pexpect между функциями, и если это так, я был бы признателен, если бы кто-то указал на мою ошибку.

#!/usr/bin/env python

import os
import traceback

import pexpect

class SSHTool():

    def __init__(self):
        self.aos_user = 'some_user'
        self.aos_passwd = 'some_passwd'
        self.aos_init_prompt = 'accelerator>'
        self.aos_enable_prompt = 'accelerator#'
        self.aos_lnxsh_prompt = 'ACC#'
        self.linux_passwd = 'linux_passwd'
        self.root_prompt = ''

    def _timeout_error(self, child):
        print 'SSH could not login.  Timeout error.'
        print child.before, child.after
        return None

    def _password_error(self, child):
        print 'SSH could not login.  Password error.'
        print child.before, child.after
        return None

    def _ssh_connect(self, user, address, passwd):
        self.root_prompt = "root@%s's password: " % address
        ssh_newkey = "Are you sure you want to continue connecting"
        child = pexpect.spawn('ssh -l %s %s' % (user, address))
        i = child.expect([pexpect.TIMEOUT, \
                            ssh_newkey, \
                            'Password: ', \
                            self.root_prompt])
        if i == 0: # Timeout
            return self._timeout_error(child)
        elif i == 1: # SSH does not have the public key. Just accept it.
            child.sendline ('yes')
            i = child.expect([pexpect.TIMEOUT, \
                            'Password: ', \
                            self.root_prompt])
            if i == 0: # Timeout
                return self._timeout_error(child)
            else:
                child.sendline(passwd)
                return child
        elif i == 2 or i == 3:
            child.sendline(passwd)
            return child
        else:
            return self._password_error(child)

    def ssh_to_aos_expsh(self, ip_address, command = ''):
        child = self._ssh_connect(self.aos_user, \
                                    ip_address, \
                                    self.aos_passwd)
        i = child.expect([pexpect.TIMEOUT, \
                            self.aos_init_prompt])
        if i == 0:
            return self._timeout_error(child)
        child.sendline('enable')
        i = child.expect([pexpect.TIMEOUT, \
                            self.aos_enable_prompt])
        if i == 0:
            return self._timeout_error(child)
        if command:
            child.sendline(command)
            i = child.expect([pexpect.TIMEOUT, \
                                self.aos_enable_prompt])
            if i == 0:
                return self._timeout_error(child)
            else:
                return child.before
        else:
            return child

    def ssh_to_aos_config(self, ip_address, command):
        child = self.ssh_to_aos_expsh(ip_address)
        i = child.expect([pexpect.TIMEOUT, \
                            self.aos_enable_prompt])
        if i == 0:
            return self._timeout_error(child)
        child.sendline('config')
        i = child.expect([pexpect.TIMEOUT, \
                            self.aos_config_prompt])
        if i == 0:
            return self._timeout_error(child)
        child.sendline(command)
        i = child.expect([pexpect.TIMEOUT, \
                            self.aos_config_prompt])
        if i == 0:
            return self._timeout_error(child)
        else:
            return child.before

Ответы [ 3 ]

1 голос
/ 16 ноября 2009

Оказалось, что было две проблемы, обе легко исправить, когда я узнал, что это за проблемы. Во-первых, метод __init__ не содержит self.aos_config_prompt - то, что исключение pexpect довольно четко заявило, когда я закомментировал свой код обработки исключений. Во-вторых, с учетом self.aos_config_prompt, который выглядел как «accelerator (config) #», pexpect компилирует его в код повторного соответствия модуля, который только тогда будет соответствовать приглашению, содержащему содержимое скобок. Просто уберите круглые скобки в строке, и совпадение будет работать так, как вам нужно.

0 голосов
/ 13 ноября 2009

Если вы получаете тайм-аут, это потому, что вы не получаете ни одной из ожидаемых строк. Возможно, вместо этого вы получаете сообщение об ошибке или ожидаемое сообщение неверно.

Включите ведение журнала, чтобы увидеть все взаимодействие - в pexpect 2.3 это делается путем назначения файлового объекта атрибуту child.logfile - тогда вы можете точно видеть, что происходит. Проверьте документы для более ранних версий, так как я думаю, что это изменилось.

Я заметил пару вещей в вашем коде:

1) root_prompt - пустая строка. Это всегда будет совпадать немедленно, даже если от клиента ничего не было возвращено. Это может быть причиной вашей проблемы - функция ssh connect считает, что она увидела приглашение и успешно вошла в систему, пока клиент все еще ожидает какой-то другой ввод.

2) в вашем коде есть синтаксическая ошибка - в ssh_connect есть последовательность:

if i == 0: # Timeout
    return self._timeout_error(child)
else:
    child.sendline(passwd)
    return child
elif i == 2 or i == 3:
    child.sendline(passwd)
    return child
else:
    return self._password_error(child)

elif не совпадает с оператором if, поэтому AFAIK никогда не скомпилируется. Я предполагаю, что это ошибка «вырезать и вставить», поскольку вы говорите, что выполняете код.

0 голосов
/ 13 ноября 2009

Я бы предположил, что тайм-аут случается, потому что ssh_to_aos_config() не получает все ожидаемые данные: вызов ssh_to_aos_expsh() вполне может сработать, а последующие вызовы expect - нет.

Таким образом, вопрос будет: , где случается ли тайм-аут? Вы можете отслеживать это, вызывая исключение вместо возврата self._timeout_error (child). Местоположение, которое вы найдете, будет указывать на ввод, который pexpect никогда не получит (отсюда время ожидания), и вы можете обновить свой код там.

...