expect4r 0.0.1.dev
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +674 -0
- data/LICENSE +53 -0
- data/README.rdoc +126 -0
- data/lib/expect/io.rb +484 -0
- data/lib/expect4r.rb +49 -0
- data/lib/misc/passwd.rb +19 -0
- data/lib/misc/shell.rb +19 -0
- data/lib/router/cisco/common/common.rb +25 -0
- data/lib/router/cisco/common/ping.rb +39 -0
- data/lib/router/cisco/common/show.rb +23 -0
- data/lib/router/cisco/ios/ios.rb +65 -0
- data/lib/router/cisco/ios/modes.rb +97 -0
- data/lib/router/cisco/ios/termserver.rb +20 -0
- data/lib/router/cisco/iox/iox.rb +54 -0
- data/lib/router/cisco/iox/modes.rb +101 -0
- data/lib/router/common.rb +42 -0
- data/lib/router/error.rb +76 -0
- data/lib/router/juniper/junos/junos.rb +53 -0
- data/lib/router/juniper/junos/modes.rb +109 -0
- data/lib/router/juniper/junos/show.rb +23 -0
- data/lib/router/modes.rb +37 -0
- data/test/misc/passwd_test.rb +9 -0
- data/test/router/cisco/iox/iox_test.rb +67 -0
- metadata +105 -0
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
|
data/lib/misc/passwd.rb
ADDED
@@ -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
|