knife 18.8.68 → 19.0.102

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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +30 -9
  3. data/LICENSE +201 -201
  4. data/Rakefile +23 -0
  5. data/knife.gemspec +9 -15
  6. data/lib/chef/application/knife.rb +3 -5
  7. data/lib/chef/chef_fs/knife.rb +1 -1
  8. data/lib/chef/knife/acl_base.rb +1 -1
  9. data/lib/chef/knife/acl_bulk_add.rb +0 -1
  10. data/lib/chef/knife/acl_bulk_remove.rb +0 -1
  11. data/lib/chef/knife/bootstrap/templates/chef-full.erb +24 -5
  12. data/lib/chef/knife/bootstrap/templates/windows-chef-client-msi.erb +121 -4
  13. data/lib/chef/knife/bootstrap.rb +25 -29
  14. data/lib/chef/knife/config_get.rb +1 -1
  15. data/lib/chef/knife/config_get_profile.rb +1 -1
  16. data/lib/chef/knife/config_list_profiles.rb +1 -1
  17. data/lib/chef/knife/config_show.rb +1 -1
  18. data/lib/chef/knife/config_use_profile.rb +3 -3
  19. data/lib/chef/knife/configure_client.rb +1 -1
  20. data/lib/chef/knife/cookbook_bulk_delete.rb +1 -1
  21. data/lib/chef/knife/cookbook_delete.rb +1 -1
  22. data/lib/chef/knife/cookbook_download.rb +1 -1
  23. data/lib/chef/knife/cookbook_upload.rb +1 -1
  24. data/lib/chef/knife/core/bootstrap_context.rb +36 -6
  25. data/lib/chef/knife/core/cookbook_scm_repo.rb +2 -2
  26. data/lib/chef/knife/core/cookbook_site_streaming_uploader.rb +1 -6
  27. data/lib/chef/knife/core/gem_glob_loader.rb +4 -4
  28. data/lib/chef/knife/core/object_loader.rb +1 -1
  29. data/lib/chef/knife/core/status_presenter.rb +1 -1
  30. data/lib/chef/knife/core/subcommand_loader.rb +1 -1
  31. data/lib/chef/knife/core/text_formatter.rb +0 -1
  32. data/lib/chef/knife/core/windows_bootstrap_context.rb +103 -37
  33. data/lib/chef/knife/data_bag_secret_options.rb +1 -1
  34. data/lib/chef/knife/download.rb +1 -1
  35. data/lib/chef/knife/environment_compare.rb +2 -3
  36. data/lib/chef/knife/key_create.rb +1 -5
  37. data/lib/chef/knife/key_edit.rb +1 -5
  38. data/lib/chef/knife/license.rb +6 -2
  39. data/lib/chef/knife/list.rb +1 -1
  40. data/lib/chef/knife/node_edit.rb +1 -1
  41. data/lib/chef/knife/raw.rb +1 -2
  42. data/lib/chef/knife/recipe_list.rb +1 -1
  43. data/lib/chef/knife/search.rb +2 -2
  44. data/lib/chef/knife/ssh.rb +5 -5
  45. data/lib/chef/knife/ssl_fetch.rb +1 -1
  46. data/lib/chef/knife/supermarket_share.rb +3 -2
  47. data/lib/chef/knife/upload.rb +1 -1
  48. data/lib/chef/knife/user_create.rb +11 -21
  49. data/lib/chef/knife/user_list.rb +3 -3
  50. data/lib/chef/knife/version.rb +1 -3
  51. data/lib/chef/knife/xargs.rb +0 -1
  52. data/lib/chef/knife.rb +4 -1
  53. data/lib/chef/utils/licensing_config.rb +0 -1
  54. data/lib/chef/utils/licensing_handler.rb +18 -28
  55. data/spec/data/apt/chef-integration-test-1.0/debian/rules +0 -0
  56. data/spec/data/apt/chef-integration-test-1.1/debian/rules +0 -0
  57. data/spec/data/apt/chef-integration-test2-1.0/debian/rules +0 -0
  58. data/spec/data/cookbooks/openldap/templates/default/all_windows_line_endings.erb +4 -4
  59. data/spec/data/cookbooks/openldap/templates/default/some_windows_line_endings.erb +2 -2
  60. data/spec/functional/cookbook_delete_spec.rb +4 -4
  61. data/spec/functional/version_spec.rb +2 -3
  62. data/spec/integration/config_use_spec.rb +8 -8
  63. data/spec/integration/cookbook_api_ipv6_spec.rb +2 -2
  64. data/spec/integration/node_environment_set_spec.rb +1 -1
  65. data/spec/integration/node_run_list_set_spec.rb +1 -1
  66. data/spec/knife_spec_helper.rb +0 -5
  67. data/spec/support/platforms/prof/gc.rb +1 -1
  68. data/spec/support/shared/integration/integration_helper.rb +1 -1
  69. data/spec/tiny_server.rb +2 -2
  70. data/spec/unit/knife/bootstrap/templates/windows_presigned_url_spec.rb +183 -0
  71. data/spec/unit/knife/bootstrap_chef19_spec.rb +122 -0
  72. data/spec/unit/knife/bootstrap_spec.rb +121 -7
  73. data/spec/unit/knife/configure_spec.rb +3 -3
  74. data/spec/unit/knife/cookbook_list_spec.rb +1 -1
  75. data/spec/unit/knife/core/bootstrap_context_spec.rb +137 -0
  76. data/spec/unit/knife/core/windows_bootstrap_context_chef19_spec.rb +82 -0
  77. data/spec/unit/knife/core/windows_bootstrap_context_spec.rb +51 -64
  78. data/spec/unit/knife/license_spec.rb +1 -1
  79. data/spec/unit/knife/search_spec.rb +3 -3
  80. data/spec/unit/knife/supermarket_install_spec.rb +4 -5
  81. data/spec/unit/knife/utils/licensing_handler_chef19_spec.rb +144 -0
  82. metadata +61 -100
  83. data/spec/data/gems/chef-integration-test-0.1.0.gem +0 -0
  84. data/spec/data/nodes/default.rb +0 -15
  85. data/spec/data/nodes/test.example.com.rb +0 -17
  86. data/spec/data/nodes/test.rb +0 -15
  87. data/spec/unit/utils/licensing_handler_spec.rb +0 -140
