rbeapi 0.1.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 +35 -0
- data/Gemfile +25 -0
- data/Guardfile +15 -0
- data/LICENSE +28 -0
- data/README.md +218 -0
- data/Rakefile +12 -0
- data/lib/rbeapi.rb +32 -0
- data/lib/rbeapi/api.rb +135 -0
- data/lib/rbeapi/api/aaa.rb +410 -0
- data/lib/rbeapi/api/dns.rb +198 -0
- data/lib/rbeapi/api/interfaces.rb +1193 -0
- data/lib/rbeapi/api/ipinterfaces.rb +328 -0
- data/lib/rbeapi/api/logging.rb +157 -0
- data/lib/rbeapi/api/mlag.rb +519 -0
- data/lib/rbeapi/api/ntp.rb +201 -0
- data/lib/rbeapi/api/ospf.rb +214 -0
- data/lib/rbeapi/api/prefixlists.rb +98 -0
- data/lib/rbeapi/api/radius.rb +317 -0
- data/lib/rbeapi/api/radius.rb.old +399 -0
- data/lib/rbeapi/api/routemaps.rb +100 -0
- data/lib/rbeapi/api/snmp.rb +427 -0
- data/lib/rbeapi/api/staticroutes.rb +88 -0
- data/lib/rbeapi/api/stp.rb +381 -0
- data/lib/rbeapi/api/switchports.rb +272 -0
- data/lib/rbeapi/api/system.rb +87 -0
- data/lib/rbeapi/api/tacacs.rb +236 -0
- data/lib/rbeapi/api/varp.rb +181 -0
- data/lib/rbeapi/api/vlans.rb +338 -0
- data/lib/rbeapi/client.rb +454 -0
- data/lib/rbeapi/eapilib.rb +334 -0
- data/lib/rbeapi/netdev/snmp.rb +370 -0
- data/lib/rbeapi/utils.rb +70 -0
- data/lib/rbeapi/version.rb +37 -0
- data/rbeapi.gemspec +32 -0
- data/spec/fixtures/dut.conf +5 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/fixtures.rb +114 -0
- data/spec/support/shared_examples_for_api_modules.rb +124 -0
- data/spec/system/api_ospf_interfaces_spec.rb +58 -0
- data/spec/system/api_ospf_spec.rb +111 -0
- data/spec/system/api_varp_interfaces_spec.rb +60 -0
- data/spec/system/api_varp_spec.rb +44 -0
- data/spec/system/rbeapi/api/dns_spec.rb +77 -0
- data/spec/system/rbeapi/api/interfaces_base_spec.rb +94 -0
- data/spec/system/rbeapi/api/interfaces_ethernet_spec.rb +135 -0
- data/spec/system/rbeapi/api/interfaces_portchannel_spec.rb +188 -0
- data/spec/system/rbeapi/api/interfaces_vxlan_spec.rb +115 -0
- data/spec/system/rbeapi/api/ipinterfaces_spec.rb +97 -0
- data/spec/system/rbeapi/api/logging_spec.rb +65 -0
- data/spec/system/rbeapi/api/mlag_interfaces_spec.rb +80 -0
- data/spec/system/rbeapi/api/mlag_spec.rb +94 -0
- data/spec/system/rbeapi/api/ntp_spec.rb +76 -0
- data/spec/system/rbeapi/api/snmp_spec.rb +68 -0
- data/spec/system/rbeapi/api/stp_instances_spec.rb +61 -0
- data/spec/system/rbeapi/api/stp_interfaces_spec.rb +71 -0
- data/spec/system/rbeapi/api/stp_spec.rb +57 -0
- data/spec/system/rbeapi/api/switchports_spec.rb +135 -0
- data/spec/system/rbeapi/api/system_spec.rb +38 -0
- data/spec/system/rbeapi/api/vlans_spec.rb +121 -0
- 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
|