cisco_node_utils 1.2.0 → 1.3.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 (255) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +13 -0
  5. data/.travis.yml +4 -1
  6. data/CHANGELOG.md +81 -2
  7. data/CONTRIBUTING.md +2 -17
  8. data/Gemfile +5 -0
  9. data/README.md +92 -47
  10. data/Rakefile +23 -1
  11. data/bin/git/hooks/hook_lib +7 -0
  12. data/bin/git/hooks/pre-commit/check_unstaged_changes +18 -0
  13. data/bin/git/hooks/pre-commit/rubocop +7 -2
  14. data/bin/git/hooks/pre-commit/validate-diffs +18 -4
  15. data/bin/git/hooks/pre-commit/validate-yaml +18 -0
  16. data/bin/git/update-hooks +64 -6
  17. data/cisco_node_utils.gemspec +9 -6
  18. data/docs/README-develop-best-practices.md +149 -50
  19. data/docs/README-develop-node-utils-APIs.md +92 -42
  20. data/docs/README-maintainers.md +7 -4
  21. data/docs/README-test-execution.md +57 -0
  22. data/docs/cisco_node_utils.yaml.example +30 -0
  23. data/docs/template-router.rb +4 -0
  24. data/ext/mkrf_conf.rb +63 -0
  25. data/lib/.rubocop.yml +2 -2
  26. data/lib/cisco_node_utils.rb +5 -0
  27. data/lib/cisco_node_utils/aaa_authentication_login.rb +5 -6
  28. data/lib/cisco_node_utils/aaa_authorization_service.rb +1 -1
  29. data/lib/cisco_node_utils/ace.rb +165 -12
  30. data/lib/cisco_node_utils/acl.rb +2 -1
  31. data/lib/cisco_node_utils/bgp.rb +184 -21
  32. data/lib/cisco_node_utils/bgp_af.rb +94 -249
  33. data/lib/cisco_node_utils/bgp_neighbor.rb +94 -14
  34. data/lib/cisco_node_utils/bgp_neighbor_af.rb +75 -8
  35. data/lib/cisco_node_utils/bridge_domain.rb +183 -0
  36. data/lib/cisco_node_utils/bridge_domain_vni.rb +206 -0
  37. data/lib/cisco_node_utils/cisco_cmn_utils.rb +85 -2
  38. data/lib/cisco_node_utils/client.rb +35 -0
  39. data/lib/cisco_node_utils/client/client.rb +234 -0
  40. data/lib/cisco_node_utils/client/grpc.rb +33 -0
  41. data/lib/cisco_node_utils/client/grpc/client.rb +311 -0
  42. data/lib/cisco_node_utils/client/grpc/ems.proto +148 -0
  43. data/lib/cisco_node_utils/client/grpc/ems.rb +111 -0
  44. data/lib/cisco_node_utils/client/grpc/ems_services.rb +49 -0
  45. data/lib/cisco_node_utils/client/nxapi.rb +31 -0
  46. data/lib/cisco_node_utils/client/nxapi/client.rb +305 -0
  47. data/lib/cisco_node_utils/client/utils.rb +164 -0
  48. data/lib/cisco_node_utils/cmd_ref/README_YAML.md +222 -254
  49. data/lib/cisco_node_utils/cmd_ref/aaa_auth_login_service.yaml +11 -8
  50. data/lib/cisco_node_utils/cmd_ref/aaa_authentication_login.yaml +22 -15
  51. data/lib/cisco_node_utils/cmd_ref/aaa_authorization_service.yaml +11 -8
  52. data/lib/cisco_node_utils/cmd_ref/acl.yaml +21 -16
  53. data/lib/cisco_node_utils/cmd_ref/bgp.yaml +239 -109
  54. data/lib/cisco_node_utils/cmd_ref/bgp_af.yaml +114 -55
  55. data/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml +76 -52
  56. data/lib/cisco_node_utils/cmd_ref/bgp_neighbor_af.yaml +106 -62
  57. data/lib/cisco_node_utils/cmd_ref/bridge_domain.yaml +71 -0
  58. data/lib/cisco_node_utils/cmd_ref/bridge_domain_vni.yaml +33 -0
  59. data/lib/cisco_node_utils/cmd_ref/dnsclient.yaml +35 -14
  60. data/lib/cisco_node_utils/cmd_ref/encapsulation.yaml +25 -0
  61. data/lib/cisco_node_utils/cmd_ref/evpn_vni.yaml +23 -17
  62. data/lib/cisco_node_utils/cmd_ref/fabricpath.yaml +94 -83
  63. data/lib/cisco_node_utils/cmd_ref/fabricpath_topology.yaml +22 -17
  64. data/lib/cisco_node_utils/cmd_ref/feature.yaml +76 -26
  65. data/lib/cisco_node_utils/cmd_ref/images.yaml +3 -2
  66. data/lib/cisco_node_utils/cmd_ref/interface.yaml +381 -153
  67. data/lib/cisco_node_utils/cmd_ref/interface_channel_group.yaml +21 -11
  68. data/lib/cisco_node_utils/cmd_ref/interface_ospf.yaml +21 -21
  69. data/lib/cisco_node_utils/cmd_ref/interface_portchannel.yaml +30 -21
  70. data/lib/cisco_node_utils/cmd_ref/interface_service_vni.yaml +18 -13
  71. data/lib/cisco_node_utils/cmd_ref/inventory.yaml +26 -31
  72. data/lib/cisco_node_utils/cmd_ref/itd_device_group.yaml +83 -0
  73. data/lib/cisco_node_utils/cmd_ref/itd_service.yaml +119 -0
  74. data/lib/cisco_node_utils/cmd_ref/memory.yaml +17 -6
  75. data/lib/cisco_node_utils/cmd_ref/ntp_config.yaml +10 -3
  76. data/lib/cisco_node_utils/cmd_ref/ntp_server.yaml +17 -5
  77. data/lib/cisco_node_utils/cmd_ref/ospf.yaml +33 -29
  78. data/lib/cisco_node_utils/cmd_ref/overlay_global.yaml +12 -10
  79. data/lib/cisco_node_utils/cmd_ref/pim.yaml +16 -19
  80. data/lib/cisco_node_utils/cmd_ref/portchannel_global.yaml +40 -25
  81. data/lib/cisco_node_utils/cmd_ref/radius_global.yaml +17 -12
  82. data/lib/cisco_node_utils/cmd_ref/radius_server.yaml +71 -35
  83. data/lib/cisco_node_utils/cmd_ref/radius_server_group.yaml +10 -5
  84. data/lib/cisco_node_utils/cmd_ref/show_system.yaml +6 -2
  85. data/lib/cisco_node_utils/cmd_ref/show_version.yaml +47 -43
  86. data/lib/cisco_node_utils/cmd_ref/snmp_community.yaml +13 -11
  87. data/lib/cisco_node_utils/cmd_ref/snmp_group.yaml +4 -2
  88. data/lib/cisco_node_utils/cmd_ref/snmp_notification_receiver.yaml +23 -21
  89. data/lib/cisco_node_utils/cmd_ref/snmp_server.yaml +26 -22
  90. data/lib/cisco_node_utils/cmd_ref/snmp_user.yaml +19 -17
  91. data/lib/cisco_node_utils/cmd_ref/snmpnotification.yaml +18 -6
  92. data/lib/cisco_node_utils/cmd_ref/stp_global.yaml +234 -0
  93. data/lib/cisco_node_utils/cmd_ref/syslog_server.yaml +24 -9
  94. data/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml +5 -3
  95. data/lib/cisco_node_utils/cmd_ref/system.yaml +4 -3
  96. data/lib/cisco_node_utils/cmd_ref/tacacs_server.yaml +22 -20
  97. data/lib/cisco_node_utils/cmd_ref/tacacs_server_group.yaml +27 -15
  98. data/lib/cisco_node_utils/cmd_ref/tacacs_server_host.yaml +45 -16
  99. data/lib/cisco_node_utils/cmd_ref/vdc.yaml +21 -11
  100. data/lib/cisco_node_utils/cmd_ref/virtual_service.yaml +3 -2
  101. data/lib/cisco_node_utils/cmd_ref/vlan.yaml +60 -32
  102. data/lib/cisco_node_utils/cmd_ref/vpc.yaml +118 -101
  103. data/lib/cisco_node_utils/cmd_ref/vrf.yaml +54 -58
  104. data/lib/cisco_node_utils/cmd_ref/vrf_af.yaml +118 -0
  105. data/lib/cisco_node_utils/cmd_ref/vtp.yaml +19 -25
  106. data/lib/cisco_node_utils/cmd_ref/vxlan_vtep.yaml +28 -18
  107. data/lib/cisco_node_utils/cmd_ref/vxlan_vtep_vni.yaml +34 -17
  108. data/lib/cisco_node_utils/cmd_ref/yum.yaml +6 -4
  109. data/lib/cisco_node_utils/command_reference.rb +261 -142
  110. data/lib/cisco_node_utils/constants.rb +33 -0
  111. data/lib/cisco_node_utils/encapsulation.rb +112 -0
  112. data/lib/cisco_node_utils/environment.rb +102 -0
  113. data/lib/cisco_node_utils/evpn_vni.rb +5 -3
  114. data/lib/cisco_node_utils/exceptions.rb +111 -0
  115. data/lib/cisco_node_utils/fabricpath_global.rb +52 -35
  116. data/lib/cisco_node_utils/fabricpath_topology.rb +44 -57
  117. data/lib/cisco_node_utils/feature.rb +165 -3
  118. data/lib/cisco_node_utils/interface.rb +1051 -260
  119. data/lib/cisco_node_utils/interface_channel_group.rb +11 -10
  120. data/lib/cisco_node_utils/interface_ospf.rb +1 -2
  121. data/lib/cisco_node_utils/interface_portchannel.rb +4 -12
  122. data/lib/cisco_node_utils/interface_service_vni.rb +7 -7
  123. data/lib/cisco_node_utils/itd_device_group.rb +248 -0
  124. data/lib/cisco_node_utils/itd_device_group_node.rb +144 -0
  125. data/lib/cisco_node_utils/itd_service.rb +523 -0
  126. data/lib/cisco_node_utils/logger.rb +75 -0
  127. data/lib/cisco_node_utils/node.rb +62 -192
  128. data/lib/cisco_node_utils/node_util.rb +56 -10
  129. data/lib/cisco_node_utils/overlay_global.rb +2 -2
  130. data/lib/cisco_node_utils/pim.rb +2 -13
  131. data/lib/cisco_node_utils/pim_group_list.rb +1 -1
  132. data/lib/cisco_node_utils/pim_rp_address.rb +1 -1
  133. data/lib/cisco_node_utils/platform.rb +52 -21
  134. data/lib/cisco_node_utils/portchannel_global.rb +89 -19
  135. data/lib/cisco_node_utils/radius_server.rb +168 -37
  136. data/lib/cisco_node_utils/router_ospf.rb +20 -35
  137. data/lib/cisco_node_utils/router_ospf_vrf.rb +4 -4
  138. data/lib/cisco_node_utils/snmpserver.rb +1 -6
  139. data/lib/cisco_node_utils/snmpuser.rb +6 -4
  140. data/lib/cisco_node_utils/stp_global.rb +676 -0
  141. data/lib/cisco_node_utils/syslog_server.rb +77 -18
  142. data/lib/cisco_node_utils/syslog_settings.rb +1 -1
  143. data/lib/cisco_node_utils/tacacs_server_group.rb +8 -4
  144. data/lib/cisco_node_utils/tacacs_server_host.rb +115 -25
  145. data/lib/cisco_node_utils/vdc.rb +12 -0
  146. data/lib/cisco_node_utils/version.rb +1 -1
  147. data/lib/cisco_node_utils/vlan.rb +147 -29
  148. data/lib/cisco_node_utils/vpc.rb +55 -3
  149. data/lib/cisco_node_utils/vrf.rb +72 -11
  150. data/lib/cisco_node_utils/vrf_af.rb +114 -29
  151. data/lib/cisco_node_utils/vtp.rb +34 -52
  152. data/lib/cisco_node_utils/vxlan_vtep.rb +34 -8
  153. data/lib/cisco_node_utils/vxlan_vtep_vni.rb +36 -4
  154. data/lib/minitest/environment_plugin.rb +31 -0
  155. data/lib/minitest/log_level_plugin.rb +41 -0
  156. data/spec/client_spec.rb +7 -0
  157. data/spec/environment_spec.rb +263 -0
  158. data/spec/grpc_client_spec.rb +23 -0
  159. data/spec/isolate/all_clients_spec.rb +9 -0
  160. data/spec/isolate/grpc_only_spec.rb +16 -0
  161. data/spec/isolate/no_clients_spec.rb +26 -0
  162. data/spec/isolate/nxapi_only_spec.rb +16 -0
  163. data/spec/nxapi_client_spec.rb +42 -0
  164. data/spec/schema.yaml +75 -0
  165. data/spec/shared_examples_for_clients.rb +14 -0
  166. data/spec/spec_helper.rb +91 -0
  167. data/spec/whitespace_spec.rb +10 -0
  168. data/spec/yaml_spec.rb +42 -0
  169. data/tests/.rubocop.yml +2 -2
  170. data/tests/CSCuxdublin-1.0.0-7.0.3.I3.1.lib32_n9000.rpm +0 -0
  171. data/tests/basetest.rb +96 -36
  172. data/tests/ciscotest.rb +220 -12
  173. data/tests/cmd_config.yaml +71 -49
  174. data/tests/cmd_config_invalid.yaml +1 -1
  175. data/tests/test_aaa_authentication_login.rb +1 -0
  176. data/tests/test_aaa_authentication_login_service.rb +9 -0
  177. data/tests/test_aaa_authorization_service.rb +173 -367
  178. data/tests/test_ace.rb +171 -100
  179. data/tests/test_acl.rb +10 -1
  180. data/tests/test_bgp_af.rb +395 -728
  181. data/tests/test_bgp_neighbor.rb +274 -115
  182. data/tests/test_bgp_neighbor_af.rb +178 -77
  183. data/tests/test_bridge_domain.rb +191 -0
  184. data/tests/test_bridge_domain_vni.rb +116 -0
  185. data/tests/test_client_utils.rb +111 -0
  186. data/tests/test_command_config.rb +9 -5
  187. data/tests/test_command_reference.rb +380 -102
  188. data/tests/test_dns_domain.rb +13 -3
  189. data/tests/test_domain_name.rb +13 -3
  190. data/tests/test_encapsulation.rb +77 -0
  191. data/tests/test_evpn_vni.rb +25 -7
  192. data/tests/test_fabricpath_global.rb +167 -163
  193. data/tests/test_fabricpath_topology.rb +12 -33
  194. data/tests/test_feature.rb +215 -0
  195. data/tests/test_grpc.rb +166 -0
  196. data/tests/test_interface.rb +585 -344
  197. data/tests/test_interface_bdi.rb +80 -0
  198. data/tests/test_interface_channel_group.rb +6 -3
  199. data/tests/test_interface_ospf.rb +26 -24
  200. data/tests/test_interface_portchannel.rb +1 -0
  201. data/tests/test_interface_private_vlan.rb +724 -0
  202. data/tests/test_interface_service_vni.rb +37 -66
  203. data/tests/test_interface_svi.rb +98 -101
  204. data/tests/test_interface_switchport.rb +419 -549
  205. data/tests/test_itd_device_group.rb +145 -0
  206. data/tests/test_itd_device_group_node.rb +199 -0
  207. data/tests/test_itd_service.rb +298 -0
  208. data/tests/test_logger.rb +43 -0
  209. data/tests/test_name_server.rb +11 -2
  210. data/tests/test_node.rb +16 -75
  211. data/tests/test_node_ext.rb +174 -163
  212. data/tests/test_node_util.rb +119 -0
  213. data/tests/test_ntp_config.rb +5 -1
  214. data/tests/test_ntp_server.rb +2 -2
  215. data/tests/test_nxapi.rb +221 -0
  216. data/tests/test_overlay_global.rb +47 -38
  217. data/tests/test_pim.rb +2 -0
  218. data/tests/test_pim_group_list.rb +2 -0
  219. data/tests/test_pim_rp_address.rb +2 -0
  220. data/tests/test_platform.rb +86 -39
  221. data/tests/test_portchannel_global.rb +211 -135
  222. data/tests/test_radius_global.rb +13 -5
  223. data/tests/test_radius_server.rb +256 -104
  224. data/tests/test_radius_server_group.rb +2 -0
  225. data/tests/test_router_bgp.rb +781 -485
  226. data/tests/test_router_ospf.rb +26 -103
  227. data/tests/test_router_ospf_vrf.rb +52 -57
  228. data/tests/test_snmp_notification_receiver.rb +2 -0
  229. data/tests/test_snmpcommunity.rb +2 -0
  230. data/tests/test_snmpgroup.rb +2 -0
  231. data/tests/test_snmpnotification.rb +40 -21
  232. data/tests/test_snmpserver.rb +2 -0
  233. data/tests/test_snmpuser.rb +2 -0
  234. data/tests/test_stp_global.rb +563 -0
  235. data/tests/test_syslog_server.rb +32 -8
  236. data/tests/test_syslog_settings.rb +22 -9
  237. data/tests/test_tacacs_server.rb +32 -27
  238. data/tests/test_tacacs_server_group.rb +100 -45
  239. data/tests/test_tacacs_server_host.rb +135 -43
  240. data/tests/test_vdc.rb +2 -16
  241. data/tests/test_vlan.rb +106 -54
  242. data/tests/test_vlan_mt_full.rb +11 -21
  243. data/tests/test_vlan_private.rb +669 -0
  244. data/tests/test_vpc.rb +312 -159
  245. data/tests/test_vrf.rb +122 -113
  246. data/tests/test_vrf_af.rb +238 -0
  247. data/tests/test_vtp.rb +58 -102
  248. data/tests/test_vxlan_vtep.rb +38 -17
  249. data/tests/test_vxlan_vtep_vni.rb +61 -9
  250. data/tests/test_yum.rb +49 -25
  251. metadata +122 -36
  252. data/lib/cisco_node_utils/cmd_ref/fex.yaml +0 -9
  253. data/lib/cisco_node_utils/cmd_ref/vni.yaml +0 -76
  254. data/lib/cisco_node_utils/vni.rb +0 -227
  255. data/tests/test_vni.rb +0 -106
