cisco_node_utils 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.rubocop.yml +81 -1
- data/.travis.yml +9 -0
- data/CHANGELOG.md +72 -6
- data/CONTRIBUTING.md +32 -7
- data/README.md +70 -7
- data/Rakefile +17 -0
- data/bin/check_metric_limits.rb +109 -0
- data/bin/git/hooks/commit-msg/enforce_style +81 -0
- data/bin/git/hooks/hook_lib +108 -0
- data/bin/git/hooks/hooks-wrapper +38 -0
- data/bin/git/hooks/post-flow-hotfix-start/update-version +24 -0
- data/bin/git/hooks/post-flow-release-finish/update-version +29 -0
- data/bin/git/hooks/post-flow-release-start/update-version +19 -0
- data/bin/git/hooks/post-merge/update-hooks +6 -0
- data/bin/git/hooks/post-rewrite/update-hooks +6 -0
- data/bin/git/hooks/pre-commit/rubocop +20 -0
- data/bin/git/hooks/pre-commit/validate-diffs +31 -0
- data/bin/git/hooks/pre-push/check-changelog +24 -0
- data/bin/git/hooks/pre-push/rubocop +7 -0
- data/bin/git/update-hooks +65 -0
- data/cisco_node_utils.gemspec +9 -3
- data/docs/README-develop-best-practices.md +404 -0
- data/docs/README-develop-node-utils-APIs.md +215 -365
- data/docs/README-maintainers.md +33 -3
- data/docs/template-router.rb +89 -91
- data/docs/template-test_router.rb +52 -55
- data/lib/.rubocop.yml +18 -0
- data/lib/cisco_node_utils.rb +2 -19
- data/lib/cisco_node_utils/README_YAML.md +1 -9
- data/lib/cisco_node_utils/bgp.rb +664 -0
- data/lib/cisco_node_utils/bgp_af.rb +530 -0
- data/lib/cisco_node_utils/bgp_neighbor.rb +425 -0
- data/lib/cisco_node_utils/bgp_neighbor_af.rb +709 -0
- data/lib/cisco_node_utils/cisco_cmn_utils.rb +59 -25
- data/lib/cisco_node_utils/command_reference.rb +72 -74
- data/lib/cisco_node_utils/command_reference_common.yaml +174 -9
- data/lib/cisco_node_utils/command_reference_common_bgp.yaml +535 -0
- data/lib/cisco_node_utils/command_reference_n7k.yaml +4 -0
- data/lib/cisco_node_utils/command_reference_n9k.yaml +0 -9
- data/lib/cisco_node_utils/configparser_lib.rb +152 -147
- data/lib/cisco_node_utils/dns_domain.rb +79 -0
- data/lib/cisco_node_utils/domain_name.rb +71 -0
- data/lib/cisco_node_utils/interface.rb +167 -161
- data/lib/cisco_node_utils/interface_ospf.rb +78 -81
- data/lib/cisco_node_utils/name_server.rb +64 -0
- data/lib/cisco_node_utils/node.rb +154 -198
- data/lib/cisco_node_utils/node_util.rb +61 -0
- data/lib/cisco_node_utils/ntp_config.rb +65 -0
- data/lib/cisco_node_utils/ntp_server.rb +76 -0
- data/lib/cisco_node_utils/platform.rb +174 -165
- data/lib/cisco_node_utils/radius_global.rb +146 -0
- data/lib/cisco_node_utils/radius_server.rb +295 -0
- data/lib/cisco_node_utils/router_ospf.rb +59 -63
- data/lib/cisco_node_utils/router_ospf_vrf.rb +226 -210
- data/lib/cisco_node_utils/snmpcommunity.rb +52 -58
- data/lib/cisco_node_utils/snmpgroup.rb +22 -23
- data/lib/cisco_node_utils/snmpserver.rb +99 -103
- data/lib/cisco_node_utils/snmpuser.rb +294 -274
- data/lib/cisco_node_utils/syslog_server.rb +92 -0
- data/lib/cisco_node_utils/syslog_settings.rb +69 -0
- data/lib/cisco_node_utils/tacacs_server.rb +137 -133
- data/lib/cisco_node_utils/tacacs_server_host.rb +84 -87
- data/lib/cisco_node_utils/version.rb +2 -1
- data/lib/cisco_node_utils/vlan.rb +28 -31
- data/lib/cisco_node_utils/vrf.rb +80 -0
- data/lib/cisco_node_utils/vtp.rb +100 -97
- data/lib/cisco_node_utils/yum.rb +15 -17
- data/tests/.rubocop.yml +15 -0
- data/tests/basetest.rb +81 -36
- data/tests/ciscotest.rb +38 -78
- data/{lib/cisco_node_utils → tests}/platform_info.rb +12 -8
- data/{lib/cisco_node_utils → tests}/platform_info.yaml +1 -1
- data/tests/test_bgp_af.rb +920 -0
- data/tests/test_bgp_neighbor.rb +403 -0
- data/tests/test_bgp_neighbor_af.rb +589 -0
- data/tests/test_command_config.rb +65 -62
- data/tests/test_command_reference.rb +31 -45
- data/tests/test_dns_domain.rb +113 -0
- data/tests/test_domain_name.rb +86 -0
- data/tests/test_interface.rb +424 -548
- data/tests/test_interface_ospf.rb +248 -432
- data/tests/test_interface_svi.rb +56 -79
- data/tests/test_interface_switchport.rb +196 -272
- data/tests/test_name_server.rb +85 -0
- data/tests/test_node.rb +7 -6
- data/tests/test_node_ext.rb +133 -186
- data/tests/test_ntp_config.rb +49 -0
- data/tests/test_ntp_server.rb +74 -0
- data/tests/test_platform.rb +58 -37
- data/tests/test_radius_global.rb +78 -0
- data/tests/test_radius_server.rb +185 -0
- data/tests/test_router_bgp.rb +838 -0
- data/tests/test_router_ospf.rb +49 -80
- data/tests/test_router_ospf_vrf.rb +274 -392
- data/tests/test_snmpcommunity.rb +128 -172
- data/tests/test_snmpgroup.rb +12 -14
- data/tests/test_snmpserver.rb +160 -189
- data/tests/test_snmpuser.rb +568 -717
- data/tests/test_syslog_server.rb +88 -0
- data/tests/test_syslog_settings.rb +54 -0
- data/tests/test_tacacs_server.rb +113 -148
- data/tests/test_tacacs_server_host.rb +108 -161
- data/tests/test_vlan.rb +63 -79
- data/tests/test_vrf.rb +92 -0
- data/tests/test_vtp.rb +108 -126
- data/tests/test_yum.rb +47 -41
- metadata +92 -56
- data/.rubocop_todo.yml +0 -293
- data/docs/.rubocop.yml +0 -13
- data/docs/template-feature.rb +0 -45
- data/docs/template-test_feature.rb +0 -51
- data/tests/test_all_cisco.rb +0 -46
|
@@ -14,52 +14,55 @@
|
|
|
14
14
|
# See the License for the specific language governing permissions and
|
|
15
15
|
# limitations under the License.
|
|
16
16
|
|
|
17
|
+
# Add some general-purpose constants and APIs to the Cisco namespace
|
|
17
18
|
module Cisco
|
|
18
19
|
# global constants
|
|
19
20
|
DEFAULT_INSTANCE_NAME = 'default'
|
|
20
21
|
|
|
22
|
+
# Encryption - helper class for translating encryption type CLI
|
|
21
23
|
class Encryption
|
|
22
24
|
# password encryption types
|
|
23
|
-
def
|
|
25
|
+
def self.cli_to_symbol(cli)
|
|
24
26
|
case cli
|
|
25
|
-
when
|
|
27
|
+
when '0', 0
|
|
26
28
|
:cleartext
|
|
27
|
-
when
|
|
28
|
-
:"3des"
|
|
29
|
-
when
|
|
29
|
+
when '3', 3
|
|
30
|
+
:"3des" # yuck :-(
|
|
31
|
+
when '5', 5
|
|
30
32
|
:md5
|
|
31
|
-
when
|
|
33
|
+
when '6', 6
|
|
32
34
|
:aes
|
|
33
|
-
when
|
|
35
|
+
when '7', 7
|
|
34
36
|
:cisco_type_7
|
|
35
37
|
else
|
|
36
|
-
|
|
38
|
+
fail KeyError
|
|
37
39
|
end
|
|
38
40
|
end
|
|
39
41
|
|
|
40
|
-
def
|
|
42
|
+
def self.symbol_to_cli(symbol)
|
|
41
43
|
symbol = symbol.downcase if symbol.is_a? String
|
|
42
44
|
case symbol
|
|
43
|
-
when :cleartext, :none,
|
|
44
|
-
|
|
45
|
-
when :"3des",
|
|
46
|
-
|
|
47
|
-
when :md5,
|
|
48
|
-
|
|
49
|
-
when :aes,
|
|
50
|
-
|
|
51
|
-
when :cisco_type_7, :type_7,
|
|
52
|
-
|
|
45
|
+
when :cleartext, :none, 'cleartext', 'none', '0', 0
|
|
46
|
+
'0'
|
|
47
|
+
when :"3des", '3des', '3', 3
|
|
48
|
+
'3'
|
|
49
|
+
when :md5, 'md5', '5', 5
|
|
50
|
+
'5'
|
|
51
|
+
when :aes, 'aes', '6', 6
|
|
52
|
+
'6'
|
|
53
|
+
when :cisco_type_7, :type_7, 'cisco_type_7', 'type_7', '7', 7
|
|
54
|
+
'7'
|
|
53
55
|
else
|
|
54
|
-
|
|
56
|
+
fail KeyError
|
|
55
57
|
end
|
|
56
58
|
end
|
|
57
59
|
end
|
|
58
60
|
|
|
61
|
+
# ChefUtils - helper class for Chef code generation
|
|
59
62
|
class ChefUtils
|
|
60
|
-
def
|
|
63
|
+
def self.generic_prop_set(klass, rlbname, props)
|
|
61
64
|
props.each do |prop|
|
|
62
|
-
klass.instance_eval
|
|
65
|
+
klass.instance_eval do
|
|
63
66
|
# Helper Chef setter method, e.g.:
|
|
64
67
|
# if @new_resource.foo.nil?
|
|
65
68
|
# def_prop = @rlb.default_foo
|
|
@@ -79,14 +82,45 @@ module Cisco
|
|
|
79
82
|
end
|
|
80
83
|
current = instance_variable_get(rlbname).send(prop)
|
|
81
84
|
if current != @new_resource.send(prop)
|
|
82
|
-
converge_by("update #{prop} '#{current}' => "
|
|
85
|
+
converge_by("update #{prop} '#{current}' => " \
|
|
83
86
|
"'#{@new_resource.send(prop)}'") do
|
|
84
87
|
instance_variable_get(rlbname).send("#{prop}=",
|
|
85
|
-
|
|
88
|
+
@new_resource.send(prop))
|
|
86
89
|
end
|
|
87
90
|
end
|
|
88
|
-
|
|
91
|
+
end
|
|
89
92
|
end
|
|
90
93
|
end
|
|
91
94
|
end # class ChefUtils
|
|
95
|
+
|
|
96
|
+
# General utility class
|
|
97
|
+
class Utils
|
|
98
|
+
require 'ipaddr'
|
|
99
|
+
# Helper utility method for ip/prefix format networks.
|
|
100
|
+
# For ip/prefix format '1.1.1.1/24' or '2000:123:38::34/64',
|
|
101
|
+
# we need to mask the address using the prefix length so that they
|
|
102
|
+
# are converted to '1.1.1.0/24' or '2000:123:38::/64'
|
|
103
|
+
def self.process_network_mask(network)
|
|
104
|
+
mask = network.split('/')[1]
|
|
105
|
+
address = IPAddr.new(network).to_s
|
|
106
|
+
network = address + '/' + mask unless mask.nil?
|
|
107
|
+
network
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Helper to build a hash of add/remove commands for a nested array.
|
|
111
|
+
# Useful for network, redistribute, etc.
|
|
112
|
+
# should: an array of expected cmds (manifest/recipe)
|
|
113
|
+
# current: an array of existing cmds on the device
|
|
114
|
+
def self.delta_add_remove(should, current=[])
|
|
115
|
+
# Remove nil entries from array
|
|
116
|
+
should.each(&:compact!) unless should.empty?
|
|
117
|
+
delta = { add: should - current, remove: current - should }
|
|
118
|
+
|
|
119
|
+
# Delete entries from :remove if f1 is an update to an existing command
|
|
120
|
+
delta[:add].each do |id, _|
|
|
121
|
+
delta[:remove].delete_if { |f1, f2| [f1, f2] if f1.to_s == id.to_s }
|
|
122
|
+
end
|
|
123
|
+
delta
|
|
124
|
+
end # delta_add_remove
|
|
125
|
+
end # class Utils
|
|
92
126
|
end # module Cisco
|
|
@@ -30,7 +30,7 @@ module CommandReference
|
|
|
30
30
|
if expression.is_a? Regexp
|
|
31
31
|
@regex = expression
|
|
32
32
|
else
|
|
33
|
-
|
|
33
|
+
fail ArgumentError
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
|
|
@@ -38,7 +38,7 @@ module CommandReference
|
|
|
38
38
|
if file.is_a? String
|
|
39
39
|
@file = file
|
|
40
40
|
else
|
|
41
|
-
|
|
41
|
+
fail ArgumentError
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
|
|
@@ -54,13 +54,15 @@ module CommandReference
|
|
|
54
54
|
attr_reader :sources
|
|
55
55
|
attr_reader :hash
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
# rubocop:disable Style/ClassVars
|
|
58
|
+
@@keys = %w(default_value
|
|
58
59
|
config_set config_set_append
|
|
59
60
|
config_get config_get_token config_get_token_append
|
|
60
61
|
test_config_get test_config_get_regex test_config_result)
|
|
62
|
+
# rubocop:enable Style/ClassVars
|
|
61
63
|
|
|
62
64
|
def initialize(feature, name, ref, source)
|
|
63
|
-
|
|
65
|
+
fail ArgumentError, "'#{ref}' is not a hash." unless ref.is_a? Hash
|
|
64
66
|
|
|
65
67
|
@feature = feature
|
|
66
68
|
@name = name
|
|
@@ -72,14 +74,14 @@ module CommandReference
|
|
|
72
74
|
|
|
73
75
|
# Overwrite values from more specific references.
|
|
74
76
|
def merge(values, file)
|
|
75
|
-
values.each
|
|
76
|
-
unless @@
|
|
77
|
-
|
|
77
|
+
values.each do |key, value|
|
|
78
|
+
unless @@keys.include?(key)
|
|
79
|
+
fail "Unrecognized key #{key} for #{feature}, #{name} in #{file}"
|
|
78
80
|
end
|
|
79
81
|
if value.nil?
|
|
80
82
|
# Some attributes can store an explicit nil.
|
|
81
83
|
# Others treat this as unset (allowing a platform to override common).
|
|
82
|
-
if key ==
|
|
84
|
+
if key == 'default_value'
|
|
83
85
|
@hash[key] = value
|
|
84
86
|
else
|
|
85
87
|
@hash.delete(key)
|
|
@@ -87,7 +89,7 @@ module CommandReference
|
|
|
87
89
|
else
|
|
88
90
|
@hash[key] = value
|
|
89
91
|
end
|
|
90
|
-
|
|
92
|
+
end
|
|
91
93
|
@sources << file
|
|
92
94
|
end
|
|
93
95
|
|
|
@@ -98,29 +100,26 @@ module CommandReference
|
|
|
98
100
|
# If value is a string and it is empty OR the first letter is lower case
|
|
99
101
|
# then leave value untouched.
|
|
100
102
|
# If value is a string and the first letter is uppercase this indicates
|
|
101
|
-
# that it could be a constant in Ruby so attempt to convert it
|
|
102
|
-
|
|
103
|
+
# that it could be a constant in Ruby, so attempt to convert it
|
|
104
|
+
# to a Constant.
|
|
105
|
+
if value.is_a?(String) && !value.empty?
|
|
103
106
|
if value[0].chr == value[0].chr.upcase
|
|
104
|
-
|
|
105
|
-
value = Object.const_get(value) if Object.const_defined?(value)
|
|
106
|
-
rescue NameError
|
|
107
|
-
# debug("#{value} looks like a constant but is not")
|
|
108
|
-
end
|
|
107
|
+
value = Object.const_get(value) if Object.const_defined?(value)
|
|
109
108
|
end
|
|
110
109
|
end
|
|
111
110
|
value
|
|
112
111
|
end
|
|
113
112
|
|
|
114
113
|
def test_config_result(value)
|
|
115
|
-
result = @hash[
|
|
114
|
+
result = @hash['test_config_result'][value]
|
|
116
115
|
convert_to_constant(result)
|
|
117
116
|
end
|
|
118
117
|
|
|
119
118
|
def method_missing(method_name, *args, &block)
|
|
120
|
-
super(method_name, *args, &block) unless @@
|
|
119
|
+
super(method_name, *args, &block) unless @@keys.include?(method_name.to_s)
|
|
121
120
|
method_name = method_name.to_s
|
|
122
121
|
unless @hash.include?(method_name)
|
|
123
|
-
|
|
122
|
+
fail IndexError, "No #{method_name} defined for #{@feature}, #{@name}"
|
|
124
123
|
end
|
|
125
124
|
# puts("get #{method_name}: '#{@hash[method_name]}'")
|
|
126
125
|
@hash[method_name]
|
|
@@ -128,32 +127,27 @@ module CommandReference
|
|
|
128
127
|
|
|
129
128
|
# Print useful debugging information about the object.
|
|
130
129
|
def to_s
|
|
131
|
-
str =
|
|
130
|
+
str = ''
|
|
132
131
|
str << "Command: #{@feature} #{@name}\n"
|
|
133
|
-
@hash.each { |key, value|
|
|
134
|
-
str << " #{key}: #{value}\n"
|
|
135
|
-
}
|
|
132
|
+
@hash.each { |key, value| str << " #{key}: #{value}\n" }
|
|
136
133
|
str
|
|
137
134
|
end
|
|
138
135
|
|
|
139
136
|
# Check that all necessary values have been populated.
|
|
140
137
|
def valid?
|
|
141
|
-
return false unless @feature
|
|
138
|
+
return false unless @feature && @name
|
|
142
139
|
true
|
|
143
140
|
end
|
|
144
141
|
end
|
|
145
142
|
|
|
146
143
|
# Builds reference hash for the platform specified in the product id.
|
|
147
144
|
class CommandReference
|
|
148
|
-
@@debug = false
|
|
149
|
-
|
|
150
|
-
def self.debug
|
|
151
|
-
@@debug
|
|
152
|
-
end
|
|
145
|
+
@@debug = false # rubocop:disable Style/ClassVars
|
|
153
146
|
|
|
154
147
|
def self.debug=(value)
|
|
155
|
-
|
|
156
|
-
|
|
148
|
+
fail ArgumentError, 'Debug must be boolean' unless value == true ||
|
|
149
|
+
value == false
|
|
150
|
+
@@debug = value # rubocop:disable Style/ClassVars
|
|
157
151
|
end
|
|
158
152
|
|
|
159
153
|
attr_reader :files, :product_id
|
|
@@ -171,25 +165,31 @@ module CommandReference
|
|
|
171
165
|
@files = files
|
|
172
166
|
else
|
|
173
167
|
@files = []
|
|
174
|
-
# Hashes are unordered in Ruby 1.8.7
|
|
168
|
+
# Hashes are unordered in Ruby 1.8.7, so instead, we use an array
|
|
169
|
+
# of objects.
|
|
170
|
+
# rubocop:disable Metrics/LineLength
|
|
175
171
|
platforms = [
|
|
176
172
|
CommandPlatformFile.new(//,
|
|
177
173
|
File.join(File.dirname(__FILE__),
|
|
178
|
-
|
|
174
|
+
'command_reference_common.yaml')),
|
|
175
|
+
CommandPlatformFile.new(//,
|
|
176
|
+
File.join(File.dirname(__FILE__),
|
|
177
|
+
'command_reference_common_bgp.yaml')),
|
|
179
178
|
CommandPlatformFile.new(/N9K/,
|
|
180
179
|
File.join(File.dirname(__FILE__),
|
|
181
|
-
|
|
180
|
+
'command_reference_n9k.yaml')),
|
|
182
181
|
CommandPlatformFile.new(/N7K/,
|
|
183
182
|
File.join(File.dirname(__FILE__),
|
|
184
|
-
|
|
183
|
+
'command_reference_n7k.yaml')),
|
|
185
184
|
CommandPlatformFile.new(/C3064/,
|
|
186
185
|
File.join(File.dirname(__FILE__),
|
|
187
|
-
|
|
186
|
+
'command_reference_n3064.yaml')),
|
|
188
187
|
]
|
|
188
|
+
# rubocop:enable Metrics/LineLength
|
|
189
189
|
# Build array
|
|
190
|
-
platforms.each
|
|
190
|
+
platforms.each do |reference|
|
|
191
191
|
@files << reference.file if reference.match(@product_id)
|
|
192
|
-
|
|
192
|
+
end
|
|
193
193
|
end
|
|
194
194
|
|
|
195
195
|
build_cmd_ref
|
|
@@ -204,19 +204,19 @@ module CommandReference
|
|
|
204
204
|
|
|
205
205
|
reference_yaml = {}
|
|
206
206
|
|
|
207
|
-
@files.each
|
|
207
|
+
@files.each do |file|
|
|
208
208
|
debug "Processing file '#{file}'"
|
|
209
209
|
reference_yaml = load_yaml(file)
|
|
210
210
|
|
|
211
|
-
reference_yaml.each
|
|
212
|
-
if names.nil?
|
|
213
|
-
|
|
211
|
+
reference_yaml.each do |feature, names|
|
|
212
|
+
if names.nil? || names.empty?
|
|
213
|
+
fail "No names under feature #{feature}: #{names}"
|
|
214
214
|
elsif @hash[feature].nil?
|
|
215
215
|
@hash[feature] = {}
|
|
216
216
|
else
|
|
217
217
|
debug " Merging feature '#{feature}' retrieved from '#{file}'."
|
|
218
218
|
end
|
|
219
|
-
names.each
|
|
219
|
+
names.each do |name, values|
|
|
220
220
|
debug " Processing feature '#{feature}' name '#{name}'"
|
|
221
221
|
if @hash[feature][name].nil?
|
|
222
222
|
begin
|
|
@@ -225,14 +225,15 @@ module CommandReference
|
|
|
225
225
|
raise "Invalid data for '#{feature}', '#{name}': #{e}"
|
|
226
226
|
end
|
|
227
227
|
else
|
|
228
|
-
debug " Merging feature '#{feature}' name '#{name}'
|
|
228
|
+
debug " Merging feature '#{feature}' name '#{name}' " \
|
|
229
|
+
"from '#{file}'."
|
|
229
230
|
@hash[feature][name].merge(values, file)
|
|
230
231
|
end
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
234
235
|
|
|
235
|
-
|
|
236
|
+
fail 'Missing values in CommandReference.' unless valid?
|
|
236
237
|
end
|
|
237
238
|
|
|
238
239
|
# Get the command reference
|
|
@@ -243,9 +244,7 @@ module CommandReference
|
|
|
243
244
|
# happens if @hash[feature] doesn't exist
|
|
244
245
|
value = nil
|
|
245
246
|
end
|
|
246
|
-
if value.nil?
|
|
247
|
-
raise IndexError, "No CmdRef defined for #{feature}, #{name}"
|
|
248
|
-
end
|
|
247
|
+
fail IndexError, "No CmdRef defined for #{feature}, #{name}" if value.nil?
|
|
249
248
|
value
|
|
250
249
|
end
|
|
251
250
|
|
|
@@ -258,18 +257,18 @@ module CommandReference
|
|
|
258
257
|
puts "DEBUG: #{text}" if @@debug
|
|
259
258
|
end
|
|
260
259
|
|
|
261
|
-
def
|
|
260
|
+
def mapping?(node)
|
|
262
261
|
# Need to handle both Syck::Map and Psych::Nodes::Mapping
|
|
263
262
|
node.class.ancestors.any? { |name| /Map/ =~ name.to_s }
|
|
264
263
|
end
|
|
265
|
-
private :
|
|
264
|
+
private :mapping?
|
|
266
265
|
|
|
267
266
|
def get_keys_values_from_map(node)
|
|
268
267
|
if node.class.ancestors.any? { |name| /Psych/ =~ name.to_s }
|
|
269
268
|
# A Psych::Node::Mapping instance has an Array of children in
|
|
270
269
|
# the format [key1, val1, key2, val2]
|
|
271
|
-
key_children = node.children.select.each_with_index { |
|
|
272
|
-
val_children = node.children.select.each_with_index { |
|
|
270
|
+
key_children = node.children.select.each_with_index { |_, i| i.even? }
|
|
271
|
+
val_children = node.children.select.each_with_index { |_, i| i.odd? }
|
|
273
272
|
else
|
|
274
273
|
# Syck::Map nodes have a .children method but it doesn't work :-(
|
|
275
274
|
# Instead we access the node.value which is a hash.
|
|
@@ -291,18 +290,20 @@ module CommandReference
|
|
|
291
290
|
# @param depth Depth into the node tree
|
|
292
291
|
# @param parents String describing parents of this node, for messages
|
|
293
292
|
def validate_yaml(node, filename, depth=0, parents=nil)
|
|
294
|
-
return unless node
|
|
293
|
+
return unless node && (mapping?(node) || node.children)
|
|
295
294
|
# Psych wraps everything in a Document instance, while
|
|
296
295
|
# Syck does not. To keep the "depth" counting consistent,
|
|
297
296
|
# we need to ignore Documents.
|
|
298
|
-
|
|
297
|
+
unless node.class.ancestors.any? { |name| /Document/ =~ name.to_s }
|
|
298
|
+
depth += 1
|
|
299
|
+
end
|
|
299
300
|
debug "Validating #{node.class} at depth #{depth}"
|
|
300
301
|
|
|
301
302
|
# No special validation for non-mapping nodes - just recurse
|
|
302
|
-
unless
|
|
303
|
-
node.children.each
|
|
303
|
+
unless mapping?(node)
|
|
304
|
+
node.children.each do |child|
|
|
304
305
|
validate_yaml(child, filename, depth, parents)
|
|
305
|
-
|
|
306
|
+
end
|
|
306
307
|
return
|
|
307
308
|
end
|
|
308
309
|
|
|
@@ -325,7 +326,7 @@ module CommandReference
|
|
|
325
326
|
dup = key_arr.detect { |e| key_arr.index(e) != key_arr.rindex(e) }
|
|
326
327
|
if dup
|
|
327
328
|
msg = "Duplicate #{label} '#{dup}'#{parents} in #{filename}!"
|
|
328
|
-
|
|
329
|
+
fail msg
|
|
329
330
|
end
|
|
330
331
|
|
|
331
332
|
=begin
|
|
@@ -338,7 +339,7 @@ module CommandReference
|
|
|
338
339
|
if depth == 1
|
|
339
340
|
last_key = nil
|
|
340
341
|
key_arr.each do |key|
|
|
341
|
-
if last_key
|
|
342
|
+
if last_key && key < last_key
|
|
342
343
|
raise RuntimeError, "features out of order (#{last_key} > #{key})"
|
|
343
344
|
end
|
|
344
345
|
last_key = key
|
|
@@ -363,7 +364,7 @@ module CommandReference
|
|
|
363
364
|
|
|
364
365
|
# Read in yaml file.
|
|
365
366
|
def load_yaml(yaml_file)
|
|
366
|
-
|
|
367
|
+
fail "File #{yaml_file} doesn't exist." unless File.exist?(yaml_file)
|
|
367
368
|
# Parse YAML file into a tree of nodes
|
|
368
369
|
# Psych::SyntaxError doesn't inherit from StandardError in some versions,
|
|
369
370
|
# so we want to explicitly catch it if using Psych.
|
|
@@ -394,22 +395,19 @@ module CommandReference
|
|
|
394
395
|
# Check that all resources were pulled in correctly.
|
|
395
396
|
def valid?
|
|
396
397
|
complete_status = true
|
|
397
|
-
@hash.
|
|
398
|
-
names.
|
|
398
|
+
@hash.each_value do |names|
|
|
399
|
+
names.each_value do |ref|
|
|
399
400
|
status = ref.valid?
|
|
400
|
-
debug
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
401
|
+
debug('Reference does not contain all supported values:' \
|
|
402
|
+
"\n#{ref}") unless status
|
|
403
|
+
complete_status = (status && complete_status)
|
|
404
|
+
end
|
|
405
|
+
end
|
|
404
406
|
complete_status
|
|
405
407
|
end
|
|
406
408
|
|
|
407
409
|
def to_s
|
|
408
|
-
@hash.
|
|
409
|
-
names.each { |name, ref|
|
|
410
|
-
ref.to_s
|
|
411
|
-
}
|
|
412
|
-
}
|
|
410
|
+
@hash.each_value { |names| names.each_value(&:to_s) }
|
|
413
411
|
end
|
|
414
412
|
end
|
|
415
413
|
end
|