cisco_node_utils 2.0.2 → 2.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/lib/cisco_node_utils/bfd_global.rb +4 -0
  4. data/lib/cisco_node_utils/cisco_cmn_utils.rb +25 -0
  5. data/lib/cisco_node_utils/cmd_ref/interface.yaml +18 -18
  6. data/lib/cisco_node_utils/cmd_ref/interface_channel_group.yaml +4 -1
  7. data/lib/cisco_node_utils/cmd_ref/interface_evpn_multisite.yaml +1 -1
  8. data/lib/cisco_node_utils/cmd_ref/interface_ospf.yaml +17 -15
  9. data/lib/cisco_node_utils/interface.rb +117 -118
  10. data/lib/cisco_node_utils/interface_channel_group.rb +17 -8
  11. data/lib/cisco_node_utils/interface_evpn_multisite.rb +15 -6
  12. data/lib/cisco_node_utils/interface_ospf.rb +126 -102
  13. data/lib/cisco_node_utils/itd_service.rb +8 -0
  14. data/lib/cisco_node_utils/node.rb +0 -1
  15. data/lib/cisco_node_utils/platform.rb +16 -32
  16. data/lib/cisco_node_utils/version.rb +1 -1
  17. data/lib/cisco_node_utils/vlan.rb +1 -2
  18. data/lib/cisco_node_utils/vxlan_vtep.rb +1 -1
  19. data/tests/test_interface.rb +74 -13
  20. data/tests/test_interface_bdi.rb +2 -2
  21. data/tests/test_interface_channel_group.rb +24 -17
  22. data/tests/test_interface_evpn_multisite.rb +35 -0
  23. data/tests/test_interface_ospf.rb +71 -3
  24. data/tests/test_itd_service.rb +16 -4
  25. data/tests/test_node_ext.rb +4 -1
  26. data/tests/test_portchannel_global.rb +3 -0
  27. data/tests/test_router_ospf_vrf.rb +2 -34
  28. data/tests/test_stp_global.rb +4 -0
  29. metadata +3 -6
  30. data/lib/cisco_node_utils/cmd_ref/DEPRECATED.yaml +0 -118
  31. data/lib/cisco_node_utils/interface_DEPRECATED.rb +0 -518
  32. data/lib/cisco_node_utils/vlan_DEPRECATED.rb +0 -108
@@ -21,39 +21,48 @@ require_relative 'feature'
21
21
  module Cisco
22
22
  # Interface - node utility class for general interface config management
23
23
  class InterfaceChannelGroup < NodeUtil
24
- attr_reader :name
24
+ attr_reader :name, :show_name
25
25
 
26
- def initialize(name)
27
- validate_args(name)
26
+ def initialize(name, show_name=nil)
27
+ validate_args(name, show_name)
28
28
  end
29
29
 
30
30
  def to_s
31
31
  "interface_channel_group #{name}"
32
32
  end
33
33
 
34
- def self.interfaces
34
+ def self.interfaces(show_name=nil)
35
35
  hash = {}
36
- all = config_get('interface_channel_group', 'all_interfaces')
36
+ show_name = Utils.normalize_intf_pattern(show_name)
37
+ begin
38
+ all = config_get('interface_channel_group', 'all_interfaces',
39
+ show_name: show_name)
40
+ rescue CliError => e
41
+ raise unless show_name
42
+ # ignore logical interfaces that do not exist
43
+ debug 'InterfaceChannelGroup.interfaces ignoring CliError => ' + e.to_s
44
+ end
37
45
  return hash if all.nil?
38
46
 
39
47
  all.each do |id|
40
48
  id = id.downcase
41
- hash[id] = InterfaceChannelGroup.new(id)
49
+ hash[id] = InterfaceChannelGroup.new(id, show_name)
42
50
  end
43
51
  hash
44
52
  end
45
53
 
46
- def validate_args(name)
54
+ def validate_args(name, show_name)
47
55
  fail TypeError unless name.is_a?(String)
48
56
  fail ArgumentError unless name.length > 0
49
57
  fail "channel_group is not supported on #{name}" unless
50
58
  name[/Ethernet/i]
51
59
  @name = name.downcase
