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
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # January 2016, Glenn F. Matthews
4
+ #
5
+ # Copyright (c) 2015-2016 Cisco and/or its affiliates.
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require_relative '../constants'
20
+ require_relative '../logger'
21
+
22
+ # Utility methods for clients of various RPC formats
23
+ class Cisco::Client
24
+ # Make a best effort to convert a given input value to an Array.
25
+ # Strings are split by newlines, and nil becomes an empty Array.
26
+ def self.munge_to_array(val)
27
+ val = [] if val.nil?
28
+ val = val.split("\n") if val.is_a?(String)
29
+ val
30
+ end
31
+
32
+ def munge_to_array(val)
33
+ self.class.munge_to_array(val)
34
+ end
35
+
36
+ # Helper function that subclasses may use with get(data_format: :cli)
37
+ # Method for working with hierarchical show command output such as
38
+ # "show running-config". Searches the given multi-line string
39
+ # for all matches to the given value query. If context is provided,
40
+ # the matches will be filtered to only those that are located "under"
41
+ # the given context sequence (as determined by indentation).
42
+ #
43
+ # @param cli_output [String] The body of text to search
44
+ # @param context [*Regex] zero or more regular expressions defining
45
+ # the parent configs to filter by.
46
+ # @param value [Regex] The regular expression to match
47
+ # @return [[String], nil] array of matching (sub)strings, else nil.
48
+ #
49
+ # @example Find all OSPF router names in the running-config
50
+ # ospf_names = filter_cli(cli_output: running_cfg,
51
+ # value: /^router ospf (\d+)/)
52
+ #
53
+ # @example Find all address-family types under the given BGP router
54
+ # bgp_afs = filter_cli(cli_output: show_run_bgp,
55
+ # context: [/^router bgp #{ASN}/],
56
+ # value: /^address-family (.*)/)
57
+ def self.filter_cli(cli_output: nil,
58
+ context: nil,
59
+ value: nil)
60
+ return cli_output if cli_output.nil?
61
+ context ||= []
62
+ context.each { |filter| cli_output = find_subconfig(cli_output, filter) }
63
+ return nil if cli_output.nil? || cli_output.empty?
64
+ return cli_output if value.nil?
65
+ value = to_regexp(value)
66
+ match = cli_output.scan(value)
67
+ return nil if match.empty?
68
+ # find matches and return as array of String if it only does one match.
69
+ # Otherwise return array of array.
70
+ match.flatten! if match[0].is_a?(Array) && match[0].length == 1
71
+ match
72
+ end
73
+
74
+ # Returns the subsection associated with the given
75
+ # line of config
76
+ # @param [String] the body of text to search
77
+ # @param [Regex] the regex key of the config for which
78
+ # to retrieve the subsection
79
+ # @return [String, nil] the subsection of body, de-indented
80
+ # appropriately, or nil if no such subsection exists.
81
+ def self.find_subconfig(body, regexp_query)
82
+ return nil if body.nil? || regexp_query.nil?
83
+ regexp_query = to_regexp(regexp_query)
84
+
85
+ rows = body.split("\n")
86
+ match_row_index = rows.index { |row| regexp_query =~ row }
87
+ return nil if match_row_index.nil?
88
+
89
+ cur = match_row_index + 1
90
+ subconfig = []
91
+
92
+ until (/\A\s+.*/ =~ rows[cur]).nil? || cur == rows.length
93
+ subconfig << rows[cur]
94
+ cur += 1
95
+ end
96
+ return nil if subconfig.empty?
97
+ # Strip an appropriate minimal amount of leading whitespace from
98
+ # all lines in the subconfig
99
+ min_leading = subconfig.map { |line| line[/\A */].size }.min
100
+ subconfig = subconfig.map { |line| line[min_leading..-1] }
101
+ subconfig.join("\n")
102
+ end
103
+
104
+ # Helper method for CLI getters
105
+ #
106
+ # Convert a string or array of strings to a Regexp or array thereof
107
+ def self.to_regexp(input)
108
+ if input.is_a?(Regexp)
109
+ return input
110
+ elsif input.is_a?(Array)
111
+ return input.map { |item| to_regexp(item) }
112
+ else
113
+ # The string might be explicitly formatted as a regexp
114
+ if input[0] == '/' && input[-1] == '/'
115
+ # '/foo/' => %r{foo}
116
+ return Regexp.new(input[1..-2])
117
+ elsif input[0] == '/' && input[-2..-1] == '/i'
118
+ # '/foo/i' => %r{foo}i
119
+ return Regexp.new(input[1..-3], Regexp::IGNORECASE)
120
+ else
121
+ # 'foo' => %r{^foo$}i
122
+ return Regexp.new("^#{input}$", Regexp::IGNORECASE)
123
+ end
124
+ end
125
+ end
126
+
127
+ # Helper method for get(data_format: :nxapi_structured).
128
+ #
129
+ # @param data [Array, Hash] structured output from node
130
+ # @param keys [Array] lookup sequence
131
+ def self.filter_data(data: nil,
132
+ keys: nil)
133
+ return nil if data.nil?
134
+ keys ||= []
135
+ keys.each do |filter|
136
+ # if filter is a Hash and data is an array, check each
137
+ # array index (which should return another hash) to see if
138
+ # it contains the matching key/value pairs specified in token,
139
+ # and return the first match (or nil)
140
+ if filter.kind_of?(Hash)
141
+ fail "Expected Array, got #{data.class}" unless data.is_a? Array
142
+ data = data.select { |x| filter.all? { |k, v| x[k] == v } }
143
+ fail "Multiple matches found for #{filter}" if data.length > 1
144
+ fail "No match found for #{filter}" if data.length == 0
145
+ data = data[0]
146
+ else # data is array or hash
147
+ filter = filter.to_i if data.is_a? Array
148
+ fail "No key \"#{filter}\" in #{data}" if data[filter].nil?
149
+ data = data[filter]
150
+ end
151
+ end
152
+ data
153
+ end
154
+
155
+ # Helper method for calls into third-party code - suppresses Ruby warnings
156
+ # for the given block since we have no control over that code.
157
+ def self.silence_warnings(&block)
158
+ warn_level = $VERBOSE
159
+ $VERBOSE = nil
160
+ result = block.call
161
+ $VERBOSE = warn_level
162
+ result
163
+ end
164
+ end
@@ -12,25 +12,27 @@ This document describes the structure and semantics of these files.
12
12
  * [Wildcard substitution](#wildcard-substitution)
13
13
  * [Printf-style wildcards](#printf-style-wildcards)
14
14
  * [Key-value wildcards](#key-value-wildcards)
15
+ * [Optional tokens in key-value lists](#optional-tokens-in-key-value-lists)
15
16
  * [Advanced attribute definition](#advanced-attribute-definition)
16
17
  * [`_template`](#_template)
17
- * [Platform and API variants](#platform-and-api-variants)
18
+ * [Data format variants](#data-format-variants)
19
+ * [Platform variants](#platform-variants)
18
20
  * [Product variants](#product-variants)
19
21
  * [`_exclude`](#_exclude)
22
+ * [YAML anchors and aliases](#YAML-anchors-and-aliases)
20
23
  * [Combinations of these](#combinations-of-these)
21
24
  * [Attribute properties](#attribute-properties)
22
- * [`config_get`](#config_get)
23
- * [`config_get_token`](#config_get_token)
24
- * [`config_get_token_append`](#config_get_token_append)
25
- * [`config_set`](#config_set)
26
- * [`config_set_append`](#config_set_append)
25
+ * [`get_data_format`](#get_data_format)
26
+ * [`get_command`](#get_command)
27
+ * [`get_context`](#get_context)
28
+ * [`get_value`](#get_value)
29
+ * [`set_context`](#set_context)
30
+ * [`set_value`](#set_value)
27
31
  * [`default_value`](#default_value)
28
32
  * [`default_only`](#default_only)
29
33
  * [`kind`](#kind)
30
34
  * [`multiple`](#multiple)
31
35
  * [`auto_default`](#auto_default)
32
- * [`test_config_get` and `test_config_get_regex`](#test_config_get-and-test_config_get_regex)
33
- * [`test_config_result`](#test_config_result)
34
36
  * [Style Guide](#style-guide)
35
37
 
36
38
  ## Introduction
@@ -59,14 +61,14 @@ An example:
59
61
  ```yaml
60
62
  # vtp.yaml
61
63
  domain:
62
- config_get: "show vtp status"
63
- config_get_token: "domain_name"
64
- config_set: "vtp domain <domain>"
64
+ get_command: "show vtp status"
65
+ get_value: "domain_name"
66
+ set_value: "vtp domain <domain>"
65
67
 
66
68
  filename:
67
- config_get: "show running vtp"
68
- config_get_token: '/vtp file (\S+)/'
69
- config_set: "<state> vtp file <filename>"
69
+ get_command: "show running vtp"
70
+ get_value: '/vtp file (\S+)/'
71
+ set_value: "<state> vtp file <filename>"
70
72
  default_value: ""
71
73
  ```
72
74
 
@@ -79,16 +81,36 @@ needed. In the above, example 'domain' does not have a value defined for
79
81
 
80
82
  ### Wildcard substitution
81
83
 
82
- The `config_get_token` and `config_set` properties (and their associated
83
- `_append` variants) all support two forms of wildcarding - printf-style and
84
- key-value. Key-value is generally preferred, as described below.
84
+ The `(get|set)_(context|value)` properties all support two forms of wildcarding - printf-style and key-value. Each has advantages and disadvantages but key-value is generally preferred for a number of reasons as seen below:
85
+
86
+ <table>
87
+ <tr><th></th><th>Advantages</th><th>Disadvantages</th></tr>
88
+ <tr>
89
+ <th>Printf-style</th>
90
+ <td><ul><li>Quick to implement, concise</li></ul></td>
91
+ <td><ul><li>Can't handle differences in wildcard order between nodes</li>
92
+ <li>Can't handle differences in wildcard count between nodes</li>
93
+ <li>Can't support optional tokens (e.g., VRF context)</li>
94
+ <li>Less readable in Ruby code (not obvious which parameters mean what)</li>
95
+ </ul></td>
96
+ </tr><tr>
97
+ <th>Key-Value</th>
98
+ <td><ul><li>Can handle differences in wildcard order/count between nodes</li>
99
+ <li>Can handle differences in which wildcards are used on various nodes</li>
100
+ <li>Can flag tokens as optional (see below)</li>
101
+ <li>More readable Ruby code due to parameter labels</li>
102
+ </ul></td>
103
+ <td><ul><li>Slightly more complex to implement than printf-style</li>
104
+ <li>Slightly more verbose YAML and Ruby code</li>
105
+ </ul></td>
106
+ </tr></table>
85
107
 
86
108
  #### Printf-style wildcards
87
109
 
88
110
  ```yaml
89
111
  # tacacs_server_host.yaml
90
112
  encryption:
91
- config_set: '%s tacacs-server host %s key %s %s'
113
+ set_value: '%s tacacs-server host %s key %s %s'
92
114
  ```
93
115
 
94
116
  This permits parameter values to be passed as a simple sequence to generate the resulting string or regexp:
@@ -108,7 +130,8 @@ the Ruby code.
108
130
  ```yaml
109
131
  # ospf.yaml
110
132
  auto_cost:
111
- config_set: ['router ospf <name>', 'auto-cost reference-bandwidth <cost> <type>']
133
+ set_context: 'router ospf <name>'
134
+ set_value: 'auto-cost reference-bandwidth <cost> <type>'
112
135
  ```
113
136
 
114
137
  This requires parameter values to be passed as a hash:
@@ -119,16 +142,33 @@ irb(main):016:0> ref.config_set(name: 'red', cost: '40', type: 'Gbps')
119
142
  => ["router ospf red", "auto-cost reference-bandwidth 40 Gbps"]
120
143
  ```
121
144
 
122
- Array elements that contain a parameter that is *not* included in the argument hash are not included in the result:
145
+ Key-value wildcards are moderately more complex to implement than Printf-style wildcards but they are more readable in the Ruby code and are flexible enough to handle significant platform differences in CLI. Key-value wildcards are therefore the recommended approach for new development.
123
146
 
124
- ```ruby
125
- irb(main):017:0> ref.config_set(name: 'red', cost: '40')
126
- => ["router ospf red"]
147
+ ##### Optional tokens in key-value lists
148
+
149
+ When defining `(get|set)_context` entries with key-value wildcards, it is possible to mark some or all of the tokens in the context as optional by prepending `(?)` to them. A common example of this is to support properties that can be defined either globally or under a VRF routing context:
150
+
151
+ ```yaml
152
+ # bgp.yaml
153
+ confederation_peers:
154
+ ios_xr:
155
+ get_context:
156
+ - 'router bgp <asnum>'
157
+ - '(?)/^vrf <vrf>$/i'
158
+ - 'bgp confederation peers'
127
159
  ```
128
160
 
129
- If this process results in an empty array, then an `ArgumentError` is raised to indicate that not enough parameters were supplied.
161
+ An optional token will be omitted if any of the wildcards in this token do not have an assigned value. By contrast, mandatory tokens (i.e., any token not explicitly flagged as optional) will raise an ArgumentError if wildcard values are missing:
130
162
 
131
- Key-value wildcards are moderately more complex to implement than Printf-style wildcards but they are more readable in the Ruby code and are flexible enough to handle significant platform differences in CLI. Key-value wildcards are therefore the recommended approach for new development.
163
+ ```ruby
164
+ irb(main):003:0> ref = node.cmd_ref.lookup('bgp', 'confederation_peers')
165
+ irb(main):006:0> ref.getter(asnum: 1)[:context]
166
+ => ["router bgp 1", "bgp confederation peers"]
167
+ irb(main):007:0> ref.getter(asnum: 1, vrf: 'red')[:context]
168
+ => ["router bgp 1", "/^vrf red$/i", "bgp confederation peers"]
169
+ irb(main):008:0> ref.getter(vrf: 'red')[:context]
170
+ ArgumentError: No value specified for 'asnum' in 'router bgp <asnum>'
171
+ ```
132
172
 
133
173
  ## Advanced attribute definition
134
174
 
@@ -143,17 +183,17 @@ with the `interface <name>` configuration command. Thus, you might have:
143
183
  ```yaml
144
184
  # interface.yaml
145
185
  _template:
146
- config_get: 'show running-config interface all'
147
- config_get_token: '/^interface <name>$/'
148
- config_set: 'interface <name>'
186
+ get_command: 'show running-config interface all'
187
+ get_context: 'interface <name>'
188
+ set_context: 'interface <name>'
149
189
 
150
190
  access_vlan:
151
- config_get_token_append: '/^switchport access vlan (.*)$/'
152
- config_set_append: 'switchport access vlan <number>'
191
+ get_value: 'switchport access vlan (.*)'
192
+ set_value: 'switchport access vlan <number>'
153
193
 
154
194
  description:
155
- config_get_token_append: '/^description (.*)$/'
156
- config_set_append: 'description <desc>'
195
+ get_value: '/^description (.*)$/'
196
+ set_value: 'description <desc>'
157
197
 
158
198
  ...
159
199
  ```
@@ -163,64 +203,67 @@ instead of the more repetitive (but equally valid):
163
203
  ```yaml
164
204
  # interface.yaml
165
205
  access_vlan:
166
- config_get: 'show running interface all'
167
- config_get_token: ['/^interface <name>$/i', '/^switchport access vlan (.*)$/']
168
- config_set: ['interface <name>', 'switchport access vlan <number>']
206
+ get_command: 'show running interface all'
207
+ get_context: 'interface <name>'
208
+ get_value: 'switchport access vlan (.*)'
209
+ set_context: 'interface <name>'
210
+ set_value: 'switchport access vlan <number>'
169
211
 
170
212
  description:
171
- config_get: 'show running-config interface all'
172
- config_get_token: ['/^interface <name>$/i', '/^description (.*)$/']
173
- config_set: ['interface <name>', 'description <desc>']
213
+ get_command: 'show running-config interface all'
214
+ get_context: 'interface <name>'
215
+ get_value: '/^description (.*)$/'
216
+ set_context: 'interface <name>'
217
+ set_value: 'description <desc>'
174
218
 
175
219
  ...
176
220
  ```
177
221
 
178
- ### Platform and API variants
222
+ ### Data format variants
179
223
 
180
- Clients for different Cisco platforms may use different APIs. Currently the only supported API is NXAPI (CLI-based API used for Cisco Nexus platforms). Often the CLI or other input/output formats (YANG, etc.) needed will vary between APIs, so the YAML must be able to accomodate this.
224
+ Clients for different Cisco platforms may use different data formats. NXAPI (used for Cisco Nexus platforms) supports a CLI-based data format (essentially a wrapper for the Nexus CLI) as well as a NXAPI-specific structured format for some 'show' commands. Currently the gRPC client provided here (used for Cisco IOS XR platforms) supports a CLI-based format. Other platforms may have other formats such as YANG. As different formats have different requirements, the YAML must be able to accommodate this.
181
225
 
182
- Any of the attribute properties can be subdivided by platform and API type by using the
183
- combination of API type and platform type as a key. For example, interface VRF membership defaults to "" (no VRF) on both Nexus and IOS XR platforms, but the CLI is 'vrf member <vrf>' for Nexus and 'vrf <vrf>' for IOS XR. Thus, the YAML could be written as:
226
+ CLI is the lowest common denominator, so YAML entries not otherwise flagged as applicable to a specific API type will be assumed to reference CLI. Other API types can be indicated by using the API type as a key (`cli`, `nxapi_structured`, `yang`, etc.). For example, Nexus platforms support a structured form of 'show version', while other clients might use the same command but will need to parse CLI output with a regular expression:
184
227
 
185
228
  ```yaml
186
- # interface.yaml
187
- vrf:
188
- default_value: ""
189
- cli_nexus:
190
- config_get_token_append: '/^vrf member (.*)/'
191
- config_set_append: "<state> vrf member <vrf>"
229
+ # show_version.yaml
230
+ description:
231
+ get_command: 'show version'
232
+ nexus:
233
+ data_format: nxapi_structured
234
+ get_value: 'chassis_id'
235
+ else:
236
+ data_format: cli
237
+ get_value: '/Hardware\n cisco (([^(\n]+|\(\d+ Slot\))+\w+)/'
192
238
  ```
193
239
 
194
- and later, once we have a CLI-based API for IOS XR, this could be extended:
240
+ ### Platform variants
241
+
242
+ Even for clients using the same data format (e.g., CLI), there may be differences between classes of Cisco platform. Any of the attribute properties can be subdivided by platform type by using the platform type as a key. For example, interface VRF membership defaults to `""` (no VRF) on both Nexus and IOS XR platforms, but the CLI is `vrf member <vrf>` for Nexus and `vrf <vrf>` for IOS XR. Thus, the YAML could be written as:
195
243
 
196
244
  ```yaml
197
245
  # interface.yaml
198
246
  vrf:
199
247
  default_value: ""
200
- cli_nexus:
201
- config_get_token_append: '/^vrf member (.*)/'
202
- config_set_append: "<state> vrf member <vrf>"
203
- cli_ios_xr:
204
- config_get_token_append: '/^vrf (.*)/'
205
- config_set_append: "<state> vrf <vrf>"
248
+ nexus:
249
+ get_value: 'vrf member (.*)'
250
+ set_value: "<state> vrf member <vrf>"
251
+ ios_xr:
252
+ get_value: 'vrf (.*)'
253
+ set_value: "<state> vrf <vrf>"
206
254
  ```
207
255
 
208
256
  ### Product variants
209
257
 
210
- Any of the attribute properties can be subdivided by platform product ID string
211
- using a regexp against the product ID as a key. When one or more regexp keys
212
- are defined thus, you can also use the special key `else` to provide values
213
- for all products that do not match any of the given regexps:
258
+ Various product categories can also be used as keys to subdivide attributes as needed. Supported categories currently include the various Nexus switch product lines (`N3k`, `N5k`, `N6k`. `N7k`, `N9k`). When using one or more product keys in this fashion, you can also use the special key `else` to handle all other products not specifically called out:
214
259
 
215
260
  ```yaml
216
261
  # show_version.yaml
217
262
  system_image:
218
- /N9/:
219
- config_get_token: "kick_file_name"
220
- test_config_get_regex: '/.*NXOS image file is: (.*)$.*/'
263
+ N9k:
264
+ get_value: "kick_file_name"
221
265
  else:
222
- config_get_token: "isan_file_name"
223
- test_config_get_regex: '/.*system image file is: (.*)$.*/'
266
+ get_value: "isan_file_name"
224
267
  ```
225
268
 
226
269
  ### `_exclude`
@@ -230,7 +273,7 @@ Related to product variants, an `_exclude` entry can be used to mark an entire f
230
273
  ```yaml
231
274
  # fabricpath.yaml
232
275
  ---
233
- _exclude: [/N3/, /N9/]
276
+ _exclude: [N3k, N9k]
234
277
 
235
278
  _template:
236
279
  ...
@@ -241,221 +284,176 @@ Individual feature attributes can also be excluded in this way:
241
284
  ```yaml
242
285
  attribute:
243
286
  _exclude:
244
- - /N7/
287
+ - N7k
245
288
  default_value: true
246
- config_get: 'show attribute'
247
- config_set: 'attribute'
289
+ get_command: 'show attribute'
290
+ set_value: 'attribute'
248
291
  ```
249
292
 
250
293
  When a feature or attribute is excluded in this way, attempting to call `config_get` or `config_set` on an excluded node will result in a `Cisco::UnsupportedError` being raised. Calling `config_get_default` on such a node will always return `nil`.
251
294
 
295
+ ### YAML anchors and aliases
296
+
297
+ To reduce repetition, YAML provides the 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). A node anchor can be defined with the syntax `&anchor_name` and other nodes can alias against this anchor with the syntax `*anchor_name`. For example, to provide the same data for N3k and N9k platforms:
298
+
299
+ ```yaml
300
+ vn_segment_vlan_based:
301
+ # MT-lite only
302
+ N3k: &vn_segment_vlan_based_mt_lite
303
+ kind: boolean
304
+ config_get: 'show running section feature'
305
+ config_get_token: '/^feature vn-segment-vlan-based$/'
306
+ config_set: 'feature vn-segment-vlan-based'
307
+ default_value: false
308
+ N9k: *vn_segment_vlan_based_mt_lite
309
+ ```
310
+
252
311
  ### Combinations of these
253
312
 
254
313
  In many cases, supporting multiple platforms and multiple products will require
255
314
  using several or all of the above options.
256
315
 
257
- Using `_template` in combination with API variants:
316
+ Using `_template` in combination with platform and data format variants:
258
317
 
259
318
  ```yaml
260
319
  # inventory.yaml
261
320
  _template:
262
- cli_ios_xr:
263
- config_get: 'show inventory | begin "Rack 0"'
264
- test_config_get: 'show inventory'
265
- cli_nexus:
266
- config_get: 'show inventory'
267
- test_config_get: 'show inventory | no-more'
321
+ ios_xr:
322
+ get_command: 'show inventory | begin "Rack 0"'
323
+ get_data_format: cli
324
+ nexus:
325
+ get_command: 'show inventory'
326
+ get_data_format: nxapi_structured
268
327
 
269
328
  productid:
270
- cli_ios_xr:
271
- config_get_token: '/PID: ([^ ,]+)/'
272
- cli_nexus:
273
- config_get_token: ["TABLE_inv", "ROW_inv", 0, "productid"]
329
+ ios_xr:
330
+ get_value: '/PID: ([^ ,]+)/'
331
+ nexus:
332
+ get_context: ["TABLE_inv", "ROW_inv", 0]
333
+ get_value: "productid"
274
334
  ```
275
335
 
276
336
  Using platform variants and product variants together:
277
337
 
278
338
  ```yaml
279
- # inventory.yaml
280
- description:
281
- config_get_token: "chassis_id"
282
- cli_nexus:
283
- /N7/:
284
- test_config_get_regex: '/.*Hardware\n cisco (\w+ \w+ \(\w+ \w+\) \w+).*/'
339
+ # interface.yaml
340
+ negotiate_auto_portchannel:
341
+ kind: boolean
342
+ _exclude: [ios_xr]
343
+ nexus:
344
+ N7k:
345
+ default_only: false
285
346
  else:
286
- test_config_get_regex: '/Hardware\n cisco (([^(\n]+|\(\d+ Slot\))+\w+)/'
287
- cli_ios_xr:
288
- config_get: 'show inventory | inc "Rack 0"'
289
- config_get_token: '/DESCR: "(.*)"/'
290
- test_config_get: 'show inventory | inc "Rack 0"'
291
- test_config_get_regex: '/DESCR: "(.*)"/'
347
+ get_value: '(no )?negotiate auto'
348
+ set_value: "<state> negotiate auto"
349
+ default_value: true
292
350
  ```
293
351
 
294
352
  ## Attribute properties
295
353
 
296
- ### `config_get`
354
+ ### `get_data_format`
355
+
356
+ The `get_data_format` key is optionally used to specify which data format a given client should use for a get operation. Supported values are `cli` and `nxapi_structured`. If not specified, this key defaults to `cli`.
357
+
358
+ ```yaml
359
+ # inventory.yaml
360
+ productid:
361
+ get_command: 'show inventory'
362
+ nexus:
363
+ get_data_format: nxapi_structured
364
+ get_context: ['TABLE_inv', 'ROW_inv', 0]
365
+ ```
366
+
367
+ ### `get_command`
297
368
 
298
- `config_get` must be a single string representing the CLI command (usually a
369
+ `get_command` must be a single string representing the CLI command (usually a
299
370
  `show` command) to be used to display the information needed to get the
300
371
  current value of this attribute.
301
372
 
302
373
  ```yaml
303
374
  # interface_ospf.yaml
304
375
  area:
305
- config_get: 'show running interface all'
376
+ get_command: 'show running interface all'
306
377
  ```
307
378
 
308
- ### `config_get_token`
309
-
310
- `config_get_token` can be a single string, a single regex, an array of strings,
311
- or an array of regexs.
379
+ ### `get_context`
312
380
 
313
- If this value is a string or array of strings, then the `config_get` command
314
- will be executed to produce _structured_ output and the string(s) will be
315
- used as lookup keys.
381
+ `get_context` is an optional sequence of tokens used to filter the output from the `get_command` down to the desired context where the `get_value` can be found. For CLI properties, these tokens are implicitly Regexps used to filter down through the hierarchical CLI output, while for `nxapi_structured` properties, the tokens are used as string keys.
316
382
 
317
- **WARNING: structured output, although elegant, may not be supported for all commands or all platforms. Use with caution.**
318
-
319
- ```yaml
320
- # show_version.yaml
321
- cpu:
322
- config_get: 'show version'
323
- config_get_token: 'cpu_name'
324
- # config_get('show_version', 'cpu') returns structured_output['cpu_name']
325
- ```
326
383
 
327
384
  ```yaml
328
385
  # inventory.yaml
329
386
  productid:
330
- config_get: 'show inventory'
331
- config_get_token: ['TABLE_inv', 'ROW_inv', 0, 'productid']
332
- # config_get('inventory', 'productid') returns
333
- # structured_output['TABLE_inv']['ROW_inv'][0]['productid']
387
+ get_command: 'show inventory'
388
+ nexus:
389
+ get_data_format: nxapi_structured
390
+ get_context: ['TABLE_inv', 'ROW_inv', 0]
391
+ get_value: 'productid'
392
+ # config_get('inventory', 'productid') returns
393
+ # structured_output['TABLE_inv']['ROW_inv'][0]['productid']
334
394
  ```
335
395
 
336
- If this value is a regexp or array of regexps, then the `config_get` command
337
- will be executed to produce _plaintext_ output.
338
-
339
- For a single regexp, it will be used to match against the plaintext.
340
-
341
- ```yaml
342
- # memory.yaml
343
- total:
344
- config_get: 'show system resources'
345
- config_get_token: '/Memory.* (\S+) total/'
346
- # config_get('memory', 'total') returns
347
- # plaintext_output.scan(/Memory.* (\S+) total/)
348
- ```
349
-
350
- For an array of regex, then the plaintext is assumed to be hierarchical in
351
- nature (like `show running-config`) and the regexs are used to filter down
352
- through the hierarchy.
353
-
354
396
  ```yaml
355
397
  # interface.yaml
356
398
  description:
357
- config_get: 'show running interface all'
358
- config_get_token: ['/^interface <name>$/i', '/^description (.*)/']
359
- # config_get('interface', 'description', name: 'Ethernet1/1') gets the
360
- # plaintext output, finds the subsection under /^interface Ethernet1/1$/i,
361
- # then finds the line matching /^description (.*)$/ in that subsection
399
+ get_command: 'show running interface all'
400
+ ios_xr:
401
+ get_context: 'interface <name>'
402
+ get_value: '/^description (.*)/'
403
+ # config_get('interface', 'description', name: 'Ethernet1/1') gets the
404
+ # plaintext output, finds the subsection under /^interface Ethernet1/1$/i,
405
+ # then finds the line matching /^description (.*)$/ in that subsection
362
406
  ```
363
407
 
364
- ### `config_get_token_append`
408
+ If the context is defined using the recommended key-value wildcarding style, it is possible to define individual tokens as [optional](#optional-tokens-in-key-value-lists).
365
409
 
366
- When using a `_template` section, an attribute can use
367
- `config_get_token_append` to extend the `config_get_token` value provided by
368
- the template instead of replacing it:
369
-
370
- ```yaml
371
- # interface.yaml
372
- _template:
373
- config_get: 'show running-config interface all'
374
- config_get_token: '/^interface <name>$/i'
410
+ ### `get_value`
375
411
 
376
- description:
377
- config_get_token_append: '/^description (.*)$/'
378
- # config_get_token value for 'description' is now:
379
- # ['/^interface <name>$/i', '/^description (.*)$/']
380
- ```
412
+ `get_value` is the specific token used to locate the desired value. As with `get_context`, this is implicitly a Regexp for a CLI command, and implicitly a Hash key for a `nxapi_structured` command.
381
413
 
382
- This can also be used to specify conditional tokens which may or may not be
383
- used depending on the set of parameters passed into `config_get()`:
414
+ When using a `_template` section, a common pattern is to place the `get_context` in the template to be shared among all attributes, then have specific `get_value` defined for each individual attribute:
384
415
 
385
416
  ```yaml
386
- # ospf.yaml
417
+ # interface.yaml
387
418
  _template:
388
- config_get: 'show running ospf all'
389
- config_get_token: '/^router ospf <name>$/'
390
- config_get_token_append:
391
- - '/^vrf <vrf>$/'
392
-
393
- router_id:
394
- config_get_token_append: '/^router-id (\S+)$/'
395
- ```
419
+ get_command: 'show running-config interface all'
420
+ get_context: 'interface <name>'
396
421
 
397
- In this example, the `vrf` parameter is optional and a different
398
- `config_get_token` value will be generated depending on its presence or absence:
422
+ description:
423
+ get_value: '/^description (.*)$/'
399
424
 
400
- ```ruby
401
- irb(main):008:0> ref = cr.lookup('ospf', 'router_id')
402
- irb(main):012:0> ref.config_get_token(name: 'red')
403
- => [/^router ospf red$/, /^router-id (\S+)?$/]
404
- irb(main):013:0> ref.config_get_token(name: 'red', vrf: 'blue')
405
- => [/^router ospf red$/, /^vrf blue$/, /^router-id (\S+)?$/]
425
+ duplex:
426
+ get_value: 'duplex (.*)'
406
427
  ```
407
428
 
408
- ### `config_set`
429
+ ### `set_context`
409
430
 
410
- The `config_set` parameter is a string or array of strings representing the
411
- configuration CLI command(s) used to set the value of the attribute.
431
+ The optional `set_context` parameter is a sequence of strings representing the
432
+ configuration CLI command(s) used to enter the necessary configuration submode before configuring the attribute's `set_value`.
412
433
 
413
434
  ```yaml
414
435
  # interface.yaml
415
- create:
416
- config_set: 'interface <name>'
417
-
418
436
  description:
419
- config_set: ['interface <name>', 'description <desc>']
437
+ set_context: ['interface <name>']
438
+ set_value: 'description <desc>'
420
439
  ```
421
440
 
422
- ### `config_set_append`
441
+ If the context is defined using the recommended key-value wildcarding style, it is possible to define individual tokens as [optional](#optional-tokens-in-key-value-lists).
442
+
443
+ ### `set_value`
423
444
 
424
- When using a `_template` section, an attribute can use `config_set_append` to
425
- extend the `config_set` value provided by the template instead of replacing it:
445
+ `set_value` is the specific command used to set the desired attribute value. As with `get_value`, a common pattern is to specify a `set_context` in the `_template` section and specify `set_value` on a per-attribute basis:
426
446
 
427
447
  ```yaml
428
448
  # interface.yaml
429
449
  _template:
430
- config_set: 'interface <name>'
450
+ set_context: ['interface <name>']
431
451
 
432
452
  access_vlan:
433
- config_set_append: 'switchport access vlan <number>'
434
- # config_set value for 'access_vlan' is now:
435
- # ['interface <name>', 'switchport access vlan <number>']
436
- ```
437
-
438
- Much like `config_get_token_append`, this can also be used to specify optional
439
- commands that can be included or omitted as needed:
440
-
441
- ```yaml
442
- # ospf.yaml
443
- _template:
444
- config_set: 'router ospf <name>'
445
- config_set_append:
446
- - 'vrf <vrf>'
447
-
448
- router_id:
449
- config_set_append: 'router-id <router_id>'
450
- ```
453
+ set_value: 'switchport access vlan <number>'
451
454
 
452
- ```ruby
453
- irb(main):008:0> ref = cr.lookup('ospf', 'router_id')
454
- irb(main):017:0> ref.config_set(name: 'red', state: nil, router_id: '1.1.1.1')
455
- => ["router ospf red", " router-id 1.1.1.1"]
456
- irb(main):019:0> ref.config_set(name: 'red', vrf: 'blue',
457
- state: 'no', router_id: '1.1.1.1')
458
- => ["router ospf red", "vrf blue", "no router-id 1.1.1.1"]
455
+ description:
456
+ set_value: '<state> description <desc>'
459
457
  ```
460
458
 
461
459
  ### `default_value`
@@ -479,22 +477,22 @@ ipv4_address:
479
477
 
480
478
  By convention, a `default_value` of `''` (empty string) represents a configurable property that defaults to absent, while a default of `nil` (Ruby) or `~` (YAML) represents a property that has no meaningful default at all.
481
479
 
482
- `config_get()` will return the defined `default_value` if the defined `config_get_token` does not match anything on the node. Normally this is desirable behavior, but you can use [`auto_default`](#auto_default) to change this behavior if needed.
480
+ `config_get()` will return the defined `default_value` if the defined `get_value` does not match anything on the node. Normally this is desirable behavior, but you can use [`auto_default`](#auto_default) to change this behavior if needed.
483
481
 
484
482
  ### `default_only`
485
483
 
486
- Some attributes may be hard-coded in such a way that they have a meaningful default value but no relevant `config_get_token` or `config_set` behavior. For such attributes, the key `default_only` should be used as an alternative to `default_value`. The benefit of using this key is that it causes the `config_get()` API to always return the default value and `config_set()` to raise a `Cisco::UnsupportedError`.
484
+ Some attributes may be hard-coded in such a way that they have a meaningful default value but no relevant `get_value` or `set_value` behavior. For such attributes, the key `default_only` should be used as an alternative to `default_value`. The benefit of using this key is that it causes the `config_get()` API to always return the default value and `config_set()` to raise a `Cisco::UnsupportedError`.
487
485
 
488
486
  ```yaml
489
487
  negotiate_auto_ethernet:
490
488
  kind: boolean
491
- cli_nexus:
489
+ nexus:
492
490
  /(N7|C3064)/:
493
491
  # this feature is always off on these platforms and cannot be changed
494
492
  default_only: false
495
493
  else:
496
- config_get_token_append: '/^(no )?negotiate auto$/'
497
- config_set_append: "%s negotiate auto"
494
+ get_value: '(no )?negotiate auto'
495
+ set_value: "%s negotiate auto"
498
496
  default_value: true
499
497
  ```
500
498
 
@@ -510,39 +508,39 @@ The `kind` attribute is used to specify the type of value that is returned by `c
510
508
  # interface.yaml
511
509
  ---
512
510
  access_vlan:
513
- config_get_token_append: '/^switchport access vlan (.*)$/'
514
- config_set_append: "switchport access vlan %s"
511
+ get_value: 'switchport access vlan (.*)'
512
+ set_value: "switchport access vlan <vlan>"
515
513
  kind: int
516
514
  default_value: 1
517
515
 
518
516
  description:
519
517
  kind: string
520
- config_get_token_append: '/^description (.*)/'
521
- config_set_append: "%s description %s"
518
+ get_value: 'description (.*)'
519
+ set_value: "<state> description <desc>"
522
520
  default_value: ""
523
521
 
524
522
  feature_lacp:
525
523
  kind: boolean
526
- config_get: "show running | i ^feature"
527
- config_get_token: '/^feature lacp$/'
528
- config_set: "%s feature lacp"
524
+ get_command: "show running | i ^feature"
525
+ get_value: 'feature lacp'
526
+ set_value: "<state> feature lacp"
529
527
  ```
530
528
 
531
529
  ### `multiple`
532
530
 
533
- By default, `config_get_token` should uniquely identify a single configuration entry, and `config_get()` will raise an error if more than one match is found. For a small number of attributes, it may be desirable to permit multiple matches (in particular, '`all_*`' attributes that are used up to look up all interfaces, all VRFs, etc.). For such attributes, you must specify the key `multiple:`. When this key is present, `config_get()` will permit multiple matches and will return an array of matches (even if there is only a single match).
531
+ By default, `get_value` should uniquely identify a single configuration entry, and `config_get()` will raise an error if more than one match is found. For a small number of attributes, it may be desirable to permit multiple matches (in particular, '`all_*`' attributes that are used up to look up all interfaces, all VRFs, etc.). For such attributes, you must specify the key `multiple:`. When this key is present, `config_get()` will permit multiple matches and will return an array of matches (even if there is only a single match).
534
532
 
535
533
  ```yaml
536
534
  # interface.yaml
537
535
  ---
538
536
  all_interfaces:
539
537
  multiple:
540
- config_get_token: '/^interface (.*)/'
538
+ get_value: 'interface (.*)'
541
539
  ```
542
540
 
543
541
  ### `auto_default`
544
542
 
545
- Normally, if `config_get_token` produces no match, `config_get()` will return the defined `default_value` for this attribute. For some attributes, this may not be desirable. Setting `auto_default: false` will force `config_get()` to return `nil` in the non-matching case instead.
543
+ Normally, if `get_value` produces no match, `config_get()` will return the defined `default_value` for this attribute. For some attributes, this may not be desirable. Setting `auto_default: false` will force `config_get()` to return `nil` in the non-matching case instead.
546
544
 
547
545
  ```yaml
548
546
  # bgp_af.yaml
@@ -554,38 +552,8 @@ dampen_igp_metric:
554
552
  default_value: 600
555
553
  auto_default: false
556
554
  kind: int
557
- config_get_token_append: '/^dampen-igp-metric (\d+)$/'
558
- config_set_append: '<state> dampen-igp-metric <num>'
559
- ```
560
-
561
- ### `test_config_get` and `test_config_get_regex`
562
-
563
- Test-only equivalents to `config_get` and `config_get_token` - a show command
564
- to be executed over telnet by the minitest unit test scripts, and a regex
565
- (or array thereof) to match in the resulting plaintext output.
566
- Should only be referenced by test scripts, never by a feature provider itself.
567
-
568
- ```yaml
569
- # show_version.yaml
570
- boot_image:
571
- test_config_get: 'show version | no-more'
572
- test_config_get_regex: '/NXOS image file is: (.*)$/'
573
- ```
574
-
575
- ### `test_config_result`
576
-
577
- Test-only container for input-result pairs that might differ by platform.
578
- Should only be referenced by test scripts, never by a feature provider itself.
579
-
580
- ```yaml
581
- # vtp.yaml
582
- version:
583
- /N7/:
584
- test_config_result:
585
- 3: 3
586
- else:
587
- test_config_result:
588
- 3: 'Cisco::CliError'
555
+ get_value: 'dampen-igp-metric (\d+)'
556
+ set_value: '<state> dampen-igp-metric <num>'
589
557
  ```
590
558
 
591
559
  ## Style Guide