rbeapi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/.gitignore +35 -0
  2. data/Gemfile +25 -0
  3. data/Guardfile +15 -0
  4. data/LICENSE +28 -0
  5. data/README.md +218 -0
  6. data/Rakefile +12 -0
  7. data/lib/rbeapi.rb +32 -0
  8. data/lib/rbeapi/api.rb +135 -0
  9. data/lib/rbeapi/api/aaa.rb +410 -0
  10. data/lib/rbeapi/api/dns.rb +198 -0
  11. data/lib/rbeapi/api/interfaces.rb +1193 -0
  12. data/lib/rbeapi/api/ipinterfaces.rb +328 -0
  13. data/lib/rbeapi/api/logging.rb +157 -0
  14. data/lib/rbeapi/api/mlag.rb +519 -0
  15. data/lib/rbeapi/api/ntp.rb +201 -0
  16. data/lib/rbeapi/api/ospf.rb +214 -0
  17. data/lib/rbeapi/api/prefixlists.rb +98 -0
  18. data/lib/rbeapi/api/radius.rb +317 -0
  19. data/lib/rbeapi/api/radius.rb.old +399 -0
  20. data/lib/rbeapi/api/routemaps.rb +100 -0
  21. data/lib/rbeapi/api/snmp.rb +427 -0
  22. data/lib/rbeapi/api/staticroutes.rb +88 -0
  23. data/lib/rbeapi/api/stp.rb +381 -0
  24. data/lib/rbeapi/api/switchports.rb +272 -0
  25. data/lib/rbeapi/api/system.rb +87 -0
  26. data/lib/rbeapi/api/tacacs.rb +236 -0
  27. data/lib/rbeapi/api/varp.rb +181 -0
  28. data/lib/rbeapi/api/vlans.rb +338 -0
  29. data/lib/rbeapi/client.rb +454 -0
  30. data/lib/rbeapi/eapilib.rb +334 -0
  31. data/lib/rbeapi/netdev/snmp.rb +370 -0
  32. data/lib/rbeapi/utils.rb +70 -0
  33. data/lib/rbeapi/version.rb +37 -0
  34. data/rbeapi.gemspec +32 -0
  35. data/spec/fixtures/dut.conf +5 -0
  36. data/spec/spec_helper.rb +22 -0
  37. data/spec/support/fixtures.rb +114 -0
  38. data/spec/support/shared_examples_for_api_modules.rb +124 -0
  39. data/spec/system/api_ospf_interfaces_spec.rb +58 -0
  40. data/spec/system/api_ospf_spec.rb +111 -0
  41. data/spec/system/api_varp_interfaces_spec.rb +60 -0
  42. data/spec/system/api_varp_spec.rb +44 -0
  43. data/spec/system/rbeapi/api/dns_spec.rb +77 -0
  44. data/spec/system/rbeapi/api/interfaces_base_spec.rb +94 -0
  45. data/spec/system/rbeapi/api/interfaces_ethernet_spec.rb +135 -0
  46. data/spec/system/rbeapi/api/interfaces_portchannel_spec.rb +188 -0
  47. data/spec/system/rbeapi/api/interfaces_vxlan_spec.rb +115 -0
  48. data/spec/system/rbeapi/api/ipinterfaces_spec.rb +97 -0
  49. data/spec/system/rbeapi/api/logging_spec.rb +65 -0
  50. data/spec/system/rbeapi/api/mlag_interfaces_spec.rb +80 -0
  51. data/spec/system/rbeapi/api/mlag_spec.rb +94 -0
  52. data/spec/system/rbeapi/api/ntp_spec.rb +76 -0
  53. data/spec/system/rbeapi/api/snmp_spec.rb +68 -0
  54. data/spec/system/rbeapi/api/stp_instances_spec.rb +61 -0
  55. data/spec/system/rbeapi/api/stp_interfaces_spec.rb +71 -0
  56. data/spec/system/rbeapi/api/stp_spec.rb +57 -0
  57. data/spec/system/rbeapi/api/switchports_spec.rb +135 -0
  58. data/spec/system/rbeapi/api/system_spec.rb +38 -0
  59. data/spec/system/rbeapi/api/vlans_spec.rb +121 -0
  60. metadata +274 -0