60
+ @show_name = show_name.nil? ? '' : Utils.normalize_intf_pattern(show_name)
52
61
  set_args_keys
53
62
  end
54
63
 
55
64
  def set_args_keys(hash={}) # rubocop:disable Style/AccessorMethodName
56
- @get_args = { name: @name }
65
+ @get_args = { name: @name, show_name: @show_name }
57
66
  @set_args = @get_args.merge!(hash) unless hash.empty?
58
67
  end
59
68
 
@@ -19,22 +19,31 @@ require_relative 'node_util'
19
19
  module Cisco
20
20
  # node_utils class for interface_evpn_multisite
21
21
  class InterfaceEvpnMultisite < NodeUtil
22
- attr_reader :interface, :tracking
22
+ attr_reader :interface, :show_name, :tracking
23
23
 
24
- def initialize(interface)
24
+ def initialize(interface, show_name=nil)
25
25
  fail TypeError unless interface.is_a?(String)
26
26
  @interface = interface.downcase
27
- @get_args = @set_args = { interface: @interface }
27
+ @show_name = show_name.nil? ? '' : Utils.normalize_intf_pattern(show_name)
28
+ @get_args = @set_args = { interface: @interface, show_name: @show_name }
28
29
  end
29
30
 
30
- def self.interfaces
31
+ def self.interfaces(show_name=nil)
31
32
  hash = {}
32
- intf_list = config_get('interface_evpn_multisite', 'all_interfaces')
33
+ show_name = Utils.normalize_intf_pattern(show_name)
34
+ begin
35
+ intf_list = config_get('interface_evpn_multisite', 'all_interfaces',
36
+ show_name: show_name)
37
+ rescue CliError => e
38
+ raise unless show_name
39
+ # ignore logical interfaces that do not exist
40
+ debug 'InterfaceEvpnMultisite.interfaces ignoring CliError => ' + e.to_s
41
+ end
33
42
  return hash if intf_list.nil?
34
43
 
35
44
  intf_list.each do |id|
36
45
  id = id.downcase
37
- intf = InterfaceEvpnMultisite.new(id)
46
+ intf = InterfaceEvpnMultisite.new(id, show_name)
38
47
  hash[id] = intf if intf.tracking
39
48
  end
40
49
  hash
@@ -23,53 +23,66 @@ require_relative 'interface'
23
23
  module Cisco
24
24
  # InterfaceOspf - node utility class for per-interface OSPF config management
25
25
  class InterfaceOspf < NodeUtil
26
- attr_reader :interface, :ospf_name
26
+ attr_reader :intf_name, :ospf_name, :area, :show_name
27
27
 
28
- def initialize(int_name, ospf_name, area, create=true)
29
- fail TypeError unless int_name.is_a? String
28
+ def initialize(intf_name, ospf_name, area, create=true, show_name=nil)
29
+ fail TypeError unless intf_name.is_a? String
30
30
  fail TypeError unless ospf_name.is_a? String
31
31
  fail TypeError unless area.is_a? String
32
- fail ArgumentError unless int_name.length > 0
32
+ fail ArgumentError unless intf_name.length > 0
33
33
  fail ArgumentError unless ospf_name.length > 0
34
34
  fail ArgumentError unless area.length > 0
35
35
 
36
36
  # normalize
37
- int_name = int_name.downcase
38
- @interface = Interface.interfaces[int_name]
39
- fail "interface #{int_name} does not exist" if @interface.nil?
40
-
37
+ @intf_name = intf_name.downcase
38
+ @show_name = show_name.nil? ? '' : Utils.normalize_intf_pattern(show_name)
39
+ fail "interface #{@intf_name} does not exist" if
40
+ Interface.interfaces(nil, @intf_name)[@intf_name].nil?
41
41
  @ospf_name = ospf_name
42
+ @area = area
43
+ @get_args = { name: intf_name, show_name: @show_name }
44
+ set_args_keys_default
42
45
 
43
46
  return unless create
44
47
  Feature.ospf_enable
48
+ self.area = area
49
+ end
45
50
 
