test-kitchen 1.2.1 → 1.3.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 +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
|