cisco_node_utils 1.3.0 → 1.4.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 (151) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +66 -0
  4. data/Gemfile +1 -0
  5. data/README.md +44 -43
  6. data/bin/.rubocop.yml +18 -0
  7. data/bin/show_running_yang.rb +233 -0
  8. data/cisco_node_utils.gemspec +1 -1
  9. data/docs/README-maintainers.md +1 -0
  10. data/docs/README-utilities.md +14 -0
  11. data/lib/.rubocop.yml +1 -1
  12. data/lib/cisco_node_utils/aaa_authentication_login_service.rb +8 -3
  13. data/lib/cisco_node_utils/aaa_authorization_service.rb +6 -0
  14. data/lib/cisco_node_utils/bfd_global.rb +300 -0
  15. data/lib/cisco_node_utils/bgp.rb +6 -4
  16. data/lib/cisco_node_utils/bgp_af.rb +2 -0
  17. data/lib/cisco_node_utils/bgp_neighbor.rb +14 -0
  18. data/lib/cisco_node_utils/bgp_neighbor_af.rb +4 -1
  19. data/lib/cisco_node_utils/cisco_cmn_utils.rb +126 -0
  20. data/lib/cisco_node_utils/client/client.rb +6 -2
  21. data/lib/cisco_node_utils/client/grpc/client.rb +120 -36
  22. data/lib/cisco_node_utils/client/nxapi/client.rb +6 -2
  23. data/lib/cisco_node_utils/cmd_ref/DEPRECATED.yaml +118 -0
  24. data/lib/cisco_node_utils/cmd_ref/aaa_authorization_service.yaml +14 -0
  25. data/lib/cisco_node_utils/cmd_ref/bfd_global.yaml +117 -0
  26. data/lib/cisco_node_utils/cmd_ref/bgp.yaml +7 -7
  27. data/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml +7 -0
  28. data/lib/cisco_node_utils/cmd_ref/dhcp_relay_global.yaml +125 -0
  29. data/lib/cisco_node_utils/cmd_ref/feature.yaml +10 -0
  30. data/lib/cisco_node_utils/cmd_ref/interface.yaml +141 -49
  31. data/lib/cisco_node_utils/cmd_ref/interface_ospf.yaml +44 -0
  32. data/lib/cisco_node_utils/cmd_ref/interface_portchannel.yaml +6 -0
  33. data/lib/cisco_node_utils/cmd_ref/ospf.yaml +6 -0
  34. data/lib/cisco_node_utils/cmd_ref/ospf_area.yaml +91 -0
  35. data/lib/cisco_node_utils/cmd_ref/ospf_area_vlink.yaml +88 -0
  36. data/lib/cisco_node_utils/cmd_ref/overlay_global.yaml +0 -3
  37. data/lib/cisco_node_utils/cmd_ref/show_version.yaml +3 -3
  38. data/lib/cisco_node_utils/cmd_ref/snmp_community.yaml +39 -15
  39. data/lib/cisco_node_utils/cmd_ref/snmp_notification_receiver.yaml +43 -21
  40. data/lib/cisco_node_utils/cmd_ref/snmp_server.yaml +48 -19
  41. data/lib/cisco_node_utils/cmd_ref/snmp_user.yaml +0 -0
  42. data/lib/cisco_node_utils/cmd_ref/tacacs_global.yaml +30 -0
  43. data/lib/cisco_node_utils/cmd_ref/tacacs_server.yaml +18 -6
  44. data/lib/cisco_node_utils/cmd_ref/vdc.yaml +4 -0
  45. data/lib/cisco_node_utils/cmd_ref/virtual_service.yaml +1 -0
  46. data/lib/cisco_node_utils/cmd_ref/vlan.yaml +23 -10
  47. data/lib/cisco_node_utils/cmd_ref/vxlan_vtep.yaml +8 -2
  48. data/lib/cisco_node_utils/cmd_ref/yang.yaml +7 -0
  49. data/lib/cisco_node_utils/cmd_ref/yum.yaml +10 -1
  50. data/lib/cisco_node_utils/constants.rb +8 -1
  51. data/lib/cisco_node_utils/dhcp_relay_global.rb +302 -0
  52. data/lib/cisco_node_utils/exceptions.rb +29 -0
  53. data/lib/cisco_node_utils/feature.rb +28 -0
  54. data/lib/cisco_node_utils/interface.rb +493 -402
  55. data/lib/cisco_node_utils/interface_DEPRECATED.rb +513 -0
  56. data/lib/cisco_node_utils/interface_ospf.rb +126 -0
  57. data/lib/cisco_node_utils/interface_portchannel.rb +16 -0
  58. data/lib/cisco_node_utils/logger.rb +3 -0
  59. data/lib/cisco_node_utils/node.rb +29 -1
  60. data/lib/cisco_node_utils/overlay_global.rb +1 -12
  61. data/lib/cisco_node_utils/pim.rb +1 -0
  62. data/lib/cisco_node_utils/pim_group_list.rb +1 -0
  63. data/lib/cisco_node_utils/pim_rp_address.rb +1 -0
  64. data/lib/cisco_node_utils/platform.rb +9 -2
  65. data/lib/cisco_node_utils/router_ospf.rb +1 -1
  66. data/lib/cisco_node_utils/router_ospf_area.rb +416 -0
  67. data/lib/cisco_node_utils/router_ospf_area_vlink.rb +313 -0
  68. data/lib/cisco_node_utils/router_ospf_vrf.rb +17 -0
  69. data/lib/cisco_node_utils/snmp_notification_receiver.rb +27 -9
  70. data/lib/cisco_node_utils/snmpcommunity.rb +34 -8
  71. data/lib/cisco_node_utils/snmpserver.rb +4 -4
  72. data/lib/cisco_node_utils/snmpuser.rb +0 -0
  73. data/lib/cisco_node_utils/tacacs_global.rb +102 -0
  74. data/lib/cisco_node_utils/tacacs_server.rb +8 -7
  75. data/lib/cisco_node_utils/vdc.rb +25 -7
  76. data/lib/cisco_node_utils/version.rb +1 -1
  77. data/lib/cisco_node_utils/vlan.rb +30 -56
  78. data/lib/cisco_node_utils/vlan_DEPRECATED.rb +108 -0
  79. data/lib/cisco_node_utils/yang.rb +160 -0
  80. data/lib/cisco_node_utils/yum.rb +25 -32
  81. data/tests/.rubocop.yml +3 -0
  82. data/tests/ciscotest.rb +136 -19
  83. data/tests/cmd_config_invalid.yaml +1 -1
  84. data/tests/noop.rb +7 -0
  85. data/tests/tacacs_server.yaml.example +6 -0
  86. data/tests/test_aaa_authentication_login.rb +24 -1
  87. data/tests/test_aaa_authentication_login_service.rb +9 -16
  88. data/tests/test_aaa_authorization_service.rb +111 -84
  89. data/tests/test_bfd_global.rb +278 -0
  90. data/tests/test_bgp_neighbor.rb +20 -0
  91. data/tests/test_bridge_domain_vni.rb +2 -9
  92. data/tests/test_cmn_utils.rb +76 -0
  93. data/tests/test_dhcp_relay_global.rb +284 -0
  94. data/tests/test_dns_domain.rb +4 -4
  95. data/tests/test_domain_name.rb +2 -2
  96. data/tests/test_encapsulation.rb +2 -4
  97. data/tests/test_evpn_vni.rb +14 -7
  98. data/tests/test_fabricpath_global.rb +12 -13
  99. data/tests/test_feature.rb +35 -17
  100. data/tests/test_interface.rb +352 -127
  101. data/tests/test_interface_bdi.rb +2 -2
  102. data/tests/test_interface_channel_group.rb +1 -1
  103. data/tests/test_interface_ospf.rb +153 -23
  104. data/tests/test_interface_portchannel.rb +15 -6
  105. data/tests/test_interface_private_vlan.rb +200 -576
  106. data/tests/test_interface_svi.rb +5 -52
  107. data/tests/test_interface_switchport.rb +80 -240
  108. data/tests/test_itd_device_group.rb +2 -2
  109. data/tests/test_itd_device_group_node.rb +2 -2
  110. data/tests/test_itd_service.rb +1 -1
  111. data/tests/test_name_server.rb +3 -3
  112. data/tests/test_node_ext.rb +15 -17
  113. data/tests/test_ntp_config.rb +1 -1
  114. data/tests/test_ntp_server.rb +3 -3
  115. data/tests/test_nxapi.rb +1 -0
  116. data/tests/test_overlay_global.rb +15 -19
  117. data/tests/test_pim.rb +5 -5
  118. data/tests/test_pim_group_list.rb +1 -37
  119. data/tests/test_pim_rp_address.rb +1 -1
  120. data/tests/test_platform.rb +9 -11
  121. data/tests/test_portchannel_global.rb +43 -3
  122. data/tests/test_radius_server.rb +1 -1
  123. data/tests/test_radius_server_group.rb +1 -1
  124. data/tests/test_router_bgp.rb +17 -30
  125. data/tests/test_router_ospf_area.rb +433 -0
  126. data/tests/test_router_ospf_area_vlink.rb +298 -0
  127. data/tests/test_router_ospf_vrf.rb +17 -0
  128. data/tests/test_snmp_notification_receiver.rb +11 -11
  129. data/tests/test_snmpcommunity.rb +177 -69
  130. data/tests/test_snmpgroup.rb +7 -7
  131. data/tests/test_snmpserver.rb +164 -253
  132. data/tests/test_snmpuser.rb +73 -69
  133. data/tests/test_stp_global.rb +15 -15
  134. data/tests/test_syslog_settings.rb +1 -1
  135. data/tests/test_tacacs_global.rb +80 -0
  136. data/tests/test_tacacs_server.rb +129 -51
  137. data/tests/test_tacacs_server_group.rb +3 -29
  138. data/tests/test_tacacs_server_host.rb +24 -27
  139. data/tests/test_vlan.rb +57 -59
  140. data/tests/test_vlan_private.rb +271 -284
  141. data/tests/test_vpc.rb +10 -4
  142. data/tests/test_vrf.rb +2 -0
  143. data/tests/test_vrf_af.rb +2 -5
  144. data/tests/test_vtp.rb +5 -2
  145. data/tests/test_vxlan_vtep.rb +20 -44
  146. data/tests/test_vxlan_vtep_vni.rb +23 -16
  147. data/tests/test_yang.rb +369 -0
  148. data/tests/test_yum.rb +34 -42
  149. data/tests/yum_package.yaml +35 -0
  150. metadata +31 -4
  151. data/tests/test_vlan_mt_full.rb +0 -85