46
- config_set('interface_ospf', 'area', @interface.name,
47
- '', @ospf_name, area)
51
+ def set_args_keys_default
52
+ @set_args = { name: @intf_name, ospf_name: @ospf_name, area: @area }
48
53
  end
49
54
 
50
55
  # can't re-use Interface.interfaces because we need to filter based on
51
56
  # "ip router ospf <name>", which Interface doesn't retrieve
52
- def self.interfaces(ospf_name=nil)
57
+ def self.interfaces(ospf_name=nil, show_name=nil)
53
58
  fail TypeError unless ospf_name.is_a?(String) || ospf_name.nil?
54
59
  ints = {}
55
-
56
- intf_list = config_get('interface_ospf', 'all_interfaces')
60
+ show_name = Utils.normalize_intf_pattern(show_name)
61
+ begin
62
+ intf_list = config_get('interface_ospf', 'all_interfaces',
63
+ show_name: show_name)
64
+ rescue CliError => e
65
+ raise unless show_name
66
+ # ignore logical interfaces that do not exist
67
+ debug 'InterfaceOspf.interfaces ignoring CliError => ' + e.to_s
68
+ end
57
69
  return ints if intf_list.nil?
58
70
  intf_list.each do |name|
59
- match = config_get('interface_ospf', 'area', name)
71
+ # Find interfaces with 'ip router ospf <name> area <area>'
72
+ match = config_get('interface_ospf', 'area',
73
+ name: name, show_name: show_name)
60
74
  next if match.nil?
61
- # ip router ospf <name> area <area>
62
75
  ospf = match[0]
63
76
  area = match[1]
64
77
  next unless ospf_name.nil? || ospf == ospf_name
65
78
  int = name.downcase
66
- ints[int] = InterfaceOspf.new(int, ospf, area, false)
79
+ ints[int] = InterfaceOspf.new(int, ospf, area, false, show_name)
67
80
  end
68
81
  ints
69
82
  end
70
83
 
71
84
  def area
72
- match = config_get('interface_ospf', 'area', @interface.name)
85
+ match = config_get('interface_ospf', 'area', @get_args)
73
86
  return nil if match.nil?
74
87
  val = match[1]
75
88
  # Coerce numeric area to the expected dot-decimal format.
@@ -78,20 +91,20 @@ module Cisco
78
91
  end
79
92
 
80
93
  def area=(a)
81
- config_set('interface_ospf', 'area', @interface.name,
82
- '', @ospf_name, a)
94
+ config_set('interface_ospf', 'area',
95
+ @set_args.merge!(state: '', area: a))
96
+ set_args_keys_default
83
97
  end
84
98
 
85
99
  def destroy
86
- config_set('interface_ospf', 'area', @interface.name,
87
- 'no', @ospf_name, area)
100
+ config_set('interface_ospf', 'area', @set_args.merge!(state: 'no'))
101
+ set_args_keys_default
88
102
  # Reset everything else back to default as well:
89
103
  self.message_digest = default_message_digest
90
104
  message_digest_key_set(default_message_digest_key_id, '', '', '')
91
105
  self.cost = default_cost
92
- self.hello_interval = default_hello_interval
93
- config_set('interface_ospf', 'dead_interval',
94
- @interface.name, 'no', '')
106
+ destroy_interval('hello_interval')
107
+ destroy_interval('dead_interval')
95
108
  self.bfd = default_bfd
96
109
  self.mtu_ignore = default_mtu_ignore
97
110
  self.priority = default_priority
@@ -106,15 +119,14 @@ module Cisco
106
119
  end
107
120
 
108
121
  def message_digest
109
- config_get('interface_ospf', 'message_digest', @interface.name)
122
+ config_get('interface_ospf', 'message_digest', @get_args)
110
123
  end
111
124
 
112
- # interface %s
113
- # %s ip ospf authentication message-digest
114
125
  def message_digest=(enable)
115
126
  return if enable == message_digest
116
- config_set('interface_ospf', 'message_digest', @interface.name,
117
- enable ? '' : 'no')
127
+ @set_args[:state] = (enable ? '' : 'no')
128
+ config_set('interface_ospf', 'message_digest', @set_args)
129
+ set_args_keys_default
118
130
  end
119
131
 
120
132
  def default_message_digest_key_id
