expect4r 0.0.3.dev → 0.0.4.dev

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -14,7 +14,13 @@ You talk to routers by connecting to them using ssh or telnet and send exec or c
14
14
 
15
15
  j = J.new_telnet :host=> '', :user=> 'lab', :pwd => 'lab'
16
16
  j.login
17
-
17
+
18
+ * Connect to a box via another
19
+
20
+ my_mac = RShell.new_ssh 'mac', 'me'
21
+ router = Iox.new_telnet 'hostname', 'username'
22
+ router.login_via my_mac
23
+
18
24
  * Push configurations to routers
19
25
 
20
26
  ios.config 'no logging console'
@@ -118,7 +124,7 @@ You talk to routers by connecting to them using ssh or telnet and send exec or c
118
124
  output[n-1] contains output for nth command.
119
125
 
120
126
 
121
- * Ping
127
+ * Ios Ping
122
128
 
123
129
  irb(main):016:0> ios.ping '192.168.1.23', :count=> 100, :pct_success=>90, :sweep_max_size=> 1500
124
130
  => [ 99, [146148, 146500],
@@ -144,6 +150,8 @@ You talk to routers by connecting to them using ssh or telnet and send exec or c
144
150
  "ios#"]]]
145
151
 
146
152
 
153
+ * Iox ping
154
+
147
155
  irb> iox.ping '192.168.1.100'
148
156
  => [100, [5, 5],
149
157
  [["ping 192.168.1.100",
@@ -178,3 +186,16 @@ You talk to routers by connecting to them using ssh or telnet and send exec or c
178
186
  "Success rate is 100 percent (1505/1505), round-trip min/avg/max = 1/1/3 ms",
179
187
  "RP/0/0/CPU0:Paris-rp0#"]]]
180
188
 
