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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rspec +2 -0
- data/.rubocop.yml +13 -0
- data/.travis.yml +4 -1
- data/CHANGELOG.md +81 -2
- data/CONTRIBUTING.md +2 -17
- data/Gemfile +5 -0
- data/README.md +92 -47
- data/Rakefile +23 -1
- data/bin/git/hooks/hook_lib +7 -0
- data/bin/git/hooks/pre-commit/check_unstaged_changes +18 -0
- data/bin/git/hooks/pre-commit/rubocop +7 -2
- data/bin/git/hooks/pre-commit/validate-diffs +18 -4
- data/bin/git/hooks/pre-commit/validate-yaml +18 -0
- data/bin/git/update-hooks +64 -6
- data/cisco_node_utils.gemspec +9 -6
- data/docs/README-develop-best-practices.md +149 -50
- data/docs/README-develop-node-utils-APIs.md +92 -42
- data/docs/README-maintainers.md +7 -4
- data/docs/README-test-execution.md +57 -0
- data/docs/cisco_node_utils.yaml.example +30 -0
- data/docs/template-router.rb +4 -0
- data/ext/mkrf_conf.rb +63 -0
- data/lib/.rubocop.yml +2 -2
- data/lib/cisco_node_utils.rb +5 -0
- data/lib/cisco_node_utils/aaa_authentication_login.rb +5 -6
- data/lib/cisco_node_utils/aaa_authorization_service.rb +1 -1
- data/lib/cisco_node_utils/ace.rb +165 -12
- data/lib/cisco_node_utils/acl.rb +2 -1
- data/lib/cisco_node_utils/bgp.rb +184 -21
- data/lib/cisco_node_utils/bgp_af.rb +94 -249
- data/lib/cisco_node_utils/bgp_neighbor.rb +94 -14
- data/lib/cisco_node_utils/bgp_neighbor_af.rb +75 -8
- data/lib/cisco_node_utils/bridge_domain.rb +183 -0
- data/lib/cisco_node_utils/bridge_domain_vni.rb +206 -0
- data/lib/cisco_node_utils/cisco_cmn_utils.rb +85 -2
- data/lib/cisco_node_utils/client.rb +35 -0
- data/lib/cisco_node_utils/client/client.rb +234 -0
- data/lib/cisco_node_utils/client/grpc.rb +33 -0
- data/lib/cisco_node_utils/client/grpc/client.rb +311 -0
- data/lib/cisco_node_utils/client/grpc/ems.proto +148 -0
- data/lib/cisco_node_utils/client/grpc/ems.rb +111 -0
- data/lib/cisco_node_utils/client/grpc/ems_services.rb +49 -0
- data/lib/cisco_node_utils/client/nxapi.rb +31 -0
- data/lib/cisco_node_utils/client/nxapi/client.rb +305 -0
- data/lib/cisco_node_utils/client/utils.rb +164 -0
- data/lib/cisco_node_utils/cmd_ref/README_YAML.md +222 -254
- data/lib/cisco_node_utils/cmd_ref/aaa_auth_login_service.yaml +11 -8
- data/lib/cisco_node_utils/cmd_ref/aaa_authentication_login.yaml +22 -15
- data/lib/cisco_node_utils/cmd_ref/aaa_authorization_service.yaml +11 -8
- data/lib/cisco_node_utils/cmd_ref/acl.yaml +21 -16
- data/lib/cisco_node_utils/cmd_ref/bgp.yaml +239 -109
- data/lib/cisco_node_utils/cmd_ref/bgp_af.yaml +114 -55
- data/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml +76 -52
- data/lib/cisco_node_utils/cmd_ref/bgp_neighbor_af.yaml +106 -62
- data/lib/cisco_node_utils/cmd_ref/bridge_domain.yaml +71 -0
- data/lib/cisco_node_utils/cmd_ref/bridge_domain_vni.yaml +33 -0
- data/lib/cisco_node_utils/cmd_ref/dnsclient.yaml +35 -14
- data/lib/cisco_node_utils/cmd_ref/encapsulation.yaml +25 -0
- data/lib/cisco_node_utils/cmd_ref/evpn_vni.yaml +23 -17
- data/lib/cisco_node_utils/cmd_ref/fabricpath.yaml +94 -83
- data/lib/cisco_node_utils/cmd_ref/fabricpath_topology.yaml +22 -17
- data/lib/cisco_node_utils/cmd_ref/feature.yaml +76 -26
- data/lib/cisco_node_utils/cmd_ref/images.yaml +3 -2
- data/lib/cisco_node_utils/cmd_ref/interface.yaml +381 -153
- data/lib/cisco_node_utils/cmd_ref/interface_channel_group.yaml +21 -11
- data/lib/cisco_node_utils/cmd_ref/interface_ospf.yaml +21 -21
- data/lib/cisco_node_utils/cmd_ref/interface_portchannel.yaml +30 -21
- data/lib/cisco_node_utils/cmd_ref/interface_service_vni.yaml +18 -13
- data/lib/cisco_node_utils/cmd_ref/inventory.yaml +26 -31
- data/lib/cisco_node_utils/cmd_ref/itd_device_group.yaml +83 -0
- data/lib/cisco_node_utils/cmd_ref/itd_service.yaml +119 -0
- data/lib/cisco_node_utils/cmd_ref/memory.yaml +17 -6
- data/lib/cisco_node_utils/cmd_ref/ntp_config.yaml +10 -3
- data/lib/cisco_node_utils/cmd_ref/ntp_server.yaml +17 -5
- data/lib/cisco_node_utils/cmd_ref/ospf.yaml +33 -29
- data/lib/cisco_node_utils/cmd_ref/overlay_global.yaml +12 -10
- data/lib/cisco_node_utils/cmd_ref/pim.yaml +16 -19
- data/lib/cisco_node_utils/cmd_ref/portchannel_global.yaml +40 -25
- data/lib/cisco_node_utils/cmd_ref/radius_global.yaml +17 -12
- data/lib/cisco_node_utils/cmd_ref/radius_server.yaml +71 -35
- data/lib/cisco_node_utils/cmd_ref/radius_server_group.yaml +10 -5
- data/lib/cisco_node_utils/cmd_ref/show_system.yaml +6 -2
- data/lib/cisco_node_utils/cmd_ref/show_version.yaml +47 -43
- data/lib/cisco_node_utils/cmd_ref/snmp_community.yaml +13 -11
- data/lib/cisco_node_utils/cmd_ref/snmp_group.yaml +4 -2
- data/lib/cisco_node_utils/cmd_ref/snmp_notification_receiver.yaml +23 -21
- data/lib/cisco_node_utils/cmd_ref/snmp_server.yaml +26 -22
- data/lib/cisco_node_utils/cmd_ref/snmp_user.yaml +19 -17
- data/lib/cisco_node_utils/cmd_ref/snmpnotification.yaml +18 -6
- data/lib/cisco_node_utils/cmd_ref/stp_global.yaml +234 -0
- data/lib/cisco_node_utils/cmd_ref/syslog_server.yaml +24 -9
- data/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml +5 -3
- data/lib/cisco_node_utils/cmd_ref/system.yaml +4 -3
- data/lib/cisco_node_utils/cmd_ref/tacacs_server.yaml +22 -20
- data/lib/cisco_node_utils/cmd_ref/tacacs_server_group.yaml +27 -15
- data/lib/cisco_node_utils/cmd_ref/tacacs_server_host.yaml +45 -16
- data/lib/cisco_node_utils/cmd_ref/vdc.yaml +21 -11
- data/lib/cisco_node_utils/cmd_ref/virtual_service.yaml +3 -2
- data/lib/cisco_node_utils/cmd_ref/vlan.yaml +60 -32
- data/lib/cisco_node_utils/cmd_ref/vpc.yaml +118 -101
- data/lib/cisco_node_utils/cmd_ref/vrf.yaml +54 -58
- data/lib/cisco_node_utils/cmd_ref/vrf_af.yaml +118 -0
- data/lib/cisco_node_utils/cmd_ref/vtp.yaml +19 -25
- data/lib/cisco_node_utils/cmd_ref/vxlan_vtep.yaml +28 -18
- data/lib/cisco_node_utils/cmd_ref/vxlan_vtep_vni.yaml +34 -17
- data/lib/cisco_node_utils/cmd_ref/yum.yaml +6 -4
- data/lib/cisco_node_utils/command_reference.rb +261 -142
- data/lib/cisco_node_utils/constants.rb +33 -0
- data/lib/cisco_node_utils/encapsulation.rb +112 -0
- data/lib/cisco_node_utils/environment.rb +102 -0
- data/lib/cisco_node_utils/evpn_vni.rb +5 -3
- data/lib/cisco_node_utils/exceptions.rb +111 -0
- data/lib/cisco_node_utils/fabricpath_global.rb +52 -35
- data/lib/cisco_node_utils/fabricpath_topology.rb +44 -57
- data/lib/cisco_node_utils/feature.rb +165 -3
- data/lib/cisco_node_utils/interface.rb +1051 -260
- data/lib/cisco_node_utils/interface_channel_group.rb +11 -10
- data/lib/cisco_node_utils/interface_ospf.rb +1 -2
- data/lib/cisco_node_utils/interface_portchannel.rb +4 -12
- data/lib/cisco_node_utils/interface_service_vni.rb +7 -7
- data/lib/cisco_node_utils/itd_device_group.rb +248 -0
- data/lib/cisco_node_utils/itd_device_group_node.rb +144 -0
- data/lib/cisco_node_utils/itd_service.rb +523 -0
- data/lib/cisco_node_utils/logger.rb +75 -0
- data/lib/cisco_node_utils/node.rb +62 -192
- data/lib/cisco_node_utils/node_util.rb +56 -10
- data/lib/cisco_node_utils/overlay_global.rb +2 -2
- data/lib/cisco_node_utils/pim.rb +2 -13
- data/lib/cisco_node_utils/pim_group_list.rb +1 -1
- data/lib/cisco_node_utils/pim_rp_address.rb +1 -1
- data/lib/cisco_node_utils/platform.rb +52 -21
- data/lib/cisco_node_utils/portchannel_global.rb +89 -19
- data/lib/cisco_node_utils/radius_server.rb +168 -37
- data/lib/cisco_node_utils/router_ospf.rb +20 -35
- data/lib/cisco_node_utils/router_ospf_vrf.rb +4 -4
- data/lib/cisco_node_utils/snmpserver.rb +1 -6
- data/lib/cisco_node_utils/snmpuser.rb +6 -4
- data/lib/cisco_node_utils/stp_global.rb +676 -0
- data/lib/cisco_node_utils/syslog_server.rb +77 -18
- data/lib/cisco_node_utils/syslog_settings.rb +1 -1
- data/lib/cisco_node_utils/tacacs_server_group.rb +8 -4
- data/lib/cisco_node_utils/tacacs_server_host.rb +115 -25
- data/lib/cisco_node_utils/vdc.rb +12 -0
- data/lib/cisco_node_utils/version.rb +1 -1
- data/lib/cisco_node_utils/vlan.rb +147 -29
- data/lib/cisco_node_utils/vpc.rb +55 -3
- data/lib/cisco_node_utils/vrf.rb +72 -11
- data/lib/cisco_node_utils/vrf_af.rb +114 -29
- data/lib/cisco_node_utils/vtp.rb +34 -52
- data/lib/cisco_node_utils/vxlan_vtep.rb +34 -8
- data/lib/cisco_node_utils/vxlan_vtep_vni.rb +36 -4
- data/lib/minitest/environment_plugin.rb +31 -0
- data/lib/minitest/log_level_plugin.rb +41 -0
- data/spec/client_spec.rb +7 -0
- data/spec/environment_spec.rb +263 -0
- data/spec/grpc_client_spec.rb +23 -0
- data/spec/isolate/all_clients_spec.rb +9 -0
- data/spec/isolate/grpc_only_spec.rb +16 -0
- data/spec/isolate/no_clients_spec.rb +26 -0
- data/spec/isolate/nxapi_only_spec.rb +16 -0
- data/spec/nxapi_client_spec.rb +42 -0
- data/spec/schema.yaml +75 -0
- data/spec/shared_examples_for_clients.rb +14 -0
- data/spec/spec_helper.rb +91 -0
- data/spec/whitespace_spec.rb +10 -0
- data/spec/yaml_spec.rb +42 -0
- data/tests/.rubocop.yml +2 -2
- data/tests/CSCuxdublin-1.0.0-7.0.3.I3.1.lib32_n9000.rpm +0 -0
- data/tests/basetest.rb +96 -36
- data/tests/ciscotest.rb +220 -12
- data/tests/cmd_config.yaml +71 -49
- data/tests/cmd_config_invalid.yaml +1 -1
- data/tests/test_aaa_authentication_login.rb +1 -0
- data/tests/test_aaa_authentication_login_service.rb +9 -0
- data/tests/test_aaa_authorization_service.rb +173 -367
- data/tests/test_ace.rb +171 -100
- data/tests/test_acl.rb +10 -1
- data/tests/test_bgp_af.rb +395 -728
- data/tests/test_bgp_neighbor.rb +274 -115
- data/tests/test_bgp_neighbor_af.rb +178 -77
- data/tests/test_bridge_domain.rb +191 -0
- data/tests/test_bridge_domain_vni.rb +116 -0
- data/tests/test_client_utils.rb +111 -0
- data/tests/test_command_config.rb +9 -5
- data/tests/test_command_reference.rb +380 -102
- data/tests/test_dns_domain.rb +13 -3
- data/tests/test_domain_name.rb +13 -3
- data/tests/test_encapsulation.rb +77 -0
- data/tests/test_evpn_vni.rb +25 -7
- data/tests/test_fabricpath_global.rb +167 -163
- data/tests/test_fabricpath_topology.rb +12 -33
- data/tests/test_feature.rb +215 -0
- data/tests/test_grpc.rb +166 -0
- data/tests/test_interface.rb +585 -344
- data/tests/test_interface_bdi.rb +80 -0
- data/tests/test_interface_channel_group.rb +6 -3
- data/tests/test_interface_ospf.rb +26 -24
- data/tests/test_interface_portchannel.rb +1 -0
- data/tests/test_interface_private_vlan.rb +724 -0
- data/tests/test_interface_service_vni.rb +37 -66
- data/tests/test_interface_svi.rb +98 -101
- data/tests/test_interface_switchport.rb +419 -549
- data/tests/test_itd_device_group.rb +145 -0
- data/tests/test_itd_device_group_node.rb +199 -0
- data/tests/test_itd_service.rb +298 -0
- data/tests/test_logger.rb +43 -0
- data/tests/test_name_server.rb +11 -2
- data/tests/test_node.rb +16 -75
- data/tests/test_node_ext.rb +174 -163
- data/tests/test_node_util.rb +119 -0
- data/tests/test_ntp_config.rb +5 -1
- data/tests/test_ntp_server.rb +2 -2
- data/tests/test_nxapi.rb +221 -0
- data/tests/test_overlay_global.rb +47 -38
- data/tests/test_pim.rb +2 -0
- data/tests/test_pim_group_list.rb +2 -0
- data/tests/test_pim_rp_address.rb +2 -0
- data/tests/test_platform.rb +86 -39
- data/tests/test_portchannel_global.rb +211 -135
- data/tests/test_radius_global.rb +13 -5
- data/tests/test_radius_server.rb +256 -104
- data/tests/test_radius_server_group.rb +2 -0
- data/tests/test_router_bgp.rb +781 -485
- data/tests/test_router_ospf.rb +26 -103
- data/tests/test_router_ospf_vrf.rb +52 -57
- data/tests/test_snmp_notification_receiver.rb +2 -0
- data/tests/test_snmpcommunity.rb +2 -0
- data/tests/test_snmpgroup.rb +2 -0
- data/tests/test_snmpnotification.rb +40 -21
- data/tests/test_snmpserver.rb +2 -0
- data/tests/test_snmpuser.rb +2 -0
- data/tests/test_stp_global.rb +563 -0
- data/tests/test_syslog_server.rb +32 -8
- data/tests/test_syslog_settings.rb +22 -9
- data/tests/test_tacacs_server.rb +32 -27
- data/tests/test_tacacs_server_group.rb +100 -45
- data/tests/test_tacacs_server_host.rb +135 -43
- data/tests/test_vdc.rb +2 -16
- data/tests/test_vlan.rb +106 -54
- data/tests/test_vlan_mt_full.rb +11 -21
- data/tests/test_vlan_private.rb +669 -0
- data/tests/test_vpc.rb +312 -159
- data/tests/test_vrf.rb +122 -113
- data/tests/test_vrf_af.rb +238 -0
- data/tests/test_vtp.rb +58 -102
- data/tests/test_vxlan_vtep.rb +38 -17
- data/tests/test_vxlan_vtep_vni.rb +61 -9
- data/tests/test_yum.rb +49 -25
- metadata +122 -36
- data/lib/cisco_node_utils/cmd_ref/fex.yaml +0 -9
- data/lib/cisco_node_utils/cmd_ref/vni.yaml +0 -76
- data/lib/cisco_node_utils/vni.rb +0 -227
- 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
|
-
* [
|
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
|
-
* [`
|
23
|
-
* [`
|
24
|
-
* [`
|
25
|
-
* [`
|
26
|
-
* [`
|
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
|
-
|
63
|
-
|
64
|
-
|
64
|
+
get_command: "show vtp status"
|
65
|
+
get_value: "domain_name"
|
66
|
+
set_value: "vtp domain <domain>"
|
65
67
|
|
66
68
|
filename:
|
67
|
-
|
68
|
-
|
69
|
-
|
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 `
|
83
|
-
|
84
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
125
|
-
|
126
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
147
|
-
|
148
|
-
|
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
|
-
|
152
|
-
|
191
|
+
get_value: 'switchport access vlan (.*)'
|
192
|
+
set_value: 'switchport access vlan <number>'
|
153
193
|
|
154
194
|
description:
|
155
|
-
|
156
|
-
|
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
|
-
|
167
|
-
|
168
|
-
|
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
|
-
|
172
|
-
|
173
|
-
|
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
|
-
###
|
222
|
+
### Data format variants
|
179
223
|
|
180
|
-
Clients for different Cisco platforms may use different
|
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
|
-
|
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
|
-
#
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
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
|
-
|
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
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
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
|
-
|
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
|
-
|
219
|
-
|
220
|
-
test_config_get_regex: '/.*NXOS image file is: (.*)$.*/'
|
263
|
+
N9k:
|
264
|
+
get_value: "kick_file_name"
|
221
265
|
else:
|
222
|
-
|
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: [
|
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
|
-
-
|
287
|
+
- N7k
|
245
288
|
default_value: true
|
246
|
-
|
247
|
-
|
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
|
316
|
+
Using `_template` in combination with platform and data format variants:
|
258
317
|
|
259
318
|
```yaml
|
260
319
|
# inventory.yaml
|
261
320
|
_template:
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
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
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
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
|
-
#
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
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
|
-
|
287
|
-
|
288
|
-
|
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
|
-
### `
|
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
|
-
`
|
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
|
-
|
376
|
+
get_command: 'show running interface all'
|
306
377
|
```
|
307
378
|
|
308
|
-
### `
|
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
|
-
|
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
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
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
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
#
|
417
|
+
# interface.yaml
|
387
418
|
_template:
|
388
|
-
|
389
|
-
|
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
|
-
|
398
|
-
|
422
|
+
description:
|
423
|
+
get_value: '/^description (.*)$/'
|
399
424
|
|
400
|
-
|
401
|
-
|
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
|
-
### `
|
429
|
+
### `set_context`
|
409
430
|
|
410
|
-
The `
|
411
|
-
configuration CLI command(s) used to
|
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
|
-
|
437
|
+
set_context: ['interface <name>']
|
438
|
+
set_value: 'description <desc>'
|
420
439
|
```
|
421
440
|
|
422
|
-
|
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
|
-
|
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
|
-
|
450
|
+
set_context: ['interface <name>']
|
431
451
|
|
432
452
|
access_vlan:
|
433
|
-
|
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
|
-
|
453
|
-
|
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 `
|
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 `
|
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
|
-
|
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
|
-
|
497
|
-
|
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
|
-
|
514
|
-
|
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
|
-
|
521
|
-
|
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
|
-
|
527
|
-
|
528
|
-
|
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, `
|
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
|
-
|
538
|
+
get_value: 'interface (.*)'
|
541
539
|
```
|
542
540
|
|
543
541
|
### `auto_default`
|
544
542
|
|
545
|
-
Normally, if `
|
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
|
-
|
558
|
-
|
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
|