@@ -92,7 +92,13 @@ module Cisco
92
92
  self.hello_interval = default_hello_interval
93
93
  config_set('interface_ospf', 'dead_interval',
94
94
  @interface.name, 'no', '')
95
+ self.bfd = default_bfd
96
+ self.mtu_ignore = default_mtu_ignore
97
+ self.priority = default_priority
98
+ self.network_type = default_network_type
95
99
  self.passive_interface = default_passive_interface if passive_interface
100
+ self.shutdown = default_shutdown
101
+ self.transmit_delay = default_transmit_delay
96
102
  end
97
103
 
98
104
  def default_message_digest
@@ -106,6 +112,7 @@ module Cisco
106
112
  # interface %s
107
113
  # %s ip ospf authentication message-digest
108
114
  def message_digest=(enable)
115
+ return if enable == message_digest
109
116
  config_set('interface_ospf', 'message_digest', @interface.name,
110
117
  enable ? '' : 'no')
111
118
  end
@@ -144,6 +151,10 @@ module Cisco
144
151
  config_get('interface_ospf', 'message_digest_password', @interface.name)
145
152
  end
146
153
 
154
+ def default_message_digest_password
155
+ config_get_default('interface_ospf', 'message_digest_password')
156
+ end
157
+
147
158
  # interface %s
