knife-windows 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -5
  3. data/.travis.yml +20 -20
  4. data/CHANGELOG.md +87 -83
  5. data/DOC_CHANGES.md +20 -20
  6. data/Gemfile +12 -12
  7. data/LICENSE +201 -201
  8. data/README.md +396 -396
  9. data/RELEASE_NOTES.md +34 -34
  10. data/Rakefile +21 -21
  11. data/appveyor.yml +42 -42
  12. data/ci.gemfile +15 -15
  13. data/features/knife_help.feature +20 -20
  14. data/features/support/env.rb +5 -5
  15. data/knife-windows.gemspec +28 -28
  16. data/lib/chef/knife/bootstrap/windows-chef-client-msi.erb +247 -247
  17. data/lib/chef/knife/bootstrap_windows_base.rb +407 -401
  18. data/lib/chef/knife/bootstrap_windows_ssh.rb +110 -110
  19. data/lib/chef/knife/bootstrap_windows_winrm.rb +95 -102
  20. data/lib/chef/knife/core/windows_bootstrap_context.rb +362 -362
  21. data/lib/chef/knife/knife_windows_base.rb +33 -33
  22. data/lib/chef/knife/windows_cert_generate.rb +155 -155
  23. data/lib/chef/knife/windows_cert_install.rb +68 -68
  24. data/lib/chef/knife/windows_helper.rb +36 -36
  25. data/lib/chef/knife/windows_listener_create.rb +107 -107
  26. data/lib/chef/knife/winrm.rb +122 -212
  27. data/lib/chef/knife/winrm_base.rb +118 -118
  28. data/lib/chef/knife/winrm_knife_base.rb +309 -218
  29. data/lib/chef/knife/winrm_session.rb +82 -82
  30. data/lib/chef/knife/winrm_shared_options.rb +47 -47
  31. data/lib/chef/knife/wsman_endpoint.rb +44 -44
  32. data/lib/chef/knife/wsman_test.rb +95 -95
  33. data/lib/knife-windows/path_helper.rb +234 -234
  34. data/lib/knife-windows/version.rb +6 -6
  35. data/spec/assets/win_template_rendered_with_bootstrap_install_command.txt +217 -217
  36. data/spec/assets/win_template_rendered_with_bootstrap_install_command_on_12_5_client.txt +217 -217
  37. data/spec/assets/win_template_rendered_without_bootstrap_install_command.txt +329 -329
  38. data/spec/assets/win_template_rendered_without_bootstrap_install_command_on_12_5_client.txt +329 -329
  39. data/spec/assets/win_template_unrendered.txt +246 -246
  40. data/spec/functional/bootstrap_download_spec.rb +234 -233
  41. data/spec/spec_helper.rb +88 -88
  42. data/spec/unit/knife/bootstrap_options_spec.rb +148 -146
  43. data/spec/unit/knife/bootstrap_template_spec.rb +92 -92
  44. data/spec/unit/knife/bootstrap_windows_winrm_spec.rb +259 -243
  45. data/spec/unit/knife/core/windows_bootstrap_context_spec.rb +151 -151
  46. data/spec/unit/knife/windows_cert_generate_spec.rb +90 -90
  47. data/spec/unit/knife/windows_cert_install_spec.rb +51 -51
  48. data/spec/unit/knife/windows_listener_create_spec.rb +76 -76
  49. data/spec/unit/knife/winrm_session_spec.rb +73 -73
  50. data/spec/unit/knife/winrm_spec.rb +551 -504
  51. data/spec/unit/knife/wsman_test_spec.rb +178 -175
  52. metadata +3 -23
