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.
- data/.gitignore +5 -0
- data/.rubocop.yml +21 -0
- data/CHANGELOG.md +24 -0
- data/Gemfile +3 -1
- data/Guardfile +3 -3
- data/README.md +92 -17
- data/Rakefile +99 -4
- data/gems/README.rst +4 -0
- data/gems/inifile/.gitignore +2 -0
- data/gems/inifile/README.rst +5 -0
- data/gems/inifile/inifile.spec.tmpl +84 -0
- data/gems/net_http_unix/.gitignore +2 -0
- data/gems/net_http_unix/README.rst +5 -0
- data/gems/net_http_unix/net_http_unix.spec.tmpl +54 -0
- data/gems/netaddr/README.rst +5 -0
- data/gems/netaddr/netaddr.spec.tmpl +50 -0
- data/lib/rbeapi/api/aaa.rb +14 -17
- data/lib/rbeapi/api/acl.rb +276 -0
- data/lib/rbeapi/api/dns.rb +7 -4
- data/lib/rbeapi/api/interfaces.rb +239 -239
- data/lib/rbeapi/api/ipinterfaces.rb +5 -3
- data/lib/rbeapi/api/logging.rb +8 -5
- data/lib/rbeapi/api/mlag.rb +45 -127
- data/lib/rbeapi/api/ntp.rb +1 -4
- data/lib/rbeapi/api/ospf.rb +16 -13
- data/lib/rbeapi/api/prefixlists.rb +4 -4
- data/lib/rbeapi/api/radius.rb +34 -25
- data/lib/rbeapi/api/routemaps.rb +16 -10
- data/lib/rbeapi/api/snmp.rb +26 -13
- data/lib/rbeapi/api/staticroutes.rb +6 -5
- data/lib/rbeapi/api/stp.rb +77 -18
- data/lib/rbeapi/api/switchports.rb +20 -12
- data/lib/rbeapi/api/system.rb +6 -6
- data/lib/rbeapi/api/tacacs.rb +9 -6
- data/lib/rbeapi/api/varp.rb +15 -10
- data/lib/rbeapi/api/vlans.rb +5 -6
- data/lib/rbeapi/api.rb +56 -16
- data/lib/rbeapi/client.rb +85 -50
- data/lib/rbeapi/eapilib.rb +95 -56
- data/lib/rbeapi/netdev/snmp.rb +7 -16
- data/lib/rbeapi/utils.rb +3 -5
- data/lib/rbeapi/version.rb +1 -1
- data/rbeapi.gemspec +4 -2
- data/rbeapi.spec.tmpl +72 -0
- data/spec/support/fixtures.rb +6 -4
- data/spec/support/shared_examples_for_api_modules.rb +3 -18
- data/spec/system/api_acl_spec.rb +128 -0
- data/spec/system/api_ospf_interfaces_spec.rb +17 -14
- data/spec/system/api_ospf_spec.rb +8 -8
- data/spec/system/api_varp_interfaces_spec.rb +22 -13
- data/spec/system/api_varp_spec.rb +1 -4
- data/spec/system/rbeapi/api/interfaces_base_spec.rb +3 -4
- data/spec/system/rbeapi/api/interfaces_ethernet_spec.rb +13 -9
- data/spec/system/rbeapi/api/interfaces_portchannel_spec.rb +43 -26
- data/spec/system/rbeapi/api/interfaces_vxlan_spec.rb +7 -6
- data/spec/system/rbeapi/api/ipinterfaces_spec.rb +34 -21
- data/spec/system/rbeapi/api/mlag_interfaces_spec.rb +15 -38
- data/spec/system/rbeapi/api/mlag_spec.rb +26 -30
- data/spec/system/rbeapi/api/snmp_spec.rb +0 -3
- data/spec/system/rbeapi/api/stp_instances_spec.rb +20 -12
- data/spec/system/rbeapi/api/stp_interfaces_spec.rb +1 -3
- data/spec/system/rbeapi/api/switchports_spec.rb +14 -12
- data/spec/system/rbeapi/api/system_spec.rb +0 -3
- data/spec/system/rbeapi/api/vlans_spec.rb +19 -9
- data/spec/unit/rbeapi/api/acl/default_spec.rb +158 -0
- data/spec/unit/rbeapi/api/acl/fixture_acl_standard.text +22 -0
- data/spec/unit/rbeapi/api/interfaces/base_spec.rb +123 -0
- data/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb +89 -0
- data/spec/unit/rbeapi/api/interfaces/fixture_interfaces.text +219 -0
- data/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb +149 -0
- data/spec/unit/rbeapi/api/interfaces/vxlan_spec.rb +243 -0
- data/spec/unit/rbeapi/api/mlag/default_spec.rb +218 -0
- data/spec/unit/rbeapi/api/mlag/fixture_mlag.text +238 -0
- data/spec/unit/rbeapi/api/vlans/default_spec.rb +135 -0
- data/spec/unit/rbeapi/api/vlans/fixture_vlans.text +5 -0
- metadata +79 -4
- 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
|
-
|
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
|
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
|
81
|
-
# the loaded
|
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
|
-
|
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
|
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
|
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
|
162
|
-
#
|
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
|
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.
|
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
|
-
|
206
|
-
|
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
|
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
|
-
#
|
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
|
234
|
-
|
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
|
-
#
|
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
|
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
|
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
|
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
|
-
# @
|
325
|
-
# receive eAPI messages. Valid values are json and text. The
|
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,
|
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,
|
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
|
-
|
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
|
-
# @
|
380
|
-
# receive eAPI requests. This argument is optional.
|
381
|
-
# include json or text. The default is json
|
382
|
-
|
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,
|
421
|
+
commands.insert(0, 'cmd' => 'enable', 'input' => @enablepwd)
|
388
422
|
else
|
389
423
|
commands.insert(0, 'enable')
|
390
424
|
end
|
391
425
|
|
392
|
-
|
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
|
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')
|
data/lib/rbeapi/eapilib.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
|
@@ -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
|
-
|
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
|
-
#
|
54
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
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
|
-
#
|
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
|
-
# @
|
137
|
-
# eAPI
|
138
|
-
# @
|
139
|
-
# eAPI
|
140
|
-
def authentication(
|
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
|
193
|
+
# suitable to be JSON encoded and sent to the destination node
|
174
194
|
def request(commands, opts = {})
|
175
|
-
id = opts.fetch(:reqid,
|
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 =
|
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
|
-
|
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
|
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
|
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
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
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
|
-
|
301
|
-
|
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
|
-
|
313
|
-
|
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
|
-
|
329
|
-
|
330
|
-
authentication(user, pass)
|
368
|
+
authentication(opts)
|
369
|
+
timeouts(opts)
|
331
370
|
end
|
332
371
|
end
|
333
372
|
end
|