148
159
  # %s ip ospf message-digest-key %d %s %d %s
149
160
  def message_digest_key_set(keyid, algtype, enctype, enc)
@@ -209,6 +220,72 @@ module Cisco
209
220
  @interface.name, '', interval.to_i)
210
221
  end
211
222
 
223
+ # CLI can be either of the following or none
224
+ # ip ospf bfd
225
+ # ip ospf bfd disable
226
+ def bfd
227
+ val = config_get('interface_ospf', 'bfd', @interface.name)
228
+ return if val.nil?
229
+ val.include?('disable') ? false : true
230
+ end
231
+
232
+ # interface %s
233
+ # %s ip ospf bfd %s
234
+ def bfd=(val)
235
+ return if val == bfd
236
+ Feature.bfd_enable
237
+ state = (val == default_bfd) ? 'no' : ''
238
+ disable = val ? '' : 'disable'
239
+ config_set('interface_ospf', 'bfd', @interface.name,
240
+ state, disable)
241
+ end
242
+
243
+ def default_bfd
244
+ config_get_default('interface_ospf', 'bfd')
245
+ end
246
+
247
+ def default_network_type
248
+ case @interface.name
249
+ when /loopback/i
250
+ lookup = 'network_type_loopback_default'
251
+ else
252
+ lookup = 'network_type_default'
253
+ end
254
+ config_get_default('interface_ospf', lookup)
255
+ end
256
+
257
+ def mtu_ignore
258
+ config_get('interface_ospf', 'mtu_ignore', @interface.name)
259
+ end
260
+
261
+ # interface %s
262
+ # %s ip ospf mtu-ignore
263
+ def mtu_ignore=(enable)
264
+ config_set('interface_ospf', 'mtu_ignore', @interface.name,
265
+ enable ? '' : 'no')
266
+ end
267
+
268
+ def default_mtu_ignore
269
+ config_get_default('interface_ospf', 'mtu_ignore')
270
+ end
271
+
272
+ def network_type
273
+ type = config_get('interface_ospf', 'network_type', @interface.name)
274
+ return 'p2p' if type == 'point-to-point'
275
+ return default_network_type if type.nil?
276
+ type
277
+ end
278
+
279
+ # interface %s
280
+ # %s ip ospf network %s
281
+ 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)
287
+ end
288
+
212
289
  def default_passive_interface
213
290
  config_get_default('interface_ospf', 'passive_interface')
214
291
  end
@@ -224,5 +301,54 @@ module Cisco
224
301
  config_set('interface_ospf', 'passive_interface', @interface.name,
225
302
  enable ? '' : 'no')
