expect4r 0.0.1.dev

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/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