cisco_node_utils 1.10.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,