226
303
  end
304
+
305
+ def priority
306
+ config_get('interface_ospf', 'priority', @interface.name)
307
+ end
308
+
309
+ # interface %s
310
+ # ip ospf priority %d
311
+ 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)
316
+ end
317
+
318
+ def default_priority
319
+ config_get_default('interface_ospf', 'priority')
320
+ end
321
+
322
+ def shutdown
323
+ config_get('interface_ospf', 'shutdown', @interface.name)
324
+ end
325
+
326
+ # interface %s
327
+ # %s ip ospf shutdown
328
+ def shutdown=(state)
329
+ config_set('interface_ospf', 'shutdown', @interface.name,
330
+ state ? '' : 'no')
331
+ end
332
+
333
+ def default_shutdown
334
+ config_get_default('interface_ospf', 'shutdown')
335
+ end
336
+
337
+ def transmit_delay
338
+ config_get('interface_ospf', 'transmit_delay', @interface.name)
339
+ end
340
+
341
+ # interface %s
342
+ # ip ospf transmit-delay %d
343
+ 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)
348
+ end
349
+
350
+ def default_transmit_delay
351
+ config_get_default('interface_ospf', 'transmit_delay')
352
+ end
227
353
  end
228
354
  end
@@ -61,6 +61,22 @@ module Cisco
61
61
  # PROPERTIES #
62
62
  ########################################################
63
63
 
64
+ def bfd_per_link
65
+ config_get('interface_portchannel', 'bfd_per_link', @name)
66
+ end
67
+
68
+ def bfd_per_link=(state)
69
+ return if state == bfd_per_link
70
+ no_cmd = (state ? '' : 'no')
71
+ Feature.bfd_enable
72
+ config_set('interface_portchannel',
73
+ 'bfd_per_link', @name, no_cmd)
74
+ end
75
+
76
+ def default_bfd_per_link
77
+ config_get_default('interface_portchannel', 'bfd_per_link')
78
+ end
79
+
64
80
  def lacp_graceful_convergence
65
81
  config_get('interface_portchannel', 'lacp_graceful_convergence', @name)
66
82
  end
@@ -45,6 +45,9 @@ module Cisco::Logger
45
45
  @@logger = Chef::Log # rubocop:disable Style/ClassVars
46
46
  else
47
47
  @@logger = Logger.new(STDOUT) # rubocop:disable Style/ClassVars
48
+ @@logger.formatter = proc do |severity, _datetime, _progname, msg|
49
+ "#{severity} -- : #{msg}\n"
50
+ end
48
51
  @@logger.level = Logger::INFO
49
52
 
50
53
  def level
@@ -206,6 +206,34 @@ module Cisco
206
206
  @client.get(**kwargs)
207
207
  end
208
208
 
209
+ # Merge the specified JSON YANG config with the running config on
210
+ # the device.
211
+ def merge_yang(yang)
212
+ @client.set(data_format: :yang_json, values: [yang], mode: :merge_config)
213
+ end
214
+
215
+ # Replace the running config on the device with the specified
216
+ # JSON YANG config.
217
+ def replace_yang(yang)
218
+ @client.set(data_format: :yang_json, values: [yang],
219
+ mode: :replace_config)
220
+ end
221
+
222
+ # Delete the specified JSON YANG config from the device.
223
+ def delete_yang(yang)
224
+ @client.set(data_format: :yang_json, values: [yang], mode: :delete_config)
225
+ end
226
+
227
+ # Retrieve JSON YANG config from the device for the specified path.
228
+ def get_yang(yang_path)
229
+ @client.get(data_format: :yang_json, command: yang_path)
230
+ end
231
+
232
+ # Retrieve JSON YANG operational data for the specified path.
233
+ def get_yang_oper(yang_path)
234
+ @client.get(data_format: :yang_json, command: yang_path, mode: :get_oper)
235
+ end
236
+
209
237
  # @return [String] such as "Cisco Nexus Operating System (NX-OS) Software"
210
238
  def os
211
239
  o = config_get('show_version', 'header')
@@ -237,7 +265,7 @@ module Cisco
237
265
  # No support for structured output for this command yet
238
266
  output = get(command: 'show inventory',
239
267
  data_format: :cli)
240
- return /NAME: "Rack 0".*\nPID: (\S+)/.match(output)[1]
268
+ return /NAME: .*\nPID: (\S+)/.match(output)[1]
241
269
  end
242
270
  end
243
271
  end
@@ -31,7 +31,6 @@ module Cisco
31
31
 
32
32
  # dup-host-ip-addr-detection
33
33
  def dup_host_ip_addr_detection
34
- return nil unless Feature.nv_overlay_evpn_enabled?
35
34
  match = config_get('overlay_global', 'dup_host_ip_addr_detection')
36
35
  if match.nil?
37
36
  default_dup_host_ip_addr_detection
@@ -99,16 +98,7 @@ module Cisco
99
98
 
