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
data/tests/test_vpc.rb CHANGED
@@ -368,10 +368,16 @@ class TestVpc < CiscoTestCase
368
368
  interface_pc.switchport_mode = :trunk
369
369
  refute(interface_pc.vpc_peer_link,
370
370
  'vpc_peer_link should not be set by default')
371
- interface_pc.vpc_peer_link = true
372
- assert(interface_pc.vpc_peer_link, 'vpc_peer_link should be set')
373
- interface_pc.vpc_peer_link = false
374
- refute(interface_pc.vpc_peer_link, 'vpc_peer_link should not be set')
371
+ begin
372
+ # vpc peer-link has linecard limitations
373
+ interface_pc.vpc_peer_link = true
374
+ assert(interface_pc.vpc_peer_link, 'vpc_peer_link should be set')
375
+ interface_pc.vpc_peer_link = false
376
+ refute(interface_pc.vpc_peer_link, 'vpc_peer_link should not be set')
377
+ rescue RuntimeError => e
378
+ raise unless e.message[/Interface needs to be 10G to act as a peer-link/]
379
+ end
380
+
375
381
  # clean up
376
382
  interface.channel_group = false
377
383
  refute(interface.channel_group, 'channel group should be unset')
data/tests/test_vrf.rb CHANGED
@@ -108,6 +108,8 @@ class TestVrf < CiscoTestCase
108
108
  end
109
109
 
110
110
  def test_description
111
+ skip_legacy_defect?('7.3.0.(N1|D1).1.bin',
112
+ 'CSCuy36637: Cannot remove description')
111
113
  v = Vrf.new('test_description')
112
114
  desc = 'tested by minitest'
113
115
  v.description = desc
data/tests/test_vrf_af.rb CHANGED
@@ -111,15 +111,12 @@ class TestVrfAf < CiscoTestCase
111
111
  end
112
112
 
113
113
  def test_route_target
114
+ vdc_limit_f3_no_intf_needed(:set)
114
115
  [%w(ipv4 unicast), %w(ipv6 unicast)].each { |af| route_target(af) }
116
+ vdc_limit_f3_no_intf_needed(:clear)
115
117
  end
116
118
 
117
119
  def route_target(af)
118
- #
119
- # TBD: The evpn parts of this test need to check for compatible linecards to
120
- # skip the evpn portions. Don't use vxlan_linecard? as that will cause all
121
- # tests to be skipped.
122
- #
123
120
  # Common tester for route-target properties. Tests evpn and non-evpn.
124
121
  # route_target_both_auto
125
122
  # route_target_both_auto_evpn
data/tests/test_vtp.rb CHANGED
@@ -87,9 +87,7 @@ class TestVtp < CiscoTestCase
87
87
  assert_raises(ArgumentError) { vtp_domain(nil) }
88
88
  assert_raises(ArgumentError) { vtp_domain('') }
89
89
 
90
- # Create the same domain twice
91
90
  vtp = vtp_domain('accounting')
92
- assert_raises(Cisco::CliError) { vtp_domain('accounting') }
93
91
 
94
92
  # Set password to nil
95
93
  assert_raises(TypeError) { vtp.password = nil }
@@ -176,7 +174,12 @@ class TestVtp < CiscoTestCase
176
174
  end
177
175
  end
178
176
 
177
+ # this fails on n7k running 7.3(0)D1.1 image but it
178
+ # is fixed in later releases. The bugID is CSCuy87970
179
+ # which is already verified.
179
180
  def test_password_special_characters
181
+ skip_legacy_defect?('7.3.0.(N1|D1).1.bin',
182
+ 'CSCuy87970: NXAPI incorrect backslash escape')
180
183
  vtp = vtp_domain('password')
181
184
  vtp.password = 'hello!//\\#%$x'
182
185
  assert_equal('hello!//\\#%$x', vtp.password)
@@ -22,42 +22,39 @@ include Cisco
22
22
  # TestVxlanVtep - Minitest for VxlanVtep node utility
23
23
  class TestVxlanVtep < CiscoTestCase
24
24
  @skip_unless_supported = 'vxlan_vtep'
25
+ @@pre_clean_needed = true # rubocop:disable Style/ClassVars
25
26
 
26
27
  def setup
27
28
  super
28
29
  skip('Platform does not support MT-full or MT-lite') unless
29
30
  VxlanVtep.mt_full_support || VxlanVtep.mt_lite_support
31
+ Interface.interfaces(:nve).each { |_nve, obj| obj.destroy }
32
+ vdc_limit_f3_no_intf_needed(:set)
33
+ feature_cleanup if @@pre_clean_needed
34
+ Feature.nv_overlay_enable
35
+ @@pre_clean_needed = false # rubocop:disable Style/ClassVars
30
36
  end
31
37
 
32
38
  def teardown
33
- Feature.nv_overlay_disable
34
- return unless Vdc.vdc_support
35
- # Reset the vdc module type back to default
36
- v = Vdc.new('default')
37
- v.limit_resource_module_type = '' if v.limit_resource_module_type == 'f3'
38
- end
39
-
40
- def mt_full_env_setup
41
- skip('Platform does not support MT-full') unless VxlanVtep.mt_full_support
42
- vxlan_linecard?
43
- v = Vdc.new('default')
44
- v.limit_resource_module_type = 'f3' unless
45
- v.limit_resource_module_type == 'f3'
46
- Feature.nv_overlay_disable
39
+ if first_or_last_teardown
40
+ vdc_limit_f3_no_intf_needed(:clear)
41
+ feature_cleanup
42
+ end
43
+ super
47
44
  end
48
45
 
49
- def mt_lite_env_setup
50
- skip('Platform does not support MT-lite') unless VxlanVtep.mt_lite_support
51
- vxlan_linecard?
52
- Feature.nv_overlay_disable
53
- config('no feature vn-segment-vlan-based')
46
+ def feature_cleanup
47
+ config_no_warn('no feature-set fabricpath')
48
+ config_no_warn('no feature vni')
49
+ config_no_warn('no feature vn-segment-vlan-based')
50
+ config_no_warn('no nv overlay evpn ; no feature nv overlay')
51
+ # Rapid nv feature toggle can cause failures on some platforms;
52
+ # symptom e.g. 'show runn | i ^feature' will hang
53
+ sleep 5
54
54
  end
55
55
 
56
56
  def test_create_destroy_one
57
57
  # VxlanVtep.new() will enable 'feature nv overlay'
58
- mt_full_env_setup if VxlanVtep.mt_full_support
59
- mt_lite_env_setup if VxlanVtep.mt_lite_support
60
-
61
58
  id = 'nve1'
62
59
  vtep = VxlanVtep.new(id)
63
60
  @default_show_command = "show running | i 'interface #{id}'"
@@ -74,11 +71,7 @@ class TestVxlanVtep < CiscoTestCase
74
71
  end
75
72
 
76
73
  def test_mt_full_create_destroy_multiple
77
- if VxlanVtep.mt_full_support
78
- mt_full_env_setup
79
- else
80
- skip('Platform does not support MT-full')
81
- end
74
+ skip('Platform does not support MT-full') unless VxlanVtep.mt_full_support
82
75
 
83
76
  id1 = 'nve1'
84
77
  id2 = 'nve2'
@@ -110,14 +103,11 @@ class TestVxlanVtep < CiscoTestCase
110
103
 
111
104
  def test_create_negative
112
105
  # MT-lite supports a single nve int, MT-full supports 4.
113
- mt_full_env_setup if VxlanVtep.mt_full_support
114
- mt_lite_env_setup if VxlanVtep.mt_lite_support
115
106
  if VxlanVtep.mt_lite_support
116
107
  VxlanVtep.new('nve1')
117
108
  negative_id = 'nve2'
118
109
 
119
110
  elsif VxlanVtep.mt_full_support
120
- mt_full_env_setup
121
111
  (1..4).each { |n| VxlanVtep.new("nve#{n}") }
122
112
  negative_id = 'nve5'
123
113
  end
@@ -128,9 +118,6 @@ class TestVxlanVtep < CiscoTestCase
128
118
  end
129
119
 
130
120
  def test_description
131
- mt_full_env_setup if VxlanVtep.mt_full_support
132
- mt_lite_env_setup if VxlanVtep.mt_lite_support
133
-
134
121
  vtep = VxlanVtep.new('nve1')
135
122
 
136
123
  # Set description to non-default value and verify
@@ -147,8 +134,6 @@ class TestVxlanVtep < CiscoTestCase
147
134
  def test_host_reachability
148
135
  skip("Test not supported on #{node.product_id}") if
149
136
  cmd_ref.lookup('vxlan_vtep', 'host_reachability').default_value.nil?
150
- mt_full_env_setup if VxlanVtep.mt_full_support
151
- mt_lite_env_setup if VxlanVtep.mt_lite_support
152
137
 
153
138
  vtep = VxlanVtep.new('nve1')
154
139
 
@@ -163,9 +148,6 @@ class TestVxlanVtep < CiscoTestCase
163
148
  end
164
149
 
165
150
  def test_shutdown
166
- mt_full_env_setup if VxlanVtep.mt_full_support
167
- mt_lite_env_setup if VxlanVtep.mt_lite_support
168
-
169
151
  vtep = VxlanVtep.new('nve1')
170
152
 
171
153
  vtep.shutdown = true
@@ -179,9 +161,6 @@ class TestVxlanVtep < CiscoTestCase
179
161
  end
180
162
 
181
163
  def test_source_interface
182
- mt_full_env_setup if VxlanVtep.mt_full_support
183
- mt_lite_env_setup if VxlanVtep.mt_lite_support
184
-
185
164
  vtep = VxlanVtep.new('nve1')
186
165
 
187
166
  # Set source_interface to non-default value
@@ -204,9 +183,6 @@ class TestVxlanVtep < CiscoTestCase
204
183
  end
205
184
 
206
185
  def test_source_interface_hold_down_time
207
- mt_full_env_setup if VxlanVtep.mt_full_support
208
- mt_lite_env_setup if VxlanVtep.mt_lite_support
209
-
210
186
  vtep = VxlanVtep.new('nve1')
211
187
  if validate_property_excluded?('vxlan_vtep', 'source_intf_hold_down_time')
212
188
  assert_nil(vtep.source_interface_hold_down_time)
@@ -25,31 +25,32 @@ class TestVxlanVtepVni < CiscoTestCase
25
25
 
26
26
  def setup
27
27
  super
28
- return unless @@pre_clean_needed
29
- # Disable features on initial cleanup only as it's too expensive
30
- # to do a disable for every testcase.
31
- Feature.nv_overlay_disable
32
- # nv overlay is slow on some platforms
33
- sleep 1
34
- vxlan_linecard?
35
- if VxlanVtep.mt_full_support
36
- return unless Vdc.vdc_support
37
- v = Vdc.new('default')
38
- v.limit_resource_module_type = 'f3' unless
39
- v.limit_resource_module_type == 'f3'
40
- else
41
- config_no_warn('no feature vn-segment-vlan-based')
42
- end
28
+ vdc_limit_f3_no_intf_needed(:set) if VxlanVtep.mt_full_support
29
+ Interface.interfaces(:nve).each { |_nve, obj| obj.destroy }
30
+ feature_cleanup if @@pre_clean_needed
43
31
  Feature.nv_overlay_enable
44
32
  config_no_warn('feature vn-segment-vlan-based') if VxlanVtep.mt_lite_support
45
33
  @@pre_clean_needed = false # rubocop:disable Style/ClassVars
46
34
  end
47
35
 
48
36
  def teardown
49
- config_no_warn('no interface nve1')
37
+ if first_or_last_teardown
38
+ vdc_limit_f3_no_intf_needed(:clear)
39
+ feature_cleanup
40
+ end
50
41
  super
51
42
  end
52
43
 
44
+ def feature_cleanup
45
+ config_no_warn('no feature-set fabricpath')
46
+ config_no_warn('no feature vni')
47
+ config_no_warn('no feature vn-segment-vlan-based')
48
+ config_no_warn('no nv overlay evpn ; no feature nv overlay')
49
+ # Rapid nv feature toggle can cause failures on some platforms;
50
+ # symptom e.g. 'show runn | i ^feature' will hang
51
+ sleep 5
52
+ end
53
+
53
54
  def test_create_with_existing
