From: "Henderson, Michael D" Date: 2002-09-18T03:09:26+09:00 Subject: Net/Telnet Script Tuning question I've modified an expect script to reset passwords for batch accounts into a ruby script. Our sysadmin has them expire every month, so we change them to a temporary value, then change them right back. The ruby script works and looks neat, but it is much slower than the expect script. I was hoping that you might have some tips on speeding it up. I'm pretty sure that I'm not using net/telnet to it's fullest. Usage is simple, chgpass.rb [test|prod], the flag indicates where we're changing (frodo being test system, gandalf being production). Thanks, Mike Henderson #! /usr/bin/env ruby ##################################################################### # # To maintain, search for arrUsers.append. Update the list of append # statements to contain the host, user, password you're working with # require 'net/telnet' ##################################################################### # # # class UserAccount def initialize(host, user, pass) @host = host @user = user @pass = pass @tn = nil puts puts " info: #{__LINE__} #{@host} #{@user} #{@pass}" puts # # can change if you're testing and don't wish to really do this # @cmdPassword = 'passwd' end def Close @tn.close if @tn puts puts "logged off" puts end def Login # # attempt to connect to the host # begin @tn = Net::Telnet.new( {'Host' => @host, 'Waittime' => 0, 'Timeout' => 15, 'Debug_Log' => true} ) { |str| print str } @tn.login(@user, @pass) { |str| print str } rescue raise end end def ChangePassword(oldPassWord, newPassWord) # #/userhome/mdhender/src/mdh/spect # mdhender@zinc > passwd # @tn.puts @cmdPassword # #ksh: passwd: not found # begin @tn.waitfor("Match" => /not found|denied/, "Timeout" => 3) { |str| print str } puts puts "error: #{__LINE__}: invalid command '#{@cmdPassword}' on host '#{@host}" puts return false rescue TimeoutError # # wait did not find what it wanted to find. that is good in this case # rescue puts puts "error: #{__LINE__}: Unknown Error" puts raise end # #/bin/passwd: Permission denied # begin @tn.waitfor("Match" => /Permission denied/, "Timeout" => 3) { |str| print str } puts puts "error: #{__LINE__}: invalid command '#{@cmdPassword}' on host '#{@host}" puts return false rescue TimeoutError # # wait did not find what it wanted to find. that is good in this case # rescue puts puts "error: #{__LINE__}: Unknown Error" puts raise end # #passwd: Changing password for mdhender #Enter login password: # @tn.puts oldPassWord # #passwd(SYSTEM): Sorry, wrong passwd #Permission denied # begin @tn.waitfor("Match" => /SYSTEM/, "Timeout" => 3) { |str| print str } puts puts "error: #{__LINE__}: invalid password" puts return false rescue TimeoutError # # wait did not find what it wanted to find. that is good in this case # rescue puts puts "error: #{__LINE__}: Unknown Error" puts raise end # #New password: # @tn.puts newPassWord # #Re-enter new password: # @tn.waitfor(/password:/) { |str| print str } @tn.puts newPassWord # #passwd(SYSTEM): They don't match; try again. #passwd(SYSTEM): Password too short - must be at least 6 characters. #passwd(SYSTEM): Too many failures - try later. #New password: # # #passwd (SYSTEM): passwd successfully changed for mdhender # @tn.waitfor(/passwd successfully changed/) { |str| print str } return true # #/userhome/mdhender/src/mdh/spect # mdhender@zinc > # end def Reset begin self.Login rescue TimeoutError # # unable to log in # return " failed: #{@user}@#{@host} -- invalid password #{@pass}" rescue puts puts "error: #{__LINE__}: Unknown Error" puts raise end # # use a temporary (but known) password for the update # if !ChangePassword(@pass, 'tmpWrd12') puts puts "error: #{__LINE__}: unable to baboozle password for #{@user}@#{@host}" puts return " failed: #{@user}@#{@host}" else if !ChangePassword('tmpWrd12', @pass) puts puts "error: #{__LINE__}: unable to reset password for #{@user}@#{@host}" puts "error: #{__LINE__}: #{@user}@#{@host} password is 'tmpWrd12' and is corrupted" puts return " FAILED: #{@user}@#{@host} -- corrupted -- unix01" end return "succeed: #{@user}@#{@host}" end end end ##################################################################### # # create an array to hold the list of user account information # class UserList def initialize @users = Array.new @results = Array.new end def append(host, user, password) @users.push([ host, user, password ]) end def [](key) return @users[key] if key.kind_of?(Integer) return @users.find { |aUser| aUser.name = key } end def each @users.each { |anEntry| host = anEntry[0] user = anEntry[1] pass = anEntry[2] yield host, user, pass } end def sort @users.sort! end def push(str) @results.push(str) end def Results puts puts @results puts end end arrUsers = UserList.new ##################################################################### # # specify the accounts to work with # # - format is host_______ user__________ password______ # arrUsers.append( 'frodo', 'hobbit', 'daRing@' ) arrUsers.append( 'gandalf', 'greyone', 'eag1e' ) ##################################################################### # # sort the users array to make output look nicer # arrUsers.sort ##################################################################### # # attempt to reset the password for each user in the array # jArgs = ARGV.dup if jArgs while thisArg = jArgs.shift do if thisArg == "test" arrUsers.each { |host, user, pass| begin if host =~ /frodo|gandalf/ acct = UserAccount.new(host, user, pass) arrUsers.push(acct.Reset) end ensure if acct acct.Close end end } arrUsers.Results end if thisArg == "prod" arrUsers.each { |host, user, pass| begin if host =~ /frodo|gandalf/ acct = UserAccount.new(host, user, pass) arrUsers.push(acct.Reset) end ensure if acct acct.Close end end } arrUsers.Results end end end