@@ -1,110 +1,110 @@
1
- #
2
- # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
- # Copyright:: Copyright (c) 2011 Opscode, 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/bootstrap_windows_base'
20
-
21
- class Chef
22
- class Knife
23
- class BootstrapWindowsSsh < Bootstrap
24
-
25
- include Chef::Knife::BootstrapWindowsBase
26
-
27
- deps do
28
- require 'chef/knife/core/windows_bootstrap_context'
29
- require 'chef/json_compat'
30
- require 'tempfile'
31
- require 'highline'
32
- require 'net/ssh'
33
- require 'net/ssh/multi'
34
- Chef::Knife::Ssh.load_deps
35
- end
36
-
37
- banner "knife bootstrap windows ssh FQDN (options)"
38
-
39
- option :ssh_user,
40
- :short => "-x USERNAME",
41
- :long => "--ssh-user USERNAME",
42
- :description => "The ssh username",
43
- :default => "root"
44
-
45
- option :ssh_password,
46
- :short => "-P PASSWORD",
47
- :long => "--ssh-password PASSWORD",
48
- :description => "The ssh password"
49
-
50
- option :ssh_port,
51
- :short => "-p PORT",
52
- :long => "--ssh-port PORT",
53
- :description => "The ssh port",
54
- :proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key.strip }
55
-
56
- option :ssh_gateway,
57
- :short => "-G GATEWAY",
58
- :long => "--ssh-gateway GATEWAY",
59
- :description => "The ssh gateway",
60
- :proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key }
61
-
62
- option :forward_agent,
63
- :short => "-A",
64
- :long => "--forward-agent",
65
- :description => "Enable SSH agent forwarding",
66
- :boolean => true
67
-
68
- option :identity_file,
69
- :short => "-i IDENTITY_FILE",
70
- :long => "--identity-file IDENTITY_FILE",
71
- :description => "The SSH identity file used for authentication"
72
-
73
- # DEPR: Remove this option for the next release.
74
- option :host_key_verification,
75
- :long => "--[no-]host-key-verify",
76
- :description => "Verify host key, enabled by default. [DEPRECATED] Use --host-key-verify option instead.",
77
- :boolean => true,
78
- :default => true,
79
- :proc => Proc.new { |key|
80
- Chef::Log.warn("[DEPRECATED] --host-key-verification option is deprecated. Use --host-key-verify option instead.")
81
- config[:host_key_verify] = key
82
- }
83
-
84
- option :host_key_verify,
85
- :long => "--[no-]host-key-verify",
86
- :description => "Verify host key, enabled by default.",
87
- :boolean => true,
88
- :default => true
89
-
90
- def run
91
- bootstrap
92
- end
93
-
94
- def run_command(command = '')
95
- ssh = Chef::Knife::Ssh.new
96
- ssh.name_args = [ server_name, command ]
97
- ssh.config[:ssh_user] = locate_config_value(:ssh_user)
98
- ssh.config[:ssh_password] = locate_config_value(:ssh_password)
99
- ssh.config[:ssh_port] = locate_config_value(:ssh_port)
100
- ssh.config[:ssh_gateway] = locate_config_value(:ssh_gateway)
101
- ssh.config[:identity_file] = config[:identity_file]
102
- ssh.config[:forward_agent] = config[:forward_agent]
103
- ssh.config[:manual] = true
104
- ssh.config[:host_key_verify] = config[:host_key_verify]
105
- ssh.run
106
- end
107
-
108
- end
109
- end
110
- end
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, 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/bootstrap_windows_base'
20
+
21
+ class Chef
22
+ class Knife
23
+ class BootstrapWindowsSsh < Bootstrap
24
+
25
+ include Chef::Knife::BootstrapWindowsBase
26
+
27
+ deps do
28
+ require 'chef/knife/core/windows_bootstrap_context'
29
+ require 'chef/json_compat'
30
+ require 'tempfile'
31
+ require 'highline'
32
+ require 'net/ssh'
33
+ require 'net/ssh/multi'
34
+ Chef::Knife::Ssh.load_deps
35
+ end
36
+
37
+ banner "knife bootstrap windows ssh FQDN (options)"
38
+
39
+ option :ssh_user,
40
+ :short => "-x USERNAME",
41
+ :long => "--ssh-user USERNAME",
42
+ :description => "The ssh username",
43
+ :default => "root"
44
+
45
+ option :ssh_password,
46
+ :short => "-P PASSWORD",
47
+ :long => "--ssh-password PASSWORD",
48
+ :description => "The ssh password"
49
+
50
+ option :ssh_port,
51
+ :short => "-p PORT",
52
+ :long => "--ssh-port PORT",
53
+ :description => "The ssh port",
54
+ :proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key.strip }
55
+
56
+ option :ssh_gateway,
57
+ :short => "-G GATEWAY",
58
+ :long => "--ssh-gateway GATEWAY",
59
+ :description => "The ssh gateway",
60
+ :proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key }
61
+
62
+ option :forward_agent,
63
+ :short => "-A",
64
+ :long => "--forward-agent",
65
+ :description => "Enable SSH agent forwarding",
66
+ :boolean => true
67
+
68
+ option :identity_file,
69
+ :short => "-i IDENTITY_FILE",
70
+ :long => "--identity-file IDENTITY_FILE",
71
+ :description => "The SSH identity file used for authentication"
72
+
73
+ # DEPR: Remove this option for the next release.
74
+ option :host_key_verification,
75
+ :long => "--[no-]host-key-verify",
76
+ :description => "Verify host key, enabled by default. [DEPRECATED] Use --host-key-verify option instead.",
77
+ :boolean => true,
78
+ :default => true,
79
+ :proc => Proc.new { |key|
80
+ Chef::Log.warn("[DEPRECATED] --host-key-verification option is deprecated. Use --host-key-verify option instead.")
81
+ config[:host_key_verify] = key
82
+ }
83
+
84
+ option :host_key_verify,
85
+ :long => "--[no-]host-key-verify",
86
+ :description => "Verify host key, enabled by default.",
87
+ :boolean => true,
88
+ :default => true
89
+
90
+ def run
91
+ bootstrap
92
+ end
93
+
94
+ def run_command(command = '')
95
+ ssh = Chef::Knife::Ssh.new
96
+ ssh.name_args = [ server_name, command ]
97
+ ssh.config[:ssh_user] = locate_config_value(:ssh_user)
98
+ ssh.config[:ssh_password] = locate_config_value(:ssh_password)
99
+ ssh.config[:ssh_port] = locate_config_value(:ssh_port)
100
+ ssh.config[:ssh_gateway] = locate_config_value(:ssh_gateway)
101
+ ssh.config[:identity_file] = config[:identity_file]
102
+ ssh.config[:forward_agent] = config[:forward_agent]
103
+ ssh.config[:manual] = true
104
+ ssh.config[:host_key_verify] = config[:host_key_verify]
105
+ ssh.run
106
+ end
107
+
108
+ end
109
+ end
110
+ end
@@ -1,102 +1,95 @@
1
- #
2
- # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
- # Copyright:: Copyright (c) 2011 Opscode, 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/bootstrap_windows_base'
20
- require 'chef/knife/winrm'
21
- require 'chef/knife/winrm_base'
22
- require 'chef/knife/winrm_knife_base'
23
-
24
-
25
- class Chef
26
- class Knife
27
- class BootstrapWindowsWinrm < Bootstrap
28
-
29
- include Chef::Knife::BootstrapWindowsBase
30
- include Chef::Knife::WinrmBase
31
- include Chef::Knife::WinrmCommandSharedFunctions
32
-
33
- deps do
34
- require 'chef/knife/core/windows_bootstrap_context'
35
- require 'chef/json_compat'
36
- require 'tempfile'
37
- Chef::Knife::Winrm.load_deps
38
- end
39
-
40
- banner 'knife bootstrap windows winrm FQDN (options)'
41
-
42
- def run
43
- if (Chef::Config[:validation_key] && !File.exist?(File.expand_path(Chef::Config[:validation_key])))
44
- if !negotiate_auth? && !(locate_config_value(:winrm_transport) == 'ssl')
45
- ui.error('Validatorless bootstrap over unsecure winrm channels could expose your key to network sniffing')
46
- exit 1
47
- end
48
- end
49
-
50
- validate_winrm_options!
51
- resolve_session_options
52
- @session_opts[:host] = server_name
53
- @session = Chef::Knife::WinrmSession.new(@session_opts)
54
-
55
- bootstrap
56
- end
57
-
58
- def run_command(command = '')
59
- @session.relay_command(command)
60
- return @session.exit_code
61
- end
62
-
63
- protected
64
-
65
- def wait_for_remote_response(wait_max_minutes)
66
- wait_max_seconds = wait_max_minutes * 60
67
- retry_interval_seconds = 10
68
- retries_left = wait_max_seconds / retry_interval_seconds
69
- print(ui.color("\nWaiting for remote response before bootstrap", :magenta))
70
- wait_start_time = Time.now
71
- begin
72
- print(".")
73
- # Return status of the command is non-zero, typically nil,
74
- # for our simple echo command in cases where run_command
75
- # swallows the exception, such as 401's. Treat such cases
76
- # the same as the case where we encounter an exception.
77
- status = run_command("echo . & echo Response received.")
78
- raise RuntimeError, 'Command execution failed.' if status != 0
79
- ui.info(ui.color("Remote node responded after #{elapsed_time_in_minutes(wait_start_time)} minutes.", :magenta))
80
- return
81
- rescue Errno::ECONNREFUSED => e
82
- ui.error("Connection refused connecting to #{locate_config_value(:server_name)}:#{locate_config_value(:winrm_port)}.")
83
- raise
84
- rescue Exception => e
85
- retries_left -= 1
86
- if retries_left <= 0 || (elapsed_time_in_minutes(wait_start_time) > wait_max_minutes)
87
- ui.error("No response received from remote node after #{elapsed_time_in_minutes(wait_start_time)} minutes, giving up.")
88
- ui.error("Exception: #{e.message}")
89
- raise
90
- end
91
- print '.'
92
- sleep retry_interval_seconds
93
- retry
94
- end
95
- end
96
-
97
- def elapsed_time_in_minutes(start_time)
98
- ((Time.now - start_time) / 60).round(2)
99
- end
100
- end
101
- end
102
- end
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, 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/bootstrap_windows_base'
20
+ require 'chef/knife/winrm'
21
+ require 'chef/knife/winrm_base'
22
+ require 'chef/knife/winrm_knife_base'
23
+
24
+
25
+ class Chef
26
+ class Knife
27
+ class BootstrapWindowsWinrm < Bootstrap
28
+
29
+ include Chef::Knife::BootstrapWindowsBase
30
+ include Chef::Knife::WinrmBase
31
+ include Chef::Knife::WinrmCommandSharedFunctions
32
+
33
+ deps do
34
+ require 'chef/knife/core/windows_bootstrap_context'
35
+ require 'chef/json_compat'
36
+ require 'tempfile'
37
+ Chef::Knife::Winrm.load_deps
38
+ end
39
+
40
+ banner 'knife bootstrap windows winrm FQDN (options)'
41
+
42
+ def run
43
+ if (Chef::Config[:validation_key] && !File.exist?(File.expand_path(Chef::Config[:validation_key])))
44
+ if !negotiate_auth? && !(locate_config_value(:winrm_transport) == 'ssl')
45
+ ui.error('Validatorless bootstrap over unsecure winrm channels could expose your key to network sniffing')
46
+ exit 1
47
+ end
48
+ end
49
+
50
+ config[:manual] = true
51
+ configure_session
52
+
53
+ bootstrap
54
+ end
55
+
56
+ protected
57
+
58
+ def wait_for_remote_response(wait_max_minutes)
59
+ wait_max_seconds = wait_max_minutes * 60
60
+ retry_interval_seconds = 10
61
+ retries_left = wait_max_seconds / retry_interval_seconds
62
+ print(ui.color("\nWaiting for remote response before bootstrap", :magenta))
63
+ wait_start_time = Time.now
64
+ begin
65
+ print(".")
66
+ # Return status of the command is non-zero, typically nil,
67
+ # for our simple echo command in cases where run_command
68
+ # swallows the exception, such as 401's. Treat such cases
69
+ # the same as the case where we encounter an exception.
70
+ status = run_command("echo . & echo Response received.")
71
+ raise RuntimeError, 'Command execution failed.' if status != 0
72
+ ui.info(ui.color("Remote node responded after #{elapsed_time_in_minutes(wait_start_time)} minutes.", :magenta))
73
+ return
74
+ rescue Errno::ECONNREFUSED => e
75
+ ui.error("Connection refused connecting to #{locate_config_value(:server_name)}:#{locate_config_value(:winrm_port)}.")
76
+ raise
77
+ rescue Exception => e
78
+ retries_left -= 1
79
+ if retries_left <= 0 || (elapsed_time_in_minutes(wait_start_time) > wait_max_minutes)
80
+ ui.error("No response received from remote node after #{elapsed_time_in_minutes(wait_start_time)} minutes, giving up.")
81
+ ui.error("Exception: #{e.message}")
82
+ raise
83
+ end
84
+ print '.'
85
+ sleep retry_interval_seconds
86
+ retry
87
+ end
88
+ end
89
+
90
+ def elapsed_time_in_minutes(start_time)
91
+ ((Time.now - start_time) / 60).round(2)
92
+ end
93
+ end
94
+ end
95
+ end
@@ -1,362 +1,362 @@
1
- #
2
- # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
- # Copyright:: Copyright (c) 2011 Opscode, 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/core/bootstrap_context'
20
-
21
- # Chef::Util::PathHelper in Chef 11 is a bit juvenile still
22
- require 'knife-windows/path_helper'
23
- # require 'chef/util/path_helper'
24
-
25
-
26
- class Chef
27
- class Knife
28
- module Core
29
- # Instances of BootstrapContext are the context objects (i.e., +self+) for
30
- # bootstrap templates. For backwards compatability, they +must+ set the
31
- # following instance variables:
32
- # * @config - a hash of knife's config values
33
- # * @run_list - the run list for the node to boostrap
34
- #
35
- class WindowsBootstrapContext < BootstrapContext
36
- PathHelper = ::Knife::Windows::PathHelper
37
-
38
- attr_accessor :client_pem
39
-
40
- def initialize(config, run_list, chef_config, secret=nil)
41
- @config = config
42
- @run_list = run_list
43
- @chef_config = chef_config
44
- @secret = secret
45
- # Compatibility with Chef 12 and Chef 11 versions
46
- begin
47
- # Pass along the secret parameter for Chef 12
48
- super(config, run_list, chef_config, secret)
49
- rescue ArgumentError
50
- # The Chef 11 base class only has parameters for initialize
51
- super(config, run_list, chef_config)
52
- end
53
- end
54
-
55
- def validation_key
56
- if File.exist?(File.expand_path(@chef_config[:validation_key]))
57
- IO.read(File.expand_path(@chef_config[:validation_key]))
58
- else
59
- false
60
- end
61
- end
62
-
63
- def secret
64
- escape_and_echo(@config[:secret])
65
- end
66
-
67
- def trusted_certs_script
68
- @trusted_certs_script ||= trusted_certs_content
69
- end
70
-
71
- def config_content
72
- client_rb = <<-CONFIG
73
- log_level :info
74
- log_location STDOUT
75
-
76
- chef_server_url "#{@chef_config[:chef_server_url]}"
77
- validation_client_name "#{@chef_config[:validation_client_name]}"
78
-
79
- file_cache_path "c:/chef/cache"
80
- file_backup_path "c:/chef/backup"
81
- cache_options ({:path => "c:/chef/cache/checksums", :skip_expires => true})
82
-
83
- CONFIG
84
- if @config[:chef_node_name]
85
- client_rb << %Q{node_name "#{@config[:chef_node_name]}"\n}
86
- else
87
- client_rb << "# Using default node name (fqdn)\n"
88
- end
89
-
90
- # We configure :verify_api_cert only when it's overridden on the CLI
91
- # or when specified in the knife config.
92
- if !@config[:node_verify_api_cert].nil? || knife_config.has_key?(:verify_api_cert)
93
- value = @config[:node_verify_api_cert].nil? ? knife_config[:verify_api_cert] : @config[:node_verify_api_cert]
94
- client_rb << %Q{verify_api_cert #{value}\n}
95
- end
96
-
97
- # We configure :ssl_verify_mode only when it's overridden on the CLI
98
- # or when specified in the knife config.
99
- if @config[:node_ssl_verify_mode] || knife_config.has_key?(:ssl_verify_mode)
100
- value = case @config[:node_ssl_verify_mode]
101
- when "peer"
102
- :verify_peer
103
- when "none"
104
- :verify_none
105
- when nil
106
- knife_config[:ssl_verify_mode]
107
- else
108
- nil
109
- end
110
-
111
- if value
112
- client_rb << %Q{ssl_verify_mode :#{value}\n}
113
- end
114
- end
115
-
116
- if @config[:ssl_verify_mode]
117
- client_rb << %Q{ssl_verify_mode :#{knife_config[:ssl_verify_mode]}\n}
118
- end
119
-
120
- if knife_config[:bootstrap_proxy]
121
- client_rb << "\n"
122
- client_rb << %Q{http_proxy "#{knife_config[:bootstrap_proxy]}"\n}
123
- client_rb << %Q{https_proxy "#{knife_config[:bootstrap_proxy]}"\n}
124
- client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n} if knife_config[:bootstrap_no_proxy]
125
- end
126
-
127
- if knife_config[:bootstrap_no_proxy]
128
- client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n}
129
- end
130
-
131
- if @config[:secret]
132
- client_rb << %Q{encrypted_data_bag_secret "c:/chef/encrypted_data_bag_secret"\n}
133
- end
134
-
135
- unless trusted_certs_script.empty?
136
- client_rb << %Q{trusted_certs_dir "c:/chef/trusted_certs"\n}
137
- end
138
-
139
- escape_and_echo(client_rb)
140
- end
141
-
142
- def start_chef
143
- bootstrap_environment_option = bootstrap_environment.nil? ? '' : " -E #{bootstrap_environment}"
144
- start_chef = "SET \"PATH=%PATH%;C:\\ruby\\bin;C:\\opscode\\chef\\bin;C:\\opscode\\chef\\embedded\\bin\"\n"
145
- start_chef << "chef-client -c c:/chef/client.rb -j c:/chef/first-boot.json#{bootstrap_environment_option}\n"
146
- end
147
-
148
- def latest_current_windows_chef_version_query
149
- installer_version_string = nil
150
- if @config[:prerelease]
151
- installer_version_string = "&prerelease=true"
152
- else
153
- chef_version_string = if knife_config[:bootstrap_version]
154
- knife_config[:bootstrap_version]
155
- else
156
- Chef::VERSION.split(".").first
157
- end
158
-
159
- installer_version_string = "&v=#{chef_version_string}"
160
-
161
- # If bootstrapping a pre-release version add the prerelease query string
162
- if chef_version_string.split(".").length > 3
163
- installer_version_string << "&prerelease=true"
164
- end
165
- end
166
-
167
- installer_version_string
168
- end
169
-
170
- def win_wget
171
- # I tried my best to figure out how to properly url decode and switch / to \
172
- # but this is VBScript - so I don't really care that badly.
173
- win_wget = <<-WGET
174
- url = WScript.Arguments.Named("url")
175
- path = WScript.Arguments.Named("path")
176
- proxy = null
177
- '* Vaguely attempt to handle file:// scheme urls by url unescaping and switching all
178
- '* / into \. Also assume that file:/// is a local absolute path and that file://<foo>
179
- '* is possibly a network file path.
180
- If InStr(url, "file://") = 1 Then
181
- url = Unescape(url)
182
- If InStr(url, "file:///") = 1 Then
183
- sourcePath = Mid(url, Len("file:///") + 1)
184
- Else
185
- sourcePath = Mid(url, Len("file:") + 1)
186
- End If
187
- sourcePath = Replace(sourcePath, "/", "\\")
188
-
189
- Set objFSO = CreateObject("Scripting.FileSystemObject")
190
- If objFSO.Fileexists(path) Then objFSO.DeleteFile path
191
- objFSO.CopyFile sourcePath, path, true
192
- Set objFSO = Nothing
193
-
194
- Else
195
- Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP")
196
- Set wshShell = CreateObject( "WScript.Shell" )
197
- Set objUserVariables = wshShell.Environment("USER")
198
-
199
- rem http proxy is optional
200
- rem attempt to read from HTTP_PROXY env var first
201
- On Error Resume Next
202
-
203
- If NOT (objUserVariables("HTTP_PROXY") = "") Then
204
- proxy = objUserVariables("HTTP_PROXY")
205
-
206
- rem fall back to named arg
207
- ElseIf NOT (WScript.Arguments.Named("proxy") = "") Then
208
- proxy = WScript.Arguments.Named("proxy")
209
- End If
210
-
211
- If NOT isNull(proxy) Then
212
- rem setProxy method is only available on ServerXMLHTTP 6.0+
213
- Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP.6.0")
214
- objXMLHTTP.setProxy 2, proxy
215
- End If
216
-
217
- On Error Goto 0
218
-
219
- objXMLHTTP.open "GET", url, false
220
- objXMLHTTP.send()
221
- If objXMLHTTP.Status = 200 Then
222
- Set objADOStream = CreateObject("ADODB.Stream")
223
- objADOStream.Open
224
- objADOStream.Type = 1
225
- objADOStream.Write objXMLHTTP.ResponseBody
226
- objADOStream.Position = 0
227
- Set objFSO = Createobject("Scripting.FileSystemObject")
228
- If objFSO.Fileexists(path) Then objFSO.DeleteFile path
229
- Set objFSO = Nothing
230
- objADOStream.SaveToFile path
231
- objADOStream.Close
232
- Set objADOStream = Nothing
233
- End If
234
- Set objXMLHTTP = Nothing
235
- End If
236
- WGET
237
- escape_and_echo(win_wget)
238
- end
239
-
240
- def win_wget_ps
241
- win_wget_ps = <<-WGET_PS
242
- param(
243
- [String] $remoteUrl,
244
- [String] $localPath
245
- )
246
-
247
- $webClient = new-object System.Net.WebClient;
248
-
249
- $webClient.DownloadFile($remoteUrl, $localPath);
250
- WGET_PS
251
-
252
- escape_and_echo(win_wget_ps)
253
- end
254
-
255
- def install_chef
256
- # The normal install command uses regular double quotes in
257
- # the install command, so request such a string from install_command
258
- install_chef = install_command('"') + "\n" + fallback_install_task_command
259
- end
260
-
261
- def bootstrap_directory
262
- bootstrap_directory = "C:\\chef"
263
- end
264
-
265
- def local_download_path
266
- local_download_path = "%TEMP%\\chef-client-latest.msi"
267
- end
268
-
269
- def msi_url(machine_os=nil, machine_arch=nil, download_context=nil)
270
- # The default msi path has a number of url query parameters - we attempt to substitute
271
- # such parameters in as long as they are provided by the template.
272
-
273
- if @config[:msi_url].nil? || @config[:msi_url].empty?
274
- url = "https://www.chef.io/chef/download?p=windows"
275
- url += "&pv=#{machine_os}" unless machine_os.nil?
276
- url += "&m=#{machine_arch}" unless machine_arch.nil?
277
- url += "&DownloadContext=#{download_context}" unless download_context.nil?
278
- url += latest_current_windows_chef_version_query
279
- else
280
- @config[:msi_url]
281
- end
282
- end
283
-
284
- def first_boot
285
- escape_and_echo(super.to_json)
286
- end
287
-
288
- # escape WIN BATCH special chars
289
- # and prefixes each line with an
290
- # echo
291
- def escape_and_echo(file_contents)
292
- file_contents.gsub(/^(.*)$/, 'echo.\1').gsub(/([(<|>)^])/, '^\1')
293
- end
294
-
295
- private
296
-
297
- def install_command(executor_quote)
298
- if @config[:install_as_service]
299
- "msiexec /qn /log #{executor_quote}%CHEF_CLIENT_MSI_LOG_PATH%#{executor_quote} /i #{executor_quote}%LOCAL_DESTINATION_MSI_PATH%#{executor_quote} ADDLOCAL=#{executor_quote}ChefClientFeature,ChefServiceFeature#{executor_quote}"
300
- else
301
- "msiexec /qn /log #{executor_quote}%CHEF_CLIENT_MSI_LOG_PATH%#{executor_quote} /i #{executor_quote}%LOCAL_DESTINATION_MSI_PATH%#{executor_quote}"
302
- end
303
- end
304
-
305
- # Returns a string for copying the trusted certificates on the workstation to the system being bootstrapped
306
- # This string should contain both the commands necessary to both create the files, as well as their content
307
- def trusted_certs_content
308
- content = ""
309
- if @chef_config[:trusted_certs_dir]
310
- Dir.glob(File.join(PathHelper.escape_glob(@chef_config[:trusted_certs_dir]), "*.{crt,pem}")).each do |cert|
311
- content << "> #{bootstrap_directory}/trusted_certs/#{File.basename(cert)} (\n" +
312
- escape_and_echo(IO.read(File.expand_path(cert))) + "\n)\n"
313
- end
314
- end
315
- content
316
- end
317
-
318
- def fallback_install_task_command
319
- # This command will be executed by schtasks.exe in the batch
320
- # code below. To handle tasks that contain arguments that
321
- # need to be double quoted, schtasks allows the use of single
322
- # quotes that will later be converted to double quotes
323
- command = install_command('\'')
324
- <<-EOH
325
- @set MSIERRORCODE=!ERRORLEVEL!
326
- @if ERRORLEVEL 1 (
327
- @echo WARNING: Failed to install Chef Client MSI package in remote context with status code !MSIERRORCODE!.
328
- @echo WARNING: This may be due to a defect in operating system update KB2918614: http://support.microsoft.com/kb/2918614
329
- @set OLDLOGLOCATION="%CHEF_CLIENT_MSI_LOG_PATH%-fail.log"
330
- @move "%CHEF_CLIENT_MSI_LOG_PATH%" "!OLDLOGLOCATION!" > NUL
331
- @echo WARNING: Saving installation log of failure at !OLDLOGLOCATION!
332
- @echo WARNING: Retrying installation with local context...
333
- @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\"
334
-
335
- @if ERRORLEVEL 1 (
336
- @echo ERROR: Failed to create Chef Client installation scheduled task with status code !ERRORLEVEL! > "&2"
337
- ) else (
338
- @echo Successfully created scheduled task to install Chef Client.
339
- @schtasks /run /tn chefclientbootstraptask
340
- @if ERRORLEVEL 1 (
341
- @echo ERROR: Failed to execut Chef Client installation scheduled task with status code !ERRORLEVEL!. > "&2"
342
- ) else (
343
- @echo Successfully started Chef Client installation scheduled task.
344
- @echo Waiting for installation to complete -- this may take a few minutes...
345
- waitfor chefclientinstalldone /t 600
346
- if ERRORLEVEL 1 (
347
- @echo ERROR: Timed out waiting for Chef Client package to install
348
- ) else (
349
- @echo Finished waiting for Chef Client package to install.
350
- )
351
- @schtasks /delete /f /tn chefclientbootstraptask > NUL
352
- )
353
- )
354
- ) else (
355
- @echo Successfully installed Chef Client package.
356
- )
357
- EOH
358
- end
359
- end
360
- end
361
- end
362
- end
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, 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/core/bootstrap_context'
20
+
21
+ # Chef::Util::PathHelper in Chef 11 is a bit juvenile still
22
+ require 'knife-windows/path_helper'
23
+ # require 'chef/util/path_helper'
24
+
25
+
26
+ class Chef
27
+ class Knife
28
+ module Core
29
+ # Instances of BootstrapContext are the context objects (i.e., +self+) for
30
+ # bootstrap templates. For backwards compatability, they +must+ set the
31
+ # following instance variables:
32
+ # * @config - a hash of knife's config values
33
+ # * @run_list - the run list for the node to boostrap
34
+ #
35
+ class WindowsBootstrapContext < BootstrapContext
36
+ PathHelper = ::Knife::Windows::PathHelper
37
+
38
+ attr_accessor :client_pem
39
+
40
+ def initialize(config, run_list, chef_config, secret=nil)
41
+ @config = config
42
+ @run_list = run_list
43
+ @chef_config = chef_config
44
+ @secret = secret
45
+ # Compatibility with Chef 12 and Chef 11 versions
46
+ begin
47
+ # Pass along the secret parameter for Chef 12
48
+ super(config, run_list, chef_config, secret)
49
+ rescue ArgumentError
50
+ # The Chef 11 base class only has parameters for initialize
51
+ super(config, run_list, chef_config)
52
+ end
53
+ end
54
+
55
+ def validation_key
56
+ if File.exist?(File.expand_path(@chef_config[:validation_key]))
57
+ IO.read(File.expand_path(@chef_config[:validation_key]))
58
+ else
59
+ false
60
+ end
61
+ end
62
+
63
+ def secret
64
+ escape_and_echo(@config[:secret])
65
+ end
66
+
67
+ def trusted_certs_script
68
+ @trusted_certs_script ||= trusted_certs_content
69
+ end
70
+
71
+ def config_content
72
+ client_rb = <<-CONFIG
73
+ log_level :info
74
+ log_location STDOUT
75
+
76
+ chef_server_url "#{@chef_config[:chef_server_url]}"
77
+ validation_client_name "#{@chef_config[:validation_client_name]}"
78
+
79
+ file_cache_path "c:/chef/cache"
80
+ file_backup_path "c:/chef/backup"
81
+ cache_options ({:path => "c:/chef/cache/checksums", :skip_expires => true})
82
+
83
+ CONFIG
84
+ if @config[:chef_node_name]
85
+ client_rb << %Q{node_name "#{@config[:chef_node_name]}"\n}
86
+ else
87
+ client_rb << "# Using default node name (fqdn)\n"
88
+ end
89
+
90
+ # We configure :verify_api_cert only when it's overridden on the CLI
91
+ # or when specified in the knife config.
92
+ if !@config[:node_verify_api_cert].nil? || knife_config.has_key?(:verify_api_cert)
93
+ value = @config[:node_verify_api_cert].nil? ? knife_config[:verify_api_cert] : @config[:node_verify_api_cert]
94
+ client_rb << %Q{verify_api_cert #{value}\n}
95
+ end
96
+
97
+ # We configure :ssl_verify_mode only when it's overridden on the CLI
98
+ # or when specified in the knife config.
99
+ if @config[:node_ssl_verify_mode] || knife_config.has_key?(:ssl_verify_mode)
100
+ value = case @config[:node_ssl_verify_mode]
101
+ when "peer"
102
+ :verify_peer
103
+ when "none"
104
+ :verify_none
105
+ when nil
106
+ knife_config[:ssl_verify_mode]
107
+ else
108
+ nil
109
+ end
110
+
111
+ if value
112
+ client_rb << %Q{ssl_verify_mode :#{value}\n}
113
+ end
114
+ end
115
+
116
+ if @config[:ssl_verify_mode]
117
+ client_rb << %Q{ssl_verify_mode :#{knife_config[:ssl_verify_mode]}\n}
118
+ end
119
+
120
+ if knife_config[:bootstrap_proxy]
121
+ client_rb << "\n"
122
+ client_rb << %Q{http_proxy "#{knife_config[:bootstrap_proxy]}"\n}
123
+ client_rb << %Q{https_proxy "#{knife_config[:bootstrap_proxy]}"\n}
124
+ client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n} if knife_config[:bootstrap_no_proxy]
125
+ end
126
+
127
+ if knife_config[:bootstrap_no_proxy]
128
+ client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n}
129
+ end
130
+
131
+ if @config[:secret]
132
+ client_rb << %Q{encrypted_data_bag_secret "c:/chef/encrypted_data_bag_secret"\n}
133
+ end
134
+
135
+ unless trusted_certs_script.empty?
136
+ client_rb << %Q{trusted_certs_dir "c:/chef/trusted_certs"\n}
137
+ end
138
+
139
+ escape_and_echo(client_rb)
140
+ end
141
+
142
+ def start_chef
143
+ bootstrap_environment_option = bootstrap_environment.nil? ? '' : " -E #{bootstrap_environment}"
144
+ start_chef = "SET \"PATH=%PATH%;C:\\ruby\\bin;C:\\opscode\\chef\\bin;C:\\opscode\\chef\\embedded\\bin\"\n"
145
+ start_chef << "chef-client -c c:/chef/client.rb -j c:/chef/first-boot.json#{bootstrap_environment_option}\n"
146
+ end
147
+
148
+ def latest_current_windows_chef_version_query
149
+ installer_version_string = nil
150
+ if @config[:prerelease]
151
+ installer_version_string = "&prerelease=true"
152
+ else
153
+ chef_version_string = if knife_config[:bootstrap_version]
154
+ knife_config[:bootstrap_version]
155
+ else
156
+ Chef::VERSION.split(".").first
157
+ end
158
+
159
+ installer_version_string = "&v=#{chef_version_string}"
160
+
161
+ # If bootstrapping a pre-release version add the prerelease query string
162
+ if chef_version_string.split(".").length > 3
163
+ installer_version_string << "&prerelease=true"
164
+ end
165
+ end
166
+
167
+ installer_version_string
168
+ end
169
+
170
+ def win_wget
171
+ # I tried my best to figure out how to properly url decode and switch / to \
172
+ # but this is VBScript - so I don't really care that badly.
173
+ win_wget = <<-WGET
174
+ url = WScript.Arguments.Named("url")
175
+ path = WScript.Arguments.Named("path")
176
+ proxy = null
177
+ '* Vaguely attempt to handle file:// scheme urls by url unescaping and switching all
178
+ '* / into \. Also assume that file:/// is a local absolute path and that file://<foo>
179
+ '* is possibly a network file path.
180
+ If InStr(url, "file://") = 1 Then
181
+ url = Unescape(url)
182
+ If InStr(url, "file:///") = 1 Then
183
+ sourcePath = Mid(url, Len("file:///") + 1)
184
+ Else
185
+ sourcePath = Mid(url, Len("file:") + 1)
186
+ End If
187
+ sourcePath = Replace(sourcePath, "/", "\\")
188
+
189
+ Set objFSO = CreateObject("Scripting.FileSystemObject")
190
+ If objFSO.Fileexists(path) Then objFSO.DeleteFile path
191
+ objFSO.CopyFile sourcePath, path, true
192
+ Set objFSO = Nothing
193
+
194
+ Else
195
+ Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP")
196
+ Set wshShell = CreateObject( "WScript.Shell" )
197
+ Set objUserVariables = wshShell.Environment("USER")
198
+
199
+ rem http proxy is optional
200
+ rem attempt to read from HTTP_PROXY env var first
201
+ On Error Resume Next
202
+
203
+ If NOT (objUserVariables("HTTP_PROXY") = "") Then
204
+ proxy = objUserVariables("HTTP_PROXY")
205
+
206
+ rem fall back to named arg
207
+ ElseIf NOT (WScript.Arguments.Named("proxy") = "") Then
208
+ proxy = WScript.Arguments.Named("proxy")
209
+ End If
210
+
211
+ If NOT isNull(proxy) Then
212
+ rem setProxy method is only available on ServerXMLHTTP 6.0+
213
+ Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP.6.0")
214
+ objXMLHTTP.setProxy 2, proxy
215
+ End If
216
+
217
+ On Error Goto 0
218
+
219
+ objXMLHTTP.open "GET", url, false
220
+ objXMLHTTP.send()
221
+ If objXMLHTTP.Status = 200 Then
222
+ Set objADOStream = CreateObject("ADODB.Stream")
223
+ objADOStream.Open
224
+ objADOStream.Type = 1
225
+ objADOStream.Write objXMLHTTP.ResponseBody
226
+ objADOStream.Position = 0
227
+ Set objFSO = Createobject("Scripting.FileSystemObject")
228
+ If objFSO.Fileexists(path) Then objFSO.DeleteFile path
229
+ Set objFSO = Nothing
230
+ objADOStream.SaveToFile path
231
+ objADOStream.Close
232
+ Set objADOStream = Nothing
233
+ End If
234
+ Set objXMLHTTP = Nothing
235
+ End If
236
+ WGET
237
+ escape_and_echo(win_wget)
238
+ end
239
+
240
+ def win_wget_ps
241
+ win_wget_ps = <<-WGET_PS
242
+ param(
243
+ [String] $remoteUrl,
244
+ [String] $localPath
245
+ )
246
+
247
+ $webClient = new-object System.Net.WebClient;
248
+
249
+ $webClient.DownloadFile($remoteUrl, $localPath);
250
+ WGET_PS
251
+
252
+ escape_and_echo(win_wget_ps)
253
+ end
254
+
255
+ def install_chef
256
+ # The normal install command uses regular double quotes in
257
+ # the install command, so request such a string from install_command
258
+ install_chef = install_command('"') + "\n" + fallback_install_task_command
259
+ end
260
+
261
+ def bootstrap_directory
262
+ bootstrap_directory = "C:\\chef"
263
+ end
264
+
265
+ def local_download_path
266
+ local_download_path = "%TEMP%\\chef-client-latest.msi"
267
+ end
268
+
269
+ def msi_url(machine_os=nil, machine_arch=nil, download_context=nil)
270
+ # The default msi path has a number of url query parameters - we attempt to substitute
271
+ # such parameters in as long as they are provided by the template.
272
+
273
+ if @config[:msi_url].nil? || @config[:msi_url].empty?
274
+ url = "https://www.chef.io/chef/download?p=windows"
275
+ url += "&pv=#{machine_os}" unless machine_os.nil?
276
+ url += "&m=#{machine_arch}" unless machine_arch.nil?
277
+ url += "&DownloadContext=#{download_context}" unless download_context.nil?
278
+ url += latest_current_windows_chef_version_query
279
+ else
280
+ @config[:msi_url]
281
+ end
282
+ end
283
+
284
+ def first_boot
285
+ escape_and_echo(super.to_json)
286
+ end
287
+
288
+ # escape WIN BATCH special chars
289
+ # and prefixes each line with an
290
+ # echo
291
+ def escape_and_echo(file_contents)
292
+ file_contents.gsub(/^(.*)$/, 'echo.\1').gsub(/([(<|>)^])/, '^\1')
293
+ end
294
+
295
+ private
296
+
297
+ def install_command(executor_quote)
298
+ if @config[:install_as_service]
299
+ "msiexec /qn /log #{executor_quote}%CHEF_CLIENT_MSI_LOG_PATH%#{executor_quote} /i #{executor_quote}%LOCAL_DESTINATION_MSI_PATH%#{executor_quote} ADDLOCAL=#{executor_quote}ChefClientFeature,ChefServiceFeature#{executor_quote}"
300
+ else
301
+ "msiexec /qn /log #{executor_quote}%CHEF_CLIENT_MSI_LOG_PATH%#{executor_quote} /i #{executor_quote}%LOCAL_DESTINATION_MSI_PATH%#{executor_quote}"
302
+ end
303
+ end
304
+
305
+ # Returns a string for copying the trusted certificates on the workstation to the system being bootstrapped
306
+ # This string should contain both the commands necessary to both create the files, as well as their content
307
+ def trusted_certs_content
308
+ content = ""
309
+ if @chef_config[:trusted_certs_dir]
310
+ Dir.glob(File.join(PathHelper.escape_glob(@chef_config[:trusted_certs_dir]), "*.{crt,pem}")).each do |cert|
311
+ content << "> #{bootstrap_directory}/trusted_certs/#{File.basename(cert)} (\n" +
312
+ escape_and_echo(IO.read(File.expand_path(cert))) + "\n)\n"
313
+ end
314
+ end
315
+ content
316
+ end
317
+
318
+ def fallback_install_task_command
319
+ # This command will be executed by schtasks.exe in the batch
320
+ # code below. To handle tasks that contain arguments that
321
+ # need to be double quoted, schtasks allows the use of single
322
+ # quotes that will later be converted to double quotes
323
+ command = install_command('\'')
324
+ <<-EOH
325
+ @set MSIERRORCODE=!ERRORLEVEL!
326
+ @if ERRORLEVEL 1 (
327
+ @echo WARNING: Failed to install Chef Client MSI package in remote context with status code !MSIERRORCODE!.
328
+ @echo WARNING: This may be due to a defect in operating system update KB2918614: http://support.microsoft.com/kb/2918614
329
+ @set OLDLOGLOCATION="%CHEF_CLIENT_MSI_LOG_PATH%-fail.log"
330
+ @move "%CHEF_CLIENT_MSI_LOG_PATH%" "!OLDLOGLOCATION!" > NUL
331
+ @echo WARNING: Saving installation log of failure at !OLDLOGLOCATION!
332
+ @echo WARNING: Retrying installation with local context...
333
+ @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\"
334
+
335
+ @if ERRORLEVEL 1 (
336
+ @echo ERROR: Failed to create Chef Client installation scheduled task with status code !ERRORLEVEL! > "&2"
337
+ ) else (
338
+ @echo Successfully created scheduled task to install Chef Client.
339
+ @schtasks /run /tn chefclientbootstraptask
340
+ @if ERRORLEVEL 1 (
341
+ @echo ERROR: Failed to execut Chef Client installation scheduled task with status code !ERRORLEVEL!. > "&2"
342
+ ) else (
343
+ @echo Successfully started Chef Client installation scheduled task.
344
+ @echo Waiting for installation to complete -- this may take a few minutes...
345
+ waitfor chefclientinstalldone /t 600
346
+ if ERRORLEVEL 1 (
347
+ @echo ERROR: Timed out waiting for Chef Client package to install
348
+ ) else (
349
+ @echo Finished waiting for Chef Client package to install.
350
+ )
351
+ @schtasks /delete /f /tn chefclientbootstraptask > NUL
352
+ )
353
+ )
354
+ ) else (
355
+ @echo Successfully installed Chef Client package.
356
+ )
357
+ EOH
358
+ end
359
+ end
360
+ end
361
+ end
362
+ end