knife-winops 2.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.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +30 -0
  5. data/CHANGELOG.md +147 -0
  6. data/DOC_CHANGES.md +22 -0
  7. data/Gemfile +13 -0
  8. data/LICENSE +201 -0
  9. data/README.md +430 -0
  10. data/RELEASE_NOTES.md +17 -0
  11. data/Rakefile +21 -0
  12. data/appveyor.yml +36 -0
  13. data/ci.gemfile +15 -0
  14. data/knife-winops.gemspec +26 -0
  15. data/lib/chef/knife/bootstrap/Chef_bootstrap.erb +44 -0
  16. data/lib/chef/knife/bootstrap/bootstrap.ps1 +134 -0
  17. data/lib/chef/knife/bootstrap/tail.cmd +15 -0
  18. data/lib/chef/knife/bootstrap/windows-chef-client-msi.erb +302 -0
  19. data/lib/chef/knife/bootstrap_windows_base.rb +473 -0
  20. data/lib/chef/knife/bootstrap_windows_ssh.rb +115 -0
  21. data/lib/chef/knife/bootstrap_windows_winrm.rb +102 -0
  22. data/lib/chef/knife/core/windows_bootstrap_context.rb +356 -0
  23. data/lib/chef/knife/knife_windows_base.rb +33 -0
  24. data/lib/chef/knife/windows_cert_generate.rb +155 -0
  25. data/lib/chef/knife/windows_cert_install.rb +68 -0
  26. data/lib/chef/knife/windows_helper.rb +36 -0
  27. data/lib/chef/knife/windows_listener_create.rb +107 -0
  28. data/lib/chef/knife/winrm.rb +127 -0
  29. data/lib/chef/knife/winrm_base.rb +128 -0
  30. data/lib/chef/knife/winrm_knife_base.rb +315 -0
  31. data/lib/chef/knife/winrm_session.rb +101 -0
  32. data/lib/chef/knife/winrm_shared_options.rb +54 -0
  33. data/lib/chef/knife/wsman_endpoint.rb +44 -0
  34. data/lib/chef/knife/wsman_test.rb +118 -0
  35. data/lib/knife-winops/path_helper.rb +242 -0
  36. data/lib/knife-winops/version.rb +6 -0
  37. data/spec/assets/fake_trusted_certs/excluded.txt +2 -0
  38. data/spec/assets/fake_trusted_certs/github.pem +42 -0
  39. data/spec/assets/fake_trusted_certs/google.crt +41 -0
  40. data/spec/assets/win_fake_trusted_cert_script.txt +89 -0
  41. data/spec/dummy_winrm_connection.rb +21 -0
  42. data/spec/functional/bootstrap_download_spec.rb +229 -0
  43. data/spec/spec_helper.rb +93 -0
  44. data/spec/unit/knife/bootstrap_options_spec.rb +164 -0
  45. data/spec/unit/knife/bootstrap_template_spec.rb +98 -0
  46. data/spec/unit/knife/bootstrap_windows_winrm_spec.rb +410 -0
  47. data/spec/unit/knife/core/windows_bootstrap_context_spec.rb +292 -0
  48. data/spec/unit/knife/windows_cert_generate_spec.rb +90 -0
  49. data/spec/unit/knife/windows_cert_install_spec.rb +51 -0
  50. data/spec/unit/knife/windows_listener_create_spec.rb +76 -0
  51. data/spec/unit/knife/winrm_session_spec.rb +101 -0
  52. data/spec/unit/knife/winrm_spec.rb +494 -0
  53. data/spec/unit/knife/wsman_test_spec.rb +209 -0
  54. metadata +157 -0
