knife-winops 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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