rbeapi 0.1.0 → 0.2.0

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.
Files changed (77) hide show
  1. data/.gitignore +5 -0
  2. data/.rubocop.yml +21 -0
  3. data/CHANGELOG.md +24 -0
  4. data/Gemfile +3 -1
  5. data/Guardfile +3 -3
  6. data/README.md +92 -17
  7. data/Rakefile +99 -4
  8. data/gems/README.rst +4 -0
  9. data/gems/inifile/.gitignore +2 -0
  10. data/gems/inifile/README.rst +5 -0
  11. data/gems/inifile/inifile.spec.tmpl +84 -0
  12. data/gems/net_http_unix/.gitignore +2 -0
  13. data/gems/net_http_unix/README.rst +5 -0
  14. data/gems/net_http_unix/net_http_unix.spec.tmpl +54 -0
  15. data/gems/netaddr/README.rst +5 -0
  16. data/gems/netaddr/netaddr.spec.tmpl +50 -0
  17. data/lib/rbeapi/api/aaa.rb +14 -17
  18. data/lib/rbeapi/api/acl.rb +276 -0
  19. data/lib/rbeapi/api/dns.rb +7 -4
  20. data/lib/rbeapi/api/interfaces.rb +239 -239
  21. data/lib/rbeapi/api/ipinterfaces.rb +5 -3
  22. data/lib/rbeapi/api/logging.rb +8 -5
  23. data/lib/rbeapi/api/mlag.rb +45 -127
  24. data/lib/rbeapi/api/ntp.rb +1 -4
  25. data/lib/rbeapi/api/ospf.rb +16 -13
  26. data/lib/rbeapi/api/prefixlists.rb +4 -4
  27. data/lib/rbeapi/api/radius.rb +34 -25
  28. data/lib/rbeapi/api/routemaps.rb +16 -10
  29. data/lib/rbeapi/api/snmp.rb +26 -13
  30. data/lib/rbeapi/api/staticroutes.rb +6 -5
  31. data/lib/rbeapi/api/stp.rb +77 -18
  32. data/lib/rbeapi/api/switchports.rb +20 -12
  33. data/lib/rbeapi/api/system.rb +6 -6
  34. data/lib/rbeapi/api/tacacs.rb +9 -6
  35. data/lib/rbeapi/api/varp.rb +15 -10
  36. data/lib/rbeapi/api/vlans.rb +5 -6
  37. data/lib/rbeapi/api.rb +56 -16
  38. data/lib/rbeapi/client.rb +85 -50
  39. data/lib/rbeapi/eapilib.rb +95 -56
  40. data/lib/rbeapi/netdev/snmp.rb +7 -16
  41. data/lib/rbeapi/utils.rb +3 -5
  42. data/lib/rbeapi/version.rb +1 -1
  43. data/rbeapi.gemspec +4 -2
  44. data/rbeapi.spec.tmpl +72 -0
  45. data/spec/support/fixtures.rb +6 -4
  46. data/spec/support/shared_examples_for_api_modules.rb +3 -18
  47. data/spec/system/api_acl_spec.rb +128 -0
  48. data/spec/system/api_ospf_interfaces_spec.rb +17 -14
  49. data/spec/system/api_ospf_spec.rb +8 -8
  50. data/spec/system/api_varp_interfaces_spec.rb +22 -13
  51. data/spec/system/api_varp_spec.rb +1 -4
  52. data/spec/system/rbeapi/api/interfaces_base_spec.rb +3 -4
  53. data/spec/system/rbeapi/api/interfaces_ethernet_spec.rb +13 -9
  54. data/spec/system/rbeapi/api/interfaces_portchannel_spec.rb +43 -26
  55. data/spec/system/rbeapi/api/interfaces_vxlan_spec.rb +7 -6
  56. data/spec/system/rbeapi/api/ipinterfaces_spec.rb +34 -21
  57. data/spec/system/rbeapi/api/mlag_interfaces_spec.rb +15 -38
  58. data/spec/system/rbeapi/api/mlag_spec.rb +26 -30
  59. data/spec/system/rbeapi/api/snmp_spec.rb +0 -3
  60. data/spec/system/rbeapi/api/stp_instances_spec.rb +20 -12
  61. data/spec/system/rbeapi/api/stp_interfaces_spec.rb +1 -3
  62. data/spec/system/rbeapi/api/switchports_spec.rb +14 -12
  63. data/spec/system/rbeapi/api/system_spec.rb +0 -3
  64. data/spec/system/rbeapi/api/vlans_spec.rb +19 -9
  65. data/spec/unit/rbeapi/api/acl/default_spec.rb +158 -0
  66. data/spec/unit/rbeapi/api/acl/fixture_acl_standard.text +22 -0
  67. data/spec/unit/rbeapi/api/interfaces/base_spec.rb +123 -0
  68. data/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb +89 -0
  69. data/spec/unit/rbeapi/api/interfaces/fixture_interfaces.text +219 -0
  70. data/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb +149 -0
  71. data/spec/unit/rbeapi/api/interfaces/vxlan_spec.rb +243 -0
  72. data/spec/unit/rbeapi/api/mlag/default_spec.rb +218 -0
  73. data/spec/unit/rbeapi/api/mlag/fixture_mlag.text +238 -0
  74. data/spec/unit/rbeapi/api/vlans/default_spec.rb +135 -0
  75. data/spec/unit/rbeapi/api/vlans/fixture_vlans.text +5 -0
  76. metadata +79 -4
  77. data/lib/rbeapi/api/radius.rb.old +0 -399
