cisco_node_utils 1.10.0 → 2.0.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/CHANGELOG.md +25 -0
  4. data/lib/cisco_node_utils/bgp.rb +1 -1
  5. data/lib/cisco_node_utils/cisco_cmn_utils.rb +11 -3
  6. data/lib/cisco_node_utils/client/nxapi/client.rb +40 -6
  7. data/lib/cisco_node_utils/cmd_ref/acl.yaml +1 -1
  8. data/lib/cisco_node_utils/cmd_ref/banner.yaml +5 -1
  9. data/lib/cisco_node_utils/cmd_ref/feature.yaml +8 -1
  10. data/lib/cisco_node_utils/cmd_ref/interface_ospf.yaml +1 -1
  11. data/lib/cisco_node_utils/cmd_ref/interface_service_vni.yaml +5 -0
  12. data/lib/cisco_node_utils/cmd_ref/inventory.yaml +1 -1
  13. data/lib/cisco_node_utils/cmd_ref/ospf.yaml +7 -0
  14. data/lib/cisco_node_utils/cmd_ref/route_map.yaml +1 -1
  15. data/lib/cisco_node_utils/cmd_ref/vtp.yaml +1 -1
  16. data/lib/cisco_node_utils/cmd_ref/vxlan_vtep.yaml +30 -0
  17. data/lib/cisco_node_utils/cmd_ref/vxlan_vtep_vni.yaml +9 -2
  18. data/lib/cisco_node_utils/command_reference.rb +2 -2
  19. data/lib/cisco_node_utils/dhcp_relay_global.rb +1 -5
  20. data/lib/cisco_node_utils/feature.rb +30 -4
  21. data/lib/cisco_node_utils/interface.rb +3 -3
  22. data/lib/cisco_node_utils/interface_service_vni.rb +1 -1
  23. data/lib/cisco_node_utils/node.rb +11 -22
  24. data/lib/cisco_node_utils/node_util.rb +1 -1
  25. data/lib/cisco_node_utils/radius_global.rb +3 -3
  26. data/lib/cisco_node_utils/radius_server.rb +1 -2
  27. data/lib/cisco_node_utils/route_map.rb +1 -1
  28. data/lib/cisco_node_utils/router_ospf_vrf.rb +49 -5
  29. data/lib/cisco_node_utils/tacacs_global.rb +1 -2
  30. data/lib/cisco_node_utils/tacacs_server.rb +1 -2
  31. data/lib/cisco_node_utils/tacacs_server_host.rb +1 -2
  32. data/lib/cisco_node_utils/version.rb +1 -1
  33. data/lib/cisco_node_utils/vlan.rb +1 -1
  34. data/lib/cisco_node_utils/vxlan_vtep.rb +89 -4
  35. data/lib/cisco_node_utils/vxlan_vtep_vni.rb +32 -1
  36. data/spec/schema.yaml +2 -0
  37. data/tests/basetest.rb +40 -4
  38. data/tests/ciscotest.rb +15 -5
  39. data/tests/cmd_config.yaml +0 -2
  40. data/tests/test_acl.rb +1 -1
  41. data/tests/test_bgp_af.rb +6 -0
  42. data/tests/test_feature.rb +30 -4
  43. data/tests/test_interface.rb +5 -7
  44. data/tests/test_interface_ospf.rb +5 -1
  45. data/tests/test_interface_private_vlan.rb +18 -1
  46. data/tests/test_interface_svi.rb +1 -1
  47. data/tests/test_interface_switchport.rb +4 -7
  48. data/tests/test_node_ext.rb +1 -1
  49. data/tests/test_nxapi.rb +18 -8
  50. data/tests/test_radius_global.rb +3 -2
  51. data/tests/test_route_map.rb +2 -4
  52. data/tests/test_router_bgp.rb +10 -14
  53. data/tests/test_router_ospf_vrf.rb +61 -0
  54. data/tests/test_snmpserver.rb +1 -1
  55. data/tests/test_tacacs_global.rb +4 -2
  56. data/tests/test_upgrade.rb +1 -1
  57. data/tests/test_vrf.rb +2 -0
  58. data/tests/test_vrf_af.rb +2 -0
  59. data/tests/test_vtp.rb +6 -4
  60. data/tests/test_vxlan_vtep.rb +93 -1
  61. data/tests/test_vxlan_vtep_vni.rb +35 -1
  62. data/tests/yum_package.yaml +5 -0
  63. metadata +3 -3