@@ -169,14 +169,65 @@ class Chef
169
169
  end
170
170
 
171
171
  def start_chef
172
- c_opscode_dir = ChefConfig::PathHelper.cleanpath(ChefConfig::Config.c_opscode_dir, windows: true)
172
+ path_command = build_path_command
173
+ chef_executable = build_chef_executable
174
+ license_argument = build_license_argument
175
+
173
176
  client_rb = clean_etc_chef_file("client.rb")
174
177
  first_boot = clean_etc_chef_file("first-boot.json")
178
+ bootstrap_environment_option = build_environment_option
175
179
 
176
- bootstrap_environment_option = bootstrap_environment.nil? ? "" : " -E #{bootstrap_environment}"
180
+ "#{path_command}#{chef_executable} -c #{client_rb} -j #{first_boot}#{bootstrap_environment_option}#{license_argument}\n"
181
+ end
177
182
 
178
- start_chef = "SET \"PATH=%SYSTEM32%;%SystemRoot%;%SYSTEM32%\\Wbem;%SYSTEM32%\\WindowsPowerShell\\v1.0\\;C:\\ruby\\bin;#{c_opscode_dir}\\bin;#{c_opscode_dir}\\embedded\\bin\;%PATH%\"\n"
179
- start_chef << "#{ChefUtils::Dist::Infra::CLIENT} -c #{client_rb} -j #{first_boot}#{bootstrap_environment_option}\n"
183
+ def build_path_command
184
+ base_path = "SET \"PATH=%SYSTEM32%;%SystemRoot%;%SYSTEM32%\\Wbem;%SYSTEM32%\\WindowsPowerShell\\v1.0\\;"
185
+
186
+ # For --bootstrap-url, use conditional logic based on chef_ice? since we don't know what the script installs
187
+ if config[:bootstrap_url] && !config[:bootstrap_url].empty?
188
+ additional_paths = if chef_ice?
189
+ "C:\\hab\\bin"
190
+ else
191
+ c_opscode_dir = ChefConfig::PathHelper.cleanpath(ChefConfig::Config.c_opscode_dir, windows: true)
192
+ "C:\\ruby\\bin;#{c_opscode_dir}\\bin;#{c_opscode_dir}\\embedded\\bin"
193
+ end
194
+ else
195
+ # For default/msi flows, use standard paths
196
+ c_opscode_dir = ChefConfig::PathHelper.cleanpath(ChefConfig::Config.c_opscode_dir, windows: true)
197
+ additional_paths = "C:\\ruby\\bin;#{c_opscode_dir}\\bin;#{c_opscode_dir}\\embedded\\bin;C:\\hab\\bin"
198
+ end
199
+
200
+ "#{base_path}#{additional_paths};%PATH%\"\n"
201
+ end
202
+
203
+ def build_chef_executable
204
+ # For --bootstrap-url, use conditional logic based on chef_ice? since we don't know what the script installs
205
+ if config[:bootstrap_url] && !config[:bootstrap_url].empty?
206
+ if chef_ice?
207
+ # Set HAB_LICENSE to auto-accept Habitat license for non-interactive bootstrap
208
+ "SET \"HAB_LICENSE=accept-no-persist\"\nhab pkg exec chef/chef-infra-client #{ChefUtils::Dist::Infra::CLIENT}"
209
+ else
210
+ ChefUtils::Dist::Infra::CLIENT
211
+ end
212
+ else
213
+ # For default/msi flows, use standard chef-client
214
+ ChefUtils::Dist::Infra::CLIENT
215
+ end
216
+ end
217
+
218
+ def build_license_argument
219
+ return "" if config[:disable_license_activation]
220
+ return "" unless chef_ice? && config[:license_id]
221
+
222
+ # Skip license flag when using custom MSI or bootstrap URLs
223
+ return "" if config[:msi_url] && !config[:msi_url].empty?
224
+ return "" if config[:bootstrap_url] && !config[:bootstrap_url].empty?
225
+
226
+ " --chef-license-key #{config[:license_id]}"
227
+ end
228
+
229
+ def build_environment_option
230
+ bootstrap_environment.nil? ? "" : " -E #{bootstrap_environment}"
180
231
  end
