2012-06-06 3 views
0

파이썬/Pexpect를 사용하여 여러 라우터에 SSH 세션을 생성합니다. 이 코드는 하나의 라우터에서 작동하지만 session.before의 출력은 일부 라우터와 동기화되지 않으므로 이전 sendline의 출력을 반환합니다. 이것은 빈 줄 (sendline())을 보낼 때 특히 그렇습니다. 누구든지 아이디어가있어? 모든 통찰력은 정말 감사하겠습니다. (내가 그것을 해결할 방법을 기억하려고하고있어) 내가 pexpect와 전에이로 실행했습니다출력이 동기화되기 전에 파이썬/Pexpect

ssh_session.sendline('sh version') 
while (iresult==2): 
    iresult = ssh_session.expect(['>','#','--More--'],timeout=SESSION_TIMEOUT) 
    debug_print("execute_1 " + str(iresult)) 
    debug_print("execute_bef " + ssh_session.before) 
    debug_print("execute_af " + ssh_session.after) 

    thisoutput = ssh_session.before 
    output += thisoutput 

    if(iresult==2): 
     debug_print("exec MORE") 
     ssh_session.send(" ") 
    else: 
     debug_print("exec: end loop") 

for cmd in config_commands: 
    debug_print("------------------------------------------------\n") 
    debug_print ("running command " + cmd.strip() + "\n") 
    iresult=2 
    ssh_session.sendline(cmd.strip()) 
    while (iresult==2): 
     iresult = ssh_session.expect([prompt+">",prompt+"#"," --More-- "],timeout=SESSION_TIMEOUT) 
     thisoutput = ssh_session.before 
     debug_print("execute_1 " + str(iresult)) 
     debug_print("execute_af " + ssh_session.after) 
     debug_print("execute_bef " + thisoutput) 
     thisoutput = ssh_session.before 
     output += thisoutput 

     if(iresult==2): 
      debug_print("exec MORE") 
      ssh_session.send(" ") 
     else: 
      debug_print("exec: end loop") 


I get this: 

logged in 
exec: sh version 
execute_1 1 
execute_bef 
R9 
execute_af # 
exec: end loop 
------------------------------------------------ 

running command config t 

execute_1 1 
execute_af # 
execute_bef sh version 
Cisco IOS Software, 1841 Software (C1841-IPBASEK9-M), Version 15.1(4)M4, RELEASE SOFTWARE (fc1) 
Technical Support: http://www.cisco.com/techsupport... 

답변

1

: 아래

내가보고있는 무슨의 샘플입니다.

반환을 보내고 프롬프트에서 루프를 기다리면 터미널 세션과 다시 동기화 할 수 있습니다. 예상 시간이 초과되면 동기화 된 것을 알게됩니다.

근본 원인은 아마 당신이 것을 다음 중 하나

  • (당신이 출력에 대해 신경 쓰지 않기 때문에) 출력을 생성하는 명령을 실행 기대 일치하지 않고

  • 을 보낼 호출하지만, 해당 출력 중간에 패턴을 예상하고 출력의 끝 부분에 다음 프롬프트를 표시하지 않습니다. 이를 처리하는 한 가지 방법은 기대 패턴을 "(. +) PROMPT"로 변경하는 것입니다. 다음 프롬프트가 나타날 때까지 기다렸다가 보낸 명령의 모든 출력을 캡처합니다 (다음 단계에서 구문 분석 할 수 있음).

+0

아이디어를 다시 동기화 해 주셔서 감사합니다. 추악하다고 생각하지만 저에게는 효과적입니다. – Magentron

0

나는 비슷한 문제에 직면했다. 나는 명령이 화면에 표시되고 송신 명령이 기다리는 것을 시도했다.

난 당신은 당신이 명령 'cmd를'말을 실행하려는 :

session.send(cmd) 
    index = session.expect([cmd, pexpect.TIMEOUT], 1) 
    session.send('\n') 
    index = session.expect([whatever you expect]) 

나를 위해 일했다.

0

이것이 문제의 근원인지 잘 모르겠지만 시도해 볼 가치가 있습니다.

