0

下面的类旨在操作类似 cisco 的设备接口,以执行命令和更新配置元素。

按照目前的情况,我可以实例化类,调用ssh_to_aos_expsh函数并取回有效输出(例如,当命令为“show running-config”时获取配置)。但是,当我调用ssh_to_aos_config函数(调用ssh_to_aos_expsh函数)时,我得到一个 pexpect 超时错误。

我已经比较了 to 返回的 pexpect 对象( 和 中的“孩子” _ssh_connectssh_to_aos_expsh与tossh_to_aos_config返回的对象,它似乎位于相同的内存位置,所以我不清楚为什么我不能继续使用 pexpect 操作对象。_ssh_connectssh_to_aos_expshssh_to_aos_expshssh_toaos_config

我不是最复杂的 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
4

3 回答 3

1

事实证明,有两个问题,一旦我知道问题所在,这两个问题都很容易解决。首先,该__init__方法不包含任何内容self.aos_config_prompt——当我注释掉我的异常处理代码时,pexpect 异常清楚地说明了这一点。其次,给定一个self.aos_config_prompt看起来像 'accelerator(config)#' 的代码,pexpect 会将其编译为 re 模块匹配代码,然后才会匹配包含括号内容的提示。只需转义字符串中的括号,匹配就会按需要进行。

于 2009-11-16T05:45:46.787 回答
0

如果你得到一个超时,那是因为你没有得到任何你期望的字符串。可能是您收到错误消息,或者您期望的提示错误。

启用日志记录以查看整个交互 - 在 pexpect 2.3 中,这是通过将文件对象分配给 child.logfile 属性来完成的 - 然后您可以准确地看到正在发生的事情。检查早期版本的文档,因为我认为这已经改变。

我注意到您的代码中有几件事:

1) root_prompt 是一个空字符串。这将始终立即匹配,即使客户端没有返回任何内容。这可能是您的问题的原因 - ssh 连接功能认为它已经看到提示并成功登录,而客户端仍在等待其他一些输入。

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 这永远不会编译。我认为这是一个剪切和粘贴错误,因为您说您一直在运行代码。

于 2009-11-13T08:26:03.007 回答
0

我猜想超时的发生是因为ssh_to_aos_config()没有得到它期望的所有输入:调用ssh_to_aos_expsh()可能很好,而后续调用expect不会。

所以一个问题是:超时发生在哪里?您可以通过引发异常而不是返回 self._timeout_error(child) 来跟踪这一点。您找到的位置将指向 pexpect 永远不会获得的输入(因此超时),您可以在那里更新您的代码。

于 2009-11-13T08:14:37.583 回答