181
232
 
182
233
  def win_wget
@@ -187,7 +238,7 @@ class Chef
187
238
  path = WScript.Arguments.Named("path")
188
239
  proxy = null
189
240
  '* Vaguely attempt to handle file:// scheme urls by url unescaping and switching all
190
- '* / into \. Also assume that file:/// is a local absolute path and that file://<foo>
241
+ '* / into . Also assume that file:/// is a local absolute path and that file://<foo>
191
242
  '* is possibly a network file path.
192
243
  If InStr(url, "file://") = 1 Then
193
244
  url = Unescape(url)
@@ -305,10 +356,8 @@ class Chef
305
356
  escape_and_echo(win_wget_ps)
306
357
  end
307
358
 
308
- def install_chef
309
- # The normal install command uses regular double quotes in
310
- # the install command, so request such a string from install_command
311
- install_command('"') + "\n" + fallback_install_task_command
359
+ def first_boot
360
+ escape_and_echo(super.to_json)
312
361
  end
313
362
 
314
363
  def clean_etc_chef_file(path)
@@ -323,31 +372,17 @@ class Chef
323
372
  ChefConfig::Config.etc_chef_dir(windows: true)
324
373
  end
325
374
 
326
- def local_download_path
327
- "%TEMP%\\#{ChefUtils::Dist::Infra::CLIENT}-latest.msi"
328
- end
329
-
330
- # Build a URL that will redirect to the correct Chef Infra msi download.
331
- def msi_url(machine_os = nil, machine_arch = nil, download_context = nil)
332
- if config[:msi_url].nil? || config[:msi_url].empty?
333
- url = if config[:license_id] && !config[:omnitruck_url].empty?
334
- format(config[:omnitruck_url], config[:channel] + "/chef/download") + "&p=windows"
335
- else
336
- "https://omnitruck.chef.io/chef/download?p=windows&channel=#{config[:channel]}"
337
- end
338
- url += "&pv=#{machine_os}" unless machine_os.nil?
339
- url += "&m=#{machine_arch}" unless machine_arch.nil?
340
- url += "&DownloadContext=#{download_context}" unless download_context.nil?
341
- url += "&v=#{version_to_install}"
342
- else
343
- config[:msi_url]
375
+ # Build a URL for the PowerShell install script (install.ps1)
376
+ def install_ps1_url
377
+ if config[:bootstrap_url]
378
+ # Use custom bootstrap URL if provided
379
+ config[:bootstrap_url]
380
+ elsif config[:license_url]
381
+ # Use license-aware install script URL
382
+ config[:license_url].gsub("install.sh", "install.ps1")
344
383
  end
