test-kitchen-rsync 3.0.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +21 -0
  3. data/LICENSE +15 -0
  4. data/Rakefile +53 -0
  5. data/bin/zl-kitchen +11 -0
  6. data/lib/kitchen/base64_stream.rb +48 -0
  7. data/lib/kitchen/chef_utils_wiring.rb +40 -0
  8. data/lib/kitchen/cli.rb +413 -0
  9. data/lib/kitchen/collection.rb +52 -0
  10. data/lib/kitchen/color.rb +63 -0
  11. data/lib/kitchen/command/action.rb +41 -0
  12. data/lib/kitchen/command/console.rb +54 -0
  13. data/lib/kitchen/command/diagnose.rb +84 -0
  14. data/lib/kitchen/command/doctor.rb +39 -0
  15. data/lib/kitchen/command/exec.rb +37 -0
  16. data/lib/kitchen/command/list.rb +148 -0
  17. data/lib/kitchen/command/login.rb +39 -0
  18. data/lib/kitchen/command/package.rb +32 -0
  19. data/lib/kitchen/command/sink.rb +50 -0
  20. data/lib/kitchen/command/test.rb +47 -0
  21. data/lib/kitchen/command.rb +207 -0
  22. data/lib/kitchen/config.rb +344 -0
  23. data/lib/kitchen/configurable.rb +616 -0
  24. data/lib/kitchen/data_munger.rb +1024 -0
  25. data/lib/kitchen/diagnostic.rb +138 -0
  26. data/lib/kitchen/driver/base.rb +133 -0
  27. data/lib/kitchen/driver/dummy.rb +105 -0
  28. data/lib/kitchen/driver/exec.rb +70 -0
  29. data/lib/kitchen/driver/proxy.rb +70 -0
  30. data/lib/kitchen/driver/ssh_base.rb +351 -0
  31. data/lib/kitchen/driver.rb +40 -0
  32. data/lib/kitchen/errors.rb +243 -0
  33. data/lib/kitchen/generator/init.rb +254 -0
  34. data/lib/kitchen/instance.rb +726 -0
  35. data/lib/kitchen/lazy_hash.rb +148 -0
  36. data/lib/kitchen/lifecycle_hook/base.rb +78 -0
  37. data/lib/kitchen/lifecycle_hook/local.rb +53 -0
  38. data/lib/kitchen/lifecycle_hook/remote.rb +39 -0
  39. data/lib/kitchen/lifecycle_hooks.rb +92 -0
  40. data/lib/kitchen/loader/yaml.rb +377 -0
  41. data/lib/kitchen/logger.rb +422 -0
  42. data/lib/kitchen/logging.rb +52 -0
  43. data/lib/kitchen/login_command.rb +49 -0
  44. data/lib/kitchen/metadata_chopper.rb +49 -0
  45. data/lib/kitchen/platform.rb +64 -0
  46. data/lib/kitchen/plugin.rb +76 -0
  47. data/lib/kitchen/plugin_base.rb +60 -0
  48. data/lib/kitchen/provisioner/base.rb +269 -0
  49. data/lib/kitchen/provisioner/chef/berkshelf.rb +116 -0
  50. data/lib/kitchen/provisioner/chef/common_sandbox.rb +350 -0
  51. data/lib/kitchen/provisioner/chef/policyfile.rb +163 -0
  52. data/lib/kitchen/provisioner/chef_apply.rb +121 -0
  53. data/lib/kitchen/provisioner/chef_base.rb +705 -0
  54. data/lib/kitchen/provisioner/chef_infra.rb +167 -0
  55. data/lib/kitchen/provisioner/chef_solo.rb +82 -0
  56. data/lib/kitchen/provisioner/chef_zero.rb +12 -0
  57. data/lib/kitchen/provisioner/dummy.rb +75 -0
  58. data/lib/kitchen/provisioner/shell.rb +157 -0
  59. data/lib/kitchen/provisioner.rb +42 -0
  60. data/lib/kitchen/rake_tasks.rb +80 -0
  61. data/lib/kitchen/shell_out.rb +90 -0
  62. data/lib/kitchen/ssh.rb +289 -0
  63. data/lib/kitchen/state_file.rb +112 -0
  64. data/lib/kitchen/suite.rb +48 -0
  65. data/lib/kitchen/thor_tasks.rb +63 -0
  66. data/lib/kitchen/transport/base.rb +236 -0
  67. data/lib/kitchen/transport/dummy.rb +78 -0
  68. data/lib/kitchen/transport/exec.rb +145 -0
  69. data/lib/kitchen/transport/ssh.rb +579 -0
  70. data/lib/kitchen/transport/winrm.rb +546 -0
  71. data/lib/kitchen/transport.rb +40 -0
  72. data/lib/kitchen/util.rb +229 -0
  73. data/lib/kitchen/verifier/base.rb +243 -0
  74. data/lib/kitchen/verifier/busser.rb +275 -0
  75. data/lib/kitchen/verifier/dummy.rb +75 -0
  76. data/lib/kitchen/verifier/shell.rb +99 -0
  77. data/lib/kitchen/verifier.rb +39 -0
  78. data/lib/kitchen/version.rb +20 -0
  79. data/lib/kitchen/which.rb +26 -0
  80. data/lib/kitchen.rb +152 -0
  81. data/lib/vendor/hash_recursive_merge.rb +79 -0
  82. data/support/busser_install_command.ps1 +14 -0
  83. data/support/busser_install_command.sh +21 -0
  84. data/support/chef-client-fail-if-update-handler.rb +15 -0
  85. data/support/chef_base_init_command.ps1 +18 -0
  86. data/support/chef_base_init_command.sh +1 -0
  87. data/support/chef_base_install_command.ps1 +85 -0
  88. data/support/chef_base_install_command.sh +229 -0
  89. data/support/download_helpers.sh +109 -0
  90. data/support/dummy-validation.pem +27 -0
  91. data/templates/driver/CHANGELOG.md.erb +3 -0
  92. data/templates/driver/Gemfile.erb +3 -0
  93. data/templates/driver/README.md.erb +64 -0
  94. data/templates/driver/Rakefile.erb +21 -0
  95. data/templates/driver/driver.rb.erb +23 -0
  96. data/templates/driver/gemspec.erb +29 -0
  97. data/templates/driver/gitignore.erb +17 -0
  98. data/templates/driver/license_apachev2.erb +15 -0
  99. data/templates/driver/license_lgplv3.erb +16 -0
  100. data/templates/driver/license_mit.erb +22 -0
  101. data/templates/driver/license_reserved.erb +5 -0
  102. data/templates/driver/tailor.erb +4 -0
  103. data/templates/driver/travis.yml.erb +11 -0
  104. data/templates/driver/version.rb.erb +12 -0
  105. data/templates/init/chefignore.erb +2 -0
  106. data/templates/init/kitchen.yml.erb +18 -0
  107. data/test-kitchen.gemspec +52 -0
  108. metadata +528 -0
