expect4r 0.0.2.dev → 0.0.3.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/README.rdoc +76 -22
- data/lib/expect/io.rb +103 -31
- data/lib/expect4r.rb +2 -0
- data/lib/misc/shell.rb +40 -4
- data/lib/router/cisco/common/common.rb +10 -0
- data/lib/router/cisco/common/ping.rb +23 -8
- data/lib/router/cisco/ios/ios.rb +8 -3
- data/lib/router/cisco/ios/modes.rb +10 -0
- data/lib/router/cisco/iox/iox.rb +7 -3
- data/lib/router/cisco/iox/modes.rb +13 -0
- data/lib/router/cisco/iox/ping.rb +55 -0
- data/lib/router/common.rb +0 -24
- data/lib/router/juniper/junos/junos.rb +7 -4
- data/lib/router/juniper/junos/modes.rb +28 -1
- data/lib/router/juniper/junos/ping.rb +18 -0
- data/lib/router/modes.rb +15 -0
- metadata +5 -4
data/README.rdoc
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
= Expect4r -- Interact with Cisco IOS, IOS-XR, and Juniper JUNOS CLI.
|
2
|
+
|
1
3
|
Expect4r is a library that enables a ruby program to 'talk' to routers following a written ruby script.
|
2
4
|
You talk to routers by connecting to them using ssh or telnet and send exec or config command and collect router output than can be parsed using ruby.
|
3
5
|
|
@@ -21,16 +23,21 @@ You talk to routers by connecting to them using ssh or telnet and send exec or c
|
|
21
23
|
interface loopback0
|
22
24
|
shutdown
|
23
25
|
}
|
24
|
-
|
25
|
-
|
26
|
+
|
26
27
|
iox.config
|
27
28
|
iox.exp_send 'interface GigabitEthernet0/2/0/0'
|
28
29
|
iox.exp_send 'desc to switch port 13'
|
29
30
|
iox.exp_send 'ipv4 address 190.0.0.9 255.255.255.252'
|
30
31
|
iox.exp_send 'no shut'
|
31
32
|
iox.commit
|
32
|
-
|
33
|
-
|
33
|
+
|
34
|
+
iox.config %|
|
35
|
+
interface GigabitEthernet0/2/0/0
|
36
|
+
desc to switch port 13'
|
37
|
+
ipv4 address 190.0.0.9 255.255.255.252'
|
38
|
+
no shut'
|
39
|
+
|
|
40
|
+
|
34
41
|
j.config %{
|
35
42
|
edit logical-router Orleans protocols bgp
|
36
43
|
edit group session-to-200
|
@@ -41,7 +48,6 @@ You talk to routers by connecting to them using ssh or telnet and send exec or c
|
|
41
48
|
|
42
49
|
* exec commands
|
43
50
|
|
44
|
-
|
45
51
|
j.exec 'set cli screen-length 0'
|
46
52
|
|
47
53
|
iox.exec "terminal len 0\nterminal width 0"
|
@@ -54,7 +60,6 @@ You talk to routers by connecting to them using ssh or telnet and send exec or c
|
|
54
60
|
|
55
61
|
* interact with CLI.
|
56
62
|
|
57
|
-
|
58
63
|
irb> r.interact
|
59
64
|
|
60
65
|
#
|
@@ -98,13 +103,13 @@ You talk to routers by connecting to them using ssh or telnet and send exec or c
|
|
98
103
|
Parsing a response becomes a matter of iterating an array using the
|
99
104
|
Arrays's enumerator methods such as find, find_all ...
|
100
105
|
|
101
|
-
irb
|
102
|
-
irb
|
103
|
-
irb
|
104
|
-
irb
|
106
|
+
irb> output = ts.exec %{
|
107
|
+
irb" show terminal | include History
|
108
|
+
irb" show line | include AUX
|
109
|
+
irb" }
|
105
110
|
=> [
|
106
|
-
["show terminal | include History", "History is enabled, history size is 10.", "
|
107
|
-
["show line | include AUX", " 17 AUX 9600/9600 - 0/0 -", "
|
111
|
+
["show terminal | include History", "History is enabled, history size is 10.", "ios#"],
|
112
|
+
["show line | include AUX", " 17 AUX 9600/9600 - 0/0 -", "ios#"]
|
108
113
|
]
|
109
114
|
|
110
115
|
output[0] contains output for 1st command 'show terminal'.
|
@@ -113,14 +118,63 @@ You talk to routers by connecting to them using ssh or telnet and send exec or c
|
|
113
118
|
output[n-1] contains output for nth command.
|
114
119
|
|
115
120
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
121
|
+
* Ping
|
122
|
+
|
123
|
+
irb(main):016:0> ios.ping '192.168.1.23', :count=> 100, :pct_success=>90, :sweep_max_size=> 1500
|
124
|
+
=> [ 99, [146148, 146500],
|
125
|
+
[["ping",
|
126
|
+
"Protocol [ip]: ", "",
|
127
|
+
"Target IP address: ", "192.168.1.23",
|
128
|
+
"Repeat count [5]: ", "100",
|
129
|
+
"Datagram size [100]: ", "",
|
130
|
+
"Timeout in seconds [2]: ", "",
|
131
|
+
"Extended commands [n]: ", "",
|
132
|
+
"Sweep range of sizes [n]: ", "yes",
|
133
|
+
"Sweep min size [36]: ", "",
|
134
|
+
"Sweep max size [18024]: ", "1500",
|
135
|
+
"Sweep interval [1]: ", "",
|
136
|
+
"Type escape sequence to abort.",
|
137
|
+
"Sending 146500, [36..1500]-byte ICMP Echos to 192.168.1.23, timeout is 2 seconds:",
|
138
|
+
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!.!!!!!!!!!!!!.!!!!!!!!.!!!!!!!!!!!!!!!!!!!",
|
139
|
+
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
|
140
|
+
...
|
141
|
+
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
|
142
|
+
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
|
143
|
+
"Success rate is 99 percent (146148/146500), round-trip min/avg/max = 1/7/924 ms",
|
144
|
+
"ios#"]]]
|
145
|
+
|
146
|
+
|
147
|
+
irb> iox.ping '192.168.1.100'
|
148
|
+
=> [100, [5, 5],
|
149
|
+
[["ping 192.168.1.100",
|
150
|
+
"\rTue Oct 26 08:42:58.235 UTC",
|
151
|
+
"Type escape sequence to abort.",
|
152
|
+
"Sending 5, 100-byte ICMP Echos to 192.168.1.100, timeout is 2 seconds:",
|
153
|
+
"!!!!!",
|
154
|
+
"Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/2 ms",
|
155
|
+
"RP/0/0/CPU0:Paris-rp0#"]]]
|
156
|
+
|
157
|
+
|
158
|
+
irb> iox.ping '192.168.1.100', :sweep_min_size => 1000, :sweep_max_size => 1300
|
159
|
+
=> [100, [1505, 1505],
|
160
|
+
[["ping",
|
161
|
+
"\rTue Oct 26 08:44:33.024 UTC",
|
162
|
+
"Protocol [ipv4]: ", "",
|
163
|
+
"\rTarget IP address: ", "192.168.1.100",
|
164
|
+
"\rRepeat count [5]: ", "", "\rDatagram size [100]: ", "",
|
165
|
+
"\rTimeout in seconds [2]: ", "",
|
166
|
+
"\rExtended commands? [no]: ", "",
|
167
|
+
"\rSweep range of sizes? [no]: ", "yes",
|
168
|
+
"\rSweep min size [36]: ", "1000",
|
169
|
+
"\rSweep max size [18024]: ", "1300",
|
170
|
+
"\rSweep interval [1]: ", "",
|
171
|
+
"\rType escape sequence to abort.",
|
172
|
+
"Sending 1505, [1000..1300]-byte ICMP Echos to 192.168.1.100, timeout is 2 seconds:",
|
173
|
+
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
|
174
|
+
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
|
175
|
+
...
|
176
|
+
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
|
177
|
+
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
|
178
|
+
"Success rate is 100 percent (1505/1505), round-trip min/avg/max = 1/1/3 ms",
|
179
|
+
"RP/0/0/CPU0:Paris-rp0#"]]]
|
126
180
|
|
data/lib/expect/io.rb
CHANGED
@@ -81,14 +81,15 @@ module Expect4r
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def child_exit
|
84
|
-
if @
|
85
|
-
|
86
|
-
|
87
|
-
|
84
|
+
if @proxy
|
85
|
+
@proxy.logout
|
86
|
+
else
|
87
|
+
Process.kill(:KILL, @pid) if @pid
|
88
|
+
@thread.kill if @thread
|
88
89
|
end
|
89
90
|
rescue Errno::ESRCH, Errno::ECHILD => e
|
90
91
|
ensure
|
91
|
-
@lp, @r, @w, @pid = [nil]*
|
92
|
+
@lp, @r, @w, @pid, @proxy = [nil]*5
|
92
93
|
end
|
93
94
|
|
94
95
|
def spawn(cmd)
|
@@ -150,6 +151,7 @@ module Expect4r
|
|
150
151
|
end
|
151
152
|
|
152
153
|
def interact(k=?\C-z)
|
154
|
+
login unless connected?
|
153
155
|
STDOUT.puts "\n\#\n\# #{ctrl_key k} to terminate.\n\#\n"
|
154
156
|
reader :start
|
155
157
|
writer k
|
@@ -202,14 +204,25 @@ module Expect4r
|
|
202
204
|
@r && (not child_exited?)
|
203
205
|
end
|
204
206
|
|
205
|
-
def
|
207
|
+
def login_by_proxy(proxy)
|
208
|
+
raise ArgumentError, "Don't know how to login to #{proxy}" unless proxy.respond_to? :_login_
|
209
|
+
_login_ :proxy=> proxy
|
210
|
+
end
|
211
|
+
alias :login_via :login_by_proxy
|
212
|
+
|
213
|
+
def login(cmd, arg={})
|
214
|
+
|
206
215
|
return if connected?
|
207
216
|
|
208
|
-
|
217
|
+
if arg[:proxy]
|
218
|
+
login_proxy cmd, arg
|
219
|
+
else
|
220
|
+
spawn cmd
|
221
|
+
end
|
209
222
|
|
210
|
-
|
211
|
-
timeout =
|
212
|
-
no_echo =
|
223
|
+
arg={:timeout=>13, :no_echo=>false}.merge(arg)
|
224
|
+
timeout = arg[:timeout]
|
225
|
+
no_echo = arg[:no_echo]
|
213
226
|
|
214
227
|
output=[]
|
215
228
|
t0 = Time.now
|
@@ -223,7 +236,9 @@ module Expect4r
|
|
223
236
|
when spawnee_prompt
|
224
237
|
read_pipe._io_save false, "match PROMPT"
|
225
238
|
throw(:done, [:ok, output])
|
226
|
-
when /(
|
239
|
+
when /Last (L|l)ogin:/
|
240
|
+
read_pipe._io_save no_echo # consumes
|
241
|
+
when /(user\s*name\s*|login):\s*$/i
|
227
242
|
read_pipe._io_save no_echo, "match USERNAME"
|
228
243
|
exp_puts spawnee_username
|
229
244
|
when /password:\s*$/i
|
@@ -235,6 +250,9 @@ module Expect4r
|
|
235
250
|
when /.*\r\n/
|
236
251
|
exp_internal "match EOL"
|
237
252
|
read_pipe._io_save no_echo, "match EOL", "\r\n"
|
253
|
+
when /Are you sure you want to continue connecting \(yes\/no\)\?/
|
254
|
+
read_pipe._io_save no_echo, "match continue connecting"
|
255
|
+
exp_puts 'yes'
|
238
256
|
end
|
239
257
|
end
|
240
258
|
end
|
@@ -243,18 +261,24 @@ module Expect4r
|
|
243
261
|
elapsed = Time.now - t0
|
244
262
|
if elapsed < timeout
|
245
263
|
child_exit
|
246
|
-
raise ConnectionError.new(
|
264
|
+
raise ConnectionError.new(cmd)
|
247
265
|
else
|
248
|
-
raise ExpTimeoutError.new(
|
266
|
+
raise ExpTimeoutError.new(cmd, timeout)
|
249
267
|
end
|
250
268
|
else
|
251
269
|
@lp = buf.last
|
252
270
|
end
|
253
271
|
[buf, ev]
|
254
|
-
|
255
272
|
end
|
256
273
|
|
257
274
|
private
|
275
|
+
|
276
|
+
def login_proxy(cmd, arg)
|
277
|
+
@proxy = arg[:proxy].dup
|
278
|
+
@proxy.login
|
279
|
+
@proxy.exp_puts cmd
|
280
|
+
@r, @w, @pid = @proxy.instance_eval { [@r, @w, @pid] }
|
281
|
+
end
|
258
282
|
|
259
283
|
#FIXME ? putline to send_cmd ?
|
260
284
|
# hide putline and expose cmd
|
@@ -407,7 +431,7 @@ module Kernel
|
|
407
431
|
end
|
408
432
|
|
409
433
|
module Expect4r
|
410
|
-
class
|
434
|
+
class BaseLoginObject
|
411
435
|
class << self
|
412
436
|
def new_telnet(*args)
|
413
437
|
new :telnet, *args
|
@@ -421,11 +445,26 @@ module Expect4r
|
|
421
445
|
@routers << r
|
422
446
|
end
|
423
447
|
end
|
424
|
-
attr_reader :host, :user, :method, :port
|
448
|
+
attr_reader :host, :user, :method, :port, :proxy
|
425
449
|
alias :username :user
|
426
450
|
alias :hostname :host
|
451
|
+
# Adds a login to a Expect4r::BaseLoginObject"
|
452
|
+
#
|
453
|
+
# Constructor:
|
454
|
+
# * <tt>new</tt> <method>, <username>, <password>, [port_number]
|
455
|
+
# * <tt>new</tt> <method>, options={}
|
456
|
+
#
|
457
|
+
# Options are:
|
458
|
+
# * <tt>:host</tt> or <tt>:hostname</tt>
|
459
|
+
# * <tt>:user</tt> or <tt>:username</tt>
|
460
|
+
# * <tt>:pwd</tt> or <tt>:password</tt>
|
461
|
+
#
|
462
|
+
# Examples:
|
463
|
+
# new :telnet, :user=> 'lab', :password=>'lab'
|
464
|
+
# new :ssh, :user=> 'jme'
|
465
|
+
#
|
427
466
|
def initialize(*args)
|
428
|
-
|
467
|
+
ciphered_password=nil
|
429
468
|
if args.size>2 and args[1].is_a?(String)
|
430
469
|
@method, host, @user, pwd = args
|
431
470
|
elsif args.size == 2 and args[1].is_a?(Hash) and args[0].is_a?(Symbol)
|
@@ -433,29 +472,62 @@ module Expect4r
|
|
433
472
|
host = args[1][:host] || args[1][:hostname]
|
434
473
|
@user = args[1][:user]|| args[1][:username]
|
435
474
|
pwd = args[1][:pwd] || args[1][:password]
|
436
|
-
|
475
|
+
ciphered_password = args[1][:ciphered_password]
|
437
476
|
end
|
438
477
|
@host, port = host.split
|
439
478
|
@port = port.to_i
|
440
|
-
@pwd = if
|
441
|
-
|
479
|
+
@pwd = if ciphered_password
|
480
|
+
ciphered_password
|
442
481
|
else
|
443
482
|
Expect4r.cipher(pwd) if pwd
|
444
483
|
end
|
445
484
|
@ps1 = /(.*)(>|#|\$)\s*$/
|
446
485
|
@more = / --More-- /
|
447
486
|
@matches=Set.new
|
448
|
-
|
487
|
+
BaseLoginObject.add(self)
|
449
488
|
self
|
450
489
|
end
|
490
|
+
|
491
|
+
def spawnee
|
492
|
+
case method
|
493
|
+
when :telnet ; "telnet #{host} #{port if port>0}"
|
494
|
+
when :ssh ; "ssh #{spawnee_username}@#{host}"
|
495
|
+
else
|
496
|
+
raise RuntimeError
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
def spawnee_username
|
501
|
+
@user
|
502
|
+
end
|
503
|
+
|
504
|
+
def spawnee_prompt
|
505
|
+
@ps1
|
506
|
+
end
|
507
|
+
|
508
|
+
def dup
|
509
|
+
if @pwd
|
510
|
+
self.class.new @method, @host, @user, Expect4r.decipher(@pwd)
|
511
|
+
else
|
512
|
+
self.class.new @method, @host, @user
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
private
|
517
|
+
|
518
|
+
def spawnee_password
|
519
|
+
@pwd = Expect4r.cipher( ask("(#{self}) Enter your password: ") { |q| q.echo = "X" } ) unless @pwd
|
520
|
+
Expect4r.decipher(@pwd)
|
521
|
+
end
|
522
|
+
|
451
523
|
end
|
452
524
|
end
|
453
525
|
|
454
526
|
if __FILE__ != $0
|
455
527
|
|
456
528
|
at_exit {
|
457
|
-
if Expect4r::
|
458
|
-
Expect4r::
|
529
|
+
if Expect4r::BaseLoginObject.routers
|
530
|
+
Expect4r::BaseLoginObject.routers.each { |r| r.logout if r.respond_to? :logout }
|
459
531
|
end
|
460
532
|
}
|
461
533
|
|
@@ -463,21 +535,21 @@ else
|
|
463
535
|
|
464
536
|
require "test/unit"
|
465
537
|
|
466
|
-
class Expect4r::
|
538
|
+
class Expect4r::BaseLoginObject
|
467
539
|
def initialize
|
468
|
-
Expect4r::
|
540
|
+
Expect4r::BaseLoginObject.add(self)
|
469
541
|
end
|
470
542
|
end
|
471
543
|
|
472
|
-
class
|
544
|
+
class TestRouterBaseLoginObject < Test::Unit::TestCase
|
473
545
|
include Expect4r
|
474
546
|
|
475
547
|
def test_add
|
476
|
-
assert [],
|
477
|
-
|
478
|
-
assert 1,
|
479
|
-
|
480
|
-
assert_equal 2,
|
548
|
+
assert [], BaseLoginObject.routers
|
549
|
+
BaseLoginObject.new
|
550
|
+
assert 1, BaseLoginObject.routers.size
|
551
|
+
BaseLoginObject.new
|
552
|
+
assert_equal 2, BaseLoginObject.routers.size
|
481
553
|
end
|
482
554
|
end
|
483
555
|
|
data/lib/expect4r.rb
CHANGED
@@ -7,6 +7,7 @@ module Expect4r
|
|
7
7
|
autoload :Ios, 'router/cisco/ios/ios'
|
8
8
|
autoload :J, 'router/juniper/junos/junos'
|
9
9
|
autoload :Shell, 'misc/shell'
|
10
|
+
autoload :RShell, 'misc/shell'
|
10
11
|
|
11
12
|
module Router
|
12
13
|
autoload :Common, 'router/common'
|
@@ -33,6 +34,7 @@ module Expect4r
|
|
33
34
|
module Junos
|
34
35
|
autoload :Modes, 'router/juniper/junos/modes'
|
35
36
|
autoload :Show, 'router/juniper/junos/show'
|
37
|
+
autoload :Ping, 'router/juniper/junos/ping'
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
data/lib/misc/shell.rb
CHANGED
@@ -1,7 +1,4 @@
|
|
1
|
-
require 'expect/io'
|
2
|
-
|
3
1
|
module Expect4r
|
4
|
-
|
5
2
|
class Shell
|
6
3
|
include Expect4r
|
7
4
|
def initialize()
|
@@ -15,5 +12,44 @@ module Expect4r
|
|
15
12
|
spawn @shell
|
16
13
|
end
|
17
14
|
end
|
15
|
+
class RShell < ::Expect4r::BaseLoginObject
|
16
|
+
include Expect4r
|
17
|
+
def initialize(*args)
|
18
|
+
super
|
19
|
+
default_ps1
|
20
|
+
end
|
21
|
+
def logout
|
22
|
+
default_ps1
|
23
|
+
super
|
24
|
+
end
|
25
|
+
def login(arg={})
|
26
|
+
super(spawnee, arg)
|
27
|
+
cmd %{export COLUMNS=1024}
|
28
|
+
end
|
29
|
+
# FIXME: 1.9.2 bug:
|
30
|
+
# It calls LoginBaseOject#login() instead of calling J#login()
|
31
|
+
# modified login_by_proxy to call _login_ seems to work.
|
32
|
+
alias :_login_ :login
|
33
|
+
|
34
|
+
def ps1=(val)
|
35
|
+
# Assumes bash
|
36
|
+
@ps1_bis = /#{val}$/
|
37
|
+
cmd %? export PS1='#{val}' ?
|
38
|
+
@ps1 = @ps1_bi
|
39
|
+
end
|
40
|
+
def cmd(*args)
|
41
|
+
exp_send *args
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def default_ps1
|
47
|
+
@ps1 = /.+[^\#](\#|\$)\s+$/
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
__END__
|
53
|
+
|
18
54
|
|
19
|
-
|
55
|
+
cmd %? PROMPT_COMMAND="echo -n [$(date +%k:%m:%S)]: && pwd" && export PS1='#{val}' ?
|
@@ -2,6 +2,16 @@
|
|
2
2
|
module Expect4r::Router
|
3
3
|
module CiscoCommon
|
4
4
|
|
5
|
+
#
|
6
|
+
# Returns the config level depths:
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# iox(config-ospf-ar)#
|
11
|
+
#
|
12
|
+
# irb> iox.config_lvl?
|
13
|
+
# => 3
|
14
|
+
#
|
5
15
|
def config_lvl?
|
6
16
|
return -1 unless config?
|
7
17
|
@lp =~ /\(config(|.+)\)/
|
@@ -4,6 +4,29 @@ module Expect4r::Router::CiscoCommon
|
|
4
4
|
module Ping
|
5
5
|
include ::Expect4r::Router::Error
|
6
6
|
|
7
|
+
# Adds a <tt>ping</tt> method to <tt>CiscoCommon::Ping mixin</tt>:
|
8
|
+
#
|
9
|
+
# Options are:
|
10
|
+
# * <tt>:protocol</tt>
|
11
|
+
# * <tt>:repeat_count</tt> or <tt>:count</tt>
|
12
|
+
# * <tt>:datagram_size</tt> or <tt>:size</tt>
|
13
|
+
# * <tt>:timeout</tt>
|
14
|
+
# * <tt>:source_address</tt>
|
15
|
+
# * <tt>:tos</tt>
|
16
|
+
# * <tt>:df</tt>
|
17
|
+
# * <tt>:pattern</tt>
|
18
|
+
# * <tt>:sweep_min_size</tt>
|
19
|
+
# * <tt>:sweep_max_size</tt>
|
20
|
+
# * <tt>:sweep_interval</tt>
|
21
|
+
# * <tt>:pct_success</tt> - default is 99.
|
22
|
+
#
|
23
|
+
# Option examples:
|
24
|
+
# :protocol => 'ipv4'
|
25
|
+
# :count => 10
|
26
|
+
# :timeout => 1
|
27
|
+
# :size=> 512
|
28
|
+
# :protocol=> 'ipv4', :count=> 20, :size=> 1500, :timeout=>5
|
29
|
+
#
|
7
30
|
def ping(target_ip_address, arg={})
|
8
31
|
|
9
32
|
pct_success = arg.delete(:pct_success) || 99
|
@@ -98,11 +121,3 @@ private
|
|
98
121
|
end
|
99
122
|
end
|
100
123
|
|
101
|
-
__END__
|
102
|
-
|
103
|
-
p.ping '192.168.1.23'
|
104
|
-
p.ping '192.168.1.23', :sweep_max_size=> 1512, :pct_success => 95
|
105
|
-
p.ping '192.168.1.23', :source_address => '192.168.1.199', :count=> 100, :pct_success=> 90
|
106
|
-
|
107
|
-
puts output[2][0].join("\n").split(": \n").join(": ")
|
108
|
-
|
data/lib/router/cisco/ios/ios.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'router/cisco/common/common'
|
2
2
|
|
3
|
-
class Expect4r::Ios < ::Expect4r::
|
3
|
+
class Expect4r::Ios < ::Expect4r::BaseLoginObject
|
4
4
|
|
5
5
|
include Expect4r
|
6
6
|
include Expect4r::Router::Common
|
@@ -33,12 +33,17 @@ class Expect4r::Ios < ::Expect4r::BaseObject
|
|
33
33
|
Expect4r.decipher(@pwd) # password is ciphered ...
|
34
34
|
end
|
35
35
|
|
36
|
-
def login
|
37
|
-
super(spawnee)
|
36
|
+
def login(arg={})
|
37
|
+
super(spawnee,arg)
|
38
38
|
enable
|
39
39
|
exec "term len 0\nterm width 0"
|
40
40
|
self
|
41
41
|
end
|
42
|
+
# FIXME: 1.9.2 bug:
|
43
|
+
# It calls LoginBaseOject#login() instead of calling J#login()
|
44
|
+
# modified login_by_proxy to call _login_ seems to work.
|
45
|
+
alias :_login_ :login
|
46
|
+
|
42
47
|
|
43
48
|
def putline(line,*args)
|
44
49
|
output, rc = super
|
@@ -3,6 +3,10 @@ require 'router/modes'
|
|
3
3
|
module Expect4r::Router::Ios
|
4
4
|
module Modes
|
5
5
|
|
6
|
+
# Adds a <tt>in?</tt> mixin.
|
7
|
+
#
|
8
|
+
# Returns the mode the router is in: :user, :exec, :config
|
9
|
+
#
|
6
10
|
def in?(mode=:none)
|
7
11
|
login unless connected?
|
8
12
|
case mode
|
@@ -61,10 +65,16 @@ module Modes
|
|
61
65
|
@lp =~ /\(config(|.+)\)/
|
62
66
|
end
|
63
67
|
|
68
|
+
#
|
69
|
+
# returns <tt>true</tt> if router is in <tt>:exec</tt> (enabled) mode, <tt>false</tt> otherwise.
|
70
|
+
#
|
64
71
|
def exec?
|
65
72
|
! user? and ! config?
|
66
73
|
end
|
67
74
|
|
75
|
+
#
|
76
|
+
# returns <tt>true</tt> if router is in <tt>:user</tt> mode, <tt>false</tt> otherwise.
|
77
|
+
#
|
68
78
|
def user?
|
69
79
|
@lp =~ /.+>\s*$/
|
70
80
|
end
|
data/lib/router/cisco/iox/iox.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
require 'router/cisco/common/common'
|
3
3
|
|
4
|
-
class Expect4r::Iox < ::Expect4r::
|
4
|
+
class Expect4r::Iox < ::Expect4r::BaseLoginObject
|
5
5
|
|
6
6
|
include Expect4r
|
7
7
|
include Expect4r::Router
|
@@ -18,12 +18,16 @@ class Expect4r::Iox < ::Expect4r::BaseObject
|
|
18
18
|
@more = / --More-- /
|
19
19
|
end
|
20
20
|
|
21
|
-
def login
|
22
|
-
super(spawnee)
|
21
|
+
def login(arg={})
|
22
|
+
super(spawnee, arg)
|
23
23
|
config 'no logging console' if port>0
|
24
24
|
exec "terminal len 0\nterminal width 0"
|
25
25
|
self
|
26
26
|
end
|
27
|
+
# FIXME: 1.9.2 bug:
|
28
|
+
# It calls LoginBaseOject#login() instead of calling J#login()
|
29
|
+
# modified login_by_proxy to call _login_ seems to work.
|
30
|
+
alias :_login_ :login
|
27
31
|
|
28
32
|
def commit(arg={})
|
29
33
|
return unless config?
|
@@ -3,6 +3,19 @@ require 'router/modes'
|
|
3
3
|
module Expect4r::Router::Iox
|
4
4
|
module Modes
|
5
5
|
|
6
|
+
# Adds an Iox <tt>config>/tt> mixin.
|
7
|
+
#
|
8
|
+
# Options are:
|
9
|
+
#
|
10
|
+
# Option examples:
|
11
|
+
#
|
12
|
+
# iox.config %{
|
13
|
+
# interface GigabitEthernet0/2/0/0
|
14
|
+
# desc to switch port 13'
|
15
|
+
# ipv4 address 190.0.0.9 255.255.255.252'
|
16
|
+
# no shut'
|
17
|
+
# }
|
18
|
+
#
|
6
19
|
def config(config=nil, arg={})
|
7
20
|
login unless connected?
|
8
21
|
if config
|
@@ -0,0 +1,55 @@
|
|
1
|
+
|
2
|
+
__END__
|
3
|
+
|
4
|
+
RP/0/0/CPU0:Paris-rp0#ping ipv4 1.1.1.1 count 5 ?
|
5
|
+
donotfrag set DF bit in IP header
|
6
|
+
pattern data pattern
|
7
|
+
size datagram size
|
8
|
+
source source address or source interface
|
9
|
+
sweep sweep ping
|
10
|
+
timeout timeout in seconds
|
11
|
+
type type of service
|
12
|
+
validate validate return packet
|
13
|
+
verbose verbose output
|
14
|
+
<cr>
|
15
|
+
RP/0/0/CPU0:Paris-rp0#ping ipv4 1.1.1.1 count 5 size ?
|
16
|
+
<36-18024> datagram size
|
17
|
+
RP/0/0/CPU0:Paris-rp0#ping ipv4 1.1.1.1 count 5 size 100 ?
|
18
|
+
donotfrag set DF bit in IP header
|
19
|
+
pattern data pattern
|
20
|
+
source source address or source interface
|
21
|
+
sweep sweep ping
|
22
|
+
timeout timeout in seconds
|
23
|
+
type type of service
|
24
|
+
validate validate return packet
|
25
|
+
verbose verbose output
|
26
|
+
<cr>
|
27
|
+
RP/0/0/CPU0:Paris-rp0#ping ipv4 1.1.1.1 count 5 size 100 donotfrag ?
|
28
|
+
pattern data pattern
|
29
|
+
source source address or source interface
|
30
|
+
sweep sweep ping
|
31
|
+
timeout timeout in seconds
|
32
|
+
type type of service
|
33
|
+
validate validate return packet
|
34
|
+
verbose verbose output
|
35
|
+
<cr>
|
36
|
+
RP/0/0/CPU0:Paris-rp0#ping ipv4 1.1.1.1 count 5 size 100 donotfrag pattern ?
|
37
|
+
<0-65535> data pattern
|
38
|
+
RP/0/0/CPU0:Paris-rp0#ping ipv4 1.1.1.1 count 5 size 100 donotfrag pattern 0xdead type 2 ?
|
39
|
+
source source address or source interface
|
40
|
+
sweep sweep ping
|
41
|
+
timeout timeout in seconds
|
42
|
+
validate validate return packet
|
43
|
+
verbose verbose output
|
44
|
+
<cr>
|
45
|
+
RP/0/0/CPU0:Paris-rp0#ping ipv4 1.1.1.1 count 5 size 100 donotfrag pattern 0xdead type 2 timeout 10 sweep ?
|
46
|
+
source source address or source interface
|
47
|
+
validate validate return packet
|
48
|
+
verbose verbose output
|
49
|
+
<cr>
|
50
|
+
RP/0/0/CPU0:Paris-rp0#ping ipv4 1.1.1.1 count 5 size 100 donotfrag pattern 0xdead type 2 timeout 10 sweep ?
|
51
|
+
source source address or source interface
|
52
|
+
validate validate return packet
|
53
|
+
verbose verbose output
|
54
|
+
<cr>
|
55
|
+
RP/0/0/CPU0:Paris-rp0#
|
data/lib/router/common.rb
CHANGED
@@ -14,29 +14,5 @@ module Common
|
|
14
14
|
putc "\n" if console?
|
15
15
|
end
|
16
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
17
|
end
|
42
18
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class Expect4r::J < ::Expect4r::
|
1
|
+
class Expect4r::J < ::Expect4r::BaseLoginObject
|
2
2
|
include Expect4r
|
3
3
|
include Expect4r::Router::Error
|
4
4
|
include Expect4r::Router::Common
|
@@ -13,12 +13,15 @@ class Expect4r::J < ::Expect4r::BaseObject
|
|
13
13
|
@more = /---\(more(| \d+\%)\)---/
|
14
14
|
end
|
15
15
|
|
16
|
-
def login
|
17
|
-
|
18
|
-
super(spawnee)
|
16
|
+
def login(arg={})
|
17
|
+
super(spawnee, arg)
|
19
18
|
exec 'set cli screen-length 0'
|
20
19
|
self
|
21
20
|
end
|
21
|
+
# FIXME: 1.9.2 bug:
|
22
|
+
# It calls LoginBaseOject#login() instead of calling J#login()
|
23
|
+
# modified login_by_proxy to call _login_ seems to work.
|
24
|
+
alias :_login_ :login
|
22
25
|
|
23
26
|
def console?
|
24
27
|
@port>0
|
@@ -3,6 +3,18 @@ require 'router/modes'
|
|
3
3
|
module Expect4r::Router::Junos
|
4
4
|
module Modes
|
5
5
|
|
6
|
+
# Adds a Junos <tt>config</tt> mixin.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# j.config %{
|
11
|
+
# edit logical-router Orleans protocols bgp
|
12
|
+
# edit group session-to-200
|
13
|
+
# set type external
|
14
|
+
# set peer-as 200
|
15
|
+
# set neighbor 40.0.2.1 peer-as 200
|
16
|
+
# }
|
17
|
+
#
|
6
18
|
def config(stmts=nil, arg={})
|
7
19
|
login unless connected?
|
8
20
|
if stmts
|
@@ -13,10 +25,16 @@ def config(stmts=nil, arg={})
|
|
13
25
|
change_mode_to(mode)
|
14
26
|
output
|
15
27
|
else
|
16
|
-
|
28
|
+
to_config
|
17
29
|
end
|
18
30
|
end
|
19
31
|
|
32
|
+
# Adds a Junos <tt>exec</tt> mixin.
|
33
|
+
#
|
34
|
+
# Example:
|
35
|
+
#
|
36
|
+
# j.exec 'set cli screen-length 0'
|
37
|
+
#
|
20
38
|
def exec(cmd=nil, *args)
|
21
39
|
login unless connected?
|
22
40
|
if cmd.nil?
|
@@ -50,14 +68,23 @@ def shell(cmd=nil, *args)
|
|
50
68
|
end
|
51
69
|
end
|
52
70
|
|
71
|
+
#
|
72
|
+
# returns <tt>true</tt> if router is in <tt>:exec</tt> mode, <tt>false</tt> otherwise.
|
73
|
+
#
|
53
74
|
def exec?
|
54
75
|
@lp =~ /> $/ ? true : false
|
55
76
|
end
|
56
77
|
|
78
|
+
#
|
79
|
+
# returns <tt>true</tt> if router is in <tt>:config</tt> mode, <tt>false</tt> otherwise.
|
80
|
+
#
|
57
81
|
def config?
|
58
82
|
@lp =~ /^.+# $/ ? true : false
|
59
83
|
end
|
60
84
|
|
85
|
+
#
|
86
|
+
# returns <tt>true</tt> if router is in <tt>:shell</tt> mode, <tt>false</tt> otherwise.
|
87
|
+
#
|
61
88
|
def shell?
|
62
89
|
@lp == '% ' ? true : false
|
63
90
|
end
|
@@ -3,6 +3,24 @@ require 'router/error'
|
|
3
3
|
module Expect4r::Router::Junos
|
4
4
|
module Ping
|
5
5
|
|
6
|
+
# Adds a ping method to J class:
|
7
|
+
#
|
8
|
+
# Options are:
|
9
|
+
# * <tt>:count</tt> or <tt>:repeat_count</tt>
|
10
|
+
# * <tt>:size</tt> or <tt>:datagram_size</tt>
|
11
|
+
# * <tt>:datagram_size</tt> or <tt>:size</tt>
|
12
|
+
# * <tt>:timeout</tt>
|
13
|
+
# * <tt>:tos</tt>
|
14
|
+
# * <tt>:ttl</tt>
|
15
|
+
# * <tt>:pattern</tt>
|
16
|
+
# * <tt>:pct_success</tt> - default is 99.
|
17
|
+
#
|
18
|
+
# Option examples:
|
19
|
+
# :count => 10
|
20
|
+
# :timeout => 1
|
21
|
+
# :size=> 512
|
22
|
+
# :protocol=> 'ipv4', :count=> 20, :size=> 1500, :timeout=>5, :ttl=>16
|
23
|
+
#
|
6
24
|
def ping(host, arg={})
|
7
25
|
|
8
26
|
pct_success = arg.delete(:pct_success) || 99
|
data/lib/router/modes.rb
CHANGED
@@ -2,6 +2,21 @@ module Expect4r
|
|
2
2
|
module Router
|
3
3
|
module Common
|
4
4
|
module Modes
|
5
|
+
|
6
|
+
# Adds a <tt>in?</tt> mixin.
|
7
|
+
#
|
8
|
+
# Examples:
|
9
|
+
#
|
10
|
+
# irb(main):007:0> iox.in?
|
11
|
+
# => :exec
|
12
|
+
# irb(main):008:0> iox.config
|
13
|
+
# => :config
|
14
|
+
# irb(main):009:0> iox.in?
|
15
|
+
# => :config
|
16
|
+
# irb(main):010:0> iox.shell
|
17
|
+
# => :shell
|
18
|
+
# irb(main):011:0> iox.in?
|
19
|
+
# => :shell
|
5
20
|
def in?(mode=:none)
|
6
21
|
login unless connected?
|
7
22
|
case mode
|
metadata
CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- dev
|
10
|
-
version: 0.0.
|
10
|
+
version: 0.0.3.dev
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jean-Michel Esnault
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-10-
|
18
|
+
date: 2010-10-27 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: 1.5.0
|
33
33
|
type: :runtime
|
34
34
|
version_requirements: *id001
|
35
|
-
description: A Ruby Library for interacting with IOS, IOS-XR, and JUNOS
|
35
|
+
description: A Ruby Library for interacting with IOS, IOS-XR, and JUNOS CLI.
|
36
36
|
email: jesnault@gmail.com
|
37
37
|
executables: []
|
38
38
|
|
@@ -57,6 +57,7 @@ files:
|
|
57
57
|
- lib/router/cisco/ios/termserver.rb
|
58
58
|
- lib/router/cisco/iox/iox.rb
|
59
59
|
- lib/router/cisco/iox/modes.rb
|
60
|
+
- lib/router/cisco/iox/ping.rb
|
60
61
|
- lib/router/common.rb
|
61
62
|
- lib/router/error.rb
|
62
63
|
- lib/router/juniper/junos/junos.rb
|