expect4r 0.0.1.dev

Sign up to get free protection for your applications and to get access to all the features.
data/lib/expect4r.rb ADDED
@@ -0,0 +1,49 @@
1
+ require 'expect/io'
2
+ require 'misc/passwd'
3
+
4
+ module Expect4r
5
+
6
+ autoload :Iox, 'router/cisco/iox/iox'
7
+ autoload :Ios, 'router/cisco/ios/ios'
8
+ autoload :J, 'router/juniper/junos/junos'
9
+ autoload :Shell, 'misc/shell'
10
+
11
+ module Router
12
+ autoload :Common, 'router/common'
13
+ module Common
14
+ autoload :Modes, 'router/modes'
15
+ end
16
+ module Error
17
+ autoload :RouterError, 'router/error'
18
+ autoload :SyntaxError, 'router/error'
19
+ autoload :SemanticError, 'router/error'
20
+ autoload :PingError, 'router/error'
21
+ end
22
+ module CiscoCommon
23
+ autoload :Show, 'router/cisco/common/show'
24
+ autoload :Ping, 'router/cisco/common/ping'
25
+ end
26
+ module Ios
27
+ autoload :TermServer, 'router/cisco/ios/termserver'
28
+ autoload :Modes, 'router/cisco/ios/modes'
29
+ end
30
+ module Iox
31
+ autoload :Modes, 'router/cisco/iox/modes'
32
+ end
33
+ module Junos
34
+ autoload :Modes, 'router/juniper/junos/modes'
35
+ autoload :Show, 'router/juniper/junos/show'
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+ if __FILE__ == $0
42
+ module Expect4r
43
+ p Expect4r::Iox.new_ssh 'hostname', 'username'
44
+ p Expect4r::Iox.new_telnet 'hostname', 'username'
45
+ p Expect4r::Ios.new_ssh 'hostname', 'username'
46
+ p Expect4r::J.new_ssh 'hostname', 'username'
47
+ p Expect4r::Shell.new
48
+ end
49
+ end
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'openssl'
3
+ require 'digest/sha1'
4
+ module Expect4r
5
+ def self.cipher(this, pwd='expect4r')
6
+ c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
7
+ c.encrypt
8
+ c.key = key = Digest::SHA1.hexdigest(pwd)
9
+ e = c.update(this)
10
+ e << c.final
11
+ end
12
+ def self.decipher(cipher,pwd='expect4r')
13
+ c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
14
+ c.decrypt
15
+ c.key = key = Digest::SHA1.hexdigest(pwd)
16
+ d = c.update(cipher)
17
+ d << c.final
18
+ end
19
+ end
data/lib/misc/shell.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'expect/io'
2
+
3
+ module Expect4r
4
+
5
+ class Shell
6
+ include Expect4r
7
+ def initialize()
8
+ ENV['PROMPT_COMMAND']="date +%k:%m:%S"
9
+ ENV['PS1']="shell>"
10
+ @ps1 = /shell>$/
11
+ @shell = ENV['SHELL'] || 'bash'
12
+ login
13
+ end
14
+ def login
15
+ spawn @shell
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,25 @@
1
+
2
+ module Expect4r::Router
3
+ module CiscoCommon
4
+
5
+ def config_lvl?
6
+ return -1 unless config?
7
+ @lp =~ /\(config(|.+)\)/
8
+ lvl = Regexp.last_match(1).split('-').size
9
+ lvl == 0 ? 1 : lvl
10
+ end
11
+
12
+ def top
13
+ return unless config?
14
+ 1.upto(config_lvl? - 1) { putline 'exit'}
15
+ end
16
+
17
+ def top?
18
+ return false unless config?
19
+ @lp =~ /\(config(|.+)\)/
20
+ Regexp.last_match(1).size == 0
21
+ end
22
+
23
+ end
24
+ end
25
+
@@ -0,0 +1,39 @@
1
+ require 'router/error'
2
+
3
+ module Expect4r::Router::CiscoCommon
4
+ module Ping
5
+ include ::Expect4r::Router::Error
6
+ def ping(arg={})
7
+ if arg.is_a?(Hash)
8
+ arg = {:pct_success=>100}.merge(arg)
9
+ pct_success = arg[:pct_success]
10
+ else
11
+ pct_success = 100
12
+ end
13
+ case arg
14
+ when String
15
+ dest = arg
16
+ when Hash
17
+ dest = arg[:dest]
18
+ else
19
+ raise ArgumentError, "Invalid argument: #{arg.inspect}"
20
+ end
21
+ output = exec "ping #{dest}", arg
22
+ r = output[0].find { |x| x =~/Success.*[^\d](\d+) percent \((\d+)\/(\d+)\)/}
23
+ if r &&
24
+ Regexp.last_match(1) &&
25
+ Regexp.last_match(2) &&
26
+ Regexp.last_match(3)
27
+
28
+ if $1.to_i < pct_success
29
+ raise PingError('router name here', dest, pct_success, $1.to_i, $2.to_i,$3.to_i, output)
30
+ else
31
+ [$1.to_i,[$2.to_i,$3.to_i],output]
32
+ end
33
+
34
+ else
35
+ raise PingError.new('router name here', dest, pct_success, $1.to_i, $2.to_i,$3.to_i, output)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,23 @@
1
+ module Expect4r::Router::CiscoCommon
2
+ module Show
3
+
4
+ def show(s, arg={})
5
+ output = []
6
+ s.each_line { |l|
7
+ output << exec("show #{l}", arg) if l.strip.size>0
8
+ }
9
+ output
10
+ end
11
+
12
+ def method_missing(name, *args, &block)
13
+ if name.to_s =~ /^show_/
14
+ cmd = name.to_s.split('_').join(' ') + args.join(' ')
15
+ cmd.gsub!(/running config/, 'running-config')
16
+ output = __send__ :exec, cmd, *args
17
+ else
18
+ super
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,65 @@
1
+ class Expect4r::Ios < ::Expect4r::BaseObject
2
+
3
+ include Expect4r
4
+ include Expect4r::Router::Common
5
+ include Expect4r::Router::Common::Modes
6
+ include Expect4r::Router::Ios::Modes
7
+ include Expect4r::Router::CiscoCommon
8
+ include Expect4r::Router::CiscoCommon::Show
9
+ include Expect4r::Router::CiscoCommon::Ping
10
+ include Expect4r::Router::Ios::TermServer
11
+
12
+ def initialize(*args)
13
+ super
14
+ @ps1 = /(.*)(>|#|\$)\s*$/
15
+ @more = / --More-- /
16
+ end
17
+
18
+ def enable
19
+ @enable_password ||= @pwd
20
+ enable_pwd = [/^Password: $/, enable_password]
21
+ @matches << enable_pwd
22
+ exp_send 'enable'
23
+ rescue
24
+ raise
25
+ ensure
26
+ @matches.delete enable_pwd
27
+ end
28
+
29
+ def enable_password
30
+ @enable_password ||= @pwd # FIXME
31
+ Expect4r.decipher(@pwd) # password is ciphered ...
32
+ end
33
+
34
+ def login
35
+ super(spawnee)
36
+ enable
37
+ exec "term len 0\nterm width 0"
38
+ self
39
+ end
40
+
41
+ def putline(line,*args)
42
+ output, rc = super
43
+ return output unless error?(output)
44
+ raise SyntaxError.new(self.class.to_s,line)
45
+ end
46
+
47
+ private
48
+
49
+ if "a"[0]==97
50
+ def string_start_with_pct_char?(s)
51
+ return unless s
52
+ s[0].chr == '%' if s[0]
53
+ end
54
+ else
55
+ def string_start_with_pct_char?(s)
56
+ return unless s
57
+ s[0] == '%'
58
+ end
59
+ end
60
+
61
+ def error?(output)
62
+ string_start_with_pct_char?(output[-2]) || string_start_with_pct_char?(output[-3])
63
+ end
64
+
65
+ end
@@ -0,0 +1,97 @@
1
+ require 'router/modes'
2
+
3
+ module Expect4r::Router::Ios
4
+ module Modes
5
+
6
+ def in?(mode=:none)
7
+ login unless connected?
8
+ case mode
9
+ when :exec ; exec?
10
+ when :user ; user?
11
+ when :config ; config?
12
+ else
13
+ _mode_?
14
+ end
15
+ end
16
+
17
+
18
+ def config(config=nil, arg={})
19
+ login unless connected?
20
+ if config
21
+ mode = in?
22
+ change_mode_to :config
23
+ output = exp_send(config, arg)
24
+ change_mode_to mode
25
+ output
26
+ else
27
+ change_mode_to :config
28
+ end
29
+ end
30
+
31
+ def exec(cmd=nil, arg={})
32
+ login unless connected?
33
+ if cmd.nil?
34
+ change_mode_to :exec
35
+ else
36
+ if exec?
37
+ output = exp_send(cmd, arg)
38
+ elsif config?
39
+ output = exp_send("do #{cmd}", arg)
40
+ else
41
+ mode = in?
42
+ change_mode_to :exec
43
+ output = exp_send(cmd, arg)
44
+ change_mode_to mode
45
+ output
46
+ end
47
+ end
48
+ end
49
+
50
+ def _mode_?
51
+ if user?
52
+ :user
53
+ elsif config?
54
+ :config
55
+ elsif exec?
56
+ :exec
57
+ end
58
+ end
59
+
60
+ def config?
61
+ @lp =~ /\(config(|.+)\)/
62
+ end
63
+
64
+ def exec?
65
+ ! user? and ! config?
66
+ end
67
+
68
+ def user?
69
+ @lp =~ /.+>\s*$/
70
+ end
71
+
72
+ def to_config
73
+ return :config if config?
74
+ to_exec
75
+ putline 'configure terminal' if exec?
76
+ raise RuntimeError, "unable to got to config mode" unless config?
77
+ :config
78
+ end
79
+
80
+ def to_exec
81
+ return :exec if exec?
82
+ if config?
83
+ 1.upto(config_lvl?) { putline 'exit'}
84
+ end
85
+ raise RuntimeError, "unable to got to exec mode" unless exec?
86
+ :exec
87
+ end
88
+
89
+ def to_user
90
+ return if user?
91
+ putline "exit"
92
+ raise RuntimeError, "unable to got to user mode" unless exec?
93
+ :user
94
+ end
95
+
96
+ end
97
+ end
@@ -0,0 +1,20 @@
1
+ module Expect4r::Router::Ios
2
+ module TermServer
3
+
4
+ def powercycle(lineno)
5
+ config "line #{lineno}\nmodem dtr\nmodem dtr-active"
6
+ sleep 2
7
+ config "line #{lineno}\nno modem dtr\nno modem dtr-active"
8
+ end
9
+ def clear_line(lineno)
10
+ confirm = [/\[confirm\]/, ""]
11
+ @matches << confirm
12
+ putline "clear line #{lineno}"
13
+ rescue Expect4r::Router::Error::SyntaxError => e
14
+ puts e.err_msg
15
+ ensure
16
+ @matches.delete confirm
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,54 @@
1
+ class Expect4r::Iox < ::Expect4r::BaseObject
2
+
3
+ include Expect4r
4
+ include Expect4r::Router
5
+ include Expect4r::Router::Common
6
+ include Expect4r::Router::Common::Modes
7
+ include Expect4r::Router::CiscoCommon
8
+ include Expect4r::Router::Iox::Modes
9
+ include Expect4r::Router::CiscoCommon::Show
10
+ include Expect4r::Router::CiscoCommon::Ping
11
+
12
+ def initialize(*args)
13
+ super
14
+ @ps1 = /(.*)(>|#|\$)\s*$/
15
+ @more = / --More-- /
16
+ end
17
+
18
+ def login
19
+ super(spawnee)
20
+ config 'no logging console' if port>0
21
+ exec "terminal len 0\nterminal width 0"
22
+ self
23
+ end
24
+
25
+ def commit(arg={})
26
+ return unless config?
27
+ output = putline "commit", arg
28
+ if /\% Failed to commit/.match(output.join)
29
+ err = show_configuration_failed
30
+ abort_config
31
+ raise Iox::SemanticError.new(show_configuration_failed)
32
+ end
33
+ output
34
+ end
35
+
36
+ def putline(line,*args)
37
+ output, rc = super
38
+ raise SyntaxError.new(line) if output.join =~ /\% Invalid input detected at/
39
+ output
40
+ end
41
+
42
+ private
43
+
44
+ def abort_config
45
+ return unless config?
46
+ putline 'abort' # make sure buffer config is cleaned up.
47
+ nil
48
+ end
49
+
50
+ def show_configuration_failed
51
+ putline 'show configuration failed'
52
+ end
53
+
54
+ end
@@ -0,0 +1,101 @@
1
+ require 'router/modes'
2
+
3
+ module Expect4r::Router::Iox
4
+ module Modes
5
+
6
+ def config(config=nil, arg={})
7
+ login unless connected?
8
+ if config
9
+ mode = in?
10
+ change_mode_to :config
11
+ output = exp_send(config, arg)
12
+ output << commit
13
+ change_mode_to mode
14
+ output
15
+ else
16
+ change_mode_to :config
17
+ end
18
+ end
19
+
20
+ def exec(cmd=nil, arg={})
21
+ login unless connected?
22
+ if cmd.nil?
23
+ change_mode_to :exec
24
+ else
25
+ if exec?
26
+ output = exp_send(cmd, arg)
27
+ elsif config?
28
+ output = exp_send("do #{cmd}", arg)
29
+ else
30
+ mode = in?
31
+ change_mode_to :exec
32
+ output = exp_send(cmd, arg)
33
+ change_mode_to mode
34
+ output
35
+ end
36
+ end
37
+ end
38
+
39
+ def shell(cmd=nil, arg={})
40
+ connected = connected?
41
+ login unless connected?
42
+ if cmd.nil?
43
+ to_shell
44
+ else
45
+ if shell?
46
+ output = exp_send(cmd, arg)
47
+ elsif config?
48
+ output = exp_send("do run #{cmd}", arg)
49
+ elsif exec?
50
+ output = exp_send("run #{cmd}", arg)
51
+ else
52
+ raise RuntimeError # TODO
53
+ end
54
+ output
55
+ end
56
+ end
57
+
58
+ def config?
59
+ @lp =~ /\(config(|.+)\)/
60
+ end
61
+
62
+ def submode?
63
+ return '' unless config?
64
+ @lp =~ /\(config(|.+)\)/
65
+ Regexp.last_match(1).split('-')[1..-1].join('-')
66
+ end
67
+
68
+ def exec?
69
+ ! shell? and ! config?
70
+ end
71
+
72
+ def shell?
73
+ @lp == '# '
74
+ end
75
+
76
+ def to_config
77
+ return :config if config?
78
+ to_exec
79
+ putline 'configure'
80
+ raise RuntimeError, "unable to got to config mode" unless config?
81
+ :config
82
+ end
83
+
84
+ def to_shell
85
+ return :shell if shell?
86
+ to_exec
87
+ putline 'run'
88
+ raise RuntimeError, "unable to got to shell mode" unless shell?
89
+ :shell
90
+ end
91
+
92
+ def to_exec
93
+ return :exec if exec?
94
+ putline "exit" if shell?
95
+ putline "abort" if config?
96
+ raise RuntimeError, "unable to got to exec mode" unless exec?
97
+ :exec
98
+ end
99
+
100
+ end
101
+ end