54
55
  VxlanVtep.new('nve1').host_reachability = 'evpn'
55
56
  associate_vrf = true
@@ -110,6 +111,9 @@ class TestVxlanVtepVni < CiscoTestCase
110
111
  end
111
112
 
112
113
  def test_ingress_replication
114
+ skip_legacy_defect?('7.0.3.I3.1',
115
+ 'CSCuy27700: Validation failed for vni mcast group configured')
116
+
113
117
  vni = VxlanVtepVni.new('nve1', '5000')
114
118
  if validate_property_excluded?('vxlan_vtep_vni', 'ingress_replication')
115
119
  assert_raises(Cisco::UnsupportedError) { vni.ingress_replication = 'bgp' }
@@ -138,6 +142,9 @@ class TestVxlanVtepVni < CiscoTestCase
138
142
  end
139
143
 
140
144
  def test_multicast_group
145
+ skip_legacy_defect?('7.0.3.I3.1',
146
+ 'CSCuy27700: Validation failed for vni mcast group configured')
147
+
141
148
  vni1 = VxlanVtepVni.new('nve1', '6000')
142
149
  vni2 = VxlanVtepVni.new('nve1', '8001-8200')
143
150
 
@@ -0,0 +1,369 @@
1
+ #!/usr/bin/env ruby
2
+ # Yang Unit Tests
3
+ #
4
+ # Charles Burkett, May, 2016
5
+ #
6
+ # Copyright (c) 2015-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_relative 'ciscotest'
21
+ require_relative '../lib/cisco_node_utils/yang'
22
+
23
+ # TestYang - Minitest for Yang class
24
+ class TestYang < CiscoTestCase
25
+ BLUE_VRF = '{"Cisco-IOS-XR-infra-rsi-cfg:vrfs":{
26
+ "vrf":[
27
+ {
28
+ "vrf-name":"BLUE",
29
+ "description":"Generic external traffic",
30
+ "create":[
31
+ null
32
+ ]
33
+ }
34
+ ]
35
+ }}'
36
+
37
+ RED_VRF = '{"Cisco-IOS-XR-infra-rsi-cfg:vrfs":{
38
+ "vrf":[
39
+ {
40
+ "vrf-name":"RED",
41
+ "create":[
42
+ null
43
+ ]
44
+ }
45
+ ]
46
+ }}'
47
+
48
+ GREEN_VRF = '{"Cisco-IOS-XR-infra-rsi-cfg:vrfs":{
49
+ "vrf":[
50
+ {
51
+ "vrf-name":"GREEN",
52
+ "create": [null]
53
+ }
54
+ ]
55
+ }}'
56
+
57
+ BLUE_GREEN_VRF = '{"Cisco-IOS-XR-infra-rsi-cfg:vrfs":{
58
+ "vrf":[
59
+ {
60
+ "vrf-name":"BLUE",
61
+ "create":[null],
62
+ "description":"Generic external traffic"
63
+ },
64
+ {
65
+ "vrf-name":"GREEN",
66
+ "create":[null]
67
+ }
68
+ ]
69
+ }}'
70
+
71
+ BLUE_VRF_NO_PROPERTIES = '{"Cisco-IOS-XR-infra-rsi-cfg:vrfs":{
72
+ "vrf":[
73
+ {
74
+ "vrf-name":"BLUE",
75
+ "create":[
76
+ null
77
+ ]
78
+ }
79
+ ]
80
+ }}'
81
+
82
+ BLUE_VRF_PROPERTIES1 = '{"Cisco-IOS-XR-infra-rsi-cfg:vrfs":{
83
+ "vrf":[
84
+ {
85
+ "vrf-name":"BLUE",
86
+ "create":[
87
+ null
88
+ ],
89
+ "vpn-id":{
90
+ "vpn-oui":0,
91
+ "vpn-index":0
92
+ }
93
+ }
94
+ ]
95
+ }}'
96
+
97
+ BLUE_VRF_PROPERTIES2 = '{"Cisco-IOS-XR-infra-rsi-cfg:vrfs":{
98
+ "vrf":[
99
+ {
100
+ "vrf-name":"BLUE",
101
+ "description":"Generic external traffic",
102
+ "create":[
103
+ null
104
+ ],
105
+ "vpn-id":{
106
+ "vpn-oui":0,
107
+ "vpn-index":0
108
+ }
109
+ }
110
+ ]
111
+ }}'
112
+
113
+ BLUE_VRF_PROPERTIES3 = '{"Cisco-IOS-XR-infra-rsi-cfg:vrfs":{
114
+ "vrf":[
115
+ {
116
+ "vrf-name":"BLUE",
117
+ "description":"Generic ext traffic",
118
+ "create":[
119
+ null
120
+ ],
121
+ "vpn-id":{
122
+ "vpn-oui":8,
123
+ "vpn-index":9
124
+ }
125
+ }
126
+ ]
127
+ }}'
128
+
129
+ NO_VRFS = '{"Cisco-IOS-XR-infra-rsi-cfg:vrfs": [null]}'
130
+ PATH_VRFS = '{"Cisco-IOS-XR-infra-rsi-cfg:vrfs": [null]}'
131
+
132
+ def self.runnable_methods
133
+ return [:all_skipped] unless platform == :ios_xr
134
+ super
135
+ end
136
+
137
+ def all_skipped
138
+ puts 'Node under test does not appear to use the gRPC client'
139
+ assert(validate_property_excluded?('yang', 'support'))
140
+ end
141
+
142
+ def setup
143
+ super
144
+ clear_vrfs
145
+ end
146
+
147
+ def teardown
148
+ super
149
+ clear_vrfs
150
+ end
151
+
152
+ def clear_vrfs
153
+ return unless platform == :ios_xr
154
+ current_vrfs = node.get_yang(PATH_VRFS)
155
+
156
+ # remove all vrfs
157
+ node.delete_yang(PATH_VRFS) unless Yang.empty?(current_vrfs)
158
+ end
159
+
160
+ def test_delete_vrfs
161
+ node.merge_yang(BLUE_VRF) # ensure at least one VRF is there
162
+ assert(node.get_yang(PATH_VRFS).match('BLUE'), 'Did not find the BLUE vrf')
163
+
164
+ clear_vrfs
165
+ assert_equal('', node.get_yang(PATH_VRFS),
166
+ 'There are still vrfs configured')
167
+ end
168
+
169
+ def test_add_vrf
170
+ node.merge_yang(BLUE_VRF) # create a single VRF
171
+ assert(node.get_yang(PATH_VRFS).match('BLUE'), 'Did not find the BLUE vrf')
172
+
173
+ node.replace_yang(GREEN_VRF) # create a single VRF
174
+ assert(node.get_yang(PATH_VRFS).match('GREEN'),
175
+ 'Did not find the GREEN vrf')
176
+ refute(node.get_yang(PATH_VRFS).match('BLUE'),
177
+ 'Found the BLUE vrf')
178
+ end
179
+
180
+ def test_errors
181
+ # Note: Originally, we were checking for YangErrors and ClientErrors,
182
+ # but the type of error raised seemed to change from one XR image to the
183
+ # next, so now we check for the more general CiscoError in these tests.
184
+
185
+ # === test get_yang ===========
186
+
187
+ # Request is not wellformed
188
+ assert_raises(Cisco::CiscoError) { node.get_yang('aabbcc') }
189
+
190
+ # parse error: object key and value must be separated by a colon
191
+ assert_raises(Cisco::CiscoError) { node.get_yang('{"aabbcc"}') }
192
+
193
+ # unknown-namespace
194
+ assert_raises(Cisco::CiscoError) { node.get_yang('{"aabbcc": "foo"}') }
195
+
196
+ # unknown-element
197
+ assert_raises(Cisco::CiscoError) do
198
+ node.get_yang('{"Cisco-IOS-XR-infra-rsi-cfg:aabbcc": "foo"}')
199
+ end
200
+
201
+ # parse error: premature EOF
202
+ assert_raises(Cisco::CiscoError) { node.get_yang('{') }
203
+
204
+ # parse error: invalid object key (must be a string)
205
+ assert_raises(Cisco::CiscoError) { node.get_yang('{: "foo"}') }
206
+
207
+ # === test merge_yang ===========
208
+
209
+ # Request is not wellformed
210
+ assert_raises(Cisco::CiscoError) { node.merge_yang('aabbcc') }
211
+
212
+ # unknown-element
213
+ assert_raises(Cisco::CiscoError) do
214
+ node.merge_yang('{"Cisco-IOS-XR-infra-rsi-cfg:aabbcc": "foo"}')
215
+ end
216
+
217
+ # bad-element
218
+ assert_raises(Cisco::CiscoError) do
219
+ node.merge_yang('{"Cisco-IOS-XR-infra-rsi-cfg:vrfs": "foo"}')
220
+ end
221
+
222
+ # missing-element
223
+ assert_raises(Cisco::CiscoError) do
224
+ node.merge_yang('{"Cisco-IOS-XR-infra-rsi-cfg:vrfs": {"vrf":[{}]}}')
225
+ end
226
+
227
+ # === test replace_yang ===========
228
+
229
+ # unknown-namespace
230
+ assert_raises(Cisco::CiscoError) do
231
+ node.replace_yang('{"Cisco-IOS-XR-infra-rsi-cfg:aabbcc": "foo"}')
232
+ end
233
+
234
+ # Request is not wellformed
235
+ assert_raises(Cisco::CiscoError) do
236
+ node.replace_yang('{"Cisco-IOS-XR-infra-rsi-cfg:vrfs": }')
237
+ end
238
+ end
239
+
240
+ def test_merge_diff
241
+ # ensure we think that a merge is needed (in-sinc = false)
242
+ refute(Yang.insync_for_merge?(BLUE_VRF, node.get_yang(PATH_VRFS)),
243
+ 'Expected not in-sync')
244
+
245
+ node.merge_yang(BLUE_VRF) # create the blue VRF
246
+
247
+ # ensure we think that a merge is NOT needed (in-sinc = true)
248
+ assert(Yang.insync_for_merge?(BLUE_VRF, node.get_yang(PATH_VRFS)),
249
+ 'Expected in-sync')
250
+
251
+ # ensure we think that the merge is needed (in-sinc = false)
252
+ refute(Yang.insync_for_merge?(RED_VRF, node.get_yang(PATH_VRFS)),
253
+ 'Expected not in-sync')
254
+
255
+ node.merge_yang(RED_VRF) # create the red VRF
256
+
257
+ # ensure we think that a merge is NOT needed (in-sinc = true)
258
+ assert(Yang.insync_for_merge?(RED_VRF, node.get_yang(PATH_VRFS)),
259
+ 'Expected in-sync')
260
+
261
+ node.merge_yang(GREEN_VRF) # create green VRF
262
+ # ensure we think that a merge is NOT needed (in-sinc = true)
263
+ assert(Yang.insync_for_merge?(GREEN_VRF, node.get_yang(PATH_VRFS)),
264
+ 'Expected in-sync')
265
+ end
266
+
267
+ def test_replace_diff
268
+ # ensure we think that a merge is needed (in-sinc = false)
269
+ refute(Yang.insync_for_replace?(BLUE_VRF, node.get_yang(PATH_VRFS)),
270
+ 'Expected not in-sync')
271
+
272
+ node.replace_yang(BLUE_VRF) # create the blue VRF
273
+ # ensure we think that a replace is NOT needed (in-sinc = true)
274
+ assert(Yang.insync_for_replace?(BLUE_VRF, node.get_yang(PATH_VRFS)),
275
+ 'Expected in-sync')
276
+
277
+ node.replace_yang(RED_VRF) # create the red VRF
278
+ # ensure we think that a replace is NOT needed (in-sinc = true)
279
+ assert(Yang.insync_for_replace?(RED_VRF, node.get_yang(PATH_VRFS)),
280
+ 'Expected in-sync')
281
+
282
+ node.replace_yang(GREEN_VRF) # create green VRF
283
+ # ensure we think that a replace is NOT needed (in-sinc = true)
284
+ assert(Yang.insync_for_replace?(GREEN_VRF, node.get_yang(PATH_VRFS)),
285
+ 'Expected in-sync')
286
+
287
+ node.merge_yang(BLUE_VRF)
288
+
289
+ # ensure we think that a replace is NOT needed (in-sinc = true)
290
+ assert(Yang.insync_for_replace?(BLUE_GREEN_VRF, node.get_yang(PATH_VRFS)),
291
+ 'Expected in sync')
292
+ # ensure we think that a replace is needed (in-sinc = true)
293
+ refute(Yang.insync_for_replace?(BLUE_VRF, node.get_yang(PATH_VRFS)),
294
+ 'Expected not in sync')
295
+ refute(Yang.insync_for_replace?(GREEN_VRF, node.get_yang(PATH_VRFS)),
296
+ 'Expected not in sync')
297
+
298
+ node.replace_yang(BLUE_VRF)
299
+ # ensure we think that a replace is NOT needed (in-sinc = true)
300
+ assert(Yang.insync_for_replace?(BLUE_VRF, node.get_yang(PATH_VRFS)),
301
+ 'Expected in-sync')
302
+ # ensure we think that a replace is needed (in-sinc = true)
303
+ refute(Yang.insync_for_replace?(GREEN_VRF, node.get_yang(PATH_VRFS)),
304
+ 'Expected not in-sync')
305
+ refute(Yang.insync_for_replace?(BLUE_GREEN_VRF, node.get_yang(PATH_VRFS)),
306
+ 'Expected not in-sync')
307
+ end
308
+
309
+ def test_merge_leaves
310
+ node.merge_yang(BLUE_VRF) # create blue vrf with description
311
+
312
+ # merge blue vrf with vpn id to blue vrf with description
313
+ node.merge_yang(BLUE_VRF_PROPERTIES1)
314
+
315
+ # ensure that new leaves are merged with old.
316
+ assert(Yang.insync_for_merge?(BLUE_VRF_PROPERTIES2,
317
+ node.get_yang(PATH_VRFS)), 'Expected in-sync')
318
+
319
+ # update description and vpn-id
320
+ node.merge_yang(BLUE_VRF_PROPERTIES3)
321
+ assert(Yang.insync_for_merge?(BLUE_VRF_PROPERTIES3,
322
+ node.get_yang(PATH_VRFS)), 'Expected in-sync')
323
+ end
324
+
325
+ def test_replace_leaves
326
+ node.replace_yang(BLUE_VRF) # create blue vrf with description
327
+
328
+ # replace blue vrf (description) by blue vrf (vpn-id)
329
+ node.replace_yang(BLUE_VRF_PROPERTIES1)
330
+
331
+ # ensure that new properties are replaced by old.
332
+ assert(Yang.insync_for_replace?(BLUE_VRF_PROPERTIES1,
333
+ node.get_yang(PATH_VRFS)),
334
+ 'Expected in-sync')
335
+
336
+ # replace description and vpn-id
337
+ node.replace_yang(BLUE_VRF_PROPERTIES3)
338
+ assert(Yang.insync_for_replace?(BLUE_VRF_PROPERTIES3,
339
+ node.get_yang(PATH_VRFS)),
340
+ 'Expected in-sync')
341
+ end
342
+
343
+ def test_merge
344
+ node.merge_yang(BLUE_VRF) # create blue vrf
345
+ node.merge_yang(GREEN_VRF) # create green vrf
346
+
347
+ yang = node.get_yang(PATH_VRFS)
348
+
349
+ assert_yang_equal(BLUE_GREEN_VRF, yang)
350
+ end
351
+
352
+ def test_replace
353
+ node.merge_yang(BLUE_VRF) # create blue vrf
354
+ node.replace_yang(GREEN_VRF) # create green vrf
355
+
356
+ yang = node.get_yang(PATH_VRFS)
357
+
358
+ assert_yang_equal(GREEN_VRF, yang)
359
+ end
360
+
361
+ def assert_yang_equal(expected, actual)
362
+ equal = Yang.insync_for_replace?(expected, actual) &&
363
+ Yang.insync_for_replace?(actual, expected)
364
+ assert(equal,
365
+ "Expected: '#{expected}',\n"\
366
+ "Actual: '#{actual}',\n",
367
+ )
368
+ end
369
+ end