@@ -0,0 +1,23 @@
1
+ require_relative 'spec_helper.rb'
2
+ require 'shared_examples_for_clients'
3
+ require 'cisco_node_utils/client/grpc'
4
+
5
+ describe Cisco::Client::GRPC do
6
+ it_behaves_like 'all clients'
7
+
8
+ describe '.validate_args' do
9
+ it 'rejects nil username' do
10
+ kwargs = { host: '1.1.1.1', username: nil, password: 'bye' }
11
+ expect { described_class.validate_args(**kwargs) }.to \
12
+ raise_error(TypeError,
13
+ 'gRPC client creation failure: username must be specified')
14
+ end
15
+
16
+ it 'rejects nil password' do
17
+ kwargs = { host: '1.1.1.1', username: 'hi', password: nil }
18
+ expect { described_class.validate_args(**kwargs) }.to \
19
+ raise_error(TypeError,
20
+ 'gRPC client creation failure: password must be specified')
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,9 @@
1
+ require_relative '../spec_helper.rb'
2
+
3
+ context 'when both clients are installed' do
4
+ it 'should have both clients' do
5
+ require 'cisco_node_utils'
6
+ expect(Cisco::Client.clients).to eql [Cisco::Client::NXAPI,
7
+ Cisco::Client::GRPC]
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ require_relative '../spec_helper.rb'
2
+
3
+ context 'when only gRPC client is installed' do
4
+ let(:main_self) { TOPLEVEL_BINDING.eval('self') }
5
+ before(:example) do
6
+ allow(main_self).to receive(:require).and_wrap_original do |orig, pkg|
7
+ fail LoadError, pkg if pkg['cisco_node_utils/client/nxapi']
8
+ orig.call(pkg)
9
+ end
10
+ end
11
+
12
+ it 'should have gRPC client' do
13
+ require 'cisco_node_utils'
14
+ expect(Cisco::Client.clients).to eql [Cisco::Client::GRPC]
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ require_relative '../spec_helper.rb'
2
+ require 'rspec/core'
3
+
4
+ context 'when no client implementations are installed' do
5
+ let(:main_self) { TOPLEVEL_BINDING.eval('self') }
6
+
7
+ before(:example) do
8
+ allow(main_self).to receive(:require).and_wrap_original do |orig, pkg|
9
+ fail LoadError, pkg if pkg['client/nxapi']
10
+ fail LoadError, pkg if pkg['client/grpc']
11
+ orig.call(pkg)
12
+ end
13
+ end
14
+
15
+ it 'should not have any clients' do
16
+ require 'cisco_node_utils'
17
+ expect(Cisco::Client.clients).to eql []
18
+ end
19
+
20
+ it 'should fail Client.create' do
21
+ require 'cisco_node_utils'
22
+ expect { Cisco::Client.create }.to \
23
+ raise_error(RuntimeError, 'No client implementations available!')
24
+ end
25
+ # TODO
26
+ end
@@ -0,0 +1,16 @@
1
+ require_relative '../spec_helper.rb'
2
+
3
+ context 'when only NXAPI client is installed' do
4
+ let(:main_self) { TOPLEVEL_BINDING.eval('self') }
5
+ before(:example) do
6
+ allow(main_self).to receive(:require).and_wrap_original do |orig, pkg|
7
+ fail LoadError, pkg if pkg['cisco_node_utils/client/grpc']
8
+ orig.call(pkg)
9
+ end
10
+ end
11
+
12
+ it 'should have NXAPI client' do
13
+ require 'cisco_node_utils/client'
14
+ expect(Cisco::Client.clients).to eql [Cisco::Client::NXAPI]
15
+ end
16
+ end
@@ -0,0 +1,42 @@
1
+ require_relative 'spec_helper.rb'
2
+ require 'shared_examples_for_clients'
3
+ require 'cisco_node_utils/client/nxapi'
4
+
5
+ describe Cisco::Client::NXAPI do
6
+ it_behaves_like 'all clients'
7
+
8
+ describe '.validate_args' do
9
+ it 'accepts nil host, username, and password together' do
10
+ described_class.validate_args
11
+ end
12
+
13
+ it 'rejects the combination of nil host with non-nil username' do
14
+ kwargs = { host: nil, username: 'hi', password: nil }
15
+ expect { described_class.validate_args(**kwargs) }.to \
16
+ raise_error(ArgumentError)
17
+ end
18
+
19
+ it 'rejects the combination of nil host with non-nil password' do
20
+ kwargs = { host: nil, username: nil, password: 'bye' }
21
+ expect { described_class.validate_args(**kwargs) }.to \
22
+ raise_error(ArgumentError)
23
+ end
24
+
25
+ it 'accepts a host with username and password' do
26
+ kwargs = { host: '1.1.1.1', username: 'hi', password: 'bye' }
27
+ described_class.validate_args(**kwargs)
28
+ end
29
+
30
+ it 'rejects a host with nil username' do
31
+ kwargs = { host: '1.1.1.1', username: nil, password: 'bye' }
32
+ expect { described_class.validate_args(**kwargs) }.to \
33
+ raise_error(TypeError, 'username is required')
34
+ end
35
+
36
+ it 'rejects a host with nil password' do
37
+ kwargs = { host: '1.1.1.1', username: 'hi', password: nil }
38
+ expect { described_class.validate_args(**kwargs) }.to \
39
+ raise_error(TypeError, 'password is required')
40
+ end
41
+ end
42
+ end
data/spec/schema.yaml ADDED
@@ -0,0 +1,75 @@
1
+ # Kwalify schema for cmd_ref YAML files
2
+
3
+ type: map
4
+ mapping:
5
+ # List of cases to specifically exclude
6
+ _exclude: &exclude
7
+ type: seq
8
+ sequence:
9
+ - type: str
10
+ enum: &filters # Things we can filter by
11
+ # Platform classes
12
+ - 'ios_xr'
13
+ - 'nexus'
14
+ # Product IDs
15
+ - 'C3064'
16
+ - 'C3132'
17
+ - 'C3172'
18
+ - 'N3k'
19
+ - 'N5k'
20
+ - 'N6k'
21
+ - 'N7k'
22
+ - 'N8k'
23
+ - 'N9k'
24
+
25
+ =: &base # default rule - apply to all properties
26
+ type: map
27
+ mapping:
28
+ _exclude: *exclude
29
+ # Platform and product filters
30
+ ios_xr: *base
31
+ nexus: *base
32
+ C3064: *base
33
+ C3132: *base
34
+ C3172: *base
35
+ N3k: *base
36
+ N5k: *base
37
+ N6k: *base
38
+ N7k: *base
39
+ N8k: *base
40
+ N9k: *base
41
+ # 'else' case if not matching any filter above
42
+ else: *base
43
+ # Generally applicable attributes
44
+ data_format: &data_format
45
+ type: str
46
+ enum: [cli, nxapi_structured]
47
+ context: &context
48
+ type: seq
49
+ sequence:
50
+ - type: str
51
+ value:
52
+ type: str
53
+ default_only:
54
+ type: any
55
+ # Getter-specific attributes
56
+ auto_default:
57
+ type: bool
58
+ default_value:
59
+ type: any
60
+ get_command:
61
+ type: str
62
+ get_data_format: *data_format
63
+ get_context: *context
64
+ get_value:
65
+ type: str
66
+ kind:
67
+ type: str
68
+ enum: [boolean, int, string, symbol]
69
+ multiple:
70
+ type: bool
71
+ # Setter-specific attributes
72
+ set_data_format: *data_format
73
+ set_context: *context
74
+ set_value:
75
+ type: str
@@ -0,0 +1,14 @@
1
+ shared_examples_for 'all clients' do
2
+ describe '.validate_args' do
3
+ %i(host username password).each do |sym|
4
+ it "rejects non-String #{sym}" do
5
+ expect { described_class.validate_args(sym => 12) }.to \
6
+ raise_error(TypeError)
7
+ end
8
+ it "rejects empty #{sym}" do
9
+ expect { described_class.validate_args(sym => '') }.to \
10
+ raise_error(ArgumentError)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,91 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # The `.rspec` file also contains a few flags that are not defaults but that
16
+ # users commonly want.
17
+ #
18
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
19
+ RSpec.configure do |config|
20
+ # rspec-expectations config goes here. You can use an alternate
21
+ # assertion/expectation library such as wrong or the stdlib/minitest
22
+ # assertions if you prefer.
23
+ config.expect_with :rspec do |expectations|
24
+ # This option will default to `true` in RSpec 4. It makes the `description`
25
+ # and `failure_message` of custom matchers include text for helper methods
26
+ # defined using `chain`, e.g.:
27
+ # be_bigger_than(2).and_smaller_than(4).description
28
+ # # => "be bigger than 2 and smaller than 4"
29
+ # ...rather than:
30
+ # # => "be bigger than 2"
31
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
32
+ end
33
+
34
+ # rspec-mocks config goes here. You can use an alternate test double
35
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
36
+ config.mock_with :rspec do |mocks|
37
+ # Prevents you from mocking or stubbing a method that does not exist on
38
+ # a real object. This is generally recommended, and will default to
39
+ # `true` in RSpec 4.
40
+ mocks.verify_partial_doubles = true
41
+ end
42
+
43
+ # The settings below are suggested to provide a good initial experience
44
+ # with RSpec, but feel free to customize to your heart's content.
45
+ # rubocop:disable Style/BlockComments
46
+ =begin
47
+ # These two settings work together to allow you to limit a spec run
48
+ # to individual examples or groups you care about by tagging them with
49
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
50
+ # get run.
51
+ config.filter_run :focus
52
+ config.run_all_when_everything_filtered = true
53
+ # Allows RSpec to persist some state between runs in order to support
54
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
55
+ # you configure your source control system to ignore this file.
56
+ config.example_status_persistence_file_path = "spec/examples.txt"
57
+ # Limits the available syntax to the non-monkey patched syntax that is
58
+ # recommended. For more details, see:
59
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
60
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
61
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
62
+ config.disable_monkey_patching!
63
+ # This setting enables warnings. It's recommended, but in some cases may
64
+ # be too noisy due to issues in dependencies.
65
+ config.warnings = true
66
+ # Many RSpec users commonly either run the entire suite or an individual
67
+ # file, and it's useful to allow more verbose output when running an
68
+ # individual spec file.
69
+ if config.files_to_run.one?
70
+ # Use the documentation formatter for detailed output,
71
+ # unless a formatter has already been configured
72
+ # (e.g. via a command-line flag).
73
+ config.default_formatter = 'doc'
74
+ end
75
+ # Print the 10 slowest examples and example groups at the
76
+ # end of the spec run, to help surface which specs are running
77
+ # particularly slow.
78
+ config.profile_examples = 10
79
+ # Run specs in random order to surface order dependencies. If you find an
80
+ # order dependency and want to debug it, you can fix the order by providing
81
+ # the seed, which is printed after each run.
82
+ # --seed 1234
83
+ config.order = :random
84
+ # Seed global randomization in this process using the `--seed` CLI option.
85
+ # Setting this allows you to use `--seed` to deterministically reproduce
86
+ # test failures related to randomization by passing the same `--seed` value
87
+ # as the one that triggered the failure.
88
+ Kernel.srand config.seed
89
+ =end
90
+ # rubocop:enable Style:BlockComments
91
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'spec_helper.rb'
2
+
3
+ context 'non-ruby files' do
4
+ # Whitespace in ruby files is managed by Rubocop.
5
+ # Ignore ems.proto as it's a generated file.
6
+ failures = `git grep -n -I '\s$' | grep -v .rb | grep -v ems.proto`
7
+ it 'should have no trailing whitespace' do
8
+ expect(failures).to be_empty, -> { failures }
9
+ end
10
+ end
data/spec/yaml_spec.rb ADDED
@@ -0,0 +1,42 @@
1
+ require_relative 'spec_helper.rb'
2
+ require 'kwalify'
3
+ require 'yaml'
4
+
5
+ files = Dir.glob(__dir__ + '/../lib/cisco_node_utils/cmd_ref/*.yaml')
6
+
7
+ def print_errors(errors)
8
+ str = "Schema validation errors:\n"
9
+ error_str_list = errors.map do |e|
10
+ "line #{e.linenum}, column #{e.column}: [#{e.path}] #{e.message}"
11
+ end
12
+ str + error_str_list.join("\n")
13
+ end
14
+
15
+ # Use the MetaValidator to make sure the schema itself is sane
16
+ metavalidator = Kwalify::MetaValidator.instance
17
+
18
+ schema_file = File.join(__dir__, 'schema.yaml')
19
+
20
+ metaparser = Kwalify::Yaml::Parser.new(metavalidator)
21
+ context 'schema.yaml' do
22
+ it 'should have no schema metavalidation errors' do
23
+ metaparser.parse_file(schema_file)
24
+ errors = metaparser.errors()
25
+ expect(errors).to be_empty, -> { print_errors(errors) }
26
+ end
27
+ end
28
+
29
+ # Then use the Validator to make sure our files comply with the schema
30
+ schema = Kwalify::Yaml.load_file(schema_file)
31
+ validator = Kwalify::Validator.new(schema)
32
+ parser = Kwalify::Yaml::Parser.new(validator)
33
+
34
+ files.each do |file|
35
+ context file.split('/')[-1] do
36
+ it 'should have no schema validation errors' do
37
+ parser.parse_file(file)
38
+ errors = parser.errors()
39
+ expect(errors).to be_empty, -> { print_errors(errors) }
40
+ end
41
+ end
42
+ end
data/tests/.rubocop.yml CHANGED
@@ -3,13 +3,13 @@ inherit_from: ../.rubocop.yml
3
3
  # Code complexity metrics for the tests/ subdirectory