data/lib/rbeapi/client.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2014, Arista Networks, Inc.
2
+ # Copyright (c) 2014, 2015 Arista Networks, Inc.
3
3
  # All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without
@@ -41,10 +41,8 @@ module Rbeapi
41
41
  ##
42
42
  # Rbeapi::Client
43
43
  module Client
44
-
45
44
  class << self
46
-
47
- DEFAULT_TRANSPORT = 'http'
45
+ DEFAULT_TRANSPORT = 'https'
48
46
 
49
47
  TRANSPORTS = { 'http' => 'Rbeapi::Eapilib::HttpEapiConnection',
50
48
  'https' => 'Rbeapi::Eapilib::HttpsEapiConnection',
@@ -60,15 +58,15 @@ module Rbeapi
60
58
  # with the eapi.conf file
61
59
  def config
62
60
  return @config if @config
63
- @config = Config.new()
64
- return @config
61
+ @config = Config.new
62
+ @config
65
63
  end
66
64
 
67
65
  ##
68
66
  # load_config overrides the default conf file loaded in the config
69
67
  # instances using the supplied conf argument as the conf file. This
70
68
  # method will clear out an previously loaded configuration and replace
71
- # all entries with the contects of the supplied file.
69
+ # all entries with the contents of the supplied file.
72
70
  #
73
71
  # @param [String] :conf The full path to the conf file to load into
74
72
  # the config instance.
@@ -77,8 +75,8 @@ module Rbeapi
77
75
  end
78
76
 
79
77
  ##
80
- # Returns the configuration options for the named connection from the
81
- # the loaded configuuration. The configuration name is specified as
78
+ # Returns the configuration options for the named connection from
79
+ # the loaded configuration. The configuration name is specified as
82
80
  # the string right of the colon in the section name.
83
81
  #
84
82
  # @param [String] :name The connection name to return from the loaded
@@ -88,7 +86,7 @@ module Rbeapi
88
86
  # the named configuration if found. If the name is not found, then
89
87
  # nil is returned
90
88
  def config_for(name)
91
- return config.get_connection(name)
89
+ config.get_connection(name)
92
90
  end
93
91
 
94
92
  ##
@@ -103,6 +101,7 @@ module Rbeapi
103
101
  def connect_to(name)
104
102
  config = config_for(name)
105
103
  return nil unless config
104
+ config['host'] = name if config['host'] == '*'
106
105
  config = Rbeapi::Utils.transform_keys_to_symbols(config)
107
106
  connection = connect config
108
107
  Node.new(connection)
@@ -118,13 +117,13 @@ module Rbeapi
118
117
  #
119
118
  # @param [Hash] :opts the options to create a message with
120
119
  # @option :opts [String] :host The IP address or hostname of the remote
121
- # eAPI endpint
120
+ # eAPI endpoint
122
121
  # @option :opts [String] :username The username to use to authenticate
123
122
  # the eAPI connection with
124
123
  # @option :opts [String] :password The password to use to authenticate
125
124
  # the eAPI connection with
126
125
  # @option :opts [String] :enable_pwd The enable password (if defined) to
127
- # pass to the remote node to enter priviledged mode
126
+ # pass to the remote node to enter privilege mode
128
127
  # @option :opts [String] :use_ssl Specifies whether or not to use the
129
128
  # HTTP or HTTPS protocol
130
129
  # @option :opts [String] :port The port to connect to. If not specified
@@ -153,15 +152,15 @@ module Rbeapi
153
152
  end
154
153
  end
155
154
 
155
+ ##
156
+ # The Config class holds the loaded configuration file data. It is a
157
+ # subclass of IniFile.
156
158
  class Config < IniFile
157
-
158
159
  CONFIG_SEARCH_PATH = ['~/.eapi.conf', '/mnt/flash/eapi.conf']
159
160
 
160
161
  ##
161
- # The Config class holds the loaded configuration file data. It is a
162
- # subclass of IniFile. The Config class will automatically search for
163
- # a filename to load (if none provided) and load the data when the
164
- # object is instantiated.
162
+ # The Config class will automatically search for a filename to load
163
+ # (if none provided) and load the data when the object is instantiated.
165
164
  #
166
165
  # @param [String] :filename The full path to the filename to load. If
167
166
  # the filename is not provided, then this class will attempt to find
@@ -173,7 +172,7 @@ module Rbeapi
173
172
  end
174
173
 
175
174
  ##
176
- # This private method automtically finds and loads the conf file
175
+ # This private method automatically finds and loads the conf file
177
176
  # into the instance using the class variable CONFIG_SEARCH_PATH. The
178
177
  # connections should be retrieved using the get_connection method
179
178
  #
@@ -189,8 +188,11 @@ module Rbeapi
189
188
 
190
189
  path.each do |fn|
191
190
  fn = File.expand_path(fn)
192
- return read(fn) if File.exists?(fn)
191
+ return read(fn) if File.exist?(fn)
193
192
  end
193
+
194
+ return if get_connection 'localhost'
195
+ add_connection('localhost', transport: 'socket')
194
196
  end
195
197
  private :autoload
196
198
 
@@ -202,15 +204,24 @@ module Rbeapi
202
204
  # @param [String] :filename The full path to the filename to load
203
205
  def read(filename)
204
206
  super(filename: filename)
205
- unless get_connection 'localhost'
206
- add_connection('localhost', transport: 'socket')
207
+
208
+ # For each section, if the host parameter is omitted then the
209
+ # connection name is used
210
+ sections.each do |name|
211
+ if name.start_with?('connection:')
212
+ conn = self["#{name}"]
213
+ conn['host'] = name.split(':')[1] unless conn['host']
214
+ end
207
215
  end
216
+
217
+ return if get_connection 'localhost'
218
+ add_connection('localhost', transport: 'socket')
208
219
  end
209
220
 
210
221
  ##
211
222
  # This method will cause the config to be loaded. The process of
212
223
  # finding the configuration will be repeated so it is possible a
213
- # different conf file could be choosen if the original file was
224
+ # different conf file could be chosen if the original file was
214
225
  # removed or a new file added higher on the search priority list
215
226
  #
216
227
  # @param [Hash] :opts The options for specifying the message
@@ -220,18 +231,22 @@ module Rbeapi
220
231
  end
221
232
 
222
233
  ##
223
- # Returns the configuration for the connection specified
234
+ # Returns the configuration for the connection specified. If a
235
+ # connection is not found matching the name and if a default
236
+ # connection has been specified then return the default connection.
224
237
  #
225
238
  # @param [String] :name The name of the connection to return from
226
239
  # the configuration. This should be the string right of the :
227
240
  # in the config section header
228
241
  #
229
242
  # @return [nil, Hash<String, String> Returns a hash of the connection
230
- # properities from the loaded config. This method will return nil
243
+ # properties from the loaded config. This method will return nil
231
244
  # if the connection name is not found.
232
245
  def get_connection(name)
233
- return nil unless sections.include? "connection:#{name}"
234
- self["connection:#{name}"]
246
+ return self["connection:#{name}"] \
247
+ if sections.include? "connection:#{name}"
248
+ return self['connection:*'] if sections.include? 'connection:*'
249
+ nil
235
250
  end
236
251
 
237
252
  ##
@@ -245,14 +260,15 @@ module Rbeapi
245
260
  end
246
261
  end
247
262
 
263
+ ##
264
+ # The Node object provides an instance for sending and receiving messages
265
+ # with a specific EOS device. The methods provided in this class allow
266
+ # for handling both enable mode and config mode commands
248
267
  class Node
249
-
250
268
  attr_reader :connection
251
269
 
252
270
  ##
253
- # The Node object provies an instnace for sending and receiveing messages
254
- # with a specific EOS device. The methods provided in this calss allow
255
- # for handling both enable mode and config mode commands
271
+ # Save the connection and set autorefresh to true.
256
272
  #
257
273
  # @param [Rbeapi::Eapilib::EapiConnection] :connection An instance of
258
274
  # EapiConnection used to send and receive eAPI formatted messages
@@ -269,18 +285,16 @@ module Rbeapi
269
285
  def running_config
270
286
  return @running_config if @running_config
271
287
  @running_config = get_config(params: 'all', as_string: true)
272
- return @running_config
273
288
  end
274
289
 
275
290
  ##
276
291
  # Provides access to the nodes startup-configuration. This is a lazily
277
- # loaded memoized prpoerty for working with the nodes startup config
292
+ # loaded memoized property for working with the nodes startup config
278
293
  #
279
294
  # @return [String] The node's startup-config as a string
280
295
  def startup_config
281
296
  return @startup_config if @startup_config
282
297
  @startup_config = get_config(config: 'startup-config', as_string: true)
283
- return @startup_config
284
298
  end
285
299
 
286
300
  ##
@@ -302,13 +316,20 @@ module Rbeapi
302
316
  # to the caller
303
317
  #
304
318
  # @param [Array<String>] commands An ordered list of commands to execute
319
+ # @option :opts [String] :encoding The encoding scheme to use for sending
320
+ # and receive eAPI messages. Valid values are json and text. The
321
+ # default value is json
322
+ # @option :opts [Float] :open_timeout Number of seconds to wait for the
323
+ # eAPI connection to open.
324
+ # @option :opts [Float] :read_timeout Number of seconds to wait for one
325
+ # block of eAPI results to be read (via one read(2) call).
305
326
  #
306
327
  # @return [Array<Hash>] ordered list of output from commands
307
- def config(commands)
328
+ def config(commands, opts = {})
308
329
  commands = [*commands] unless commands.respond_to?('each')
309
330
 
310
331
  commands.insert(0, 'configure')
311
- response = run_commands commands
332
+ response = run_commands(commands, opts)
312
333
 
313
334
  refresh if @autorefresh
314
335
 
@@ -318,34 +339,42 @@ module Rbeapi
318
339
 
319
340
  ##
320
341
  # The enable method is a convenience method that will handling putting
321
- # the switch into priviledge mode prior to executing commands.
342
+ # the switch into privilege mode prior to executing commands.
343
+ #
344
+ # rubocop:disable Metrics/MethodLength
322
345
  #
323
346
  # @param [Array<String>] commands An ordered list of commands to execute
324
- # @param [String] :encoding The encoding scheme to use for sending and
325
- # receive eAPI messages. Valid values are json and text. The default
326
- # value is json
347
+ # @option :opts [String] :encoding The encoding scheme to use for sending
348
+ # and receive eAPI messages. Valid values are json and text. The
349
+ # default value is json
350
+ # @option :opts [Float] :open_timeout Number of seconds to wait for the
351
+ # eAPI connection to open.
352
+ # @option :opts [Float] :read_timeout Number of seconds to wait for one
353
+ # block of eAPI results to be read (via one read(2) call).
327
354
  #
328
355
  # @return [Array<Hash>] ordered list of output from commands
329
356
  def enable(commands, opts = {})
330
357
  commands = [*commands] unless commands.respond_to?('each')
331
358
 
332
359
  encoding = opts.fetch(:encoding, 'json')
360
+ opts[:encoding] = encoding
333
361
  strict = opts.fetch(:strict, false)
334
362
 
335
363
  results = []
336
364
  if strict
337
- responses = run_commands(commands, encoding)
365
+ responses = run_commands(commands, opts)
338
366
  responses.each_with_index do |resp, idx|
339
367
  results << make_response(commands[idx], resp, encoding)
340
368
  end
341
369
  else
342
370
  commands.each do |cmd|
343
371
  begin
344
- response = run_commands(cmd, encoding)
372
+ response = run_commands(cmd, opts)
345
373
  results << make_response(cmd, response.first, encoding)
346
374
  rescue Rbeapi::Eapilib::CommandError => exc
347
375
  raise unless exc.error_code == 1003
348
- response = run_commands(cmd, 'text')
376
+ opts[:encoding] = 'text'
377
+ response = run_commands(cmd, opts)
349
378
  results << make_response(cmd, response.first, encoding)
350
379
  end
351
380
  end
@@ -376,20 +405,26 @@ module Rbeapi
376
405
  #
377
406
  # @param [Array] :commands The ordered list of commands to send to the
378
407
  # destination node.
379
- # @param [String] :encoding The encoding scheme to use for sending and
380
- # receive eAPI requests. This argument is optional. Valid values
381
- # include json or text. The default is json
382
- def run_commands(commands, encoding = 'json')
408
+ # @option :opts [String] :encoding The encoding scheme to use for
409
+ # sending and receive eAPI requests. This argument is optional.
410
+ # Valid values include json or text. The default is json
411
+ # @option :opts [Float] :open_timeout Number of seconds to wait for the
412
+ # eAPI connection to open.
413
+ # @option :opts [Float] :read_timeout Number of seconds to wait for one
414
+ # block of eAPI results to be read (via one read(2) call).
415
+ def run_commands(commands, opts = {})
416
+ encoding = opts.fetch(:encoding, 'json')
383
417
  commands = [*commands] unless commands.respond_to?('each')
384
418
  commands = commands.dup
385
419
 
386
420
  if @enablepwd
387
- commands.insert(0, { 'cmd' => 'enable', 'input' => @enablepwd })
421
+ commands.insert(0, 'cmd' => 'enable', 'input' => @enablepwd)
388
422
  else
389
423
  commands.insert(0, 'enable')
390
424
  end
391
425
 
392
- response = @connection.execute(commands, format: encoding)
426
+ opts[:format] = encoding
427
+ response = @connection.execute(commands, opts)
393
428
  response.shift
394
429
  response
395
430
  end
@@ -424,13 +459,13 @@ module Rbeapi
424
459
  config = opts.fetch(:config, 'running-config')
425
460
  params = opts.fetch(:params, '')
426
461
  as_string = opts.fetch(:as_string, false)
427
- result = run_commands("show #{config} #{params}", 'text')
462
+ result = run_commands("show #{config} #{params}", encoding: 'text')
428
463
  return result.first['output'].strip.split("\n") unless as_string
429
464
  result.first['output'].strip
430
465
  end
431
466
 
432
467
  ##
433
- # Returns an API module for working with the active conifguraiton
468
+ # Returns an API module for working with the active configuration
434
469
  # of the node
435
470
  def api(name, opts = {})
436
471
  path = opts.fetch(:path, 'rbeapi/api')
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2014, Arista Networks, Inc.
2
+ # Copyright (c) 2014, 2015, Arista Networks, Inc.
3
3
  # All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without
@@ -31,28 +31,32 @@
31
31
  #
32
32
  require 'net/http'
33
33
  require 'json'
34
+ require 'openssl'
34
35
 
35
36
  require 'net_http_unix'
36
37
 
38
+ ##
39
+ # Rbeapi toplevel namespace
37
40
  module Rbeapi
38
-
41
+ ##
42
+ # Rbeapi::Eapilib
39
43
  module Eapilib
40
-
41
44
  DEFAULT_HTTP_PORT = 80
42
45
  DEFAULT_HTTPS_PORT = 443
43
46
  DEFAULT_HTTP_LOCAL_PORT = 8080
44
- DEFAULT_HTTP_TIMEOUT = 10
47
+ DEFAULT_HTTP_OPEN_TIMEOUT = 10
48
+ DEFAULT_HTTP_READ_TIMEOUT = 10
45
49
  DEFAULT_HTTP_PATH = '/command-api'
46
50
  DEFAULT_UNIX_SOCKET = '/var/run/command-api.sock'
47
51
 
52
+ ##
53
+ # Base error class for generating exceptions. The EapiError class
48
54
  class EapiError < StandardError
49
-
50
55
  attr_accessor :commands
51
56
 
52
57
  ##
53
- # Base error class for generating exceptions. The EapiError class
54
- # provides one property for holding the set of commands issued
55
- # when the error was generated
58
+ # The EapiError class provides one property for holding the set of
59
+ # commands issued when the error was generated.
56
60
  #
57
61
  # @param [String] :message The error message to return from raising
58
62
  # the exception
@@ -63,20 +67,20 @@ module Rbeapi
63
67
  end
64
68
  end
65
69
 
70
+ ##
71
+ # A CommandError exception is raised in response to an eAPI call that
72
+ # returns a failure message.
66
73
  class CommandError < EapiError
67
-
68
74
  attr_reader :error_code
69
75
  attr_reader :error_text
70
76
 
71
77
  ##
72
- # A CommandError exception is raised in response to an eAPI call that
73
- # returns a failure message. The exception contains the eAPI error
74
- # code and error text.
78
+ # The exception contains the eAPI error code and error text.
75
79
  #
76
80
  # @param [String] :message The error message to return from raising
77
81
  # this exception
78
82
  # @param [Integer] :code The error code associated with the error
79
- # messsage to be raised
83
+ # message to be raised
80
84
  # @param [Array] :commands The list of commands that were used in the
81
85
  # eAPI request message
82
86
  def initialize(message, code, commands = nil)
@@ -88,13 +92,14 @@ module Rbeapi
88
92
  end
89
93
  end
90
94
 
95
+ ##
96
+ # A ConnectionError exception is raised when the connection object
97
+ # is unable to establish a connection with eAPI.
91
98
  class ConnectionError < EapiError
92
-
93
99
  attr_accessor :connection_type
94
100
 
95
101
  ##
96
- # A ConnectionError exception is raised when the connection object
97
- # is unable to establish a connection with eAPI.
102
+ # The exception contains the eAPI error code and error text.
98
103
  #
99
104
  # @param [String] :message The error message to return from raising
100
105
  # this exception
@@ -109,16 +114,16 @@ module Rbeapi
109
114
  end
110
115
  end
111
116
 
117
+ ##
118
+ # The EapiConnection provides a base class for building eAPI connection
119
+ # instances with a specific transport for connecting to Arista EOS
120
+ # devices. This class handles sending and receiving eAPI calls using
121
+ # JSON-RPC. This class should not need to be directly instantiated.
112
122
  class EapiConnection
113
-
114
123
  attr_reader :error
115
124
 
116
125
  ##
117
- # The EapiConnection provides a base class for building eAPI connection
118
- # instances with a specific transport for connecting to Arista EOS
119
- # devices. This class handles sending and receiving eAPI calls using
120
- # JSON-RPC over HTTP. This class should not need to be directly
121
- # instantiated.
126
+ # The connection contains the transport.
122
127
  #
123
128
  # @param [Net::HTTP] :transport The HTTP transport to use for sending
124
129
  # and receive eAPI request and response messages
@@ -129,17 +134,32 @@ module Rbeapi
129
134
 
130
135
  ##
131
136
  # Configures the connection authentication values (username and
132
- # and password). The authentication values are used to authenticate
137
+ # password). The authentication values are used to authenticate
133
138
  # the eAPI connection. Using authentication is only required for
134
139
  # connections that use Http or Https transports
135
140
  #
136
- # @param [String] :username The username to use to authenticate to
137
- # eAPI with
138
- # @param [String] :password The password to use to authenticate to
139
- # eAPI with
140
- def authentication(username, password)
141
- @username = username
142
- @password = password
141
+ # @options :opts [String] :username The username to use to
142
+ # authenticate with eAPI. Default is 'admin'.
143
+ # @options :opts [String] :password The password to use to
144
+ # authenticate with eAPI. Default is ''.
145
+ def authentication(opts = {})
146
+ @username = opts.fetch(:username, 'admin')
147
+ @password = opts.fetch(:password, '')
148
+ end
149
+
150
+ ##
151
+ # Configures the connection timeout values (open_timeout and
152
+ # read_timeout). The timeout values are used for the eAPI
153
+ # connection.
154
+ #
155
+ # @option :opts [Float] :open_timeout Number of seconds to wait for the
156
+ # eAPI connection to open. Default is DEFAULT_HTTP_OPEN_TIMEOUT.
157
+ # @option :opts [Float] :read_timeout Number of seconds to wait for one
158
+ # block of eAPI results to be read (via one read(2) call). Default
159
+ # is DEFAULT_HTTP_READ_TIMEOUT.
160
+ def timeouts(opts = {})
161
+ @open_timeout = opts.fetch(:open_timeout, DEFAULT_HTTP_OPEN_TIMEOUT)
162
+ @read_timeout = opts.fetch(:read_timeout, DEFAULT_HTTP_READ_TIMEOUT)
143
163
  end
144
164
 
145
165
  ##
@@ -170,9 +190,9 @@ module Rbeapi
170
190
  # value is json
171
191
  #
172
192
  # @return [Hash] Returns a Ruby hash of the request message that is
173
- # suitable to be JSON encoded and sent to the desitination node
193
+ # suitable to be JSON encoded and sent to the destination node
174
194
  def request(commands, opts = {})
175
- id = opts.fetch(:reqid, self.object_id)
195
+ id = opts.fetch(:reqid, object_id)
176
196
  format = opts.fetch(:format, 'json')
177
197
  cmds = [*commands]
178
198
  params = { 'version' => 1, 'cmds' => cmds, 'format' => format }
@@ -222,18 +242,26 @@ module Rbeapi
222
242
  #
223
243
  # @param [Hash] :data A hash containing the body of the request
224
244
  # message. This should be a valid eAPI request message.
245
+ # @option :opts [Float] :open_timeout Number of seconds to wait for the
246
+ # eAPI connection to open.
247
+ # @option :opts [Float] :read_timeout Number of seconds to wait for one
248
+ # block of eAPI results to be read (via one read(2) call).
225
249
  #
226
250
  # @return [Hash] returns the response message as a Ruby hash object
227
251
  #
228
252
  # @raises [CommandError] Raised if an eAPI failure response is return
229
253
  # from the destination node.
230
- def send(data)
254
+ def send(data, opts)
231
255
  request = Net::HTTP::Post.new('/command-api')
232
256
  request.body = JSON.dump(data)
233
257
  request.basic_auth @username, @password
234
258
 
259
+ open_timeout = opts.fetch(:open_timeout, @open_timeout)
260
+ read_timeout = opts.fetch(:read_timeout, @read_timeout)
261
+
235
262
  begin
236
- @transport.open_timeout = DEFAULT_HTTP_TIMEOUT
263
+ @transport.open_timeout = open_timeout
264
+ @transport.read_timeout = read_timeout
237
265
  response = @transport.request(request)
238
266
  decoded = JSON(response.body)
239
267
 
@@ -246,18 +274,22 @@ module Rbeapi
246
274
  raise ConnectionError, 'unable to connect to eAPI'
247
275
  end
248
276
 
249
- return decoded
277
+ decoded
250
278
  end
251
279
 
252
280
  ##
253
281
  # Executes the commands on the destination node and returns the
254
282
  # response from the node.
255
283
  #
256
- # @param [Array] :commands The ordered list of commandst to execute
284
+ # @param [Array] :commands The ordered list of commands to execute
257
285
  # on the destination node.
258
286
  # @param [Hash] :opts Optional keyword arguments
259
287
  # @option :opts [String] :encoding Used to specify the encoding to be
260
288
  # used for the response. Valid encoding values are json or text
289
+ # @option :opts [Float] :open_timeout Number of seconds to wait for the
290
+ # eAPI connection to open.
291
+ # @option :opts [Float] :read_timeout Number of seconds to wait for one
292
+ # block of eAPI results to be read (via one read(2) call).
261
293
  #
262
294
  # @returns [Array<Hash>] This method will return the array of responses
263
295
  # for each command executed on the node.
@@ -265,22 +297,23 @@ module Rbeapi
265
297
  # @raises [CommandError] Raises a CommandError if rescued from the
266
298
  # send method and adds the list of commands to the exception message
267
299
  #
268
- # @raises [ConnectionError] Raises a ConnectionError if resuced and
300
+ # @raises [ConnectionError] Raises a ConnectionError if rescued and
269
301
  # adds the list of commands to the exception message
270
302
  def execute(commands, opts = {})
271
- begin
272
- @error = nil
273
- request = request(commands, opts)
274
- response = send request
275
- return response['result']
276
- rescue ConnectionError, CommandError => exc
277
- exc.commands = commands
278
- @error = exc
279
- raise
280
- end
303
+ @error = nil
304
+ request = request(commands, opts)
305
+ response = send(request, opts)
306
+ return response['result']
307
+ rescue ConnectionError, CommandError => exc
308
+ exc.commands = commands
309
+ @error = exc
310
+ raise
281
311
  end
282
312
  end
283
313
 
314
+ ##
315
+ # The SocketEapiConnection provides a class for building a domain
316
+ # socket eAPI connection to Arista EOS devices.
284
317
  class SocketEapiConnection < EapiConnection
285
318
  def initialize(opts = {})
286
319
  path = opts.fetch(:path, DEFAULT_UNIX_SOCKET)
@@ -289,6 +322,9 @@ module Rbeapi
289
322
  end
290
323
  end
291
324
 
325
+ ##
326
+ # The HttpEapiConnection provides a class for building an HTTP
327
+ # eAPI connection to a Arista EOS devices.
292
328
  class HttpEapiConnection < EapiConnection
293
329
  def initialize(opts = {})
294
330
  port = opts.fetch(:port, DEFAULT_HTTP_PORT)
@@ -297,24 +333,28 @@ module Rbeapi
297
333
  transport = Net::HTTP.new(host, port.to_i)
298
334
  super(transport)
299
335
 
300
- user = opts.fetch(:username, 'admin')
301
- pass = opts.fetch(:password, '')
302
- authentication(user, pass)
336
+ authentication(opts)
337
+ timeouts(opts)
303
338
  end
304
339
  end
305
340
 
341
+ ##
342
+ # The HttpLocalEapiConnection provides a class for building an HTTP
343
+ # eAPI connection to a local Arista EOS devices.
306
344
  class HttpLocalEapiConnection < EapiConnection
307
345
  def initialize(opts = {})
308
346
  port = opts.fetch(:port, DEFAULT_HTTP_LOCAL_PORT)
309
347
  transport = Net::HTTP.new('localhost', port)
310
348
  super(transport)
311
349
 
312
- user = opts.fetch(:username, 'admin')
313
- pass = opts.fetch(:password, '')
314
- authentication(user, pass)
350
+ authentication(opts)
351
+ timeouts(opts)
315
352
  end
316
353
  end
317
354
 
355
+ ##
356
+ # The HttpEapiConnection provides a class for building an HTTPS
357
+ # eAPI connection to a Arista EOS devices.
318
358
  class HttpsEapiConnection < EapiConnection
319
359
  def initialize(opts = {})
320
360
  host = opts.fetch(:host, 'localhost')
@@ -325,9 +365,8 @@ module Rbeapi
325
365
  transport.verify_mode = OpenSSL::SSL::VERIFY_NONE
326
366
  super(transport)
327
367
 
328
- user = opts.fetch(:username, 'admin')
329
- pass = opts.fetch(:password, '')
330
- authentication(user, pass)
368
+ authentication(opts)
369
+ timeouts(opts)
331
370
  end
332
371
  end
333
372
  end