@@ -0,0 +1,1193 @@
1
+ #
2
+ # Copyright (c) 2014, 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
+ require 'rbeapi/utils'
34
+
35
+ module Rbeapi
36
+
37
+ module Api
38
+
39
+ class Interfaces < Entity
40
+
41
+ METHODS = [:create, :delete, :default]
42
+
43
+ def initialize(node)
44
+ super(node)
45
+ @instances = {}
46
+ end
47
+
48
+ def get(name)
49
+ get_instance(name).get(name)
50
+ end
51
+
52
+ def getall
53
+ interfaces = config.scan(/(?<=^interface\s).+$/)
54
+
55
+ interfaces.each_with_object({}) do |name, hsh|
56
+ data = get(name)
57
+ hsh[name] = data if data
58
+ end
59
+ end
60
+
61
+ def get_instance(name)
62
+ name = name[0,2].upcase
63
+ case name
64
+ when 'ET'
65
+ cls = 'Rbeapi::Api::EthernetInterface'
66
+ when 'PO'
67
+ cls = 'Rbeapi::Api::PortchannelInterface'
68
+ when 'VX'
69
+ cls = 'Rbeapi::Api::VxlanInterface'
70
+ else
71
+ cls = 'Rbeapi::Api::BaseInterface'
72
+ end
73
+
74
+ return @instances[name] if @instances.include?(cls)
75
+ instance = Rbeapi::Utils.class_from_string(cls).new(@node)
76
+ @instances[name] = instance
77
+ instance
78
+ end
79
+
80
+ def method_missing(method_name, *args, &block)
81
+ if method_name.to_s =~ /set_(.*)/ || METHODS.include?(method_name)
82
+ instance = get_instance(args[0])
83
+ instance.send(method_name.to_sym, *args, &block)
84
+ end
85
+ end
86
+
87
+ def respond_to?(method_name, name = nil)
88
+ return super unless name
89
+ instance = get_instance(name)
90
+ instance.respond_to?(method_name) || super
91
+ end
92
+
93
+ end
94
+
95
+ ##
96
+ # The BaseInterface class extends Entity and provides an implementation
97
+ # that is common to all interfaces configured in EOS.
98
+ class BaseInterface < Entity
99
+
100
+ DEFAULT_INTF_DESCRIPTION = ''
101
+
102
+ ##
103
+ # get returns the specified interface resource hash that represents the
104
+ # node's current interface configuration. The BaseInterface class
105
+ # provides all the set of attributres that are common to all interfaces
106
+ # in EOS. This method will return an interface type of generic
107
+ #
108
+ # @example
109
+ # {
110
+ # name: <string>
111
+ # type: 'generic'
112
+ # description: <string>
113
+ # shutdown: [true, false]
114
+ # }
115
+ #
116
+ # @param [String] :name The name of the interface to return from the
117
+ # running-configuration
118
+ #
119
+ # @return [nil, Hash<String, Object>] Returns a hash of the interface
120
+ # properties if the interface name was found in the running
121
+ # configuration. If the interface was not found, nil is returned
122
+ def get(name)
123
+ config = get_block("^interface #{name}")
124
+ return nil unless config
125
+
126
+ response = { name: name, type: 'generic' }
127
+ response.merge!(parse_description(config))
128
+ response.merge!(parse_shutdown(config))
129
+ response
130
+ end
131
+
132
+ ##
133
+ # parse_description scans the provided configuration block and parses
134
+ # the description value if it exists in the cofiguration. If the
135
+ # description value is not configured, then the DEFALT_INTF_DESCRIPTION
136
+ # value is returned. The hash returned by this method is inteded to be
137
+ # merged into the interface resource hash returned by the get method.
138
+ #
139
+ # @api private
140
+ #
141
+ # @eturn [Hash<Symbol, Object>] resource hash attribute
142
+ def parse_description(config)
143
+ mdata = /^\s{3}description\s(.+)$/.match(config)
144
+ { description: mdata.nil? ? DEFAULT_INTF_DESCRIPTION : mdata[1] }
145
+ end
146
+ private :parse_description
147
+
148
+ ##
149
+ # parse_shutdown scans the provided configuration block and parses
150
+ # the shutdown value. If the shutdown value is configured then true
151
+ # is returned as its value otherwise false is returned. The hash
152
+ # returned by this method is intended to be merged into the interface
153
+ # ressource hash returned by the get method.
154
+ #
155
+ # @api private
156
+ #
157
+ # @return [Hash<Symbol, Object>] resource hash attribute
158
+ def parse_shutdown(config)
159
+ value = /no shutdown/ =~ config
160
+ { shutdown: value.nil? }
161
+ end
162
+ private :parse_shutdown
163
+
164
+ ##
165
+ # create will create a new interface resource in the node's current
166
+ # configuration with the specified interface name. If the create
167
+ # method is called and the interface already exists, this method will
168
+ # return successful
169
+ #
170
+ # @eos_version 4.13.7M
171
+ #
172
+ # @commands
173
+ # interface <value>
174
+ #
175
+ # @param [String] :value The interface name to create on the node. The
176
+ # interface name must be the full interface identifier (ie Loopback,
177
+ # not Lo)
178
+ #
179
+ # @return [Boolean] returns true if the command completed succesfully
180
+ def create(value)
181
+ configure("interface #{value}")
182
+ end
183
+
184
+ ##
185
+ # delete will delete an existing interface resource in the node's
186
+ # current configuration with the specified interface name. If the
187
+ # delete method is called and interface does not exist, this method
188
+ # will return successful
189
+ #
190
+ # @eos_version 4.13.7M
191
+ #
192
+ # @commands
193
+ # no interface <value>
194
+ #
195
+ # @param [String] :value The interface name to delete from the node.
196
+ # The interface name must be the full interface identifier
197
+ # (ie Loopback, no Lo)
198
+ #
199
+ # @return [Boolean] returns true if the command completed successfully
200
+ def delete(value)
201
+ configure("no interface #{value}")
202
+ end
203
+
204
+ ##
205
+ # default will configure the interface using the default keyword. For
206
+ # virtual interfaces this is equivalent to deleting the interface. For
207
+ # physical interfaces, the entire interface configuration will be set
208
+ # to defaults.
209
+ #
210
+ # @eos_version 4.13.7M
211
+ #
212
+ # @commands
213
+ # default interface <value>
214
+ #
215
+ # @param [String] :value The interface name to default in the node. The
216
+ # interface name must be the full interface identifier (ie Loopback,
217
+ # not Lo)
218
+ #
219
+ # @return [Boolean] returns true if the command completed successfully
220
+ def default(value)
221
+ configure("default interface #{value}")
222
+ end
223
+
224
+ ##
225
+ # set_description configures the description value for the specified
226
+ # interface name in the nodes running configuration. If the value is
227
+ # not provided in the opts keyword hash then the description value is
228
+ # negated using the no keyword. If the default keyword is set to
229
+ # true, then the description value is defaulted using the default
230
+ # keyword. The default keyword takes precedence over the value
231
+ # keyword if both are provided.
232
+ #
233
+ # @eos_version 4.13.7M
234
+ #
235
+ # @commands
236
+ # interface <name>
237
+ # description <value>
238
+ # no description
239
+ # default description
240
+ #
241
+ # @param [String] :name The interface name to apply the configuration
242
+ # to. The name value must be the full interface identifier
243
+ #
244
+ # @param [hash] :opts Optional keyword arguments
245
+ #
246
+ # @option :opts [String] :value The value to configure the description
247
+ # to in the node's configuration.
248
+ #
249
+ # @option :opts [Boolean] :default Configure the interface description
250
+ # using the default keyword
251
+ #
252
+ # @return [Boolean] returns true if the command completed successfully
253
+ def set_description(name, opts = {})
254
+ value = opts[:value]
255
+ value = nil if value.empty?
256
+ default = opts.fetch(:default, false)
257
+
258
+ cmds = ["interface #{name}"]
259
+ case default
260
+ when true
261
+ cmds << 'default description'
262
+ when false
263
+ cmds << (value.nil? ? 'no description' : "description #{value}")
264
+ end
265
+ configure(cmds)
266
+ end
267
+
268
+ ##
269
+ # set_shutdown configures the adminstrative state of the specified
270
+ # interface in the node. If the value is true, then the interface
271
+ # is adminstratively disabled. If the value is false, then the
272
+ # interface is adminstratively enabled. If no value is provided, then
273
+ # the interface is configured with the no keyword which is equivalent
274
+ # to false. If the default keyword is set to true, then the interface
275
+ # shutdown value is configured using the default keyword. The default
276
+ # keyword takes precedence over the value keyword if both are provided.
277
+ #
278
+ # @eos_version 4.13.7M
279
+ #
280
+ # @commands
281
+ # interface <name<
282
+ # shutdown
283
+ # no shutdown
284
+ # default shutdown
285
+ #
286
+ # @param [String] :name The interface name to apply the configuration
287
+ # to. The name value must be the full interface identifier
288
+ #
289
+ # @param [hash] :opts Optional keyword arguments
290
+ #
291
+ # @option :opts [Boolean] :value True if the interface should be
292
+ # administratively disabled or false if the interface should be
293
+ # administratively enabled
294
+ #
295
+ # @option :opts [Boolean] :default Configure the interface shutdown
296
+ # using the default keyword
297
+ #
298
+ # @return [Boolean] returns true if the command completed successfully
299
+ def set_shutdown(name, opts = {})
300
+ value = opts[:value]
301
+ default = opts.fetch(:default, false)
302
+
303
+ cmds = ["interface #{name}"]
304
+ case default
305
+ when true
306
+ cmds << 'default shutdown'
307
+ when false
308
+ cmds << (value ? 'shutdown' : 'no shutdown')
309
+ end
310
+ configure(cmds)
311
+ end
312
+ end
313
+
314
+ class EthernetInterface < BaseInterface
315
+
316
+ DEFAULT_ETH_FLOWC_TX = 'off'
317
+ DEFAULT_ETH_FLOWC_RX = 'off'
318
+ DEFAULT_SPEED = 'auto'
319
+ DEFAULT_FORCED = false
320
+
321
+ ##
322
+ # get returns the specified Etherent interface resource hash that
323
+ # respresents the interface's current configuration in th e node.
324
+ #
325
+ # The resource hash returned contains the following information:
326
+ #
327
+ # * name (string): the interface name (eg Ethernet1)
328
+ # * type (string): will always be 'ethernet'
329
+ # * description (string): the interface description value
330
+ # * speed (string): the current speed setting for the interface speed
331
+ # * forced (boolean): true if autonegotiation is disabled otherwise
332
+ # false
333
+ # * sflow (boolean): true if sflow is enabled on the interface
334
+ # otherwise false
335
+ # * flowcontrol_send (string): the inteface flowcontrol send value.
336
+ # Valid values are 'on' or 'off'
337
+ # * flowconrol_receive (string): the interface flowcontrol receive
338
+ # value. Valid values are 'on' or 'off'
339
+ #
340
+ # @param [String] :name The interface name to return a resource hash
341
+ # for from the node's running configuration
342
+ #
343
+ # @return [nil, Hash<Symbol, Object>] Returns the interface resource as
344
+ # a hash. If the specified interface name is not found in the node's
345
+ # configuration a nil object is returned
346
+ def get(name)
347
+ config = get_block("^interface #{name}")
348
+ return nil unless config
349
+
350
+ response = super(name)
351
+ response[:type] = 'ethernet'
352
+
353
+ response.merge!(parse_speed(config))
354
+ response.merge!(parse_sflow(config))
355
+ response.merge!(parse_flowcontrol_send(config))
356
+ response.merge!(parse_flowcontrol_receive(config))
357
+
358
+ response
359
+ end
360
+
361
+ ##
362
+ # parse_speed scans the provided configuration block and parses the speed
363
+ # value. If the speed value is not found in the interface configuration
364
+ # block provided, DEFAULT_SPEED and DEFAULT_FORCED are used. The
365
+ # returned hash is intended to be merged into the interface resource hash
366
+ #
367
+ # @api private
368
+ #
369
+ # @return [Hash<Symbol, Object>] resource hash attribute
370
+ def parse_speed(config)
371
+ value = config.scan(/speed (forced)?[ ]?(\w+)/).first
372
+ return { speed: DEFAULT_SPEED, forced: DEFAULT_FORCED } unless value
373
+ (forced, value) = value.first
374
+ { speed: value, forced: forced != nil }
375
+ end
376
+ private :parse_speed
377
+
378
+ ##
379
+ # parse_sflow scans the provided configuration block and parse the
380
+ # sflow value. The sflow values true if sflow is enabled on the
381
+ # interface or returns false if it is not enabled. The hash returned
382
+ # is intended to be merged into the interface hash.
383
+ #
384
+ # @api private
385
+ #
386
+ # @return [Hash<Symbol, Object>] resource hash attribute
387
+ def parse_sflow(config)
388
+ value = /no sflow enable/ =~ config
389
+ { sflow: value.nil? }
390
+ end
391
+ private :parse_sflow
392
+
393
+ ##
394
+ # parse_flowcontrol_send scans the provided configuration block and
395
+ # parses the flowcontrol send value. If the interface flowcontrol value
396
+ # is not configured, then this method will return the value of
397
+ # DEFAULT_ETH_FLOWC_TX. The hash returned is intended to be merged into
398
+ # the interface resource hash.
399
+ #
400
+ # @api private
401
+ #
402
+ # @return [Hash<Symbol, Object>] resource hash attribute
403
+ def parse_flowcontrol_send(config)
404
+ mdata = /flowcontrol send (\w+)$/.match(config)
405
+ { flowcontrol_send: mdata.nil? ? DEFAULT_ETH_FLOWC_TX : mdata[1] }
406
+ end
407
+ private :parse_flowcontrol_send
408
+
409
+ ##
410
+ # parse_flowcontrol_receive scans the provided configuration block and
411
+ # parse the flowcontrol receive value. If the interface flowcontrol
412
+ # value is not configured, then this method will return the value of
413
+ # DEFAULT_ETH_FLOWC_RX. The hash returned is intended to be merged into
414
+ # the interface resource hash.
415
+ #
416
+ # @api private
417
+ #
418
+ # @return [Hash<Symbol, Object>] resource hash attribute
419
+ def parse_flowcontrol_receive(config)
420
+ mdata = /flowcontrol receive (\w+)$/.match(config)
421
+ { flowcontrol_receive: mdata.nil? ? DEFAULT_ETH_FLOWC_RX : mdata[1] }
422
+ end
423
+ private :parse_flowcontrol_receive
424
+
425
+ ##
426
+ # create overrides the create method from the BaseInterface and raises
427
+ # an exception because Ethernet interface creation is not supported.
428
+ #
429
+ # @param [String] :name The name of the interface
430
+ #
431
+ # @raise [NotImplementedError] Creation of physical Ethernet interfaces
432
+ # is not supported
433
+ def create(name)
434
+ raise NotImplementedError, 'creating Ethernet interfaces is '\
435
+ 'not supported'
436
+ end
437
+
438
+ ##
439
+ # delete overrides the delete method fro the BaseInterface instance and
440
+ # raises an exception because Ethernet interface deletion is not
441
+ # supported.
442
+ #
443
+ # @param [String] :name The name of the interface
444
+ #
445
+ # @raise [NotImplementedError] Deletion of physical Ethernet interfaces
446
+ # is not supported
447
+ def delete(name)
448
+ raise NotImplementedError, 'deleting Ethernet interfaces is '\
449
+ 'not supported'
450
+ end
451
+
452
+ ##
453
+ # set_speed configures the interface speed and negotiation values on the
454
+ # specified interface. If the value option is not provide, the speed
455
+ # setting is configured using the no keyword. If the default options is
456
+ # set to true, then the speed setting is configured using the default
457
+ # keyword. If both options are specified, the default keyword takes
458
+ # precedence.
459
+ #
460
+ # @eos_version 4.13.7M
461
+ #
462
+ # @commands
463
+ # interface <name>
464
+ # speed [forced] <value>
465
+ # no speed
466
+ # default speed
467
+ #
468
+ # @param [String] :name The interface name to apply the configuration
469
+ # values to. The name must be the full interface identifier.
470
+ #
471
+ # @param [Hash] :opts optional keyword arguments
472
+ #
473
+ # @option [String] :value The value to configure the speed setting to in
474
+ # the nodes running configuration
475
+ #
476
+ # @option [Boolean] :forced Specifies if autonegotiation should be
477
+ # enabled (true) or disabled (false)
478
+ #
479
+ # @option :opts [Boolean] :default Configures the sflow value on the
480
+ # interface using the default keyword
481
+ #
482
+ # @return [Boolean] returns true if the command completed successfully
483
+ def set_speed(name, opts = {})
484
+ value = opts[:value]
485
+ forced = opts.fetch(:forced, false)
486
+ default = opts.fetch(:default, false)
487
+
488
+ forced = 'forced' if forced
489
+ forced = '' if value == 'auto'
490
+
491
+ cmds = ["interface #{name}"]
492
+ case default
493
+ when true
494
+ cmds << 'default speed'
495
+ when false
496
+ cmds << value ? "speed #{forced} #{value}" : 'no speed'
497
+ end
498
+ configure cmds
499
+ end
500
+
501
+ ##
502
+ # set_sflow configures the administrative state of sflow on the
503
+ # interface. Setting the value to true enables sflow on the interface
504
+ # and setting the value to false disables sflow on the interface. If the
505
+ # value is not provided, the sflow state is negated using the no keyword.
506
+ # If the default keyword is set to true, then the sflow value is
507
+ # defaulted using the default keyword. The default keyword takes
508
+ # precedence over the value keyword
509
+ #
510
+ # @eos_version 4.13.7M
511
+ #
512
+ # @commands
513
+ # interface <name>
514
+ # sflow enable
515
+ # no sflow enable
516
+ # default sflow
517
+ #
518
+ # @param [String] :name The interface name to apply the configuration
519
+ # values to. The name must be the full interface identifier.
520
+ #
521
+ # @param [Hash] :opts optional keyword arguments
522
+ #
523
+ # @option :opts [Boolean] :value Enables sflow if the value is true or
524
+ # disables sflow on the interface if false
525
+ #
526
+ # @option :opts [Boolean] :default Configures the sflow value on the
527
+ # interface using the default keyword
528
+ #
529
+ # @return [Boolean] returns true if the command completed successfully
530
+ def set_sflow(name, opts = {})
531
+ value = opts[:value]
532
+ default = opts.fetch(:default, false)
533
+
534
+ cmds = ["interface #{name}"]
535
+ case default
536
+ when true
537
+ cmds << 'default sflow'
538
+ when false
539
+ cmds << (value ? 'sflow enable' : 'no sflow enable')
540
+ end
541
+ configure(cmds)
542
+ end
543
+
544
+ ##
545
+ # set_flowcontrol configures the flowcontrol value either on or off for
546
+ # the for the specified interface in the specified direction (either send
547
+ # or receive). If the value is not provided then the configuration is
548
+ # negated using the no keyword. If the default keyword is set to true,
549
+ # then the state value is defaulted using the default keyword. The
550
+ # default keyword takes precedence over the value keyword
551
+ #
552
+ # @eos_version 4.13.7M
553
+ #
554
+ # @commands
555
+ # interface <name>
556
+ # flowcontrol [send | receive] [on, off]
557
+ # no flowcontrol [send | receive]
558
+ # default flowcontrol [send | receive]
559
+ #
560
+ # @param [String] :name The interface name to apply the configuration
561
+ # values to. The name must be the full interface identifier.
562
+ #
563
+ # @param [String] :direction Specifies the flowcontrol direction to
564
+ # configure. Valid values include send and receive.
565
+ #
566
+ # @param [Hash] :opts optional keyword arguments
567
+ #
568
+ # @option :opts [String] :value Specifies the value to configure the
569
+ # flowcontrol setting for. Valid values include on or off
570
+ #
571
+ # @option :opts [Boolean] :default Configures the flowcontrol value on
572
+ # the interface using the default keyword
573
+ #
574
+ # @return [Boolean] returns true if the command completed successfully
575
+ def set_flowcontrol(name, direction, opts = {})
576
+ value = opts[:value]
577
+ default = opts.fetch(:default, false)
578
+
579
+ commands = ["interface #{name}"]
580
+ case default
581
+ when true
582
+ commands << "default flowcontrol #{direction}"
583
+ when false
584
+ commands << (value.nil? ? "no flowcontrol #{direction}" :
585
+ "flowcontrol #{direction} #{value}")
586
+ end
587
+ configure(commands)
588
+ end
589
+
590
+ ##
591
+ # set_flowcontrol_send is a convenience function for configuring the
592
+ # value of interface flowcontrol.
593
+ #
594
+ # @see set_flowcontrol
595
+ #
596
+ # @eos_version 4.13.7M
597
+ #
598
+ # @commands
599
+ # interface <name>
600
+ # flowcontrol [send | receive] [on, off]
601
+ # no flowcontrol [send | receive]
602
+ # default flowcontrol [send | receive]
603
+ #
604
+ # @param [String] :name The interface name to apply the configuration
605
+ # values to. The name must be the full interface identifier.
606
+ #
607
+ # @param [Hash] :opts optional keyword arguments
608
+ #
609
+ # @option :opts [String] :value Specifies the value to configure the
610
+ # flowcontrol setting for. Valid values include on or off
611
+ #
612
+ # @option :opts [Boolean] :default Configures the flowcontrol value on
613
+ # the interface using the default keyword
614
+ #
615
+ # @return [Boolean] returns true if the command completed successfully
616
+ def set_flowcontrol_send(name, opts = {})
617
+ set_flowcontrol(name, 'send', opts)
618
+ end
619
+
620
+ ##
621
+ # set_flowcontrol_receive is a convenience function for configuring th e
622
+ # value of interface flowcontrol
623
+ #
624
+ # @see set_flowcontrol
625
+ #
626
+ # @eos_version 4.13.7M
627
+ #
628
+ # @commands
629
+ # interface <name>
630
+ # flowcontrol [send | receive] [on, off]
631
+ # no flowcontrol [send | receive]
632
+ # default flowcontrol [send | receive]
633
+ #
634
+ # @param [String] :name The interface name to apply the configuration
635
+ # values to. The name must be the full interface identifier.
636
+ #
637
+ # @param [Hash] :opts optional keyword arguments
638
+ #
639
+ # @option :opts [String] :value Specifies the value to configure the
640
+ # flowcontrol setting for. Valid values include on or off
641
+ #
642
+ # @option :opts [Boolean] :default Configures the flowcontrol value on
643
+ # the interface using the default keyword
644
+ #
645
+ # @return [Boolean] returns true if the command completed successfully
646
+ def set_flowcontrol_receive(name, opts = {})
647
+ set_flowcontrol(name, 'receive', opts)
648
+ end
649
+ end
650
+
651
+ class PortchannelInterface < BaseInterface
652
+
653
+ DEFAULT_LACP_FALLBACK = 'disabled'
654
+ DEFAULT_LACP_MODE = 'on'
655
+ DEFAULT_MIN_LINKS = '0'
656
+
657
+ ##
658
+ # get returns the specified port-channel interface configuration from
659
+ # the nodes running configuration as a resource hash. The resource
660
+ # hash returned extends the BaseInterface resource hash, sets the type
661
+ # value to portchannel and adds the portchannel specific attributes
662
+ #
663
+ # @example
664
+ # {
665
+ # type: 'portchannel'
666
+ # description: <string>
667
+ # shutdown: [true, false]
668
+ # members: array[<strings>]
669
+ # lacp_mode: [active, passive, on]
670
+ # minimum_links: <string>
671
+ # lacp_timeout: <string>
672
+ # lacp_fallback: [static, individual, disabled]
673
+ # }
674
+ #
675
+ # @see BaseInterface Interface get example
676
+ #
677
+ # @param [String] :name The name of the portchannel interface to return
678
+ # a resource hash for. The name must be the full interface name of
679
+ # the desired interface.
680
+ #
681
+ # @return [nil, Hash<Symbol, Object>] returns the interface resource as
682
+ # a hash object. If the specified interface does not exist in the
683
+ # running configuration, a nil object is returned
684
+ def get(name)
685
+ config = get_block("^interface #{name}")
686
+ return nil unless config
687
+ response = super(name)
688
+ response[:type] = 'portchannel'
689
+ response.merge!(parse_members(name))
690
+ response.merge!(parse_lacp_mode(name))
691
+ response.merge!(parse_minimum_links(config))
692
+ response.merge!(parse_lacp_fallback(config))
693
+ response.merge!(parse_lacp_timeout(config))
694
+ response
695
+ end
696
+
697
+ ##
698
+ # parse_members scans the nodes running config and returns all of the
699
+ # ethernet members for the port-channel interface specified. If the
700
+ # port-channel interface has no members configured, then this method will
701
+ # assign an empty array as the value for members. The hash returned is
702
+ # intended to be merged into the interface resource hash
703
+ #
704
+ # @api private
705
+ #
706
+ # @param [String] :name The name of the portchannel interface to extract
707
+ # the members for
708
+ #
709
+ # @return [Hash<Symbol, Object>] resource hash attribute
710
+ def parse_members(name)
711
+ grpid = name.scan(/(?<=Port-Channel)\d+/)[0]
712
+ command = "show port-channel #{grpid} all-ports"
713
+ config = node.enable(command, format: 'text')
714
+ values = config.first[:result]['output'].scan(/Ethernet[\d\/]*/)
715
+ { members: values }
716
+ end
717
+ private :parse_members
718
+
719
+ ##
720
+ # parse_lacp_mode scans the member interfaces and returns the configured
721
+ # lacp mode. The lacp mode value must be common across every member
722
+ # in the port channel interface. If no members are configured, the value
723
+ # for lacp_mode will be set using DEFAULT_LACP_MODE. The hash returned is
724
+ # intended to be merged into the interface resource hash
725
+ #
726
+ # @api private
727
+ #
728
+ # @param [String] :name The name of the portchannel interface to extract
729
+ # the members from in order to get the configured lacp_mode
730
+ #
731
+ # @return [Hash<Symbol, Object>] resource hash attribute
732
+ def parse_lacp_mode(name)
733
+ members = parse_members(name)[:members]
734
+ return { lacp_mode: DEFAULT_LACP_MODE } unless members
735
+ config = get_block("interface #{members.first}")
736
+ mdata = /channel-group \d+ mode (\w+)/.match(config)
737
+ { lacp_mode: mdata.nil? ? DEFAULT_LACP_MODE : mdata[1] }
738
+ end
739
+ private :parse_lacp_mode
740
+
741
+ ##
742
+ # parse_minimum_links scans the port-channel configuration and returns
743
+ # the value for port-channel minimum-links. If the value is not found
744
+ # in the interface configuration, then DEFAULT_MIN_LINKS value is used.
745
+ # The hash returned is intended to be merged into the interface
746
+ # resource hash
747
+ #
748
+ # @api private
749
+ #
750
+ # @param [String] :config The interface configuration blcok to extract
751
+ # the minimum links value from
752
+ #
753
+ # @return [Hash<Symbol, Object>] resource hash attribute
754
+ def parse_minimum_links(config)
755
+ mdata = /port-channel min-links (\d+)$/.match(config)
756
+ { minimum_links: mdata.nil? ? DEFAULT_MIN_LINKS : mdata[1] }
757
+ end
758
+ private :parse_minimum_links
759
+
760
+ ##
761
+ # parse_lacp_fallback scans the interface config block and returns the
762
+ # confiured value of the lacp fallback attribute. If the value is not
763
+ # configured, then the method will return the value of
764
+ # DEFAULT_LACP_FALLBACK. The hash returned is intended to be merged into
765
+ # the interface resource hash
766
+ #
767
+ # @api private
768
+ #
769
+ # @param [String] :config The interface configuration block to extract
770
+ # the lacp fallback value from
771
+ #
772
+ # @return [Hash<Symbol, Object>] resource hash attribute
773
+ def parse_lacp_fallback(config)
774
+ mdata = /lacp fallback (static|individual)/.match(config)
775
+ { lacp_fallback: mdata.nil? ? DEFAULT_LACP_FALLBACK : mdata[1] }
776
+ end
777
+ private :parse_lacp_fallback
778
+
779
+ ##
780
+ # parse_lacp_timeout scans the interface config block and returns the
781
+ # value of the lacp fallback timeout value. The value is expected to be
782
+ # found in the interface configuration block. The hash returned is
783
+ # intended to be merged into the interface resource hash
784
+ #
785
+ # @api private
786
+ #
787
+ # @param [String] :config The interface configuration block to extract
788
+ # the lacp timeout value from
789
+ #
790
+ # @return [Hash<Symbol, Object>] resource hash attribute
791
+ def parse_lacp_timeout(config)
792
+ mdata = /lacp fallback timeout (\d+)$/.match(config)
793
+ { lacp_timeout: mdata[1] }
794
+ end
795
+ private :parse_lacp_timeout
796
+
797
+ ##
798
+ # set_minimum_links configures the minimum physical links up required to
799
+ # consider the logical portchannel interface operationally up. If no
800
+ # value is provided then the minimum-links is configured using the no
801
+ # keyword argument. If the default keyword argument is provided and set
802
+ # to true, the minimum-links value is defaulted using the default
803
+ # keyword. The default keyword takes precedence over the value keyword
804
+ # argument if both are provided.
805
+ #
806
+ # @eos_version 4.13.7M
807
+ #
808
+ # @commands
809
+ # interface <name>
810
+ # port-channel min-links <value>
811
+ # no port-channel min-links
812
+ # default port-channel min-links
813
+ #
814
+ # @param [String] :name The interface name to apply the configuration
815
+ # values to. The name must be the full interface identifier.
816
+ #
817
+ # @param [Hash] :opts optional keyword arguments
818
+ #
819
+ # @option :opts [String, Integer] :value Specifies the value to
820
+ # configure the minimum-links to in the configuration. Valid values
821
+ # are in the range of 1 to 16.
822
+ #
823
+ # @option :opts [Boolean] :default Configures the minimum links value on
824
+ # the interface using the default keyword
825
+ #
826
+ # @return [Boolean] returns true if the command completed successfully
827
+ def set_minimum_links(name, opts = {})
828
+ value = opts[:value]
829
+ default = opts.fetch(:default, false)
830
+
831
+ cmds = ["interface #{name}"]
832
+ case default
833
+ when true
834
+ cmds << 'default port-channel min-links'
835
+ when false
836
+ cmds << (value ? "port-channel min-links #{value}" : \
837
+ 'no port-channel min-links')
838
+ end
839
+ configure(cmds)
840
+ end
841
+
842
+ ##
843
+ # set_members configures the set of physical interfaces that comprise the
844
+ # logical port-channel interface. The members value passed should be an
845
+ # array of physical interface names that comprise the port-channel
846
+ # interface. This method will add and remove individual members as
847
+ # required to sync the provided members array
848
+ #
849
+ # @see add_member Adds member links to the port-channel interface
850
+ # @see remove_member Removes member links from the port-channel interface
851
+ #
852
+ # @param [String] :name The name of the port-channel interface to apply
853
+ # the members to. If the port-channel interface does not already exist
854
+ # it will be created
855
+ #
856
+ # @param [Array] :members The array of physical interface members to add
857
+ # to the port-channel logical interface.
858
+ #
859
+ # @return [Boolean] returns true if the command completed successfully
860
+ def set_members(name, members)
861
+ current_members = Set.new parse_members(name)[:members]
862
+ members = Set.new members
863
+
864
+ # remove members from the current port-channel interface
865
+ current_members.difference(members).each do |intf|
866
+ result = remove_member(name, intf)
867
+ return false unless result
868
+ end
869
+
870
+ # add new member interfaces to the port-channel
871
+ members.difference(current_members).each do |intf|
872
+ result = add_member(name, intf)
873
+ return false unless result
874
+ end
875
+
876
+ return true
877
+ end
878
+
879
+ ##
880
+ # add_member adds the interface specified in member to the port-channel
881
+ # interface specified by name in the nodes running-configuration. If
882
+ # the port-channel interface does not already exist, it will be created.
883
+ #
884
+ # @eos_version 4.13.7M
885
+ #
886
+ # @commands
887
+ # interface <name>
888
+ # channel-group <grpid> mode <lacp_mode>
889
+ #
890
+ # @param [String] :name The name of the port-channel interface to apply
891
+ # the configuration to.
892
+ #
893
+ # @param [String] :member The name of the physical ethernet interface to
894
+ # add to the logical port-channel interface.
895
+ #
896
+ # @return [Boolean] returns true if the command completed successfully
897
+ def add_member(name, member)
898
+ lacp = parse_lacp_mode(name)[:lacp_mode]
899
+ grpid = /(\d+)/.match(name)[0]
900
+ configure ["interface #{member}", "channel-group #{grpid} mode #{lacp}"]
901
+ end
902
+
903
+ ##
904
+ # remove_member removes the interface specified in member from the
905
+ # port-channel interface specified by name in the nodes
906
+ # running-configuration.
907
+ #
908
+ # @eos_version 4.13.7M
909
+ #
910
+ # @commands
911
+ # interface <name>
912
+ # no channel-group <grpid>
913
+ #
914
+ # @param [String] :name The name of the port-channel interface to apply
915
+ # the configuration to.
916
+ #
917
+ # @param [String] :member The name of the physical ethernet interface to
918
+ # remove from the logical port-channel interface.
919
+ #
920
+ # @return [Boolean] returns true if the command completed successfully
921
+ def remove_member(name, member)
922
+ grpid = /(\d+)/.match(name)[0]
923
+ configure ["interface #{member}", "no channel-group #{grpid}"]
924
+ end
925
+
926
+ ##
927
+ # set_lacp_mode configures the lacp mode on the port-channel interface
928
+ # by configuring the lacp mode value for each member interface. This
929
+ # method will find all member interfaces for a port-channel and
930
+ # reconfigure them using the mode argument.
931
+ #
932
+ # @eos_version 4.13.7M
933
+ #
934
+ # @commands
935
+ # interface <name>
936
+ # no channel-group <grpid>
937
+ # channge-group <grpid> mode <lacp_mode>
938
+ #
939
+ # @param [String] :name The interface name to apply the configuration
940
+ # values to. The name must be the full interface identifier.
941
+ #
942
+ # @param [String] :mode The lacp mode to configure on the member
943
+ # interfaces for the port-channel. Valid values include active,
944
+ # passive or on
945
+ #
946
+ # @return [Boolean] returns true if the command completed successfully
947
+ def set_lacp_mode(name, mode)
948
+ return false unless %w(on passive active).include?(mode)
949
+ grpid = /(\d+)/.match(name)[0]
950
+
951
+ remove_commands = []
952
+ add_commands = []
953
+
954
+ parse_members(name)[:members].each do |member|
955
+ remove_commands << "interface #{member}"
956
+ remove_commands << "no channel-group #{grpid}"
957
+ add_commands << "interface #{member}"
958
+ add_commands << "channel-group #{grpid} mode #{mode}"
959
+ end
960
+ configure remove_commands + add_commands
961
+ end
962
+
963
+ ##
964
+ # set_lacp_fallback configures the lacp fallback mode for the
965
+ # port-channel interface. If no value is provided, lacp fallback is
966
+ # configured using the no keyword argument. If the default option is
967
+ # specified and set to true, the lacp fallback value is configured using
968
+ # the default keyword. The default keyword takes precedence over the
969
+ # value keyword if both options are provided.
970
+ #
971
+ # @eos_version 4.13.7M
972
+ #
973
+ # @commands
974
+ # interface <name>
975
+ # port-channel lacp fallback <value>
976
+ # no port-channel lacp fallback
977
+ # default port-channel lacp fallback
978
+ #
979
+ # @param [String] :name The interface name to apply the configuration
980
+ # values to. The name must be the full interface identifier.
981
+ #
982
+ # @param [Hash] :opts optional keyword arguments
983
+ #
984
+ # @option :opts [String] :value Specifies the value to configure for
985
+ # the port-channel lacp fallback. Valid values are individual and
986
+ # static
987
+ #
988
+ # @option :opts [Boolean] :default Configures the lacp fallback value on
989
+ # the interface using the default keyword
990
+ #
991
+ # @return [Boolean] returns true if the command completed successfully
992
+ def set_lacp_fallback(name, opts = {})
993
+ value = opts[:value]
994
+ default = opts.fetch(:default, false)
995
+
996
+ cmds = ["interface #{name}"]
997
+ case default
998
+ when true
999
+ cmds << 'default port-channel lacp fallback'
1000
+ when false
1001
+ if [nil, 'disabled'].include?(value)
1002
+ cmds << 'no port-channel lacp fallback'
1003
+ else
1004
+ cmds << "port-channel lacp fallback #{value}"
1005
+ end
1006
+ end
1007
+ configure(cmds)
1008
+ end
1009
+
1010
+ ##
1011
+ # set_lacp_timeout configures the lacp fallback timeou for the
1012
+ # port-channel interface. If no value is provided, lacp fallback timeout
1013
+ # is configured using the no keyword argument. If the default option is
1014
+ # specified and set to true, the lacp fallback timeout value is
1015
+ # configured using the default keyword. The default keyword takes
1016
+ # precedence over the value keyword if both options are provided.
1017
+ #
1018
+ # @eos_version 4.13.7M
1019
+ #
1020
+ # @commands
1021
+ # interface <name>
1022
+ # port-channel lacp fallback timeout <value>
1023
+ # no port-channel lacp fallback timeout
1024
+ # default port-channel lacp fallback timeout
1025
+ #
1026
+ # @param [String] :name The interface name to apply the configuration
1027
+ # values to. The name must be the full interface identifier.
1028
+ #
1029
+ # @param [Hash] :opts optional keyword arguments
1030
+ #
1031
+ # @option :opts [String] :value Specifies the value to configure for
1032
+ # the port-channel lacp fallback timeout. Valid values range from
1033
+ # 1 to 100 seconds
1034
+ #
1035
+ # @option :opts [Boolean] :default Configures the lacp fallback timeout
1036
+ # value on the interface using the default keyword
1037
+ #
1038
+ # @return [Boolean] returns true if the command completed successfully
1039
+ def set_lacp_timeout(name, opts = {})
1040
+ value = opts[:value]
1041
+ default = opts.fetch(:default, false)
1042
+
1043
+ cmds = ["interface #{name}"]
1044
+ case default
1045
+ when true
1046
+ cmds << 'default port-channel lacp fallback timeout'
1047
+ when false
1048
+ cmds << (value ? "port-channel lacp fallback timeout #{value}" : \
1049
+ 'no port-channel lacp fallback timeout')
1050
+ end
1051
+ configure(cmds)
1052
+ end
1053
+ end
1054
+
1055
+ class VxlanInterface < BaseInterface
1056
+
1057
+ DEFAULT_SRC_INTF = ''
1058
+ DEFAULT_MCAST_GRP = ''
1059
+
1060
+ ##
1061
+ # Returns the Vxlan interface configuration as a Ruby hash of key/value
1062
+ # pairs from the nodes running configuration. This method extends the
1063
+ # BaseInterface get method and adds the Vxlan specific attributes to
1064
+ # the hash
1065
+ #
1066
+ # @example
1067
+ # {
1068
+ # "name": <string>,
1069
+ # "type": 'vxlan',
1070
+ # "description": <string>,
1071
+ # "shutdown": [true, false],
1072
+ # "source_interface": <string>,
1073
+ # "multicast_group": <string>
1074
+ # }
1075
+ #
1076
+ # @param [String] :name The interface name to return from the nodes
1077
+ # configuration. This optional parameter defaults to Vxlan1
1078
+ #
1079
+ # @return [nil, Hash<String, String>] Returns the interface configuration
1080
+ # as a Ruby hash object. If the provided interface name is not found
1081
+ # then this method will return nil
1082
+ def get(name = 'Vxlan1')
1083
+ config = get_block("interface #{name}")
1084
+ return nil unless config
1085
+
1086
+ response = super(name)
1087
+ response[:type] = 'vxlan'
1088
+ response.merge!(parse_source_interface(config))
1089
+ response.merge!(parse_multicast_group(config))
1090
+ response
1091
+ end
1092
+
1093
+ ##
1094
+ # parse_source_interface scans the interface config block and returns the
1095
+ # value of the vxlan source-interace. If the source-interface is not
1096
+ # configured then the value of DEFAULT_SRC_INTF is used. The hash
1097
+ # returned is intended to be merged into the interface resource hash
1098
+ #
1099
+ # @api private
1100
+ #
1101
+ # @param [String] :config The interface configuration block to extract
1102
+ # the vxlan source-interface value from
1103
+ #
1104
+ # @return [Hash<Symbol, Object>] resource hash attribute
1105
+ def parse_source_interface(config)
1106
+ mdata = /source-interface ([^\s]+)$/.match(config)
1107
+ { source_interface: mdata.nil? ? DEFAULT_SRC_INTF : mdata[1] }
1108
+ end
1109
+ private :parse_source_interface
1110
+
1111
+ ##
1112
+ # parse_multicast_group scans the interface config block and returns the
1113
+ # value of the vxlan multicast-group. If the multicast-group is not
1114
+ # configured then the value of DEFAULT_MCAST_GRP is used. The hash
1115
+ # returned is intended to be merged into the interface resource hash
1116
+ #
1117
+ # @api private
1118
+ #
1119
+ # @param [String] :config The interface configuration block to extract
1120
+ # the vxlan multicast-group value from
1121
+ #
1122
+ # @return [Hash<Symbol, Object>] resource hash attribute
1123
+ def parse_multicast_group(config)
1124
+ mdata = /multicast-group ([^\s]+)$/.match(config)
1125
+ { multicast_group: mdata.nil? ? DEFAULT_MCAST_GRP : mdata[1] }
1126
+ end
1127
+ private :parse_multicast_group
1128
+
1129
+ ##
1130
+ # Configures the vxlan source-interface to the specified value. This
1131
+ # parameter should be a the interface identifier of the interface to act
1132
+ # as the source for all Vxlan traffic
1133
+ #
1134
+ # @param [String] :name The name of the interface to apply the
1135
+ # configuration values to
1136
+ # @param [Hash] :opt Optional keyword arguments
1137
+ # @option :opts [String] :value Configures the vxlan source-interface to
1138
+ # the spcified value. If no value is provided and the
1139
+ # default keyword is not specified then the value is negated
1140
+ # @option :opts [Boolean] :default Specifies whether or not the
1141
+ # multicast-group command is configured as default. The value of this
1142
+ # option has a higher precedence than :value
1143
+ #
1144
+ # @return [Boolean] This method returns true if the commands were
1145
+ # successful otherwise it returns false
1146
+ def set_source_interface(name = 'Vxlan1', opts = {})
1147
+ value = opts[:value]
1148
+ default = opts.fetch(:default, false)
1149
+
1150
+ cmds = ["interface #{name}"]
1151
+ case default
1152
+ when true
1153
+ cmds << 'default vxlan source-interface'
1154
+ when false
1155
+ cmds << (value ? "vxlan source-interface #{value}" : \
1156
+ 'no vxlan source-interface')
1157
+ end
1158
+ configure(cmds)
1159
+ end
1160
+
1161
+ ##
1162
+ # Configures the vxlan multcast-group flood address to the specified
1163
+ # value. The value should be a valid multicast address
1164
+ #
1165
+ # @param [String] :name The name of the interface to apply the
1166
+ # configuration values to
1167
+ # @param [Hash] :opt Optional keyword arguments
1168
+ # @option :opts [String] :value Configures the mutlicast-group flood
1169
+ # address to the specified value. If no value is provided and the
1170
+ # default keyword is not specified then the value is negated
1171
+ # @option :opts [Boolean] :default Specifies whether or not the
1172
+ # multicast-group command is configured as default. The value of this
1173
+ # option has a higher precedence than :value
1174
+ #
1175
+ # @return [Boolean] This method returns true if the commands were
1176
+ # successful otherwise it returns false
1177
+ def set_multicast_group(name = 'Vxlan1', opts = {})
1178
+ value = opts[:value]
1179
+ default = opts.fetch(:default, false)
1180
+
1181
+ cmds = ["interface #{name}"]
1182
+ case default
1183
+ when true
1184
+ cmds << 'default vxlan multicast-group'
1185
+ when false
1186
+ cmds << (value ? "vxlan multicast-group #{value}" : \
1187
+ 'no vxlan multtcast-group')
1188
+ end
1189
+ configure(cmds)
1190
+ end
1191
+ end
1192
+ end
1193
+ end