@@ -122,7 +134,7 @@ module Cisco
122
134
  end
123
135
 
124
136
  def message_digest_key_id
125
- config_get('interface_ospf', 'message_digest_key_id', @interface.name)
137
+ config_get('interface_ospf', 'message_digest_key_id', @get_args)
126
138
  end
127
139
 
128
140
  def default_message_digest_algorithm_type
@@ -132,7 +144,7 @@ module Cisco
132
144
 
133
145
  def message_digest_algorithm_type
134
146
  match = config_get('interface_ospf', 'message_digest_alg_type',
135
- @interface.name)
147
+ @get_args)
136
148
  match.to_sym
137
149
  end
138
150
 
@@ -143,101 +155,113 @@ module Cisco
143
155
 
144
156
  def message_digest_encryption_type
145
157
  match = config_get('interface_ospf', 'message_digest_enc_type',
146
- @interface.name)
158
+ @get_args)
147
159
  Encryption.cli_to_symbol(match)
148
160
  end
149
161
 
150
162
  def message_digest_password
151
- config_get('interface_ospf', 'message_digest_password', @interface.name)
163
+ config_get('interface_ospf', 'message_digest_password', @get_args)
152
164
  end
153
165
 
154
166
  def default_message_digest_password
155
167
  config_get_default('interface_ospf', 'message_digest_password')
156
168
  end
157
169
 
158
- # interface %s
159
- # %s ip ospf message-digest-key %d %s %d %s
160
- def message_digest_key_set(keyid, algtype, enctype, enc)
170
+ def message_digest_key_set(keyid, algtype, enctype, password)
161
171
  current_keyid = message_digest_key_id
162
172
  if keyid == default_message_digest_key_id && current_keyid != keyid
163
- config_set('interface_ospf', 'message_digest_key_set',
164
- @interface.name, 'no', current_keyid,
165
- '', '', '')
173
+ @set_args.merge!(state: 'no',
174
+ keyid: current_keyid,
175
+ algtype: '',
176
+ enctype: '',
177
+ password: '')
178
+ config_set('interface_ospf', 'message_digest_key_set', @set_args)
166
179
  elsif keyid != default_message_digest_key_id
167
- fail TypeError unless enc.is_a?(String)
168
- fail ArgumentError unless enc.length > 0
180
+ fail TypeError unless password.is_a?(String)
181
+ fail ArgumentError unless password.length > 0
169
182
  enctype = Encryption.symbol_to_cli(enctype)
170
- config_set('interface_ospf', 'message_digest_key_set',
171
- @interface.name, '', keyid, algtype, enctype, enc)
183
+ @set_args.merge!(state: '',
184
+ keyid: keyid,
185
+ algtype: algtype,
186
+ enctype: enctype,
187
+ password: password)
188
+ config_set('interface_ospf', 'message_digest_key_set', @set_args)
172
189
  end
190
+ set_args_keys_default
173
191
  end
174
192
 
175
193
  def cost
176
- config_get('interface_ospf', 'cost', @interface.name)
194
+ config_get('interface_ospf', 'cost', @get_args)
177
195
  end
178
196
 
179
197
  def default_cost
180
198
  config_get_default('interface_ospf', 'cost')
181
199
  end
182
200
 
183
- # interface %s
184
- # ip ospf cost %d
185
201
  def cost=(c)
186
202
  if c == default_cost
187
- config_set('interface_ospf', 'cost', @interface.name, 'no', '')
203
+ @set_args.merge!(state: 'no', cost: '')
188
204
  else
189
- config_set('interface_ospf', 'cost', @interface.name, '', c)
205
+ @set_args.merge!(state: '', cost: c)
190
206
  end
207
+ config_set('interface_ospf', 'cost', @set_args)
208
+ set_args_keys_default
191
209
  end
192
210
 
193
211
  def hello_interval
194
- config_get('interface_ospf', 'hello_interval', @interface.name)
212
+ config_get('interface_ospf', 'hello_interval', @get_args)
195
213
  end
196
214
 
197
215
  def default_hello_interval
198
216
  config_get_default('interface_ospf', 'hello_interval')
199
217
  end