4
4
 
5
5
  Metrics/AbcSize:
6
- Enabled: false
6
+ Max: 158 # ouch!
7
7
 
8
8
  Metrics/CyclomaticComplexity:
9
9
  Max: 15
10
10
 
11
11
  Metrics/MethodLength:
12
- Max: 91
12
+ Max: 100
13
13
 
14
14
  Metrics/PerceivedComplexity:
15
15
  Max: 17
data/tests/basetest.rb CHANGED
@@ -17,6 +17,9 @@
17
17
  # See the License for the specific language governing permissions and
18
18
  # limitations under the License.
19
19
 
20
+ # Minitest needs to have this path in order to discover our logging plugin
21
+ $LOAD_PATH.push File.expand_path('../../lib', __FILE__)
22
+
20
23
  require 'simplecov'
21
24
  SimpleCov.start do
22
25
  # Don't calculate coverage of our test code itself!
@@ -27,7 +30,10 @@ require 'rubygems'
27
30
  gem 'minitest', '~> 5.0'
28
31
  require 'minitest/autorun'
29
32
  require 'net/telnet'
30
- require 'cisco_nxapi'
33
+ require_relative '../lib/cisco_node_utils/client'
34
+ require_relative '../lib/cisco_node_utils/environment'
35
+ require_relative '../lib/cisco_node_utils/command_reference'
36
+ require_relative '../lib/cisco_node_utils/logger'
31
37
 
