2009-11-13 39 views
0

類下面被設計成操縱一個cisco狀裝置接口,用於執行命令和更新配置元件的目的。我現在可以實例化這個類,調用ssh_to_aos_expsh函數並獲取有效的輸出(例如,當命令是'show running-config'時獲取配置)。然而,當我做出了ssh_to_aos_config函數的調用(它調用ssh_to_aos_expsh功能),我得到一個Pexpect的超時錯誤。問題的Pexpect的和「鏈狀」的函數調用

我比較(在_ssh_connectssh_to_aos_expshssh_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 = "[email protected]%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 

回答

1

原來,有兩個問題,都容易解決,一旦我知道問題是什麼。首先,__init__方法不包含self.aos_config_prompt - 當我註釋掉我的異常處理代碼時,pexpect異常非常清楚地說明了這一點。其次,如果self.aos_config_prompt看起來像'accelerator(config)#',那麼pexpect會將它編譯爲重新匹配模塊的代碼,然後匹配包含圓括號內容的提示。只需要避開字符串中的圓括號,匹配就可以按照需要進行。

0

我猜想,超時是因爲ssh_to_aos_config()沒有得到所有預計的輸入:調用ssh_to_aos_expsh()很可能工作,而後續調用expect不會。

因此,一個問題是:其中不超時發生?你可以通過引發一個異常來追蹤它,而不是返回self._timeout_error(child)。你發現的位置會指向一個pexpect永遠不會得到的輸入(因此超時),並且你可以在那裏更新你的代碼。

0

如果你得到一個超時那是因爲你沒有得到任何您所期待的琴絃。可能是因爲您收到了錯誤消息,或者您所期望的提示是錯誤的。

啓用日誌記錄看到整個互動 - 在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語句匹配,所以據我所知,這將永遠不會編譯。我認爲這是一個減少&粘貼錯誤,因爲你說你已經運行了代碼。

+0

實際上,調用_ssh_connect時會設置self.root_prompt。由於每個連接到的設備的根提示都不同,我需要動態構建它。 我在_ssh_connect中修正了縮進問題,它只是我粘貼文本的工件。 – 2009-11-14 11:21:19