100
99
  def dup_host_mac_detection_set(host_moves, timeout)
101
100
  set_args = { host_moves: host_moves, timeout: timeout }
102
- if host_moves == default_dup_host_mac_detection_host_moves &&
103
- timeout == default_dup_host_mac_detection_timeout
104
- dup_host_mac_detection_default
105
- else
106
- config_set('overlay_global', 'dup_host_mac_detection', set_args)
107
- end
108
- end
109
-
110
- def dup_host_mac_detection_default
111
- config_set('overlay_global', 'dup_host_mac_detection_default')
101
+ config_set('overlay_global', 'dup_host_mac_detection', set_args)
112
102
  end
113
103
 
114
104
  def default_dup_host_mac_detection
@@ -126,7 +116,6 @@ module Cisco
126
116
 
127
117
  # anycast-gateway-mac
128
118
  def anycast_gateway_mac
129
- return nil unless Feature.nv_overlay_evpn_enabled?
130
119
  mac = config_get('overlay_global', 'anycast_gateway_mac')
131
120
  mac.nil? || mac.empty? ? default_anycast_gateway_mac : mac.downcase
132
121
  end
@@ -45,6 +45,7 @@ module Cisco
45
45
  def self.pims
46
46
  afis = %w(ipv4) # TBD: No support for ipv6 at this time
47
47
  hash_final = {}
48
+ return hash_final unless Feature.pim_enabled?
48
49
  afis.each do |afi|
49
50
  hash_final[afi] = {}
50
51
  default_vrf = 'default'
@@ -42,6 +42,7 @@ module Cisco
42
42
  def self.group_lists
43
43
  afis = %w(ipv4) # TBD ipv6
44
44
  hash = {}
45
+ return hash unless Feature.pim_enabled?
45
46
  afis.each do |afi|
46
47
  hash[afi] = {}
47
48
  default_vrf = 'default'
@@ -39,6 +39,7 @@ module Cisco
39
39
  def self.rp_addresses
40
40
  afis = %w(ipv4) # TBD ipv6
41
41
  hash = {}
42
+ return hash unless Feature.pim_enabled?
42
43
  afis.each do |afi|
43
44
  hash[afi] = {}
44
45
  default_vrf = 'default'
@@ -28,7 +28,7 @@ module Cisco
28
28
 
29
29
  # ex: 'n3500-uk9.6.0.2.A3.0.40.bin'
30
30
  def self.system_image
31
- config_get('show_version', 'boot_image')
31
+ config_get('show_version', 'system_image')
32
32
  end
33
33
 
34
34
  # Returns package hash with state values
@@ -188,7 +188,14 @@ module Cisco
188
188
  # 'cpu' => '0% system CPU' }},
189
189
  # { ... }}
190
190
  def self.virtual_services
