簡體   English   中英

pexpect和“鏈接”函數調用的問題

[英]Problem with pexpect and 'chained' function calls

下面的類旨在操縱類cisco的設備接口,以執行命令和更新配置元素。

按照目前的情況,我可以實例化該類,調用ssh_to_aos_expsh函數並返回有效輸出(例如,當命令為“ show running-config”時獲取配置)。 但是,當我調用ssh_to_aos_config函數(該函數調用ssh_to_aos_expsh函數)時,出現了預期超時錯誤。

我將_ssh_connect返回_ssh_connectssh_to_aos_expsh返回的pexpect對象( _ssh_connectssh_to_aos_expshssh_to_aos_config的“子”)與ssh_to_aos_config返回到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

事實證明,存在兩個問題,一旦我知道了問題所在,就可以輕松解決。 首先, __init__方法不包含self.aos_config_prompt當我注釋掉異常處理代碼時,pexpect異常非常清楚地說明了這一點。 第二,給定一個self.aos_config_prompt看起來像“促進劑(配置)#”,Pexpect的編譯到這一點re模塊匹配的代碼,然后只將匹配包含括號的內容的提示。 只需對字符串中的括號進行轉義,即可根據需要進行匹配。

我猜想發生超時是因為ssh_to_aos_config()沒有得到它期望的所有輸入: ssh_to_aos_expsh()的調用可能會正常工作,而隨后的expect調用則不會。

因此,問題將是:超時發生在哪里 您可以通過引發異常而不是返回self._timeout_error(child)來跟蹤此事件。 您找到的位置將指向預期不會得到的輸入(因此會超時),您可以在那里更新代碼。

如果超時,那是因為您沒有得到期望的任何字符串。 可能是您收到一條錯誤消息,或者您期望的提示是錯誤的。

啟用日志記錄以查看整個交互-在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永遠不會編譯它。 我認為這是剪切和粘貼錯誤,因為您說您一直在運行代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM