cisco_node_utils 1.0.1 → 1.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 (114) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rubocop.yml +81 -1
  4. data/.travis.yml +9 -0
  5. data/CHANGELOG.md +72 -6
  6. data/CONTRIBUTING.md +32 -7
  7. data/README.md +70 -7
  8. data/Rakefile +17 -0
  9. data/bin/check_metric_limits.rb +109 -0
  10. data/bin/git/hooks/commit-msg/enforce_style +81 -0
  11. data/bin/git/hooks/hook_lib +108 -0
  12. data/bin/git/hooks/hooks-wrapper +38 -0
  13. data/bin/git/hooks/post-flow-hotfix-start/update-version +24 -0
  14. data/bin/git/hooks/post-flow-release-finish/update-version +29 -0
  15. data/bin/git/hooks/post-flow-release-start/update-version +19 -0
  16. data/bin/git/hooks/post-merge/update-hooks +6 -0
  17. data/bin/git/hooks/post-rewrite/update-hooks +6 -0
  18. data/bin/git/hooks/pre-commit/rubocop +20 -0
  19. data/bin/git/hooks/pre-commit/validate-diffs +31 -0
  20. data/bin/git/hooks/pre-push/check-changelog +24 -0
  21. data/bin/git/hooks/pre-push/rubocop +7 -0
  22. data/bin/git/update-hooks +65 -0
  23. data/cisco_node_utils.gemspec +9 -3
  24. data/docs/README-develop-best-practices.md +404 -0
  25. data/docs/README-develop-node-utils-APIs.md +215 -365
  26. data/docs/README-maintainers.md +33 -3
  27. data/docs/template-router.rb +89 -91
  28. data/docs/template-test_router.rb +52 -55
  29. data/lib/.rubocop.yml +18 -0
  30. data/lib/cisco_node_utils.rb +2 -19
  31. data/lib/cisco_node_utils/README_YAML.md +1 -9
  32. data/lib/cisco_node_utils/bgp.rb +664 -0
  33. data/lib/cisco_node_utils/bgp_af.rb +530 -0
  34. data/lib/cisco_node_utils/bgp_neighbor.rb +425 -0
  35. data/lib/cisco_node_utils/bgp_neighbor_af.rb +709 -0
  36. data/lib/cisco_node_utils/cisco_cmn_utils.rb +59 -25
  37. data/lib/cisco_node_utils/command_reference.rb +72 -74
  38. data/lib/cisco_node_utils/command_reference_common.yaml +174 -9
  39. data/lib/cisco_node_utils/command_reference_common_bgp.yaml +535 -0
  40. data/lib/cisco_node_utils/command_reference_n7k.yaml +4 -0
  41. data/lib/cisco_node_utils/command_reference_n9k.yaml +0 -9
  42. data/lib/cisco_node_utils/configparser_lib.rb +152 -147
  43. data/lib/cisco_node_utils/dns_domain.rb +79 -0
  44. data/lib/cisco_node_utils/domain_name.rb +71 -0
  45. data/lib/cisco_node_utils/interface.rb +167 -161
  46. data/lib/cisco_node_utils/interface_ospf.rb +78 -81
  47. data/lib/cisco_node_utils/name_server.rb +64 -0
  48. data/lib/cisco_node_utils/node.rb +154 -198
  49. data/lib/cisco_node_utils/node_util.rb +61 -0
  50. data/lib/cisco_node_utils/ntp_config.rb +65 -0
  51. data/lib/cisco_node_utils/ntp_server.rb +76 -0
  52. data/lib/cisco_node_utils/platform.rb +174 -165
  53. data/lib/cisco_node_utils/radius_global.rb +146 -0
  54. data/lib/cisco_node_utils/radius_server.rb +295 -0
  55. data/lib/cisco_node_utils/router_ospf.rb +59 -63
  56. data/lib/cisco_node_utils/router_ospf_vrf.rb +226 -210
  57. data/lib/cisco_node_utils/snmpcommunity.rb +52 -58
  58. data/lib/cisco_node_utils/snmpgroup.rb +22 -23
  59. data/lib/cisco_node_utils/snmpserver.rb +99 -103
  60. data/lib/cisco_node_utils/snmpuser.rb +294 -274
  61. data/lib/cisco_node_utils/syslog_server.rb +92 -0
  62. data/lib/cisco_node_utils/syslog_settings.rb +69 -0
  63. data/lib/cisco_node_utils/tacacs_server.rb +137 -133
  64. data/lib/cisco_node_utils/tacacs_server_host.rb +84 -87
  65. data/lib/cisco_node_utils/version.rb +2 -1
  66. data/lib/cisco_node_utils/vlan.rb +28 -31
  67. data/lib/cisco_node_utils/vrf.rb +80 -0
  68. data/lib/cisco_node_utils/vtp.rb +100 -97
  69. data/lib/cisco_node_utils/yum.rb +15 -17
  70. data/tests/.rubocop.yml +15 -0
  71. data/tests/basetest.rb +81 -36
  72. data/tests/ciscotest.rb +38 -78
  73. data/{lib/cisco_node_utils → tests}/platform_info.rb +12 -8
  74. data/{lib/cisco_node_utils → tests}/platform_info.yaml +1 -1
  75. data/tests/test_bgp_af.rb +920 -0
  76. data/tests/test_bgp_neighbor.rb +403 -0
  77. data/tests/test_bgp_neighbor_af.rb +589 -0
  78. data/tests/test_command_config.rb +65 -62
  79. data/tests/test_command_reference.rb +31 -45
  80. data/tests/test_dns_domain.rb +113 -0
  81. data/tests/test_domain_name.rb +86 -0
  82. data/tests/test_interface.rb +424 -548
  83. data/tests/test_interface_ospf.rb +248 -432
  84. data/tests/test_interface_svi.rb +56 -79
  85. data/tests/test_interface_switchport.rb +196 -272
  86. data/tests/test_name_server.rb +85 -0
  87. data/tests/test_node.rb +7 -6
  88. data/tests/test_node_ext.rb +133 -186
  89. data/tests/test_ntp_config.rb +49 -0
  90. data/tests/test_ntp_server.rb +74 -0
  91. data/tests/test_platform.rb +58 -37
  92. data/tests/test_radius_global.rb +78 -0
  93. data/tests/test_radius_server.rb +185 -0
  94. data/tests/test_router_bgp.rb +838 -0
  95. data/tests/test_router_ospf.rb +49 -80
  96. data/tests/test_router_ospf_vrf.rb +274 -392
  97. data/tests/test_snmpcommunity.rb +128 -172
  98. data/tests/test_snmpgroup.rb +12 -14
  99. data/tests/test_snmpserver.rb +160 -189
  100. data/tests/test_snmpuser.rb +568 -717
  101. data/tests/test_syslog_server.rb +88 -0
  102. data/tests/test_syslog_settings.rb +54 -0
  103. data/tests/test_tacacs_server.rb +113 -148
  104. data/tests/test_tacacs_server_host.rb +108 -161
  105. data/tests/test_vlan.rb +63 -79
  106. data/tests/test_vrf.rb +92 -0
  107. data/tests/test_vtp.rb +108 -126
  108. data/tests/test_yum.rb +47 -41
  109. metadata +92 -56
  110. data/.rubocop_todo.yml +0 -293
  111. data/docs/.rubocop.yml +0 -13
  112. data/docs/template-feature.rb +0 -45
  113. data/docs/template-test_feature.rb +0 -51
  114. data/tests/test_all_cisco.rb +0 -46
