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/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
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'highline/import'
|
4
|
+
require 'misc/passwd'
|
5
|
+
|
6
|
+
module Expect4r::Router
|
7
|
+
module Common
|
8
|
+
|
9
|
+
def console?
|
10
|
+
@port.to_i > 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def io_escape_char_cb
|
14
|
+
putc "\n" if console?
|
15
|
+
end
|
16
|
+
|
17
|
+
def spawnee
|
18
|
+
case method
|
19
|
+
when :telnet ; "telnet #{host} #{port if port>0}"
|
20
|
+
when :ssh ; "ssh #{spawnee_username}@#{host}"
|
21
|
+
else
|
22
|
+
raise RuntimeError
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def spawnee_username
|
27
|
+
@user
|
28
|
+
end
|
29
|
+
|
30
|
+
def spawnee_prompt
|
31
|
+
@ps1
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def spawnee_password
|
37
|
+
@pwd = Expect4r.cipher( ask("Enter your password: ") { |q| q.echo = "X" } ) unless @pwd
|
38
|
+
Expect4r.decipher(@pwd)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
data/lib/router/error.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module Expect4r::Router
|
2
|
+
module Error
|
3
|
+
class RouterError < RuntimeError
|
4
|
+
def initialize(rname, msg)
|
5
|
+
@rname = rname
|
6
|
+
@msg = msg
|
7
|
+
end
|
8
|
+
def err_msg
|
9
|
+
"#{@rname} [Error] : #{@msg}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class SyntaxError < RouterError
|
14
|
+
def err_msg
|
15
|
+
"#{@rname} [SyntaxError] : #{@msg}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class SemanticError < RouterError
|
20
|
+
def err_msg
|
21
|
+
"#{@rname} [SemanticError] : #{@msg}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class PingError < RuntimeError
|
26
|
+
attr_reader :rname, :dest, :exp_pct, :act_pct, :sent, :recv
|
27
|
+
def initialize(rname, dest, exp_pct, act_pct, sent, recv, output)
|
28
|
+
@rname, @dest, @exp_pct, @act_pct, @sent, @recv = rname, dest, exp_pct, act_pct, sent, recv
|
29
|
+
end
|
30
|
+
def err_msg
|
31
|
+
"#{@rname} [PingError] : failed to ping #{@dest}, expected/actual pct: #{@exp_pct}/#{@act_pct}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
if __FILE__ == $0
|
39
|
+
|
40
|
+
require "test/unit"
|
41
|
+
|
42
|
+
# require "router/error"
|
43
|
+
|
44
|
+
class TestRouterError < Test::Unit::TestCase
|
45
|
+
include Expect4r::Router::Error
|
46
|
+
def test_raise
|
47
|
+
assert_raise(RouterError) {raise RouterError.new('paris','show bogus command')}
|
48
|
+
assert_err_msg 'paris [Error] : show bogus command', lambda {raise RouterError.new('paris','show bogus command')}
|
49
|
+
assert_err_msg 'paris [SyntaxError] : show bogus command', lambda {raise SyntaxError.new('paris','show bogus command')}
|
50
|
+
assert_err_msg 'paris [SemanticError] : show bogus command', lambda {raise SemanticError.new('paris','show bogus command')}
|
51
|
+
assert_err_msg 'paris [PingError] : failed to ping 1.1.1.1, expected/actual pct: 100/90', lambda {raise PingError.new('paris','1.1.1.1', 100, 90, 10, 9, '')}
|
52
|
+
assert_equal 100, exception(lambda {raise PingError.new('paris','1.1.1.1', 100, 90, 10, 9,'')}).exp_pct
|
53
|
+
assert_equal 'paris', exception(lambda {raise PingError.new('paris','1.1.1.1', 100, 90, 10, 9,'')}).rname
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def assert_err_msg(err_msg, block)
|
59
|
+
begin
|
60
|
+
block.call
|
61
|
+
rescue RouterError, PingError => re
|
62
|
+
assert_equal err_msg, re.err_msg
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def exception(block)
|
67
|
+
begin
|
68
|
+
block.call
|
69
|
+
rescue RouterError, PingError => re
|
70
|
+
re
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class Expect4r::J < ::Expect4r::BaseObject
|
2
|
+
include Expect4r
|
3
|
+
include Expect4r::Router::Error
|
4
|
+
include Expect4r::Router::Common
|
5
|
+
include Expect4r::Router::Common::Modes
|
6
|
+
include Expect4r::Router::Junos::Modes
|
7
|
+
include Expect4r::Router::Junos::Show
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
super
|
11
|
+
@ps1 = /(^|\r\r)([-a-zA-z@_~=\.\(\)\d]+(>|\#|%)|%|\$) $/
|
12
|
+
@more = /---\(more(| \d+\%)\)---/
|
13
|
+
end
|
14
|
+
|
15
|
+
def login
|
16
|
+
ENV['TERM']='dumb'
|
17
|
+
super(spawnee)
|
18
|
+
exec 'set cli screen-length 0'
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def console?
|
23
|
+
@port>0
|
24
|
+
end
|
25
|
+
|
26
|
+
def putline(line,arg={})
|
27
|
+
o, rc = super
|
28
|
+
raise SyntaxError.new(self.class.to_s, line) if o.join =~ /(unknown command|syntax error)\./
|
29
|
+
o
|
30
|
+
end
|
31
|
+
|
32
|
+
def top
|
33
|
+
putline 'top'
|
34
|
+
end
|
35
|
+
|
36
|
+
def exit
|
37
|
+
putline 'exit'
|
38
|
+
end
|
39
|
+
|
40
|
+
def commit(arg={})
|
41
|
+
return unless config?
|
42
|
+
@matches << [/Exit with uncommitted changes.+\(yes\)/, 'yes']
|
43
|
+
output = putline "commit", arg
|
44
|
+
if /error: configuration check-out failed/.match(output.join)
|
45
|
+
putline 'rollback'
|
46
|
+
raise SemanticError.new(self.class.to_s, output)
|
47
|
+
end
|
48
|
+
output
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'router/modes'
|
2
|
+
|
3
|
+
module Expect4r::Router::Junos
|
4
|
+
module Modes
|
5
|
+
|
6
|
+
def config(stmts=nil, arg={})
|
7
|
+
login unless connected?
|
8
|
+
if stmts
|
9
|
+
mode = in?
|
10
|
+
to_config
|
11
|
+
output = exp_send(stmts, arg)
|
12
|
+
output << commit
|
13
|
+
change_mode_to(mode)
|
14
|
+
output
|
15
|
+
else
|
16
|
+
mode
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def exec(cmd=nil, *args)
|
21
|
+
login unless connected?
|
22
|
+
if cmd.nil?
|
23
|
+
to_exec
|
24
|
+
else
|
25
|
+
if config?
|
26
|
+
exp_send("run #{cmd}", *args)
|
27
|
+
elsif exec?
|
28
|
+
exp_send cmd, *args
|
29
|
+
else
|
30
|
+
mode = _mode_?
|
31
|
+
to_exec
|
32
|
+
output = exp_send(cmd, *args)
|
33
|
+
change_mode_to mode
|
34
|
+
output
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def shell(cmd=nil, *args)
|
40
|
+
connected = connected?
|
41
|
+
login unless connected?
|
42
|
+
if cmd.nil?
|
43
|
+
to_shell
|
44
|
+
else
|
45
|
+
mode = _mode_?
|
46
|
+
to_shell
|
47
|
+
output = exp_send(cmd, *args)
|
48
|
+
change_mode_to mode
|
49
|
+
output
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def exec?
|
54
|
+
@lp =~ /> $/ ? true : false
|
55
|
+
end
|
56
|
+
|
57
|
+
def config?
|
58
|
+
@lp =~ /^.+# $/ ? true : false
|
59
|
+
end
|
60
|
+
|
61
|
+
def shell?
|
62
|
+
@lp == '% ' ? true : false
|
63
|
+
end
|
64
|
+
|
65
|
+
def set_cli_logical_router(logical_router)
|
66
|
+
return if @ps1_bis
|
67
|
+
to_exec
|
68
|
+
arr= @lp.split(">")
|
69
|
+
@ps1_bis = /#{arr[0]}:#{logical_router}(\#|>)\s*$/
|
70
|
+
p @ps1_bis
|
71
|
+
putline "set cli logical-router #{logical_router}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def clear_cli_logical_router()
|
75
|
+
return unless @ps1_bis
|
76
|
+
to_exec
|
77
|
+
@ps1_bis=nil
|
78
|
+
putline "clear cli logical-router"
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def to_config
|
84
|
+
return :config if config?
|
85
|
+
to_exec
|
86
|
+
putline 'edit', :debug=>1
|
87
|
+
raise RuntimeError, "unable to got to config mode" unless config?
|
88
|
+
:config
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_shell
|
92
|
+
return in? if @ps1_bis
|
93
|
+
return :shell if shell?
|
94
|
+
to_exec
|
95
|
+
putline 'start shell'
|
96
|
+
raise RuntimeError, "unable to got to shell mode" unless shell?
|
97
|
+
:shell
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_exec
|
101
|
+
return :exec if exec?
|
102
|
+
top if config?
|
103
|
+
exit
|
104
|
+
raise RuntimeError, "unable to got to exec mode" unless exec?
|
105
|
+
:exec
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
module Expect4r::Router::Junos
|
3
|
+
module Show
|
4
|
+
|
5
|
+
def show(s, arg={})
|
6
|
+
output = []
|
7
|
+
s.each_line { |l|
|
8
|
+
output << exec("show #{l}", arg) if l.strip.size>0
|
9
|
+
}
|
10
|
+
output
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(name, *args, &block)
|
14
|
+
if name.to_s =~ /^show_/
|
15
|
+
cmd = name.to_s.split('_').join(' ') + args.join(' ')
|
16
|
+
output = __send__ :exec, cmd, *args
|
17
|
+
else
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
data/lib/router/modes.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Expect4r
|
2
|
+
module Router
|
3
|
+
module Common
|
4
|
+
module Modes
|
5
|
+
def in?(mode=:none)
|
6
|
+
login unless connected?
|
7
|
+
case mode
|
8
|
+
when :exec ; exec?
|
9
|
+
when :shell ; shell?
|
10
|
+
when :config ; config?
|
11
|
+
else
|
12
|
+
_mode_?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
def change_mode_to(mode)
|
16
|
+
login unless connected?
|
17
|
+
case mode
|
18
|
+
when :exec ; to_exec
|
19
|
+
when :shell ; to_shell
|
20
|
+
when :config ; to_config
|
21
|
+
end
|
22
|
+
end
|
23
|
+
def _mode_?
|
24
|
+
putline ' ', :no_trim=>true, :no_echo=>true unless @lp
|
25
|
+
if exec?
|
26
|
+
:exec
|
27
|
+
elsif config?
|
28
|
+
:config
|
29
|
+
elsif shell?
|
30
|
+
:shell
|
31
|
+
else
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "misc/passwd"
|
3
|
+
|
4
|
+
class TestMiscPasswd < Test::Unit::TestCase
|
5
|
+
def test_cipher
|
6
|
+
assert_not_equal 'my password', Expect4r.cipher('my password')
|
7
|
+
assert_equal 'my password', Expect4r.decipher(Expect4r.cipher('my password'))
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
|
3
|
+
require "router/cisco/iox/iox"
|
4
|
+
|
5
|
+
class TestRouterCiscoIoxIox < Test::Unit::TestCase
|
6
|
+
def test_new_hash_terse
|
7
|
+
x = Iox.new :ssh,
|
8
|
+
:host=> '1.1.1.1',
|
9
|
+
:user=> 'username',
|
10
|
+
:pwd=> 'lab',
|
11
|
+
:method=> :ssh
|
12
|
+
assert_equal '1.1.1.1', x.host
|
13
|
+
assert_equal '1.1.1.1', x.hostname
|
14
|
+
assert_equal 0, x.port
|
15
|
+
assert_equal 'username', x.user
|
16
|
+
assert_equal 'username', x.username
|
17
|
+
assert_raise(NoMethodError) { x.pwd }
|
18
|
+
assert_not_equal "lab", x.instance_eval { @pwd }
|
19
|
+
end
|
20
|
+
def test_new_hash
|
21
|
+
x = Iox.new :ssh,
|
22
|
+
:hostname=> '1.1.1.1',
|
23
|
+
:username=> 'username',
|
24
|
+
:password=> 'lab'
|
25
|
+
assert_equal '1.1.1.1', x.host
|
26
|
+
assert_equal '1.1.1.1', x.hostname
|
27
|
+
assert_equal 0, x.port
|
28
|
+
assert_equal 'username', x.user
|
29
|
+
assert_equal 'username', x.username
|
30
|
+
assert_raise(NoMethodError) { x.pwd }
|
31
|
+
assert_not_equal "lab", x.instance_eval { @pwd }
|
32
|
+
assert_equal :ssh, x.instance_eval { @method }
|
33
|
+
end
|
34
|
+
def test_new
|
35
|
+
x = Iox.new :telnet, '1.1.1.1 4002', 'username', 'lab'
|
36
|
+
assert_equal '1.1.1.1', x.host
|
37
|
+
assert_equal 4002, x.port
|
38
|
+
assert_equal '1.1.1.1', x.hostname
|
39
|
+
assert_equal 'username', x.user
|
40
|
+
assert_equal 'username', x.username
|
41
|
+
assert_raise(NoMethodError) { x.pwd }
|
42
|
+
assert_not_equal "lab", x.instance_eval { @pwd }
|
43
|
+
assert_equal :telnet, x.instance_eval { @method }
|
44
|
+
end
|
45
|
+
def test_new_ssh
|
46
|
+
x = Iox.new_ssh :hostname=> '1.1.1.1'
|
47
|
+
assert_equal '1.1.1.1', x.host
|
48
|
+
assert_equal '1.1.1.1', x.hostname
|
49
|
+
assert_equal 0, x.port
|
50
|
+
assert_nil x.user
|
51
|
+
assert_nil x.username
|
52
|
+
assert_raise(NoMethodError) { x.pwd }
|
53
|
+
assert_not_equal "lab", x.instance_eval { @pwd }
|
54
|
+
assert_equal :ssh, x.instance_eval { @method }
|
55
|
+
end
|
56
|
+
def test_new_telnet
|
57
|
+
x = Iox.new_telnet :hostname=> '1.1.1.1'
|
58
|
+
assert_equal '1.1.1.1', x.host
|
59
|
+
assert_equal '1.1.1.1', x.hostname
|
60
|
+
assert_equal 0, x.port
|
61
|
+
assert_nil x.user
|
62
|
+
assert_nil x.username
|
63
|
+
assert_raise(NoMethodError) { x.pwd }
|
64
|
+
assert_not_equal "lab", x.instance_eval { @pwd }
|
65
|
+
assert_equal :telnet, x.instance_eval { @method }
|
66
|
+
end
|
67
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: expect4r
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: true
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- dev
|
10
|
+
version: 0.0.1.dev
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jean-Michel Esnault
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-24 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: highline
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 5
|
31
|
+
- 0
|
32
|
+
version: 1.5.0
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description: A Ruby Library for interacting with Ios, IosXR, and Junos CLI.
|
36
|
+
email: jesnault@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.rdoc
|
44
|
+
files:
|
45
|
+
- COPYING
|
46
|
+
- LICENSE
|
47
|
+
- README.rdoc
|
48
|
+
- lib/expect/io.rb
|
49
|
+
- lib/expect4r.rb
|
50
|
+
- lib/misc/passwd.rb
|
51
|
+
- lib/misc/shell.rb
|
52
|
+
- lib/router/cisco/common/common.rb
|
53
|
+
- lib/router/cisco/common/ping.rb
|
54
|
+
- lib/router/cisco/common/show.rb
|
55
|
+
- lib/router/cisco/ios/ios.rb
|
56
|
+
- lib/router/cisco/ios/modes.rb
|
57
|
+
- lib/router/cisco/ios/termserver.rb
|
58
|
+
- lib/router/cisco/iox/iox.rb
|
59
|
+
- lib/router/cisco/iox/modes.rb
|
60
|
+
- lib/router/common.rb
|
61
|
+
- lib/router/error.rb
|
62
|
+
- lib/router/juniper/junos/junos.rb
|
63
|
+
- lib/router/juniper/junos/modes.rb
|
64
|
+
- lib/router/juniper/junos/show.rb
|
65
|
+
- lib/router/modes.rb
|
66
|
+
has_rdoc: true
|
67
|
+
homepage:
|
68
|
+
licenses: []
|
69
|
+
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options:
|
72
|
+
- --quiet
|
73
|
+
- --title
|
74
|
+
- Expect4r
|
75
|
+
- --line-numbers
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
segments:
|
83
|
+
- 1
|
84
|
+
- 8
|
85
|
+
- 7
|
86
|
+
version: 1.8.7
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">"
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
segments:
|
92
|
+
- 1
|
93
|
+
- 3
|
94
|
+
- 1
|
95
|
+
version: 1.3.1
|
96
|
+
requirements: []
|
97
|
+
|
98
|
+
rubyforge_project:
|
99
|
+
rubygems_version: 1.3.6
|
100
|
+
signing_key:
|
101
|
+
specification_version: 3
|
102
|
+
summary: Expect4r
|
103
|
+
test_files:
|
104
|
+
- test/misc/passwd_test.rb
|
105
|
+
- test/router/cisco/iox/iox_test.rb
|