cisco 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+