diff options
author | Saku Ytti <saku@ytti.fi> | 2013-05-01 13:45:02 +0300 |
---|---|---|
committer | Saku Ytti <saku@ytti.fi> | 2013-05-01 14:06:44 +0300 |
commit | c252a589b6b0274a17bfe40db3fd57ebeea3beb8 (patch) | |
tree | 0115a10db0f37506e72aaf4a873aeea93734f6ab /lib/oxidized/input/telnet.rb | |
parent | 387b725fcd248d052cfe68da97f03192959ad6a4 (diff) |
Add Model#expect, support block at post/pre config
Now we can deal with pager and additional PW prompts, such as 'enable'
Examples in IOS model how to use.
The Telnet implementation is particularly fugly, I just need one line in
'waitfor' to handle pager while waiting for prompt, but couldn't figure
out clean way to do it, so needed to rewrit whole Telnet#waitfor just to
add that line.
Diffstat (limited to 'lib/oxidized/input/telnet.rb')
-rw-r--r-- | lib/oxidized/input/telnet.rb | 95 |
1 files changed, 93 insertions, 2 deletions
diff --git a/lib/oxidized/input/telnet.rb b/lib/oxidized/input/telnet.rb index 0ec08f9..c1afde2 100644 --- a/lib/oxidized/input/telnet.rb +++ b/lib/oxidized/input/telnet.rb @@ -10,7 +10,8 @@ module Oxidized @timeout = CFG.timeout @node.model.cfg['telnet'].each { |cb| instance_exec &cb } begin - @telnet = Net::Telnet.new 'Host' => @node.ip, 'Waittime' => @timeout + @telnet = Net::Telnet.new 'Host' => @node.ip, 'Waittime' => @timeout, + 'Model' => @node.model expect username @telnet.puts @node.auth[:username] expect password @@ -32,6 +33,10 @@ module Oxidized end end + def send data + @telnet.write data + end + private def expect re @@ -40,7 +45,7 @@ module Oxidized def disconnect begin - @pre_logout.each { |command| cmd(command, nil) } + disconnect_cli @telnet.close rescue Errno::ECONNRESET end @@ -56,3 +61,89 @@ module Oxidized end end + + +class Net::Telnet + ## FIXME: we just need 'line = model.expects line' to handle pager + ## how to do this, without redefining the whole damn thing + def waitfor(options) # :yield: recvdata + time_out = @options["Timeout"] + waittime = @options["Waittime"] + fail_eof = @options["FailEOF"] + model = @options["Model"] + + if options.kind_of?(Hash) + prompt = if options.has_key?("Match") + options["Match"] + elsif options.has_key?("Prompt") + options["Prompt"] + elsif options.has_key?("String") + Regexp.new( Regexp.quote(options["String"]) ) + end + time_out = options["Timeout"] if options.has_key?("Timeout") + waittime = options["Waittime"] if options.has_key?("Waittime") + fail_eof = options["FailEOF"] if options.has_key?("FailEOF") + else + prompt = options + end + + if time_out == false + time_out = nil + end + + line = '' + buf = '' + rest = '' + until(prompt === line and not IO::select([@sock], nil, nil, waittime)) + unless IO::select([@sock], nil, nil, time_out) + raise Net::ReadTimeout, "timed out while waiting for more data" + end + begin + c = @sock.readpartial(1024 * 1024) + @dumplog.log_dump('<', c) if @options.has_key?("Dump_log") + if @options["Telnetmode"] + c = rest + c + if Integer(c.rindex(/#{IAC}#{SE}/no) || 0) < + Integer(c.rindex(/#{IAC}#{SB}/no) || 0) + buf = preprocess(c[0 ... c.rindex(/#{IAC}#{SB}/no)]) + rest = c[c.rindex(/#{IAC}#{SB}/no) .. -1] + elsif pt = c.rindex(/#{IAC}[^#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]?\z/no) || + c.rindex(/\r\z/no) + buf = preprocess(c[0 ... pt]) + rest = c[pt .. -1] + else + buf = preprocess(c) + rest = '' + end + else + # Not Telnetmode. + # + # We cannot use preprocess() on this data, because that + # method makes some Telnetmode-specific assumptions. + buf = rest + c + rest = '' + unless @options["Binmode"] + if pt = buf.rindex(/\r\z/no) + buf = buf[0 ... pt] + rest = buf[pt .. -1] + end + buf.gsub!(/#{EOL}/no, "\n") + end + end + @log.print(buf) if @options.has_key?("Output_log") + line += buf + line = model.expects line + line = yield line if block_given? + yield buf if block_given? + rescue EOFError # End of file reached + raise if fail_eof + if line == '' + line = nil + yield nil if block_given? + end + break + end + end + line + end +end |