Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Re^2: Off Topic: Looking for good Expect scripts

by 5mi11er (Deacon)
on Jun 27, 2013 at 22:31 UTC ( #1041114=note: print w/ replies, xml ) Need Help??


in reply to Re: Off Topic: Looking for good Expect scripts
in thread Off Topic: Looking for good Expect scripts

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


Comment on Re^2: Off Topic: Looking for good Expect scripts
Download Code
Re^3: Off Topic: Looking for good Expect scripts
by salva (Monsignor) on Jun 28, 2013 at 08:05 UTC
    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.

      Like what?

      I'll give you it's possible to use ssl key authentication for automatically logging into cisco devices, but that's not an option via telnet, and if you've got more than 600 devices that you don't remember which small subset are still on old enough code they don't yet do SSH, this can come in handy.

      When you're dealing with hundreds or thousands of devices and need to make a small change to a large number of them, there's no way to accomplish that without using something like expect; at least I don't know of one now. If you do, please enlighten.

      -Scott

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (5)
As of 2014-11-29 05:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My preferred Perl binaries come from:














    Results (203 votes), past polls