@@ -1085,7 +1085,7 @@ module Cisco
1085
1085
  end
1086
1086
 
1087
1087
  def storm_control_multicast=(val)
1088
- return if val == storm_control_broadcast
1088
+ return if val == storm_control_multicast
1089
1089
  state = val == default_storm_control_multicast ? 'no' : ''
1090
1090
  level = val == default_storm_control_multicast ? '' : val
1091
1091
  config_set('interface', 'storm_control_multicast',
@@ -1102,7 +1102,7 @@ module Cisco
1102
1102
  end
1103
1103
 
1104
1104
  def storm_control_unicast=(val)
1105
- return if val == storm_control_broadcast
1105
+ return if val == storm_control_unicast
1106
1106
  state = val == default_storm_control_unicast ? 'no' : ''
1107
1107
  level = val == default_storm_control_unicast ? '' : val
1108
1108
  config_set('interface', 'storm_control_unicast',
@@ -2025,7 +2025,7 @@ module Cisco
2025
2025
  end
2026
2026
 
2027
2027
  def vpc_peer_link=(state)
2028
- return if vpc_peerlink == state
2028
+ return if vpc_peer_link == state
2029
2029
  no_cmd = (state ? '' : 'no')
2030
2030
  config_set('interface', 'vpc_peer_link', name: @name, state: no_cmd)
2031
2031
  end
@@ -36,7 +36,7 @@ module Cisco
36
36
 
37
37
  def self.svc_vni_ids
38
38
  hash = {}
39
- intf_list = config_get('interface', 'all_interfaces')
39
+ intf_list = config_get('interface_service_vni', 'all_interfaces')
40
40
  return hash if intf_list.nil?
41
41
 
42
42
  intf_list.each do |intf|
@@ -237,6 +237,11 @@ module Cisco
237
237
  @instance ||= new
238
238
  end
239
239
 
240
+ # Allow instance cache to be reset
241
+ def self.reset_instance
242
+ @instance = nil
243
+ end
244
+
240
245
  def initialize
241
246
  @client = Cisco::Client.create
242
247
  @cmd_ref = nil
@@ -357,33 +362,17 @@ module Cisco
357
362
 
358
363
  def prod_qualifier(prod, inventory)
359
364
  case prod
360
- when /N9K/
361
- # Two datapoints are used to determine if the current n9k
362
- # platform is a fretta based n9k or non-fretta.
365
+ when /N(3|9)K/
366
+ # one datapoint is used to determine if the current n9k/n3k
367
+ # platform is a fretta based or non-fretta.
363
368
  #
364
- # 1) Image Version == 7.0(3)F*
365
- # 2) Fabric Module == N9K-C9*-FM-R
366
- if @cmd_ref
367
- ver = os_version
368
- else
369
- ver = get(command: 'show version',
370
- data_format: :nxapi_structured)['kickstart_ver_str']
371
- end
372
- # Append -F for fretta platform.
369
+ # Module == *-R
373
370
  inventory.each do |row|
374
- if row['productid'][/N9K-C9...-FM-R/] && ver[/7.0\(3\)F/]
371
+ if row['productid'][/-R/]
372
+ # Append -F for fretta platform.
375
373
  return prod.concat('-F') unless prod[/-F/]
376
374
  end
377
375
  end
378
- when /N3K/
379
- if @cmd_ref
380
- ver = os_version
381
- else
382
- ver = get(command: 'show version',
383
- data_format: :nxapi_structured)['kickstart_ver_str']
384
- end
385
- # Append -F for fretta platform.
386
- return prod.concat('-F') if ver[/7.0\(3\)F/] && !prod[/-F/]
387
376
  end
388
377
  prod
389
378
  end
@@ -21,7 +21,7 @@ module Cisco
21
21
  # NodeUtil - generic functionality for node utility subclasses to use
22
22
  class NodeUtil
23
23
  def self.node
24
- @node ||= Cisco::Node.instance
24
+ Cisco::Node.instance
25
25
  end
26
26
 
27
27
  def node
@@ -103,8 +103,7 @@ module Cisco
103
103
  def key
104
104
  str = config_get('radius_global', 'key')
105
105
  return if str.nil?
106
- str = str.strip
107
- Utils.add_quotes(str)
106
+ str.strip
108
107
  end
109
108
 
110
109
  def key_set(value, format)
@@ -119,10 +118,11 @@ module Cisco
119
118
  end
120
119
 
121
120
  if value.nil? && !key.nil?
121
+ value = Utils.add_quotes(key)
122
122
  config_set('radius_global',
123
123
  'key',
124
124
  state: 'no',
125
- key: "#{key_format} #{key}")
125
+ key: "#{key_format} #{value}")
126
126
  elsif !format.nil?
127
127
  value = Utils.add_quotes(value)
128
128
  config_set('radius_global',
@@ -372,8 +372,7 @@ module Cisco
372
372
  return if val.nil? || val.empty?
373
373
  index = val.index('auth-port')
374
374
  val = val[0..index - 2] unless index.nil?
375
- val = val.strip
376
- Utils.add_quotes(val)
375
+ val.strip
377
376
  end
378
377
 
379
378
  def key_set(value, format)
@@ -309,7 +309,7 @@ module Cisco
309
309
  # match source-protocol tcp udp
310
310
  def match_src_proto
311
311
  str = config_get('route_map', 'match_src_proto', @get_args)
312
- str.empty? ? default_match_src_proto : str.split
312
+ str.empty? ? default_match_src_proto : str.split.sort
313
313
  end
314
314
 
315
315
  def match_src_proto=(list)
@@ -41,11 +41,7 @@ module Cisco
41
41
  @router = router
42
42
  @name = name
43
43
  @parent = {}
44
- if @name == 'default'
45
- @get_args = @set_args = { name: @router }
46
- else
47
- @get_args = @set_args = { name: @router, vrf: @name }
48
- end
44
+ set_args_keys_default
49
45
 
50
46
  create if instantiate
51
47
  end
@@ -87,6 +83,24 @@ module Cisco
87
83
  list.each { |key| @set_args.delete(key) }
88
84
  end
89
85
 
86
+ #
87
+ # Helper methods to delete @set_args hash keys
88
+ #
89
+ def set_args_keys_default
90
+ keys = { name: @router }
91
+ keys[:vrf] = @name unless @name == 'default'
92
+ @get_args = @set_args = keys
93
+ end
94
+
95
+ def set_args_keys(hash={}) # rubocop:disable Style/AccessorMethodName
96
+ set_args_keys_default
97
+ @set_args = @get_args.merge!(hash) unless hash.empty?
98
+ end
99
+
100
+ ########################################################
101
+ # PROPERTIES #
102
+ ########################################################
103
+
90
104
  def auto_cost
91
105
  match = config_get('ospf', 'auto_cost', @get_args)
92
106
  return default_auto_cost if match.nil?
@@ -168,6 +182,36 @@ module Cisco
168
182
  config_get_default('ospf', 'log_adjacency')
169
183
  end
170
184
 
185
+ #
186
+ # Redistribute
187
+ #
188
+
189
+ # Build an array of all redistribute commands currently on the device
190
+ def redistribute
191
+ c = config_get('ospf', 'redistribute', @get_args)
192
+ c.nil? ? nil : c.each(&:compact!).sort
193
+ end
194
+
195
+ # redistribute setter.
196
+ # Process a hash of redistribute commands from delta_add_remove().
197
+ def redistribute=(should)
198
+ delta_hash = Utils.delta_add_remove(should, redistribute)
199
+ return if delta_hash.values.flatten.empty?
200
+ [:add, :remove].each do |action|
201
+ Cisco::Logger.debug("redistribute delta #{@get_args}\n #{action}: " \
202
+ "#{delta_hash[action]}")
203
+ delta_hash[action].each do |protocol, route_map|
204
+ state = (action == :add) ? '' : 'no'
205
+ set_args_keys(state: state, protocol: protocol, route_map: route_map)
206
+ config_set('ospf', 'redistribute', @set_args)
207
+ end
208
+ end
209
+ end
210
+
211
+ def default_redistribute
212
+ config_get_default('ospf', 'redistribute')
213
+ end
214
+
171
215
  def router_id
172
216
  config_get('ospf', 'router_id', @get_args)
173
217
  end
@@ -79,8 +79,7 @@ module Cisco
79
79
  return nil unless Feature.tacacs_enabled?
80
80
  str = config_get('tacacs_global', 'key')
81
81
  return TacacsGlobal.default_key if str.empty?
82
- str = str[1].strip
83
- Utils.add_quotes(str)
82
+ str[1].strip.gsub(/\"/, '')
84
83
  end
85
84
 
86
85
  # Get default encryption password
@@ -143,8 +143,7 @@ module Cisco
143
143
  def encryption_password
144
144
  str = config_get('tacacs_server', 'encryption_password')
145
145
  return TacacsServer.default_encryption_password if str.empty?
146
- str = str[1].strip
147
- Utils.add_quotes(str)
146
+ str[1].strip
148
147
  end
149
148
 
150
149
  # Get default encryption password
@@ -147,8 +147,7 @@ module Cisco
147
147
  return str if str.nil? || str.empty?
148
148
  index = str.index('port')
149
149
  str = str[0..index - 2] unless index.nil?
150
- str = str.strip
151
- Utils.add_quotes(str)
150
+ str.strip
152
151
  end
153
152
 
154
153
  def self.default_encryption_password
@@ -14,7 +14,7 @@
14
14
 
15
15
  # Container module for version number only.
16
16
  module CiscoNodeUtils
17
- VERSION = '1.10.0'
17
+ VERSION = '2.0.0'
18
18
  gem_version = Gem::Version.new(Gem::VERSION)
19
19
  min_gem_version = Gem::Version.new('2.1.0')
20
20
  fail 'Required rubygems version >= 2.1.0' if gem_version < min_gem_version
@@ -229,7 +229,7 @@ module Cisco
229
229
  Feature.vn_segment_vlan_based_enable
230
230
  # Remove the existing mapping first as cli doesn't support overwriting.
231
231
  config_set('vlan', 'mapped_vni', vlan: @vlan_id,
232
- state: 'no', vni: vni)
232
+ state: 'no', vni: vni) unless mapped_vni.to_s.empty?
233
233
  # Configure the new mapping
234
234
  state = vni == default_mapped_vni ? 'no' : ''
235
235
  config_set('vlan', 'mapped_vni', vlan: @vlan_id,
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # November 2015, Deepak Cherian
5
5
  #
6
- # Copyright (c) 2015-2016 Cisco and/or its affiliates.
6
+ # Copyright (c) 2015-2018 Cisco and/or its affiliates.
7
7
  #
8
8
  # Licensed under the Apache License, Version 2.0 (the "License");
9
9
  # you may not use this file except in compliance with the License.
@@ -181,10 +181,10 @@ module Cisco
181
181
  def multisite_border_gateway_interface=(val)
182
182
  set_args = { name: @name }
183
183
  set_args[:state] = val.empty? ? 'no' : ''
184
- set_args[:lpbk_intf] = val.empty? ? 'loopback0' : val
184
+ # rubocop:disable LineLength
185
+ set_args[:lpbk_intf] = val.empty? ? multisite_border_gateway_interface : val
186
+ # rubocop:enable LineLength
185
187
  if set_args[:state] == 'no'
186
- # 'no multisite border-gateway' doesn't work without interface
187
- # defaulting to 'loopback0' still clears any configuration
188
188
  intf = multisite_border_gateway_interface
189
189
  unless intf == default_multisite_border_gateway_interface
190
190
  config_set('vxlan_vtep', 'multisite_bg_intf', set_args)
@@ -197,5 +197,90 @@ module Cisco
197
197
  def default_multisite_border_gateway_interface
198
198
  config_get_default('vxlan_vtep', 'multisite_bg_intf')
199
199
  end
200
+
201
+ def global_ingress_replication_bgp
202
+ config_get('vxlan_vtep', 'global_ingress_replication_bgp', name: @name)
203
+ end
204
+
205
+ def global_ingress_replication_bgp=(state)
206
+ set_args = { name: @name }
207
+ if state
208
+ set_args[:state] = ''
209
+ # Host reachability must be enabled for this property
210
+ unless VxlanVtep.new(@name).host_reachability == 'evpn'
211
+ fail "Dependency: vxlan_vtep host_reachability must be 'evpn'."
212
+ end
213
+ config_set('vxlan_vtep', 'global_ingress_replication_bgp', set_args)
214
+ else
215
+ set_args[:state] = 'no'
216
+ config_set('vxlan_vtep',
217
+ 'global_ingress_replication_bgp', set_args) if
218
+ global_ingress_replication_bgp
219
+ end
220
+ end
221
+
222
+ def default_global_ingress_replication_bgp
223
+ config_get_default('vxlan_vtep', 'global_ingress_replication_bgp')
224
+ end
225
+
226
+ def global_suppress_arp
227
+ config_get('vxlan_vtep', 'global_suppress_arp', name: @name)
228
+ end
229
+
230
+ def global_suppress_arp=(state)
231
+ set_args = { name: @name }
232
+ if state
233
+ set_args[:state] = ''
234
+ # Host reachability must be enabled for this property
235
+ unless VxlanVtep.new(@name).host_reachability == 'evpn'
236
+ fail "Dependency: vxlan_vtep host_reachability must be 'evpn'."
237
+ end
238
+ Feature.nv_overlay_evpn_enable if
239
+ Feature.nv_overlay_evpn_supported? && !Feature.nv_overlay_evpn_enabled?
240
+ config_set('vxlan_vtep', 'global_suppress_arp', set_args)
241
+ else
242
+ set_args[:state] = 'no'
243
+ config_set('vxlan_vtep',
244
+ 'global_suppress_arp', set_args) if global_suppress_arp
245
+ end
246
+ end
247
+
248
+ def default_global_suppress_arp
249
+ config_get_default('vxlan_vtep', 'global_suppress_arp')
250
+ end
251
+
252
+ def global_mcast_group_l2
253
+ config_get('vxlan_vtep', 'global_mcast_group_l2', name: @name)
254
+ end
255
+
256
+ def global_mcast_group_l2=(val)
257
+ if val
258
+ set_args = { name: @name, ip: val, state: '' }
259
+ else
260
+ set_args = { name: @name, ip: '', state: 'no' }
261
+ end
262
+ config_set('vxlan_vtep', 'global_mcast_group_l2', set_args)
263
+ end
264
+
265
+ def default_global_mcast_group_l2
266
+ config_get_default('vxlan_vtep', 'global_mcast_group_l2')
267
+ end
268
+
269
+ def global_mcast_group_l3
270
+ config_get('vxlan_vtep', 'global_mcast_group_l3', name: @name)
271
+ end
272
+
273
+ def global_mcast_group_l3=(val)
274
+ if val
275
+ set_args = { name: @name, ip: val, state: '' }
276
+ else
277
+ set_args = { name: @name, ip: '', state: 'no' }
278
+ end
279
+ config_set('vxlan_vtep', 'global_mcast_group_l3', set_args)
280
+ end
281
+
282
+ def default_global_mcast_group_l3
283
+ config_get_default('vxlan_vtep', 'global_mcast_group_l3')
284
+ end
200
285
  end # Class
201
286
  end # Module
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # November 2015 Michael G Wiebe
5
5
  #
6
- # Copyright (c) 2015-2016 Cisco and/or its affiliates.
6
+ # Copyright (c) 2015-2018 Cisco and/or its affiliates.
7
7
  #
8
8
  # Licensed under the Apache License, Version 2.0 (the "License");
9
9
  # you may not use this file except in compliance with the License.
@@ -252,6 +252,37 @@ module Cisco
252
252
  config_get_default('vxlan_vtep_vni', 'suppress_arp')
253
253
  end
254
254
 
255
+ def suppress_arp_disable
256
+ # suppress_arp_disable is really a boolean kind, however,
257
+ # since the get is looking for a string with 'disable'
258
+ # we have to treat it as string first and then massage it
259
+ # to boolean
260
+ str = config_get('vxlan_vtep_vni', 'suppress_arp_disable', @get_args)
261
+ str.nil? ? false : true
262
+ end
263
+
264
+ def suppress_arp_disable=(state)
265
+ if state
266
+ set_args_keys(state: '')
267
+ # Host reachability must be enabled for this property
268
+ unless VxlanVtep.new(@name).host_reachability == 'evpn'
269
+ fail "Dependency: vxlan_vtep host_reachability must be 'evpn'."
270
+ end
271
+ Feature.nv_overlay_evpn_enable if
272
+ Feature.nv_overlay_evpn_supported? && !Feature.nv_overlay_evpn_enabled?
273
+ config_set('vxlan_vtep_vni', 'suppress_arp_disable', @set_args)
274
+ else
275
+ set_args_keys(state: 'no')
276
+ # Remove suppress-arp-disable only if it is configured.
277
+ config_set('vxlan_vtep_vni', 'suppress_arp_disable', @set_args) if
278
+ suppress_arp_disable
279
+ end
280
+ end
281
+
282
+ def default_suppress_arp_disable
283
+ config_get_default('vxlan_vtep_vni', 'suppress_arp_disable')
284
+ end
285
+
255
286
  def suppress_uuc
256
287
  config_get('vxlan_vtep_vni', 'suppress_uuc', @get_args)
257
288
  end
@@ -12,6 +12,7 @@ mapping:
12
12
  - 'ios_xr'
13
13
  - 'nexus'
14
14
  # Product IDs
15
+ - 'C3048'
15
16
  - 'C3064'
16
17
  - 'C3132'
17
18
  - 'C3172'
@@ -31,6 +32,7 @@ mapping:
31
32
  # Platform and product filters
32
33
  ios_xr: *base
33
34
  nexus: *base
35
+ C3048: *base
34
36
  C3064: *base
35
37
  C3132: *base
36
38
  C3172: *base
@@ -85,6 +85,38 @@ class TestCase < Minitest::Test
85
85
  self.class.password
86
86
  end
87
87
 
88
+ def self.telnet_port
89
+ Cisco::Environment.environment[:telnet_port] || 23
90
+ end
91
+
92
+ def telnet_port
93
+ self.class.telnet_port
94
+ end
95
+
96
+ def self.port
97
+ Cisco::Environment.environment[:port] || address.split(':')[1]
98
+ end
99
+
100
+ def port
101
+ self.class.port
102
+ end
103
+
104
+ def self.transport
105
+ Cisco::Environment.environment[:transport] || 'http'
106
+ end
107
+
108
+ def transport
109
+ self.class.transport
110
+ end
111
+
112
+ def self.verify_mode
113
+ Cisco::Environment.environment[:verify_mode] || 'none'
114
+ end
115
+
116
+ def verify_mode
117
+ self.class.verify_mode
118
+ end
119
+
88
120
  def setup
89
121
  # Hack - populate environment from user-entered values from basetest.rb
90
122
  if Cisco::Environment.environments.empty?
@@ -92,13 +124,17 @@ class TestCase < Minitest::Test
92
124
  attr_writer :environments
93
125
  end
94
126
  Cisco::Environment.environments['default'] = {
95
- host: address.split(':')[0],
96
- port: address.split(':')[1],
97
- username: username,
98
- password: password,
127
+ host: address.split(':')[0],
128
+ port: port,
129
+ telnet_port: telnet_port,
130
+ transport: transport,
131
+ verify_mode: verify_mode,
132
+ username: username,
133
+ password: password,
99
134
  }
100
135
  end
101
136
  @device = Net::Telnet.new('Host' => address.split(':')[0],
137
+ 'Port' => telnet_port,
102
138
  'Timeout' => 240,
103
139
  # NX-OS has a space after '#', IOS XR does not
104
140
  'Prompt' => /[$%#>] *\z/n,