32
38
  # rubocop:disable Style/ClassVars
33
39
  # We *want* the address/username/password class variables to be shared
@@ -36,22 +42,12 @@ require 'cisco_nxapi'
36
42
  # TestCase - common base class for all minitest cases in this module.
37
43
  # Most node utility tests should inherit from CiscoTestCase instead.
38
44
  class TestCase < Minitest::Test
39
- # These variables can be set in one of three ways:
40
- # 1) ARGV:
41
- # $ ruby basetest.rb -- address username password
42
- # 2) NODE environment variable
43
- # $ export NODE="address username password"
44
- # $ rake test
45
- # 3) At run time:
46
- # $ rake test
47
- # Enter address or hostname of node under test:
48
45
  @@address = nil
49
46
  @@username = nil
50
47
  @@password = nil
51
48
 
52
- def address
53
- @@address ||= ARGV[0]
54
- @@address ||= ENV['NODE'].split(' ')[0] if ENV['NODE']
49
+ def self.address
50
+ @@address ||= Cisco::Environment.environment[:host]
55
51
  unless @@address
56
52
  print 'Enter address or hostname of node under test: '
57
53
  @@address = gets.chomp
@@ -59,9 +55,12 @@ class TestCase < Minitest::Test
59
55
  @@address
60
56
  end