@@ -0,0 +1,473 @@
1
+ #
2
+ # Original knife-windows author:: Seth Chisamore (<schisamo@chef.io>)
3
+ # Copyright:: Copyright (c) 2011-2016 Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/knife'
20
+ require 'chef/knife/bootstrap'
21
+ require 'chef/encrypted_data_bag_item'
22
+ require 'chef/knife/core/windows_bootstrap_context'
23
+ require 'chef/knife/knife_windows_base'
24
+ # Chef 11 PathHelper doesn't have #home
25
+ #require 'chef/util/path_helper'
26
+
27
+ class Chef
28
+ class Knife
29
+ module BootstrapWindowsBase
30
+
31
+ include Chef::Knife::KnifeWindowsBase
32
+
33
+ # :nodoc:
34
+ # Would prefer to do this in a rational way, but can't be done b/c of
35
+ # Mixlib::CLI's design :(
36
+ def self.included(includer)
37
+ includer.class_eval do
38
+
39
+ deps do
40
+ require 'readline'
41
+ require 'chef/json_compat'
42
+ end
43
+
44
+ option :chef_node_name,
45
+ :short => "-N NAME",
46
+ :long => "--node-name NAME",
47
+ :description => "The Chef node name for your new node"
48
+
49
+ option :prerelease,
50
+ :long => "--prerelease",
51
+ :description => "Install the pre-release chef gems"
52
+
53
+ option :bootstrap_version,
54
+ :long => "--bootstrap-version VERSION",
55
+ :description => "The version of Chef to install",
56
+ :proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
57
+
58
+ option :bootstrap_proxy,
59
+ :long => "--bootstrap-proxy PROXY_URL",
60
+ :description => "The proxy server for the node being bootstrapped",
61
+ :proc => Proc.new { |p| Chef::Config[:knife][:bootstrap_proxy] = p }
62
+
63
+ option :bootstrap_no_proxy,
64
+ :long => "--bootstrap-no-proxy [NO_PROXY_URL|NO_PROXY_IP]",
65
+ :description => "Do not proxy locations for the node being bootstrapped; this option is used internally by Opscode",
66
+ :proc => Proc.new { |np| Chef::Config[:knife][:bootstrap_no_proxy] = np }
67
+
68
+ option :bootstrap_debug,
69
+ :long => "--bootstrap-debug",
70
+ :description => "Verbose bootstrap output",
71
+ :proc => Proc.new { |bv| Chef::Config[:knife][:bootstrap_debug] = bv }
72
+
73
+ option :bootstrap_install_command,
74
+ :long => "--bootstrap-install-command COMMANDS",
75
+ :description => "Custom command to install chef-client",
76
+ :proc => Proc.new { |ic| Chef::Config[:knife][:bootstrap_install_command] = ic }
77
+
78
+ option :bootstrap_run_command,
79
+ :long => "--bootstrap_run_command COMMANDS",
80
+ :description => "Custom command to run (chef-client)",
81
+ :proc => Proc.new { |rc| Chef::Config[:knife][:bootstrap_run_command] = rc }
82
+
83
+ option :bootstrap_tail_file,
84
+ :long => "--bootstrap_tail_file FILENAME",
85
+ :description => "Custom (log)file to tail on console",
86
+ :proc => Proc.new { |tf| Chef::Config[:knife][:bootstrap_tail_file] = tf }
87
+
88
+ # DEPR: Remove this option in Chef 13
89
+ option :distro,
90
+ :short => "-d DISTRO",
91
+ :long => "--distro DISTRO",
92
+ :description => "Bootstrap a distro using a template. [DEPRECATED] Use -t / --bootstrap-template option instead.",
93
+ :proc => Proc.new { |v|
94
+ Chef::Log.warn("[DEPRECATED] -d / --distro option is deprecated. Use --bootstrap-template option instead.")
95
+ v
96
+ }
97
+
98
+ option :bootstrap_template,
99
+ :short => "-t TEMPLATE",
100
+ :long => "--bootstrap-template TEMPLATE",
101
+ :description => "Bootstrap Chef using a built-in or custom template. Set to the full path of an erb template or use one of the built-in templates."
102
+
103
+ # DEPR: Remove this option in Chef 13
104
+ option :template_file,
105
+ :long => "--template-file TEMPLATE",
106
+ :description => "Full path to location of template to use. [DEPRECATED] Use -t / --bootstrap-template option instead.",
107
+ :proc => Proc.new { |v|
108
+ Chef::Log.warn("[DEPRECATED] --template-file option is deprecated. Use --bootstrap-template option instead.")
109
+ v
110
+ }
111
+
112
+ option :run_list,
113
+ :short => "-r RUN_LIST",
114
+ :long => "--run-list RUN_LIST",
115
+ :description => "Comma separated list of roles/recipes to apply",
116
+ :proc => lambda { |o| o.split(",") },
117
+ :default => []
118
+
119
+ option :hint,
120
+ :long => "--hint HINT_NAME[=HINT_FILE]",
121
+ :description => "Specify Ohai Hint to be set on the bootstrap target. Use multiple --hint options to specify multiple hints.",
122
+ :proc => Proc.new { |h|
123
+ Chef::Config[:knife][:hints] ||= Hash.new
124
+ name, path = h.split("=")
125
+ Chef::Config[:knife][:hints][name] = path ? Chef::JSONCompat.parse(::File.read(path)) : Hash.new
126
+ }
127
+
128
+ option :first_boot_attributes,
129
+ :short => "-j JSON_ATTRIBS",
130
+ :long => "--json-attributes",
131
+ :description => "A JSON string to be added to the first run of chef-client",
132
+ :proc => lambda { |o| JSON.parse(o) },
133
+ :default => nil
134
+
135
+ option :first_boot_attributes_from_file,
136
+ :long => "--json-attribute-file FILE",
137
+ :description => "A JSON file to be used to the first run of chef-client",
138
+ :proc => lambda { |o| Chef::JSONCompat.parse(File.read(o)) },
139
+ :default => nil
140
+
141
+ # Mismatch between option 'encrypted_data_bag_secret' and it's long value '--secret' is by design for compatibility
142
+ option :encrypted_data_bag_secret,
143
+ :short => "-s SECRET",
144
+ :long => "--secret ",
145
+ :description => "The secret key to use to decrypt data bag item values. Will be rendered on the node at c:/chef/encrypted_data_bag_secret and set in the rendered client config.",
146
+ :default => false
147
+
148
+ # Mismatch between option 'encrypted_data_bag_secret_file' and it's long value '--secret-file' is by design for compatibility
149
+ option :encrypted_data_bag_secret_file,
150
+ :long => "--secret-file SECRET_FILE",
151
+ :description => "A file containing the secret key to use to encrypt data bag item values. Will be rendered on the node at c:/chef/encrypted_data_bag_secret and set in the rendered client config."
152
+
153
+ option :auth_timeout,
154
+ :long => "--auth-timeout MINUTES",
155
+ :description => "The maximum time in minutes to wait to for authentication over the transport to the node to succeed. The default value is 2 minutes.",
156
+ :default => 2
157
+
158
+ option :node_ssl_verify_mode,
159
+ :long => "--node-ssl-verify-mode [peer|none]",
160
+ :description => "Whether or not to verify the SSL cert for all HTTPS requests.",
161
+ :proc => Proc.new { |v|
162
+ valid_values = ["none", "peer"]
163
+ unless valid_values.include?(v)
164
+ raise "Invalid value '#{v}' for --node-ssl-verify-mode. Valid values are: #{valid_values.join(", ")}"
165
+ end
166
+ v
167
+ }
168
+
169
+ option :node_verify_api_cert,
170
+ :long => "--[no-]node-verify-api-cert",
171
+ :description => "Verify the SSL cert for HTTPS requests to the Chef server API.",
172
+ :boolean => true
173
+
174
+ option :msi_url,
175
+ :short => "-u URL",
176
+ :long => "--msi-url URL",
177
+ :description => "Location of the Chef Client MSI. The default templates will prefer to download from this location. The MSI will be downloaded from chef.io if not provided.",
178
+ :default => ''
179
+
180
+ option :install_as_service,
181
+ :long => "--install-as-service",
182
+ :description => "Install chef-client as a Windows service",
183
+ :default => false
184
+
185
+ option :bootstrap_vault_file,
186
+ :long => '--bootstrap-vault-file VAULT_FILE',
187
+ :description => 'A JSON file with a list of vault(s) and item(s) to be updated'
188
+
189
+ option :bootstrap_vault_json,
190
+ :long => '--bootstrap-vault-json VAULT_JSON',
191
+ :description => 'A JSON string with the vault(s) and item(s) to be updated'
192
+
193
+ option :bootstrap_vault_item,
194
+ :long => '--bootstrap-vault-item VAULT_ITEM',
195
+ :description => 'A single vault and item to update as "vault:item"',
196
+ :proc => Proc.new { |i|
197
+ (vault, item) = i.split(/:/)
198
+ Chef::Config[:knife][:bootstrap_vault_item] ||= {}
199
+ Chef::Config[:knife][:bootstrap_vault_item][vault] ||= []
200
+ Chef::Config[:knife][:bootstrap_vault_item][vault].push(item)
201
+ Chef::Config[:knife][:bootstrap_vault_item]
202
+ }
203
+
204
+ option :policy_name,
205
+ :long => "--policy-name POLICY_NAME",
206
+ :description => "Policyfile name to use (--policy-group must also be given)",
207
+ :default => nil
208
+
209
+ option :policy_group,
210
+ :long => "--policy-group POLICY_GROUP",
211
+ :description => "Policy group name to use (--policy-name must also be given)",
212
+ :default => nil
213
+
214
+ option :tags,
215
+ :long => "--tags TAGS",
216
+ :description => "Comma separated list of tags to apply to the node",
217
+ :proc => lambda { |o| o.split(/[\s,]+/) },
218
+ :default => []
219
+
220
+ option :chef_server,
221
+ :long => "--[no-]chef_server",
222
+ :description => "Register node in chef server. Or not.",
223
+ :boolean => true,
224
+ :default => true
225
+
226
+ option :payload_folder,
227
+ :long => "--payload_folder FOLDER",
228
+ :description => "Folder to copy to the remote server",
229
+ :boolean => false
230
+ end
231
+ end
232
+
233
+ def default_bootstrap_template
234
+ "windows-chef-client-msi"
235
+ end
236
+
237
+ def bootstrap_template
238
+ # The order here is important. We want to check if we have the new Chef 12 option is set first.
239
+ # Knife cloud plugins unfortunately all set a default option for the :distro so it should be at
240
+ # the end.
241
+ config[:bootstrap_template] || config[:template_file] || config[:distro] || default_bootstrap_template
242
+ end
243
+
244
+ # TODO: This should go away when CHEF-2193 is fixed
245
+ def load_template(template=nil)
246
+ # Are we bootstrapping using an already shipped template?
247
+
248
+ template = bootstrap_template
249
+
250
+ # Use the template directly if it's a path to an actual file
251
+ if File.exists?(template)
252
+ Chef::Log.debug("Using the specified bootstrap template: #{File.dirname(template)}")
253
+ return IO.read(template).chomp
254
+ end
255
+
256
+ # Otherwise search the template directories until we find the right one
257
+ bootstrap_files = []
258
+ bootstrap_files << File.join(File.dirname(__FILE__), 'bootstrap/templates', "#{template}.erb")
259
+ bootstrap_files << File.join(Knife.chef_config_dir, "bootstrap", "#{template}.erb") if Chef::Knife.chef_config_dir
260
+ ::Knife::Windows::PathHelper.all_homes('.chef', 'bootstrap', "#{template}.erb") { |p| bootstrap_files << p }
261
+ bootstrap_files << Gem.find_files(File.join("chef","knife","bootstrap","#{template}.erb"))
262
+ bootstrap_files.flatten!
263
+
264
+ template = Array(bootstrap_files).find do |bootstrap_template|
265
+ Chef::Log.debug("Looking for bootstrap template in #{File.dirname(bootstrap_template)}")
266
+ ::File.exists?(bootstrap_template)
267
+ end
268
+
269
+ unless template
270
+ ui.info("Can not find bootstrap definition for #{config[:distro]}")
271
+ raise Errno::ENOENT
272
+ end
273
+
274
+ Chef::Log.debug("Found bootstrap template in #{File.dirname(template)}")
275
+
276
+ IO.read(template).chomp
277
+ end
278
+
279
+ def bootstrap_context
280
+ @bootstrap_context ||= Knife::Core::WindowsBootstrapContext.new(config, config[:run_list], Chef::Config)
281
+ end
282
+
283
+ def load_correct_secret
284
+ knife_secret_file = Chef::Config[:knife][:encrypted_data_bag_secret_file]
285
+ knife_secret = Chef::Config[:knife][:encrypted_data_bag_secret]
286
+ cli_secret_file = config[:encrypted_data_bag_secret_file]
287
+ cli_secret = config[:encrypted_data_bag_secret]
288
+
289
+ cli_secret_file = nil if cli_secret_file == knife_secret_file
290
+ cli_secret = nil if cli_secret == knife_secret
291
+
292
+ cli_secret_file = Chef::EncryptedDataBagItem.load_secret(cli_secret_file) if cli_secret_file != nil
293
+ knife_secret_file = Chef::EncryptedDataBagItem.load_secret(knife_secret_file) if knife_secret_file != nil
294
+
295
+ cli_secret_file || cli_secret || knife_secret_file || knife_secret
296
+ end
297
+
298
+ def first_boot_attributes
299
+ config[:first_boot_attributes] || config[:first_boot_attributes_from_file] || {}
300
+ end
301
+
302
+ def render_template(template=nil)
303
+ config[:first_boot_attributes] = first_boot_attributes
304
+ config[:secret] = load_correct_secret
305
+ Erubis::Eruby.new(template).evaluate(bootstrap_context)
306
+ end
307
+
308
+ def bootstrap(proto=nil)
309
+ if Chef::Config[:knife][:encrypted_data_bag_secret_file] || Chef::Config[:knife][:encrypted_data_bag_secret]
310
+ warn_chef_config_secret_key
311
+ end
312
+
313
+ set_target_architecture
314
+
315
+ # adding respond_to? so this works with pre 12.4 chef clients
316
+ validate_options! if respond_to?(:validate_options!)
317
+
318
+ @node_name = Array(@name_args).first
319
+ # back compat--templates may use this setting:
320
+ config[:server_name] = @node_name
321
+
322
+ STDOUT.sync = STDERR.sync = true
323
+
324
+ if Chef::VERSION.split('.').first.to_i == 11 && Chef::Config[:validation_key] && !File.exist?(File.expand_path(Chef::Config[:validation_key]))
325
+ ui.error("Unable to find validation key. Please verify your configuration file for validation_key config value.")
326
+ exit 1
327
+ end
328
+
329
+ if (defined?(chef_vault_handler) && chef_vault_handler.doing_chef_vault?) ||
330
+ (Chef::Config[:validation_key] && !File.exist?(File.expand_path(Chef::Config[:validation_key])))
331
+
332
+ unless locate_config_value(:chef_node_name)
333
+ ui.error("You must pass a node name with -N when bootstrapping with user credentials")
334
+ exit 1
335
+ end
336
+
337
+ if config[:chef_server]
338
+ client_builder.run
339
+ end
340
+
341
+ if client_builder.respond_to?(:client)
342
+ chef_vault_handler.run(client_builder.client)
343
+ else
344
+ chef_vault_handler.run(node_name: config[:chef_node_name])
345
+ end
346
+
347
+ bootstrap_context.client_pem = client_builder.client_path
348
+
349
+ else
350
+ ui.info("Doing old-style registration with the validation key at #{Chef::Config[:validation_key]}...")
351
+ ui.info("Delete your validation key in order to use your user credentials instead")
352
+ ui.info("")
353
+ end
354
+
355
+ wait_for_remote_response( config[:auth_timeout].to_i )
356
+
357
+ ui.info("Bootstrapping Chef on #{ui.color(@node_name, :bold)}")
358
+ # create a bootstrap.bat file on the node
359
+ # we have to run the remote commands in 2047 char chunks
360
+ create_bootstrap_bat_command do |command_chunk|
361
+ render_command_result = run_command(command_chunk)
362
+ unless render_command_result == 0
363
+ ui.error("Batch render command returned #{render_command_result}")
364
+ exit render_command_result
365
+ end
366
+ end
367
+
368
+ # execute the bootstrap.bat file
369
+ bootstrap_command_result = run_command(bootstrap_command)
370
+ unless bootstrap_command_result == 0
371
+ ui.error("Bootstrap command returned #{bootstrap_command_result}")
372
+ exit bootstrap_command_result
373
+ end
374
+
375
+ # exit 0
376
+ 0
377
+ end
378
+
379
+ protected
380
+
381
+ # Default implementation -- override only if required by the transport
382
+ def wait_for_remote_response(wait_max_minutes)
383
+ end
384
+
385
+ def bootstrap_command
386
+ @bootstrap_command ||= "cmd.exe /C #{bootstrap_bat_file}"
387
+ end
388
+
389
+ def bootstrap_render_banner_command(chunk_num)
390
+ "cmd.exe /C echo Rendering #{bootstrap_bat_file} chunk #{chunk_num}"
391
+ end
392
+
393
+ def escape_windows_batch_characters(line)
394
+ # TODO: The commands are going to get redirected - do we need to escape &?
395
+ line.gsub!(/[(<|>)^]/).each{|m| "^#{m}"}
396
+ end
397
+
398
+ def create_bootstrap_bat_command()
399
+ chunk_num = 0
400
+ bootstrap_bat = ""
401
+ banner = bootstrap_render_banner_command(chunk_num += 1)
402
+ render_template(load_template(config[:bootstrap_template])).each_line do |line|
403
+ escape_windows_batch_characters(line)
404
+ # We are guaranteed to have a prefix "banner" command that echo's chunk number. We can
405
+ # confidently prefix every actual command with &&.
406
+ # TODO: Why does ^\n&& work directly through the commandline but not through SOAP?
407
+ render_line = " && >> #{bootstrap_bat_file} (echo.#{line.chomp.strip})"
408
+ # Windows commands are limited to 8191 characters for machines running XP or higher but
409
+ # this includes the length of environment variables after they have been expanded.
410
+ # Since we don't actually know how long %TEMP% (and it's used twice - once in the banner
411
+ # and once in every command redirection), we simply guess and set the max to 5000.
412
+ # TODO: When a more accurate method is available, fix this.
413
+ if bootstrap_bat.length + render_line.length + banner.length > 5000
414
+ # Can't fit it into this chunk? - flush (if necessary) and then try.
415
+ # Do this first because banner.length might change (e.g. due to an extra digit) and
416
+ # prevent a fit.
417
+ unless bootstrap_bat.empty?
418
+ yield banner + bootstrap_bat
419
+ bootstrap_bat = ""
420
+ banner = bootstrap_render_banner_command(chunk_num += 1)
421
+ end
422
+ # Will this ever fit?
423
+ if render_line.length + banner.length > 5000
424
+ raise "Command in bootstrap template too long by #{render_line.length + banner.length - 5000} characters : #{line}"
425
+ end
426
+ end
427
+ bootstrap_bat << render_line
428
+ end
429
+ raise "Bootstrap template was empty! Check #{config[:bootstrap_template]}" if bootstrap_bat.empty?
430
+ yield banner + bootstrap_bat
431
+ end
432
+
433
+ def bootstrap_bat_file
434
+ @bootstrap_bat_file ||= "\"%TEMP%\\bootstrap-#{Process.pid}-#{Time.now.to_i}.bat\""
435
+ end
436
+
437
+ def warn_chef_config_secret_key
438
+ ui.info "* " * 40
439
+ ui.warn(<<-WARNING)
440
+ \nSpecifying the encrypted data bag secret key using an 'encrypted_data_bag_secret'
441
+ entry in 'knife.rb' is deprecated. Please use the '--secret' or '--secret-file'
442
+ options of this command instead.
443
+
444
+ #{ui.color('IMPORTANT:', :red, :bold)} In a future version of Chef, this
445
+ behavior will be removed and any 'encrypted_data_bag_secret' entries in
446
+ 'knife.rb' will be ignored completely.
447
+ WARNING
448
+ ui.info "* " * 40
449
+ end
450
+
451
+ # We allow the user to specify the desired architecture of Chef to install or we default
452
+ # to whatever the target system is.
453
+ # This is because a user might want to install a 32bit chef client on a 64bit machine
454
+ def set_target_architecture
455
+ if Chef::Config[:knife][:architecture]
456
+ raise "Do not set :architecture in your knife config, use :bootstrap_architecture."
457
+ end
458
+
459
+ if Chef::Config[:knife][:bootstrap_architecture]
460
+ bootstrap_architecture = Chef::Config[:knife][:bootstrap_architecture]
461
+
462
+ if ![:x86_64, :i386].include?(bootstrap_architecture.to_sym)
463
+ raise "Valid values for the knife config :bootstrap_architecture are i386 or x86_64. Supplied value is #{bootstrap_architecture}"
464
+ end
465
+
466
+ # The windows install script wants i686, not i386
467
+ bootstrap_architecture = :i686 if bootstrap_architecture == :i386
468
+ Chef::Config[:knife][:architecture] = bootstrap_architecture
469
+ end
470
+ end
471
+ end
472
+ end
473
+ end