Ruby & Telnet & Cisco

Ruby friends,

Is there any approach similar to perl's Net:Telnet:Cisco [1] in ruby?
Has anyone nice experiences in this mix?

I usually interact with my routers/switches with perl but I would like
to switch to ruby :wink:

Regards,

Pablo

[1] http://search.cpan.org/~joshua/Net-Telnet-Cisco-1.10/Cisco.pm

Not that I'm aware of. But if you discover something please let me know -
I'm going to have to do this myself in the next few weeks too.

I was planning just to use plain Net::Telnet, which I think is good enough
for what I need. I was also planning to try to make a wrapper for Net::SSH
to make it provide an IO object that can be passed into Net::Telnet.

Regards,

Brian.

路路路

On Sat, Mar 31, 2007 at 12:48:22AM +0900, Pablo Zorzoli wrote:

Is there any approach similar to perl's Net:Telnet:Cisco [1] in ruby?
Has anyone nice experiences in this mix?

Pablo Zorzoli wrote:

Ruby friends,

Is there any approach similar to perl's Net:Telnet:Cisco [1] in ruby?
Has anyone nice experiences in this mix?

I usually interact with my routers/switches with perl but I would like
to switch to ruby :wink:

Regards,

Pablo

[1] Net::Telnet::Cisco - interact with a Cisco router - metacpan.org

I don't know what perl's Net:Telnet:Cisco does, but I wrote this script
that allows me to run commands on our Cisco fiber switches without
having to login.

I'm not sure this is what your looking for but I hope it helps out.
I can provide the 'hec_getopts' module if you're intrested.

Hector

require 'pty'
require 'expect'
require 'hec_getopts'

# Global variables
$expect_verbose = true # Writes all characters read from the I/O
stram to STDOUT.

class MyExpect
  def initialize(switch='cisco1')
    @switch = switch
    STDOUT.sync = true
    STDERR.sync = true
    @passwd =
File.new("/root/.system/.fraces/#{@switch}_dm").gets.chomp
    @uid =
File.new("/root/.system/.fraces/#{@switch}_dm_user").gets.chomp
  end

  # This is where RubyExpect takes over
  def showInfo(cmd)
    PTY.spawn("ssh #{@uid}@#{@switch}") do |r_f, w_f, pid| # Spaw a
