cisco_node_utils 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -86,6 +86,13 @@ get_last_version() {
86
86
  }
87
87
  export -f get_last_version
88
88
 
89
+ get_staged_ruby_files() {
90
+ rubocop_target=$(rubocop --list-target-files)
91
+ staged_files=$(git diff --name-only --staged)
92
+ echo $(printf "$rubocop_target $staged_files " | tr ' ' '\n' | sort | uniq -d)
93
+ }
94
+ export -f get_staged_ruby_files
95
+
89
96
  add_changelog_diff_link() {
90
97
  local OLD_VERSION=$1
91
98
  local NEW_VERSION=$2
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Check if a staged file has unstaged changes and print a warning
4
+
5
+ staged_files = `git diff --name-only --staged`.split(' ')
6
+ unstaged_files = `git diff --name-only`.split(' ')
7
+ files = (staged_files << unstaged_files).flatten!
8
+
9
+ if files.length != files.uniq.length
10
+ puts 'Warning: a staged file has unstaged changes!'
11
+ fd = IO.sysopen('/dev/tty', 'w+')
12
+ a = IO.new(fd, 'w+')
13
+ a.print 'Continue anyway? [y/N] '
14
+ input = a.gets.chomp
15
+ exit input =~ /^y/i ? 0 : -1
16
+ end
17
+
18
+ exit 0
@@ -9,12 +9,17 @@
9
9
  # rubocop run of all checks as part of the pre-push hook
10
10
 
11
11
  step_name "Running RuboCop lint checks"
12
- rubocop --lint
12
+ staged_ruby_files=$(get_staged_ruby_files)
13
+ if [ -z "$staged_ruby_files" ]; then
14
+ # quit since there are no ruby files to check
15
+ exit 0
16
+ fi
17
+ rubocop --lint $staged_ruby_files
13
18
  check_rc "Please fix RuboCop lint failures before committing."
14
19
 
15
20
  # Do a full rubocop run to warn the user, but don't block a commit by it.
16
21
  step_name "Running all RuboCop checks"
17
- rubocop
22
+ rubocop $staged_ruby_files
18
23
  check_rc_optional "Fix all RuboCop failures before pushing upstream"
19
24
 
20
25
  exit 0
@@ -17,15 +17,29 @@ else
17
17
  against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
18
18
  fi
19
19
 
20
+ step_name 'Checking for non-ASCII filenames'
20
21
  # We exploit the fact that the printable range starts at the space character
21
22
  # and ends with tilde.
22
23
  # Note that the use of brackets around a tr range is ok here, (it's
23
24
  # even required, for portability to Solaris 10's /usr/bin/tr), since
24
25
  # the square bracket bytes happen to fall in the designated range.
25
- git diff --cached --name-only --diff-filter=A -z $against |
26
- LC_ALL=C tr -d '[ -~]\0' | wc -c
26
+ added_files=$(git diff --cached --name-only --diff-filter=A -z $against | tr '\0' ' ')
27
+ added_files_array=(`echo $added_files`)
28
+ # Print the files that have non-ascii text
29
+ for i in ${added_files_array[@]}; do
30
+ bad_chars=$(echo -n $i | LC_ALL=C tr -d '[ -~]\0')
31
+ if [ -n "$bad_chars" ]; then echo $i; fi
32
+ done
33
+ # Fail if any non-ASCII characters are discovered
34
+ (echo -n $added_files | LC_ALL=C tr -d '[ -~]\0' | exit $(wc -c))
27
35
  check_rc "Rename non-ASCII file name(s) before committing"
28
36
 
37
+ step_name 'Checking for trailing whitespace in non-Ruby files'
29
38
  # If there are whitespace errors, print the offending file names and fail.
30
- git diff-index --check --cached $against --
31
- check_rc "Fix trailing whitespace before committing"
39
+ # Ignore .rb files, as whitespace in these files is managed by Rubocop
40
+ # Ignore .proto files, as they are generated code
41
+ non_ruby_files=`git diff --staged --name-only | grep -v \.rb | grep -v \.proto`
42
+ if [ -n "$non_ruby_files" ]; then
43
+ ! git grep -n -I '\s$' -- $non_ruby_files
44
+ check_rc "Fix trailing whitespace before committing"
45
+ fi
@@ -0,0 +1,18 @@
1
+ #!/bin/bash
2
+
3
+ [ -n "$GIT_DIR" ] || export GIT_DIR="$(git rev-parse --show-toplevel 2>/dev/null)/.git"
4
+ . "$GIT_DIR"/hooks/hook_lib
5
+
6
+ # Run the Kwalify YAML schema validation
7
+
8
+ step_name "Validating YAML files"
9
+ rspec "$REPO_DIR"/spec/yaml_spec.rb
10
+ check_rc "Please fix YAML schema validation failures before committing"
11
+
12
+ # Ensure that command_reference can parse all the YAML as well
13
+
14
+ step_name "Checking command_reference YAML parsing"
15
+ ruby "$REPO_DIR"/tests/test_command_reference.rb
16
+ check_rc "Please fix command_reference unit test failures before committing"
17
+
18
+ exit 0
data/bin/git/update-hooks CHANGED
@@ -12,6 +12,52 @@ HOOK_DIR="$(git rev-parse --show-toplevel)/.git/hooks"
12
12
 
13
13
  . "$SRC_DIR/hook_lib"
14
14
 
15
+ usage() {
16
+ echo "Usage: update-hooks [OPTION]"
17
+ echo "Update the hooks in the local git repository to match those"
18
+ echo "under version control."
19
+ echo
20
+ echo "Options:"
21
+ echo " --dry-run Do not make any updates"
22
+ echo " -v --verbose Verbose output, including diffs of updated files"
23
+ echo " --[no-]pager Explicity request or suppress pagination in git diff"
24
+ echo " -h --help Display this help text"
25
+ }
26
+
27
+ # Flags that can be set from the command line, with default values
28
+ make_updates=1 # the inverse of --dry-run
29
+ verbose=0
30
+ pager= # default to whatever defaults git has configured
31
+
32
+ # parse command line options
33
+ while [ "$#" -gt 0 ]; do
34
+ case "$1" in
35
+ (-h|--help)
36
+ usage
37
+ exit 0
38
+ ;;
39
+ (-v|--verbose)
40
+ verbose=1
41
+ ;;
42
+ (--pager)
43
+ pager=--paginate
44
+ ;;
45
+ (--no-pager)
46
+ pager=--no-pager
47
+ ;;
48
+ (--dry-run)
49
+ make_updates=0
50
+ ;;
51
+ (*)
52
+ echo "Unrecognized option: $1"
53
+ usage
54
+ exit 1
55
+ ;;
56
+ esac
57
+ shift 1
58
+ done
59
+
60
+
15
61
  install_hook_wrapper() {
16
62
  local hook=$1
17
63
  # Does the symlink exist?
@@ -19,11 +65,15 @@ install_hook_wrapper() {
19
65
  # If a hook already exists and is a file:
20
66
  if [ -f $HOOK_DIR/$hook ]; then
21
67
  step_name "Moving existing '$hook' script to '$hook-local'"
22
- mv $HOOK_DIR/$hook $HOOK_DIR/$hook-local
68
+ if [ $make_updates == 1 ]; then
69
+ mv $HOOK_DIR/$hook $HOOK_DIR/$hook-local
70
+ fi
23
71
  fi
24
72
  # create the symlink to our wrapper script
25
73
  step_name "Installing hook wrapper script for '$hook'"
26
- ln -s -f ./hooks-wrapper $HOOK_DIR/$hook
74
+ if [ $make_updates == 1 ]; then
75
+ ln -s -f ./hooks-wrapper $HOOK_DIR/$hook
76
+ fi
27
77
  fi
28
78
  }
29
79
 
@@ -32,14 +82,22 @@ check_update() {
32
82
  local dest=$2
33
83
  if [ ! -e "$dest" ] ; then
34
84
  step_name "Creating new file at '$dest':"
35
- git diff --color --no-index /dev/null $src
36
- cp $src $dest
85
+ if [ $verbose == 1 ]; then
86
+ git ${pager} diff --color --no-index /dev/null $src
87
+ fi
88
+ if [ $make_updates == 1 ]; then
89
+ cp $src $dest
90
+ fi
37
91
  else
38
92
  diff $src $dest >> /dev/null
39
93
  if [ $? -ne 0 ] ; then
40
94
  step_name "File '$dest' will be updated: "
41
- git diff --color --no-index $dest $src
42
- cp -f $src $dest
95
+ if [ $verbose == 1 ]; then
96
+ git ${pager} diff --color --no-index $dest $src
97
+ fi
98
+ if [ $make_updates == 1 ]; then
99
+ cp -f $src $dest
100
+ fi
43
101
  fi
44
102
  fi
45
103
  }
@@ -6,15 +6,15 @@ require 'cisco_node_utils/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'cisco_node_utils'
8
8
  spec.version = CiscoNodeUtils::VERSION
9
- spec.authors = ['Alex Hunsberger', 'Glenn Matthews',
10
- 'Chris Van Heuveln', 'Mike Wiebe', 'Jie Yang',
11
- 'Rob Gries']
9
+ spec.authors = ['Rob Gries', 'Alex Hunsberger', 'Glenn Matthews',
10
+ 'Chris Van Heuveln', 'Rich Wellum', 'Mike Wiebe',
11
+ 'Jie Yang']
12
12
  spec.email = 'cisco_agent_gem@cisco.com'
13
13
  spec.summary = 'Utilities for management of Cisco network nodes'
14
14
  spec.description = <<-EOF
15
15
  Utilities for management of Cisco network nodes.
16
16
  Designed to work with Puppet and Chef.
17
- Currently supports NX-OS nodes.
17
+ Currently supports NX-OS and IOS XR nodes.
18
18
  EOF
19
19
  spec.license = 'Apache-2.0'
20
20
  spec.homepage = 'https://github.com/cisco/cisco-network-node-utils'
@@ -28,10 +28,13 @@ Currently supports NX-OS nodes.
28
28
  spec.required_ruby_version = '>= 2.0.0'
29
29
  spec.required_rubygems_version = '>= 2.1.0'
30
30
 
31
- spec.add_development_dependency 'minitest', '~> 5.0'
32
31
  spec.add_development_dependency 'bundler', '~> 1.7'
32
+ spec.add_development_dependency 'kwalify', '~> 0.7.2'
33
+ spec.add_development_dependency 'minitest', '~> 5.0'
33
34
  spec.add_development_dependency 'rake', '~> 10.0'
35
+ spec.add_development_dependency 'rspec', '~> 3.0'
34
36
  spec.add_development_dependency 'rubocop', '= 0.35.1'
35
37
  spec.add_development_dependency 'simplecov', '~> 0.9'
36
- spec.add_runtime_dependency 'cisco_nxapi', '~> 1.0', '>= 1.0.1'
38
+
39
+ spec.extensions = ['ext/mkrf_conf.rb']
37
40
  end
@@ -14,24 +14,25 @@ This document is intended to assist in developing cisco_node_utils API's that ar
14
14
 
15
15
  * [Y1](#yaml1): One feature per YAML file
16
16
  * [Y2](#yaml2): All attribute entries must be kept in alphabetical order.
17
- * [Y3](#yaml3): Use *regexp* anchors where needed for `config_get` and `config_get_token` entries.
17
+ * [Y3](#yaml3): Use *regexp* anchors where needed for CLI `get_context` and `get_value` entries.
18
18
  * [Y4](#yaml4): Avoid nested optional matches.
19
19
  * [Y5](#yaml5): Use the `_template` feature when getting/setting the same property value at multiple levels.
20
20
  * [Y6](#yaml6): When possible include a `default_value` that represents the system default value.
21
- * [Y7](#yaml7): When possible, use the same `config_get` show command for all properties and document any anomalies.
21
+ * [Y7](#yaml7): When possible, use the same `get_command` for all properties and document any anomalies.
22
22
  * [Y8](#yaml8): Use Key-value wildcards instead of Printf-style wildcards.
23
- * [Y9](#yaml9): Selection of `show` commands for `config_get`.
23
+ * [Y9](#yaml9): Selection of `show` commands for `get_command`.
24
24
  * [Y10](#yaml10): Use `true` and `false` for boolean values.
25
-
26
-
25
+ * [Y11](#yaml11): Use YAML anchors and aliases to avoid redundant entries.
26
+ * [Y12](#yaml12): Use `_exclude` to return `nil` for unsupported properties.
27
27
 
28
28
  ## <a name="odbp">Common Object Development Best Practices</a>
29
29
 
30
30
  * [CO1](#co1): Features that can be configured under the global and non-global vrfs need to account for this in the object design.
31
31
  * [CO2](#co2): Make use of the equality operator allowing proper `instance1 == instance2` checks in the minitests.
32
32
  * [CO3](#co3): Use `''` rather than `nil` to represent "property is absent entirely"
33
- * [CO4](#co4): Make sure all new properites have a `getter`, `setter` and `default_getter` method.
33
+ * [CO4](#co4): Make sure all new properties have a `getter`, `setter` and `default_getter` method.
34
34
  * [CO5](#co5): Use singleton-like design for resources that cannot have multiple instances.
35
+ * [CO6](#co6): Implement a meaningful `to_s` method
35
36
 
36
37
  ## <a name="mdbp">MiniTest Development Best Practices</a>
37
38
 
@@ -40,7 +41,7 @@ This document is intended to assist in developing cisco_node_utils API's that ar
40
41
  * [MT3](#mt3): Do not hardcode interface names.
41
42
  * [MT4](#mt4): Make use of the `config` helper method for device configuration instead of `@device.cmd`.
42
43
  * [MT5](#mt5): Make use of the `assert_show_match` and `refute_show_match` helper methods to validate expected outcomes in the CLI instead of `@device.cmd("show...")`.
43
-
44
+ * [MT6](#mt6): Unsupported properties must include negative test cases.
44
45
 
45
46
 
46
47
  ## YAML Best Practices:
@@ -55,16 +56,18 @@ All attribute entries in a given YAML file must be kept in alphabetical order. A
55
56
 
56
57
  This rule is enforced by the `Cisco::CommandReference` class itself - it will raise an exception if it detects any out-of-order entries.
57
58
 
58
- ### <a name="yaml3">Y3: Use *regexp* anchors where needed for `config_get` and `config_get_token` entries.
59
+ ### <a name="yaml3">Y3: Use *regexp* anchors where needed for CLI `get_context` and `get_value` entries.
59
60
 
60
- Please use *regexp* anchors `^$` to ensure you match the correct feature information in the `show` output.
61
+ By default, CLI clients assume that `get_context` and `get_value` are to be treated as Regexps, and implicitly add regexp anchors and case-insensitivity (i.e., a `get_value` of `'router bgp 100'` becomes the regexp `/^router bgp 100$/i`). If you want to explicitly specify a regexp (perhaps because the default behavior does not meet your needs for a specific property), be sure to add the `^` and `$` anchors to ensure you match the correct feature information in the `show` output and do not unexpectedly match similar but undesired CLI strings.
61
62
 
62
63
  ```yaml
63
64
  # syslog_settings.yaml
64
65
  timestamp:
65
- config_get: "show running-config all | include '^logging timestamp'"
66
- config_get_token: '/^logging timestamp (.*)$/'
67
- config_set: '<state> logging timestamp <units>'
66
+ get_command: "show running-config all | include '^logging timestamp'"
67
+ get_value: 'logging timestamp (.*)'
68
+ # this is equivalent to:
69
+ # get_value: '/^logging timestamp (.*)$/'
70
+ set_value: '<state> logging timestamp <units>'
68
71
  default_value: 'seconds'
69
72
  ```
70
73
 
@@ -77,18 +80,20 @@ One case where this may crop up is in trying to match both affirmative and
77
80
  negative variants of a config command:
78
81
 
79
82
  ```yaml
80
- config_get_token: ['/^interface <name>$/i', '/^((no )?switchport)$/']
83
+ get_context: ['interface <name>']
84
+ get_value: '((no )?switchport)'
81
85
 
82
- config_get_token: '/^(no)? ?ip tacacs source-interface ?(\S+)?$/'
86
+ get_value: '(no)? ?ip tacacs source-interface ?(\S+)?'
83
87
  ```
84
88
 
85
89
  Instead, match the affirmative form of a command and treat its absence as
86
90
  confirmation of the negative form:
87
91
 
88
92
  ```yaml
89
- config_get_token: ['/^interface <name>$/i', '/^switchport$/']
93
+ get_context: ['interface <name>']
94
+ get_value: 'switchport'
90
95
 
91
- config_get_token: '/^tacacs-server source-interface (\S+)$/'
96
+ get_value: 'tacacs-server source-interface (\S+)'
92
97
  ```
93
98
 
94
99
  ### <a name="yaml5">Y5: Use the `_template` feature when getting/setting the same property value at multiple levels.
@@ -98,22 +103,19 @@ Using the template below, `auto_cost` and `default_metric` can be set under `rou
98
103
  ```yaml
99
104
  # ospf.yaml
100
105
  _template:
101
- config_get: "show running ospf all"
102
- config_get_token: '/^router ospf <name>$/'
103
- config_get_token_append:
104
- - '/^vrf <vrf>$/'
105
- config_set: "router ospf <name>"
106
- config_set_append:
107
- - "vrf <vrf>"
106
+ get_command: "show running ospf all"
107
+ context:
108
+ - 'router ospf <name>'
109
+ - '(?)vrf <vrf>'
108
110
 
109
111
  auto_cost:
110
- config_get_token_append: '/^auto-cost reference-bandwidth (\d+)\s*(\S+)?$/'
111
- config_set_append: "auto-cost reference-bandwidth <cost> <type>"
112
+ get_value: 'auto-cost reference-bandwidth (\d+)\s*(\S+)?'
113
+ set_value: "auto-cost reference-bandwidth <cost> <type>"
112
114
  default_value: [40, "Gbps"]
113
115
 
114
116
  default_metric:
115
- config_get_token_append: '/^default-metric (\d+)?$/'
116
- config_set_append: "<state> default-metric <metric>"
117
+ get_value: 'default-metric (\d+)?'
118
+ set_value: "<state> default-metric <metric>"
117
119
  default_value: 0
118
120
  ```
119
121
 
@@ -126,20 +128,22 @@ Default value for `message_digest_alg_type` is `md5`
126
128
 
127
129
  ```yaml
128
130
  message_digest_alg_type:
129
- config_get: 'show running interface all'
130
- config_get_token: ['/^interface <name>$/i', '/^\s*ip ospf message-digest-key \d+ (\S+)/']
131
+ get_command: 'show running interface all'
132
+ get_context: 'interface <name>'
133
+ get_value: '/^\s*ip ospf message-digest-key \d+ (\S+)/'
131
134
  default_value: 'md5'
132
135
  ```
133
136
 
134
137
  **NOTE1: Use strings rather then symbols when applicable**.
135
138
 
136
- If the `default_value` differs between cisco platforms, use per-API or per-platform keys in the YAML as needed. For example, if the default value on all platforms except the N9K is `md5` then you might do something like this:
139
+ If the `default_value` differs between cisco platforms, use per-API or per-platform keys in the YAML as needed. For example, if the default value on all platforms except the N9k is `md5` then you might do something like this:
137
140
 
138
141
  ```yaml
139
142
  message_digest_alg_type:
140
- config_get: 'show running interface all'
141
- config_get_token: ['/^interface <name>$/i', '/^\s*ip ospf message-digest-key \d+ (\S+)/']
142
- /N9K/:
143
+ get_command: 'show running interface all'
144
+ get_context: 'interface <name>'
145
+ get_value: '/^\s*ip ospf message-digest-key \d+ (\S+)/'
146
+ N9k:
143
147
  default_value: 'sha2'
144
148
  else:
145
149
  default_value: 'md5'
@@ -147,33 +151,33 @@ message_digest_alg_type:
147
151
 
148
152
  See [README_YAML](../lib/cisco_node_utils/cmd_ref/README_YAML.md) for more details about this advanced feature.
149
153
 
150
- ### <a name="yaml7">Y7: When possible, use the same `config_get` show command for all properties and document any anomalies.
154
+ ### <a name="yaml7">Y7: When possible, use the same `get_command` for all properties and document any anomalies.
151
155
 
152
156
  All properties below use the `show run tacacs all` command except `directed_request` which is documented.
153
157
 
154
158
  ```yaml
155
159
  # tacacs_server.yaml
160
+ _template:
161
+ get_command: "show run tacacs all"
162
+
156
163
  deadtime:
157
- config_get: "show run tacacs all"
158
- config_get_token: '/^tacacs-server deadtime\s+(\d+)/'
159
- config_set: "<state> tacacs-server deadtime <time>"
164
+ get_value: '/^tacacs-server deadtime\s+(\d+)/'
165
+ set_value: "<state> tacacs-server deadtime <time>"
160
166
  default_value: 0
161
167
 
162
168
  directed_request:
163
169
  # oddly, directed request must be retrieved from aaa output
164
- config_get: "show running aaa all"
165
- config_get_token: '/(?:no)?\s*tacacs-server directed-request/'
166
- config_set: "<state> tacacs-server directed-request"
170
+ get_command: "show running aaa all"
171
+ get_value: '/(?:no)?\s*tacacs-server directed-request/'
172
+ set_value: "<state> tacacs-server directed-request"
167
173
  default_value: false
168
174
 
169
175
  encryption_type:
170
- config_get: "show run tacacs all"
171
- config_get_token: '/^tacacs-server key (\d+)\s+(\S+)/'
176
+ get_value: '/^tacacs-server key (\d+)\s+(\S+)/'
172
177
  default_value: 0
173
178
 
174
179
  encryption_password:
175
- config_get: "show run tacacs all"
176
- config_get_token: '/^tacacs-server key (\d+)\s+(\S+)/'
180
+ get_value: '/^tacacs-server key (\d+)\s+(\S+)/'
177
181
  default_value: ""
178
182
  ```
179
183
 
@@ -184,7 +188,7 @@ Key-value wildcards are moderately more complex to implement than Printf-style w
184
188
  **Key-value wildcards**
185
189
 
186
190
  ```yaml
187
- config_set_append: "<state> log-adjacency-changes <type>"
191
+ get_value: "<state> log-adjacency-changes <type>"
188
192
  ```
189
193
 
190
194
  This following approach is quick to implement and concise, but less flexible - in particular it cannot handle a case where different platforms take parameters in a different order - and less readable in the ruby code.
@@ -192,10 +196,10 @@ This following approach is quick to implement and concise, but less flexible - i
192
196
  **Printf-style wildcards**
193
197
 
194
198
  ```yaml
195
- config_set_append: "%s log-adjacency-changes %s"
199
+ get_value: "%s log-adjacency-changes %s"
196
200
  ```
197
201
 
198
- ### <a name="yaml9">Y9: Selection of `show` commands for `config_get`.
202
+ ### <a name="yaml9">Y9: Selection of `show` commands for `get_command`.
199
203
 
200
204
  The following commands should be preferred over `show [feature]` commands since not all `show [feature]` commands behave in the same manner across cisco platforms.
201
205
 
@@ -206,6 +210,48 @@ The following commands should be preferred over `show [feature]` commands since
206
210
 
207
211
  YAML allows various synonyms for `true` and `false` such as `yes` and `no`, but for consistency and readability (especially to users more familiar with Ruby than with YAML), we recommend using `true` and `false` rather than any of their synonyms.
208
212
 
213
+ ### <a name="yaml11">Y11: Use YAML anchors and aliases to avoid redundant entries.
214
+
215
+ Use the standard YAML functionality of [node anchors](http://www.yaml.org/spec/1.2/spec.html#id2785586) and [node aliases](http://www.yaml.org/spec/1.2/spec.html#id2786196) to avoid redundant entries. In other words, instead of:
216
+
217
+ ```yaml
218
+ vn_segment_vlan_based:
219
+ # MT-lite only
220
+ N3k:
221
+ kind: boolean
222
+ config_get: 'show running section feature'
223
+ config_get_token: '/^feature vn-segment-vlan-based$/'
224
+ config_set: 'feature vn-segment-vlan-based'
225
+ default_value: false
226
+ N9k:
227
+ # same as N3k
228
+ kind: boolean
229
+ config_get: 'show running section feature'
230
+ config_get_token: '/^feature vn-segment-vlan-based$/'
231
+ config_set: 'feature vn-segment-vlan-based'
232
+ default_value: false
233
+ ```
234
+
235
+ instead you can do:
236
+
237
+ ```yaml
238
+ vn_segment_vlan_based:
239
+ # MT-lite only
240
+ N3k: &vn_segment_vlan_based_mt_lite
241
+ kind: boolean
242
+ config_get: 'show running section feature'
243
+ config_get_token: '/^feature vn-segment-vlan-based$/'
244
+ config_set: 'feature vn-segment-vlan-based'
245
+ default_value: false
246
+ N9k: *vn_segment_vlan_based_mt_lite
247
+ ```
248
+
249
+ ### <a name="yaml12">Y12: Use `_exclude` to return `nil` for unsupported properties.
250
+
251
+ Some properties are only applicable to specific platforms. Rather than using `default_only` to specify an 'unconfigured' default like `''` or `false`, it is more accurate to return `nil` for a property that is not applicable at all. By returning `nil`, the property will not even appear in commands like `puppet resource`, which is the desired outcome.
252
+
253
+ Rather than specifying `default_only: nil`, the most straightforward and self-evident way to mark a property as unsupported is to use the `_exclude: [my_platform]` YAML tag. See [README_YAML.md](../lib/cisco_node_utils/cmd_ref/README_YAML.md#_exclude) for more details about the `_exclude` tag.
254
+
209
255
  ## Common Object Best Practices:
210
256
 
211
257
  ### <a name="co1">CO1: Features that can be configured under the global and non-global vrfs need to account for this in the object design.
@@ -319,7 +365,7 @@ def access_vlan=(vlan)
319
365
  config_set('interface', 'access_vlan', @name, vlan)
320
366
  ```
321
367
 
322
- ### <a name="co4">CO4: Make sure all new properites have a `getter`, `setter` and `default_getter` method.
368
+ ### <a name="co4">CO4: Make sure all new properties have a `getter`, `setter` and `default_getter` method.
323
369
 
324
370
  In order to have a complete set of api's for each property it is important that all properties have a `getter`, `setter` and `default_getter` method.
325
371
 
@@ -356,10 +402,49 @@ end
356
402
 
357
403
  See [TacacsServer](../lib/cisco_node_utils/tacacs_server.rb) and [SnmpServer](../lib/cisco_node_utils/snmpserver.rb) for examples.
358
404
 
405
+ ### <a name="co6">CO6: Implement a meaningful `to_s` method
406
+
407
+ Request errors generated by a `NodeUtil` subclass calling `config_get` or `config_set` will automatically prepend the output of the class's `to_s` method. The default output of this method is not especially helpful as it just identifies the class name:
408
+
409
+ ```
410
+ Cisco::CliError: [#<Cisco::Bgp:0x007f1b3b7af5a0>] The command 'foobar shutdown' was rejected with error:
411
+ ...
412
+ ```
413
+
414
+ But by implementing the `to_s` method:
415
+
416
+ ```ruby
417
+ module Cisco
418
+ # RouterBgp - node utility class for BGP general config management
419
+ class RouterBgp < NodeUtil
420
+ attr_reader :asnum, :vrf
421
+ ...
422
+ def to_s
423
+ "BGP #{asnum} VRF '#{vrf}'"
424
+ end
425
+ ```
426
+
427
+ The error output can now clearly identify the instance that failed:
428
+
429
+ ```
430
+ Cisco::CliError: [BGP 100 VRF 'red'] The command 'foobar shutdown' was rejected with error:
431
+ ...
432
+ ```
433
+
359
434
  ## MiniTest Best Practices:
360
435
 
361
436
  ### <a name="mt1">MT1: Ensure that *all new API's* have minitest coverage.
362
437
 
438
+ Running minitest will automatically produce code coverage results using the [SimpleCov](http://www.rubydoc.info/gems/simplecov) Gem:
439
+
440
+ ```
441
+ test_interface:
442
+ 39 runs, 316 assertions, 0 failures, 0 errors, 2 skips
443
+ Coverage report generated for MiniTest to cisco-network-node-utils/coverage. 602 / 814 LOC (73.96%) covered.
444
+ ```
445
+
446
+ If you are adding new APIs, after running the tests, you should inspect the coverage results (open `coverage/index.html` with a web browser) to ensure that your new APIs are being exercised appropriately by your new tests.
447
+
363
448
  ### <a name="mt2">MT2: Use appropriate `assert_foo` and `refute_foo` statements rather than `assert_equal`.
364
449
 
365
450
 
@@ -377,8 +462,7 @@ The more specific assertions also produce more helpful failure messages if somet
377
462
 
378
463
  ### <a name="mt3">MT3: Do not hardcode interface names.
379
464
 
380
- Rather then hardcode an interface name that may or may not exist, instead use
381
- the `interfaces[]` array.
465
+ Rather then hardcode an interface name that may or may not exist, instead use the `interfaces[]` array.
382
466
 
383
467
  ```ruby
384
468
  def create_interface(ifname=interfaces[0])
@@ -420,3 +504,18 @@ refute_output_match(pattern: /interface port-channel 11/)
420
504
  refute_output_match(pattern: /interface port-channel 12/)
421
505
  assert_output_match(pattern: /interface port-channel 13/)
422
506
  ```
507
+
508
+ ### <a name="mt6">MT6: Unsupported properties must include negative test cases.
509
+
510
+ Some properties are only applicable to a particular platform and are unsupported on other platforms. To ensure that this lack of support is properly validated, at least one of the test cases for this property should include tests of the getter and default methods and a negative test for the setter method. If you followed [Y11](#yaml11), this means checking that the getter and default methods return `nil` and the setter method raises a `Cisco::UnsupportedError`:
511
+
512
+ ```ruby
513
+ def test_foo_bar
514
+ if platform == :platform_not_supporting_bar
515
+ assert_nil(foo.bar)
516
+ assert_nil(foo.default_bar)
517
+ assert_raises(Cisco::UnsupportedError) { foo.bar = baz }
518
+ else
519
+ # tests for foo.bar on a platform that supports this
520
+ ...
521
+ ```