345
384
  end
346
385
 
347
- def first_boot
348
- escape_and_echo(super.to_json)
349
- end
350
-
351
386
  # escape WIN BATCH special chars
352
387
  # and prefixes each line with an
353
388
  # echo
@@ -355,12 +390,15 @@ class Chef
355
390
  file_contents.gsub(/^(.*)$/, 'echo.\1').gsub(/([(<|>)^])/, '^\1')
356
391
  end
357
392
 
358
- private
359
-
360
- def install_command(executor_quote)
361
- "msiexec /qn /log #{executor_quote}%CHEF_CLIENT_MSI_LOG_PATH%#{executor_quote} /i #{executor_quote}%LOCAL_DESTINATION_MSI_PATH%#{executor_quote}"
393
+ # Returns the MSI URL for downloading Chef Infra Client
394
+ # Supports both chef and chef-ice products, and custom URLs
395
+ def msi_url
396
+ # If a custom MSI URL is provided, use it directly
397
+ config[:msi_url] if config[:msi_url] && !config[:msi_url].empty?
362
398
  end
363
399
 
400
+ private
401
+
364
402
  # Returns a string for copying the trusted certificates on the workstation to the system being bootstrapped
365
403
  # This string should contain both the commands necessary to both create the files, as well as their content
366
404
  def trusted_certs_content
@@ -394,12 +432,39 @@ class Chef
394
432
  content
395
433
  end
396
434
 
435
+ def install_chef
436
+ # The normal install command uses regular double quotes in
437
+ # the install command, so request such a string from msi_install_command
438
+ msi_install_command('"') + "\n" + fallback_install_task_command
439
+ end
440
+
441
+ def msi_install_command(executor_quote)
442
+ "msiexec /qn /log #{executor_quote}%CHEF_CLIENT_MSI_LOG_PATH%#{executor_quote} /i #{executor_quote}%LOCAL_DESTINATION_MSI_PATH%#{executor_quote}"
443
+ end
444
+
445
+ def install_command(executor_quote)
446
+ commands = []
447
+
448
+ # Add license environment variable if applicable
449
+ license_key = @config[:license_key] || @config[:license_id]
450
+
451
+ # Only add license environment variable for Chef Infra 19+
452
+ if license_key && chef_ice?
453
+ commands << "set CHEF_LICENSE_KEY=#{license_key}"
454
+ end
455
+
456
+ # Add the msiexec installation command
457
+ commands << msi_install_command(executor_quote)
458
+
459
+ commands.join("\n")
460
+ end
461
+
397
462
  def fallback_install_task_command
398
463
  # This command will be executed by schtasks.exe in the batch
399
464
  # code below. To handle tasks that contain arguments that
400
465
  # need to be double quoted, schtasks allows the use of single
401
466
  # quotes that will later be converted to double quotes
402
- command = install_command("'")
467
+ command = msi_install_command("'")
403
468
  <<~EOH
404
469
  @set MSIERRORCODE=!ERRORLEVEL!
