cisco 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,73 @@
1
+ Ruby-Cisco
2
+ ==========
3
+ This tool aims to provide transport-flexible functionality, for easy communication
4
+ with Cisco devices. It currently allows you to execute commands on a device and get
5
+ back the output of those commands.
6
+
7
+ To install:
8
+
9
+ git clone git://github.com/yakischloba/ruby-cisco.git
10
+ cd ruby-cisco
11
+ gem build cisco.gemspec
12
+ sudo gem install cisco-<version>.gem
13
+
14
+ The library provides two styles to use:
15
+
16
+ cisco = Cisco::Base.new(:host => "10.0.0.1", :password => "accesspass")
17
+ cisco.cmd("sh ver")
18
+ cisco.enable("enablepass")
19
+ cisco.cmd("sh run")
20
+ output = cisco.run
21
+
22
+ This will return an array of results, one string for the output of each command. The
23
+ following block style usage returns the same results, though some may prefer it:
24
+
25
+ output = cisco.run do |x|
26
+ x.cmd("sh ver")
27
+ x.enable("enablepass")
28
+ x.cmd("sh run")
29
+ end
30
+
31
+ SSH and Telnet should be working OK at this time. Unfortunately due to the asynchronous
32
+ design of the Net::SSH library's API, it is not easy to provide an interface for
33
+ operating conditionally on output data in the middle of a session like you may be
34
+ used to, for example:
35
+
36
+ output = device.cmd("show version")
37
+ if output =~ "IOS"
38
+ device.cmd("run some ios command")
39
+ else
40
+ device.cmd("run some catos command")
41
+ end
42
+
43
+ Similar behavior could be achieved by setting up the SSH session yourself. You can peek
44
+ at the #run method in ssh.rb for how to do this. Instead, the interface of this library
45
+ allows you to simply execute a series of commands all in one run, and get the output at
46
+ the end. I have limited the synchronous advantage of Net::Telnet by conforming it to this
47
+ model, but I wanted to have them both be used in the same fashion.
48
+
49
+ The Base class should be used unless you know what you're doing and what I have provided
50
+ is not adequate. Telnet is used by default. To use SSH, you must specify:
51
+
52
+ cisco = Cisco::Base.new(:host => "10.0.0.1", :user => "admin", :password => "accesspass", :transport => :ssh)
53
+
54
+ You can also pass an array of direct arguments that are used to instantiate the transport object.
55
+ This is useful, if for instance, you want to use public key authentication with SSH:
56
+
57
+ cisco = Cisco::Base.new(:directargs => ["10.0.0.1", "admin", :auth_methods => ["publickey"]])
58
+
59
+ In the future, I would like to provide subclasses to retrieve, present and set configuration
60
+ parameters in an OO fashion, like:
61
+
62
+ router.int["fa0/4"].speed
63
+ => 100
64
+ router.int["fa0/4"].speed = 10
65
+ router.apply!
66
+
67
+ I have yet to come up with a good way for implementing this that will scale across
68
+ a wide variety of devices. Please let me know if you have input and want to help.
69
+
70
+ jakecdouglas@gmail.com
71
+ yakischloba on Freenode
72
+
73
+ Thanks to Jamis Buck for creating Net::SSH and helping me understand how to do this.
@@ -0,0 +1,5 @@
1
+ $:.unshift File.expand_path(File.dirname(File.expand_path(__FILE__)))
2
+ require 'cisco/common'
3
+ require 'cisco/telnet'
4
+ require 'cisco/ssh'
5
+ require 'cisco/base'
@@ -0,0 +1,57 @@
1
+ module Cisco
2
+
3
+ class CiscoError < StandardError
4
+ end
5
+
6
+ class Base
7
+
8
+ attr_reader :transport
9
+
10
+ def initialize(options)
11
+ @transport = options[:transport] || :telnet
12
+ options[:prompt] ||= /[#>]\s?\z/n
13
+ options[:password] ||= ""
14
+ options[:autoinit] ||= true
15
+ @transport = Cisco.const_get(Cisco.constants.find {|const| const =~ Regexp.new(@transport.to_s, Regexp::IGNORECASE)}).new(options)
16
+ extra_init("terminal length 0")
17
+ end
18
+
19
+ def host
20
+ @transport.host
21
+ end
22
+
23
+ def password
24
+ @transport.password
25
+ end
26
+
27
+ def prompt
28
+ @transport.prompt
29
+ end
30
+
31
+ def clear_cmd
32
+ @transport.clear_cmd
33
+ end
34
+
35
+ def extra_init(*args)
36
+ @transport.extra_init(*args)
37
+ end
38
+
39
+ def clear_init
40
+ @transport.clear_init
41
+ end
42
+
43
+ def cmd(*args)
44
+ @transport.cmd(*args)
45
+ end
46
+
47
+ def run(&block)
48
+ @transport.run(&block)
49
+ end
50
+
51
+ def enable(*args)
52
+ @transport.enable(*args)
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,29 @@
1
+ module Cisco
2
+
3
+ module Common
4
+
5
+ attr_accessor :host, :password, :prompt
6
+
7
+ def enable(password, pwprompt = nil)
8
+ @pwprompt = pwprompt || @pwprompt
9
+ old = @prompt
10
+ cmd("enable", @pwprompt)
11
+ cmd(password, old)
12
+ end
13
+
14
+ def extra_init(*args)
15
+ cmd(*args)
16
+ @extra_init << @cmdbuf.pop
17
+ end
18
+
19
+ def clear_init
20
+ @extra_init = []
21
+ end
22
+
23
+ def clear_cmd
24
+ @cmdbuf = []
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,83 @@
1
+ require 'net/ssh'
2
+
3
+ module Cisco
4
+
5
+ class SSH
6
+
7
+ include Common
8
+
9
+ def initialize(options)
10
+ @host = options[:host]
11
+ @user = options[:user]
12
+ @password = options[:password]
13
+ @prompt = options[:prompt]
14
+ @sshargs = options[:directargs] || [@host, @user, {:password => @password, :auth_methods => ["password"]}]
15
+ @pwprompt = options[:pwprompt] || "Password:"
16
+ @cmdbuf, @extra_init = [], []
17
+ end
18
+
19
+ def cmd(cmd, prompt = nil, &block)
20
+ @cmdbuf << [cmd + "\n", prompt, block]
21
+ end
22
+
23
+ def run
24
+ @inbuf = ""
25
+ @results = []
26
+ @ssh = Net::SSH.start(*@sshargs)
27
+ @ssh.open_channel do |chan|
28
+ chan.send_channel_request("shell") do |ch, success|
29
+ if !success
30
+ abort "Could not open shell channel"
31
+ else
32
+ ch.on_data do |chn, data|
33
+ @outblock.call(data) if @outblock
34
+ @inbuf << data
35
+ check_and_send(chn)
36
+ end
37
+ (@cmdbuf = [] and yield self) if block_given?
38
+ @cmdbuf.insert(0, *@extra_init) if @extra_init.any?
39
+ end
40
+ end
41
+ end
42
+ @ssh.loop
43
+
44
+ @results
45
+ end
46
+
47
+ # Disconnect the session. Either Net::SSH has a bug, or the Cisco implementation is sometimes whacky,
48
+ # causing an exception to be thrown when trying to close the channel via the SSH protocol. To get around
49
+ # this, this method simply sends "exit" until the device disconnects us.
50
+ def close(chn)
51
+ 10.times do
52
+ chn.send_data("exit\n") unless (!chn.active? || chn.closing?)
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def check_and_send(chn)
59
+ if @inbuf =~ @prompt
60
+ @results << @inbuf.gsub(Regexp.new("\r\n"), "\n")
61
+ @inbuf = ""
62
+ if @cmdbuf.any?
63
+ send_next(chn)
64
+ else
65
+ close(chn)
66
+ end
67
+ elsif (@inbuf =~ Regexp.new(@pwprompt) and @prompt != Regexp.new(@pwprompt))
68
+ @cmdbuf = []
69
+ close(chn)
70
+ raise CiscoError.new("Enable password was not correct.")
71
+ end
72
+ end
73
+
74
+ def send_next(chn)
75
+ cmd = @cmdbuf.shift
76
+ @prompt = Regexp.new(cmd[1]) if cmd[1]
77
+ @outblock = cmd[2] if cmd[2]
78
+ chn.send_data(cmd.first)
79
+ end
80
+
81
+ end
82
+
83
+ end
@@ -0,0 +1,60 @@
1
+ require 'net/telnet'
2
+
3
+ module Cisco
4
+
5
+ class Telnet
6
+
7
+ include Common
8
+
9
+ def initialize(options)
10
+ @host = options[:host]
11
+ @password = options[:password]
12
+ @prompt = options[:prompt]
13
+ @targs = options[:directargs] || ["Host" => @host]
14
+ @pwprompt = options[:pwprompt] || "Password:"
15
+ @cmdbuf, @extra_init = [], []
16
+ end
17
+
18
+ def run
19
+ @results = []
20
+ (@cmdbuf = [] and yield self) if block_given?
21
+ @cmdbuf.insert(0, *@extra_init) if @extra_init.any?
22
+ @telnet = Net::Telnet.new(*@targs)
23
+ login
24
+ until @cmdbuf.empty?
25
+ send_next
26
+ @results << @telnet.waitfor(@prompt) {|x| @outblock.call(x) if @outblock}
27
+ end
28
+
29
+ @results
30
+ end
31
+
32
+ def cmd(cmd, prompt = nil, &block)
33
+ @cmdbuf << [cmd, prompt, block]
34
+ end
35
+
36
+ def close
37
+ 10.times do
38
+ chn.send_data("exit\n") while @telnet.sock
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def login
45
+ raise CiscoError.new("No login password provided.") unless @password
46
+ @results << @telnet.waitfor(Regexp.new("Password:"))
47
+ @telnet.puts(@password)
48
+ @results << @telnet.waitfor(@prompt)
49
+ end
50
+
51
+ def send_next
52
+ cmd = @cmdbuf.shift
53
+ @prompt = Regexp.new(cmd[1]) if cmd[1]
54
+ @outblock = cmd[2] if cmd[2]
55
+ @telnet.puts(cmd.first)
56
+ end
57
+
58
+ end
59
+
60
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cisco
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jake Douglas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-13 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: net-ssh
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: |-
26
+ This tool aims to provide transport-flexible functionality, for easy communication
27
+ with Cisco devices. It currently allows you to execute commands on a device and get
28
+ back the output of those commands.
29
+ email: jakecdouglas@gmail.com
30
+ executables: []
31
+
32
+ extensions: []
33
+
34
+ extra_rdoc_files: []
35
+
36
+ files:
37
+ - README
38
+ - lib/cisco.rb
39
+ - lib/cisco/common.rb
40
+ - lib/cisco/telnet.rb
41
+ - lib/cisco/base.rb
42
+ - lib/cisco/ssh.rb
43
+ has_rdoc: true
44
+ homepage: http://www.github.com/yakischloba/ruby-cisco
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options: []
49
+
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ requirements: []
65
+
66
+ rubyforge_project: cisco
67
+ rubygems_version: 1.3.5
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: Library for accessing Cisco devices via Telnet and SSH
71
+ test_files: []
72
+