Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Off Topic: Looking for good Expect scripts

by 5mi11er (Deacon)
on Jun 26, 2013 at 19:25 UTC ( #1040834=perlquestion: print w/ replies, xml ) Need Help??
5mi11er has asked for the wisdom of the Perl Monks concerning the following question:

Hey all, sorry for being a bit off topic, but with this community being pretty well rounded, I figured I would have a decent shot at finding a pointer or two.

So, over the period of 10 years or so, I've been developing a suite of Perl driven Expect scripts used to backup various vendors' routers, switches, firewalls, etc. I've managed to hone them to the point where, they're what I would consider at least beginning to be worthy of "enterprise" type status.

So, I went off googling last week to find, well, something. An expect community, a loose collection of expect scripts at sourceforge, blogs that had lots of expect posts, maybe some decent examples of resilient or at least some error checking expect scripts, and essentially found nothing. Sure, I found a few mentions of expect, there's the "repository" of example scripts that comes with expect. There are a few scripts to be found dealing with backing up cisco devices, but they are very simplistic. Blech.

Can anyone out there point me toward any sites/people/repositories/blogs that deal with more advanced expect scripts?

-Scott

Comment on Off Topic: Looking for good Expect scripts
Re: Off Topic: Looking for good Expect scripts
by salva (Monsignor) on Jun 27, 2013 at 07:39 UTC
    There are few scenarios where Expect (or any of its TCL or Python siblings) is the right tool to use. Interacting with a shell in a reliable way is quite hard and laborious.

    Nowadays, most devices support running single commands through SSH or, at least, support SSH2 that allows to run several independent, short shell sessions over the same connection.

      True, interacting with a shell reliably is not simple, but neither are many other tasks. It's taken many years of small incremental improvements to get where it is today.

      # #!/usr/bin/expect -f (include this file, don't run it) # Login and logout expect procedures for Cisco SSH or telnet access # # written by Scott L. Miller # # Last modified: # 6/15/2013 By Scott L. Miller # ###################################################################### +# # Handle the login & logout procedures # # login will return the prompt string if successful # # The calling script expects return codes of 2 or less to mean the # login was unsuccessful, and 3 or more if at least the login was # successful but there were other errors. ###################################################################### +# proc connect_login { hostaddr user } { global logfile procid expect_out spawn_id set try_telnet 0 spawn /usr/bin/ssh -l $user $hostaddr expect { -gl "timeout" { puts $logfile "Connection t +imed out"; exit 1 } "timed out" { puts $logfile "Connection tim +ed out"; exit 1 } "Connection refused" { puts $logfile "Connectio +n refused ssh"; set try_telnet 1 } "uthentication failed" { puts $logfile "SSH Aut +hentication failed"; exit 1 } -re "authenticity of host .* can't be established" { expect { "connecting (yes/no)" { send "yes\r" } } } "REMOTE HOST IDENTIFICATION HAS CHANGED" { expect { -re "(Offending key \[^\r]*)" { puts $logfile "Host SSH key has changed, $expect_o +ut(1,string)"; } } exit 1 } -notransfer "assword:" { } default { puts $logfile "expect timed o +ut ssh"; exit 2 } } if { $try_telnet > 0 } { set pstr [login_telnet $hostaddr $user] } else { set procid $spawn_id catch { login_ssh } pstr } return $pstr } proc login_ssh {} { global logfile procid ropwd rwpwd expect_out spawn_id #set spawn_id $procid expect { -gl "timeout" { puts $logfile "Connection t +imed out"; exit 1 } "timed out" { puts $logfile "Connection tim +ed out"; exit 1 } "Connection refused" { puts $logfile "Connectio +n refused"; exit 1 } "assword:" { send "$ropwd\r" } default { puts $logfile "expect timed o +ut ssh login"; exit 2 } } expect { "Permission denied" { puts $logfile "Login inco +rrect"; exit 1 } "assword:" { puts $logfile "Login incorrect +"; exit 1 } #attempt to match empty line between password prompt and cisco + command prompt #"\r\n\r\n" { } "\r\n" { } "available commands.\r\n" { } default { puts $logfile "expect timed o +ut ssh passwd"; exit 2 } } catch { get_prompt_and_enable } pstr return $pstr } proc login_telnet { hostaddr user } { global logfile ropwd rwpwd expect_out spawn_id spawn telnet $hostaddr expect { "timeout" { puts $logfile "Connection timed + out"; exit 1 } "timed out" { puts $logfile "Connection tim +ed out"; exit 1 } "Connection refused" { puts $logfile "Connectio +n refused telnet"; exit 1 } "sername:" { send "$user\r" } default { puts $logfile "Connection tim +ed out"; exit 2 } } set procid $spawn_id expect { "assword:" { send "$ropwd\r" } default { puts $logfile "expect timed o +ut waiting for telnet password:"; exit 2 } } expect { "assword:" { puts $logfile "Login incorrect +"; exit 1 } "Authentication failed" { puts $logfile "Login +incorrect"; exit 1 } -notransfer -re "(>|#)" { } default { puts $logfile "expect timed o +ut after telnet password"; exit 2 } } catch { get_prompt_and_enable } pstr return $pstr } proc get_prompt_and_enable {} { global logfile procid rwpwd expect_out spawn_id expect { "assword:" { puts $logfile "Login incorrect +"; exit 1 } -re "(\[a-zA-Z0-9_@\\-: ]*)(>|#)" { #### grab the prompt string to simplify prompt recognition & he +lp eliminate false positives set pstr $expect_out(1,string) set plvl $expect_out(2,string) #yeah, the bare '>' below is correct, but I don't like the + way it looks either if { [string equal $plvl >] } { send "enable\r" expect { "assword:" { send "$rwpwd\r" } default { puts $logfile "ex +pect timed out during enable"; exit 2 } } expect { "Access denied" { puts $logfile + "Enable Login incorrect"; exit 1 } -notransfer "[set pstr]#" { } default { puts $logfile "ex +pect timed out after enable passwd"; exit 2 } } } send "\r" } default { puts $logfile "expect timed o +ut while identifying prompt string"; exit 2 } } expect { -notransfer "[set pstr]#" { } default { puts $logfile "expect timed o +ut after enable mode"; exit 3 } } return $pstr } ###################################################################### +### # remember, all the expect pre- and post- tests are still active, # That's why we need the "global ... " statement ###################################################################### +### proc logout {} { global pstr logfile lastcmd errorcount expect_after { #The work is done, we're just trying to shutdown cleanly, If t +his #shutdown attempt is ALL that fails, there's no sense in sayin +g the #operations failed. Unless of course the operations did fail.. +. default { puts $logfile "expect timed out after \'$lastcmd\', exitin +g with $errorcount status" exit $errorcount } } expect "[set pstr]#" { send "exit\r" } expect { "\r\n" { close } } wait; } # # vim:ai:ts=8:sw=8
      -Scott
        True, interacting with a shell reliably is not simple, but neither are many other tasks

        The point is that there are other ways to accomplish what you are doing here that are actually reliable and simple.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1040834]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (10)
As of 2014-09-23 18:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (239 votes), past polls