405
470
  @if ERRORLEVEL 1 (
@@ -409,7 +474,7 @@ class Chef
409
474
  @move "%CHEF_CLIENT_MSI_LOG_PATH%" "!OLDLOGLOCATION!" > NUL
410
475
  @echo WARNING: Saving installation log of failure at !OLDLOGLOCATION!
411
476
  @echo WARNING: Retrying installation with local context...
412
- @schtasks /create /f /sc once /st 00:00:00 /tn chefclientbootstraptask /ru SYSTEM /rl HIGHEST /tr \"cmd /c #{command} & sleep 2 & waitfor /s %computername% /si chefclientinstalldone\"
477
+ @schtasks /create /f /sc once /st 00:00:00 /tn chefclientbootstraptask /ru SYSTEM /rl HIGHEST /tr "cmd /c #{command} & sleep 2 & waitfor /s %computername% /si chefclientinstalldone"
413
478
 
414
479
  @if ERRORLEVEL 1 (
415
480
  @echo ERROR: Failed to create #{ChefUtils::Dist::Infra::PRODUCT} installation scheduled task with status code !ERRORLEVEL! > "&2"
@@ -435,6 +500,7 @@ class Chef
435
500
  )
436
501
  EOH
437
502
  end
503
+
438
504
  end
439
505
  end
440
506
  end
@@ -66,7 +66,7 @@ class Chef
66
66
  config[:cl_secret]
67
67
  elsif config[:cl_secret_file]
68
68
  Chef::EncryptedDataBagItem.load_secret(config[:cl_secret_file])
69
- elsif secret = config[:secret]
69
+ elsif (secret = config[:secret])
70
70
  secret
71
71
  else
72
72
  secret_file = config[:secret_file]
@@ -71,7 +71,7 @@ class Chef
71
71
 
72
72
  error = false
73
73
  pattern_args.each do |pattern|
74
- fs_error, result = Chef::ChefFS::FileSystem.copy_to(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, config, ui, proc { |entry| format_path(entry) })
74
+ fs_error, _result = Chef::ChefFS::FileSystem.copy_to(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, config, ui, proc { |entry| format_path(entry) })
75
75
  if fs_error
76
76
  error = true
77
77
  end
@@ -105,9 +105,8 @@ class Chef
105
105
  columns = environments.count + 1
106
106
  environments.each { |env| rows << ui.color(env, :bold) }
107
107
  cookbooks.each_key do |c|
108
- total = []
109
- environments.each { |n| total << constraints[n][c] }
110
- if total.uniq.count == 1
108
+ total = environments.map { |n| constraints[n][c] }
109
+ if total.uniq.one?
111
110
  next if config[:mismatch]
112
111
 
113
112
  color = :white
@@ -89,11 +89,7 @@ class Chef
89
89
  key.name(@config[:key_name])
90
90
  end
91
91
 
92
- if @config[:expiration_date]
93
- key.expiration_date(@config[:expiration_date])
94
- else
95
- key.expiration_date("infinity")
96
- end
92
+ key.expiration_date(@config[:expiration_date] || "infinity")
97
93
 
98
94
  output = edit_hash(key)
99
95
  key = create_key_from_hash(output)
@@ -89,11 +89,7 @@ class Chef
89
89
  key.public_key(File.read(File.expand_path(@config[:public_key])))
90
90
  end
91
91
 
92
- if @config[:key_name]
93
- key.name(@config[:key_name])
94
- else
95
- key.name(@original_name)
96
- end
92
+ key.name(@config[:key_name] || @original_name)
97
93
 
98
94
  if @config[:expiration_date]
99
95
  key.expiration_date(@config[:expiration_date])
@@ -42,8 +42,12 @@ class Chef
42
42
  when "add"
43
43
  ChefLicensing.add_license
44
44
  else
45
- ChefLicensing.fetch_and_persist.each do |key|
46
- ui.msg("License_key: #{key}")
45
+ # The license command needs to run with require_license, otherwise
46
+ # license activation will be skipped
47
+ ChefLicensing::Config.require_license_for do
48
+ ChefLicensing.fetch_and_persist.each do |key|
49
+ ui.msg("License_key: #{key}")
50
+ end
47
51
  end
48
52
  end
49
53
  end
@@ -115,7 +115,7 @@ class Chef
115
115
  printed_something = true
116
116
  end
117
117
  output "#{format_path(result)}:"
118
- print_results(children.map { |result| maybe_add_slash(result.display_name, result.dir?) }.sort, "")
118
+ print_results(children.map { |child| maybe_add_slash(child.display_name, child.dir?) }.sort, "")
119
119
  end
120
120
 
121
121
  exit exit_code if exit_code
@@ -45,7 +45,7 @@ class Chef
45
45
  end
46
46
 
47
47
  updated_node = node_editor.edit_node
48
- if updated_values = node_editor.updated?
48
+ if (updated_values = node_editor.updated?)
49
49
  ui.info "Saving updated #{updated_values.join(", ")} on node #{node.name}"
50
50
  updated_node.save
51
51
  else
@@ -83,7 +83,6 @@ class Chef
83
83
  exit(1)
84
84
  end
85
85
 
86
- path = name_args[0]
87
86
  data = false
88
87
  if config[:input]
89
88
  data = File.read(config[:input])
@@ -108,7 +107,7 @@ class Chef
108
107
  result = chef_rest.request(method, name_args[0], headers, data)
109
108
  end
110
109
  output result
111
- rescue Timeout::Error => e
110
+ rescue Timeout::Error
112
111
  ui.error "Server timeout"
113
112
  exit 1
114
113
  rescue Net::HTTPClientException => e
@@ -23,7 +23,7 @@ class Chef::Knife::RecipeList < Chef::Knife
23
23
 
24
24
  def run
25
25
  recipes = rest.get("cookbooks/_recipes")
26
- if pattern = @name_args.first
26
+ if (pattern = @name_args.first)
27
27
  recipes = recipes.grep(Regexp.new(pattern))
28
28
  end
29
29
  output(recipes)
@@ -42,14 +42,14 @@ class Chef
42
42
  long: "--start ROW",
43
43
  description: "The row to start returning results at.",
44
44
  default: 0,
45
- proc: lambda { |i| i.to_i }
45
+ proc: lambda(&:to_i)
46
46
 
47
47
  option :rows,
48
48
  short: "-R INT",
49
49
  long: "--rows INT",
50
50
  description: "The number of rows to return.",
51
51
  default: nil,
52
- proc: lambda { |i| i.to_i }
52
+ proc: lambda(&:to_i)
53
53
 
54
54
  option :run_list,
55
55
  short: "-r",
@@ -43,7 +43,7 @@ class Chef
43
43
  long: "--concurrency NUM",
44
44
  description: "The number of concurrent connections.",
45
45
  default: nil,
46
- proc: lambda { |o| o.to_i }
46
+ proc: lambda(&:to_i)
47
47
 
48
48
  option :ssh_attribute,
49
49
  short: "-a ATTR",
@@ -79,7 +79,7 @@ class Chef
79
79
  short: "-p PORT",
80
80
  long: "--ssh-port PORT",
81
81
  description: "The ssh port.",
82
- proc: Proc.new { |key| key.strip }
82
+ proc: Proc.new(&:strip)
83
83
 
84
84
  option :ssh_timeout,
85
85
  short: "-t SECONDS",
@@ -92,7 +92,7 @@ class Chef
92
92
  short: "-G GATEWAY",
93
93
  long: "--ssh-gateway GATEWAY",
94
94
  description: "The ssh gateway.",
95
- proc: Proc.new { |key| key.strip }
95
+ proc: Proc.new(&:strip)
96
96
 
97
97
  option :ssh_gateway_identity,
98
98
  long: "--ssh-gateway-identity SSH_GATEWAY_IDENTITY",
@@ -344,11 +344,11 @@ class Chef
344
344
 
345
345
  def print_data(host, data)
346
346
  @buffers ||= {}
347
- if leftover = @buffers[host]
347
+ if (leftover = @buffers[host])
348
348
  @buffers[host] = nil
349
349
  print_data(host, leftover + data)
350
350
  else
351
- if newline_index = data.index("\n")
351
+ if (newline_index = data.index("\n"))
352
352
  line = data.slice!(0...newline_index)
353
353
  data.slice!(0)
354
354
  print_line(host, line)
@@ -90,7 +90,7 @@ class Chef
90
90
 
91
91
  def cn_of(certificate)
92
92
  subject = certificate.subject
93
- if cn_field_tuple = subject.to_a.find { |field| field[0] == "CN" }
93
+ if (cn_field_tuple = subject.to_a.find { |field| field[0] == "CN" })
94
94
  cn_field_tuple[1]
95
95
  else
96
96
  nil
@@ -95,11 +95,12 @@ class Chef
95
95
  do_upload("#{tmp_cookbook_dir}/#{cookbook_name}.tgz", category, Chef::Config[:node_name], Chef::Config[:client_key])
96
96
  ui.info("Upload complete")
97
97
  Chef::Log.trace("Removing local staging directory at #{tmp_cookbook_dir}")
98
- FileUtils.rm_rf tmp_cookbook_dir
99
98
  rescue => e
100
99
  ui.error("Error uploading cookbook #{cookbook_name} to Supermarket: #{e.message}. Increase log verbosity (-VV) for more information.")
101
100
  Chef::Log.trace("\n#{e.backtrace.join("\n")}")
102
101
  exit(1)
102
+ ensure
103
+ FileUtils.rm_rf tmp_cookbook_dir
103
104
  end
104
105
 
105
106
  else
@@ -132,7 +133,7 @@ class Chef
132
133
  res = Chef::JSONCompat.from_json(http_resp.body)
133
134
  if http_resp.code.to_i != 201
134
135
  if res["error_messages"]
135
- if /Version already exists/.match?(res["error_messages"][0])
136
+ if res["error_messages"][0].match?(/Version (already exists|has already been taken)/)
136
137
  ui.error "The same version of this cookbook already exists on Supermarket."
137
138
  exit(1)
138
139
  else
@@ -73,7 +73,7 @@ class Chef
73
73
 
74
74
  error = false
75
75
  pattern_args.each do |pattern|
76
- fs_error, result = Chef::ChefFS::FileSystem.copy_to(pattern, local_fs, chef_fs, config[:recurse] ? nil : 1, config, ui, proc { |entry| format_path(entry) })
76
+ fs_error, _result = Chef::ChefFS::FileSystem.copy_to(pattern, local_fs, chef_fs, config[:recurse] ? nil : 1, config, ui, proc { |entry| format_path(entry) })
77
77
  if fs_error
78
78
  error = true
79
79
  end
@@ -120,27 +120,17 @@ class Chef
120
120
  user.public_key File.read(File.expand_path(config[:user_key]))
121
121
  end
122
122
 
123
- if @name_args.size > 1
124
- user_hash = {
125
- username: user.username,
126
- first_name: user.first_name,
127
- last_name: user.last_name,
128
- display_name: "#{user.first_name} #{user.last_name}",
129
- email: user.email,
130
- password: password,
131
- create_key: user.create_key,
132
- }
133
- else
134
- user_hash = {
135
- username: user.username,
136
- first_name: user.first_name,
137
- last_name: user.last_name,
138
- display_name: user.display_name,
139
- email: user.email,
140
- password: password,
141
- create_key: user.create_key,
142
- }
143
- end
123
+ user_hash = {
124
+ username: user.username,
125
+ first_name: user.first_name,
126
+ last_name: user.last_name,
127
+ display_name: @name_args.size > 1 ? "#{user.first_name} #{user.last_name}" : user.display_name,
128
+ email: user.email,
129
+ password: password,
130
+ }
131
+
132
+ user_hash[:create_key] = user.create_key if user.create_key
133
+ user_hash[:public_key] = user.public_key if user.public_key
144
134
 
145
135
  # Check the file before creating the user so the api is more transactional.
146
136
  if config[:file]
@@ -35,9 +35,9 @@ class Chef
35
35
  description: "Show corresponding URIs."
36
36
 
37
37
  option :all_users,
38
- short: "-a",
39
- long: "--all-users",
40
- description: "Show all user details."
38
+ short: "-a",
39
+ long: "--all-users",
40
+ description: "Show all user details."
41
41
  def run
42
42
  users = Chef::UserV1.list(config[:all_users])
43
43
  if config[:all_users]
@@ -17,8 +17,6 @@
17
17
  class Chef
18
18
  class Knife
19
19
  KNIFE_ROOT = File.expand_path("../..", __dir__)
20
- VERSION = "18.8.68".freeze
20
+ VERSION = "19.0.102".freeze
21
21
  end
22
22
  end
23
-
24
-
@@ -131,7 +131,6 @@ class Chef
131
131
  begin
132
132
  error = true if xargs_files(command, tempfiles)
133
133
  files = []
134
- ran = true
135
134
  ensure
136
135
  destroy_tempfiles(tempfiles)
137
136
  end
data/lib/chef/knife.rb CHANGED
@@ -32,6 +32,7 @@ require "chef/server_api" unless defined?(Chef::ServerAPI)
32
32
  require "http/authenticator" unless defined?(Chef::HTTP::Authenticator)
33
33
  require "http/http_request" unless defined?(Chef::HTTP::HTTPRequest)
34
34
  require "http" unless defined?(Chef::HTTP)
35
+ # require "chef/utils/licensing_handler"
35
36
  # End
36
37
 
37
38
  require "pp" unless defined?(PP)
@@ -215,6 +216,8 @@ class Chef
215
216
  # subcommands know about global knife CLI options
216
217
  #
217
218
  def self.run(args, options = {})
219
+ # Check software entitlement
220
+ # Chef::Utils::LicensingHandler.check_software_entitlement!(ui)
218
221
  # Fallback debug logging. Normally the logger isn't configured until we
219
222
  # read the config, but this means any logging that happens before the
220
223
  # config file is read may be lost. If the KNIFE_DEBUG variable is set, we
@@ -283,7 +286,7 @@ class Chef
283
286
 
284
287
  if CHEF_ORGANIZATION_MANAGEMENT.include?(args[0])
285
288
  list_commands("CHEF ORGANIZATION MANAGEMENT")
286
- elsif category_commands = guess_category(args)
289
+ elsif (category_commands = guess_category(args))
287
290
  list_commands(category_commands)
288
291
  elsif OFFICIAL_PLUGINS.include?(args[0]) # command was an uninstalled official chef knife plugin
289
292
  ui.info("Use `#{ChefUtils::Dist::Infra::EXEC} gem install knife-#{args[0]}` to install the plugin into Chef Workstation")
@@ -6,4 +6,3 @@ ChefLicensing.configure do |config|
6
6
  config.chef_executable_name = "knife"
7
7
  config.license_server_url = "https://services.chef.io/licensing"
8
8
  end
9
-
@@ -1,31 +1,13 @@
1
- #
2
- # Copyright:: Copyright (c) Chef Software Inc.
3
- # License:: Apache License, Version 2.0
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.
16
- #
17
-
18
1
  require_relative "licensing_config"
19
2
 
20
3
  class Chef
21
4
  class Utils
22
5
  class LicensingHandler
23
- LEGACY_OMNITRUCK_URL = "https://omnitruck.chef.io".freeze
24
-
25
- OMNITRUCK_URLS = {
26
- "free" => "https://chefdownload-trial.chef.io",
27
- "trial" => "https://chefdownload-trial.chef.io",
28
- "commercial" => "https://chefdownload-commerical.chef.io",
6
+ # Omnitruck URLs are no longer used. Updated to new download URLs.
7
+ DOWNLOAD_URLS = {
8
+ "free" => "https://chefdownload-trial.chef.io",
9
+ "trial" => "https://chefdownload-trial.chef.io",
10
+ "commercial" => "https://chefdownload-commercial.chef.io",
29
11
  }.freeze
30
12
 
31
13
  attr_reader :license_key, :license_type
@@ -36,11 +18,9 @@ class Chef
36
18
  end
37
19
 
38
20
  def omnitruck_url
39
- url = OMNITRUCK_URLS[license_type]
40
- is_legacy = url.nil?
41
- url ||= LEGACY_OMNITRUCK_URL
21
+ url = DOWNLOAD_URLS[license_type]
42
22
 
43
- "#{url}/%s#{is_legacy ? "" : "?license_id=#{license_key}"}"
23
+ "#{url}/%s?license_id=#{license_key}"
44
24
  end
45
25
 
46
26
  def install_sh_url
@@ -50,7 +30,7 @@ class Chef
50
30
  class << self
51
31
  def validate!
52
32
  license_keys = begin
53
- ChefLicensing::LicenseKeyFetcher.fetch
33
+ ChefLicensing.fetch_and_persist
54
34
  # If the env is airgapped or the local licensing service is unreachable,
55
35
  # the licensing gem will raise ChefLicensing::RestfulClientConnectionError.
56
36
  # In such cases, we are assuming the license is not available.
@@ -66,6 +46,16 @@ class Chef
66
46
 
67
47
  new(licenses_metadata.last.id, licenses_metadata.last.license_type)
68
48
  end
49
+
50
+ def check_software_entitlement!(ui)
51
+ ChefLicensing.check_software_entitlement!
52
+ rescue ChefLicensing::SoftwareNotEntitled
53
+ ui.error "License is not entitled to use Workstation."
54
+ exit 1
55
+ rescue ChefLicensing::Error => e
56
+ ui.error e.message
57
+ exit 1
58
+ end
69
59
  end
70
60
  end
71
61
  end
File without changes
File without changes
@@ -1,4 +1,4 @@
1
- Template rendering libraries
2
- should support
3
- different line endings
4
-
1
+ Template rendering libraries
2
+ should support
3
+ different line endings
4
+
@@ -1,4 +1,4 @@
1
1
  Template rendering libraries
2
- should support
2
+ should support
3
3
  different line endings
4
-
4
+