rbeapi 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/CHANGELOG.md +16 -0
  2. data/Gemfile +3 -1
  3. data/Guardfile +2 -2
  4. data/README.md +35 -24
  5. data/Rakefile +48 -18
  6. data/gems/inifile/inifile.spec.tmpl +50 -14
  7. data/gems/net_http_unix/net_http_unix.spec.tmpl +48 -15
  8. data/gems/netaddr/netaddr.spec.tmpl +47 -14
  9. data/lib/rbeapi/api/bgp.rb +100 -4
  10. data/lib/rbeapi/api/interfaces.rb +4 -5
  11. data/lib/rbeapi/api/radius.rb +1 -1
  12. data/lib/rbeapi/api/routemaps.rb +405 -37
  13. data/lib/rbeapi/api/system.rb +21 -0
  14. data/lib/rbeapi/api/users.rb +361 -0
  15. data/lib/rbeapi/api/varp.rb +50 -22
  16. data/lib/rbeapi/api/vrrp.rb +1072 -0
  17. data/lib/rbeapi/client.rb +12 -4
  18. data/lib/rbeapi/eapilib.rb +1 -1
  19. data/lib/rbeapi/version.rb +1 -1
  20. data/rbeapi.spec.tmpl +57 -25
  21. data/spec/system/rbeapi/api/dns_spec.rb +2 -2
  22. data/spec/system/rbeapi/api/routemaps_spec.rb +344 -0
  23. data/spec/system/rbeapi/api/switchports_spec.rb +1 -1
  24. data/spec/system/rbeapi/api/system_spec.rb +44 -4
  25. data/spec/system/{api_varp_interfaces_spec.rb → rbeapi/api/varp_interfaces_spec.rb} +25 -16
  26. data/spec/system/rbeapi/api/varp_spec.rb +76 -0
  27. data/spec/unit/rbeapi/api/bgp/bgp_neighbors_spec.rb +2 -0
  28. data/spec/unit/rbeapi/api/bgp/bgp_spec.rb +54 -1
  29. data/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb +1 -1
  30. data/spec/unit/rbeapi/api/routemaps/default_spec.rb +370 -0
  31. data/spec/unit/rbeapi/api/routemaps/fixture_routemaps.text +27 -0
  32. data/spec/unit/rbeapi/api/system/default_spec.rb +102 -0
  33. data/spec/unit/rbeapi/api/system/fixture_system.text +2 -0
  34. data/spec/unit/rbeapi/api/users/default_spec.rb +280 -0
  35. data/spec/unit/rbeapi/api/users/fixture_users.text +4 -0
  36. data/spec/unit/rbeapi/api/vrrp/default_spec.rb +582 -0
  37. data/spec/unit/rbeapi/api/vrrp/fixture_vrrp.text +186 -0
  38. metadata +28 -8
  39. data/spec/system/api_varp_spec.rb +0 -41