쉘에서 시작하거나 쉘을 시작하는 세션을 생성 할 때 TERM 유형 (vt220, color-xterm 등)의 단점을 처리해야합니다. 커서를 이동하거나 색상을 변경하는 데 사용되는 문자가 표시됩니다. 이 문제는 프롬프트와 함께 나타나기가 거의 확실합니다. 프롬프트를 식별하기 위해 찾고있는 문자열은 색상 변경이 처리되는 방식으로 인해 두 번 나타납니다 (프롬프트가 전송 된 후 백 스페이스 코드가 변경되고 색상이 변경된 후 다시 프롬프트가 전송됩니다). 신속한). 여기

매우 파이썬하지, 추한 해키 보장이 처리 뭔가 및 기능이다 :

import pexpect 

# wait_for_prompt: handle terminal prompt craziness 
# returns either the pexpect.before contents that occurred before the 
# first sighting of the prompt, or returns False if we had a timeout 
# 
def wait_for_prompt(session, wait_for_this, wait_timeout=30): 
    status = session.expect([wait_for_this, pexpect.TIMEOUT, pexpect.EOF], timeout=wait_timeout) 
    if status != 0: 
     print 'ERROR : timeout waiting for "' + wait_for_this + '"' 
     return False 
    before = session.before # this is what we will want to return 
    # now look for and handle any additional sightings of the prompt 
    while True: 
     try: 
      session.expect(wait_for_this, timeout=0.1) 
     except: 
      # we expect a timeout here. All is normal. Move along, Citizen. 
      break # get out of the while loop 
     return before 

s = pexpect.spawn('ssh [email protected]') 
s.expect('password') # yes, we assume that the SSH key is already there 
        # and that we will successfully connect. I'm bad. 
s.sendline('mypasswordisverysecure') # Also assuming the right password 
prompt = 'me$' 
wait_for_prompt(s, prompt) 
s.sendline('df -h') # how full are my disks? 
results = wait_for_prompt(s, prompt) 
if results: 
    print results 
    sys.exit(0) 
else: 
    print 'Misery. You lose.' 
    sys.exit(1) 
0

나는이 오래된 스레드 알고,하지만이 온라인에 대해 많은 것을 발견하지 않았고, 방금이 문제를 해결할 수있는 빠른 해결 방법을 찾았습니다. 또한 pexpect를 사용하여 네트워크 장치 목록을 실행하고 통계를 기록하는 등의 작업을 수행하며 pexpect.spawn.before도 때때로 동기화되지 않습니다. 이것은 어떤 이유로 더 빠르고 더 현대적인 장치에서 자주 발생합니다.

해결책은 각 명령 사이에 빈 캐리지 리턴을 쓰고 .before 변수의 len()을 확인하는 것이 었습니다.너무 작 으면 프롬프트를 캡처했음을 의미합니다. 즉, 실제 ssh 세션 뒤에 적어도 하나의 명령이 있어야 함을 의미합니다. 나는 마침내 캡처 .before 변수까지 자신을 호출하는 재귀 명령으로이를

def new_line(this, iteration): 
    if iteration > 4: 
     return data 
    else: 
     iteration+=1 
     this.expect(":") 
     this.sendline(" \r") 
     data = this.before 
     if len(data) < 50: 
     # The numer 50 was chosen because it should be longer than just the hostname and prompt of the device, but shorter than any actual output 
      data = new_line(this, iteration) 
     return data 

def login(hostname): 
    this = pexpect.spawn("ssh %s" % hostname) 
    stop = this.expect([pexpect.TIMEOUT,pexpect.EOF,":"], timeout=20) 
    if stop == 2: 
     try: 
      this.sendline("\r") 
      this.expect(":") 
      this.sendline("show version\r") 
      version = new_line(this,0) 
      this.expect(":") 
      this.sendline("quit\r") 
      return version 
     except: 
      print 'failed to execute commands' 
      this.kill(0) 
    else: 
     print 'failed to login' 
     this.kill(0) 

: 그런 경우에는, 프로그램은 내가 .before 변수에 원하는 실제 데이터를 이동하는 또 다른 빈 줄을 전송 명령의 출력 또는 자체를 5 번 호출 할 때까지는 단순히 포기합니다.