@@ -0,0 +1,1024 @@
1
+ #
2
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
3
+ #
4
+ # Copyright (C) 2013, Fletcher Nichol
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require_relative "../vendor/hash_recursive_merge"
19
+
20
+ module Kitchen
21
+ # Class to handle recursive merging of configuration between platforms,
22
+ # suites, and common data.
23
+ #
24
+ # This object will mutate the data Hash passed into its constructor and so
25
+ # should not be reused or shared across threads.
26
+ #
27
+ # If you are squeamish or faint of heart, then you might want to skip this
28
+ # class. Just remember, you were warned. And if you made it this far, be
29
+ # sure to tweet at @fnichol and let him know your fear factor level.
30
+ #
31
+ # @author Fletcher Nichol <fnichol@nichol.ca>
32
+ class DataMunger
33
+ # Constructs a new DataMunger object.
34
+ #
35
+ # @param data [Hash] the incoming user data hash
36
+ # @param kitchen_config [Hash] the incoming Test Kitchen-provided
37
+ # configuration hash
38
+ def initialize(data, kitchen_config = {})
39
+ @data = data
40
+ @kitchen_config = kitchen_config
41
+ convert_legacy_driver_format!
42
+ convert_legacy_chef_paths_format!
43
+ convert_legacy_require_chef_omnibus_format!
44
+ convert_legacy_busser_format!
45
+ convert_legacy_driver_http_proxy_format!
46
+ move_chef_data_to_provisioner!
47
+ convert_legacy_pre_create_command!
48
+ end
49
+
50
+ # Generate a new Hash of configuration data that can be used to construct
51
+ # a new Driver 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 Driver
57
+ def driver_data_for(suite, platform)
58
+ merged_data_for(:driver, suite, platform).tap do |ddata|
59
+ set_kitchen_config_at!(ddata, :kitchen_root)
60
+ set_kitchen_config_at!(ddata, :test_base_path)
61
+ set_kitchen_config_at!(ddata, :log_level)
62
+ end
63
+ end
64
+
65
+ # Generate a new Hash of configuration data that can be used to construct
66
+ # a new LifecycleHooks 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 LifecycleHooks
72
+ def lifecycle_hooks_data_for(suite, platform)
73
+ merged_data_for(:lifecycle, suite, platform).tap do |lhdata|
74
+ lhdata.each_key do |k|
75
+ combine_arrays!(lhdata, k, :common, :platform, :suite)
76
+ end
77
+ set_kitchen_config_at!(lhdata, :kitchen_root)
78
+ set_kitchen_config_at!(lhdata, :test_base_path)
79
+ set_kitchen_config_at!(lhdata, :log_level)
80
+ set_kitchen_config_at!(lhdata, :debug)
81
+ end
82
+ end
83
+
84
+ # Returns an Array of platform Hashes.
85
+ #
86
+ # @return [Array<Hash>] an Array of Hashes
87
+ def platform_data
88
+ data.fetch(:platforms, [])
89
+ end
90
+
91
+ # Generate a new Hash of configuration data that can be used to construct
92
+ # a new Provisioner object.
93
+ #
94
+ # @param suite [String] a suite name
95
+ # @param platform [String] a platform name
96
+ # @return [Hash] a new configuration Hash that can be used to construct a
97
+ # new Provisioner
98
+ def provisioner_data_for(suite, platform)
99
+ merged_data_for(:provisioner, suite, platform).tap do |pdata|
100
+ set_kitchen_config_at!(pdata, :kitchen_root)
101
+ set_kitchen_config_at!(pdata, :test_base_path)
102
+ set_kitchen_config_at!(pdata, :debug)
103
+ combine_arrays!(pdata, :run_list, :platform, :suite)
104
+ end
105
+ end
106
+
107
+ # Returns an Array of suite Hashes.
108
+ #
109
+ # @return [Array<Hash>] an Array of Hashes
110
+ def suite_data
111
+ data.fetch(:suites, [])
112
+ end
113
+
114
+ # Generate a new Hash of configuration data that can be used to construct
115
+ # a new Transport object.
116
+ #
117
+ # @param suite [String] a suite name
118
+ # @param platform [String] a platform name
119
+ # @return [Hash] a new configuration Hash that can be used to construct a
120
+ # new Transport
121
+ def transport_data_for(suite, platform)
122
+ merged_data_for(:transport, suite, platform).tap do |tdata|
123
+ set_kitchen_config_at!(tdata, :kitchen_root)
124
+ set_kitchen_config_at!(tdata, :test_base_path)
125
+ set_kitchen_config_at!(tdata, :log_level)
126
+ end
127
+ end
128
+
129
+ # Generate a new Hash of configuration data that can be used to construct
130
+ # a new Verifier object.
131
+ #
132
+ # @param suite [String] a suite name
133
+ # @param platform [String] a platform name
134
+ # @return [Hash] a new configuration Hash that can be used to construct a
135
+ # new Verifier
136
+ def verifier_data_for(suite, platform)
137
+ merged_data_for(:verifier, suite, platform).tap do |vdata|
138
+ set_kitchen_config_at!(vdata, :kitchen_root)
139
+ set_kitchen_config_at!(vdata, :test_base_path)
140
+ set_kitchen_config_at!(vdata, :log_level)
141
+ set_kitchen_config_at!(vdata, :debug)
142
+ end
143
+ end
144
+
145
+ private
146
+
147
+ # @return [Hash] the user data hash
148
+ # @api private
149
+ attr_reader :data
150
+
151
+ # @return [Hash] the Test Kitchen-provided configuration hash
152
+ # @api private
153
+ attr_reader :kitchen_config
154
+
155
+ def combine_arrays!(root, key, *namespaces)
156
+ if root.key?(key)
157
+ root[key] = namespaces
158
+ .map { |namespace| root.fetch(key).fetch(namespace, []) }.flatten
159
+ .compact
160
+ end
161
+ end
162
+
163
+ # Destructively moves old-style `:busser` configuration hashes into the
164
+ # correct `:verifier` hash.
165
+ #
166
+ # This method converts the following:
167
+ #
168
+ # {
169
+ # :busser => { :one => "two" },
170
+ #
171
+ # :platforms => [
172
+ # {
173
+ # :name => "ubuntu-16.04",
174
+ # :busser => "bar"
175
+ # }
176
+ # ],
177
+ #
178
+ # :suites => [
179
+ # {
180
+ # :name => "alpha",
181
+ # :busser => { :three => "four" }
182
+ # }
183
+ # ]
184
+ # }
185
+ #
186
+ # into the following:
187
+ #
188
+ # {
189
+ # :verifier => {
190
+ # :name => "busser",
191
+ # :one => "two"
192
+ # }
193
+ #
194
+ # :platforms => [
195
+ # {
196
+ # :name => "ubuntu-16.04",
197
+ # :verifier => {
198
+ # :name => "busser",
199
+ # :version => "bar
200
+ # }
201
+ # }
202
+ # ],
203
+ #
204
+ # :suites => [
205
+ # {
206
+ # :name => "alpha",
207
+ # :verifier => {
208
+ # :name => "busser",
209
+ # :three => "four"
210
+ # }
211
+ # }
212
+ # ]
213
+ # }
214
+ #
215
+ # @deprecated The following configuration hashes should no longer be
216
+ # created in a `:platform`, `:suite`, or common location:
217
+ # `:busser`. Use a `:verifier` hash block in their place.
218
+ # @api private
219
+ def convert_legacy_busser_format!
220
+ convert_legacy_busser_format_at!(data)
221
+ data.fetch(:platforms, []).each do |platform|
222
+ convert_legacy_busser_format_at!(platform)
223
+ end
224
+ data.fetch(:suites, []).each do |suite|
225
+ convert_legacy_busser_format_at!(suite)
226
+ end
227
+ end
228
+
229
+ # Destructively moves old-style `:busser` configuration hashes into the
230
+ # correct `:verifier` hashes. This method has no knowledge of suites,
231
+ # platforms, or the like, just a vanilla hash.
232
+ #
233
+ # @param root [Hash] a hash to use as the root of the conversion
234
+ # @deprecated The following configuration hashses should no longer be
235
+ # created in a Test Kitchen hash: `:busser`. Use a `:verifier` hash
236
+ # block in their place.
237
+ # @api private
238
+ def convert_legacy_busser_format_at!(root)
239
+ if root.key?(:busser)
240
+ bdata = root.delete(:busser)
241
+ bdata = { version: bdata } if bdata.is_a?(String)
242
+ bdata[:name] = "busser" if bdata[:name].nil?
243
+
244
+ vdata = root.fetch(:verifier, {})
245
+ vdata = { name: vdata } if vdata.is_a?(String)
246
+ root[:verifier] = bdata.rmerge(vdata)
247
+ end
248
+ end
249
+
250
+ # Destructively moves Chef-related paths out of a suite hash and into the
251
+ # suite's provisioner sub-hash.
252
+ #
253
+ # This method converts the following:
254
+ #
255
+ # {
256
+ # :suites => [
257
+ # {
258
+ # :name => "alpha",
259
+ # :nodes_path => "/a/b/c"
260
+ # },
261
+ # {
262
+ # :name => "beta",
263
+ # :roles_path => "/tmp/roles",
264
+ # :data_bags_path => "/bags"
265
+ # },
266
+ # ]
267
+ # }
268
+ #
269
+ # into the following:
270
+ #
271
+ # {
272
+ # :suites => [
273
+ # {
274
+ # :name => "alpha",
275
+ # :provisioner => {
276
+ # :nodes_path => "/a/b/c"
277
+ # }
278
+ # },
279
+ # {
280
+ # :name => "beta",
281
+ # :provisioner => {
282
+ # :roles_path => "/tmp/roles",
283
+ # :data_bags_path => "/bags"
284
+ # }
285
+ # },
286
+ # ]
287
+ # }
288
+ #
289
+ # @deprecated The following Chef paths should no longer be created directly
290
+ # under a suite hash: [`data_path`, `data_bags_path`,
291
+ # `encrypted_data_bag_secret_key_path`, `environments_path`, `nodes_path`,
292
+ # `roles_path`]. Instead put these key/value pairs directly inside a
293
+ # `provisioner` hash.
294
+ # @api private
295
+ def convert_legacy_chef_paths_format!
296
+ data.fetch(:suites, []).each do |suite|
297
+ %w{
298
+ data data_bags encrypted_data_bag_secret_key
299
+ environments nodes roles
300
+ }.each do |key|
301
+ move_data_to!(:provisioner, suite, "#{key}_path".to_sym)
302
+ end
303
+ end
304
+ end
305
+
306
+ # Destructively moves old-style `:driver_plugin` and `:driver_config`
307
+ # configuration hashes into the correct `:driver` hash.
308
+ #
309
+ # This method converts the following:
310
+ #
311
+ # {
312
+ # :driver_plugin => "foo",
313
+ # :driver_config => { :one => "two" },
314
+ #
315
+ # :platforms => [
316
+ # {
317
+ # :name => "ubuntu-16.04",
318
+ # :driver_plugin => "bar"
319
+ # }
320
+ # ],
321
+ #
322
+ # :suites => [
323
+ # {
324
+ # :name => "alpha",
325
+ # :driver_plugin => "baz"
326
+ # :driver_config => { :three => "four" }
327
+ # }
328
+ # ]
329
+ # }
330
+ #
331
+ # into the following:
332
+ #
333
+ # {
334
+ # :driver => {
335
+ # :name => "foo",
336
+ # :one => "two"
337
+ # }
338
+ #
339
+ # :platforms => [
340
+ # {
341
+ # :name => "ubuntu-16.04",
342
+ # :driver => {
343
+ # :name => "bar"
344
+ # }
345
+ # }
346
+ # ],
347
+ #
348
+ # :suites => [
349
+ # {
350
+ # :name => "alpha",
351
+ # :driver => {
352
+ # :name => "baz",
353
+ # :three => "four"
354
+ # }
355
+ # }
356
+ # ]
357
+ # }
358
+ #
359
+ # @deprecated The following configuration hashes should no longer be
360
+ # created in a `:platform`, `:suite`, or common location:
361
+ # [`:driver_plugin`, `:driver_config`]. Use a `:driver` hash block in
362
+ # their place.
363
+ # @api private
364
+ def convert_legacy_driver_format!
365
+ convert_legacy_driver_format_at!(data)
366
+ data.fetch(:platforms, []).each do |platform|
367
+ convert_legacy_driver_format_at!(platform)
368
+ end
369
+ data.fetch(:suites, []).each do |suite|
370
+ convert_legacy_driver_format_at!(suite)
371
+ end
372
+ end
373
+
374
+ # Destructively moves old-style `:driver_plugin` and `:driver_config`
375
+ # configuration hashes into the correct `:driver` in the first level depth
376
+ # of a hash. This method has no knowledge of suites, platforms, or the
377
+ # like, just a vanilla hash.
378
+ #
379
+ # @param root [Hash] a hash to use as the root of the conversion
380
+ # @deprecated The following configuration hashes should no longer be
381
+ # created in a Test Kitche hash: [`:driver_plugin`, `:driver_config`].
382
+ # Use a `:driver` hash block in their place.
383
+ # @api private
384
+ def convert_legacy_driver_format_at!(root)
385
+ if root.key?(:driver_config)
386
+ ddata = root.fetch(:driver, {})
387
+ ddata = { name: ddata } if ddata.is_a?(String)
388
+ root[:driver] = root.delete(:driver_config).rmerge(ddata)
389
+ end
390
+
391
+ if root.key?(:driver_plugin)
392
+ ddata = root.fetch(:driver, {})
393
+ ddata = { name: ddata } if ddata.is_a?(String)
394
+ root[:driver] = { name: root.delete(:driver_plugin) }.rmerge(ddata)
395
+ end
396
+ end
397
+
398
+ # Copies `:http_proxy` and `:https_proxy` values in a driver hash into the
399
+ # provisioner and verifier hashes. For backwards compatibility with legacy
400
+ # Drivers (those inheriting directly from `SSHBase`), the original
401
+ # values are maintained in the driver hash.
402
+ #
403
+ # This method converts the following:
404
+ #
405
+ # {
406
+ # :driver => {
407
+ # :http_proxy => "http://proxy",
408
+ # :https_proxy => "https://proxy"
409
+ # },
410
+ #
411
+ # :platforms => [
412
+ # {
413
+ # :name => "ubuntu-16.04",
414
+ # :driver => {
415
+ # :http_proxy => "foo"
416
+ # }
417
+ # }
418
+ # ],
419
+ #
420
+ # :suites => [
421
+ # {
422
+ # :name => "alpha",
423
+ # :driver => {
424
+ # :https_proxy => "bar"
425
+ # }
426
+ # }
427
+ # ]
428
+ # }
429
+ #
430
+ # into the following:
431
+ #
432
+ # {
433
+ # :driver => {
434
+ # :http_proxy => "http://proxy",
435
+ # :https_proxy => "https://proxy"
436
+ # },
437
+ #
438
+ # :provisioner => {
439
+ # :http_proxy => "http://proxy",
440
+ # :https_proxy => "https://proxy"
441
+ # },
442
+ #
443
+ # :verifier => {
444
+ # :http_proxy => "http://proxy",
445
+ # :https_proxy => "https://proxy"
446
+ # },
447
+ #
448
+ # :platforms => [
449
+ # {
450
+ # :name => "ubuntu-16.04",
451
+ # :driver => {
452
+ # :http_proxy => "foo"
453
+ # },
454
+ # :provisioner => {
455
+ # :http_proxy => "foo"
456
+ # },
457
+ # :verifier => {
458
+ # :http_proxy => "foo"
459
+ # }
460
+ # }
461
+ # ],
462
+ #
463
+ # :suites => [
464
+ # {
465
+ # :name => "alpha",
466
+ # :driver => {
467
+ # :https_proxy => "bar"
468
+ # },
469
+ # :provisioner => {
470
+ # :https_proxy => "bar"
471
+ # },
472
+ # :verifier => {
473
+ # :https_proxy => "bar"
474
+ # }
475
+ # }
476
+ # ]
477
+ # }
478
+ #
479
+ # @deprecated The `:http_proxy` and `:https_proxy` should no longer be
480
+ # used in driver blocks, they should be added to the provisioner and
481
+ # verifier blocks so that they can be independantly configured.
482
+ # Provisioners and Verifiers are responsible for HTTP proxying and no
483
+ # longer are Drivers responsible for this.
484
+ # @api private
485
+ def convert_legacy_driver_http_proxy_format!
486
+ convert_legacy_driver_http_proxy_format_at!(data)
487
+ data.fetch(:platforms, []).each do |platform|
488
+ convert_legacy_driver_http_proxy_format_at!(platform)
489
+ end
490
+ data.fetch(:suites, []).each do |suite|
491
+ convert_legacy_driver_http_proxy_format_at!(suite)
492
+ end
493
+ end
494
+
495
+ # Copies `:http_proxy` and `:https_proxy` values in a driver hash into
496
+ # the provisioner and verifier hashes. This method has no knowledge of
497
+ # suites, platforms, or the like, just a vanilla hash.
498
+ #
499
+ # @param root [Hash] a hash to use as the root of the conversion
500
+ # @deprecated The `:http_proxy` and `:https_proxy` should no longer be
501
+ # used in driver blocks, they should be added to the provisioner and
502
+ # verifier blocks so that they can be independantly configured.
503
+ # Provisioners and Verifiers are responsible for HTTP proxying and no
504
+ # longer are Drivers responsible for this.
505
+ # @api private
506
+ def convert_legacy_driver_http_proxy_format_at!(root)
507
+ ddata = root.fetch(:driver, {})
508
+
509
+ %i{http_proxy https_proxy}.each do |key|
510
+ next unless ddata.is_a?(Hash) && ddata.key?(key)
511
+
512
+ pdata = root.fetch(:provisioner, {})
513
+ pdata = { name: pdata } if pdata.is_a?(String)
514
+ root[:provisioner] = { key => ddata.fetch(key) }.rmerge(pdata)
515
+
516
+ vdata = root.fetch(:verifier, {})
517
+ vdata = { name: vdata } if vdata.is_a?(String)
518
+ root[:verifier] = { key => ddata.fetch(key) }.rmerge(vdata)
519
+ end
520
+ end
521
+
522
+ # Destructively moves a `:require_chef_omnibus` key/value pair from a
523
+ # `:driver` hash block to a `:provisioner` hash block.
524
+ #
525
+ # This method converts the following:
526
+ #
527
+ # {
528
+ # :driver => {
529
+ # :require_chef_omnibus => true
530
+ # }
531
+ #
532
+ # :platforms => [
533
+ # {
534
+ # :name => "ubuntu-16.04",
535
+ # :driver => {
536
+ # :require_chef_omnibus => "10.8.2"
537
+ # }
538
+ # }
539
+ # ],
540
+ #
541
+ # :suites => [
542
+ # {
543
+ # :name => "alpha",
544
+ # :driver => {
545
+ # :require_chef_omnibus => "11"
546
+ # }
547
+ # }
548
+ # ]
549
+ # }
550
+ #
551
+ # into the following:
552
+ #
553
+ # {
554
+ # :provisioner => {
555
+ # :require_chef_omnibus => true
556
+ # }
557
+ #
558
+ # :platforms => [
559
+ # {
560
+ # :name => "ubuntu-16.04",
561
+ # :provisioner => {
562
+ # :require_chef_omnibus => "10.8.2"
563
+ # }
564
+ # }
565
+ # ],
566
+ #
567
+ # :suites => [
568
+ # {
569
+ # :name => "alpha",
570
+ # :provisioner => {
571
+ # :require_chef_omnibus => "11"
572
+ # }
573
+ # }
574
+ # ]
575
+ # }
576
+ #
577
+ # @deprecated The `:require_chef_omnibus` key/value pair should no longer
578
+ # be created inside a `:driver` hash block. Put it in a `:provisioner`
579
+ # hash block instead.
580
+ # @api private
581
+ def convert_legacy_require_chef_omnibus_format!
582
+ convert_legacy_require_chef_omnibus_format_at!(data)
583
+ data.fetch(:platforms, []).each do |platform|
584
+ convert_legacy_require_chef_omnibus_format_at!(platform)
585
+ end
586
+ data.fetch(:suites, []).each do |suite|
587
+ convert_legacy_require_chef_omnibus_format_at!(suite)
588
+ end
589
+ end
590
+
591
+ # Destructively moves a `:require_chef_omnibus` key/value pair from a
592
+ # `:driver` hash block to a `:provisioner` hash block in the first leve
593
+ # depth of a hash. This method has no knowledge of suites, platforms, or
594
+ # the like, just a vanilla haash.
595
+ #
596
+ # @param root [Hash] a hash to use as the root of the conversion
597
+ # @deprecated The `:require_chef_omnibus` key/value pair should no longer
598
+ # be created inside a `:driver` hash block. Put it in a `:provisioner`
599
+ # hash block instead.
600
+ # @api private
601
+ def convert_legacy_require_chef_omnibus_format_at!(root)
602
+ key = :require_chef_omnibus
603
+ ddata = root.fetch(:driver, {})
604
+
605
+ if ddata.is_a?(Hash) && ddata.key?(key)
606
+ pdata = root.fetch(:provisioner, {})
607
+ pdata = { name: pdata } if pdata.is_a?(String)
608
+ root[:provisioner] =
609
+ { key => root.fetch(:driver).delete(key) }.rmerge(pdata)
610
+ end
611
+ end
612
+
613
+ def convert_legacy_pre_create_command!
614
+ convert_legacy_pre_create_command_at!(data)
615
+ data.fetch(:platforms, []).each do |platform|
616
+ convert_legacy_pre_create_command_at!(platform)
617
+ end
618
+ data.fetch(:suites, []).each do |suite|
619
+ convert_legacy_pre_create_command_at!(suite)
620
+ end
621
+ end
622
+
623
+ def convert_legacy_pre_create_command_at!(root)
624
+ ddata = root[:driver] || {}
625
+ if ddata.is_a?(Hash) && ddata.include?(:pre_create_command)
626
+ root[:lifecycle] ||= {}
627
+ root[:lifecycle][:pre_create] ||= []
628
+ root[:lifecycle][:pre_create] = Array(root[:lifecycle][:pre_create])
629
+ root[:lifecycle][:pre_create] << { local: ddata[:pre_create_command] }
630
+ ddata.delete(:pre_create_command)
631
+ end
632
+ end
633
+
634
+ # Performs a prioritized recursive merge of several source Hashes and
635
+ # returns a new merged Hash. For these data sub-hash structures, there are
636
+ # 4 sources for configuration data:
637
+ #
638
+ # 1. defaults, provided by Test Kitchen code
639
+ # 2. user-provided in the common root-level of the incoming data hash
640
+ # 3. user-provided in a platform sub-hash
641
+ # 4. user-provided in a suite sub-hash
642
+ #
643
+ # The merge order is 4 -> 3 -> 2 -> 1, meaning that the highest number in
644
+ # the above list has merge precedence over any lower numbered source. Put
645
+ # another way, a key/value pair in a suite sub-hash will be used over the
646
+ # key/value pair in a platform sub-hash.
647
+ #
648
+ # @param key [Symbol] the data sub-hash(es) to merge
649
+ # @param suite [String] a suite name
650
+ # @param platform [String] a platform name
651
+ # @param default_key [Symbol] the default key to use when normalizing the
652
+ # data sub-hashes (default: `:name`)
653
+ # @return [Hash] a new merged Hash
654
+ # @api private
655
+ def merged_data_for(key, suite, platform, default_key = :name)
656
+ ddata = normalized_default_data(key, default_key, suite, platform)
657
+ cdata = normalized_common_data(key, default_key)
658
+ pdata = normalized_platform_data(key, default_key, platform)
659
+ sdata = normalized_suite_data(key, default_key, suite)
660
+
661
+ ddata.rmerge(cdata.rmerge(pdata.rmerge(sdata)))
662
+ end
663
+
664
+ # Destructively moves key Chef configuration key/value pairs from being
665
+ # directly under a suite or platform into a `:provisioner` sub-hash.
666
+ #
667
+ # There are three key Chef configuration key/value pairs:
668
+ #
669
+ # 1. `:attributes`
670
+ # 2. `:run_list`
671
+ # 3. `:named_run_list`
672
+ #
673
+ # This method converts the following:
674
+ #
675
+ # {
676
+ # :platforms => [
677
+ # {
678
+ # :name => "ubuntu-16.04",
679
+ # :attributes => { :one => "two" },
680
+ # :run_list => ["alpha", "bravo"]
681
+ # }
682
+ # ],
683
+ #
684
+ # :suites => [
685
+ # {
686
+ # :name => "alpha",
687
+ # :attributes => { :three => "four" },
688
+ # :run_list => ["charlie", "delta"]
689
+ # }
690
+ # ]
691
+ # }
692
+ #
693
+ # into the following:
694
+ #
695
+ # {
696
+ # :platforms => [
697
+ # {
698
+ # :name => "ubuntu-16.04",
699
+ # :provisioner => {
700
+ # :attributes => { :one => "two" },
701
+ # :run_list => ["alpha", "bravo"]
702
+ # }
703
+ # }
704
+ # ],
705
+ #
706
+ # :suites => [
707
+ # {
708
+ # :name => "alpha",
709
+ # :provisioner => {
710
+ # :attributes => { :three => "four" },
711
+ # :run_list => ["charlie", "delta"]
712
+ # }
713
+ # }
714
+ # ]
715
+ # }
716
+ #
717
+ # @api private
718
+ def move_chef_data_to_provisioner!
719
+ data.fetch(:suites, []).each do |suite|
720
+ move_data_to!(:provisioner, suite, :attributes)
721
+ move_data_to!(:provisioner, suite, :run_list)
722
+ move_data_to!(:provisioner, suite, :named_run_list)
723
+ move_data_to!(:provisioner, suite, :policy_group)
724
+ end
725
+
726
+ data.fetch(:platforms, []).each do |platform|
727
+ move_data_to!(:provisioner, platform, :attributes)
728
+ move_data_to!(:provisioner, platform, :run_list)
729
+ move_data_to!(:provisioner, platform, :named_run_list)
730
+ move_data_to!(:provisioner, platform, :policy_group)
731
+ end
732
+ end
733
+
734
+ # Destructively moves key Chef configuration key/value pairs from being
735
+ # directly under a hash into a `:provisioner` sub-hash block. This method
736
+ # has no knowledge of suites, platforms, or the like, just a vanilla hash.
737
+ #
738
+ # @param root [Hash] a hash to use as the root of the conversion
739
+ # @param key [Symbol] a key in the root hash to move into a `:provisioner`
740
+ # sub-hash block
741
+ # @api private
742
+ def move_data_to!(to, root, key)
743
+ if root.key?(key)
744
+ pdata = root.fetch(to, {})
745
+ pdata = { name: pdata } if pdata.is_a?(String)
746
+ unless root.fetch(key, nil).nil?
747
+ root[to] = pdata.rmerge(key => root.delete(key))
748
+ end
749
+ end
750
+ end
751
+
752
+ # Vicious hack to allow for Array-appending merge semantics. This method
753
+ # takes an array value and transforms it into a hash with a bucket name
754
+ # containing the original Array. This way semantic Hash merging will do
755
+ # its thing and another process can collapse the hash into a flat array
756
+ # afterwards, given a strategy (like use the array segmenet from one
757
+ # bucket first, then another one second). To anyone who made it this far,
758
+ # Fletcher appologizes.
759
+ #
760
+ # @param root [Hash] a hash to use as the root of the conversion
761
+ # @param key [Symbol] a key in the root hash that, if exists, has its
762
+ # value transformed into a sub-hash
763
+ # @param bucket [Symbol] a key to use for the sub-hash
764
+ # @api private
765
+ def namespace_array!(root, key, bucket)
766
+ root[key] = { bucket => root.fetch(key) } if root.key?(key)
767
+ end
768
+
769
+ # Normalizes a specific key in the root of the data hash to be a proper
770
+ # sub-hash in all cases. Specifically handled are the following cases:
771
+ #
772
+ # * If the value for a key is set to `nil`, a new Hash will be put in
773
+ # its place.
774
+ # * If the value is a String, then convert the value to a new Hash with
775
+ # a default key pointing to the original String
776
+ #
777
+ # Given a hash:
778
+ #
779
+ # { :driver => nil }
780
+ #
781
+ # this method (`normalized_common_data(:driver, :name)`) would return:
782
+ #
783
+ # {}
784
+ #
785
+ # Given a hash:
786
+ #
787
+ # { :driver => "coolbeans" }
788
+ #
789
+ # this method (`normalized_common_data(:driver, :name)`) would return:
790
+ #
791
+ # { :name => "coolbeans" }
792
+ #
793
+ # @param key [Symbol] the value to normalize
794
+ # @param default_key [Symbol] the implicit default key if a String value
795
+ # is given
796
+ # @return [Hash] a shallow Hash copy of the original if not modified, or a
797
+ # new Hash otherwise
798
+ # @api private
799
+ def normalized_common_data(key, default_key)
800
+ cdata = data.fetch(key, {})
801
+ cdata = cdata.nil? ? {} : cdata.dup
802
+ cdata = { default_key => cdata } if cdata.is_a?(String)
803
+ case key
804
+ when :lifecycle
805
+ cdata.each_key do |k|
806
+ namespace_array!(cdata, k, :common)
807
+ end
808
+ end
809
+ cdata
810
+ end
811
+
812
+ # Normalizes a specific key in the `:defaults` data sub-hash to be a proper
813
+ # sub-hash in all cases. Specifically handled are the following cases:
814
+ #
815
+ # * If the value for a key is not set, a new Hash will be put in its place
816
+ # * If the value is a String, then convert the value to a new Hash with
817
+ # a default key pointing to the original String
818
+ #
819
+ # Given a hash:
820
+ #
821
+ # {
822
+ # :defaults => {}
823
+ # }
824
+ #
825
+ # this method (`normalized_default_data(:driver, :name)`) would return:
826
+ #
827
+ # {}
828
+ #
829
+ # Given a hash:
830
+ #
831
+ # {
832
+ # :defaults => {
833
+ # :driver => "coolbeans"
834
+ # }
835
+ # }
836
+ #
837
+ # this method (`normalized_default_data(:driver, :name)`) would return:
838
+ #
839
+ # { :name => "coolbeans" }
840
+ #
841
+ # @param key [Symbol] the value to normalize
842
+ # @param default_key [Symbol] the implicit default key if a String value
843
+ # is given
844
+ # @param suite [String] name of a suite
845
+ # @param platform [String] name of a platform
846
+ # @return [Hash] a shallow Hash copy of the original if not modified, or a
847
+ # new Hash otherwise
848
+ # @api private
849
+ def normalized_default_data(key, default_key, suite, platform)
850
+ ddata = kitchen_config.fetch(:defaults, {}).fetch(key, {}).dup
851
+ ddata = { default_key => ddata.call(suite, platform) } if ddata.is_a?(Proc)
852
+ ddata = { default_key => ddata } if ddata.is_a?(String)
853
+ ddata
854
+ end
855
+
856
+ # Normalizes a specific key in a platform hash data sub-hash to be a proper
857
+ # sub-hash in all cases. Specifically handled are the following cases:
858
+ #
859
+ # * If the value for a key is set to `nil`, a new Hash will be put in
860
+ # its place.
861
+ # * If the value is a String, then convert the value to a new Hash with
862
+ # a default key pointing to the original String
863
+ #
864
+ # Given a hash:
865
+ #
866
+ # {
867
+ # :platforms => [
868
+ # {
869
+ # :name => "alpha",
870
+ # :driver => nil
871
+ # }
872
+ # ]
873
+ # }
874
+ #
875
+ # this method (`normalized_platform_data(:driver, :name, "alpha)`) would
876
+ # return:
877
+ #
878
+ # {}
879
+ #
880
+ # Given a hash:
881
+ #
882
+ # {
883
+ # :platforms => [
884
+ # {
885
+ # :name => "alpha",
886
+ # :driver => "coolbeans"
887
+ # }
888
+ # ]
889
+ # }
890
+ #
891
+ # this method (`normalized_common_data(:driver, :name, "alpha")`) would
892
+ # return:
893
+ #
894
+ # { :name => "coolbeans" }
895
+ #
896
+ # @param key [Symbol] the value to normalize
897
+ # @param default_key [Symbol] the implicit default key if a String value
898
+ # is given
899
+ # @param platform [String] name of a platform
900
+ # @return [Hash] a shallow Hash copy of the original if not modified, or a
901
+ # new Hash otherwise
902
+ # @api private
903
+ def normalized_platform_data(key, default_key, platform)
904
+ pdata = platform_data_for(platform).fetch(key, {})
905
+ pdata = pdata.nil? ? {} : pdata.dup
906
+ pdata = { default_key => pdata } if pdata.is_a?(String)
907
+ case key
908
+ when :provisioner
909
+ namespace_array!(pdata, :run_list, :platform)
910
+ when :lifecycle
911
+ pdata.each_key do |k|
912
+ namespace_array!(pdata, k, :platform)
913
+ end
914
+ end
915
+ pdata
916
+ end
917
+
918
+ # Normalizes a specific key in a suite hash data sub-hash to be a proper
919
+ # sub-hash in all cases. Specifically handled are the following cases:
920
+ #
921
+ # * If the value for a key is set to `nil`, a new Hash will be put in
922
+ # its place.
923
+ # * If the value is a String, then convert the value to a new Hash with
924
+ # a default key pointing to the original String
925
+ #
926
+ # Given a hash:
927
+ #
928
+ # {
929
+ # :suites => [
930
+ # {
931
+ # :name => "full",
932
+ # :driver => nil
933
+ # }
934
+ # ]
935
+ # }
936
+ #
937
+ # this method (`normalized_platform_data(:driver, :name, "full)`) would
938
+ # return:
939
+ #
940
+ # {}
941
+ #
942
+ # Given a hash:
943
+ #
944
+ # {
945
+ # :suites => [
946
+ # {
947
+ # :name => "full",
948
+ # :driver => "coolbeans"
949
+ # }
950
+ # ]
951
+ # }
952
+ #
953
+ # this method (`normalized_common_data(:driver, :name, "full")`) would
954
+ # return:
955
+ #
956
+ # { :name => "coolbeans" }
957
+ #
958
+ # @param key [Symbol] the value to normalize
959
+ # @param default_key [Symbol] the implicit default key if a String value
960
+ # is given
961
+ # @param suite [String] name of a suite
962
+ # @return [Hash] a shallow Hash copy of the original if not modified, or a
963
+ # new Hash otherwise
964
+ # @api private
965
+ def normalized_suite_data(key, default_key, suite)
966
+ sdata = suite_data_for(suite).fetch(key, {})
967
+ sdata = sdata.nil? ? {} : sdata.dup
968
+ sdata = { default_key => sdata } if sdata.is_a?(String)
969
+ case key
970
+ when :provisioner
971
+ namespace_array!(sdata, :run_list, :suite)
972
+ when :lifecycle
973
+ sdata.each_key do |k|
974
+ namespace_array!(sdata, k, :suite)
975
+ end
976
+ end
977
+ sdata
978
+ end
979
+
980
+ # Returns the hash for a platform by name, or an empty Hash if none
981
+ # could be found.
982
+ #
983
+ # @param name [String] name of a platform
984
+ # @return [Hash] the configuration hash for the platform, or an empty
985
+ # Hash if not found
986
+ # @api private
987
+ def platform_data_for(name)
988
+ data.fetch(:platforms, {}).find(-> { {} }) do |platform|
989
+ platform.fetch(:name, nil) == name
990
+ end
991
+ end
992
+
993
+ # Destructively sets a base kitchen config key/value pair at the root of
994
+ # the given hash. If the key is present in the given Hash, it is deleted
995
+ # and will not be used. If the key is found in the `kitchen_config` hash
996
+ # (default values), then its value will be used and set. Finally, if
997
+ # the key is found in `:kitchen` data sub-hash, then its value will be used
998
+ # and set.
999
+ #
1000
+ # @param root [Hash] a hash to use as the root of the conversion
1001
+ # @param key [Symbol] the key to search for
1002
+ # @api private
1003
+ def set_kitchen_config_at!(root, key)
1004
+ kdata = data.fetch(:kitchen, {})
1005
+
1006
+ root.delete(key) if root.key?(key)
1007
+ root[key] = kitchen_config.fetch(key) if kitchen_config.key?(key)
1008
+ root[key] = kdata.fetch(key) if kdata.key?(key)
1009
+ end
1010
+
1011
+ # Returns the hash for a suite by name, or an empty Hash if none
1012
+ # could be found.
1013
+ #
1014
+ # @param name [String] name of a suite
1015
+ # @return [Hash] the configuration hash for the suite, or an empty
1016
+ # Hash if not found
1017
+ # @api private
1018
+ def suite_data_for(name)
1019
+ data.fetch(:suites, {}).find(-> { {} }) do |suite|
1020
+ suite.fetch(:name, nil) == name
1021
+ end
1022
+ end
1023
+ end
1024
+ end