My brain is fried, and I can't think of how to do this (sorry if I don't
explain this well)
I'm creating a bunch of telnet connections for a single user, and logging
that user into each connection. Then I have a loop that prompts for a
command and sends that command to each of the connections (i.e. you can
issue a single command on multiple machines). I usually want to loop for
each host, but sometimes I want something to execute only once. I'd like
not to have to test within the loop for what the command is, I'd rather be
able to just pass it along. I'm sure this is easy, but I can't think of a
good way right now.
# create connections
user = User.new('abheww6', 'secret')
['orion', 'oscar'].each do |host|
Connection.new({'Host'=>host}, user)
end
# Connection.currentConnections is an accessor to a class variable
# @@currentConnections = {}
# every time the Connection.initialize is called we push self onto it
# login to each
Connection.currentConnections[user].each do |con|
con.loginOnConnection
end
begin
while true
print "Enter command: "
cmd = $stdin.readline.chomp
#Connection.currentConnections[user].each do |con|
foo = Connection.currentConnections[user].dup
foo.each do |con|
con.executeCmd(cmd) {|c| puts c}
# If 'cmd' looks like !LOGIN(somemachine), I want
# to create that connection to act on in the future
# but because I'm in a loop, it logs into that machine
# once for every host that I'm currently acting on. If I
# don't dup the @@currentConnections (above: foo =)
# it adds the object, has that one to loop on, so it
# does it again ad infinitum. I can't think of how I
# can add the connection once and be done with it.
#con.executeCmd("!LOGIN(rana)") {|c| puts c}
end
end
rescue Interrupt, EOFError
puts
Connection.currentConnections[user].each do |con|
con.logoffConnection
end
end
-- WARNING: full code below for those who need more context (this isn't
finished, be gentle ;)
require 'net/telnet'
module Net
class Telnet
def to_s
@options['Host']
end
end
end
module SuperTelnet
class User
@@currentUsers = []
attr_accessor :username, :passwd, :suuser, :supasswd
def initialize(user, pass)
@username = user
@passwd = pass
@@currentUsers << self
end
def User.currentUsers
@@currentUsers
end
end
class Connection
@@currentConnections = {}
def initialize(aHash, userObj)
@conOptions = aHash
@thisUser = userObj
raise ArgumentError if not @thisUser.kind_of? SuperTelnet::User
if not @@currentConnections.has_key? @thisUser
@@currentConnections[@thisUser] = []
end
if not @conOptions.has_key? 'Prompt'
@conOptions['Prompt'] = Regexp.new('[#$%>] \z', false, 'n')
end
if not @conOptions.has_key? 'Timeout'
@conOptions['Timeout'] = 10
end
if not @conOptions.has_key? 'Port'
@conOptions['Port'] = 23
end
@thisConnection = Net::Telnet.new(@conOptions)
@@currentConnections[@thisUser] << self
end
def Connection.currentConnections
@@currentConnections
end
#def method_missing(methodId)
# executeCmd(self.instance_eval(methodId.id2name)) do |c|
# yield c if block_given?
# end
#end
def loginOnConnection
@thisConnection.login(@thisUser.username, @thisUser.passwd)
end
def logoffConnection
@@currentConnections[@thisUser].delete(self)
@thisConnection.close
end
def switchUser(suuser, supasswd)
tmpHash = @conOptions
tmpHash['String'] = "su - #{suuser}"
tmpHash['Match'] = /[pP]assword:/
@thisConnection.cmd(tmpHash) do |c| yield c if block_given? end
tmpHash['String'] = supasswd
tmpHash['Match'] = @conOptions['Prompt']
@thisConnection.cmd(tmpHash) do |c| yield c if block_given? end
end
def executeCmd(cmd)
output = case cmd
when /^!(.*)/
executeAsInternalCmd($1)
when /^\?(.*)/
runCmdConditionally($1)
else
runCmdOnConnection(cmd)
end
if output and not output.empty? and block_given?
yield "\n#{@thisConnection}:\n#{output}\n\n"
end
end
private
def runCmdOnConnection(cmd)
output = []
@thisConnection.cmd({
'String' => cmd,
'Match' => /.+ \z/n,
'Timeout' => false
}) do |c|
if c.chomp != cmd
output << c
end
end
output
end
def runCmdConditionally(cmd)
output = []
case cmd
when /on\s*\((.*)\)\s+(.*)/
args = $1.split
args.each do |arg|
arg == @thisConnection.to_s and
output << runCmdOnConnection($2)
end
else
raise ArgumentError, "No such command: #{cmd}"
end
output
end
def executeAsInternalCmd(cmd)
allowedCommands = ['SU', 'LOGIN', 'LOGOFF', 'HELP']
seen = false
checker, *args = cmd.gsub(/(\w+)\s*\((.*)\)/, '\1 \2').split
raise FormatError, "Bad command format: #{cmd}" if not checker
allowedCommands.each do |thisCmd|
seen = true if thisCmd =~ checker
end
raise ArgumentError, "No such command: #{cmd}" if not seen
case checker
when 'SU'
user, pass = args
switchUser(user, pass)
when 'LOGIN'
args.each do |arg|
Connection.new({'Host' => arg}, @thisUser).
loginOnConnection
end
nil
when 'LOGOFF'
args.each do |arg|
logoffConnection if @thisConnection.to_s == arg
end
nil
when 'HELP'
puts "this is help"
else
raise ArgumentError, "No such command: #{cmd}"
end
end
end
end
if __FILE__ == $0
include SuperTelnet
user = User.new('abheww6', 'secret')
['orion', 'oscar'].each do |host|
Connection.new({'Host'=>host}, user)
end
Connection.currentConnections[user].each do |con|
con.loginOnConnection
end
#def foo
# "ls -la /"
#end
begin
while true
print "Enter command: "
cmd = $stdin.readline.chomp
#Connection.currentConnections[user].each do |con|
foo = Connection.currentConnections[user].dup
foo.each do |con|
con.executeCmd(cmd) {|c| puts c}
#con.foo {|c| puts c}
#con.executeCmd("ls") {|c| puts c}
#con.executeCmd("?on(orion) ls -la") {|c| puts c}
#con.executeCmd("!SU(root secret)") {|c| puts c}
#con.executeCmd("!LOGIN(rana)") {|c| puts c}
#con.executeCmd("ls") {|c| puts c}
#con.executeCmd("whoami") {|c| puts c}
end
end
rescue Interrupt, EOFError
puts
Connection.currentConnections[user].each do |con|
con.logoffConnection
end
end
end
_________________________________________________________________
Get your FREE download of MSN Explorer at http://explorer.msn.com