process and create filehandles to it's input/output
      w_f.sync = true
      r_f.expect(/^password:/io) { w_f.puts @passwd }
      r_f.expect(/(switch\d+|1301)#\s+/io) { w_f.puts "terminal length
0\n" } # Make terminal length infinite!!!

      case cmd
        when /^rc$/
          r_f.expect(/(switch\d+|1301)#\s+/io) { w_f.puts "show
running-config\n" }
        when /^sc$/
          r_f.expect(/(switch\d+|1301)#\s+/io) { w_f.puts "show
startup-config\n" }
        when /^az$/
          r_f.expect(/(switch\d+|1301)#\s+/io) { w_f.puts "show zoneset
active\n" }
        when /^zs$/
          r_f.expect(/(switch\d+|1301)#\s+/io) { w_f.puts "show
zoneset\n" }
        when /^fl$/
          r_f.expect(/(switch\d+|1301)#\s+/io) { w_f.puts "show flogi
database\n" }
        when /^pi$/
          r_f.expect(/(switch\d+|1301)#\s+/io) { w_f.puts "show port
internal info\n" }
        when /^td$/
          r_f.expect(/(switch\d+|1301)#\s+/io) { w_f.puts "show tech
detail\n" }
        else
          r_f.expect(/(switch\d+|1301)#\s+/io) { w_f.puts "#{cmd}\n" }
      end
      r_f.expect(/(switch\d+|1301)#\s+/io) { w_f.puts "exit\n" }
      puts
    end
  end
end

class Help
  def showHelp(help)
    help_string = <<-EOHelp

  #{$PROG_NAME} lists configuration information for the Cisco directors.
  Syntax: #{$PROG_NAME} [-s[cisco1|cisco2|tcisco1|tcisco2]] <command>

-Options-

  -s cisco_switch_name
    Selects a Cisco switch to pull information from(Cisco1, Cisco2,
tcisco1, tcisco2).
    If no switch number is specified on the command-line, Cisco1 is the
default.

[ Commands: ]
  rc - Shows running-config
  az - Shows active zone
  zs - Shows zoneset
  fl - Shows flogi database
  pc <slot> <port> - Shows port config for <slot> and <port>
  td - Show tech detail

[ Examples: ]
  #{$PROG_NAME} rc
    Displays currently running configuration for Cisco1

  #{$PROG_NAME} -scisco2 az
    Displays currently active zone for Cisco2
EOHelp

    (help == '?' or help == 'h') and puts(help_string)
    help and exit(0)
  end
end

$PROG_NAME = File.basename($0).freeze

# ? = help, h = help, s = switch_name
cmdln = GetOpts.new('?hs:')
Help.new.showHelp(cmdln.orHas?('?', 'h'))
cmdln.has?('s') ? exp = MyExpect.new(cmdln.has?('s')) : exp =
MyExpect.new()
#cmdln.argv[0] ? exp.showInfo(cmdln.argv[0], cmdln.argv[1],
cmdln.argv[2]) : Help.new.showHelp('?')
cmdln.argv[0] ? exp.showInfo("#{cmdln.argv.join(' ')}") :
Help.new.showHelp('?')

路路路

--
Posted via http://www.ruby-forum.com/\.

> Is there any approach similar to perl's Net:Telnet:Cisco [1] in ruby?
> Has anyone nice experiences in this mix?

Not that I'm aware of. But if you discover something please let me know -
I'm going to have to do this myself in the next few weeks too.

I was planning just to use plain Net::Telnet, which I think is good enough
for what I need.

Please kindly let me know about this, I was trying to do this with
Catalyst 29xx series Switches and a 2600 router, no luck so far, I
guess the prompt, timeout selection is quite tricky :frowning:

Cheers
Robert

路路路

On 3/31/07, Brian Candler <B.Candler@pobox.com> wrote:

On Sat, Mar 31, 2007 at 12:48:22AM +0900, Pablo Zorzoli wrote:
I was also planning to try to make a wrapper for Net::SSH
to make it provide an IO object that can be passed into Net::Telnet.

Regards,

Brian.

--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

The best documentation is the source, /usr/lib/ruby/1.8/net/telnet.rb

Make sure you call your code with a debug block, e.g. (untested)

   n = Net::Telnet(...)
   blk = proc { |str| $stderr << str }
   n.login("user", "password", &blk)
   n.cmd("show users", &blk)

By adding &blk to all of the Net::Telnet methods, you'll get debugging
output to the screen and you can see how far it's getting.

IIRC, the default regexp for a prompt looks for '# ' and '> ' (i.e. with a
trailing space). Typical Cisco prompt is 'router>' without the trailing
space. So easy enough to fix: just pass in a suitable prompt regexp.

Brian.

路路路

On Sat, Mar 31, 2007 at 10:40:15PM +0900, Robert Dober wrote:

>Not that I'm aware of. But if you discover something please let me know -
>I'm going to have to do this myself in the next few weeks too.
>
>I was planning just to use plain Net::Telnet, which I think is good enough
>for what I need.
Please kindly let me know about this, I was trying to do this with
Catalyst 29xx series Switches and a 2600 router, no luck so far, I
guess the prompt, timeout selection is quite tricky :frowning:

I don't know perl's cisco library, but this (see attached) is what I wrote to
send commands to cisco routers and switches or fetch some values.

To get it's running config for example I do this:

ciscotelnet.rb (1.29 KB)

路路路

------------------------------------
require 'ciscotelnet'

c = CiscoTelnet.new("Host" => '10.253.1.8',
                    "Password" => "users-password",
                     "Enable" => "enable-password",
                     "User" => "martin")

c.open
c.login
c.enable
c.cmd "terminal length 0"
puts c.cmd("show run", 20)
------------------------------------

Martin

On Saturday 31 March 2007 13:40:15 Robert Dober wrote:

On 3/31/07, Brian Candler <B.Candler@pobox.com> wrote:
> On Sat, Mar 31, 2007 at 12:48:22AM +0900, Pablo Zorzoli wrote:
> > Is there any approach similar to perl's Net:Telnet:Cisco [1] in ruby?
> > Has anyone nice experiences in this mix?
>
> Not that I'm aware of. But if you discover something please let me know -
> I'm going to have to do this myself in the next few weeks too.
>
> I was planning just to use plain Net::Telnet, which I think is good
> enough for what I need.

Please kindly let me know about this, I was trying to do this with
Catalyst 29xx series Switches and a 2600 router, no luck so far, I
guess the prompt, timeout selection is quite tricky :frowning:

Cheers
Robert

>I was also planning to try to make a wrapper for Net::SSH
> to make it provide an IO object that can be passed into Net::Telnet.
>
> Regards,
>
> Brian.

> >Not that I'm aware of. But if you discover something please let me know -
> >I'm going to have to do this myself in the next few weeks too.
> >
> >I was planning just to use plain Net::Telnet, which I think is good enough
> >for what I need.
> Please kindly let me know about this, I was trying to do this with
> Catalyst 29xx series Switches and a 2600 router, no luck so far, I
> guess the prompt, timeout selection is quite tricky :frowning:

The best documentation is the source, /usr/lib/ruby/1.8/net/telnet.rb

Make sure you call your code with a debug block, e.g. (untested)

   n = Net::Telnet(...)
   blk = proc { |str| $stderr << str }
   n.login("user", "password", &blk)
   n.cmd("show users", &blk)

By adding &blk to all of the Net::Telnet methods, you'll get debugging
output to the screen and you can see how far it's getting.

IIRC, the default regexp for a prompt looks for '# ' and '> ' (i.e. with a
trailing space). Typical Cisco prompt is 'router>' without the trailing
space. So easy enough to fix: just pass in a suitable prompt regexp.

Brian.

Brian that is sound advice, but actually the problem is more or less
the subtle details about the Cisco interface(1), like getting rid of
the '---More---' or nonstandard login without user.

I think that's why there are some modules around in other languages. I
think it is a good possibility to share some findings and I might have
a look at the Perl module some of these days.

Cheers Robert

(1) used net/telnet for some remote control of old Unix systems
without ssh quite often, the code is really easy to factorize, maybe
it is too for Cisco, but given the complexity of the Cisco OS I doubt
it :(, So the problem is not within Ruby but within Cisco.

路路路

On 4/1/07, Brian Candler <B.Candler@pobox.com> wrote:

On Sat, Mar 31, 2007 at 10:40:15PM +0900, Robert Dober wrote:

--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

If all the devices are under your control, it's probably reasonable to
standardise on "login local" so that you get prompted for both username and
password (since this can then be extended to RADIUS/TACACS without changing
the interaction)

As for the ---More--- prompt, simply send "term length 0" as the first
command after logging in and that problem goes away :slight_smile:

Regards,

Brian.

路路路

On Sun, Apr 01, 2007 at 04:58:22PM +0900, Robert Dober wrote:

Brian that is sound advice, but actually the problem is more or less
the subtle details about the Cisco interface(1), like getting rid of
the '---More---' or nonstandard login without user.