200
218
 
201
- # interface %s
202
- # ip ospf hello-interval %d
203
219
  def hello_interval=(interval)
204
- config_set('interface_ospf', 'hello_interval',
205
- @interface.name, '', interval.to_i)
220
+ # Previous behavior always sets interval and ignores 'no' cmd
221
+ @set_args.merge!(state: '', interval: interval.to_i)
222
+ config_set('interface_ospf', 'hello_interval', @set_args)
223
+ set_args_keys_default
224
+ end
225
+
226
+ def destroy_interval(prop)
227
+ # Helper to remove cli completely
228
+ @set_args.merge!(state: 'no', interval: '')
229
+ config_set('interface_ospf', prop, @set_args)
230
+ set_args_keys_default
206
231
  end
207
232
 
208
233
  def dead_interval
209
- config_get('interface_ospf', 'dead_interval', @interface.name)
234
+ config_get('interface_ospf', 'dead_interval', @get_args)
210
235
  end
211
236
 
212
237
  def default_dead_interval
213
238
  config_get_default('interface_ospf', 'dead_interval')
214
239
  end
215
240
 
216
- # interface %s
217
- # ip ospf dead-interval %d
218
241
  def dead_interval=(interval)
219
- config_set('interface_ospf', 'dead_interval',
220
- @interface.name, '', interval.to_i)
242
+ # Previous behavior always sets interval and ignores 'no' cmd
243
+ @set_args.merge!(state: '', interval: interval.to_i)
244
+ config_set('interface_ospf', 'dead_interval', @set_args)
245
+ set_args_keys_default
221
246
  end
222
247
 
223
248
  # CLI can be either of the following or none
224
249
  # ip ospf bfd
225
250
  # ip ospf bfd disable
226
251
  def bfd
227
- val = config_get('interface_ospf', 'bfd', @interface.name)
252
+ val = config_get('interface_ospf', 'bfd', @get_args)
228
253
  return if val.nil?
229
254
  val.include?('disable') ? false : true
230
255
  end
231
256
 
232
- # interface %s
233
- # %s ip ospf bfd %s
234
257
  def bfd=(val)
235
258
  return if val == bfd
236
259
  Feature.bfd_enable
237
260
  state = (val == default_bfd) ? 'no' : ''
238
261
  disable = val ? '' : 'disable'
239
- config_set('interface_ospf', 'bfd', @interface.name,
240
- state, disable)
262
+ config_set('interface_ospf', 'bfd',
263
+ @set_args.merge!(state: state, disable: disable))
264
+ set_args_keys_default
241
265
  end
242
266
 
243
267
  def default_bfd
@@ -245,7 +269,7 @@ module Cisco
245
269
  end
246
270
 
247
271
  def default_network_type
248
- case @interface.name
272
+ case @intf_name
249
273
  when /loopback/i
250
274
  lookup = 'network_type_loopback_default'
251
275
  else
@@ -255,14 +279,13 @@ module Cisco
255
279
  end
256
280
 
257
281
  def mtu_ignore
258
- config_get('interface_ospf', 'mtu_ignore', @interface.name)
282
+ config_get('interface_ospf', 'mtu_ignore', @get_args)
259
283
  end
260
284
 
261
- # interface %s
262
- # %s ip ospf mtu-ignore
263
285
  def mtu_ignore=(enable)
264
- config_set('interface_ospf', 'mtu_ignore', @interface.name,
265
- enable ? '' : 'no')
286
+ @set_args[:state] = enable ? '' : 'no'
287
+ config_set('interface_ospf', 'mtu_ignore', @set_args)
288
+ set_args_keys_default
266
289
  end
267
290
 
268
291
  def default_mtu_ignore
@@ -270,20 +293,21 @@ module Cisco
270
293
  end
271
294
 
272
295
  def network_type
273
- type = config_get('interface_ospf', 'network_type', @interface.name)
296
+ type = config_get('interface_ospf', 'network_type', @get_args)
274
297
  return 'p2p' if type == 'point-to-point'
275
298
  return default_network_type if type.nil?
276
299
  type
277
300
  end
278
301
 
279
- # interface %s
280
- # %s ip ospf network %s
281
302
  def network_type=(type)
