mixlib-install 3.13.0 → 3.14.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/bin/mixlib-install +1 -1
- data/lib/mixlib/install/backend/package_router.rb +96 -24
- data/lib/mixlib/install/cli.rb +11 -0
- data/lib/mixlib/install/dist.rb +4 -0
- data/lib/mixlib/install/generator/bourne/scripts/fetch_metadata.sh.erb +54 -12
- data/lib/mixlib/install/generator/bourne/scripts/fetch_package.sh +97 -15
- data/lib/mixlib/install/generator/bourne/scripts/helpers.sh.erb +31 -7
- data/lib/mixlib/install/generator/bourne/scripts/script_cli_parameters.sh.erb +4 -2
- data/lib/mixlib/install/generator/bourne.rb +8 -3
- data/lib/mixlib/install/generator/powershell/scripts/get_project_metadata.ps1.erb +45 -3
- data/lib/mixlib/install/generator/powershell/scripts/helpers.ps1.erb +38 -4
- data/lib/mixlib/install/generator/powershell/scripts/install_project.ps1.erb +34 -4
- data/lib/mixlib/install/generator/powershell.rb +3 -2
- data/lib/mixlib/install/options.rb +1 -0
- data/lib/mixlib/install/product_matrix.rb +5 -0
- data/lib/mixlib/install/script_generator.rb +1 -1
- data/lib/mixlib/install/version.rb +1 -1
- data/lib/mixlib/install.rb +44 -5
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 40469e67a42c0b360b72c220d71d9a2a0c837dc691ed9a74a9923fc81a31240c
|
|
4
|
+
data.tar.gz: f816a7403f35f3c51a456783241a485f9e21ff05fea67c5120f0585c9d92e899
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6f9b38fec3b7689879edac7229f5793cd3c4ea842d03cd93d1c4b68afb7f02853008863ef80898a18b0745d5d25fb94afb2f1f6ea6208535bd109b0cdad247bd
|
|
7
|
+
data.tar.gz: 0d2470b2ef4d1b130f28f00b06221cfbb8e34034b320c38426953310d5d1d3f91fe2c2be42ba341952582e5f07b73eecd46e6cf999c63a73e287f03904cf1587
|
data/bin/mixlib-install
CHANGED
|
@@ -64,7 +64,17 @@ module Mixlib
|
|
|
64
64
|
#
|
|
65
65
|
# @return [Array<Array<Hash>] Build records for available versions
|
|
66
66
|
def versions
|
|
67
|
-
|
|
67
|
+
# Commercial and trial APIs use a different URL structure
|
|
68
|
+
if use_licensed_api?
|
|
69
|
+
# Response is a JSON array of version strings
|
|
70
|
+
version_list = get("/#{options.channel}/#{omnibus_project}/versions/all")
|
|
71
|
+
# Convert to the expected format with properties
|
|
72
|
+
items = version_list.map do |version|
|
|
73
|
+
{ "properties" => [{ "key" => "omnibus.version", "value" => version }] }
|
|
74
|
+
end
|
|
75
|
+
else
|
|
76
|
+
items = get("/api/v1/#{options.channel}/#{omnibus_project}/versions")["results"]
|
|
77
|
+
end
|
|
68
78
|
|
|
69
79
|
# Circumvent early when there are no product artifacts in a specific channel
|
|
70
80
|
if items.empty?
|
|
@@ -80,7 +90,7 @@ EOF
|
|
|
80
90
|
# always complete. In fact we should not do this since for some arcane
|
|
81
91
|
# builds like Chef Client 10.X we do not have build record created in
|
|
82
92
|
# artifactory.
|
|
83
|
-
if options.channel == :unstable
|
|
93
|
+
if options.channel == :unstable && !use_licensed_api?
|
|
84
94
|
# We check if "artifacts" field contains something since it is only
|
|
85
95
|
# populated with the build record if "artifact.module.build" exists.
|
|
86
96
|
items.reject! { |i| i["artifacts"].nil? }
|
|
@@ -123,24 +133,49 @@ EOF
|
|
|
123
133
|
# @return [Array<ArtifactInfo>] Array of info about found artifacts
|
|
124
134
|
def artifacts_for_version(version)
|
|
125
135
|
begin
|
|
126
|
-
|
|
136
|
+
if use_licensed_api?
|
|
137
|
+
# Commercial/trial APIs use the packages endpoint which returns metadata for all platforms
|
|
138
|
+
query = "v=#{version}"
|
|
139
|
+
packages_hash = get("/#{options.channel}/#{omnibus_project}/packages?#{query}")
|
|
140
|
+
# Response is a nested hash: platform -> platform_version -> architecture -> package_info
|
|
141
|
+
# Flatten it to an array of package metadata objects
|
|
142
|
+
results = []
|
|
143
|
+
packages_hash.each do |platform, platform_versions|
|
|
144
|
+
platform_versions.each do |platform_version, architectures|
|
|
145
|
+
architectures.each do |arch, pkg_info|
|
|
146
|
+
results << {
|
|
147
|
+
"omnibus.version" => pkg_info["version"],
|
|
148
|
+
"omnibus.platform" => platform,
|
|
149
|
+
"omnibus.platform_version" => platform_version,
|
|
150
|
+
"omnibus.architecture" => arch,
|
|
151
|
+
"omnibus.project" => omnibus_project,
|
|
152
|
+
"omnibus.license" => "Apache-2.0",
|
|
153
|
+
"omnibus.sha256" => pkg_info["sha256"],
|
|
154
|
+
"omnibus.sha1" => pkg_info.fetch("sha1", ""),
|
|
155
|
+
"omnibus.md5" => pkg_info.fetch("md5", ""),
|
|
156
|
+
}
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
else
|
|
161
|
+
results = get("/api/v1/#{options.channel}/#{omnibus_project}/#{version}/artifacts")["results"]
|
|
162
|
+
# Merge artifactory properties to a flat Hash
|
|
163
|
+
results.collect! do |result|
|
|
164
|
+
{
|
|
165
|
+
"filename" => result["name"],
|
|
166
|
+
}.merge(
|
|
167
|
+
map_properties(result["properties"])
|
|
168
|
+
)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
127
171
|
rescue Net::HTTPServerException => e
|
|
128
|
-
if e.message
|
|
172
|
+
if e.message.match?(/404/)
|
|
129
173
|
return []
|
|
130
174
|
else
|
|
131
175
|
raise e
|
|
132
176
|
end
|
|
133
177
|
end
|
|
134
178
|
|
|
135
|
-
# Merge artifactory properties to a flat Hash
|
|
136
|
-
results.collect! do |result|
|
|
137
|
-
{
|
|
138
|
-
"filename" => result["name"],
|
|
139
|
-
}.merge(
|
|
140
|
-
map_properties(result["properties"])
|
|
141
|
-
)
|
|
142
|
-
end
|
|
143
|
-
|
|
144
179
|
# Convert results to build records
|
|
145
180
|
results.map { |a| create_artifact(a) }
|
|
146
181
|
end
|
|
@@ -153,6 +188,13 @@ EOF
|
|
|
153
188
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
154
189
|
http.use_ssl = (uri.scheme == "https")
|
|
155
190
|
full_path = File.join(uri.path, url)
|
|
191
|
+
|
|
192
|
+
# Add license_id as query parameter if using commercial or trial API
|
|
193
|
+
if use_licensed_api?
|
|
194
|
+
separator = full_path.include?("?") ? "&" : "?"
|
|
195
|
+
full_path = "#{full_path}#{separator}license_id=#{options.license_id}"
|
|
196
|
+
end
|
|
197
|
+
|
|
156
198
|
res = http.request(create_http_request(full_path))
|
|
157
199
|
res.value
|
|
158
200
|
JSON.parse(res.body)
|
|
@@ -191,7 +233,7 @@ EOF
|
|
|
191
233
|
software_dependencies = metadata.fetch("version_manifest", {})
|
|
192
234
|
.fetch("software", nil)
|
|
193
235
|
rescue Net::HTTPServerException => e
|
|
194
|
-
if e.message
|
|
236
|
+
if e.message.match?(/404/)
|
|
195
237
|
license_content, software_dependencies = nil
|
|
196
238
|
else
|
|
197
239
|
raise e
|
|
@@ -202,11 +244,22 @@ EOF
|
|
|
202
244
|
end
|
|
203
245
|
|
|
204
246
|
# create the download path with the correct endpoint
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
247
|
+
if use_licensed_api?
|
|
248
|
+
# Commercial/trial APIs use the download endpoint with query parameters
|
|
249
|
+
# Construct platform parameters
|
|
250
|
+
p_param = platform
|
|
251
|
+
pv_param = platform_version
|
|
252
|
+
m_param = Util.normalize_architecture(artifact_map["omnibus.architecture"])
|
|
253
|
+
v_param = artifact_map["omnibus.version"]
|
|
254
|
+
download_url = "#{endpoint}/#{options.channel}/#{omnibus_project}/download?p=#{p_param}&pv=#{pv_param}&m=#{m_param}&v=#{v_param}&license_id=#{options.license_id}"
|
|
255
|
+
else
|
|
256
|
+
base_url = if use_compat_download_url_endpoint?(platform, platform_version)
|
|
257
|
+
COMPAT_DOWNLOAD_URL_ENDPOINT
|
|
258
|
+
else
|
|
259
|
+
endpoint
|
|
260
|
+
end
|
|
261
|
+
download_url = "#{base_url}/#{chef_standard_path}"
|
|
262
|
+
end
|
|
210
263
|
|
|
211
264
|
ArtifactInfo.new(
|
|
212
265
|
architecture: Util.normalize_architecture(artifact_map["omnibus.architecture"]),
|
|
@@ -220,7 +273,7 @@ EOF
|
|
|
220
273
|
sha1: artifact_map["omnibus.sha1"],
|
|
221
274
|
sha256: artifact_map["omnibus.sha256"],
|
|
222
275
|
software_dependencies: software_dependencies,
|
|
223
|
-
url:
|
|
276
|
+
url: download_url,
|
|
224
277
|
version: artifact_map["omnibus.version"]
|
|
225
278
|
)
|
|
226
279
|
end
|
|
@@ -241,6 +294,29 @@ EOF
|
|
|
241
294
|
end
|
|
242
295
|
end
|
|
243
296
|
|
|
297
|
+
# Public API detection methods for testing
|
|
298
|
+
def endpoint
|
|
299
|
+
@endpoint ||= if use_trial_api?
|
|
300
|
+
Mixlib::Install::Dist::TRIAL_API_ENDPOINT
|
|
301
|
+
elsif use_commercial_api?
|
|
302
|
+
Mixlib::Install::Dist::COMMERCIAL_API_ENDPOINT
|
|
303
|
+
else
|
|
304
|
+
PRODUCT_MATRIX.lookup(options.product_name, options.product_version).api_url
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def use_trial_api?
|
|
309
|
+
!options.license_id.nil? && !options.license_id.to_s.empty? && options.license_id.start_with?("free-", "trial-")
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def use_commercial_api?
|
|
313
|
+
!options.license_id.nil? && !options.license_id.to_s.empty? && !use_trial_api?
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def use_licensed_api?
|
|
317
|
+
use_trial_api? || use_commercial_api?
|
|
318
|
+
end
|
|
319
|
+
|
|
244
320
|
private
|
|
245
321
|
|
|
246
322
|
# Converts Array<Hash> where the Hash is a key pair and
|
|
@@ -267,10 +343,6 @@ EOF
|
|
|
267
343
|
path.join("/")
|
|
268
344
|
end
|
|
269
345
|
|
|
270
|
-
def endpoint
|
|
271
|
-
@endpoint ||= PRODUCT_MATRIX.lookup(options.product_name, options.product_version).api_url
|
|
272
|
-
end
|
|
273
|
-
|
|
274
346
|
def omnibus_project
|
|
275
347
|
@omnibus_project ||= PRODUCT_MATRIX.lookup(options.product_name, options.product_version).omnibus_project
|
|
276
348
|
end
|
data/lib/mixlib/install/cli.rb
CHANGED
|
@@ -35,6 +35,11 @@ module Mixlib
|
|
|
35
35
|
say Mixlib::Install.available_versions(product_name, channel).join("\n")
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
desc "list-products", "list available products"
|
|
39
|
+
def list_products
|
|
40
|
+
say PRODUCT_MATRIX.products.join("\n")
|
|
41
|
+
end
|
|
42
|
+
|
|
38
43
|
desc "download PRODUCT_NAME", "download an artifact"
|
|
39
44
|
option :channel,
|
|
40
45
|
default: :stable,
|
|
@@ -66,6 +71,10 @@ If no earlier version is found the earliest version available will be set.",
|
|
|
66
71
|
option :attributes,
|
|
67
72
|
desc: "Print artifact attributes",
|
|
68
73
|
type: :boolean
|
|
74
|
+
option :license_id,
|
|
75
|
+
desc: "License ID for commercial API downloads",
|
|
76
|
+
aliases: ["-L"]
|
|
77
|
+
|
|
69
78
|
def download(product_name)
|
|
70
79
|
# Set minimum options
|
|
71
80
|
mixlib_install_options = {
|
|
@@ -77,6 +86,7 @@ If no earlier version is found the earliest version available will be set.",
|
|
|
77
86
|
}.tap do |opt|
|
|
78
87
|
opt[:platform] = options[:platform] if options[:platform]
|
|
79
88
|
opt[:platform_version] = options[:platform_version] if options[:platform_version]
|
|
89
|
+
opt[:license_id] = options[:license_id] if options[:license_id]
|
|
80
90
|
end
|
|
81
91
|
|
|
82
92
|
# auto detect platform options if not configured
|
|
@@ -114,6 +124,7 @@ If no earlier version is found the earliest version available will be set.",
|
|
|
114
124
|
aliases: ["-t"],
|
|
115
125
|
default: "sh",
|
|
116
126
|
enum: Mixlib::Install::Options::SUPPORTED_SHELL_TYPES.map(&:to_s)
|
|
127
|
+
|
|
117
128
|
def install_script
|
|
118
129
|
context = {}
|
|
119
130
|
context[:base_url] = options[:endpoint] if options[:endpoint]
|
data/lib/mixlib/install/dist.rb
CHANGED
|
@@ -8,6 +8,10 @@ module Mixlib
|
|
|
8
8
|
PRODUCT_ENDPOINT = "https://packages.chef.io".freeze
|
|
9
9
|
# Omnitruck endpoint
|
|
10
10
|
OMNITRUCK_ENDPOINT = "https://omnitruck.chef.io".freeze
|
|
11
|
+
# Commercial API endpoint
|
|
12
|
+
COMMERCIAL_API_ENDPOINT = "https://chefdownload-commercial.chef.io".freeze
|
|
13
|
+
# Trial API endpoint
|
|
14
|
+
TRIAL_API_ENDPOINT = "https://chefdownload-trial.chef.io".freeze
|
|
11
15
|
# Default product name
|
|
12
16
|
DEFAULT_PRODUCT = "chef".freeze
|
|
13
17
|
# Default download page URL
|
|
@@ -21,26 +21,68 @@ if test "x$download_url_override" = "x"; then
|
|
|
21
21
|
echo "Getting information for $project $channel $version for $platform..."
|
|
22
22
|
|
|
23
23
|
metadata_filename="$tmp_dir/metadata.txt"
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
# Use commercial API if license_id is provided, otherwise use omnitruck
|
|
26
|
+
if test "x$license_id" != "x"; then
|
|
27
|
+
# Check if license_id starts with 'free-' or 'trial-' for trial API
|
|
28
|
+
case "$license_id" in
|
|
29
|
+
free-*|trial-*)
|
|
30
|
+
# Trial API endpoint
|
|
31
|
+
base_api_url="https://chefdownload-trial.chef.io"
|
|
32
|
+
;;
|
|
33
|
+
*)
|
|
34
|
+
# Commercial API endpoint
|
|
35
|
+
base_api_url="https://chefdownload-commercial.chef.io"
|
|
36
|
+
;;
|
|
37
|
+
esac
|
|
38
|
+
metadata_url="$base_api_url/$channel/$project/metadata?v=$version&p=$platform&pv=$platform_version&m=$machine&license_id=$license_id"
|
|
39
|
+
else
|
|
40
|
+
# Omnitruck endpoint
|
|
41
|
+
metadata_url="<%= base_url %>/$channel/$project/metadata?v=$version&p=$platform&pv=$platform_version&m=$machine"
|
|
42
|
+
fi
|
|
25
43
|
|
|
26
44
|
do_download "$metadata_url" "$metadata_filename"
|
|
27
45
|
|
|
28
46
|
cat "$metadata_filename"
|
|
29
47
|
|
|
30
48
|
echo ""
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
49
|
+
|
|
50
|
+
# Commercial and trial APIs return JSON, omnitruck returns text format
|
|
51
|
+
if test "x$license_id" != "x"; then
|
|
52
|
+
# Parse JSON response from commercial/trial API
|
|
53
|
+
# Check if response looks like JSON
|
|
54
|
+
if grep -q '^{' "$metadata_filename" 2>/dev/null; then
|
|
55
|
+
# Extract url and sha256 from JSON
|
|
56
|
+
# Try using sed for simple JSON parsing (more portable than jq)
|
|
57
|
+
download_url=`sed -n 's/.*"url":"\([^"]*\)".*/\1/p' "$metadata_filename"`
|
|
58
|
+
sha256=`sed -n 's/.*"sha256":"\([^"]*\)".*/\1/p' "$metadata_filename"`
|
|
59
|
+
|
|
60
|
+
if test "x$download_url" != "x" && test "x$sha256" != "x"; then
|
|
61
|
+
echo "downloaded metadata file looks valid..."
|
|
62
|
+
else
|
|
63
|
+
echo "downloaded metadata file is corrupted or an uncaught error was encountered in downloading the file..."
|
|
64
|
+
report_bug
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
else
|
|
68
|
+
echo "downloaded metadata file is corrupted or an uncaught error was encountered in downloading the file..."
|
|
69
|
+
report_bug
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
34
72
|
else
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
73
|
+
# Parse text response from omnitruck
|
|
74
|
+
if grep '^url' $metadata_filename > /dev/null && grep '^sha256' $metadata_filename > /dev/null; then
|
|
75
|
+
echo "downloaded metadata file looks valid..."
|
|
76
|
+
download_url=`awk '$1 == "url" { print $2 }' "$metadata_filename"`
|
|
77
|
+
sha256=`awk '$1 == "sha256" { print $2 }' "$metadata_filename"`
|
|
78
|
+
else
|
|
79
|
+
echo "downloaded metadata file is corrupted or an uncaught error was encountered in downloading the file..."
|
|
80
|
+
# this generally means one of the download methods downloaded a 404 or something like that and then reported a successful exit code,
|
|
81
|
+
# and this should be fixed in the function that was doing the download.
|
|
82
|
+
report_bug
|
|
83
|
+
exit 1
|
|
84
|
+
fi
|
|
40
85
|
fi
|
|
41
|
-
|
|
42
|
-
download_url=`awk '$1 == "url" { print $2 }' "$metadata_filename"`
|
|
43
|
-
sha256=`awk '$1 == "sha256" { print $2 }' "$metadata_filename"`
|
|
44
86
|
else
|
|
45
87
|
download_url=$download_url_override
|
|
46
88
|
# Set sha256 to empty string if checksum not set
|
|
@@ -8,26 +8,48 @@
|
|
|
8
8
|
# Optional Inputs:
|
|
9
9
|
# $cmdline_filename: Name of the package downloaded on local disk.
|
|
10
10
|
# $cmdline_dl_dir: Name of the directory downloaded package will be saved to on local disk.
|
|
11
|
+
# $license_id: If set, indicates we're using commercial/trial API with content-disposition headers
|
|
11
12
|
#
|
|
12
13
|
# Outputs:
|
|
13
14
|
# $download_filename: Name of the downloaded file on local disk.
|
|
14
15
|
# $filetype: Type of the file downloaded.
|
|
15
16
|
############
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
#
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
# For licensed APIs (commercial/trial), the URL is an endpoint, not a direct file URL
|
|
19
|
+
# The actual filename will come from the Content-Disposition header
|
|
20
|
+
if test "x$license_id" != "x"; then
|
|
21
|
+
# Use content-disposition to get the filename
|
|
22
|
+
use_content_disposition="true"
|
|
23
|
+
# We don't know the filename yet - it will come from Content-Disposition
|
|
24
|
+
# Just set the download directory
|
|
25
|
+
if test "x$cmdline_filename" != "x"; then
|
|
26
|
+
download_filename="$cmdline_filename"
|
|
27
|
+
download_dir=`dirname $download_filename`
|
|
28
|
+
use_content_disposition="false" # User specified exact filename
|
|
29
|
+
elif test "x$cmdline_dl_dir" != "x"; then
|
|
30
|
+
download_dir="$cmdline_dl_dir"
|
|
31
|
+
download_filename="" # Will be determined after download
|
|
32
|
+
else
|
|
33
|
+
download_dir="$tmp_dir"
|
|
34
|
+
download_filename="" # Will be determined after download
|
|
35
|
+
fi
|
|
36
|
+
filetype="" # Will be determined after we get the actual filename
|
|
25
37
|
else
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
# Traditional omnitruck URLs have the filename in the URL
|
|
39
|
+
use_content_disposition="false"
|
|
40
|
+
filename=`echo $download_url | sed -e 's/?.*//' | sed -e 's/^.*\///'`
|
|
41
|
+
filetype=`echo $filename | sed -e 's/^.*\.//'`
|
|
28
42
|
|
|
29
|
-
#
|
|
30
|
-
|
|
43
|
+
# use either $tmp_dir, the provided directory (-d) or the provided filename (-f)
|
|
44
|
+
if test "x$cmdline_filename" != "x"; then
|
|
45
|
+
download_filename="$cmdline_filename"
|
|
46
|
+
elif test "x$cmdline_dl_dir" != "x"; then
|
|
47
|
+
download_filename="$cmdline_dl_dir/$filename"
|
|
48
|
+
else
|
|
49
|
+
download_filename="$tmp_dir/$filename"
|
|
50
|
+
fi
|
|
51
|
+
download_dir=`dirname $download_filename`
|
|
52
|
+
fi
|
|
31
53
|
(umask 077 && mkdir -p $download_dir) || exit 1
|
|
32
54
|
|
|
33
55
|
# check if we have that file locally available and if so verify the checksum
|
|
@@ -41,12 +63,16 @@ download_dir=`dirname $download_filename`
|
|
|
41
63
|
cached_file_available="false"
|
|
42
64
|
verify_checksum="true"
|
|
43
65
|
|
|
44
|
-
|
|
66
|
+
# Skip caching checks when using content-disposition since we don't know the real filename yet
|
|
67
|
+
if test "x$use_content_disposition" = "xtrue"; then
|
|
68
|
+
cached_file_available="false"
|
|
69
|
+
verify_checksum="true"
|
|
70
|
+
elif test "x$download_filename" != "x" && test -f "$download_filename"; then
|
|
45
71
|
echo "$download_filename exists"
|
|
46
72
|
cached_file_available="true"
|
|
47
73
|
fi
|
|
48
74
|
|
|
49
|
-
if test "x$download_url_override" != "x"; then
|
|
75
|
+
if test "x$download_url_override" != "x" && test "x$use_content_disposition" = "xfalse"; then
|
|
50
76
|
echo "Download URL override specified"
|
|
51
77
|
if test "x$cached_file_available" = "xtrue"; then
|
|
52
78
|
echo "Verifying local file"
|
|
@@ -75,7 +101,63 @@ if test "x$download_url_override" != "x"; then
|
|
|
75
101
|
fi
|
|
76
102
|
|
|
77
103
|
if test "x$cached_file_available" != "xtrue"; then
|
|
78
|
-
|
|
104
|
+
if test "x$use_content_disposition" = "xtrue"; then
|
|
105
|
+
# For licensed APIs, download to a temporary file and extract filename from response headers
|
|
106
|
+
# The download_dir was already set during initialization above
|
|
107
|
+
|
|
108
|
+
# Create temp file for download
|
|
109
|
+
temp_download="$download_dir/chef-download-temp.$$"
|
|
110
|
+
|
|
111
|
+
# Download to temp file
|
|
112
|
+
do_download "$download_url" "$temp_download"
|
|
113
|
+
|
|
114
|
+
# Extract filename from response headers (try multiple methods for compatibility)
|
|
115
|
+
if test -f "$tmp_dir/stderr"; then
|
|
116
|
+
# Method 1: Try to extract filename from content-disposition header
|
|
117
|
+
# Format: content-disposition: attachment; filename="chef-18.8.54-1.el9.x86_64.rpm"
|
|
118
|
+
actual_filename=`grep -i 'content-disposition' $tmp_dir/stderr | sed -n 's/.*filename="\([^"]*\)".*/\1/p' | head -1`
|
|
119
|
+
|
|
120
|
+
# Method 2: If content-disposition failed, try to extract from location redirect header
|
|
121
|
+
# Format: location: https://packages.chef.io/files/stable/chef/18.8.54/el/9/chef-18.8.54-1.el9.x86_64.rpm?licenseId=...
|
|
122
|
+
if test "x$actual_filename" = "x"; then
|
|
123
|
+
actual_filename=`grep -i '^location:' $tmp_dir/stderr | head -1 | sed 's/.*\///' | sed 's/?.*//'`
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
# Method 3: Try extracting from any URL-like pattern in stderr
|
|
127
|
+
if test "x$actual_filename" = "x"; then
|
|
128
|
+
actual_filename=`grep -i '\.rpm\|\.deb\|\.pkg\|\.msi\|\.dmg' $tmp_dir/stderr | sed -n 's/.*\/\([^/?]*\.\(rpm\|deb\|pkg\|msi\|dmg\)\).*/\1/p' | head -1`
|
|
129
|
+
fi
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
# If we still couldn't extract from headers, construct filename from metadata
|
|
133
|
+
if test "x$actual_filename" = "x"; then
|
|
134
|
+
echo "Warning: Could not extract filename from response headers, using fallback"
|
|
135
|
+
# Construct a reasonable filename from available metadata
|
|
136
|
+
# This is a fallback and may not match the exact package name
|
|
137
|
+
if test "x$platform" = "xel" || test "x$platform" = "xfedora" || test "x$platform" = "xamazon"; then
|
|
138
|
+
actual_filename="chef-${version}-1.${platform}${platform_version}.${machine}.rpm"
|
|
139
|
+
elif test "x$platform" = "xdebian" || test "x$platform" = "xubuntu"; then
|
|
140
|
+
actual_filename="chef_${version}-1_${machine}.deb"
|
|
141
|
+
elif test "x$platform" = "xmac_os_x"; then
|
|
142
|
+
actual_filename="chef-${version}.dmg"
|
|
143
|
+
else
|
|
144
|
+
actual_filename="chef-${version}.pkg"
|
|
145
|
+
fi
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
download_filename="$download_dir/$actual_filename"
|
|
149
|
+
|
|
150
|
+
# Move temp file to final location
|
|
151
|
+
mv "$temp_download" "$download_filename"
|
|
152
|
+
|
|
153
|
+
# Extract filetype from actual filename
|
|
154
|
+
filetype=`echo $actual_filename | sed -e 's/^.*\.//'`
|
|
155
|
+
|
|
156
|
+
echo "Downloaded as: $download_filename (type: $filetype)"
|
|
157
|
+
else
|
|
158
|
+
# Traditional download with known filename
|
|
159
|
+
do_download "$download_url" "$download_filename"
|
|
160
|
+
fi
|
|
79
161
|
fi
|
|
80
162
|
|
|
81
163
|
if test "x$verify_checksum" = "xtrue"; then
|
|
@@ -115,7 +115,12 @@ capture_tmp_stderr() {
|
|
|
115
115
|
# do_wget URL FILENAME
|
|
116
116
|
do_wget() {
|
|
117
117
|
echo "trying wget..."
|
|
118
|
-
|
|
118
|
+
# If filename is empty, use --content-disposition to get filename from server
|
|
119
|
+
if test "x$2" = "x"; then
|
|
120
|
+
wget --user-agent="User-Agent: <%= user_agent_string %>" --content-disposition "$1" 2>$tmp_dir/stderr
|
|
121
|
+
else
|
|
122
|
+
wget --user-agent="User-Agent: <%= user_agent_string %>" -O "$2" "$1" 2>$tmp_dir/stderr
|
|
123
|
+
fi
|
|
119
124
|
rc=$?
|
|
120
125
|
# check for 404
|
|
121
126
|
grep "ERROR 404" $tmp_dir/stderr 2>&1 >/dev/null
|
|
@@ -124,8 +129,14 @@ do_wget() {
|
|
|
124
129
|
http_404_error
|
|
125
130
|
fi
|
|
126
131
|
|
|
127
|
-
# check for bad return status
|
|
128
|
-
if test $rc -ne 0
|
|
132
|
+
# check for bad return status (skip empty output check if using content-disposition)
|
|
133
|
+
if test $rc -ne 0; then
|
|
134
|
+
capture_tmp_stderr "wget"
|
|
135
|
+
return 1
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
# Only check for empty output if we specified a filename
|
|
139
|
+
if test "x$2" != "x" && test ! -s "$2"; then
|
|
129
140
|
capture_tmp_stderr "wget"
|
|
130
141
|
return 1
|
|
131
142
|
fi
|
|
@@ -136,8 +147,15 @@ do_wget() {
|
|
|
136
147
|
# do_curl URL FILENAME
|
|
137
148
|
do_curl() {
|
|
138
149
|
echo "trying curl..."
|
|
139
|
-
|
|
140
|
-
|
|
150
|
+
# If filename is empty, use -O and -J to get filename from Content-Disposition header
|
|
151
|
+
if test "x$2" = "x"; then
|
|
152
|
+
curl -A "User-Agent: <%= user_agent_string %>" --retry 5 -sL -D $tmp_dir/stderr -O -J "$1"
|
|
153
|
+
rc=$?
|
|
154
|
+
else
|
|
155
|
+
curl -A "User-Agent: <%= user_agent_string %>" --retry 5 -sL -D $tmp_dir/stderr "$1" > "$2"
|
|
156
|
+
rc=$?
|
|
157
|
+
fi
|
|
158
|
+
|
|
141
159
|
# check for 404
|
|
142
160
|
grep "404 Not Found" $tmp_dir/stderr 2>&1 >/dev/null
|
|
143
161
|
if test $? -eq 0; then
|
|
@@ -145,8 +163,14 @@ do_curl() {
|
|
|
145
163
|
http_404_error
|
|
146
164
|
fi
|
|
147
165
|
|
|
148
|
-
# check for bad return status
|
|
149
|
-
if test $rc -ne 0
|
|
166
|
+
# check for bad return status
|
|
167
|
+
if test $rc -ne 0; then
|
|
168
|
+
capture_tmp_stderr "curl"
|
|
169
|
+
return 1
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
# Only check for empty output if we specified a filename
|
|
173
|
+
if test "x$2" != "x" && test ! -s "$2"; then
|
|
150
174
|
capture_tmp_stderr "curl"
|
|
151
175
|
return 1
|
|
152
176
|
fi
|
|
@@ -12,13 +12,14 @@
|
|
|
12
12
|
# $install_strategy: Method of package installations. default strategy is to always install upon exec. Set to "once" to skip if project is installed
|
|
13
13
|
# $download_url_override: Install package downloaded from a direct URL.
|
|
14
14
|
# $checksum: SHA256 for download_url_override file (optional)
|
|
15
|
+
# $license_id: License ID for commercial API access (optional)
|
|
15
16
|
############
|
|
16
17
|
|
|
17
18
|
# Defaults
|
|
18
19
|
channel="stable"
|
|
19
20
|
project="<%= default_product %>"
|
|
20
21
|
|
|
21
|
-
while getopts pnv:c:f:P:d:s:l:a opt
|
|
22
|
+
while getopts pnv:c:f:P:d:s:l:a:L: opt
|
|
22
23
|
do
|
|
23
24
|
case "$opt" in
|
|
24
25
|
|
|
@@ -32,9 +33,10 @@ do
|
|
|
32
33
|
s) install_strategy="$OPTARG";;
|
|
33
34
|
l) download_url_override="$OPTARG";;
|
|
34
35
|
a) checksum="$OPTARG";;
|
|
36
|
+
L) license_id="$OPTARG";;
|
|
35
37
|
\?) # unknown flag
|
|
36
38
|
echo >&2 \
|
|
37
|
-
"usage: $0 [-P project] [-c release_channel] [-v version] [-f filename | -d download_dir] [-s install_strategy] [-l download_url_override] [-a checksum]"
|
|
39
|
+
"usage: $0 [-P project] [-c release_channel] [-v version] [-f filename | -d download_dir] [-s install_strategy] [-l download_url_override] [-a checksum] [-L license_id]"
|
|
38
40
|
exit 1;;
|
|
39
41
|
esac
|
|
40
42
|
done
|
|
@@ -57,16 +57,21 @@ module Mixlib
|
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def render_variables
|
|
60
|
-
<<EOS
|
|
60
|
+
vars = <<EOS
|
|
61
61
|
project=#{options.product_name}
|
|
62
62
|
version=#{options.product_version}
|
|
63
63
|
channel=#{options.channel}
|
|
64
|
-
#{install_command_vars}
|
|
65
64
|
EOS
|
|
65
|
+
# Add license_id if provided
|
|
66
|
+
if options.license_id && !options.license_id.to_s.empty?
|
|
67
|
+
vars += "license_id=#{options.license_id}\n"
|
|
68
|
+
end
|
|
69
|
+
vars += install_command_vars
|
|
70
|
+
vars
|
|
66
71
|
end
|
|
67
72
|
|
|
68
73
|
def install_command_vars
|
|
69
|
-
return if options.install_command_options.nil?
|
|
74
|
+
return "" if options.install_command_options.nil?
|
|
70
75
|
options.install_command_options.map { |key, value| "#{key}='#{value}'" }.join("\n")
|
|
71
76
|
end
|
|
72
77
|
end
|
|
@@ -39,7 +39,10 @@ function Get-ProjectMetadata {
|
|
|
39
39
|
$nightlies,
|
|
40
40
|
[validateset('auto', 'i386', 'x86_64')]
|
|
41
41
|
[string]
|
|
42
|
-
$architecture = 'auto'
|
|
42
|
+
$architecture = 'auto',
|
|
43
|
+
# License ID for commercial API access
|
|
44
|
+
[string]
|
|
45
|
+
$license_id
|
|
43
46
|
)
|
|
44
47
|
|
|
45
48
|
# The following legacy switches are just aliases for the current channel
|
|
@@ -60,17 +63,56 @@ function Get-ProjectMetadata {
|
|
|
60
63
|
Write-Verbose "Architecture: $architecture"
|
|
61
64
|
Write-Verbose "Project: $project"
|
|
62
65
|
|
|
66
|
+
# Use commercial API if license_id is provided, otherwise use omnitruck
|
|
67
|
+
if ($license_id) {
|
|
68
|
+
# Check if license_id starts with 'free-' or 'trial-' for trial API
|
|
69
|
+
if ($license_id -match '^(free-|trial-)') {
|
|
70
|
+
$base_server_uri = 'https://chefdownload-trial.chef.io'
|
|
71
|
+
Write-Verbose "Using Trial API with license ID"
|
|
72
|
+
} else {
|
|
73
|
+
$base_server_uri = 'https://chefdownload-commercial.chef.io'
|
|
74
|
+
Write-Verbose "Using Commercial API with license ID"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
63
78
|
$metadata_base_url = "/$($channel)/$($project)/metadata"
|
|
64
79
|
$metadata_array = ("?v=$($version)",
|
|
65
80
|
"p=$platform",
|
|
66
81
|
"pv=$platform_version",
|
|
67
82
|
"m=$architecture")
|
|
83
|
+
|
|
84
|
+
# Add license_id to query parameters if provided
|
|
85
|
+
if ($license_id) {
|
|
86
|
+
$metadata_array += "license_id=$license_id"
|
|
87
|
+
}
|
|
88
|
+
|
|
68
89
|
$metadata_base_url += [string]::join('&', $metadata_array)
|
|
69
90
|
$metadata_url = new-uri $base_server_uri $metadata_base_url
|
|
70
91
|
|
|
71
92
|
Write-Verbose "Downloading $project details from $metadata_url"
|
|
72
|
-
$
|
|
73
|
-
|
|
93
|
+
$response = (Get-WebContent $metadata_url).trim()
|
|
94
|
+
|
|
95
|
+
# Commercial and trial APIs return JSON, omnitruck returns text format
|
|
96
|
+
if ($license_id) {
|
|
97
|
+
# Parse JSON response from commercial/trial API
|
|
98
|
+
try {
|
|
99
|
+
$json = $response | ConvertFrom-Json
|
|
100
|
+
$package_metadata = @{
|
|
101
|
+
url = $json.url
|
|
102
|
+
sha256 = $json.sha256
|
|
103
|
+
version = $json.version
|
|
104
|
+
}
|
|
105
|
+
if ($json.sha1) {
|
|
106
|
+
$package_metadata['sha1'] = $json.sha1
|
|
107
|
+
}
|
|
108
|
+
} catch {
|
|
109
|
+
throw "Failed to parse JSON response from API: $_"
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
# Parse text response from omnitruck
|
|
113
|
+
$package_metadata = $response -split '\n' |
|
|
114
|
+
foreach { $hash = @{} } {$key, $value = $_ -split '\s+'; $hash.Add($key, $value)} {$hash}
|
|
115
|
+
}
|
|
74
116
|
|
|
75
117
|
Write-Verbose "Project details: "
|
|
76
118
|
foreach ($key in $package_metadata.keys) {
|
|
@@ -6,13 +6,12 @@ function Get-PlatformVersion {
|
|
|
6
6
|
|
|
7
7
|
$platform_version = switch ($osVersion) {
|
|
8
8
|
# Windows Server build numbers from: https://betawiki.net/wiki/Microsoft_Windows
|
|
9
|
+
{ $_ -ge [version]'10.0.26100' } { '2025'; break }
|
|
9
10
|
{ $_ -ge [version]'10.0.20145' } { '2022'; break }
|
|
10
11
|
{ $_ -ge [version]'10.0.17609' } { '2019'; break }
|
|
11
12
|
{ $_ -ge [version]'10.0.0' } { '2016'; break }
|
|
12
13
|
{ $_ -ge [version]'6.3.0' } { '2012r2'; break }
|
|
13
14
|
{ $_ -ge [version]'6.2.0' } { '2012'; break }
|
|
14
|
-
{ $_ -ge [version]'6.1.0' } { '2008r2'; break }
|
|
15
|
-
{ $_ -ge [version]'6.0.0' } { '2008'; break }
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
if(Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Server\ServerLevels') {
|
|
@@ -58,10 +57,10 @@ function Get-WebContent {
|
|
|
58
57
|
|
|
59
58
|
try {
|
|
60
59
|
if($PSVersionTable.PSEdition -eq 'Core') {
|
|
61
|
-
Get-WebContentOnCore $uri $filepath
|
|
60
|
+
return Get-WebContentOnCore $uri $filepath
|
|
62
61
|
}
|
|
63
62
|
else {
|
|
64
|
-
Get-WebContentOnFullNet $uri $filepath
|
|
63
|
+
return Get-WebContentOnFullNet $uri $filepath
|
|
65
64
|
}
|
|
66
65
|
}
|
|
67
66
|
catch {
|
|
@@ -98,6 +97,28 @@ function Get-WebContentOnFullNet {
|
|
|
98
97
|
}
|
|
99
98
|
else {
|
|
100
99
|
$wc.downloadfile($uri, $filepath)
|
|
100
|
+
|
|
101
|
+
# Try to extract filename from Content-Disposition header
|
|
102
|
+
$contentDisposition = $wc.ResponseHeaders["Content-Disposition"]
|
|
103
|
+
$extractedFilename = $null
|
|
104
|
+
|
|
105
|
+
if ($contentDisposition) {
|
|
106
|
+
# Try to match filename="..." or filename*=UTF-8''...
|
|
107
|
+
if ($contentDisposition -match 'filename="([^"]+)"') {
|
|
108
|
+
$extractedFilename = $matches[1]
|
|
109
|
+
}
|
|
110
|
+
elseif ($contentDisposition -match "filename='([^']+)'") {
|
|
111
|
+
$extractedFilename = $matches[1]
|
|
112
|
+
}
|
|
113
|
+
elseif ($contentDisposition -match "filename=([^;]+)") {
|
|
114
|
+
$extractedFilename = $matches[1].Trim()
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return @{
|
|
119
|
+
Filename = $extractedFilename
|
|
120
|
+
Downloaded = $true
|
|
121
|
+
}
|
|
101
122
|
}
|
|
102
123
|
}
|
|
103
124
|
|
|
@@ -125,6 +146,19 @@ function Get-WebContentOnCore {
|
|
|
125
146
|
if ($copyStreamOp.Exception -ne $null) {
|
|
126
147
|
throw $copyStreamOp.Exception
|
|
127
148
|
}
|
|
149
|
+
|
|
150
|
+
# Try to extract filename from Content-Disposition header
|
|
151
|
+
$extractedFilename = $null
|
|
152
|
+
$contentDisposition = $response.Content.Headers.ContentDisposition
|
|
153
|
+
|
|
154
|
+
if ($contentDisposition -and $contentDisposition.FileName) {
|
|
155
|
+
$extractedFilename = $contentDisposition.FileName.Trim('"')
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return @{
|
|
159
|
+
Filename = $extractedFilename
|
|
160
|
+
Downloaded = $true
|
|
161
|
+
}
|
|
128
162
|
}
|
|
129
163
|
}
|
|
130
164
|
}
|
|
@@ -56,7 +56,10 @@ function Install-Project {
|
|
|
56
56
|
$checksum,
|
|
57
57
|
# Set to 'once' to skip install if project is detected
|
|
58
58
|
[string]
|
|
59
|
-
$install_strategy
|
|
59
|
+
$install_strategy,
|
|
60
|
+
# License ID for commercial API access
|
|
61
|
+
[string]
|
|
62
|
+
$license_id
|
|
60
63
|
)
|
|
61
64
|
|
|
62
65
|
# Check for chef-client command in various locations
|
|
@@ -86,7 +89,7 @@ function Install-Project {
|
|
|
86
89
|
$download_url = $download_url_override
|
|
87
90
|
$sha256 = $checksum
|
|
88
91
|
} else {
|
|
89
|
-
$package_metadata = Get-ProjectMetadata -project $project -channel $channel -version $version -prerelease:$prerelease -nightlies:$nightlies -architecture $architecture
|
|
92
|
+
$package_metadata = Get-ProjectMetadata -project $project -channel $channel -version $version -prerelease:$prerelease -nightlies:$nightlies -architecture $architecture -license_id $license_id
|
|
90
93
|
$download_url = $package_metadata.url
|
|
91
94
|
$sha256 = $package_metadata.sha256
|
|
92
95
|
}
|
|
@@ -99,7 +102,13 @@ function Install-Project {
|
|
|
99
102
|
}
|
|
100
103
|
}
|
|
101
104
|
else {
|
|
102
|
-
|
|
105
|
+
# For licensed downloads, we won't know the filename until after download
|
|
106
|
+
if ([string]::IsNullOrEmpty($license_id)) {
|
|
107
|
+
$filename = (([System.Uri]$download_url).AbsolutePath -split '/')[-1]
|
|
108
|
+
} else {
|
|
109
|
+
$filename = "chef-download-temp-$PID"
|
|
110
|
+
Write-Host "Using temporary filename for licensed download: $filename"
|
|
111
|
+
}
|
|
103
112
|
}
|
|
104
113
|
Write-Host "Download directory: $download_directory"
|
|
105
114
|
Write-Host "Filename: $filename"
|
|
@@ -137,7 +146,28 @@ function Install-Project {
|
|
|
137
146
|
if (-not ($cached_installer_available)) {
|
|
138
147
|
if ($pscmdlet.ShouldProcess("$($download_url)", "Download $project")) {
|
|
139
148
|
Write-Host "Downloading $project from $($download_url) to $download_destination."
|
|
140
|
-
Get-WebContent $download_url -filepath $download_destination
|
|
149
|
+
$download_result = Get-WebContent $download_url -filepath $download_destination
|
|
150
|
+
|
|
151
|
+
# For licensed downloads, extract actual filename from Content-Disposition
|
|
152
|
+
if (-not [string]::IsNullOrEmpty($license_id) -and $download_result -and $download_result.Filename) {
|
|
153
|
+
$actual_filename = $download_result.Filename
|
|
154
|
+
Write-Host "Extracted filename from Content-Disposition: $actual_filename"
|
|
155
|
+
|
|
156
|
+
$final_destination = join-path $download_directory $actual_filename
|
|
157
|
+
|
|
158
|
+
# Move temp file to final location with correct name
|
|
159
|
+
if ($download_destination -ne $final_destination) {
|
|
160
|
+
Write-Host "Moving to final location: $final_destination"
|
|
161
|
+
if (test-path $final_destination) {
|
|
162
|
+
remove-item $final_destination -force
|
|
163
|
+
}
|
|
164
|
+
move-item $download_destination $final_destination -force
|
|
165
|
+
$download_destination = $final_destination
|
|
166
|
+
}
|
|
167
|
+
} elseif (-not [string]::IsNullOrEmpty($license_id)) {
|
|
168
|
+
Write-Host "Warning: Could not extract filename from Content-Disposition header for licensed download."
|
|
169
|
+
Write-Host "Using temporary filename. Package installation may fail."
|
|
170
|
+
}
|
|
141
171
|
}
|
|
142
172
|
}
|
|
143
173
|
|
|
@@ -28,7 +28,7 @@ module Mixlib
|
|
|
28
28
|
install_project_module << get_script("install_project.ps1")
|
|
29
29
|
|
|
30
30
|
install_command = []
|
|
31
|
-
install_command << ps1_modularize(install_project_module.join("\n"), "
|
|
31
|
+
install_command << ps1_modularize(install_project_module.join("\n"), "Installer-Module")
|
|
32
32
|
install_command.join("\n\n")
|
|
33
33
|
end
|
|
34
34
|
|
|
@@ -49,7 +49,7 @@ module Mixlib
|
|
|
49
49
|
install_project_module << get_script("get_project_metadata.ps1")
|
|
50
50
|
install_project_module << get_script("install_project.ps1")
|
|
51
51
|
install_command = []
|
|
52
|
-
install_command << ps1_modularize(install_project_module.join("\n"), "
|
|
52
|
+
install_command << ps1_modularize(install_project_module.join("\n"), "Installer-Module")
|
|
53
53
|
install_command << render_command
|
|
54
54
|
install_command.join("\n\n")
|
|
55
55
|
end
|
|
@@ -71,6 +71,7 @@ module Mixlib
|
|
|
71
71
|
cmd << " -version #{options.product_version}"
|
|
72
72
|
cmd << " -channel #{options.channel}"
|
|
73
73
|
cmd << " -architecture #{options.architecture}" if options.architecture
|
|
74
|
+
cmd << " -license_id #{options.license_id}" if options.license_id && !options.license_id.to_s.empty?
|
|
74
75
|
cmd << install_command_params if options.install_command_options
|
|
75
76
|
cmd << "\n"
|
|
76
77
|
end
|
|
@@ -47,6 +47,11 @@ PRODUCT_MATRIX = Mixlib::Install::ProductMatrix.new do
|
|
|
47
47
|
package_name "chef"
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
product "chef-ice" do
|
|
51
|
+
product_name "Chef Infra Client Enterprise"
|
|
52
|
+
package_name "chef-ice"
|
|
53
|
+
end
|
|
54
|
+
|
|
50
55
|
product "chef-foundation" do
|
|
51
56
|
product_name "Chef Foundation"
|
|
52
57
|
package_name "chef-foundation"
|
data/lib/mixlib/install.rb
CHANGED
|
@@ -98,14 +98,53 @@ module Mixlib
|
|
|
98
98
|
artifact = artifact_info
|
|
99
99
|
|
|
100
100
|
FileUtils.mkdir_p directory
|
|
101
|
-
file = File.join(directory, File.basename(artifact.url))
|
|
102
101
|
|
|
102
|
+
# Handle the full URL including query string and redirects
|
|
103
103
|
uri = URI.parse(artifact.url)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
filename = nil
|
|
105
|
+
final_body = nil
|
|
106
|
+
|
|
107
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
|
|
108
|
+
# Build the request path including query string
|
|
109
|
+
request_path = uri.path
|
|
110
|
+
request_path += "?#{uri.query}" if uri.query
|
|
111
|
+
|
|
112
|
+
# Get the response, following redirects
|
|
113
|
+
response = http.request_get(request_path)
|
|
114
|
+
|
|
115
|
+
# Follow redirects
|
|
116
|
+
redirect_limit = 5
|
|
117
|
+
while response.is_a?(Net::HTTPRedirection) && redirect_limit > 0
|
|
118
|
+
redirect_uri = URI.parse(response["location"])
|
|
119
|
+
# Handle relative redirects
|
|
120
|
+
redirect_uri = uri + redirect_uri if redirect_uri.relative?
|
|
121
|
+
|
|
122
|
+
Net::HTTP.start(redirect_uri.host, redirect_uri.port, use_ssl: redirect_uri.scheme == "https") do |redirect_http|
|
|
123
|
+
redirect_path = redirect_uri.path
|
|
124
|
+
redirect_path += "?#{redirect_uri.query}" if redirect_uri.query
|
|
125
|
+
response = redirect_http.request_get(redirect_path)
|
|
126
|
+
|
|
127
|
+
# Try to get filename from Content-Disposition or final URL
|
|
128
|
+
if response["content-disposition"]
|
|
129
|
+
filename = response["content-disposition"][/filename="?([^"]+)"?/, 1]
|
|
130
|
+
else
|
|
131
|
+
filename = File.basename(redirect_uri.path)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
redirect_limit -= 1
|
|
108
136
|
end
|
|
137
|
+
|
|
138
|
+
final_body = response.body
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Use the extracted filename or fall back to basename of original URL
|
|
142
|
+
filename ||= File.basename(uri.path)
|
|
143
|
+
file = File.join(directory, filename)
|
|
144
|
+
|
|
145
|
+
# Write the final response body to file
|
|
146
|
+
File.open(file, "wb") do |io|
|
|
147
|
+
io.write(final_body)
|
|
109
148
|
end
|
|
110
149
|
|
|
111
150
|
file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mixlib-install
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.14.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Thom May
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2026-01-
|
|
12
|
+
date: 2026-01-14 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: mixlib-shellout
|