@@ -0,0 +1,1072 @@
1
+ #
2
+ # Copyright (c) 2015, Arista Networks, Inc.
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are
7
+ # met:
8
+ #
9
+ # Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ #
12
+ # Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # Neither the name of Arista Networks nor the names of its
17
+ # contributors may be used to endorse or promote products derived from
18
+ # this software without specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS
24
+ # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27
+ # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30
+ # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ #
32
+ require 'rbeapi/api'
33
+
34
+ ##
35
+ # Eos is the toplevel namespace for working with Arista EOS nodes
36
+ module Rbeapi
37
+ ##
38
+ # Api is module namespace for working with the EOS command API
39
+ module Api
40
+ ##
41
+ # The Vrrp class manages the set of virtual routers.
42
+ # rubocop:disable Metrics/ClassLength
43
+ class Vrrp < Entity
44
+ def initialize(node)
45
+ super(node)
46
+ end
47
+
48
+ ##
49
+ # get returns the all the virtual router IPs for the given layer 3
50
+ # interface name from the nodes current configuration.
51
+ #
52
+ # rubocop:disable Metrics/MethodLength
53
+ #
54
+ # @example
55
+ # {
56
+ # 1: {
57
+ # enable: <True|False>
58
+ # primary_ip: <String>
59
+ # priority: <Integer>
60
+ # description: <String>
61
+ # secondary_ip: [ <ip_string1>, <ip_string2> ]
62
+ # ip_version: <Integer>
63
+ # timers_advertise: <Integer>
64
+ # mac_addr_adv_interval: <Integer>
65
+ # preempt: <True|False>
66
+ # preempt_delay_min: <Integer>
67
+ # preempt_delay_reload: <Integer>
68
+ # delay_reload: <Integer>
69
+ # track: [
70
+ # { name: 'Ethernet3', action: 'decrement', amount: 33 },
71
+ # { name: 'Ethernet2', action: 'decrement', amount: 22 },
72
+ # { name: 'Ethernet2', action: 'shutdown' }
73
+ # ]
74
+ # }
75
+ # }
76
+ #
77
+ # @param [String] :name The layer 3 interface name.
78
+ #
79
+ # @return [nil, Hash<Symbol, Object>] Returns the VRRP resource as a
80
+ # Hash with the virtual router ID as the key. If the interface name
81
+ # does not exist then a nil object is returned.
82
+ def get(name)
83
+ config = get_block("^interface #{name}")
84
+ return nil unless config
85
+
86
+ response = {}
87
+
88
+ vrids = config.scan(/^\s+(?:no |)vrrp (\d+)/)
89
+ vrids.uniq.each do |vrid_arr|
90
+ # Parse the vrrp configuration for the vrid(s) in the list
91
+ entry = {}
92
+ vrid = vrid_arr[0]
93
+ entry.merge!(parse_delay_reload(config, vrid))
94
+ entry.merge!(parse_description(config, vrid))
95
+ entry.merge!(parse_enable(config, vrid))
96
+ entry.merge!(parse_ip_version(config, vrid))
97
+ entry.merge!(parse_mac_addr_adv_interval(config, vrid))
98
+ entry.merge!(parse_preempt(config, vrid))
99
+ entry.merge!(parse_preempt_delay_min(config, vrid))
100
+ entry.merge!(parse_preempt_delay_reload(config, vrid))
101
+ entry.merge!(parse_primary_ip(config, vrid))
102
+ entry.merge!(parse_priority(config, vrid))
103
+ entry.merge!(parse_secondary_ip(config, vrid))
104
+ entry.merge!(parse_timers_advertise(config, vrid))
105
+ entry.merge!(parse_track(config, vrid))
106
+
107
+ response[vrid.to_i] = entry unless entry.nil?
108
+ end
109
+ response
110
+ end
111
+
112
+ ##
113
+ # getall returns the collection of virtual router IPs for all the
114
+ # layer 3 interfaces from the nodes running configuration as a hash.
115
+ # The resource collection hash is keyed by the ACL name.
116
+ #
117
+ # @example
118
+ # {
119
+ # 'Vlan100': {
120
+ # 1: { data },
121
+ # 250: { data },
122
+ # },
123
+ # 'Vlan200': {
124
+ # 2: { data },
125
+ # 250: { data },
126
+ # }
127
+ # }
128
+ #
129
+ # @return [nil, Hash<Symbol, Object>] Returns a hash that represents
130
+ # the entire virtual router IPs collection for all the layer 3
131
+ # interfaces from the nodes running configuration. If there are no
132
+ # virtual routers configured, this method will return an empty hash.
133
+ def getall
134
+ interfaces = config.scan(/(?<=^interface\s).+$/)
135
+ interfaces.each_with_object({}) do |name, hsh|
136
+ data = get(name)
137
+ hsh[name] = data if data
138
+ end
139
+ end
140
+
141
+ ##
142
+ # parse_primary_ip scans the nodes configurations for the given
143
+ # virtual router id and extracts the primary IP.
144
+ #
145
+ # @api private
146
+ #
147
+ # @param [String] :config The interface config.
148
+ # @param [String] :vrid The virtual router id.
149
+ #
150
+ # @return [Hash<'primary_ip', String>] Where string is the IPv4
151
+ # address or nil if the value is not set.
152
+ def parse_primary_ip(config, vrid)
153
+ match = config.scan(/^\s+vrrp #{vrid} ip (\d+\.\d+\.\d+\.\d+)$/)
154
+ if match.empty?
155
+ fail 'Did not get a default value for primary_ip'
156
+ else
157
+ value = match[0][0]
158
+ end
159
+ { primary_ip: value }
160
+ end
161
+ private :parse_primary_ip
162
+
163
+ ##
164
+ # parse_priority scans the nodes configurations for the given
165
+ # virtual router id and extracts the priority value.
166
+ #
167
+ # @api private
168
+ #
169
+ # @param [String] :config The interface config.
170
+ # @param [String] :vrid The virtual router id.
171
+ #
172
+ # @return [Hash<'priority', Integer>] The priority is between
173
+ # <1-255> or nil if the value is not set.
174
+ def parse_priority(config, vrid)
175
+ match = config.scan(/^\s+vrrp #{vrid} priority (\d+)$/)
176
+ if match.empty?
177
+ fail 'Did not get a default value for priority'
178
+ else
179
+ value = match[0][0].to_i
180
+ end
181
+ { priority: value }
182
+ end
183
+ private :parse_priority
184
+
185
+ ##
186
+ # parse_timers_advertise scans the nodes configurations for the given
187
+ # virtual router id and extracts the timers advertise value.
188
+ #
189
+ # @api private
190
+ #
191
+ # @param [String] :config The interface config.
192
+ # @param [String] :vrid The virtual router id.
193
+ #
194
+ # @return [nil, Hash<'timers_advertise', Integer>] The timers_advertise
195
+ # is between <1-255> or nil if the value is not set.
196
+ def parse_timers_advertise(config, vrid)
197
+ match = config.scan(/^\s+vrrp #{vrid} timers advertise (\d+)$/)
198
+ if match.empty?
199
+ fail 'Did not get a default value for timers advertise'
200
+ else
201
+ value = match[0][0].to_i
202
+ end
203
+ { timers_advertise: value }
204
+ end
205
+ private :parse_timers_advertise
206
+
207
+ ##
208
+ # parse_preempt scans the nodes configurations for the given
209
+ # virtual router id and extracts the preempt value.
210
+ #
211
+ # @api private
212
+ #
213
+ # @param [String] :config The interface config.
214
+ # @param [String] :vrid The virtual router id.
215
+ #
216
+ # @return [nil, Hash<'preempt', Integer>] The preempt is
217
+ # between <1-255> or nil if the value is not set.
218
+ def parse_preempt(config, vrid)
219
+ match = config.scan(/^\s+vrrp #{vrid} preempt$/)
220
+ if match.empty?
221
+ value = false
222
+ else
223
+ value = true
224
+ end
225
+ { preempt: value }
226
+ end
227
+ private :parse_preempt
228
+
229
+ ##
230
+ # parse_enable scans the nodes configurations for the given
231
+ # virtual router id and extracts the enable value.
232
+ #
233
+ # @api private
234
+ #
235
+ # @param [String] :config The interface config.
236
+ # @param [String] :vrid The virtual router id.
237
+ #
238
+ # @return [Hash<'enable', Boolean>]
239
+ def parse_enable(config, vrid)
240
+ match = config.scan(/^\s+vrrp #{vrid} shutdown$/)
241
+ if match.empty?
242
+ value = true
243
+ else
244
+ value = false
245
+ end
246
+ { enable: value }
247
+ end
248
+ private :parse_enable
249
+
250
+ ##
251
+ # parse_secondary_ip scans the nodes configurations for the given
252
+ # virtual router id and extracts the secondary_ip value.
253
+ #
254
+ # @api private
255
+ #
256
+ # @param [String] :config The interface config.
257
+ # @param [String] :vrid The virtual router id.
258
+ #
259
+ # @return [nil, Hash<'secondary_ip', Array<Strings>>] Returns an empty
260
+ # array if the value is not set.
261
+ def parse_secondary_ip(config, vrid)
262
+ regex = "vrrp #{vrid} ip"
263
+ matches = config.scan(/^\s+#{regex} (\d+\.\d+\.\d+\.\d+) secondary$/)
264
+ response = []
265
+ matches.each do |ip|
266
+ response << ip[0]
267
+ end
268
+ { secondary_ip: response }
269
+ end
270
+ private :parse_secondary_ip
271
+
272
+ ##
273
+ # parse_description scans the nodes configurations for the given
274
+ # virtual router id and extracts the description.
275
+ #
276
+ # @api private
277
+ #
278
+ # @param [String] :config The interface config.
279
+ # @param [String] :vrid The virtual router id.
280
+ #
281
+ # @return [nil, Hash<'secondary_ip', String>] Returns nil if the
282
+ # value is not set.
283
+ def parse_description(config, vrid)
284
+ match = config.scan(/^\s+vrrp #{vrid} description\s+(.*)\s*$/)
285
+ if match.empty?
286
+ value = nil
287
+ else
288
+ value = match[0][0]
289
+ end
290
+ { description: value }
291
+ end
292
+ private :parse_description
293
+
294
+ ##
295
+ # parse_track scans the nodes configurations for the given
296
+ # virtual router id and extracts the track entries.
297
+ #
298
+ # @api private
299
+ #
300
+ # @param [String] :config The interface config.
301
+ # @param [String] :vrid The virtual router id.
302
+ #
303
+ # @return [Hash<'track', Array<Hashes>] Returns an empty array if the
304
+ # value is not set. An example array of hashes follows:
305
+ # { name: 'Ethernet3', action: 'decrement', amount: 33 },
306
+ # { name: 'Ethernet2', action: 'decrement', amount: 22 },
307
+ # { name: 'Ethernet2', action: 'shutdown' }
308
+ def parse_track(config, vrid)
309
+ pre = "vrrp #{vrid} track "
310
+ matches = \
311
+ config.scan(/^\s+#{pre}(\S+) (decrement|shutdown)\s*(?:(\d+$|$))/)
312
+ response = []
313
+ matches.each do |name, action, amount|
314
+ hsh = { name: name, action: action }
315
+ hsh[:amount] = amount.to_i if action == 'decrement'
316
+ response << hsh
317
+ end
318
+ { track: response }
319
+ end
320
+ private :parse_track
321
+
322
+ ##
323
+ # parse_ip_version scans the nodes configurations for the given
324
+ # virtual router id and extracts the IP version.
325
+ #
326
+ # @api private
327
+ #
328
+ # @param [String] :config The interface config.
329
+ # @param [String] :vrid The virtual router id.
330
+ #
331
+ # @return [Hash<'ip_version', Integer>] Returns nil if the
332
+ # value is not set.
333
+ def parse_ip_version(config, vrid)
334
+ match = config.scan(/^\s+vrrp #{vrid} ip version (\d+)$/)
335
+ if match.empty?
336
+ fail 'Did not get a default value for ip version'
337
+ else
338
+ value = match[0][0].to_i
339
+ end
340
+ { ip_version: value }
341
+ end
342
+ private :parse_ip_version
343
+
344
+ ##
345
+ # parse_mac_addr_adv_interval scans the nodes configurations for the
346
+ # given virtual router id and extracts the mac address advertisement
347
+ # interval.
348
+ #
349
+ # @api private
350
+ #
351
+ # @param [String] :config The interface config.
352
+ # @param [String] :vrid The virtual router id.
353
+ #
354
+ # @return [Hash<'mac_addr_adv_interval', Integer>] Returns nil if the
355
+ # value is not set.
356
+ def parse_mac_addr_adv_interval(config, vrid)
357
+ regex = "vrrp #{vrid} mac-address advertisement-interval"
358
+ match = config.scan(/^\s+#{regex} (\d+)$/)
359
+ if match.empty?
360
+ fail 'Did not get a default value for mac address ' \
361
+ 'advertisement interval'
362
+ else
363
+ value = match[0][0].to_i
364
+ end
365
+ { mac_addr_adv_interval: value }
366
+ end
367
+ private :parse_mac_addr_adv_interval
368
+
369
+ ##
370
+ # parse_preempt_delay_min scans the nodes configurations for the given
371
+ # virtual router id and extracts the preempt delay minimum value..
372
+ #
373
+ # @api private
374
+ #
375
+ # @param [String] :config The interface config.
376
+ # @param [String] :vrid The virtual router id.
377
+ #
378
+ # @return [Hash<'preempt_delay_min', Integer>] Returns nil if the
379
+ # value is not set.
380
+ def parse_preempt_delay_min(config, vrid)
381
+ match = config.scan(/^\s+vrrp #{vrid} preempt delay minimum (\d+)$/)
382
+ if match.empty?
383
+ fail 'Did not get a default value for preempt delay minimum'
384
+ else
385
+ value = match[0][0].to_i
386
+ end
387
+ { preempt_delay_min: value }
388
+ end
389
+ private :parse_preempt_delay_min
390
+
391
+ ##
392
+ # parse_preempt_delay_reload scans the nodes configurations for the
393
+ # given virtual router id and extracts the preempt delay reload value.
394
+ #
395
+ # @api private
396
+ #
397
+ # @param [String] :config The interface config.
398
+ # @param [String] :vrid The virtual router id.
399
+ #
400
+ # @return [Hash<'preempt_delay_reload', Integer>] Returns nil if the
401
+ # value is not set.
402
+ def parse_preempt_delay_reload(config, vrid)
403
+ match = config.scan(/^\s+vrrp #{vrid} preempt delay reload (\d+)$/)
404
+ if match.empty?
405
+ fail 'Did not get a default value for preempt delay reload'
406
+ else
407
+ value = match[0][0].to_i
408
+ end
409
+ { preempt_delay_reload: value }
410
+ end
411
+ private :parse_preempt_delay_reload
412
+
413
+ ##
414
+ # parse_delay_reload scans the nodes configurations for the given
415
+ # virtual router id and extracts the delay reload value.
416
+ #
417
+ # @api private
418
+ #
419
+ # @param [String] :config The interface config.
420
+ # @param [String] :vrid The virtual router id.
421
+ #
422
+ # @return [Hash<'delay_reload', Integer>] Returns empty hash if the
423
+ # value is not set.
424
+ def parse_delay_reload(config, vrid)
425
+ match = config.scan(/^\s+vrrp #{vrid} delay reload (\d+)$/)
426
+ if match.empty?
427
+ fail 'Did not get a default value for delay reload'
428
+ else
429
+ value = match[0][0].to_i
430
+ end
431
+ { delay_reload: value }
432
+ end
433
+ private :parse_delay_reload
434
+
435
+ ##
436
+ # create will create a new virtual router ID resource for the interface
437
+ # in the nodes current. If the create method is called and the virtual
438
+ # router ID already exists for the interface, this method will still
439
+ # return true. Create takes optional parameters, but at least one
440
+ # parameter needs to be set or the command will fail.
441
+ #
442
+ # @eos_version 4.13.7M
443
+ #
444
+ # @commands
445
+ # interface <name>
446
+ # vrrp <vrid> ...
447
+ #
448
+ # @param [String] :name The layer 3 interface name.
449
+ #
450
+ # @param [String] :vrid The virtual router id.
451
+ #
452
+ # @param [hash] :opts Optional keyword arguments
453
+ #
454
+ # @option :opts [Boolean] :enable Enable the virtual router.
455
+ #
456
+ # @option :opts [String] :primary_ip The primary IPv4 address.
457
+ #
458
+ # @option :opts [Integer] :priority The priority setting for a virtual
459
+ # router.
460
+ #
461
+ # @option :opts [String] :description Associates a text string to a
462
+ # virtual router.
463
+ #
464
+ # @option :opts [Array<String>] :secondary_ip The secondary IPv4
465
+ # address to the specified virtual router.
466
+ #
467
+ # @option :opts [Integer] :ip_version Configures the VRRP version for
468
+ # the VRRP router.
469
+ #
470
+ # @option :opts [Integer] :timers_advertise The interval between
471
+ # successive advertisement messages that the switch sends to routers
472
+ # in the specified virtual router ID.
473
+ #
474
+ # @option :opts [Integer] :mac_addr_adv_interval Specifies interval in
475
+ # seconds between advertisement packets sent to VRRP group members.
476
+ #
477
+ # @option :opts [Boolean] :preempt A virtual router preempt mode
478
+ # setting. When preempt mode is enabled, if the switch has a higher
479
+ # priority it will preempt the current master virtual router. When
480
+ # preempt mode is disabled, the switch can become the master virtual
481
+ # router only when a master virtual router is not present on the
482
+ # subnet, regardless of priority settings.
483
+ #
484
+ # @option :opts [Integer] :preempt_delay_min Interval in seconds between
485
+ # VRRP preempt event and takeover. Minimum delays takeover when VRRP
486
+ # is fully implemented.
487
+ #
488
+ # @option :opts [Integer] :preempt_delay_reload Interval in seconds
489
+ # between VRRP preempt event and takeover. Reload delays takeover
490
+ # after initialization following a switch reload.
491
+ #
492
+ # @option :opts [Integer] :delay_reload Delay between system reboot and
493
+ # VRRP initialization.
494
+ #
495
+ # @option :opts [Array<Hash>] :track The track hash contains the
496
+ # name of an interface to track, the action to take on state-change
497
+ # of the tracked interface, and the amount to decrement the priority.
498
+ #
499
+ # @return [Boolean] returns true if the command completed successfully
500
+ def create(name, vrid, opts = {})
501
+ fail ArgumentError, 'create has no options set' if opts.empty?
502
+ cmds = []
503
+ if opts.key?(:enable)
504
+ if opts[:enable]
505
+ cmds << "no vrrp #{vrid} shutdown"
506
+ else
507
+ cmds << "vrrp #{vrid} shutdown"
508
+ end
509
+ end
510
+ cmds << "vrrp #{vrid} ip #{opts[:primary_ip]}" if opts.key?(:primary_ip)
511
+ if opts.key?(:priority)
512
+ cmds << "vrrp #{vrid} priority #{opts[:priority]}"
513
+ end
514
+ if opts.key?(:description)
515
+ cmds << "vrrp #{vrid} description #{opts[:description]}"
516
+ end
517
+ if opts.key?(:secondary_ip)
518
+ cmds += build_secondary_ip_cmd(name, vrid, opts[:secondary_ip])
519
+ end
520
+ if opts.key?(:ip_version)
521
+ cmds << "vrrp #{vrid} ip version #{opts[:ip_version]}"
522
+ end
523
+ if opts.key?(:timers_advertise)
524
+ cmds << "vrrp #{vrid} timers advertise #{opts[:timers_advertise]}"
525
+ end
526
+ if opts.key?(:mac_addr_adv_interval)
527
+ val = opts[:mac_addr_adv_interval]
528
+ cmds << "vrrp #{vrid} mac-address advertisement-interval #{val}"
529
+ end
530
+ if opts.key?(:preempt)
531
+ if opts[:preempt]
532
+ cmds << "vrrp #{vrid} preempt"
533
+ else
534
+ cmds << "no vrrp #{vrid} preempt"
535
+ end
536
+ end
537
+ if opts.key?(:preempt_delay_min)
538
+ val = opts[:preempt_delay_min]
539
+ cmds << "vrrp #{vrid} preempt delay minimum #{val}"
540
+ end
541
+ if opts.key?(:preempt_delay_reload)
542
+ val = opts[:preempt_delay_reload]
543
+ cmds << "vrrp #{vrid} preempt delay reload #{val}"
544
+ end
545
+ if opts.key?(:delay_reload)
546
+ cmds << "vrrp #{vrid} delay reload #{opts[:delay_reload]}"
547
+ end
548
+ cmds += build_tracks_cmd(name, vrid, opts[:track]) if opts.key?(:track)
549
+ configure_interface(name, cmds)
550
+ end
551
+
552
+ ##
553
+ # delete will delete the virtual router ID on the interface from the
554
+ # nodes current running configuration. If the delete method is called
555
+ # and the virtual router id does not exist on the interface, this
556
+ # method will succeed.
557
+ #
558
+ # @eos_version 4.13.7M
559
+ #
560
+ # @commands
561
+ # interface <name>
562
+ # no vrrp <vrid>
563
+ #
564
+ # @param [String] :name The layer 3 interface name.
565
+ # @param [Integer] :vrid The virtual router ID.
566
+ #
567
+ # @return [Boolean] returns true if the command completed successfully
568
+ def delete(name, vrid)
569
+ configure_interface(name, "no vrrp #{vrid}")
570
+ end
571
+
572
+ ##
573
+ # default will default the virtual router ID on the interface from the
574
+ # nodes current running configuration. This command has the same effect
575
+ # as deleting the virtual router id from the interface in the nodes
576
+ # running configuration. If the default method is called and the
577
+ # virtual router id does not exist on the interface, this method will
578
+ # succeed.
579
+ #
580
+ # @eos_version 4.13.7M
581
+ #
582
+ # @commands
583
+ # interface <name>
584
+ # default vrrp <vrid>
585
+ #
586
+ # @param [String] :name The layer 3 interface name.
587
+ # @param [Integer] :vrid The virtual router ID.
588
+ #
589
+ # @return [Boolean] returns true if the command complete successfully
590
+ def default(name, vrid)
591
+ configure_interface(name, "default vrrp #{vrid}")
592
+ end
593
+
594
+ ##
595
+ # set_shutdown enables and disables the virtual router.
596
+ #
597
+ # @commands
598
+ # interface <name>
599
+ # {no | default} vrrp <vrid> shutdown
600
+ #
601
+ # @param [String] :name The layer 3 interface name.
602
+ # @param [Integer] :vrid The virtual router ID.
603
+ # @param [hash] :opts Optional keyword arguments
604
+ #
605
+ # @option :opts [Boolean] :enable If enable is true then the virtual
606
+ # router is administratively enabled for the interface and if enable
607
+ # is false then the virtual router is administratively disabled
608
+ # for the interface. Default is true.
609
+ #
610
+ # @option :opts [Boolean] :default Configure shutdown using
611
+ # the default keyword.
612
+ #
613
+ # @return [Boolean] returns true if the command complete successfully
614
+ def set_shutdown(name, vrid, opts = {})
615
+ fail 'set_shutdown has the value option set' if opts[:value]
616
+ # Shutdown semantics are opposite of enable semantics so invert enable
617
+ enable = opts.fetch(:enable, true)
618
+ opts.merge!(enable: !enable)
619
+ cmd = "vrrp #{vrid} shutdown"
620
+ configure_interface(name, command_builder(cmd, opts))
621
+ end
622
+
623
+ ##
624
+ # set_primary_ip sets the primary IP address for the virtual router.
625
+ #
626
+ # @commands
627
+ # interface <name>
628
+ # {no | default} vrrp <vrid> ip <A.B.C.D>
629
+ #
630
+ # @param [String] :name The layer 3 interface name.
631
+ # @param [Integer] :vrid The virtual router ID.
632
+ # @param [hash] :opts Optional keyword arguments
633
+ #
634
+ # @option :opts [String] :value The primary IPv4 address.
635
+ #
636
+ # @option :opts [Boolean] :enable If false then the command is
637
+ # negated. Default is true.
638
+ #
639
+ # @option :opts [Boolean] :default Configure the primary IP address using
640
+ # the default keyword.
641
+ #
642
+ # @return [Boolean] returns true if the command complete successfully
643
+ def set_primary_ip(name, vrid, opts = {})
644
+ cmd = "vrrp #{vrid} ip"
645
+ configure_interface(name, command_builder(cmd, opts))
646
+ end
647
+
648
+ ##
649
+ # set_priority sets the priority for a virtual router.
650
+ #
651
+ # @commands
652
+ # interface <name>
653
+ # {no | default} vrrp <vrid> priority <priority>
654
+ #
655
+ # @param [String] :name The layer 3 interface name.
656
+ # @param [Integer] :vrid The virtual router ID.
657
+ # @param [hash] :opts Optional keyword arguments
658
+ #
659
+ # @option :opts [String] :value The priority value.
660
+ #
661
+ # @option :opts [Boolean] :enable If false then the command is
662
+ # negated. Default is true.
663
+ #
664
+ # @option :opts [Boolean] :default Configure the priority using
665
+ # the default keyword.
666
+ #
667
+ # @return [Boolean] returns true if the command complete successfully
668
+ def set_priority(name, vrid, opts = {})
669
+ cmd = "vrrp #{vrid} priority"
670
+ configure_interface(name, command_builder(cmd, opts))
671
+ end
672
+
673
+ ##
674
+ # set_description sets the description for a virtual router.
675
+ #
676
+ # @commands
677
+ # interface <name>
678
+ # {no | default} vrrp <vrid> description <description>
679
+ #
680
+ # @param [String] :name The layer 3 interface name.
681
+ # @param [Integer] :vrid The virtual router ID.
682
+ # @param [hash] :opts Optional keyword arguments
683
+ #
684
+ # @option :opts [String] :value The description value.
685
+ #
686
+ # @option :opts [Boolean] :enable If false then the command is
687
+ # negated. Default is true.
688
+ #
689
+ # @option :opts [Boolean] :default Configure the description using
690
+ # the default keyword.
691
+ #
692
+ # @return [Boolean] returns true if the command complete successfully
693
+ def set_description(name, vrid, opts = {})
694
+ cmd = "vrrp #{vrid} description"
695
+ configure_interface(name, command_builder(cmd, opts))
696
+ end
697
+
698
+ ##
699
+ # build_secondary_ip_cmd builds the array of commands required
700
+ # to update the secondary IP addresses. This method allows the
701
+ # create methods to leverage the code in the setter.
702
+ #
703
+ # @api private
704
+ #
705
+ # @param [String] :name The layer 3 interface name.
706
+ #
707
+ # @param [Integer] :vrid The virtual router ID.
708
+ #
709
+ # @param [Array<String>] :ip_addrs Array of secondary IPv4 address.
710
+ # An empty array will remove all secondary IPv4 addresses set for
711
+ # the virtual router on the specified layer 3 interface.
712
+ #
713
+ # @return [Array<String>] Returns the array of commands. The
714
+ # array could be empty.
715
+ def build_secondary_ip_cmd(name, vrid, ip_addrs)
716
+ ip_addrs = Set.new ip_addrs
717
+
718
+ # Get the current secondary IP address set for the virtual router
719
+ # A return of nil means that nothing has been configured for
720
+ # the virtual router.
721
+ vrrp = get(name)
722
+ vrrp = [] if vrrp.nil?
723
+
724
+ if vrrp.key?(vrid)
725
+ current_addrs = Set.new vrrp[vrid][:secondary_ip]
726
+ else
727
+ current_addrs = Set.new []
728
+ end
729
+
730
+ cmds = []
731
+ # Add commands to delete any secondary IP addresses that are
732
+ # currently set for the virtual router but not in ip_addrs.
733
+ current_addrs.difference(ip_addrs).each do |addr|
734
+ cmds << "no vrrp #{vrid} ip #{addr} secondary"
735
+ end
736
+
737
+ # Add commands to add any secondary IP addresses that are
738
+ # not currently set for the virtual router but are in ip_addrs.
739
+ ip_addrs.difference(current_addrs).each do |addr|
740
+ cmds << "vrrp #{vrid} ip #{addr} secondary"
741
+ end
742
+ cmds
743
+ end
744
+ private :build_secondary_ip_cmd
745
+
746
+ # set_secondary_ips configures the set of secondary IP addresses
747
+ # associated with the virtual router. The ip_addrs value passed
748
+ # should be an array of IP Addresses. This method will remove
749
+ # secondary IP addresses that are currently set for the virtual
750
+ # router but not included in the ip_addrs array value passed in.
751
+ # The method will then add secondary IP addresses that are not
752
+ # currently set for the virtual router but are included in the
753
+ # ip_addrs array value passed in.
754
+ #
755
+ # @commands
756
+ # interface <name>
757
+ # {no} vrrp <vrid> ip <A.B.C.D> secondary
758
+ #
759
+ # @param [String] :name The layer 3 interface name.
760
+ #
761
+ # @param [Integer] :vrid The virtual router ID.
762
+ #
763
+ # @param [Array<String>] :ip_addrs Array of secondary IPv4 address.
764
+ # An empty array will remove all secondary IPv4 addresses set for
765
+ # the virtual router on the specified layer 3 interface.
766
+ #
767
+ # @return [Boolean] returns true if the command complete successfully
768
+ def set_secondary_ip(name, vrid, ip_addrs)
769
+ cmds = build_secondary_ip_cmd(name, vrid, ip_addrs)
770
+ return true if cmds.empty?
771
+ configure_interface(name, cmds)
772
+ end
773
+
774
+ ##
775
+ # set_ip_version sets the VRRP version for a virtual router.
776
+ #
777
+ # @commands
778
+ # interface <name>
779
+ # {no | default} vrrp <vrid> ip version <version>
780
+ #
781
+ # @param [String] :name The layer 3 interface name.
782
+ # @param [Integer] :vrid The virtual router ID.
783
+ # @param [hash] :opts Optional keyword arguments
784
+ #
785
+ # @option :opts [String] :value The VRRP version.
786
+ #
787
+ # @option :opts [Boolean] :enable If false then the command is
788
+ # negated. Default is true.
789
+ #
790
+ # @option :opts [Boolean] :default Configure the VRRP version using
791
+ # the default keyword.
792
+ #
793
+ # @return [Boolean] returns true if the command complete successfully
794
+ def set_ip_version(name, vrid, opts = {})
795
+ cmd = "vrrp #{vrid} ip version"
796
+ configure_interface(name, command_builder(cmd, opts))
797
+ end
798
+
799
+ ##
800
+ # set_timers_advertise sets the interval between successive
801
+ # advertisement messages that the switch sends to routers in the
802
+ # specified virtual router ID.
803
+ #
804
+ # @commands
805
+ # interface <name>
806
+ # {no | default} vrrp <vrid> timers advertise <secs>
807
+ #
808
+ # @param [String] :name The layer 3 interface name.
809
+ # @param [Integer] :vrid The virtual router ID.
810
+ # @param [hash] :opts Optional keyword arguments
811
+ #
812
+ # @option :opts [String] :value The timer value in seconds.
813
+ #
814
+ # @option :opts [Boolean] :enable If false then the command is
815
+ # negated. Default is true.
816
+ #
817
+ # @option :opts [Boolean] :default Configure the timer advertise value
818
+ # using the default keyword.
819
+ #
820
+ # @return [Boolean] returns true if the command complete successfully
821
+ def set_timers_advertise(name, vrid, opts = {})
822
+ cmd = "vrrp #{vrid} timers advertise"
823
+ configure_interface(name, command_builder(cmd, opts))
824
+ end
825
+
826
+ ##
827
+ # set_mac_addr_adv_interval sets the interval in seconds between
828
+ # advertisement packets sent to VRRP group members for the
829
+ # specified virtual router ID.
830
+ #
831
+ # @commands
832
+ # interface <name>
833
+ # {no | default} vrrp <vrid> mac-address advertisement-interval <secs>
834
+ #
835
+ # @param [String] :name The layer 3 interface name.
836
+ # @param [Integer] :vrid The virtual router ID.
837
+ # @param [hash] :opts Optional keyword arguments
838
+ #
839
+ # @option :opts [String] :value The mac address advertisement interval
840
+ # value in seconds.
841
+ #
842
+ # @option :opts [Boolean] :enable If false then the command is
843
+ # negated. Default is true.
844
+ #
845
+ # @option :opts [Boolean] :default Configure the timer advertise value
846
+ # using the default keyword.
847
+ #
848
+ # @return [Boolean] returns true if the command complete successfully
849
+ def set_mac_addr_adv_interval(name, vrid, opts = {})
850
+ cmd = "vrrp #{vrid} mac-address advertisement-interval"
851
+ configure_interface(name, command_builder(cmd, opts))
852
+ end
853
+
854
+ ##
855
+ # set_preempt sets the virtual router's preempt mode setting. When
856
+ # preempt mode is enabled, if the switch has a higher priority it
857
+ # will preempt the current master virtual router. When preempt mode
858
+ # is disabled, the switch can become the master virtual router only
859
+ # when a master virtual router is not present on the subnet,
860
+ # regardless of priority settings.
861
+ #
862
+ # @commands
863
+ # interface <name>
864
+ # {no | default} vrrp <vrid> preempt
865
+ #
866
+ # @param [String] :name The layer 3 interface name.
867
+ # @param [Integer] :vrid The virtual router ID.
868
+ # @param [hash] :opts Optional keyword arguments
869
+ #
870
+ # @option :opts [Boolean] :enable If enable is true then the virtual
871
+ # router preempt mode is administratively enabled for the interface
872
+ # and if enable is false then the virtual router preempt mode is
873
+ # administratively disabled for the interface. Default is true.
874
+ #
875
+ # @option :opts [Boolean] :default Configure the timer advertise value
876
+ # using the default keyword.
877
+ #
878
+ # @return [Boolean] returns true if the command complete successfully
879
+ def set_preempt(name, vrid, opts = {})
880
+ fail 'set_preempt has the value option set' if opts[:value]
881
+ cmd = "vrrp #{vrid} preempt"
882
+ configure_interface(name, command_builder(cmd, opts))
883
+ end
884
+
885
+ ##
886
+ # set_preempt_delay_min sets the minimum time in seconds for the
887
+ # virtual router to wait before taking over the active role.
888
+ #
889
+ # @commands
890
+ # interface <name>
891
+ # {no | default} vrrp <vrid> preempt delay minimum <secs>
892
+ #
893
+ # @param [String] :name The layer 3 interface name.
894
+ # @param [Integer] :vrid The virtual router ID.
895
+ # @param [hash] :opts Optional keyword arguments
896
+ #
897
+ # @option :opts [String] :value The preempt delay minimum value.
898
+ #
899
+ # @option :opts [Boolean] :enable If false then the command is
900
+ # negated. Default is true.
901
+ #
902
+ # @option :opts [Boolean] :default Configure the preempt delay minimum
903
+ # value using the default keyword.
904
+ #
905
+ # @return [Boolean] returns true if the command complete successfully
906
+ def set_preempt_delay_min(name, vrid, opts = {})
907
+ cmd = "vrrp #{vrid} preempt delay minimum"
908
+ configure_interface(name, command_builder(cmd, opts))
909
+ end
910
+
911
+ ##
912
+ # set_preempt_delay_reload sets the preemption delay after a reload
913
+ # only. This delay period applies only to the first interface-up
914
+ # event after the virtual router has reloaded.
915
+ #
916
+ # @commands
917
+ # interface <name>
918
+ # {no | default} vrrp <vrid> preempt delay reload <secs>
919
+ #
920
+ # @param [String] :name The layer 3 interface name.
921
+ # @param [Integer] :vrid The virtual router ID.
922
+ # @param [hash] :opts Optional keyword arguments
923
+ #
924
+ # @option :opts [String] :value The preempt delay reload value.
925
+ #
926
+ # @option :opts [Boolean] :enable If false then the command is
927
+ # negated. Default is true.
928
+ #
929
+ # @option :opts [Boolean] :default Configure the preempt delay reload
930
+ # value using the default keyword.
931
+ #
932
+ # @return [Boolean] returns true if the command complete successfully
933
+ def set_preempt_delay_reload(name, vrid, opts = {})
934
+ cmd = "vrrp #{vrid} preempt delay reload"
935
+ configure_interface(name, command_builder(cmd, opts))
936
+ end
937
+
938
+ ##
939
+ # set_delay_reload sets the delay between system reboot and VRRP
940
+ # initialization for the virtual router.
941
+ #
942
+ # @commands
943
+ # interface <name>
944
+ # {no | default} vrrp <vrid> delay reload <secs>
945
+ #
946
+ # @param [String] :name The layer 3 interface name.
947
+ # @param [Integer] :vrid The virtual router ID.
948
+ # @param [hash] :opts Optional keyword arguments
949
+ #
950
+ # @option :opts [String] :value The delay reload value.
951
+ #
952
+ # @option :opts [Boolean] :enable If false then the command is
953
+ # negated. Default is true.
954
+ #
955
+ # @option :opts [Boolean] :default Configure the delay reload
956
+ # value using the default keyword.
957
+ #
958
+ # @return [Boolean] returns true if the command complete successfully
959
+ def set_delay_reload(name, vrid, opts = {})
960
+ cmd = "vrrp #{vrid} delay reload"
961
+ configure_interface(name, command_builder(cmd, opts))
962
+ end
963
+
964
+ ##
965
+ # build_tracks_cmd builds the array of commands required
966
+ # to update the tracks. This method allows the
967
+ # create methods to leverage the code in the setter.
968
+ #
969
+ # @api private
970
+ #
971
+ # @param [String] :name The layer 3 interface name.
972
+ #
973
+ # @param [Integer] :vrid The virtual router ID.
974
+ #
975
+ # @param [Array<Hash>] :tracks Array of a hash of track information.
976
+ # Hash format: { name: 'Eth2', action: 'decrement', amount: 33 },
977
+ # The name and action key are required. The amount key should only
978
+ # be specified if the action is shutdown. The valid actions are
979
+ # 'decrement' and 'shutdown'. An empty array will remove all tracks
980
+ # set for the virtual router on the specified layer 3 interface.
981
+ #
982
+ # @return [Array<String>] Returns the array of commands. The
983
+ # array could be empty.
984
+ def build_tracks_cmd(name, vrid, tracks)
985
+ # Validate the track hash
986
+ valid_keys = [:name, :action, :amount]
987
+ # rubocop:disable Style/Next
988
+ tracks.each do |track|
989
+ track.keys do |key|
990
+ unless valid_keys.include?(key)
991
+ fail ArgumentError, 'Key: #{key} invalid in track hash'
992
+ end
993
+ end
994
+ unless track.key?(:name) && track.key?(:action)
995
+ fail ArgumentError, 'Must specify :name and :action in track hash'
996
+ end
997
+ unless track[:action] == 'decrement' || track[:action] == 'shutdown'
998
+ fail ArgumentError, "Action must be 'decrement' or 'shutdown'"
999
+ end
1000
+ if track.key?(:amount) && track[:action] != 'decrement'
1001
+ fail ArgumentError, "Action must be 'decrement' to set amount"
1002
+ end
1003
+ if track.key?(:amount)
1004
+ track[:amount] = track[:amount].to_i
1005
+ if track[:amount] < 0
1006
+ fail ArgumentError, 'Amount must be greater than zero'
1007
+ end
1008
+ end
1009
+ end
1010
+
1011
+ tracks = Set.new tracks
1012
+
1013
+ # Get the current tracks set for the virtual router
1014
+ # A return of nil means that nothing has been configured for
1015
+ # the virtual router.
1016
+ vrrp = get(name)
1017
+ vrrp = [] if vrrp.nil?
1018
+
1019
+ if vrrp.key?(vrid)
1020
+ current_tracks = Set.new vrrp[vrid][:track]
1021
+ else
1022
+ current_tracks = Set.new []
1023
+ end
1024
+
1025
+ cmds = []
1026
+ # Add commands to delete any tracks that are
1027
+ # currently set for the virtual router but not in tracks.
1028
+ current_tracks.difference(tracks).each do |tk|
1029
+ cmds << "no vrrp #{vrid} track #{tk[:name]} #{tk[:action]}"
1030
+ end
1031
+
1032
+ # Add commands to add any tracks that are
1033
+ # not currently set for the virtual router but are in tracks.
1034
+ tracks.difference(current_tracks).each do |tk|
1035
+ cmd = "vrrp #{vrid} track #{tk[:name]} #{tk[:action]}"
1036
+ cmd << " #{tk[:amount]}" if tk.key?(:amount)
1037
+ cmds << cmd
1038
+ end
1039
+ cmds
1040
+ end
1041
+ private :build_tracks_cmd
1042
+
1043
+ # set_tracks configures the set of track settings associated with
1044
+ # the virtual router. The tracks value passed should be an array of
1045
+ # hashes, each hash containing a track entry. This method will remove
1046
+ # tracks that are currently set for the virtual router but not included
1047
+ # in the tracks array value passed in. The method will then add
1048
+ # tracks that are not currently set for the virtual router but are
1049
+ # included in the tracks array value passed in.
1050
+ #
1051
+ # @commands
1052
+ # interface <name>
1053
+ # {no} vrrp <vrid> track <name> <action> [<amount>]
1054
+ #
1055
+ # @param [String] :name The layer 3 interface name.
1056
+ #
1057
+ # @param [Integer] :vrid The virtual router ID.
1058
+ #
1059
+ # @param [Array<Hash>] :tracks Array of a hash of track information.
1060
+ # Hash format: { name: 'Eth2', action: 'decrement', amount: 33 },
1061
+ # An empty array will remove all tracks set for
1062
+ # the virtual router on the specified layer 3 interface.
1063
+ #
1064
+ # @return [Boolean] returns true if the command complete successfully
1065
+ def set_tracks(name, vrid, tracks)
1066
+ cmds = build_tracks_cmd(name, vrid, tracks)
1067
+ return true if cmds.empty?
1068
+ configure_interface(name, cmds)
1069
+ end
1070
+ end
1071
+ end
1072
+ end