test-kitchen 1.2.1 → 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/.cane +1 -1
- data/.rubocop.yml +3 -0
- data/.travis.yml +20 -9
- data/CHANGELOG.md +219 -108
- data/Gemfile +10 -6
- data/Guardfile +38 -9
- data/README.md +11 -1
- data/Rakefile +21 -37
- data/bin/kitchen +4 -4
- data/features/kitchen_action_commands.feature +161 -0
- data/features/kitchen_console_command.feature +34 -0
- data/features/kitchen_diagnose_command.feature +64 -0
- data/features/kitchen_init_command.feature +29 -17
- data/features/kitchen_list_command.feature +2 -2
- data/features/kitchen_login_command.feature +56 -0
- data/features/{sink_command.feature → kitchen_sink_command.feature} +0 -0
- data/features/kitchen_test_command.feature +88 -0
- data/features/step_definitions/gem_steps.rb +8 -6
- data/features/step_definitions/git_steps.rb +4 -2
- data/features/step_definitions/output_steps.rb +5 -0
- data/features/support/env.rb +12 -9
- data/lib/kitchen.rb +60 -38
- data/lib/kitchen/base64_stream.rb +55 -0
- data/lib/kitchen/busser.rb +124 -58
- data/lib/kitchen/cli.rb +121 -38
- data/lib/kitchen/collection.rb +3 -3
- data/lib/kitchen/color.rb +4 -4
- data/lib/kitchen/command.rb +78 -11
- data/lib/kitchen/command/action.rb +3 -2
- data/lib/kitchen/command/console.rb +12 -5
- data/lib/kitchen/command/diagnose.rb +17 -3
- data/lib/kitchen/command/driver_discover.rb +26 -7
- data/lib/kitchen/command/exec.rb +41 -0
- data/lib/kitchen/command/list.rb +44 -14
- data/lib/kitchen/command/login.rb +2 -1
- data/lib/kitchen/command/sink.rb +2 -1
- data/lib/kitchen/command/test.rb +5 -4
- data/lib/kitchen/config.rb +146 -14
- data/lib/kitchen/configurable.rb +314 -0
- data/lib/kitchen/data_munger.rb +522 -18
- data/lib/kitchen/diagnostic.rb +43 -4
- data/lib/kitchen/driver.rb +4 -4
- data/lib/kitchen/driver/base.rb +80 -115
- data/lib/kitchen/driver/dummy.rb +34 -6
- data/lib/kitchen/driver/proxy.rb +14 -3
- data/lib/kitchen/driver/ssh_base.rb +61 -7
- data/lib/kitchen/errors.rb +109 -9
- data/lib/kitchen/generator/driver_create.rb +39 -5
- data/lib/kitchen/generator/init.rb +130 -45
- data/lib/kitchen/instance.rb +162 -28
- data/lib/kitchen/lazy_hash.rb +79 -7
- data/lib/kitchen/loader/yaml.rb +159 -27
- data/lib/kitchen/logger.rb +267 -21
- data/lib/kitchen/logging.rb +30 -3
- data/lib/kitchen/login_command.rb +11 -2
- data/lib/kitchen/metadata_chopper.rb +2 -2
- data/lib/kitchen/provisioner.rb +4 -4
- data/lib/kitchen/provisioner/base.rb +107 -103
- data/lib/kitchen/provisioner/chef/berkshelf.rb +36 -8
- data/lib/kitchen/provisioner/chef/librarian.rb +40 -11
- data/lib/kitchen/provisioner/chef_base.rb +206 -167
- data/lib/kitchen/provisioner/chef_solo.rb +25 -7
- data/lib/kitchen/provisioner/chef_zero.rb +105 -29
- data/lib/kitchen/provisioner/dummy.rb +1 -1
- data/lib/kitchen/provisioner/shell.rb +21 -6
- data/lib/kitchen/rake_tasks.rb +8 -3
- data/lib/kitchen/shell_out.rb +15 -18
- data/lib/kitchen/ssh.rb +122 -27
- data/lib/kitchen/state_file.rb +24 -7
- data/lib/kitchen/thor_tasks.rb +9 -4
- data/lib/kitchen/util.rb +43 -118
- data/lib/kitchen/version.rb +1 -1
- data/lib/vendor/hash_recursive_merge.rb +10 -2
- data/spec/kitchen/base64_stream_spec.rb +77 -0
- data/spec/kitchen/busser_spec.rb +490 -0
- data/spec/kitchen/collection_spec.rb +10 -10
- data/spec/kitchen/color_spec.rb +2 -2
- data/spec/kitchen/config_spec.rb +234 -62
- data/spec/kitchen/configurable_spec.rb +490 -0
- data/spec/kitchen/data_munger_spec.rb +1070 -862
- data/spec/kitchen/diagnostic_spec.rb +79 -0
- data/spec/kitchen/driver/base_spec.rb +80 -85
- data/spec/kitchen/driver/dummy_spec.rb +43 -14
- data/spec/kitchen/driver/proxy_spec.rb +134 -0
- data/spec/kitchen/driver/ssh_base_spec.rb +644 -0
- data/spec/kitchen/driver_spec.rb +15 -15
- data/spec/kitchen/errors_spec.rb +309 -0
- data/spec/kitchen/instance_spec.rb +143 -46
- data/spec/kitchen/lazy_hash_spec.rb +36 -9
- data/spec/kitchen/loader/yaml_spec.rb +237 -226
- data/spec/kitchen/logger_spec.rb +419 -0
- data/spec/kitchen/logging_spec.rb +59 -0
- data/spec/kitchen/login_command_spec.rb +49 -0
- data/spec/kitchen/metadata_chopper_spec.rb +82 -0
- data/spec/kitchen/platform_spec.rb +4 -4
- data/spec/kitchen/provisioner/base_spec.rb +65 -125
- data/spec/kitchen/provisioner/chef_base_spec.rb +798 -0
- data/spec/kitchen/provisioner/chef_solo_spec.rb +316 -0
- data/spec/kitchen/provisioner/chef_zero_spec.rb +624 -0
- data/spec/kitchen/provisioner/shell_spec.rb +269 -0
- data/spec/kitchen/provisioner_spec.rb +6 -6
- data/spec/kitchen/shell_out_spec.rb +143 -0
- data/spec/kitchen/ssh_spec.rb +683 -0
- data/spec/kitchen/state_file_spec.rb +28 -21
- data/spec/kitchen/suite_spec.rb +7 -7
- data/spec/kitchen/util_spec.rb +68 -10
- data/spec/kitchen_spec.rb +107 -0
- data/spec/spec_helper.rb +18 -13
- data/support/chef-client-zero.rb +10 -9
- data/support/chef_helpers.sh +16 -0
- data/support/download_helpers.sh +109 -0
- data/test-kitchen.gemspec +42 -33
- metadata +107 -33
data/lib/kitchen/data_munger.rb
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
-
require
|
19
|
+
require "vendor/hash_recursive_merge"
|
20
20
|
|
21
21
|
module Kitchen
|
22
22
|
|
@@ -26,9 +26,18 @@ module Kitchen
|
|
26
26
|
# This object will mutate the data Hash passed into its constructor and so
|
27
27
|
# should not be reused or shared across threads.
|
28
28
|
#
|
29
|
+
# If you are squeamish or faint of heart, then you might want to skip this
|
30
|
+
# class. Just remember, you were warned. And if you made it this far, be
|
31
|
+
# sure to tweet at @fnichol and let him know your fear factor level.
|
32
|
+
#
|
29
33
|
# @author Fletcher Nichol <fnichol@nichol.ca>
|
30
34
|
class DataMunger
|
31
35
|
|
36
|
+
# Constructs a new DataMunger object.
|
37
|
+
#
|
38
|
+
# @param data [Hash] the incoming user data hash
|
39
|
+
# @param kitchen_config [Hash] the incoming Test Kitchen-provided
|
40
|
+
# configuration hash
|
32
41
|
def initialize(data, kitchen_config = {})
|
33
42
|
@data = data
|
34
43
|
@kitchen_config = kitchen_config
|
@@ -38,6 +47,13 @@ module Kitchen
|
|
38
47
|
move_chef_data_to_provisioner!
|
39
48
|
end
|
40
49
|
|
50
|
+
# Generate a new Hash of configuration data that can be used to construct
|
51
|
+
# a new Busser object.
|
52
|
+
#
|
53
|
+
# @param suite [String] a suite name
|
54
|
+
# @param platform [String] a platform name
|
55
|
+
# @return [Hash] a new configuration Hash that can be used to construct a
|
56
|
+
# new Busser
|
41
57
|
def busser_data_for(suite, platform)
|
42
58
|
merged_data_for(:busser, suite, platform, :version).tap do |bdata|
|
43
59
|
set_kitchen_config_at!(bdata, :kitchen_root)
|
@@ -46,6 +62,13 @@ module Kitchen
|
|
46
62
|
end
|
47
63
|
end
|
48
64
|
|
65
|
+
# Generate a new Hash of configuration data that can be used to construct
|
66
|
+
# a new Driver object.
|
67
|
+
#
|
68
|
+
# @param suite [String] a suite name
|
69
|
+
# @param platform [String] a platform name
|
70
|
+
# @return [Hash] a new configuration Hash that can be used to construct a
|
71
|
+
# new Driver
|
49
72
|
def driver_data_for(suite, platform)
|
50
73
|
merged_data_for(:driver, suite, platform).tap do |ddata|
|
51
74
|
set_kitchen_config_at!(ddata, :kitchen_root)
|
@@ -54,10 +77,20 @@ module Kitchen
|
|
54
77
|
end
|
55
78
|
end
|
56
79
|
|
80
|
+
# Returns an Array of platform Hashes.
|
81
|
+
#
|
82
|
+
# @return [Array<Hash>] an Array of Hashes
|
57
83
|
def platform_data
|
58
84
|
data.fetch(:platforms, [])
|
59
85
|
end
|
60
86
|
|
87
|
+
# Generate a new Hash of configuration data that can be used to construct
|
88
|
+
# a new Provisioner object.
|
89
|
+
#
|
90
|
+
# @param suite [String] a suite name
|
91
|
+
# @param platform [String] a platform name
|
92
|
+
# @return [Hash] a new configuration Hash that can be used to construct a
|
93
|
+
# new Provisioner
|
61
94
|
def provisioner_data_for(suite, platform)
|
62
95
|
merged_data_for(:provisioner, suite, platform).tap do |pdata|
|
63
96
|
set_kitchen_config_at!(pdata, :kitchen_root)
|
@@ -67,31 +100,145 @@ module Kitchen
|
|
67
100
|
end
|
68
101
|
end
|
69
102
|
|
103
|
+
# Returns an Array of suite Hashes.
|
104
|
+
#
|
105
|
+
# @return [Array<Hash>] an Array of Hashes
|
70
106
|
def suite_data
|
71
107
|
data.fetch(:suites, [])
|
72
108
|
end
|
73
109
|
|
74
110
|
private
|
75
111
|
|
76
|
-
|
112
|
+
# @return [Hash] the user data hash
|
113
|
+
# @api private
|
114
|
+
attr_reader :data
|
115
|
+
|
116
|
+
# @return [Hash] the Test Kitchen-provided configuration hash
|
117
|
+
# @api private
|
118
|
+
attr_reader :kitchen_config
|
77
119
|
|
78
120
|
def combine_arrays!(root, key, *namespaces)
|
79
|
-
if root.
|
121
|
+
if root.key?(key)
|
80
122
|
root[key] = namespaces.
|
81
123
|
map { |namespace| root.fetch(key).fetch(namespace, []) }.flatten.
|
82
124
|
compact
|
83
125
|
end
|
84
126
|
end
|
85
127
|
|
128
|
+
# Destructively moves Chef-related paths out of a suite hash and into the
|
129
|
+
# suite's provisioner sub-hash.
|
130
|
+
#
|
131
|
+
# This method converts the following:
|
132
|
+
#
|
133
|
+
# {
|
134
|
+
# :suites => [
|
135
|
+
# {
|
136
|
+
# :name => "alpha",
|
137
|
+
# :nodes_path => "/a/b/c"
|
138
|
+
# },
|
139
|
+
# {
|
140
|
+
# :name => "beta",
|
141
|
+
# :roles_path => "/tmp/roles",
|
142
|
+
# :data_bags_path => "/bags"
|
143
|
+
# },
|
144
|
+
# ]
|
145
|
+
# }
|
146
|
+
#
|
147
|
+
# into the following:
|
148
|
+
#
|
149
|
+
# {
|
150
|
+
# :suites => [
|
151
|
+
# {
|
152
|
+
# :name => "alpha",
|
153
|
+
# :provisioner => {
|
154
|
+
# :nodes_path => "/a/b/c"
|
155
|
+
# }
|
156
|
+
# },
|
157
|
+
# {
|
158
|
+
# :name => "beta",
|
159
|
+
# :provisioner => {
|
160
|
+
# :roles_path => "/tmp/roles",
|
161
|
+
# :data_bags_path => "/bags"
|
162
|
+
# }
|
163
|
+
# },
|
164
|
+
# ]
|
165
|
+
# }
|
166
|
+
#
|
167
|
+
# @deprecated The following Chef paths should no longer be created directly
|
168
|
+
# under a suite hash: [`data_path`, `data_bags_path`,
|
169
|
+
# `encrypted_data_bag_secret_key_path`, `environments_path`, `nodes_path`,
|
170
|
+
# `roles_path`]. Instead put these key/value pairs directly inside a
|
171
|
+
# `provisioner` hash.
|
172
|
+
# @api private
|
86
173
|
def convert_legacy_chef_paths_format!
|
87
174
|
data.fetch(:suites, []).each do |suite|
|
88
|
-
%w
|
89
|
-
|
90
|
-
|
175
|
+
%w[
|
176
|
+
data data_bags encrypted_data_bag_secret_key
|
177
|
+
environments nodes roles
|
178
|
+
].each do |key|
|
179
|
+
move_chef_data_to_provisioner_at!(suite, "#{key}_path".to_sym)
|
91
180
|
end
|
92
181
|
end
|
93
182
|
end
|
94
183
|
|
184
|
+
# Destructively moves old-style `:driver_plugin` and `:driver_config`
|
185
|
+
# configuration hashes into the correct `:driver` hash.
|
186
|
+
#
|
187
|
+
# This method converts the following:
|
188
|
+
#
|
189
|
+
# {
|
190
|
+
# :driver_plugin => "foo",
|
191
|
+
# :driver_config => { :one => "two" },
|
192
|
+
#
|
193
|
+
# :platforms => [
|
194
|
+
# {
|
195
|
+
# :name => "ubuntu-12.04",
|
196
|
+
# :driver_plugin => "bar"
|
197
|
+
# }
|
198
|
+
# ],
|
199
|
+
#
|
200
|
+
# :suites => [
|
201
|
+
# {
|
202
|
+
# :name => "alpha",
|
203
|
+
# :driver_plugin => "baz"
|
204
|
+
# :driver_config => { :three => "four" }
|
205
|
+
# }
|
206
|
+
# ]
|
207
|
+
# }
|
208
|
+
#
|
209
|
+
# into the following:
|
210
|
+
#
|
211
|
+
# {
|
212
|
+
# :driver => {
|
213
|
+
# :name => "foo",
|
214
|
+
# :one => "two"
|
215
|
+
# }
|
216
|
+
#
|
217
|
+
# :platforms => [
|
218
|
+
# {
|
219
|
+
# :name => "ubuntu-12.04",
|
220
|
+
# :driver => {
|
221
|
+
# :name => "bar"
|
222
|
+
# }
|
223
|
+
# }
|
224
|
+
# ],
|
225
|
+
#
|
226
|
+
# :suites => [
|
227
|
+
# {
|
228
|
+
# :name => "alpha",
|
229
|
+
# :driver => {
|
230
|
+
# :name => "baz",
|
231
|
+
# :three => "four"
|
232
|
+
# }
|
233
|
+
# }
|
234
|
+
# ]
|
235
|
+
# }
|
236
|
+
#
|
237
|
+
# @deprecated The following configuration hashes should no longer be
|
238
|
+
# created in a `:platform`, `:suite`, or common location:
|
239
|
+
# [`:driver_plugin`, `:driver_config`]. Use a `:driver` hash block in
|
240
|
+
# their place.
|
241
|
+
# @api private
|
95
242
|
def convert_legacy_driver_format!
|
96
243
|
convert_legacy_driver_format_at!(data)
|
97
244
|
data.fetch(:platforms, []).each do |platform|
|
@@ -102,20 +249,89 @@ module Kitchen
|
|
102
249
|
end
|
103
250
|
end
|
104
251
|
|
252
|
+
# Destructively moves old-style `:driver_plugin` and `:driver_config`
|
253
|
+
# configuration hashes into the correct `:driver` in the first level depth
|
254
|
+
# of a hash. This method has no knowledge of suites, platforms, or the
|
255
|
+
# like, just a vanilla hash.
|
256
|
+
#
|
257
|
+
# @param root [Hash] a hash to use as the root of the conversion
|
258
|
+
# @deprecated The following configuration hashes should no longer be
|
259
|
+
# created in a Test Kitche hash: [`:driver_plugin`, `:driver_config`].
|
260
|
+
# Use a `:driver` hash block in their place.
|
261
|
+
# @api private
|
105
262
|
def convert_legacy_driver_format_at!(root)
|
106
|
-
if root.
|
263
|
+
if root.key?(:driver_config)
|
107
264
|
ddata = root.fetch(:driver, Hash.new)
|
108
265
|
ddata = { :name => ddata } if ddata.is_a?(String)
|
109
266
|
root[:driver] = root.delete(:driver_config).rmerge(ddata)
|
110
267
|
end
|
111
268
|
|
112
|
-
if root.
|
269
|
+
if root.key?(:driver_plugin)
|
113
270
|
ddata = root.fetch(:driver, Hash.new)
|
114
271
|
ddata = { :name => ddata } if ddata.is_a?(String)
|
115
272
|
root[:driver] = { :name => root.delete(:driver_plugin) }.rmerge(ddata)
|
116
273
|
end
|
117
274
|
end
|
118
275
|
|
276
|
+
# Destructively moves a `:require_chef_omnibus` key/value pair from a
|
277
|
+
# `:driver` hash block to a `:provisioner` hash block.
|
278
|
+
#
|
279
|
+
# This method converts the following:
|
280
|
+
#
|
281
|
+
# {
|
282
|
+
# :driver => {
|
283
|
+
# :require_chef_omnibus => true
|
284
|
+
# }
|
285
|
+
#
|
286
|
+
# :platforms => [
|
287
|
+
# {
|
288
|
+
# :name => "ubuntu-12.04",
|
289
|
+
# :driver => {
|
290
|
+
# :require_chef_omnibus => "10.8.2"
|
291
|
+
# }
|
292
|
+
# }
|
293
|
+
# ],
|
294
|
+
#
|
295
|
+
# :suites => [
|
296
|
+
# {
|
297
|
+
# :name => "alpha",
|
298
|
+
# :driver => {
|
299
|
+
# :require_chef_omnibus => "11"
|
300
|
+
# }
|
301
|
+
# }
|
302
|
+
# ]
|
303
|
+
# }
|
304
|
+
#
|
305
|
+
# into the following:
|
306
|
+
#
|
307
|
+
# {
|
308
|
+
# :provisioner => {
|
309
|
+
# :require_chef_omnibus => true
|
310
|
+
# }
|
311
|
+
#
|
312
|
+
# :platforms => [
|
313
|
+
# {
|
314
|
+
# :name => "ubuntu-12.04",
|
315
|
+
# :provisioner => {
|
316
|
+
# :require_chef_omnibus => "10.8.2"
|
317
|
+
# }
|
318
|
+
# }
|
319
|
+
# ],
|
320
|
+
#
|
321
|
+
# :suites => [
|
322
|
+
# {
|
323
|
+
# :name => "alpha",
|
324
|
+
# :provisioner => {
|
325
|
+
# :require_chef_omnibus => "11"
|
326
|
+
# }
|
327
|
+
# }
|
328
|
+
# ]
|
329
|
+
# }
|
330
|
+
#
|
331
|
+
# @deprecated The `:require_chef_omnibus` key/value pair should no longer
|
332
|
+
# be created inside a `:driver` hash block. Put it in a `:provisioner`
|
333
|
+
# hash block instead.
|
334
|
+
# @api private
|
119
335
|
def convert_legacy_require_chef_omnibus_format!
|
120
336
|
convert_legacy_require_chef_omnibus_format_at!(data)
|
121
337
|
data.fetch(:platforms, []).each do |platform|
|
@@ -126,11 +342,21 @@ module Kitchen
|
|
126
342
|
end
|
127
343
|
end
|
128
344
|
|
345
|
+
# Destructively moves a `:require_chef_omnibus` key/value pair from a
|
346
|
+
# `:driver` hash block to a `:provisioner` hash block in the first leve
|
347
|
+
# depth of a hash. This method has no knowledge of suites, platforms, or
|
348
|
+
# the like, just a vanilla haash.
|
349
|
+
#
|
350
|
+
# @param root [Hash] a hash to use as the root of the conversion
|
351
|
+
# @deprecated The `:require_chef_omnibus` key/value pair should no longer
|
352
|
+
# be created inside a `:driver` hash block. Put it in a `:provisioner`
|
353
|
+
# hash block instead.
|
354
|
+
# @api private
|
129
355
|
def convert_legacy_require_chef_omnibus_format_at!(root)
|
130
356
|
key = :require_chef_omnibus
|
131
357
|
ddata = root.fetch(:driver, Hash.new)
|
132
358
|
|
133
|
-
if ddata.is_a?(Hash) && ddata.
|
359
|
+
if ddata.is_a?(Hash) && ddata.key?(key)
|
134
360
|
pdata = root.fetch(:provisioner, Hash.new)
|
135
361
|
pdata = { :name => pdata } if pdata.is_a?(String)
|
136
362
|
root[:provisioner] =
|
@@ -138,6 +364,27 @@ module Kitchen
|
|
138
364
|
end
|
139
365
|
end
|
140
366
|
|
367
|
+
# Performs a prioritized recursive merge of several source Hashes and
|
368
|
+
# returns a new merged Hash. For these data sub-hash structures, there are
|
369
|
+
# 4 sources for configuration data:
|
370
|
+
#
|
371
|
+
# 1. defaults, provided by Test Kitchen code
|
372
|
+
# 2. user-provided in the common root-level of the incoming data hash
|
373
|
+
# 3. user-provided in a platform sub-hash
|
374
|
+
# 4. user-provided in a suite sub-hash
|
375
|
+
#
|
376
|
+
# The merge order is 4 -> 3 -> 2 -> 1, meaning that the highest number in
|
377
|
+
# the above list has merge precedence over any lower numbered source. Put
|
378
|
+
# another way, a key/value pair in a suite sub-hash will be used over the
|
379
|
+
# key/value pair in a platform sub-hash.
|
380
|
+
#
|
381
|
+
# @param key [Symbol] the data sub-hash(es) to merge
|
382
|
+
# @param suite [String] a suite name
|
383
|
+
# @param platform [String] a platform name
|
384
|
+
# @param default_key [Symbol] the default key to use when normalizing the
|
385
|
+
# data sub-hashes (default: `:name`)
|
386
|
+
# @return [Hash] a new merged Hash
|
387
|
+
# @api private
|
141
388
|
def merged_data_for(key, suite, platform, default_key = :name)
|
142
389
|
ddata = normalized_default_data(key, default_key)
|
143
390
|
cdata = normalized_common_data(key, default_key)
|
@@ -147,6 +394,59 @@ module Kitchen
|
|
147
394
|
ddata.rmerge(cdata.rmerge(pdata.rmerge(sdata)))
|
148
395
|
end
|
149
396
|
|
397
|
+
# Destructively moves key Chef configuration key/value pairs from being
|
398
|
+
# directly under a suite or platform into a `:provisioner` sub-hash.
|
399
|
+
#
|
400
|
+
# There are two key Chef configuration key/value pairs:
|
401
|
+
#
|
402
|
+
# 1. `:attributes`
|
403
|
+
# 2. `:run_list`
|
404
|
+
#
|
405
|
+
# This method converts the following:
|
406
|
+
#
|
407
|
+
# {
|
408
|
+
# :platforms => [
|
409
|
+
# {
|
410
|
+
# :name => "ubuntu-12.04",
|
411
|
+
# :attributes => { :one => "two" },
|
412
|
+
# :run_list => ["alpha", "bravo"]
|
413
|
+
# }
|
414
|
+
# ],
|
415
|
+
#
|
416
|
+
# :suites => [
|
417
|
+
# {
|
418
|
+
# :name => "alpha",
|
419
|
+
# :attributes => { :three => "four" },
|
420
|
+
# :run_list => ["charlie", "delta"]
|
421
|
+
# }
|
422
|
+
# ]
|
423
|
+
# }
|
424
|
+
#
|
425
|
+
# into the following:
|
426
|
+
#
|
427
|
+
# {
|
428
|
+
# :platforms => [
|
429
|
+
# {
|
430
|
+
# :name => "ubuntu-12.04",
|
431
|
+
# :provisioner => {
|
432
|
+
# :attributes => { :one => "two" },
|
433
|
+
# :run_list => ["alpha", "bravo"]
|
434
|
+
# }
|
435
|
+
# }
|
436
|
+
# ],
|
437
|
+
#
|
438
|
+
# :suites => [
|
439
|
+
# {
|
440
|
+
# :name => "alpha",
|
441
|
+
# :provisioner => {
|
442
|
+
# :attributes => { :three => "four" },
|
443
|
+
# :run_list => ["charlie", "delta"]
|
444
|
+
# }
|
445
|
+
# }
|
446
|
+
# ]
|
447
|
+
# }
|
448
|
+
#
|
449
|
+
# @api private
|
150
450
|
def move_chef_data_to_provisioner!
|
151
451
|
data.fetch(:suites, []).each do |suite|
|
152
452
|
move_chef_data_to_provisioner_at!(suite, :attributes)
|
@@ -159,20 +459,71 @@ module Kitchen
|
|
159
459
|
end
|
160
460
|
end
|
161
461
|
|
462
|
+
# Destructively moves key Chef configuration key/value pairs from being
|
463
|
+
# directly under a hash into a `:provisioner` sub-hash block. This method
|
464
|
+
# has no knowledge of suites, platforms, or the like, just a vanilla hash.
|
465
|
+
#
|
466
|
+
# @param root [Hash] a hash to use as the root of the conversion
|
467
|
+
# @param key [Symbol] a key in the root hash to move into a `:provisioner`
|
468
|
+
# sub-hash block
|
469
|
+
# @api private
|
162
470
|
def move_chef_data_to_provisioner_at!(root, key)
|
163
|
-
if root.
|
471
|
+
if root.key?(key)
|
164
472
|
pdata = root.fetch(:provisioner, Hash.new)
|
165
473
|
pdata = { :name => pdata } if pdata.is_a?(String)
|
166
|
-
if !
|
167
|
-
root[:provisioner] = pdata.rmerge(
|
474
|
+
if !root.fetch(key, nil).nil?
|
475
|
+
root[:provisioner] = pdata.rmerge(key => root.delete(key))
|
168
476
|
end
|
169
477
|
end
|
170
478
|
end
|
171
479
|
|
480
|
+
# Vicious hack to allow for Array-appending merge semantics. This method
|
481
|
+
# takes an array value and transforms it into a hash with a bucket name
|
482
|
+
# containing the original Array. This way semantic Hash merging will do
|
483
|
+
# its thing and another process can collapse the hash into a flat array
|
484
|
+
# afterwards, given a strategy (like use the array segmenet from one
|
485
|
+
# bucket first, then another one second). To anyone who made it this far,
|
486
|
+
# Fletcher appologizes.
|
487
|
+
#
|
488
|
+
# @param root [Hash] a hash to use as the root of the conversion
|
489
|
+
# @param key [Symbol] a key in the root hash that, if exists, has its
|
490
|
+
# value transformed into a sub-hash
|
491
|
+
# @param bucket [Symbol] a key to use for the sub-hash
|
492
|
+
# @api private
|
172
493
|
def namespace_array!(root, key, bucket)
|
173
|
-
root[key] = { bucket => root.fetch(key) } if root.
|
494
|
+
root[key] = { bucket => root.fetch(key) } if root.key?(key)
|
174
495
|
end
|
175
496
|
|
497
|
+
# Normalizes a specific key in the root of the data hash to be a proper
|
498
|
+
# sub-hash in all cases. Specifically handled are the following cases:
|
499
|
+
#
|
500
|
+
# * If the value for a key is set to `nil`, a new Hash will be put in
|
501
|
+
# its place.
|
502
|
+
# * If the value is a String, then convert the value to a new Hash with
|
503
|
+
# a default key pointing to the original String
|
504
|
+
#
|
505
|
+
# Given a hash:
|
506
|
+
#
|
507
|
+
# { :driver => nil }
|
508
|
+
#
|
509
|
+
# this method (`normalized_common_data(:driver, :name)`) would return:
|
510
|
+
#
|
511
|
+
# {}
|
512
|
+
#
|
513
|
+
# Given a hash:
|
514
|
+
#
|
515
|
+
# { :driver => "coolbeans" }
|
516
|
+
#
|
517
|
+
# this method (`normalized_common_data(:driver, :name)`) would return:
|
518
|
+
#
|
519
|
+
# { :name => "coolbeans" }
|
520
|
+
#
|
521
|
+
# @param key [Symbol] the value to normalize
|
522
|
+
# @param default_key [Symbol] the implicit default key if a String value
|
523
|
+
# is given
|
524
|
+
# @return [Hash] a shallow Hash copy of the original if not modified, or a
|
525
|
+
# new Hash otherwise
|
526
|
+
# @api private
|
176
527
|
def normalized_common_data(key, default_key)
|
177
528
|
cdata = data.fetch(key, Hash.new)
|
178
529
|
cdata = cdata.nil? ? Hash.new : cdata.dup
|
@@ -180,12 +531,94 @@ module Kitchen
|
|
180
531
|
cdata
|
181
532
|
end
|
182
533
|
|
534
|
+
# Normalizes a specific key in the `:defaults` data sub-hash to be a proper
|
535
|
+
# sub-hash in all cases. Specifically handled are the following cases:
|
536
|
+
#
|
537
|
+
# * If the value for a key is not set, a new Hash will be put in its place
|
538
|
+
# * If the value is a String, then convert the value to a new Hash with
|
539
|
+
# a default key pointing to the original String
|
540
|
+
#
|
541
|
+
# Given a hash:
|
542
|
+
#
|
543
|
+
# {
|
544
|
+
# :defaults => {}
|
545
|
+
# }
|
546
|
+
#
|
547
|
+
# this method (`normalized_default_data(:driver, :name)`) would return:
|
548
|
+
#
|
549
|
+
# {}
|
550
|
+
#
|
551
|
+
# Given a hash:
|
552
|
+
#
|
553
|
+
# {
|
554
|
+
# :defaults => {
|
555
|
+
# :driver => "coolbeans"
|
556
|
+
# }
|
557
|
+
# }
|
558
|
+
#
|
559
|
+
# this method (`normalized_default_data(:driver, :name)`) would return:
|
560
|
+
#
|
561
|
+
# { :name => "coolbeans" }
|
562
|
+
#
|
563
|
+
# @param key [Symbol] the value to normalize
|
564
|
+
# @param default_key [Symbol] the implicit default key if a String value
|
565
|
+
# is given
|
566
|
+
# @return [Hash] a shallow Hash copy of the original if not modified, or a
|
567
|
+
# new Hash otherwise
|
568
|
+
# @api private
|
183
569
|
def normalized_default_data(key, default_key)
|
184
570
|
ddata = kitchen_config.fetch(:defaults, Hash.new).fetch(key, Hash.new).dup
|
185
571
|
ddata = { default_key => ddata } if ddata.is_a?(String)
|
186
572
|
ddata
|
187
573
|
end
|
188
574
|
|
575
|
+
# Normalizes a specific key in a platform hash data sub-hash to be a proper
|
576
|
+
# sub-hash in all cases. Specifically handled are the following cases:
|
577
|
+
#
|
578
|
+
# * If the value for a key is set to `nil`, a new Hash will be put in
|
579
|
+
# its place.
|
580
|
+
# * If the value is a String, then convert the value to a new Hash with
|
581
|
+
# a default key pointing to the original String
|
582
|
+
#
|
583
|
+
# Given a hash:
|
584
|
+
#
|
585
|
+
# {
|
586
|
+
# :platforms => [
|
587
|
+
# {
|
588
|
+
# :name => "alpha",
|
589
|
+
# :driver => nil
|
590
|
+
# }
|
591
|
+
# ]
|
592
|
+
# }
|
593
|
+
#
|
594
|
+
# this method (`normalized_platform_data(:driver, :name, "alpha)`) would
|
595
|
+
# return:
|
596
|
+
#
|
597
|
+
# {}
|
598
|
+
#
|
599
|
+
# Given a hash:
|
600
|
+
#
|
601
|
+
# {
|
602
|
+
# :platforms => [
|
603
|
+
# {
|
604
|
+
# :name => "alpha",
|
605
|
+
# :driver => "coolbeans"
|
606
|
+
# }
|
607
|
+
# ]
|
608
|
+
# }
|
609
|
+
#
|
610
|
+
# this method (`normalized_common_data(:driver, :name, "alpha")`) would
|
611
|
+
# return:
|
612
|
+
#
|
613
|
+
# { :name => "coolbeans" }
|
614
|
+
#
|
615
|
+
# @param key [Symbol] the value to normalize
|
616
|
+
# @param default_key [Symbol] the implicit default key if a String value
|
617
|
+
# is given
|
618
|
+
# @param platform [String] name of a platform
|
619
|
+
# @return [Hash] a shallow Hash copy of the original if not modified, or a
|
620
|
+
# new Hash otherwise
|
621
|
+
# @api private
|
189
622
|
def normalized_platform_data(key, default_key, platform)
|
190
623
|
pdata = platform_data_for(platform).fetch(key, Hash.new)
|
191
624
|
pdata = pdata.nil? ? Hash.new : pdata.dup
|
@@ -194,6 +627,53 @@ module Kitchen
|
|
194
627
|
pdata
|
195
628
|
end
|
196
629
|
|
630
|
+
# Normalizes a specific key in a suite hash data sub-hash to be a proper
|
631
|
+
# sub-hash in all cases. Specifically handled are the following cases:
|
632
|
+
#
|
633
|
+
# * If the value for a key is set to `nil`, a new Hash will be put in
|
634
|
+
# its place.
|
635
|
+
# * If the value is a String, then convert the value to a new Hash with
|
636
|
+
# a default key pointing to the original String
|
637
|
+
#
|
638
|
+
# Given a hash:
|
639
|
+
#
|
640
|
+
# {
|
641
|
+
# :suites => [
|
642
|
+
# {
|
643
|
+
# :name => "full",
|
644
|
+
# :driver => nil
|
645
|
+
# }
|
646
|
+
# ]
|
647
|
+
# }
|
648
|
+
#
|
649
|
+
# this method (`normalized_platform_data(:driver, :name, "full)`) would
|
650
|
+
# return:
|
651
|
+
#
|
652
|
+
# {}
|
653
|
+
#
|
654
|
+
# Given a hash:
|
655
|
+
#
|
656
|
+
# {
|
657
|
+
# :suites => [
|
658
|
+
# {
|
659
|
+
# :name => "full",
|
660
|
+
# :driver => "coolbeans"
|
661
|
+
# }
|
662
|
+
# ]
|
663
|
+
# }
|
664
|
+
#
|
665
|
+
# this method (`normalized_common_data(:driver, :name, "full")`) would
|
666
|
+
# return:
|
667
|
+
#
|
668
|
+
# { :name => "coolbeans" }
|
669
|
+
#
|
670
|
+
# @param key [Symbol] the value to normalize
|
671
|
+
# @param default_key [Symbol] the implicit default key if a String value
|
672
|
+
# is given
|
673
|
+
# @param suite [String] name of a suite
|
674
|
+
# @return [Hash] a shallow Hash copy of the original if not modified, or a
|
675
|
+
# new Hash otherwise
|
676
|
+
# @api private
|
197
677
|
def normalized_suite_data(key, default_key, suite)
|
198
678
|
sdata = suite_data_for(suite).fetch(key, Hash.new)
|
199
679
|
sdata = sdata.nil? ? Hash.new : sdata.dup
|
@@ -202,22 +682,46 @@ module Kitchen
|
|
202
682
|
sdata
|
203
683
|
end
|
204
684
|
|
685
|
+
# Returns the hash for a platform by name, or an empty Hash if none
|
686
|
+
# could be found.
|
687
|
+
#
|
688
|
+
# @param name [String] name of a platform
|
689
|
+
# @return [Hash] the configuration hash for the platform, or an empty
|
690
|
+
# Hash if not found
|
691
|
+
# @api private
|
205
692
|
def platform_data_for(name)
|
206
|
-
data.fetch(:platforms, Hash.new).find(
|
693
|
+
data.fetch(:platforms, Hash.new).find(-> { Hash.new }) do |platform|
|
207
694
|
platform.fetch(:name, nil) == name
|
208
695
|
end
|
209
696
|
end
|
210
697
|
|
698
|
+
# Destructively sets a base kitchen config key/value pair at the root of
|
699
|
+
# the given hash. If the key is present in the given Hash, it is deleted
|
700
|
+
# and will not be used. If the key is found in the `kitchen_config` hash
|
701
|
+
# (default values), then its value will be used and set. Finally, if
|
702
|
+
# the key is found in `:kitchen` data sub-hash, then its value will be used
|
703
|
+
# and set.
|
704
|
+
#
|
705
|
+
# @param root [Hash] a hash to use as the root of the conversion
|
706
|
+
# @param key [Symbol] the key to search for
|
707
|
+
# @api private
|
211
708
|
def set_kitchen_config_at!(root, key)
|
212
709
|
kdata = data.fetch(:kitchen, Hash.new)
|
213
710
|
|
214
|
-
root.delete(key) if root.
|
215
|
-
root[key] = kitchen_config.fetch(key) if kitchen_config.
|
216
|
-
root[key] = kdata.fetch(key) if kdata.
|
711
|
+
root.delete(key) if root.key?(key)
|
712
|
+
root[key] = kitchen_config.fetch(key) if kitchen_config.key?(key)
|
713
|
+
root[key] = kdata.fetch(key) if kdata.key?(key)
|
217
714
|
end
|
218
715
|
|
716
|
+
# Returns the hash for a suite by name, or an empty Hash if none
|
717
|
+
# could be found.
|
718
|
+
#
|
719
|
+
# @param name [String] name of a suite
|
720
|
+
# @return [Hash] the configuration hash for the suite, or an empty
|
721
|
+
# Hash if not found
|
722
|
+
# @api private
|
219
723
|
def suite_data_for(name)
|
220
|
-
data.fetch(:suites, Hash.new).find(
|
724
|
+
data.fetch(:suites, Hash.new).find(-> { Hash.new }) do |suite|
|
221
725
|
suite.fetch(:name, nil) == name
|
222
726
|
end
|
223
727
|
end
|