kitchen-provisioner-ice-temp 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 468d51adccc34199758691e4f870dc8871355fd30385f4566fce0ff45d13c37e
4
+ data.tar.gz: 0cc08b227af5a42025f618d83d45fcc7d4ed3a575bca390e669dccb5551816f8
5
+ SHA512:
6
+ metadata.gz: fc7ac161ce6246f10c1631dabac90620a56d6eb091291b629235e4ad3d3b539d4790ee14df3e2c79e80ba05eb57684a23a81dc1e8e90618e2fa8381f89e62989
7
+ data.tar.gz: 2cbadb303a0b7bc1ccd81a67beb977393f0ce197f908b0d27e5806462c35a52f718a42712386b1adcbe75366cd0188682b03cc2911b15e13671044028890b833
data/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # kitchen-provisioner-ice-temp
2
+
3
+ > **⚠️ This is a temporary stopgap gem.**
4
+ > It provides Chef ICE (Chef Infra Client 19+) support for Test Kitchen
5
+ > until a future Chef Workstation release ships with native chef-ice
6
+ > provisioning built in. Once you upgrade to that version of Chef
7
+ > Workstation, **uninstall this gem** and switch your `kitchen.yml` back
8
+ > to the built-in provisioner.
9
+
10
+ A [Test Kitchen](https://kitchen.ci/) provisioner for **Chef ICE** (Chef Infra Client 19+).
11
+
12
+ This is a thin layer on top of the existing `ChefInfra` provisioner from `kitchen-omnibus-chef`. It overrides only the install path to use the Chef commercial downloads API (or a direct URL). Everything else — cookbook upload, data bags, roles, config files, `chef-client --local-mode` execution — is inherited.
13
+
14
+ ## Installation
15
+
16
+ ```
17
+ gem install kitchen-provisioner-ice-temp
18
+ ```
19
+
20
+ Or in your cookbook's `Gemfile`:
21
+
22
+ ```ruby
23
+ gem "kitchen-provisioner-ice-temp"
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ### Via Chef commercial downloads API
29
+
30
+ ```yaml
31
+ provisioner:
32
+ name: chef_ice
33
+ product_version: 19.2.12 # or "latest"
34
+ channel: stable
35
+ chef_license_key: "your-key" # or set CHEF_LICENSE_KEY env var
36
+ chef_license: accept
37
+ ```
38
+
39
+ ### Via direct download URL
40
+
41
+ ```yaml
42
+ provisioner:
43
+ name: chef_ice
44
+ download_url: https://my-mirror.example.com/chef-ice-19.2.12-1_amd64.deb
45
+ checksum: abc123... # optional SHA-256
46
+ chef_license: accept
47
+ ```
48
+
49
+ ### Skip installation (pre-baked image)
50
+
51
+ ```yaml
52
+ provisioner:
53
+ name: chef_ice
54
+ install_strategy: skip
55
+ chef_license: accept
56
+ ```
57
+
58
+ ## Configuration
59
+
60
+ All settings from the standard `chef_infra` / `chef_zero` provisioner are supported. Additional settings:
61
+
62
+ | Setting | Default | Description |
63
+ |---------|---------|-------------|
64
+ | `product_version` | `latest` | Chef ICE version |
65
+ | `channel` | `stable` | Release channel |
66
+ | `chef_license_key` | `ENV["CHEF_LICENSE_KEY"]` | License key for commercial API |
67
+ | `downloads_api_url` | `https://commercial-acceptance.downloads.chef.co` | API base URL |
68
+ | `download_url` | `nil` | Direct package URL (bypasses API) |
69
+
70
+ ## Removal
71
+
72
+ When a future Chef Workstation ships with native chef-ice support:
73
+
74
+ 1. **Uninstall the gem:**
75
+
76
+ ```
77
+ chef exec gem uninstall kitchen-provisioner-ice-temp
78
+ ```
79
+
80
+ 2. **Update `kitchen.yml`** — the provisioner name `chef_ice` won't change, but check the Chef Workstation release notes in case the built-in provisioner uses a different name.
81
+
82
+ 3. **Remove from Gemfile** (if listed):
83
+
84
+ ```ruby
85
+ # DELETE this line:
86
+ gem "kitchen-provisioner-ice-temp"
87
+ ```
88
+
89
+ That's it — all other configuration (`product_version`, `channel`, `chef_license_key`, etc.) should carry over to the built-in provisioner unchanged.
90
+
91
+ ## License
92
+
93
+ Apache-2.0
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Provisioner
5
+ CHEF_ICE_VERSION = begin
6
+ dir = File.expand_path("../../..", __dir__)
7
+ if File.directory?(File.join(dir, ".git"))
8
+ tag = `git -C #{dir} describe --tags --match 'v*' 2>/dev/null`.strip
9
+ tag.empty? ? "0.0.0" : tag.sub(/^v/, "").sub(/-(\d+)-g/, '.\1.dev.')
10
+ else
11
+ Gem.loaded_specs["kitchen-provisioner-ice-temp"]&.version&.to_s || "0.0.0"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,467 @@
1
+ # Test Kitchen provisioner for Chef ICE (Chef Infra Client 19+).
2
+ #
3
+ # Thin layer on top of the existing ChefInfra provisioner from
4
+ # kitchen-omnibus-chef. Only overrides the install path to use the
5
+ # Chef commercial downloads API or a direct download URL.
6
+ # Everything else (sandbox, config files, run_command, policyfile/berkshelf)
7
+ # is inherited from ChefInfra.
8
+ #
9
+ # Architecture
10
+ # ------------
11
+ # The package is downloaded in Ruby on the workstation during
12
+ # create_sandbox, placed in the sandbox directory, and uploaded to
13
+ # the node with the rest of the sandbox files (cookbooks, config, etc.).
14
+ #
15
+ # prepare_command (which runs AFTER the sandbox upload but BEFORE
16
+ # run_command) installs the local package file using the native
17
+ # package manager. No curl/wget is needed on the node, no URLs
18
+ # appear in the shell script, and the license key never leaves
19
+ # the workstation.
20
+
21
+ require "kitchen/provisioner/chef_infra"
22
+ require_relative "chef_ice/version"
23
+ require "json"
24
+ require "net/http"
25
+ require "uri"
26
+ require "fileutils"
27
+ require "digest"
28
+
29
+
30
+
31
+ module Kitchen
32
+ module Provisioner
33
+ class ChefIce < ChefInfra
34
+ kitchen_provisioner_api_version 2
35
+
36
+ plugin_version Kitchen::Provisioner::CHEF_ICE_VERSION
37
+
38
+ # Do NOT set product_name — it triggers mixlib-install validation
39
+ # in the parent which doesn't know about chef-ice.
40
+ # Instead we set require_chef_omnibus to false and handle install ourselves.
41
+ default_config :require_chef_omnibus, false
42
+
43
+ # Commercial downloads API base URL
44
+ default_config :downloads_api_url, "https://commercial-acceptance.downloads.chef.co"
45
+
46
+ # Licence key for the commercial downloads API
47
+ default_config :chef_license_key do |_p|
48
+ ENV["CHEF_LICENSE_KEY"]
49
+ end
50
+
51
+ default_config :product_version, "latest"
52
+ default_config :channel, "stable"
53
+ default_config :install_strategy, "once" # once, always, skip
54
+ default_config :download_url, nil
55
+ default_config :checksum, nil
56
+
57
+ # Skip the enterprise gem delegation dance from ChefInfra —
58
+ # we ARE the replacement provisioner.
59
+ def self.new(config = {})
60
+ allocate.tap { |i| i.send(:initialize, config) }
61
+ end
62
+
63
+ # --- sandbox --------------------------------------------------
64
+
65
+ # Download the chef-ice package into the sandbox so it gets
66
+ # uploaded alongside cookbooks, data bags, etc.
67
+ def create_sandbox
68
+ super
69
+ return if config[:install_strategy] == "skip"
70
+
71
+ prepare_package
72
+ end
73
+
74
+ # --- commands sent to the node --------------------------------
75
+
76
+ # install_command runs BEFORE the sandbox upload.
77
+ # We only use it for the guard check — actual install happens
78
+ # in prepare_command after the package file has been uploaded.
79
+ def install_command
80
+ return if config[:install_strategy] == "skip"
81
+
82
+ prefix_command(wrap_shell_code(install_guard))
83
+ end
84
+
85
+ # prepare_command runs AFTER sandbox upload and BEFORE run_command.
86
+ # The package file(s) are now on the node under root_path.
87
+ def prepare_command
88
+ return if config[:install_strategy] == "skip"
89
+ return unless @package_files && !@package_files.empty?
90
+
91
+ prefix_command(wrap_shell_code(install_package_script))
92
+ end
93
+
94
+ # Skip the parent's license check which goes through
95
+ # license-acceptance gem with product names it may not recognise.
96
+ def check_license
97
+ # chef-ice license is handled by chef_license / chef_license_key
98
+ # config passed to chef-client at run time.
99
+ end
100
+
101
+ private
102
+
103
+ # ---------------------------------------------------------------
104
+ # Package download (runs on workstation during create_sandbox)
105
+ # ---------------------------------------------------------------
106
+
107
+ # Decide which path to take and download the package into the
108
+ # sandbox directory.
109
+ def prepare_package
110
+ if config[:download_url]
111
+ download_from_url
112
+ elsif config[:chef_license_key]
113
+ download_from_api
114
+ else
115
+ raise UserError,
116
+ "chef_license_key is required to download chef-ice from the " \
117
+ "commercial downloads API. Set it in kitchen.yml or via the " \
118
+ "CHEF_LICENSE_KEY env var. Alternatively, set download_url to " \
119
+ "point at a local package."
120
+ end
121
+ end
122
+
123
+ # Download from a user-supplied direct URL.
124
+ def download_from_url
125
+ url = config[:download_url]
126
+ name = File.basename(URI.parse(url).path)
127
+ dest = File.join(sandbox_path, name)
128
+
129
+ info("Downloading chef-ice from #{url}")
130
+ http_download(URI.parse(url), dest)
131
+ verify_sha256(dest, config[:checksum]) if config[:checksum]
132
+
133
+ @package_files = [{ filename: name }]
134
+ end
135
+
136
+ # Walk the commercial downloads API and download the correct
137
+ # package(s) for the target platform into the sandbox.
138
+ def download_from_api
139
+ version = resolve_version
140
+ packages = fetch_packages(version)
141
+
142
+ info("Chef ICE #{version} (license: ****)")
143
+
144
+ # Only download formats the target platform can use.
145
+ formats = windows_os? ? %w[msi] : %w[rpm deb]
146
+ platform = windows_os? ? "windows" : "linux"
147
+
148
+ @package_files = []
149
+
150
+ packages.each do |arch, pm_map|
151
+ formats.each do |pm|
152
+ detail = pm_map[pm]
153
+ next unless detail
154
+
155
+ url = detail["url"]
156
+ sha256 = detail["sha256"]
157
+
158
+ # Check the shared Chef Workstation cache first.
159
+ # Layout: ~/.chef/cached-packages/{platform}/{arch}/{pm}/chef-ice/{version}/
160
+ cache_subdir = File.join(platform, arch, pm, "chef-ice", version)
161
+ cached = find_in_cache(cache_subdir, sha256)
162
+
163
+ if cached
164
+ filename = File.basename(cached)
165
+ dest = File.join(sandbox_path, filename)
166
+ info(" Using cached #{filename}")
167
+ FileUtils.cp(cached, dest)
168
+ else
169
+ # Download to a temp location, resolve real filename from
170
+ # Content-Disposition header, then move into cache.
171
+ info(" Downloading chef-ice #{version} #{pm} (#{arch})")
172
+ tmpfile = File.join(sandbox_path, "chef-ice-download.tmp")
173
+ real_name = http_download(URI.parse(url), tmpfile)
174
+
175
+ # Use Content-Disposition filename if we got one,
176
+ # otherwise fall back to a constructed name.
177
+ filename = real_name || "chef-ice-#{version}-#{arch}.#{pm}"
178
+ dest = File.join(sandbox_path, filename)
179
+ FileUtils.mv(tmpfile, dest) if File.exist?(tmpfile)
180
+
181
+ verify_sha256(dest, sha256) if sha256 && !sha256.empty?
182
+ store_in_cache(dest, cache_subdir, sha256)
183
+ end
184
+
185
+ @package_files << { arch: arch, pm: pm, filename: filename }
186
+ end
187
+ end
188
+
189
+ if @package_files.empty?
190
+ raise UserError, "No downloadable packages found for chef-ice #{version}"
191
+ end
192
+ end
193
+
194
+ # ---------------------------------------------------------------
195
+ # API helpers (run on workstation — key never sent to the node)
196
+ # ---------------------------------------------------------------
197
+
198
+ # GET a JSON endpoint from the commercial downloads API.
199
+ def api_get(path, params = {})
200
+ params["license_id"] = config[:chef_license_key]
201
+ uri = URI.parse("#{config[:downloads_api_url]}#{path}")
202
+ uri.query = URI.encode_www_form(params)
203
+
204
+ response = http_get_follow(uri, 5)
205
+
206
+ unless response.is_a?(Net::HTTPSuccess)
207
+ safe_uri = uri.to_s.gsub(config[:chef_license_key].to_s, "****")
208
+ raise UserError,
209
+ "Chef downloads API returned #{response.code}: " \
210
+ "#{response.body.strip} (#{safe_uri})"
211
+ end
212
+
213
+ JSON.parse(response.body)
214
+ end
215
+
216
+ # Resolve "latest" to a concrete version string.
217
+ def resolve_version
218
+ version = config[:product_version]
219
+ return version unless version.nil? || version == "latest"
220
+
221
+ channel = config[:channel]
222
+ versions = api_get("/#{channel}/chef-ice/versions/all")
223
+
224
+ raise UserError, "No versions found for chef-ice on #{channel} channel" if versions.empty?
225
+
226
+ versions.sort_by { |v| Gem::Version.new(v) }.last
227
+ end
228
+
229
+ # Fetch the packages map and merge all platform keys.
230
+ # Returns: { "x86_64" => { "rpm" => { ... }, "deb" => { ... } }, ... }
231
+ def fetch_packages(version)
232
+ channel = config[:channel]
233
+ response = api_get("/#{channel}/chef-ice/packages", "v" => version)
234
+
235
+ merged = {}
236
+ response.each_value do |arch_map|
237
+ next unless arch_map.is_a?(Hash)
238
+
239
+ arch_map.each do |arch, pm_map|
240
+ merged[arch] ||= {}
241
+ merged[arch].merge!(pm_map) if pm_map.is_a?(Hash)
242
+ end
243
+ end
244
+
245
+ raise UserError, "No packages found for chef-ice #{version}" if merged.empty?
246
+
247
+ merged
248
+ end
249
+
250
+
251
+
252
+ # ---------------------------------------------------------------
253
+ # HTTP helpers
254
+ # ---------------------------------------------------------------
255
+
256
+ # GET with redirect following — returns the response object.
257
+ def http_get_follow(uri, limit)
258
+ raise UserError, "Too many HTTP redirects" if limit <= 0
259
+
260
+ http = Net::HTTP.new(uri.host, uri.port)
261
+ http.use_ssl = (uri.scheme == "https")
262
+ http.open_timeout = 10
263
+ http.read_timeout = 30
264
+
265
+ response = http.request(Net::HTTP::Get.new(uri))
266
+
267
+ case response
268
+ when Net::HTTPRedirection
269
+ http_get_follow(URI.parse(response["location"]), limit - 1)
270
+ else
271
+ response
272
+ end
273
+ end
274
+
275
+ # Stream a URI to a local file, following redirects.
276
+ # Returns the filename from Content-Disposition header if present, else nil.
277
+ def http_download(uri, dest, limit = 5)
278
+ raise UserError, "Too many HTTP redirects downloading #{File.basename(dest)}" if limit <= 0
279
+
280
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
281
+ request = Net::HTTP::Get.new(uri)
282
+ http.request(request) do |response|
283
+ case response
284
+ when Net::HTTPRedirection
285
+ return http_download(URI.parse(response["location"]), dest, limit - 1)
286
+ when Net::HTTPSuccess
287
+ File.open(dest, "wb") do |f|
288
+ response.read_body { |chunk| f.write(chunk) }
289
+ end
290
+ # Extract filename from Content-Disposition if present
291
+ cd = response["content-disposition"]
292
+ if cd && cd =~ /filename=["']?([^"';\s]+)/
293
+ return $1
294
+ end
295
+ return nil
296
+ else
297
+ raise UserError,
298
+ "Failed to download #{File.basename(dest)}: HTTP #{response.code}"
299
+ end
300
+ end
301
+ end
302
+ end
303
+
304
+ # Verify a file matches an expected SHA-256 hex digest.
305
+ def verify_sha256(path, expected)
306
+ actual = Digest::SHA256.file(path).hexdigest
307
+ return if actual == expected
308
+
309
+ raise UserError,
310
+ "Checksum mismatch for #{File.basename(path)}: " \
311
+ "expected #{expected}, got #{actual}"
312
+ end
313
+
314
+ # ---------------------------------------------------------------
315
+ # Package cache — shared with chef-pkg at ~/.chef/cached-packages/
316
+ #
317
+ # Layout:
318
+ # ~/.chef/cached-packages/{platform}/{arch}/{pm}/chef-ice/{version}/
319
+ # chef-ice-19.2.12-1.amzn2.x86_64.rpm
320
+ # chef-ice-19.2.12-1.amzn2.x86_64.rpm.sha256
321
+ # ---------------------------------------------------------------
322
+
323
+ CACHE_ROOT = File.join(Dir.home, ".chef", "cached-packages")
324
+
325
+ # Find a cached package file by scanning the cache subdirectory
326
+ # for a file whose .sha256 sidecar matches the expected digest.
327
+ # Returns the full path to the cached file, or nil.
328
+ def find_in_cache(subdir, expected_sha256)
329
+ dir = File.join(CACHE_ROOT, subdir)
330
+ return nil unless File.directory?(dir)
331
+ return nil if expected_sha256.nil? || expected_sha256.empty?
332
+
333
+ Dir.glob(File.join(dir, "*")).each do |path|
334
+ next if path.end_with?(".sha256")
335
+
336
+ sidecar = "#{path}.sha256"
337
+ next unless File.exist?(sidecar)
338
+ next unless File.read(sidecar).strip == expected_sha256
339
+
340
+ return path
341
+ end
342
+
343
+ nil
344
+ end
345
+
346
+ # Store a downloaded file in the cache with a .sha256 sidecar.
347
+ def store_in_cache(source, subdir, sha256)
348
+ return if sha256.nil? || sha256.empty?
349
+
350
+ dir = File.join(CACHE_ROOT, subdir)
351
+ FileUtils.mkdir_p(dir)
352
+ dest = File.join(dir, File.basename(source))
353
+ FileUtils.cp(source, dest)
354
+ File.write("#{dest}.sha256", sha256)
355
+ end
356
+
357
+ # ---------------------------------------------------------------
358
+ # Shell script generators (run on the node)
359
+ # ---------------------------------------------------------------
360
+
361
+ # Guard clause: skip install if chef-client already present.
362
+ def install_guard
363
+ <<~SH
364
+ if [ -x "#{config[:chef_client_path]}" ]; then
365
+ echo "-----> Chef ICE already installed, skipping"
366
+ exit 0
367
+ fi
368
+ SH
369
+ end
370
+
371
+ # Generate a shell script that installs the package file(s)
372
+ # already uploaded to root_path on the node.
373
+ def install_package_script
374
+ if @package_files.length == 1 && !@package_files[0][:arch]
375
+ # Single file from download_url — install directly
376
+ remote = remote_path_join(config[:root_path], @package_files[0][:filename])
377
+ return install_single_package(remote)
378
+ end
379
+
380
+ # Multiple arch/pm files from the API — pick the right one at runtime
381
+ install_multi_package
382
+ end
383
+
384
+ # Install a single known package file.
385
+ def install_single_package(remote_pkg)
386
+ <<~SH
387
+ echo "-----> Installing Chef ICE from uploaded package"
388
+ case "#{remote_pkg}" in
389
+ *.deb) #{sudo("dpkg")} -i "#{remote_pkg}" || #{sudo("apt-get")} install -fy ;;
390
+ *.rpm)
391
+ if command -v dnf >/dev/null 2>&1; then #{sudo("dnf")} install -y "#{remote_pkg}"
392
+ elif command -v yum >/dev/null 2>&1; then #{sudo("yum")} install -y "#{remote_pkg}"
393
+ else #{sudo("rpm")} -Uvh "#{remote_pkg}"
394
+ fi ;;
395
+ *.msi) msiexec /qn /i "#{remote_pkg}" ;;
396
+ *) echo "ERROR: unknown package format" >&2; exit 1 ;;
397
+ esac
398
+ SH
399
+ end
400
+
401
+ # Build a shell script with arch detection and pm detection that
402
+ # picks the correct package file from the set uploaded to root_path.
403
+ def install_multi_package
404
+ root = config[:root_path]
405
+
406
+ arch_branches = {}
407
+ @package_files.each do |pf|
408
+ arch_branches[pf[:arch]] ||= []
409
+ arch_branches[pf[:arch]] << pf
410
+ end
411
+
412
+ script = []
413
+ script << <<~SH
414
+ echo "-----> Installing Chef ICE from uploaded package"
415
+ machine="$(uname -m)"
416
+ case "$machine" in
417
+ x86_64|amd64) arch="x86_64" ;;
418
+ aarch64|arm64) arch="aarch64" ;;
419
+ *) echo "ERROR: unsupported architecture $machine" >&2; exit 1 ;;
420
+ esac
421
+ SH
422
+
423
+ case_lines = []
424
+ arch_branches.each do |arch, files|
425
+ pm_lines = []
426
+ files.each do |pf|
427
+ remote = remote_path_join(root, pf[:filename])
428
+ keyword = pm_lines.empty? ? "if" : "elif"
429
+ case pf[:pm]
430
+ when "rpm"
431
+ pm_lines << " #{keyword} command -v rpm >/dev/null 2>&1; then"
432
+ pm_lines << " if command -v dnf >/dev/null 2>&1; then #{sudo("dnf")} install -y \"#{remote}\""
433
+ pm_lines << " elif command -v yum >/dev/null 2>&1; then #{sudo("yum")} install -y \"#{remote}\""
434
+ pm_lines << " else #{sudo("rpm")} -Uvh \"#{remote}\""
435
+ pm_lines << " fi"
436
+ when "deb"
437
+ pm_lines << " #{keyword} command -v dpkg >/dev/null 2>&1; then"
438
+ pm_lines << " #{sudo("dpkg")} -i \"#{remote}\" || #{sudo("apt-get")} install -fy"
439
+ when "msi"
440
+ pm_lines << " #{keyword} command -v msiexec >/dev/null 2>&1; then"
441
+ pm_lines << " msiexec /qn /i \"#{remote}\""
442
+ end
443
+ end
444
+ unless pm_lines.empty?
445
+ pm_lines << " else"
446
+ pm_lines << " echo \"ERROR: no supported package manager found\" >&2"
447
+ pm_lines << " exit 1"
448
+ pm_lines << " fi"
449
+ end
450
+ case_lines << " #{arch})\n#{pm_lines.join("\n")}\n ;;"
451
+ end
452
+
453
+ script << <<~SH
454
+ case "$arch" in
455
+ #{case_lines.join("\n")}
456
+ *)
457
+ echo "ERROR: no chef-ice package for architecture $arch" >&2
458
+ exit 1
459
+ ;;
460
+ esac
461
+ SH
462
+
463
+ script.join("\n")
464
+ end
465
+ end
466
+ end
467
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kitchen-provisioner-ice-temp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Richard Nixon
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-03-30 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A temporary stopgap Test Kitchen provisioner for chef-ice (chef-client
14
+ 19+). Uninstall this gem once Chef Workstation ships with native chef-ice provisioning
15
+ built in. See README.md for removal instructions.
16
+ email:
17
+ - richard.nixon@btinternet.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - LICENSE
23
+ - README.md
24
+ - lib/kitchen/provisioner/chef_ice.rb
25
+ - lib/kitchen/provisioner/chef_ice/version.rb
26
+ homepage: https://github.com/trickyearlobe-chef/kitchen-provisioner-ice-temp
27
+ licenses:
28
+ - Apache-2.0
29
+ metadata:
30
+ rubygems_mfa_required: 'true'
31
+ source_code_uri: https://github.com/trickyearlobe-chef/kitchen-provisioner-ice-temp
32
+ bug_tracker_uri: https://github.com/trickyearlobe-chef/kitchen-provisioner-ice-temp/issues
33
+ post_install_message: |
34
+ ┌──────────────────────────────────────────────────────────────────┐
35
+ │ kitchen-provisioner-ice-temp is a TEMPORARY stopgap gem. │
36
+ │ │
37
+ │ Once Chef Workstation ships with native chef-ice support, │
38
+ │ uninstall this gem and switch to the built-in provisioner: │
39
+ │ │
40
+ │ chef exec gem uninstall kitchen-provisioner-ice-temp │
41
+ │ │
42
+ │ See README.md for full migration instructions. │
43
+ └──────────────────────────────────────────────────────────────────┘
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '3.1'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubygems_version: 3.5.22
59
+ signing_key:
60
+ specification_version: 4
61
+ summary: TEMPORARY Test Kitchen provisioner for Chef ICE (Chef Infra Client 19+)
62
+ test_files: []