@@ -7,4 +7,4 @@
7
7
  # attributes can be added in future.
8
8
 
9
9
  example_node:
10
- interfaces: [Ethernet1/1, Ethernet1/10, Ethernet1/20]
10
+ interfaces: [Ethernet1/1, Ethernet1/2, Ethernet1/3]
@@ -0,0 +1,920 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ # RouterBgpAF Unit Tests
4
+ #
5
+ # Richard Wellum, August, 2015
6
+ #
7
+ # Copyright (c) 2015 Cisco and/or its affiliates.
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+
21
+ require_relative 'ciscotest'
22
+ require_relative '../lib/cisco_node_utils/bgp'
23
+ require_relative '../lib/cisco_node_utils/bgp_af'
24
+
25
+ # TestRouterBgpAF - Minitest for RouterBgpAF class
26
+ class TestRouterBgpAF < CiscoTestCase
27
+ def setup
28
+ super
29
+ # Disable and enable feature bgp before each test to ensure we
30
+ # are starting with a clean slate for each test.
31
+ config('no feature bgp', 'feature bgp')
32
+ end
33
+
34
+ def get_bgp_af_cfg(asn, vrf, af)
35
+ afi, safi = af
36
+ string =
37
+ @device.cmd("show run bgp all | sec 'bgp #{asn}' | sec 'vrf #{vrf}' | " \
38
+ "sec 'address-family #{afi} #{safi}' | no-more")
39
+ string
40
+ end
41
+
42
+ # show bgp ipv4 unicast dampening parameters
43
+ # Route Flap Dampening Parameters for VRF default Address family IPv4 Unicast:
44
+ # Default values in use:
45
+ # Half-life time : 15 mins
46
+ # Suppress penalty : 2000
47
+ # Reuse penalty : 750
48
+ # Max suppress time : 45 mins
49
+ # Max suppress penalty : 6000
50
+ def get_bgp_af_dampening_params(_asn, vrf, af)
51
+ afi = af.first
52
+ safi = af.last
53
+ @device.cmd("show bgp vrf #{vrf} #{afi} #{safi} dampening parameters")
54
+ end
55
+
56
+ ##
57
+ ## BGP Address Family
58
+ ## Validate that RouterBgp.afs is empty when bgp is not enabled
59
+ ##
60
+ def test_collection_empty
61
+ node.cache_flush
62
+ afs = RouterBgpAF.afs
63
+ assert_empty(afs, 'BGP address-family collection is not empty')
64
+ end
65
+
66
+ ##
67
+ ## BGP Address Family
68
+ ## Configure router bgp, some VRF's and address-family statements
69
+ ## - verify that the final instance objects are correctly populated
70
+ ##
71
+ def test_collection_not_empty
72
+ config('feature bgp',
73
+ 'router bgp 55',
74
+ 'address-family ipv4 unicast',
75
+ 'vrf red',
76
+ 'address-family ipv4 unicast',
77
+ 'vrf blue',
78
+ 'address-family ipv6 multicast',
79
+ 'vrf orange',
80
+ 'address-family ipv4 multicast',
81
+ 'vrf black',
82
+ 'address-family ipv6 unicast')
83
+
84
+ # Construct a hash of routers, vrfs, afs
85
+ routers = RouterBgpAF.afs
86
+ refute_empty(routers, 'Error: BGP address_family collection is empty')
87
+
88
+ # Validate the collection
89
+ routers.each do |asn, vrfs|
90
+ assert((asn.kind_of? Fixnum),
91
+ 'Error: Autonomous number must be a fixed number')
92
+ refute_empty(vrfs, 'Error: Collection is empty')
93
+
94
+ vrfs.each do |vrf, afs|
95
+ refute_empty(afs, 'Error: No Address Family found')
96
+ assert(vrf.length > 0, 'Error: No VRF found')
97
+ afs.each_key do |af_key|
98
+ afi = af_key[0]
99
+ safi = af_key[1]
100
+ assert(afi.length > 0, 'Error: AFI length is zero')
101
+ assert_match(/^ipv[46]/, afi, 'Error: AFI must be ipv4 or ipv6')
102
+ assert(safi.length > 0, 'Error: SAFI length is zero')
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ ########################################################
109
+ # PROPERTIES #
110
+ ########################################################
111
+
112
+ ##
113
+ ## default-information originate
114
+ ##
115
+ def test_default_information_originate
116
+ asn = '55'
117
+ vrf = 'red'
118
+ af = %w(ipv4 unicast)
119
+
120
+ #
121
+ # Set and verify
122
+ #
123
+ bgp_af = RouterBgpAF.new(asn, vrf, af)
124
+ bgp_af.default_information_originate = true
125
+ assert(bgp_af.default_information_originate,
126
+ 'Error: default-information originate not set')
127
+
128
+ pattern = /^ *default-information originate$/
129
+ af_string = get_bgp_af_cfg(asn, vrf, af)
130
+
131
+ assert_match(pattern, af_string,
132
+ "Error: 'default_information originate' is not" \
133
+ ' configured and should be')
134
+
135
+ #
136
+ # Unset and verify
137
+ #
138
+
139
+ # Do a 'no default-information originate'
140
+ bgp_af.default_information_originate = false
141
+
142
+ pattern = /^ *default-information originate$/
143
+ af_string = get_bgp_af_cfg(asn, vrf, af)
144
+
145
+ refute_match(pattern, af_string,
146
+ "Error: 'default_information originate' " \
147
+ 'is configured and should not be')
148
+ end
149
+
150
+ ##
151
+ ## client-to-client reflection
152
+ ##
153
+ def test_client_to_client
154
+ asn = '55'
155
+ vrf = 'red'
156
+ af = %w(ipv4 unicast)
157
+
158
+ bgp_af = RouterBgpAF.new(asn, vrf, af)
159
+ pattern = /^ *client-to-client reflection$/
160
+ #
161
+ # Default is 'client-to-client' is configured
162
+ #
163
+ af_string = get_bgp_af_cfg(asn, vrf, af)
164
+
165
+ assert_match(pattern, af_string,
166
+ "Error: 'client-to-client reflection' is not configured " \
167
+ 'and should be')
168
+
169
+ assert(bgp_af.client_to_client,
170
+ "Error: 'client-to-client is not configured but should be")
171
+ #
172
+ # Unset and verify
173
+ #
174
+
175
+ # Do a 'no client-to-client reflection'
176
+ bgp_af.client_to_client = false
177
+ pattern = /^ *no client-to-client reflection$/
178
+ af_string = get_bgp_af_cfg(asn, vrf, af)
179
+
180
+ assert_match(pattern, af_string,
181
+ "Error: 'no client-to-client' is not configured and should be")
182
+
183
+ #
184
+ # Set and verify
185
+ #
186
+
187
+ # Do a 'client-to-client reflection'
188
+ bgp_af.client_to_client = true
189
+ af_string = get_bgp_af_cfg(asn, vrf, af)
190
+
191
+ refute_match(pattern, af_string,
192
+ "Error: 'no client-to-client' is configured and should not be")
193
+ end
194
+
195
+ ##
196
+ ## next_hop route-map
197
+ ##
198
+ def test_next_hop_route_map
199
+ asn = '55'
200
+ vrf = 'red'
201
+ af = %w(ipv4 unicast)
202
+
203
+ #
204
+ # Set and verify
205
+ #
206
+ bgp_af = RouterBgpAF.new(asn, vrf, af)
207
+ bgp_af.next_hop_route_map = 'drop_all'
208
+ assert_match(bgp_af.next_hop_route_map, 'drop_all',
209
+ 'Error: nexthop route-map not set')
210
+ pattern = /^ *nexthop route-map drop_all$/
211
+ af_string = get_bgp_af_cfg(asn, vrf, af)
212
+
213
+ assert_match(pattern, af_string,
214
+ "Error: 'nexthop route-map drop_all' is " \
215
+ 'not configured and should be')
216
+
217
+ #
218
+ # Unset and verify
219
+ #
220
+
221
+ # Do a 'no nexthop route-map drop_all'
222
+ bgp_af.next_hop_route_map = bgp_af.default_next_hop_route_map
223
+ af_string = get_bgp_af_cfg(asn, vrf, af)
224
+
225
+ refute_match(pattern, af_string,
226
+ "Error: 'nexthop route-map drop_all' is " \
227
+ 'configured and should not be')
228
+ end
229
+
230
+ ##
231
+ ## additional_paths
232
+ ##
233
+ def test_additional_paths
234
+ asn = '55'
235
+ vrf = 'red'
236
+ af = %w(ipv4 unicast)
237
+
238
+ bgp_af = RouterBgpAF.new(asn, vrf, af)
239
+
240
+ pattern_send = 'additional-paths send'
241
+ pattern_receive = 'additional-paths receive'
242
+ pattern_install = 'additional-paths install backup'
243
+
244
+ #
245
+ # Default is not configured
246
+ #
247
+ af_string = get_bgp_af_cfg(asn, vrf, af)
248
+
249
+ [pattern_send, pattern_receive, pattern_install].each do |pat|
250
+ refute_match(pat, af_string,
251
+ "Error: '#{pat}' is configured but should not be")
252
+ end
253
+
254
+ #
255
+ # Test default and getter methods
256
+ #
257
+ assert_equal(bgp_af.default_additional_paths_send,
258
+ bgp_af.additional_paths_send)
259
+ assert_equal(bgp_af.default_additional_paths_receive,
260
+ bgp_af.additional_paths_receive)
261
+ assert_equal(bgp_af.default_additional_paths_install,
262
+ bgp_af.additional_paths_install)
263
+
264
+ #
265
+ # Set and verify
266
+ #
267
+
268
+ # Do a 'additional-paths send, receive, install'
269
+ bgp_af.additional_paths_send = true
270
+ bgp_af.additional_paths_receive = true
271
+ bgp_af.additional_paths_install = true
272
+
273
+ af_string = get_bgp_af_cfg(asn, vrf, af)
274
+
275
+ [pattern_send, pattern_receive, pattern_install].each do |pat|
276
+ assert_match(pat, af_string,
277
+ "Error: '#{pat}' is not configured and should be")
278
+ end
279
+
280
+ #
281
+ # Test getter
282
+ #
283
+
284
+ assert(bgp_af.additional_paths_send)
285
+ assert(bgp_af.additional_paths_receive)
286
+ assert(bgp_af.additional_paths_install)
287
+
288
+ #
289
+ # Unset and verify
290
+ #
291
+
292
+ # Do a 'no additional-paths send, receive, install'
293
+ bgp_af.additional_paths_send = false
294
+ bgp_af.additional_paths_receive = false
295
+ bgp_af.additional_paths_install = false
296
+
297
+ af_string = get_bgp_af_cfg(asn, vrf, af)
298
+
299
+ [pattern_send, pattern_receive, pattern_install].each do |pat|
300
+ refute_match(pat, af_string,
301
+ "Error: '#{pat}' is configured but should not be")
302
+ end
303
+ end
304
+
305
+ ##
306
+ ## additional_paths_selection route-map
307
+ ##
308
+ def test_additional_paths_selection
309
+ asn = '55'
310
+ vrf = 'red'
311
+ af = %w(ipv4 unicast)
312
+
313
+ #
314
+ # Set and verify
315
+ #
316
+ bgp_af = RouterBgpAF.new(asn, vrf, af)
317
+ bgp_af.additional_paths_selection = 'drop_all'
318
+
319
+ assert_equal(bgp_af.additional_paths_selection, 'drop_all',
320
+ 'Error: additional-paths selection route-map not set')
321
+
322
+ af_string = get_bgp_af_cfg(asn, vrf, af)
323
+ pattern = /^ *additional-paths selection route-map drop_all$/
324
+
325
+ assert_match(pattern, af_string,
326
+ "Error: 'additional-paths selection route-map drop_all' is " \
327
+ 'not configured and should be')
328
+
329
+ #
330
+ # Test getter
331
+ #
332
+ pattern = /^ *drop_all$/
333
+ assert_match(pattern, bgp_af.additional_paths_selection,
334
+ "Error: 'route-map drop_all' is not configured and should be")
335
+
336
+ #
337
+ # Unset and verify
338
+ #
339
+
340
+ # Do a 'no additional-paths selection route-map drop_all'
341
+ bgp_af.additional_paths_selection =
342
+ bgp_af.default_additional_paths_selection
343
+
344
+ af_string = get_bgp_af_cfg(asn, vrf, af)
345
+
346
+ refute_match(pattern, af_string,
347
+ "Error: 'additional-paths selection route-map drop_all' is " \
348
+ 'configured and should not be')
349
+ end
350
+
351
+ ##
352
+ ## get_dampen_igp_metric
353
+ ##
354
+ def test_dampen_igp_metric
355
+ asn = '44'
356
+ vrf = 'green'
357
+ af = %w(ipv4 multicast)
358
+
359
+ bgp_af = RouterBgpAF.new(asn, vrf, af)
360
+
361
+ #
362
+ # Verify default value
363
+ #
364
+ assert_equal(bgp_af.dampen_igp_metric, bgp_af.default_dampen_igp_metric,
365
+ "Error: Default 'dampen-igp-metric' value should be " \
366
+ "#{bgp_af.default_dampen_igp_metric}")
367
+
368
+ #
369
+ # Set and verify 'dampen-igp-metric <value>'
370
+ #
371
+
372
+ # Do a 'dampen-igp-metric 555'
373
+ pattern = /^ *dampen-igp-metric 555$/
374
+ bgp_af.dampen_igp_metric = 555
375
+
376
+ af_string = get_bgp_af_cfg(asn, vrf, af)
377
+
378
+ assert_match(pattern, af_string,
379
+ "Error: 'dampen-igp-metric 555' is not configured " \
380
+ 'and should be')
381
+ #
382
+ # Test getter
383
+ #
384
+ assert_equal(bgp_af.dampen_igp_metric, 555,
385
+ 'Error: dampen_igp_metric should be 555')
386
+
387
+ #
388
+ # Set and verify 'no dampen-igp-metric'
389
+ #
390
+
391
+ # Do a 'no dampen-igp-metric'
392
+ pattern = /no dampen-igp-metric$/
393
+ bgp_af.dampen_igp_metric = nil
394
+
395
+ af_string = get_bgp_af_cfg(asn, vrf, af)
396
+
397
+ assert_match(pattern, af_string,
398
+ "Error: 'no dampen-igp-metric' is not configured " \
399
+ 'and should be')
400
+ #
401
+ # Test getter
402
+ #
403
+ assert_equal(bgp_af.dampen_igp_metric, nil,
404
+ 'Error: dampen_igp_metric should be nil')
405
+
406
+ #
407
+ # Set default value explicitly
408
+ #
409
+ bgp_af.dampen_igp_metric = bgp_af.default_dampen_igp_metric
410
+ assert_equal(bgp_af.dampen_igp_metric, bgp_af.default_dampen_igp_metric,
411
+ "Error: Default 'dampen-igp-metric' value should be " \
412
+ "#{bgp_af.default_dampen_igp_metric}")
413
+ end
414
+
415
+ ##
416
+ ## dampening
417
+ ##
418
+ # rubocop:disable Metrics/MethodLength
419
+ def test_dampening
420
+ asn = '101'
421
+
422
+ ############################################
423
+ # Set and verify 'dampening' with defaults #
424
+ ############################################
425
+ vrf = 'orange'
426
+ af = %w(ipv4 unicast)
427
+ bgp_af = RouterBgpAF.new(asn, vrf, af)
428
+
429
+ # Test no dampening configured
430
+ assert_nil(bgp_af.dampening)
431
+
432
+ pattern = /^ *dampening$/
433
+
434
+ bgp_af.dampening = []
435
+
436
+ # Check property got set
437
+ af_string = get_bgp_af_cfg(asn, vrf, af)
438
+
439
+ assert_match(pattern, af_string,
440
+ "Error: 'dampening' is not configured and should be")
441
+
442
+ # Check properties got set
443
+ af_string = get_bgp_af_dampening_params(asn, vrf, af)
444
+
445
+ pattern_params1 = 'Half-life time : 15 mins'
446
+ pattern_params2 = 'Suppress penalty : 2000'
447
+ pattern_params3 = 'Reuse penalty : 750'
448
+ pattern_params4 = 'Max suppress time : 45 mins'
449
+ pattern_params5 = 'Max suppress penalty : 6000'
450
+
451
+ error = ("Error: 'dampening' properties are incorrect")
452
+
453
+ assert_match(pattern_params1, af_string, error)
454
+ assert_match(pattern_params2, af_string, error)
455
+ assert_match(pattern_params3, af_string, error)
456
+ assert_match(pattern_params4, af_string, error)
457
+ assert_match(pattern_params5, af_string, error)
458
+
459
+ # Check getter
460
+ assert_empty(bgp_af.dampening, 'Error: dampening is configured and ' \
461
+ 'should not be')
462
+
463
+ #
464
+ # Unset and verify
465
+ #
466
+ bgp_af.dampening = nil
467
+
468
+ af_string = get_bgp_af_cfg(asn, vrf, af)
469
+ pattern = /^ *dampening$/
470
+
471
+ refute_match(pattern, af_string, "Error: 'dampening' is still configured")
472
+
473
+ #
474
+ # Test Getters
475
+ #
476
+ assert_nil(bgp_af.dampening)
477
+ assert_nil(bgp_af.dampening_half_time)
478
+ assert_nil(bgp_af.dampening_reuse_time)
479
+ assert_nil(bgp_af.dampening_suppress_time)
480
+ assert_nil(bgp_af.dampening_max_suppress_time)
481
+ assert_nil(bgp_af.dampening_routemap)
482
+
483
+ bgp_af.destroy
484
+
485
+ #############################################
486
+ # Set and verify 'dampening' with overrides #
487
+ #############################################
488
+ vrf = 'green'
489
+ af = %w(ipv4 multicast)
490
+ bgp_af = RouterBgpAF.new(asn, vrf, af)
491
+
492
+ bgp_af.dampening = %w(1 2 3 4)
493
+
494
+ # Check property got set
495
+ af_string = get_bgp_af_cfg(asn, vrf, af)
496
+ pattern = /^ *dampening 1 2 3 4$/
497
+
498
+ assert_match(pattern, af_string,
499
+ "Error: 'dampening' is not configured and should be")
500
+
501
+ # Check properties got set
502
+ af_string = get_bgp_af_dampening_params(asn, vrf, af)
503
+
504
+ pattern_params1 = 'Half-life time : 1 mins'
505
+ pattern_params2 = 'Suppress penalty : 3'
506
+ pattern_params3 = 'Reuse penalty : 2'
507
+ pattern_params4 = 'Max suppress time : 4 mins'
508
+ pattern_params5 = 'Max suppress penalty : 32'
509
+
510
+ error = ("Error: 'dampening' properties are incorrect")
511
+
512
+ assert_match(pattern_params1, af_string, error)
513
+ assert_match(pattern_params2, af_string, error)
514
+ assert_match(pattern_params3, af_string, error)
515
+ assert_match(pattern_params4, af_string, error)
516
+ assert_match(pattern_params5, af_string, error)
517
+
518
+ # Check getters
519
+ assert_equal(bgp_af.dampening, %w(1 2 3 4),
520
+ 'Error: dampening getter did not match')
521
+ assert_equal(1, bgp_af.dampening_half_time,
522
+ 'The wrong dampening half_time value is configured')
523
+ assert_equal(2, bgp_af.dampening_reuse_time,
524
+ 'The wrong dampening reuse_time value is configured')
525
+ assert_equal(3, bgp_af.dampening_suppress_time,
526
+ 'The wrong dampening suppress_time value is configured')
527
+ assert_equal(4, bgp_af.dampening_max_suppress_time,
528
+ 'The wrong dampening max_suppress_time value is configured')
529
+ assert_empty(bgp_af.dampening_routemap,
530
+ 'A routemap should not be configured')
531
+
532
+ #
533
+ # Unset and verify
534
+ #
535
+ bgp_af.dampening = nil
536
+
537
+ af_string = get_bgp_af_cfg(asn, vrf, af)
538
+ pattern = /^ *dampening$/
539
+
540
+ refute_match(pattern, af_string, "Error: 'dampening' is still configured")
541
+
542
+ #############################################
543
+ # Set and verify 'dampening' with route-map #
544
+ #############################################
545
+ vrf = 'brown'
546
+ af = %w(ipv6 unicast)
547
+ bgp_af = RouterBgpAF.new(asn, vrf, af)
548
+
549
+ bgp_af.dampening = 'DropAllTraffic'
550
+
551
+ pattern = /^ *dampening route-map DropAllTraffic$/
552
+
553
+ # Check property got set
554
+ af_string = get_bgp_af_cfg(asn, vrf, af)
555
+
556
+ assert_match(pattern, af_string,
557
+ "Error: 'dampening' is not configured and should be")
558
+
559
+ # Check properties got set
560
+ af_string = get_bgp_af_dampening_params(asn, vrf, af)
561
+ pattern_params = 'Dampening policy configured: DropAllTraffic'
562
+
563
+ assert_match(pattern_params, af_string,
564
+ 'Error: dampening properties DropAllTraffic is not ' \
565
+ 'configured and should be')
566
+
567
+ # Check getters
568
+ assert_equal(bgp_af.dampening, 'DropAllTraffic',
569
+ 'Error: dampening getter did not match')
570
+ assert_equal(bgp_af.dampening_routemap, 'DropAllTraffic',
571
+ 'Error: dampening getter did not match')
572
+
573
+ #
574
+ # Unset and verify
575
+ #
576
+ bgp_af.dampening = nil
577
+ af_string = get_bgp_af_cfg(asn, vrf, af)
578
+ pattern = /^ *dampening$/
579
+
580
+ refute_match(pattern, af_string, "Error: 'dampening' is still configured")
581
+
582
+ #############################################
583
+ # Set and verify 'dampening' with default #
584
+ #############################################
585
+ vrf = 'sangria'
586
+ af = %w(ipv4 multicast)
587
+ bgp_af = RouterBgpAF.new(asn, vrf, af)
588
+
589
+ bgp_af.dampening = bgp_af.default_dampening
590
+
591
+ # Check property got set
592
+ af_string = get_bgp_af_cfg(asn, vrf, af)
593
+
594
+ assert_match(pattern, af_string,
595
+ "Error: 'dampening' is not configured and should be")
596
+
597
+ # Check properties got set
598
+ af_string = get_bgp_af_dampening_params(asn, vrf, af)
599
+
600
+ pattern_params1 = 'Half-life time : 15 mins'
601
+ pattern_params2 = 'Suppress penalty : 2000'
602
+ pattern_params3 = 'Reuse penalty : 750'
603
+ pattern_params4 = 'Max suppress time : 45 mins'
604
+ pattern_params5 = 'Max suppress penalty : 6000'
605
+
606
+ error = ("Error: 'dampening' properties are incorrect")
607
+
608
+ assert_match(pattern_params1, af_string, error)
609
+ assert_match(pattern_params2, af_string, error)
610
+ assert_match(pattern_params3, af_string, error)
611
+ assert_match(pattern_params4, af_string, error)
612
+ assert_match(pattern_params5, af_string, error)
613
+
614
+ # Check getters
615
+ assert_empty(bgp_af.dampening, 'Error: dampening not configured ' \
616
+ 'and should be')
617
+ assert_equal(bgp_af.default_dampening_half_time, bgp_af.dampening_half_time,
618
+ 'Wrong default dampening half_time value configured')
619
+ assert_equal(bgp_af.default_dampening_reuse_time,
620
+ bgp_af.dampening_reuse_time,
621
+ 'Wrong default dampening reuse_time value configured')
622
+ assert_equal(bgp_af.default_dampening_suppress_time,
623
+ bgp_af.dampening_suppress_time,
624
+ 'Wrong default dampening suppress_time value configured')
625
+ assert_equal(bgp_af.default_dampening_max_suppress_time,
626
+ bgp_af.dampening_max_suppress_time,
627
+ 'Wrong default dampening suppress_max_time value configured')
628
+ assert_equal(bgp_af.default_dampening_routemap,
629
+ bgp_af.dampening_routemap,
630
+ 'The default dampening routemap should configured')
631
+
632
+ #
633
+ # Unset and verify
634
+ #
635
+ bgp_af.dampening = nil
636
+ af_string = get_bgp_af_cfg(asn, vrf, af)
637
+
638
+ refute_match(pattern, af_string, "Error: 'dampening' is still configured")
639
+ end
640
+ # rubocop:enable Metrics/AbcSize,Metrics/MethodLength
641
+
642
+ ##
643
+ ## maximum_paths
644
+ ##
645
+ def maximum_paths(asn, vrf, af)
646
+ bgp_af = RouterBgpAF.new(asn, vrf, af)
647
+
648
+ #
649
+ # Set and verify
650
+ #
651
+ val = 7
652
+ bgp_af.maximum_paths = val
653
+ assert_equal(bgp_af.maximum_paths, val,
654
+ 'Error: maximum paths value not match to set value')
655
+
656
+ val = 9
657
+ bgp_af.maximum_paths = val
658
+ assert_equal(bgp_af.maximum_paths, val,
659
+ 'Error: maximum paths value not match to set value')
660
+
661
+ val = bgp_af.default_maximum_paths
662
+ bgp_af.maximum_paths = val
663
+ assert_equal(bgp_af.maximum_paths, val,
664
+ 'Error: maximum paths value not match to default value')
665
+ end
666
+
667
+ def test_maximum_paths
668
+ vrfs = %w(default red)
669
+ afs = [%w(ipv4 unicast), %w(ipv6 unicast)]
670
+ vrfs.each do |vrf|
671
+ afs.each do |af|
672
+ maximum_paths(55, vrf, af)
673
+ end
674
+ end
675
+ end
676
+
677
+ ##
678
+ ## maximum_paths_ibgp
679
+ ##
680
+ def maximum_paths_ibgp(asn, vrf, af)
681
+ /ipv4/.match(af) ? af = %w(ipv4 unicast) : af = %w(ipv6 unicast)
682
+ bgp_af = RouterBgpAF.new(asn, vrf, af)
683
+
684
+ #
685
+ # Set and verify
686
+ #
687
+ val = 7
688
+ bgp_af.maximum_paths_ibgp = val
689
+ assert_equal(bgp_af.maximum_paths_ibgp, val,
690
+ 'Error: maximum paths ibgp value not match to set value')
691
+
692
+ val = 9
693
+ bgp_af.maximum_paths_ibgp = val
694
+ assert_equal(bgp_af.maximum_paths_ibgp, val,
695
+ 'Error: maximum paths ibgp value not match to set value')
696
+
697
+ val = bgp_af.default_maximum_paths_ibgp
698
+ bgp_af.maximum_paths = val
699
+ assert_equal(bgp_af.default_maximum_paths_ibgp, val,
700
+ 'Error: maximum paths ibgp value not match to default value')
701
+ end
702
+
703
+ def test_maximum_paths_ibgp
704
+ asn = '55'
705
+ vrf = 'default'
706
+ af = 'ipv4 unicast'
707
+ maximum_paths_ibgp(asn, vrf, af)
708
+
709
+ asn = '55'
710
+ vrf = 'red'
711
+ af = 'ipv4 unicast'
712
+ maximum_paths_ibgp(asn, vrf, af)
713
+
714
+ asn = '55'
715
+ vrf = 'default'
716
+ af = 'ipv6 unicast'
717
+ maximum_paths_ibgp(asn, vrf, af)
718
+
719
+ asn = '55'
720
+ vrf = 'red'
721
+ af = 'ipv6 unicast'
722
+ maximum_paths_ibgp(asn, vrf, af)
723
+ end
724
+
725
+ ##
726
+ ## network
727
+ ##
728
+
729
+ def test_network
730
+ vrfs = %w(default red)
731
+ afs = [%w(ipv4 unicast), %w(ipv6 unicast)]
732
+ vrfs.each do |vrf|
733
+ afs.each do |af|
734
+ dbg = sprintf('[VRF %s AF %s]', vrf, af.join('/'))
735
+ af_obj = RouterBgpAF.new(1, vrf, af)
736
+ network_cmd(af_obj, dbg)
737
+ end
738
+ end
739
+ end
740
+
741
+ def network_cmd(af, dbg)
742
+ # Initial 'should' state
743
+ if /ipv6/.match(dbg)
744
+ master = [
745
+ ['2000:123:38::/64', 'rtmap1'],
746
+ ['2000:123:39::/64', 'rtmap2'],
747
+ ['2000:123:40::/64', 'rtmap3'],
748
+ ['2000:123:41::/64'],
749
+ ['2000:123:42::/64', 'rtmap5'],
750
+ ['2000:123:43::/64', 'rtmap6'],
751
+ ['2000:123:44::/64'],
752
+ ['2000:123:45::/64', 'rtmap7'],
753
+ ]
754
+ else
755
+ master = [
756
+ ['192.168.5.0/24', 'rtmap1'],
757
+ ['192.168.6.0/24', 'rtmap2'],
758
+ ['192.168.7.0/24', 'rtmap3'],
759
+ ['192.168.8.0/24'],
760
+ ['192.168.9.0/24', 'rtmap5'],
761
+ ['192.168.10.0/24', 'rtmap6'],
762
+ ['192.168.11.0/24'],
763
+ ['192.168.12.0/24', 'rtmap7'],
764
+ ]
765
+ end
766
+
767
+ # Test: all networks are set when current is empty.
768
+ should = master.clone
769
+ af.networks = should
770
+ result = af.networks
771
+ assert_equal(should.sort, result.sort,
772
+ "#{dbg} Test 1. From empty, to all networks")
773
+
774
+ # Test: remove half of the networks
775
+ should.shift(4)
776
+ af.networks = should
777
+ result = af.networks
778
+ assert_equal(should.sort, result.sort,
779
+ "#{dbg} Test 2. Remove half of the networks")
780
+
781
+ # Test: restore the removed networks
782
+ should = master.clone
783
+ af.networks = should
784
+ result = af.networks
785
+ assert_equal(should.sort, result.sort,
786
+ "#{dbg} Test 3. Restore the removed networks")
787
+
788
+ # Test: Change route-maps on existing networks
789
+ should = master.map { |network, rm| [network, "#{rm}_55"] }
790
+ af.networks = should
791
+ result = af.networks
792
+ assert_equal(should.sort, result.sort,
793
+ "#{dbg} Test 4. Change route-map on existing networks")
794
+
795
+ # Test: 'default'
796
+ should = af.default_networks
797
+ af.networks = should
798
+ result = af.networks
799
+ assert_equal(should.sort, result.sort,
800
+ "#{dbg} Test 5. 'Default'")
801
+ end
802
+
803
+ ##
804
+ ## redistribute
805
+ ##
806
+
807
+ def test_redistribute
808
+ vrfs = %w(default red)
809
+ afs = [%w(ipv4 unicast), %w(ipv6 unicast)]
810
+ vrfs.each do |vrf|
811
+ afs.each do |af|
812
+ dbg = sprintf('[VRF %s AF %s]', vrf, af.join('/'))
813
+ af = RouterBgpAF.new(1, vrf, af)
814
+ redistribute_cmd(af, dbg)
815
+ end
816
+ end
817
+ end
818
+
819
+ def redistribute_cmd(af, dbg)
820
+ # rubocop:disable Style/WordArray
821
+ # Initial 'should' state
822
+ ospf = (dbg.include? 'ipv6') ? 'ospfv3 3' : 'ospf 3'
823
+ master = [['direct', 'rm_direct'],
824
+ ['lisp', 'rm_lisp'],
825
+ ['static', 'rm_static'],
826
+ ['eigrp 1', 'rm_eigrp'],
827
+ ['isis 2', 'rm_isis'],
828
+ [ospf, 'rm_ospf'],
829
+ ['rip 4', 'rm_rip']]
830
+ # rubocop:enable Style/WordArray
831
+
832
+ # Test: Add all protocols w/route-maps when no cmds are present
833
+ should = master.clone
834
+ af.redistribute = should
835
+ result = af.redistribute
836
+ assert_equal(should.sort, result.sort,
837
+ "#{dbg} Test 1. From empty, to all protocols")
838
+
839
+ # Test: remove half of the protocols
840
+ should.shift(4)
841
+ af.redistribute = should
842
+ result = af.redistribute
843
+ assert_equal(should.sort, result.sort,
844
+ "#{dbg} Test 2. Remove half of the protocols")
845
+
846
+ # Test: restore the removed protocols
847
+ should = master.clone
848
+ af.redistribute = should
849
+ result = af.redistribute
850
+ assert_equal(should.sort, result.sort,
851
+ "#{dbg} Test 3. Restore the removed protocols")
852
+
853
+ # Test: Change route-maps on existing commands
854
+ should = master.map { |prot_only, rm| [prot_only, "#{rm}_2"] }
855
+ af.redistribute = should
856
+ result = af.redistribute
857
+ assert_equal(should.sort, result.sort,
858
+ "#{dbg} Test 4. Change route-maps on existing commands")
859
+
860
+ # Test: 'default'
861
+ should = af.default_redistribute
862
+ af.redistribute = should
863
+ result = af.redistribute
864
+ assert_equal(should.sort, result.sort,
865
+ "#{dbg} Test 5. 'Default'")
866
+ end
867
+
868
+ ##
869
+ ## common utilities
870
+ ##
871
+
872
+ def test_utils_delta_add_remove
873
+ # Note: AF context is not needed. This test is only validating the
874
+ # delta_add_remove class method and does not test directly on the device.
875
+
876
+ # rubocop:disable Style/WordArray
877
+ # Initial 'should' state
878
+ should = [['direct', 'rm_direct'],
879
+ ['lisp', 'rm_lisp'],
880
+ ['static', 'rm_static'],
881
+ ['eigrp 1', 'rm_eigrp'],
882
+ ['isis 2', 'rm_isis'],
883
+ ['ospf 3', 'rm_ospf'],
884
+ ['rip 4', 'rm_rip']]
885
+ # rubocop:enable Style/WordArray
886
+
887
+ # Test: Check delta when every protocol is specified and has a route-map.
888
+ current = []
889
+ expected = { add: should, remove: [] }
890
+ result = Utils.delta_add_remove(should, current)
891
+ assert_equal(expected, result, 'Test 1. delta mismatch')
892
+
893
+ # Test: Check delta when should is the same as current.
894
+ current = should.clone
895
+ expected = { add: [], remove: [] }
896
+ result = Utils.delta_add_remove(should, current)
897
+ assert_equal(expected, result, 'Test 2. delta mismatch')
898
+
899
+ # Test: Move half the 'current' entries to 'should'. Check delta.
900
+ should = current.shift(4)
901
+ expected = { add: should, remove: current }
902
+ result = Utils.delta_add_remove(should, current)
903
+ assert_equal(expected, result, 'Test 3. delta mismatch')
904
+
905
+ # Test: Remove the route-maps from the current list. Check delta.
906
+ # Note: The :remove list should be empty since this is just
907
+ # an update of the route-map.
908
+ should = current.map { |prot_only, _route_map| [prot_only] }
909
+ expected = { add: should, remove: [] }
910
+ result = Utils.delta_add_remove(should, current)
911
+ assert_equal(expected, result, 'Test 4. delta mismatch')
912
+
913
+ # Test: Check empty inputs
914
+ should = []
915
+ current = []
916
+ expected = { add: [], remove: [] }
917
+ result = Utils.delta_add_remove(should, current)
918
+ assert_equal(expected, result, 'Test 5. delta mismatch')
919
+ end
920
+ end