191
- virts = config_get('virtual_service', 'services')
191
+ # If no virtual-services are installed, this will result
192
+ # in a RuntimeError. We need to rescue this specific case.
193
+ begin
194
+ virts = config_get('virtual_service', 'services')
195
+ rescue RuntimeError => e
196
+ return {} if e.message[/No key \"TABLE_detail\"/]
197
+ raise
198
+ end
192
199
  return {} if virts.nil?
193
200
  # NXAPI returns hash instead of array if there's only 1
194
201
  virts = [virts] if virts.is_a? Hash
@@ -61,7 +61,7 @@ module Cisco
61
61
  end
62
62
 
63
63
  def wait_for_process_initialized
64
- return unless node.product_id[/N(5|6)/]
64
+ return unless node.product_id[/N(5|6|8)/]
65
65
 
66
66
  # Hack for slow-start platforms which will have setter failures if the
67
67
  # ospf instance is still initializing. To see this problem in a sandbox
@@ -0,0 +1,416 @@
1
+ #
2
+ # NXAPI implementation of Router OSPF Area class
3
+ #
4
+ # June 2016, Sai Chintalapudi
5
+ #
6
+ # Copyright (c) 2016 Cisco and/or its affiliates.
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+
20
+ require 'ipaddr'
21
+ require_relative 'node_util'
22
+ require_relative 'router_ospf'
23
+ require_relative 'router_ospf_vrf'
24
+
25
+ module Cisco
26
+ # node_utils class for ospf_area
27
+ class RouterOspfArea < NodeUtil
28
+ attr_reader :router, :vrf, :area_id
29
+
30
+ def initialize(ospf_router, vrf_name, area_id, instantiate=true)
31
+ fail TypeError unless ospf_router.is_a?(String)
32
+ fail TypeError unless vrf_name.is_a?(String)
33
+ fail ArgumentError unless ospf_router.length > 0
34
+ fail ArgumentError unless vrf_name.length > 0
35
+ @area_id = area_id.to_s
36
+ fail ArgumentError if @area_id.empty?
37
+
38
+ Feature.ospf_enable if instantiate
39
+ # Convert to dot-notation
40
+
41
+ @router = ospf_router
42
+ @vrf = vrf_name
43
+ @area_id = IPAddr.new(area_id.to_i, Socket::AF_INET) unless @area_id[/\./]
44
+
45
+ set_args_keys_default
46
+ end
47
+
48
+ def self.areas
49
+ hash = {}
50
+ RouterOspf.routers.each do |name, _obj|
51
+ # get all area ids under default vrf
52
+ area_ids = config_get('ospf_area', 'areas', name: name)
53
+ if area_ids
54
+ hash[name] = {}
55
+ hash[name]['default'] = {}
56
+ area_ids.uniq.each do |area|
57
+ hash[name]['default'][area] =
58
+ RouterOspfArea.new(name, 'default', area, false)
59
+ end
60
+ end
61
+ vrf_ids = config_get('ospf', 'vrf', name: name)
62
+ next if vrf_ids.nil?
63
+ vrf_ids.each do |vrf|
64
+ # get all area ids under each vrf
65
+ area_ids = config_get('ospf_area', 'areas', name: name, vrf: vrf)
66
+ next if area_ids.nil?
67
+ hash[name] ||= {}
68
+ hash[name][vrf] = {}
69
+ area_ids.uniq.each do |area|
70
+ hash[name][vrf][area] =
71
+ RouterOspfArea.new(name, vrf, area, false)
72
+ end
73
+ end
74
+ end
75
+ hash
76
+ end
77
+
78
+ # Helper method to delete @set_args hash keys
79
+ def set_args_keys_default
80
+ @set_args = { name: @router, area: @area_id }
81
+ @set_args[:vrf] = @vrf unless @vrf == 'default'
82
+ @get_args = @set_args
83
+ end
84
+
85
+ # rubocop:disable Style/AccessorMethodName
86
+ def set_args_keys(hash={})
87
+ set_args_keys_default
88
+ @set_args = @get_args.merge!(hash) unless hash.empty?
89
+ end
90
+
91
+ def destroy
92
+ return unless Feature.ospf_enabled?
93
+ [:authentication,
94
+ :default_cost,
95
+ :filter_list_in,
96
+ :filter_list_out,
97
+ :nssa,
98
+ :nssa_translate_type7,
99
+ :range,
100
+ :stub,
101
+ ].each do |prop|
102
+ send("#{prop}=", send("default_#{prop}")) unless
103
+ send("#{prop}") == send("default_#{prop}")
104
+ end
105
+ set_args_keys_default
106
+ end
107
+
108
+ def ==(other)
109
+ (ospf_router == other.ospf_router) &&
110
+ (vrf_name == other.vrf_name) && (area_id == other.area_id)
111
+ end
112
+
113
+ ########################################################
114
+ # PROPERTIES #
115
+ ########################################################
116
+
117
+ # CLI can be either of the following or none
118
+ # area 1.1.1.1 authentication
119
+ # area 1.1.1.1 authentication message-digest
120
+ def authentication
121
+ auth = config_get('ospf_area', 'authentication', @get_args)
122
+ return default_authentication unless auth
123
+ auth.include?('message-digest') ? 'md5' : 'cleartext'
124
+ end
125
+
126
+ def authentication=(val)
127
+ state = val ? '' : 'no'
128
+ auth = (val.to_s == 'md5') ? 'message-digest' : ''
129
+ set_args_keys(state: state, auth: auth)
130
+ config_set('ospf_area', 'authentication', @set_args)
131
+ end
132
+
133
+ def default_authentication
134
+ config_get_default('ospf_area', 'authentication')
135
+ end
136
+
137
+ # CLI can be the following or none
138
+ # area 1.1.1.1 default-cost 1000
139
+ def default_cost
140
+ config_get('ospf_area', 'default_cost', @get_args)
141
+ end
142
+
143
+ def default_cost=(val)
144
+ state = val == default_default_cost ? 'no' : ''
145
+ cost = val == default_default_cost ? '' : val
146
+ set_args_keys(state: state, cost: cost)
147
+ config_set('ospf_area', 'default_cost', @set_args)
148
+ end
149
+
150
+ def default_default_cost
151
+ config_get_default('ospf_area', 'default_cost')
152
+ end
153
+
154
+ # CLI can be the following or none
155
+ # area 1.1.1.1 filter-list route-map aaa in
156
+ def filter_list_in
157
+ config_get('ospf_area', 'filter_list_in', @get_args)
158
+ end
159
+
160
+ def filter_list_in=(val)
161
+ return if filter_list_in == false && val == false
162
+ state = val ? '' : 'no'
163
+ rm = val ? val : filter_list_in
164
+ set_args_keys(state: state, route_map: rm)
165
+ config_set('ospf_area', 'filter_list_in', @set_args)
166
+ end
167
+
168
+ def default_filter_list_in
169
+ config_get_default('ospf_area', 'filter_list_in')
170
+ end
171
+
172
+ # CLI can be the following or none
173
+ # area 1.1.1.1 filter-list route-map bbb out
174
+ def filter_list_out
175
+ config_get('ospf_area', 'filter_list_out', @get_args)
176
+ end
177
+
178
+ def filter_list_out=(val)
179
+ return if filter_list_out == false && val == false
180
+ state = val ? '' : 'no'
181
+ rm = val ? val : filter_list_out
182
+ set_args_keys(state: state, route_map: rm)
183
+ config_set('ospf_area', 'filter_list_out', @set_args)
184
+ end
185
+
186
+ def default_filter_list_out
187
+ config_get_default('ospf_area', 'filter_list_out')
188
+ end
189
+
190
+ # CLI can be the following or none
191
+ # area 1.1.1.1 nssa
192
+ # the above command can be appended with no-summary and/or
193
+ # no-redistribution and/or default-information-originate.
194
+ # route-map <map> can be appended with default-information-originate
195
+ # Basically, every property this CLI configures is optional
196
+ # example manifest:
197
+ # nssa => true,
198
+ # nssa_default_originate => true,
199
+ # nssa_no_redistribution => false,
200
+ # nssa_no_summary => false,
201
+ # nssa_route_map => 'aaa',
202
+ def nssa_get
203
+ hash = {}
204
+ output = config_get('ospf_area', 'nssa_get', @get_args)
205
+ return hash if output.nil?
206
+ output.each do |line|
207
+ next if line.include?('translate')
208
+ hash[:nssa] = true
209
+ hash[:no_summary] = true if line.include?('no-summary')
210
+ hash[:no_redistribution] = true if line.include?('no-redistribution')
211
+ hash[:def_info_origin] = true if
212
+ line.include?('default-information-originate')
213
+ if line.include?('route-map')
214
+ params = line.split
215
+ hash[:route_map] = params[params.index('route-map') + 1]
216
+ end
217
+ end
218
+ hash
219
+ end
220
+
221
+ def nssa
222
+ nssa_get[:nssa].nil? ? false : true
223
+ end
224
+
225
+ def default_nssa
226
+ config_get_default('ospf_area', 'nssa')
227
+ end
228
+
229
+ def nssa_default_originate
230
+ nssa_get[:def_info_origin].nil? ? false : true
231
+ end
232
+
233
+ def default_nssa_default_originate
234
+ config_get_default('ospf_area', 'nssa_default_originate')
235
+ end
236
+
237
+ def nssa_no_redistribution
238
+ nssa_get[:no_redistribution].nil? ? false : true
239
+ end
240
+
241
+ def default_nssa_no_redistribution
242
+ config_get_default('ospf_area', 'nssa_no_redistribution')
243
+ end
244
+
245
+ def nssa_no_summary
246
+ nssa_get[:no_summary].nil? ? false : true
247
+ end
248
+
249
+ def default_nssa_no_summary
250
+ config_get_default('ospf_area', 'nssa_no_summary')
251
+ end
252
+
253
+ def nssa_route_map
254
+ nssa_get[:route_map].nil? ? '' : nssa_get[:route_map]
255
+ end
256
+
257
+ def default_nssa_route_map
258
+ config_get_default('ospf_area', 'nssa_route_map')
259
+ end
260
+
261
+ def nssa_set(hash)
262
+ # The nssa cli is additive so it must be removed altogether
263
+ # when making changes.
264
+ config_set('ospf_area', 'nssa_destroy', @set_args) if nssa
265
+ return if hash.empty?
266
+
267
+ @set_args[:state] = ''
268
+ @set_args[:nssa_no_summary] = ''
269
+ @set_args[:nssa_no_redistribution] = ''
270
+ @set_args[:nssa_default_originate] = ''
271
+ @set_args[:nssa_route_map] = ''
272
+ # Process each nssa property
273
+ hash.keys.each do |k|
274
+ hash[k] = 'default-information-originate' if
275
+ k == :nssa_default_originate
276
+ hash[k] = 'no-summary' if k == :nssa_no_summary
277
+ hash[k] = 'no-redistribution' if k == :nssa_no_redistribution
278
+ hash[k] = "route-map #{hash[:nssa_route_map]}" if
279
+ k == :nssa_route_map
280
+ @set_args[k] = hash[k]
281
+ end
282
+ config_set('ospf_area', 'nssa_set', @set_args)
283
+ end
284
+
285
+ # CLI can be the following or none
286
+ # area 1.1.1.1 nssa translate type7 always
287
+ # area 1.1.1.1 nssa translate type7 always supress-fa
288
+ # area 1.1.1.1 nssa translate type7 never
289
+ # area 1.1.1.1 nssa translate type7 supress-fa
290
+ def nssa_translate_type7
291
+ str = config_get('ospf_area', 'nssa_translate_type7', @get_args)
292
+ str = 'always_supress_fa' if str == 'always supress-fa'
293
+ str = 'supress_fa' if str == 'supress-fa'
294
+ str
295
+ end
296
+
297
+ def nssa_translate_type7=(val)
298
+ state = val ? '' : 'no'
299
+ value = val ? val : ''
300
+ value = 'always supress-fa' if val.to_s == 'always_supress_fa'
301
+ value = 'supress-fa' if val.to_s == 'supress_fa'
302
+ set_args_keys(state: state, value: value)
303
+ config_set('ospf_area', 'nssa_translate_type7', @set_args)
304
+ end
305
+
306
+ def default_nssa_translate_type7
307
+ config_get_default('ospf_area', 'nssa_translate_type7')
308
+ end
309
+
310
+ # range can take multiple values for the same vrf
311
+ # area 1.1.1.1 range 10.3.0.0/32
312
+ # area 1.1.1.1 range 10.3.0.1/32
313
+ # area 1.1.1.1 range 10.3.3.0/24
314
+ # area 1.1.1.1 range 10.3.0.0/16 not-advertise cost 23
315
+ # sometimes the not-advertise and cost are reversed in the
316
+ # show command for reasons unknown!
317
+ # area 1.1.1.1 range 10.3.0.0/16 cost 23 not-advertise
318
+ # use positional way of getting the values as it is
319
+ # simple and there are only two properties which are
320
+ # optional. ip is mandatory
321
+ # the return list is of the form [ip, not-advertise, cost]
322
+ # ex: [['10.3.0.0/16', 'not-advertise', '23'],
323
+ # ['10.3.0.0/32', 'not-advertise'],
324
+ # ['10.3.0.1/32'],
325
+ # ['10.3.3.0/24', '450']]
326
+ def range
327
+ list = []
328
+ ranges = config_get('ospf_area', 'range', @get_args)
329
+ ranges.each do |line|
330
+ llist = []
331
+ params = line.split
332
+ llist[0] = params[0]
333
+ llist[1] = 'not_advertise' if line.include?('not-advertise')
334
+ if line.include?('cost')
335
+ arr_index = llist[1].nil? ? 1 : 2
336
+ llist[arr_index] = params[params.index('cost') + 1]
337
+ end
338
+ list << llist
339
+ end
340
+ list
341
+ end
342
+
343
+ def range=(set_list)
344
+ # fail if set_list contains duplicate ip values
345
+ ip_list = []
346
+ set_list.each do |ip, _not_advertise, _cval|
347
+ ip_list << ip
348
+ end
349
+ fail ArgumentError, 'Duplicate ip values for range' unless
350
+ ip_list.size == ip_list.uniq.size
351
+ # reset the current ranges first due to bug CSCuz98937
352
+ cur_list = range
353
+ cur_list.each do |ip, _not_advertise, _cval|
354
+ set_args_keys(state: 'no', ip: ip, not_advertise: '',
355
+ cost: '', value: '')
356
+ config_set('ospf_area', 'range', @set_args)
357
+ end
358
+ # now set the range from the set_list
359
+ set_list.each do |ip, noadv, cval|
360
+ na = noadv == 'not_advertise' ? 'not-advertise' : ''
361
+ cost = cval ? 'cost' : ''
362
+ value = cval ? cval : ''
363
+ # in case of 2 variables, ip and cost
364
+ if noadv && noadv != 'not_advertise'
365
+ cost = 'cost'
366
+ value = noadv
367
+ end
368
+ set_args_keys(state: '', ip: ip, not_advertise: na,
369
+ cost: cost, value: value)
370
+ config_set('ospf_area', 'range', @set_args)
371
+ end
372
+ end
373
+
374
+ def default_range
375
+ config_get_default('ospf_area', 'range')
376
+ end
377
+
378
+ def stub
379
+ config_get('ospf_area', 'stub', @get_args)
380
+ end
381
+
382
+ def stub=(val)
383
+ state = val ? '' : 'no'
384
+ set_args_keys(state: state)
385
+ config_set('ospf_area', 'stub', @set_args)
386
+ end
387
+
388
+ def default_stub
389
+ config_get_default('ospf_area', 'stub')
390
+ end
391
+
392
+ def stub_no_summary
393
+ config_get('ospf_area', 'stub_no_summary', @get_args)
394
+ end
395
+
396
+ def stub_no_summary=(val)
397
+ if val
398
+ state = ''
399
+ set_args_keys(state: state)
400
+ config_set('ospf_area', 'stub_no_summary', @set_args)
401
+ else
402
+ if stub
403
+ # reset and set stub
404
+ set_args_keys(state: 'no')
405
+ config_set('ospf_area', 'stub', @set_args)
406
+ set_args_keys(state: '')
407
+ config_set('ospf_area', 'stub', @set_args)
408
+ end
409
+ end
410
+ end
411
+
412
+ def default_stub_no_summary
413
+ config_get_default('ospf_area', 'stub_no_summary')
414
+ end
415
+ end # class
416
+ end # module