| |||||||||||
running multiple ssh instances asynchronously? Posted by that_guy (that_guy), 21 July 2003 I'm writing a network monitor script that uses ssh to connect to ~40 machines and retrieve the contents of their routing tables using expect+ route -n. Right now I have a loop that goes through a list of currently available hosts. The problem is that doing this sequentially is very slow- it takes about 7 minutes to finish. Is there some reasonably simple way to run this part of the script on several machines at once in parallel? This is what the fragment of code currently looks like:foreach item $::libextreme::vlans { set ::libextreme::vlan_info($item,ports) [eval ::libextreme::get_vlan_ports [lrange "$item online" 0 end]] foreach thing [::libextreme::get_vlan_hosts $item online] { if {[catch {set ::libextreme::routes($thing) [::libextreme::get_routes $thing online ] } err] } { send_user "something's wrong with $thing\n" } } } get_routes is the procedure that sshs to machine runs 'route -n' and returns a list of routes. I've included it below: proc ::libextreme::get_routes {hostname mode} { if {[string compare $::libextreme::mode online] == 0} { variable prompt set timeout 2 set ipaddr "\[0-9]+\.\[0-9]+\.\[0-9]+\.\[0-9]+" stty -echo spawn ssh $hostname expect "*" if { [string compare $hostname unknown] != 0} { expect -re "\[\n\r\t ]*$prompt(node,$hostname)" } exp_send "su\r" expect "Password:" exp_send "mypassword\r" expect -re "\[\n\r\t ]*$hostname:/home/$user#" exp_send "route -n\r" expect "\n" expect -re ".*Iface\r\n" set num 0 #+\[\t ]\[0-9]\[\t ]\[0-9]\[\t ]\[0-9]\[\t ]\[a-zA-Z0-9]+ set routes {} expect { -re "($ipaddr)\[\t ]*($ipaddr)\[\t ]*($ipaddr)\[\t ]*(\[a-zA-Z]*)\[\t ]*(\[0-9]+)\[\t ]*(\[0-9]+)\[\t ]*(\[0-9]+)(\[a-z 0-9]*)\r\n" { lappend routes $expect_out(buffer) #send_user "row$num: $expect_out(buffer) endrow\n" incr num exp_continue } } Posted by admin (Graham Ellis), 21 July 2003 We had a similar problem in checking out a network of machines for training courses - we want to plug together anything from 2 to 20 machines and have a display come up in seconds to tell us which are there.Solution: * spawn ping processes in a loop * save the spawn_id into an array, and add it to a list too * when all the pings have been started, use the expect command with the -i option to wait for the next line back from any one of the pings * keep repeating the previous step, noting down how many lines of response have come back from each ping This way, all the processes are timing out in parallel rather than serially, which I think is wha you're looking for. Complete code of our program (64 lines, I think, when I last counted) at http://www.wellho.net/cgi-bin/net/sample.pl?which=tkpingle; it also gives you a graphic display through tk to show you the progress ... very pretty too. [Edited to correct typing error in link] Posted by that_guy (that_guy), 22 July 2003 Thanks a lot, I found tkpingle to be a very useful example, I'm retooling my ssh script. I also have a part of the script that uses fping to check all the hosts, but I think I'm going to change it over to use tkpingle. Just so you know, the link above is not functional. [Link corrected, 05:55 - Graham] Posted by that_guy (that_guy), 22 July 2003 hi, just wanted to work things through a bit more- if you don't mind. the script I posted at the top of the page has a lot of sequential expect statements-> i.e. when dealing with one process at a time, first wait for a null character, then wait for a new line, then wait for a prompt, then send command, then wait for prompt,etc. Now that I'm trying to do this for multiple processes by expect -i $idlist I'm not sure how to get the same sort of sequential behaviour, as it stands right now I'm getting weird matching behaviour- I'm sure I just need to think this through a bit more- if you could comment on what I've tried so far I'd greatly appreciate it :cleaning this up... Posted by admin (Graham Ellis), 22 July 2003 Quote:
You won't get the same sort of sequential behaviour - you'll need to "expect -i" for any of the possible sequences (use a regular expression that looks for any possibilities),. When you find which id the result came back from, update an array of state variables as appropriate and loop on the "expect -i". I would only expect to see one "expect -i" in the loop. Posted by that_guy (that_guy), 22 July 2003 I'm currently trying to do something like what I have below. Whenever some pattern arrives I move the responible spawnid into a new "stage" and then only check members of a given stage for a certain pattern. My problem now is that in the last stage, for a given host I need to match several times- there could multiple routes in the routing table. and I need to quit somehow. When dealing with one process, this sequence was in a loop and as soon as I timed out, I would break, because there were no early stages where things would time out. I would greatly appreciate any suggestions as how to get the multiple matches here and be able to quit properly. The lines below are my current final stage-i stage6 -re "($ipaddr)\[\t ]*($ipaddr)\[\t ]*($ipaddr)\[\t ]*(\[a-zA-Z]*)\[\t ]*(\[0-9]+)\[\t ]*(\[0-9]+)\[\t ]*(\[0-9]+)(\[a-z 0-9]*)\r\n" { lappend ::libextreme::routes($backlook($expect_out(spawn_id))) $expect_out(buffer) lappend routes $expect_out(buffer) } Posted by admin (Graham Ellis), 23 July 2003 I think you can probably still time out If you spawn a whole series of sessions off, and each of them only times out when completed, then the one and only situtation when you'll time out is when every one of them has been completed, isn't it? Posted by that_guy (that_guy), 23 July 2003 thanks. I got things working, although one weird thing I noticed is that although I am using the same exact sort of tk popup as in tkpingle, it's highly variable when the toplevel window actually pops up- usually not until all the processes are almost done. I am guessing that maybe spawning ssh is more of a strain than spawning ping, and the computer has trouble redrawing(?)as you can see-- it's just something identical to tkpingle proc ::libextreme::tk_route {systems} { toplevel .route set high [expr [llength $systems] * 32 + 64] wm geometry .route 400x$high foreach system $systems { label .route.la_$system -text $system pack .route.la_$system -expand true -fill x -padx 5 -pady 5 } .route config -background white Posted by admin (Graham Ellis), 23 July 2003 Tk only updates the display when it has nothing else left to do and is waiting for events - this apparently curious behaviour is to avoid it doing huge numbers of redraws as you build up your graphic in the first place, or as you make a series of changes which would cause a huge amount of display activity if the display was amended once for each change.It might be a good idea for you to add in an update idletasks at some point(s) to have it update the screen from time to time. Tkpingle doesn't exhibit the same problem because there's a good gap between returned lines, so it *does* go idle waiting for events quite frequently. This page is a thread posted to the opentalk forum
at www.opentalk.org.uk and
archived here for reference. To jump to the archive index please
follow this link.
|
| ||||||||||
PH: 01144 1225 708225 • FAX: 01144 1225 793803 • EMAIL: info@wellho.net • WEB: http://www.wellho.net • SKYPE: wellho |