282
- no_cmd = (type == default_network_type) ? 'no' : ''
283
- network = (type == default_network_type) ? '' : type
284
- network = 'point-to-point' if type.to_s == 'p2p'
285
- config_set('interface_ospf', 'network_type', @interface.name,
286
- no_cmd, network)
303
+ if type == default_network_type
304
+ @set_args.merge!(state: 'no', network_type: '')
305
+ else
306
+ network = 'point-to-point' if type.to_s == 'p2p'
307
+ @set_args.merge!(state: '', network_type: network)
308
+ end
309
+ config_set('interface_ospf', 'network_type', @set_args)
310
+ set_args_keys_default
287
311
  end
288
312
 
289
313
  def default_passive_interface
@@ -291,28 +315,28 @@ module Cisco
291
315
  end
292
316
 
293
317
  def passive_interface
294
- config_get('interface_ospf', 'passive_interface', @interface.name)
318
+ config_get('interface_ospf', 'passive_interface', @get_args)
295
319
  end
296
320
 
297
- # interface %s
298
- # %s ip ospf passive-interface
299
321
  def passive_interface=(enable)
300
322
  fail TypeError unless enable == true || enable == false
301
- config_set('interface_ospf', 'passive_interface', @interface.name,
302
- enable ? '' : 'no')
323
+ @set_args[:state] = enable ? '' : 'no'
324
+ config_set('interface_ospf', 'passive_interface', @set_args)
325
+ set_args_keys_default
303
326
  end
304
327
 
305
328
  def priority
306
- config_get('interface_ospf', 'priority', @interface.name)
329
+ config_get('interface_ospf', 'priority', @get_args)
307
330
  end
308
331
 
309
- # interface %s
310
- # ip ospf priority %d
311
332
  def priority=(val)
312
- no_cmd = (val == default_priority) ? 'no' : ''
313
- pri = (val == default_priority) ? '' : val
314
- config_set('interface_ospf', 'priority',
315
- @interface.name, no_cmd, pri)
333
+ if val == default_priority
334
+ @set_args.merge!(state: 'no', priority: '')
335
+ else
336
+ @set_args.merge!(state: '', priority: val)
337
+ end
338
+ config_set('interface_ospf', 'priority', @set_args)
339
+ set_args_keys_default
316
340
  end
317
341
 
318
342
  def default_priority
@@ -320,14 +344,13 @@ module Cisco
320
344
  end
321
345
 
322
346
  def shutdown
323
- config_get('interface_ospf', 'shutdown', @interface.name)
347
+ config_get('interface_ospf', 'shutdown', @get_args)
324
348
  end
325
349
 
326
- # interface %s
327
- # %s ip ospf shutdown
328
- def shutdown=(state)
329
- config_set('interface_ospf', 'shutdown', @interface.name,
330
- state ? '' : 'no')
350
+ def shutdown=(enable)
351
+ @set_args[:state] = enable ? '' : 'no'
352
+ config_set('interface_ospf', 'shutdown', @set_args)
353
+ set_args_keys_default
331
354
  end
332
355
 
333
356
  def default_shutdown
@@ -335,16 +358,17 @@ module Cisco
335
358
  end
336
359
 
337
360
  def transmit_delay
338
- config_get('interface_ospf', 'transmit_delay', @interface.name)
361
+ config_get('interface_ospf', 'transmit_delay', @get_args)
339
362
  end
340
363
 
341
- # interface %s
342
- # ip ospf transmit-delay %d
343
364
  def transmit_delay=(val)
344
- no_cmd = (val == default_transmit_delay) ? 'no' : ''
345
- delay = (val == default_transmit_delay) ? '' : val
346
- config_set('interface_ospf', 'transmit_delay',
347
- @interface.name, no_cmd, delay)
365
+ if val == default_transmit_delay
366
+ @set_args.merge!(state: 'no', delay: '')
367
+ else
368
+ @set_args.merge!(state: '', delay: val)
369
+ end
370
+ config_set('interface_ospf', 'transmit_delay', @set_args)
371
+ set_args_keys_default
348
372
  end
349
373
 
350
374
  def default_transmit_delay