189
+
190
+ * Junos ping
191
+
192
+ irb> j.ping '192.168.1.123'
193
+ => [5, [5, 0],
194
+ [["ping 192.168.1.123 rapid ",
195
+ "PING 192.168.1.123 (192.168.1.123): 56 data bytes",
196
+ "!!!!!",
197
+ "--- 192.168.1.123 ping statistics ---",
198
+ "5 packets transmitted, 5 packets received, 0% packet loss",
199
+ "round-trip min/avg/max/stddev = 2.310/2.943/4.390/0.753 ms",
200
+ "",
201
+ junos> "]]]
data/examples/jex1.rb ADDED
@@ -0,0 +1,104 @@
1
+ require 'expect4r'
2
+ require "enumerator"
3
+ include Expect4r
4
+ include Expect4r::Router::Error
5
+
6
+ paris_config = %|
7
+ top
8
+ edit logical-router Paris interface fxp0 unit 25
9
+ set vlan-id 25
10
+ set family inet address 40.0.1.1/24
11
+ top
12
+ edit logical-router Paris interface fxp1 unit 22
13
+ set vlan-id 22
14
+ set family inet address 40.0.2.1/24
15
+ top
16
+ edit logical-router Paris interface lo0 unit 1
17
+ set family inet address 192.168.127.1/32
18
+ top
19
+ edit logical-router Paris interface fxp0 unit 24
20
+ set vlan-id 24
21
+ set family inet address 40.0.0.2/24
22
+ top
23
+ edit logical-router Paris
24
+ set routing-options autonomous-system 200
25
+ top
26
+ edit logical-router Paris protocols bgp
27
+ edit group session-to-300
28
+ set type external
29
+ set peer-as 300
30
+ set neighbor 40.0.1.2 peer-as 300
31
+ exit
32
+ edit group session-to-210
33
+ set type external
34
+ set peer-as 210
35
+ set neighbor 40.0.2.2 peer-as 210
36
+ exit
37
+ edit group session-to-100
38
+ set type external
39
+ set peer-as 100
40
+ set neighbor 40.0.0.1 peer-as 100
41
+ |
42
+
43
+ orleans_config = %|
44
+ top
45
+ edit logical-router Orleans interface fxp2 unit 22
46
+ set vlan-id 22
47
+ set family inet address 40.0.2.2/24
48
+ top
49
+ edit logical-router Orleans
50
+ set routing-options autonomous-system 100
51
+ top
52
+ edit logical-router Orleans protocols bgp
53
+ edit group session-to-200
54
+ set type external
55
+ set peer-as 200
56
+ set neighbor 40.0.2.1 peer-as 200
57
+ |
58
+
59
+ begin
60
+
61
+ paris = J.new_telnet('olive', 'jme').login
62
+ orleans = J.new_telnet('olive', 'jme').login
63
+
64
+ threads =[]
65
+ threads << Thread.new { paris.config paris_config }
66
+ threads << Thread.new { p orleans.config orleans_config }
67
+ threads.each { |th| th.join }
68
+
69
+ rescue ConnectionError => e
70
+
71
+ p 'CONNECTION ERROR'
72
+
73
+ puts e.err_msg
74
+
75
+ rescue SyntaxError, SemanticError => e
76
+
77
+ p 'CONFIG ERROR'
78
+ puts e.err_msg
79
+
80
+ else
81
+
82
+ begin
83
+
84
+ paris.ping '40.0.2.1', :logical_router=>'Paris', :count=>100
85
+ orleans.ping '40.0.2.2', :logical_router=>'Orleans', :count=>100
86
+
87
+ rescue PingError => e
88
+
89
+ p 'PING ERROR'
90
+ puts e.err_msg
91
+
92
+ end
93
+
94
+ ensure
95
+
96
+ [paris, orleans].each { |r| r.logout }
97
+
98
+ end
99
+
100
+
101
+
102
+
103
+
104
+
data/examples/jex2.rb ADDED
@@ -0,0 +1,88 @@
1
+ require "test/unit"
2
+ require 'expect4r'
3
+
4
+ class TestPingTest < Test::Unit::TestCase
5
+ include Expect4r
6
+ include Expect4r::Router::Error
7
+
8
+ def setup
9
+
10
+ paris_config = %|
11
+ top
12
+ edit logical-router Paris interface fxp0 unit 25
13
+ set vlan-id 25
14
+ set family inet address 40.0.1.1/24
15
+ top
16
+ edit logical-router Paris interface fxp1 unit 22
17
+ set vlan-id 22
18
+ set family inet address 40.0.2.1/24
19
+ top
20
+ edit logical-router Paris interface lo0 unit 1
21
+ set family inet address 192.168.127.1/32
22
+ top
23
+ edit logical-router Paris interface fxp0 unit 24
24
+ set vlan-id 24
25
+ set family inet address 40.0.0.2/24
26
+ top
27
+ edit logical-router Paris
28
+ set routing-options autonomous-system 200
29
+ top
30
+ edit logical-router Paris protocols bgp
31
+ edit group session-to-300
32
+ set type external
33
+ set peer-as 300
34
+ set neighbor 40.0.1.2 peer-as 300
35
+ exit
36
+ edit group session-to-210
37
+ set type external
38
+ set peer-as 210
39
+ set neighbor 40.0.2.2 peer-as 210
40
+ exit
41
+ edit group session-to-100
42
+ set type external
43
+ set peer-as 100
44
+ set neighbor 40.0.0.1 peer-as 100
45
+ |
46
+
47
+ orleans_config = %|
48
+ top
49
+ edit logical-router Orleans interface fxp2 unit 22
50
+ set vlan-id 22
51
+ set family inet address 40.0.2.2/24
52
+ top
53
+ edit logical-router Orleans
54
+ set routing-options autonomous-system 100
55
+ top
56
+ edit logical-router Orleans protocols bgp
57
+ edit group session-to-200
58
+ set type external
59
+ set peer-as 200
60
+ set neighbor 40.0.2.1 peer-as 200
61
+ |
62
+
63
+ @paris = J.new_ssh('olive', 'jesnault', 'HomeLab').login
64
+ @orleans = J.new_ssh('olive', 'jesnault', 'HomeLab').login
65
+ threads =[]
66
+ threads << Thread.new { @paris.config paris_config }
67
+ threads << Thread.new { @orleans.config orleans_config }
68
+ threads.each { |th| th.join }
69
+
70
+ end
71
+
72
+ def teardown
73
+ @paris.config "delete logical-routers"
74
+ [@paris, @orleans].each { |r| r.logout }
75
+ end
76
+
77
+ def test_ping_test
78
+ assert_nothing_raised(Exception) {
79
+ threads =[]
80
+ threads << Thread.new { @paris.ping '40.0.2.1', :logical_router=>'Paris', :count=>100 }
81
+ threads << Thread.new { @orleans.ping '40.0.2.2', :logical_router=>'Orleans', :count=>100 }
82
+ threads.each { |th| th.join }
83
+ }
84
+
85
+ end
86
+
87
+ end
88
+
data/lib/expect/io.rb CHANGED
@@ -230,12 +230,12 @@ module Expect4r
230
230
  @r.readbuf(timeout) do |read_pipe|
231
231
  if read_pipe._io_exit?
232
232
  exp_internal "readbuf: _io_exit?"
233
- throw :done, [ :abort, output]
233
+ throw :done, [ :cnx_error, read_pipe._io_buf1]
234
234
  end
235
235
  case read_pipe._io_string
236
236
  when spawnee_prompt
237
- read_pipe._io_save false, "match PROMPT"
238
- throw(:done, [:ok, output])
237
+ read_pipe._io_save no_echo, "match PROMPT"
238
+ throw(:done, [:ok, read_pipe._io_buf1])
239
239
  when /Last (L|l)ogin:/
240
240
  read_pipe._io_save no_echo # consumes
241
241
  when /(user\s*name\s*|login):\s*$/i
@@ -249,22 +249,22 @@ module Expect4r
249
249
  io_escape_char_cb
250
250
  when /.*\r\n/
251
251
  exp_internal "match EOL"
252
- read_pipe._io_save no_echo, "match EOL", "\r\n"
252
+ read_pipe._io_save no_echo, "match EOL"
253
253
  when /Are you sure you want to continue connecting \(yes\/no\)\?/
254
254
  read_pipe._io_save no_echo, "match continue connecting"
255
255
  exp_puts 'yes'
256
+ when /(Login incorrect|denied, please try again)/
257
+ spawnee_reset
256
258
  end
257
259
  end
258
260
  end
259
261
  case ev
260
- when :abort
261
- elapsed = Time.now - t0
262
- if elapsed < timeout
263
- child_exit
264
- raise ConnectionError.new(cmd)
265
- else
266
- raise ExpTimeoutError.new(cmd, timeout)
267
- end
262
+ when :cnx_error
263
+ child_exit
264
+ err_msg = "Could not connect to #{@host}:\n"
265
+ err_msg += " >> #{cmd}\n "
266
+ err_msg += buf.join("\n ")
267
+ raise ConnectionError.new(err_msg)
268
268
  else
269
269
  @lp = buf.last
270
270
  end
@@ -305,12 +305,12 @@ module Expect4r
305
305
  case r._io_string
306
306
  when @ps1, @ps1_bis
307
307
  unless r._io_more?
308
- r._io_save false, "matching PROMPT"
308
+ r._io_save no_echo, "matching PROMPT"
309
309
  throw(:done, [:ok, r._io_buf1])
310
310
  end
311
311
  exp_internal "more..."
312
312
  when /(.+)\r\n/, "\r\n"
313
- r._io_save no_echo, "matching EOL", "\r\n"
313
+ r._io_save no_echo, "matching EOL"
314
314
  when @more
315
315
  r._io_save no_echo, "matching MORE"
316
316
  putc ' '
@@ -433,9 +433,19 @@ end
433
433
  module Expect4r
434
434
  class BaseLoginObject
435
435
  class << self
436
+ # Examples:
437
+ # my_mac = RShell.new_telnet '1.1.1.1', 'me', 'secret'
438
+ # ios = Ios.new_telnet '1.1.1.1', 'lab', 'lab'
439
+ # iox = Iox.new_telnet '1.1.1.1', 'username', 'pwd'
440
+ #
436
441
  def new_telnet(*args)
437
442
  new :telnet, *args
438
443
  end
444
+ # Examples:
445
+ # my_mac = RShell.new_ssh '1.1.1.1', 'me', 'secret'
446
+ # iox = Ios.new_ssh '1.1.1.1', 'lab', 'lab'
447
+ # ios = Iosx.new_ssh '1.1.1.1', 'username', 'pwd'
448
+ #
439
449
  def new_ssh(*args)
440
450
  new :ssh, *args
441
451
  end
@@ -460,8 +470,9 @@ module Expect4r
460
470
  # * <tt>:pwd</tt> or <tt>:password</tt>
461
471
  #
462
472
  # Examples:
463
- # new :telnet, :user=> 'lab', :password=>'lab'
464
- # new :ssh, :user=> 'jme'
473
+ # new :telnet, :host=> '1.1.1.1', :user=> 'lab', :password=>'lab'
474
+ # new :ssh, :host=> '1.1.1.1', :user=> 'jme'
475
+ # new :ssh, '1.1.1.1', 'me', 'secret'
465
476
  #
466
477
  def initialize(*args)
467
478
  ciphered_password=nil
@@ -516,9 +527,16 @@ module Expect4r
516
527
  private
517
528
 
518
529
  def spawnee_password
519
- @pwd = Expect4r.cipher( ask("(#{self}) Enter your password: ") { |q| q.echo = "X" } ) unless @pwd
530
+ if @pwd.nil?
531
+ @pwd = Expect4r.cipher( ask("(#{self}) Enter your password: ") { |q| q.echo = "X" } )
532
+ @asked4pwd=true
533
+ end
520
534
  Expect4r.decipher(@pwd)
521
535
  end
536
+
537
+ def spawnee_reset
538
+ @pwd=nil if @asked4pwd
539
+ end
522
540
 
523
541
  end
524
542
  end
data/lib/expect4r.rb CHANGED
@@ -39,13 +39,3 @@ module Expect4r
39
39
  end
40
40
 
41
41
  end
42
-
43
- if __FILE__ == $0
44
- module Expect4r
45
- p Expect4r::Iox.new_ssh 'hostname', 'username'
46
- p Expect4r::Iox.new_telnet 'hostname', 'username'
47
- p Expect4r::Ios.new_ssh 'hostname', 'username'
48
- p Expect4r::J.new_ssh 'hostname', 'username'
49
- p Expect4r::Shell.new
50
- end
51
- end
data/lib/misc/shell.rb CHANGED
@@ -14,6 +14,7 @@ module Expect4r
14
14
  end
15
15
  class RShell < ::Expect4r::BaseLoginObject
16
16
  include Expect4r
17
+
17
18
  def initialize(*args)
18
19
  super
19
20
  default_ps1
@@ -35,7 +36,7 @@ module Expect4r
35
36
  # Assumes bash
36
37
  @ps1_bis = /#{val}$/
37
38
  cmd %? export PS1='#{val}' ?
38
- @ps1 = @ps1_bi
39
+ @ps1 = @ps1_bis
39
40
  end
40
41
  def cmd(*args)
41
42
  exp_send *args
@@ -66,14 +66,14 @@ module Modes
66
66
  end
67
67
 
68
68
  #
69
- # returns <tt>true</tt> if router is in <tt>:exec</tt> (enabled) mode, <tt>false</tt> otherwise.
69
+ # returns *true* if router is in <tt>:exec</tt> (enabled) mode, *false* otherwise.
70
70
  #
71
71
  def exec?
72
72
  ! user? and ! config?
73
73
  end
74
74
 
75
75
  #
76
- # returns <tt>true</tt> if router is in <tt>:user</tt> mode, <tt>false</tt> otherwise.
76
+ # returns *true* if router is in <tt>:user</tt> mode, *false* otherwise.
77
77
  #
78
78
  def user?
79
79
  @lp =~ /.+>\s*$/
@@ -3,7 +3,7 @@ require 'router/modes'
3
3
  module Expect4r::Router::Iox
4
4
  module Modes
5
5
 
6
- # Adds an Iox <tt>config>/tt> mixin.
6
+ # Adds an Iox <tt>config</tt> mixin.
7
7
  #
8
8
  # Options are:
9
9
  #
@@ -29,10 +29,16 @@ class Expect4r::J < ::Expect4r::BaseLoginObject
29
29
 
30
30
  def putline(line,arg={})
31
31
  o, rc = super
32
- raise SyntaxError.new(self.class.to_s, line) if o.join =~ /(unknown command|syntax error)\./
32
+ raise SyntaxError.new(self.class.to_s, line) if o.join =~ /(unknown command|syntax error)/
33
33
  o
34
34
  end
35
35
 
36
+ def rollback
37
+ return unless config?
38
+ top
39
+ putline 'rollback'
40
+ end
41
+
36
42
  def top
37
43
  putline 'top'
38
44
  end
@@ -46,7 +52,7 @@ class Expect4r::J < ::Expect4r::BaseLoginObject
46
52
  @matches << [/Exit with uncommitted changes.+\(yes\)/, 'yes']
47
53
  output = putline "commit", arg
48
54
  if /error: configuration check-out failed/.match(output.join)
49
- putline 'rollback'
55
+ rollack
50
56
  raise SemanticError.new(self.class.to_s, output)
51
57
  end
52
58
  output
@@ -23,7 +23,7 @@ def config(stmts=nil, arg={})
23
23
  output = exp_send(stmts, arg)
24
24
  output << commit
25
25
  change_mode_to(mode)
26
- output
26
+ output.flatten
27
27
  else
28
28
  to_config
29
29
  end
@@ -69,21 +69,21 @@ def shell(cmd=nil, *args)
69
69
  end
70
70
 
71
71
  #
72
- # returns <tt>true</tt> if router is in <tt>:exec</tt> mode, <tt>false</tt> otherwise.
72
+ # returns *true* if router is in <tt>:exec</tt> mode, *false* otherwise.
73
73
  #
74
74
  def exec?
75
75
  @lp =~ /> $/ ? true : false
76
76
  end
77
77
 
78
78
  #
79
- # returns <tt>true</tt> if router is in <tt>:config</tt> mode, <tt>false</tt> otherwise.
79
+ # returns *true* if router is in <tt>:config</tt> mode, *false* otherwise.
80
80
  #
81
81
  def config?
82
82
  @lp =~ /^.+# $/ ? true : false
83
83
  end
84
84
 
85
85
  #
86
- # returns <tt>true</tt> if router is in <tt>:shell</tt> mode, <tt>false</tt> otherwise.
86
+ # returns *true* if router is in <tt>:shell</tt> mode, *false* otherwise.
87
87
  #
88
88
  def shell?
89
89
  @lp == '% ' ? true : false
@@ -27,7 +27,7 @@ module Ping
27
27
 
28
28
  output = exec(ping_cmd(host, arg), arg)
29
29
 
30
- r = output[0].find { |x| p x ; x =~/(\d+) packets transmitted, (\d+) packets received, (\d+)\% packet loss/}
30
+ r = output[0].find { |x| x =~/(\d+) packets transmitted, (\d+) packets received, (\d+)\% packet loss/}
31
31
 
32
32
  if r &&
33
33
  Regexp.last_match(1) &&
@@ -55,6 +55,7 @@ private
55
55
  def ping_cmd(host, arg={})
56
56
  cmd = "ping #{host}"
57
57
  cmd += " rapid"
58
+ cmd += " logical-router #{arg[:logical_router]}" if arg[:logical_router]
58
59
  cmd += " count #{arg[:count] || arg[:repeat_count]}" if arg[:count] || arg[:repeat_count]
59
60
  cmd += " size #{arg[:size] || arg[:datagram_size]}" if arg[:size] || arg[:datagram_size]
60
61
  cmd += " pattern #{arg[:pattern]}" if arg[:pattern]
data/lib/router/modes.rb CHANGED
@@ -7,16 +7,17 @@ module Modes
7
7
  #
8
8
  # Examples:
9
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
10
+ # >> iox.in?
11
+ # => *:exec*
12
+ # >> iox.config
13
+ # => *:config*
14
+ # >> iox.in?
15
+ # => *:config*
16
+ # >> iox.shell
17
+ # => *:shell*
18
+ # >> iox.in?
19
+ # => *:shell*
20
+ #
20
21
  def in?(mode=:none)
21
22
  login unless connected?
22
23
  case mode
@@ -0,0 +1,12 @@
1
+ require 'expect4r'
2
+ require "test/unit"
3
+ class TestAutoload < Test::Unit::TestCase
4
+ include Expect4r
5
+ def test_autoload
6
+ assert Expect4r::Iox.new_ssh 'hostname', 'username'
7
+ assert Expect4r::Iox.new_telnet 'hostname', 'username'
8
+ assert Expect4r::Ios.new_ssh 'hostname', 'username'
9
+ assert Expect4r::J.new_ssh 'hostname', 'username'
10
+ assert Expect4r::Shell.new
11
+ end
12
+ end
@@ -1,8 +1,8 @@
1
+ require 'expect4r'
1
2
  require "test/unit"
2
3
 
3
- require "router/cisco/iox/iox"
4
-
5
4
  class TestRouterCiscoIoxIox < Test::Unit::TestCase
5
+ include Expect4r
6
6
  def test_new_hash_terse
7
7
  x = Iox.new :ssh,
8
8
  :host=> '1.1.1.1',
metadata CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 3
8
+ - 4
9
9
  - dev
10
- version: 0.0.3.dev
10
+ version: 0.0.4.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-27 00:00:00 -07:00
18
+ date: 2010-10-30 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -45,6 +45,8 @@ files:
45
45
  - COPYING
46
46
  - LICENSE
47
47
  - README.rdoc
48
+ - examples/jex1.rb
49
+ - examples/jex2.rb
48
50
  - lib/expect/io.rb
49
51
  - lib/expect4r.rb
50
52
  - lib/misc/passwd.rb
@@ -84,8 +86,8 @@ required_ruby_version: !ruby/object:Gem::Requirement
84
86
  segments:
85
87
  - 1
86
88
  - 8
87
- - 7
88
- version: 1.8.7
89
+ - 6
90
+ version: 1.8.6
89
91
  required_rubygems_version: !ruby/object:Gem::Requirement
90
92
  requirements:
91
93
  - - ">"
@@ -103,5 +105,6 @@ signing_key:
103
105
  specification_version: 3
104
106
  summary: Expect4r
105
107
  test_files:
108
+ - test/expect4r_test.rb
106
109
  - test/misc/passwd_test.rb
107
110
  - test/router/cisco/iox/iox_test.rb