2009-11-13 3 views
0

아래 클래스는 명령을 실행하고 구성 요소를 업데이트하기 위해 cisco와 같은 장치 인터페이스를 조작하도록 설계되었습니다.pexpect 및 'chained'함수 호출의 문제점

현재로서는 클래스를 인스턴스화하고 ssh_to_aos_expsh 함수를 호출하고 올바른 출력을 얻을 수 있습니다 (예 : 명령이 'show running-config'일 때 구성 가져 오기). 그러나 ssh_to_aos_expsh 함수를 호출하는 ssh_to_aos_config 함수를 호출하면 pexpect 시간 초과 오류가 발생합니다.

내가 ssh_toaos_configssh_to_aos_expsh에 의해 반환 된 객체에 ssh_to_aos_expsh_ssh_connect에 의해 반환합니다 ( _ssh_connect, ssh_to_aos_expshssh_to_aos_config의 '아동')이 pexpect 개체를 비교했는데이 같은 메모리 위치에 나타납니다, 그래서

I pexpect로 오브젝트를 계속 조작 할 수없는 이유가 명확하지 않습니다.

필자는 가장 정교한 파이썬 코더가 아니므로 기능간에 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 (자식)을 반환하는 대신 예외를 발생시켜이를 추적 할 수 있습니다. 당신이 찾은 위치는 pexpect가 결코 얻지 못하는 입력을 가리킬 것이므로 (따라서 타임 아웃), 거기에서 코드를 업데이트 할 수 있습니다.

0

시간 초과가 발생하는 것은 예상 한 문자열이 없기 때문입니다. 대신 오류 메시지가 표시되거나 예상 한 프롬프트가 잘못되었을 수 있습니다.

전체 상호 작용을 보려면 로깅을 활성화하십시오. - pexpect 2.3에서는 파일 객체를 child.logfile 속성에 할당하여 수행됩니다. 그런 다음 정확히 무슨 일이 일어나는지 확인할 수 있습니다. 이전 버전에 대한 문서를 확인하십시오. 변경된 것으로 생각됩니다.

나는 코드에서 몇 가지를주의 사항 :

1) root_prompt은 빈 문자열입니다. 클라이언트에서 아무 것도 반환되지 않은 경우에도 항상 즉시 일치합니다. 이것은 문제의 원인 일 수 있습니다 - 클라이언트가 여전히 다른 입력을 기다리는 동안 ssh connect 함수는 프롬프트를보고 성공적으로 로그인했다고 생각합니다.

2) 코드에 구문 오류가 - ssh_connect 당신이 순서가 : if 문

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가와 일치하지 않기 때문에 AFAIK이 컴파일하지 않을 것입니다. 나는 당신이 코드를 실행하고 있다고 말했기 때문에 그것은 잘라 내기 & 붙여 넣기 오류라고 가정합니다.

+0

사실, _ssh_connect가 호출되면 self.root_prompt가 설정됩니다. 연결되는 각 장치마다 루트 프롬프트가 다르므로 동적으로 빌드해야합니다. _ssh_connect에 들여 쓰기 문제가 수정되었습니다. 텍스트를 붙여 넣은 방법의 인공물이었습니다. –