61
57
 
62
- def username
63
- @@username ||= ARGV[1]
64
- @@username ||= ENV['NODE'].split(' ')[1] if ENV['NODE']
58
+ def address
59
+ self.class.address
60
+ end
61
+
62
+ def self.username
63
+ @@username ||= Cisco::Environment.environment[:username]
65
64
  unless @@username
66
65
  print 'Enter username for node under test: '
67
66
  @@username = gets.chomp
@@ -69,9 +68,12 @@ class TestCase < Minitest::Test
69
68
  @@username
70
69
  end
71
70
 
72
- def password
73
- @@password ||= ARGV[2]
74
- @@password ||= ENV['NODE'].split(' ')[2] if ENV['NODE']
71
+ def username
72
+ self.class.username
73
+ end
74
+
75
+ def self.password
76
+ @@password ||= Cisco::Environment.environment[:password]
75
77
  unless @@password
76
78
  print 'Enter password for node under test: '
77
79
  @@password = gets.chomp
@@ -79,38 +81,94 @@ class TestCase < Minitest::Test
79
81
  @@password
80
82
  end
81
83
 
84
+ def password
85
+ self.class.password
86
+ end
87
+
82
88
  def setup
83
- @device = Net::Telnet.new('Host' => address, 'Timeout' => 240)
84
- @device.login(username, password)
85
- CiscoLogger.debug_enable if ARGV[3] == 'debug' || ENV['DEBUG'] == '1'
89
+ # Hack - populate environment from user-entered values from basetest.rb
90
+ if Cisco::Environment.environments.empty?
91
+ class << Cisco::Environment
92
+ attr_writer :environments
93
+ end
94
+ Cisco::Environment.environments['default'] = {
95
+ host: address.split(':')[0],
96
+ port: address.split(':')[1],
97
+ username: username,
98
+ password: password,
99
+ }
100
+ end
101
+ @device = Net::Telnet.new('Host' => address.split(':')[0],
102
+ 'Timeout' => 240,
103
+ # NX-OS has a space after '#', IOS XR does not
104
+ 'Prompt' => /[$%#>] *\z/n,
105
+ )
106
+ begin
107
+ @device.login('Name' => username,
108
+ 'Password' => password,
109
+ # NX-OS uses 'login:' while IOS XR uses 'Username:'
110
+ 'LoginPrompt' => /(?:[Ll]ogin|[Uu]sername)[: ]*\z/n,
111
+ )
112
+ rescue Errno::ECONNRESET
113
+ @device.close
114
+ # TODO
115
+ puts 'Connection reset by peer? Try again'
116
+ sleep 1
117
+ @device = Net::Telnet.new('Host' => address.split(':')[0],
118
+ 'Timeout' => 240,
119
+ # NX-OS has a space after '#', IOS XR does not
120
+ 'Prompt' => /[$%#>] *\z/n,
121
+ )
122
+ @device.login('Name' => username,
123
+ 'Password' => password,
124
+ # NX-OS uses 'login:' while IOS XR uses 'Username:'
125
+ 'LoginPrompt' => /(?:[Ll]ogin|[Uu]sername)[: ]*\z/n,
126
+ )
127
+ end
128
+ @device.cmd('term len 0')
86
129
  rescue Errno::ECONNREFUSED
87
130
  puts 'Telnet login refused - please check that the IP address is correct'
88
- puts " and that you have enabled 'feature telnet' on the UUT"
131
+ puts " and that you have configured 'feature telnet' (NX-OS) or "
132
+ puts " 'telnet ipv4 server...' (IOS XR) on the UUT"
89
133
  exit
90
134
  end
91
135
 
92
136
  def teardown
93
137
  @device.close unless @device.nil?
94
- GC.start
138
+ @device = nil
95
139
  end
96
140
 
97
- # Extend standard Minitest error handling to report UnsupportedError as skip
98
- def capture_exceptions
99
- super do
100
- begin
101
- yield
102
- rescue Cisco::UnsupportedError => e
103
- skip(e.to_s)
104
- end
105
- end
141
+ # Execute the specified config commands and warn if the
142
+ # output matches the default "warning" regex.
143
+ def config(*args)
144
+ config_and_warn_on_match(/^invalid|^%/i, *args)
106
145
  end
107
146
 
108
- def config(*args)
147
+ # Execute the specified config commands. Use this version
148
+ # of the config method if you expect possible config errors
149
+ # and do not wish to log them as a warning.
150
+ def config_no_warn(*args)
151
+ config_and_warn_on_match(nil, *args)
152
+ end
153
+
154
+ # Execute the specified config commands and warn if the
155
+ # ouput matches the specified regex. Specifying nil for
156
+ # warn_match means "do not warn".
157
+ def config_and_warn_on_match(warn_match, *args)
109
158
  # Send the entire config as one string but be sure not to return until
110
159
  # we are safely back out of config mode, i.e. prompt is
111
160
  # 'switch#' not 'switch(config)#' or 'switch(config-if)#' etc.
112
- @device.cmd('String' => "configure terminal\n" + args.join("\n") + "\nend",
113
- 'Match' => /^[^()]+[$%#>] \z/n)
161
+ result = @device.cmd(
162
+ 'String' => "configure terminal\n" + args.join("\n") + "\nend",
163
+ # NX-OS has a space after '#', IOS XR does not
164
+ 'Match' => /^[^()]+[$%#>] *\z/n)
165
+
166
+ if warn_match && warn_match.match(result)
167
+ Cisco::Logger.warn("Config result:\n#{result}")
168
+ else
169
+ Cisco::Logger.debug("Config result:\n#{result}")
170
+ end
171
+ result
114
172
  rescue Net::ReadTimeout => e
115
173
  raise "Timeout when configuring:\n#{args.join("\n")}\n\n#{e}"
116
174
  end
@@ -118,6 +176,7 @@ class TestCase < Minitest::Test
118
176
  def assert_show_match(pattern: nil, command: nil, msg: nil)
119
177
  pattern ||= @default_output_pattern
120
178
  refute_nil(pattern)
179
+ pattern = Cisco::Client.to_regexp(pattern)
121
180
  command ||= @default_show_command
122
181
  refute_nil(command)
123
182
 
@@ -133,6 +192,7 @@ class TestCase < Minitest::Test
133
192
  def refute_show_match(pattern: nil, command: nil, msg: nil)
134
193
  pattern ||= @default_output_pattern
135
194
  refute_nil(pattern)
195
+ pattern = Cisco::Client.to_regexp(pattern)
136
196
  command ||= @default_show_command
137
197
  refute_nil(command)
138
198