Search code examples
pythonpython-2.7pexpect

Pexpect not waiting for whole output - Ubuntu


I have a simple script to SSH into a network switch and run commands and save output into a file. It works fine for output that is displayed instantly but when I run "show iproute" it does not capture any output. The reason is when I run same command on switch directly, it thinks for 5-6 seconds, shows bunch of lines and thinks again and shows couple more lines and then ends. It is not waiting properly for whole command to execute that I am having issue fixing:

str_prompt = ' # '
command = "sh iproute"
device_name = "switch1.test.com"

# Spawn SSH session
ssh_command = 'ssh {}@{}'.format(username, device_name)
session = pexpect.spawn(ssh_command, timeout=5)

# Send the password
session.sendline(password)

# Expect the switch prompt (successful login)
expect_index = session.expect([pexpect.TIMEOUT, str_prompt])
# Success
if expect_index == 1:
    # Disable clipaging so that all the output is shown (not in pages) | same as term len 0 in Cisco
    session.sendline('disable clip')
    # Expect the switch prompt if command is successful
    expect_index = session.expect([pexpect.TIMEOUT, str_prompt])

    # Send show iproute command
    session.sendline(command)
    # < This is where it needs to wait >
    #session.expect(pexpect.EOF) - Tried this and wait() but that broke the scipt
    #session.wait()
    # Expect the switch prompt if command is successful
    session.expect(str_prompt)

    # Save output of "sh iproute" to a variable
    output = session.before
    # Save results to a file
    fp = open(host + '-route.txt', "w")
    fp.write(output)
    fp.close()

Here is a sample output. The out put does have "#" but not " # ".

#oa  10.10.10.0/24      10.0.0.1    4    UG-D---um--f- V-BB1 99d:0h:14m:49s
#oa  10.10.20.0/24      10.0.0.1    4    UG-D---um--f- V-BB2 99d:0h:14m:49s
#oa  10.10.30.0/24      10.0.0.1    4    UG-D---um--f- V-BB3 99d:0h:14m:49s
#oa  10.10.40.0/24      10.0.0.1    4    UG-D---um--f- V-BB4 99d:0h:14m:49s
and many more line ....

Any help will be appreciated. Thanks

Edit: I added sleep(60) and that seems to do the trick, but I do not want to use it as I am sending multiple commands and some are super fast. I do not want to wait 1 min for each command, script will take forever to run.


Solution

  • So you need to associate timeout to a commands. The way i do it today is have a xml file format which my code parses, the xml tag will have a attribute for command and another for timeout, another for end_prompt of the command and so on..

    My code reads the command and its timeout and sets the respective variables accordingly before sending the command.

    session.sendline(command) #command is read from a xml file
    session.expect(end_prompt, timeout=int(tmout)) # end_prompt, tmout for the command read form the same file
    

    For your case, if you dont want to parse a file to get command and its related params you can have them as a dictionary in your script and use it

    command_details_dict = { "cmd_details" :[
                                             {'cmd': 'pwd',
                                              'timeout': 5,
                                              },
                                             {'cmd': 'iproute',
                                              'timeout': 60,
                                              }
                                             ]
                           } 
    

    inside the dictionary cmd_details is a list of dictionary so that you can maintain the order of your commands while iterating, each command is a dictionary with relevant details, you can add more keys to the command dictionary like prompts, unique identifier etcc..

    But if you have the time i would suggest to use a config file instead