knife-windows 0.8.2 → 0.8.3.rc.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,102 +1,102 @@
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/bootstrap'
23
-
24
- class Chef
25
- class Knife
26
- class BootstrapWindowsWinrm < Bootstrap
27
-
28
- include Chef::Knife::BootstrapWindowsBase
29
- include Chef::Knife::WinrmBase
30
-
31
- deps do
32
- require 'chef/knife/core/windows_bootstrap_context'
33
- require 'chef/json_compat'
34
- require 'tempfile'
35
- Chef::Knife::Winrm.load_deps
36
- end
37
-
38
- banner "knife bootstrap windows winrm FQDN (options)"
39
-
40
- def run
41
- bootstrap
42
- end
43
-
44
-
45
- def run_command(command = '')
46
- winrm = Chef::Knife::Winrm.new
47
- winrm.name_args = [ server_name, command ]
48
- winrm.config[:winrm_user] = locate_config_value(:winrm_user)
49
- winrm.config[:winrm_password] = locate_config_value(:winrm_password)
50
- winrm.config[:winrm_transport] = locate_config_value(:winrm_transport)
51
- winrm.config[:kerberos_keytab_file] = Chef::Config[:knife][:kerberos_keytab_file] if Chef::Config[:knife][:kerberos_keytab_file]
52
- winrm.config[:kerberos_realm] = Chef::Config[:knife][:kerberos_realm] if Chef::Config[:knife][:kerberos_realm]
53
- winrm.config[:kerberos_service] = Chef::Config[:knife][:kerberos_service] if Chef::Config[:knife][:kerberos_service]
54
- winrm.config[:ca_trust_file] = Chef::Config[:knife][:ca_trust_file] if Chef::Config[:knife][:ca_trust_file]
55
- winrm.config[:manual] = true
56
- winrm.config[:winrm_port] = locate_config_value(:winrm_port)
57
- winrm.config[:suppress_auth_failure] = true
58
-
59
- #If you turn off the return flag, then winrm.run won't atually check and
60
- #return the error
61
- #codes. Otherwise, it ignores the return value of the server call.
62
- winrm.config[:returns] = "0"
63
- winrm.run
64
- end
65
-
66
- protected
67
-
68
- def wait_for_remote_response(wait_max_minutes)
69
- wait_max_seconds = wait_max_minutes * 60
70
- retry_interval_seconds = 10
71
- retries_left = wait_max_seconds / retry_interval_seconds
72
- print(ui.color("\nWaiting for remote response before bootstrap", :magenta))
73
- wait_start_time = Time.now
74
- begin
75
- print(".")
76
- # Return status of the command is non-zero, typically nil,
77
- # for our simple echo command in cases where run_command
78
- # swallows the exception, such as 401's. Treat such cases
79
- # the same as the case where we encounter an exception.
80
- status = run_command("echo . & echo Response received.")
81
- raise RuntimeError, 'Command execution failed.' if status != 0
82
- ui.info(ui.color("Remote node responded after #{elapsed_time_in_minutes(wait_start_time)} minutes.", :magenta))
83
- return
84
- rescue
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
- raise
89
- end
90
- print '.'
91
- sleep retry_interval_seconds
92
- retry
93
- end
94
- end
95
-
96
- def elapsed_time_in_minutes(start_time)
97
- ((Time.now - start_time) / 60).round(2)
98
- end
99
- end
100
- end
101
- end
102
-
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/bootstrap'
23
+
24
+ class Chef
25
+ class Knife
26
+ class BootstrapWindowsWinrm < Bootstrap
27
+
28
+ include Chef::Knife::BootstrapWindowsBase
29
+ include Chef::Knife::WinrmBase
30
+
31
+ deps do
32
+ require 'chef/knife/core/windows_bootstrap_context'
33
+ require 'chef/json_compat'
34
+ require 'tempfile'
35
+ Chef::Knife::Winrm.load_deps
36
+ end
37
+
38
+ banner "knife bootstrap windows winrm FQDN (options)"
39
+
40
+ def run
41
+ bootstrap
42
+ end
43
+
44
+
45
+ def run_command(command = '')
46
+ winrm = Chef::Knife::Winrm.new
47
+ winrm.name_args = [ server_name, command ]
48
+ winrm.config[:winrm_user] = locate_config_value(:winrm_user)
49
+ winrm.config[:winrm_password] = locate_config_value(:winrm_password)
50
+ winrm.config[:winrm_transport] = locate_config_value(:winrm_transport)
51
+ winrm.config[:kerberos_keytab_file] = Chef::Config[:knife][:kerberos_keytab_file] if Chef::Config[:knife][:kerberos_keytab_file]
52
+ winrm.config[:kerberos_realm] = Chef::Config[:knife][:kerberos_realm] if Chef::Config[:knife][:kerberos_realm]
53
+ winrm.config[:kerberos_service] = Chef::Config[:knife][:kerberos_service] if Chef::Config[:knife][:kerberos_service]
54
+ winrm.config[:ca_trust_file] = Chef::Config[:knife][:ca_trust_file] if Chef::Config[:knife][:ca_trust_file]
55
+ winrm.config[:manual] = true
56
+ winrm.config[:winrm_port] = locate_config_value(:winrm_port)
57
+ winrm.config[:suppress_auth_failure] = true
58
+
59
+ #If you turn off the return flag, then winrm.run won't atually check and
60
+ #return the error
61
+ #codes. Otherwise, it ignores the return value of the server call.
62
+ winrm.config[:returns] = "0"
63
+ winrm.run
64
+ end
65
+
66
+ protected
67
+
68
+ def wait_for_remote_response(wait_max_minutes)
69
+ wait_max_seconds = wait_max_minutes * 60
70
+ retry_interval_seconds = 10
71
+ retries_left = wait_max_seconds / retry_interval_seconds
72
+ print(ui.color("\nWaiting for remote response before bootstrap", :magenta))
73
+ wait_start_time = Time.now
74
+ begin
75
+ print(".")
76
+ # Return status of the command is non-zero, typically nil,
77
+ # for our simple echo command in cases where run_command
78
+ # swallows the exception, such as 401's. Treat such cases
79
+ # the same as the case where we encounter an exception.
80
+ status = run_command("echo . & echo Response received.")
81
+ raise RuntimeError, 'Command execution failed.' if status != 0
82
+ ui.info(ui.color("Remote node responded after #{elapsed_time_in_minutes(wait_start_time)} minutes.", :magenta))
83
+ return
84
+ rescue
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
+ raise
89
+ end
90
+ print '.'
91
+ sleep retry_interval_seconds
92
+ retry
93
+ end
94
+ end
95
+
96
+ def elapsed_time_in_minutes(start_time)
97
+ ((Time.now - start_time) / 60).round(2)
98
+ end
99
+ end
100
+ end
101
+ end
102
+
@@ -1,227 +1,249 @@
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
- class Chef
22
- class Knife
23
- module Core
24
- # Instances of BootstrapContext are the context objects (i.e., +self+) for
25
- # bootstrap templates. For backwards compatability, they +must+ set the
26
- # following instance variables:
27
- # * @config - a hash of knife's config values
28
- # * @run_list - the run list for the node to boostrap
29
- #
30
- class WindowsBootstrapContext < BootstrapContext
31
-
32
- def initialize(config, run_list, chef_config)
33
- @config = config
34
- @run_list = run_list
35
- @chef_config = chef_config
36
- super(config, run_list, chef_config)
37
- end
38
-
39
- def validation_key
40
- escape_and_echo(super)
41
- end
42
-
43
- def encrypted_data_bag_secret
44
- escape_and_echo(@config[:encrypted_data_bag_secret])
45
- end
46
-
47
- def config_content
48
- client_rb = <<-CONFIG
49
- log_level :info
50
- log_location STDOUT
51
-
52
- chef_server_url "#{@chef_config[:chef_server_url]}"
53
- validation_client_name "#{@chef_config[:validation_client_name]}"
54
- client_key "c:/chef/client.pem"
55
- validation_key "c:/chef/validation.pem"
56
-
57
- file_cache_path "c:/chef/cache"
58
- file_backup_path "c:/chef/backup"
59
- cache_options ({:path => "c:/chef/cache/checksums", :skip_expires => true})
60
-
61
- CONFIG
62
- if @config[:chef_node_name]
63
- client_rb << %Q{node_name "#{@config[:chef_node_name]}"\n}
64
- else
65
- client_rb << "# Using default node name (fqdn)\n"
66
- end
67
-
68
- if knife_config[:bootstrap_proxy]
69
- client_rb << "\n"
70
- client_rb << %Q{http_proxy "#{knife_config[:bootstrap_proxy]}"\n}
71
- client_rb << %Q{https_proxy "#{knife_config[:bootstrap_proxy]}"\n}
72
- client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n} if knife_config[:bootstrap_no_proxy]
73
- end
74
-
75
- if @config[:encrypted_data_bag_secret]
76
- client_rb << %Q{encrypted_data_bag_secret "c:/chef/encrypted_data_bag_secret"\n}
77
- end
78
-
79
- escape_and_echo(client_rb)
80
- end
81
-
82
- def start_chef
83
- start_chef = "SET \"PATH=%PATH%;C:\\ruby\\bin;C:\\opscode\\chef\\bin;C:\\opscode\\chef\\embedded\\bin\"\n"
84
- start_chef << "chef-client -c c:/chef/client.rb -j c:/chef/first-boot.json -E #{bootstrap_environment}\n"
85
- end
86
-
87
- def win_wget
88
- win_wget = <<-WGET
89
- url = WScript.Arguments.Named("url")
90
- path = WScript.Arguments.Named("path")
91
- proxy = null
92
- Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP")
93
- Set wshShell = CreateObject( "WScript.Shell" )
94
- Set objUserVariables = wshShell.Environment("USER")
95
-
96
- rem http proxy is optional
97
- rem attempt to read from HTTP_PROXY env var first
98
- On Error Resume Next
99
-
100
- If NOT (objUserVariables("HTTP_PROXY") = "") Then
101
- proxy = objUserVariables("HTTP_PROXY")
102
-
103
- rem fall back to named arg
104
- ElseIf NOT (WScript.Arguments.Named("proxy") = "") Then
105
- proxy = WScript.Arguments.Named("proxy")
106
- End If
107
-
108
- If NOT isNull(proxy) Then
109
- rem setProxy method is only available on ServerXMLHTTP 6.0+
110
- Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP.6.0")
111
- objXMLHTTP.setProxy 2, proxy
112
- End If
113
-
114
- On Error Goto 0
115
-
116
- objXMLHTTP.open "GET", url, false
117
- objXMLHTTP.send()
118
- If objXMLHTTP.Status = 200 Then
119
- Set objADOStream = CreateObject("ADODB.Stream")
120
- objADOStream.Open
121
- objADOStream.Type = 1
122
- objADOStream.Write objXMLHTTP.ResponseBody
123
- objADOStream.Position = 0
124
- Set objFSO = Createobject("Scripting.FileSystemObject")
125
- If objFSO.Fileexists(path) Then objFSO.DeleteFile path
126
- Set objFSO = Nothing
127
- objADOStream.SaveToFile path
128
- objADOStream.Close
129
- Set objADOStream = Nothing
130
- End if
131
- Set objXMLHTTP = Nothing
132
- WGET
133
- escape_and_echo(win_wget)
134
- end
135
-
136
- def win_wget_ps
137
- win_wget_ps = <<-WGET_PS
138
- param(
139
- [String] $remoteUrl,
140
- [String] $localPath
141
- )
142
-
143
- $webClient = new-object System.Net.WebClient;
144
-
145
- $webClient.DownloadFile($remoteUrl, $localPath);
146
- WGET_PS
147
-
148
- escape_and_echo(win_wget_ps)
149
- end
150
-
151
- def install_chef
152
- # The normal install command uses regular double quotes in
153
- # the install command, so request such a string from install_command
154
- install_chef = install_command('"') + "\n" + fallback_install_task_command
155
- end
156
-
157
- def bootstrap_directory
158
- bootstrap_directory = "C:\\chef"
159
- end
160
-
161
- def local_download_path
162
- local_download_path = "%TEMP%\\chef-client-latest.msi"
163
- end
164
-
165
- def first_boot
166
- first_boot_attributes_and_run_list = (@config[:first_boot_attributes] || {}).merge(:run_list => @run_list)
167
- escape_and_echo(first_boot_attributes_and_run_list.to_json)
168
- end
169
-
170
- # escape WIN BATCH special chars
171
- # and prefixes each line with an
172
- # echo
173
- def escape_and_echo(file_contents)
174
- file_contents.gsub(/^(.*)$/, 'echo.\1').gsub(/([(<|>)^])/, '^\1')
175
- end
176
-
177
- private
178
-
179
- def install_command(executor_quote)
180
- "msiexec /qn /log #{executor_quote}%CHEF_CLIENT_MSI_LOG_PATH%#{executor_quote} /i #{executor_quote}%LOCAL_DESTINATION_MSI_PATH%#{executor_quote}"
181
- end
182
-
183
- def fallback_install_task_command
184
- # This command will be executed by schtasks.exe in the batch
185
- # code below. To handle tasks that contain arguments that
186
- # need to be double quoted, schtasks allows the use of single
187
- # quotes that will later be converted to double quotes
188
- command = install_command('\'')
189
- <<-EOH
190
- @set MSIERRORCODE=!ERRORLEVEL!
191
- @if ERRORLEVEL 1 (
192
- @echo WARNING: Failed to install Chef Client MSI package in remote context with status code !MSIERRORCODE!.
193
- @echo WARNING: This may be due to a defect in operating system update KB2918614: http://support.microsoft.com/kb/2918614
194
- @set OLDLOGLOCATION="%CHEF_CLIENT_MSI_LOG_PATH%-fail.log"
195
- @move "%CHEF_CLIENT_MSI_LOG_PATH%" "!OLDLOGLOCATION!" > NUL
196
- @echo WARNING: Saving installation log of failure at !OLDLOGLOCATION!
197
- @echo WARNING: Retrying installation with local context...
198
- @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\"
199
-
200
- @if ERRORLEVEL 1 (
201
- @echo ERROR: Failed to create Chef Client installation scheduled task with status code !ERRORLEVEL! > "&2"
202
- ) else (
203
- @echo Successfully created scheduled task to install Chef Client.
204
- @schtasks /run /tn chefclientbootstraptask
205
- @if ERRORLEVEL 1 (
206
- @echo ERROR: Failed to execut Chef Client installation scheduled task with status code !ERRORLEVEL!. > "&2"
207
- ) else (
208
- @echo Successfully started Chef Client installation scheduled task.
209
- @echo Waiting for installation to complete -- this may take a few minutes...
210
- waitfor chefclientinstalldone /t 600
211
- if ERRORLEVEL 1 (
212
- @echo ERROR: Timed out waiting for Chef Client package to install
213
- ) else (
214
- @echo Finished waiting for Chef Client package to install.
215
- )
216
- @schtasks /delete /f /tn chefclientbootstraptask > NUL
217
- )
218
- )
219
- ) else (
220
- @echo Successfully installed Chef Client package.
221
- )
222
- EOH
223
- end
224
- end
225
- end
226
- end
227
- 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
+ class Chef
22
+ class Knife
23
+ module Core
24
+ # Instances of BootstrapContext are the context objects (i.e., +self+) for
25
+ # bootstrap templates. For backwards compatability, they +must+ set the
26
+ # following instance variables:
27
+ # * @config - a hash of knife's config values
28
+ # * @run_list - the run list for the node to boostrap
29
+ #
30
+ class WindowsBootstrapContext < BootstrapContext
31
+
32
+ def initialize(config, run_list, chef_config)
33
+ @config = config
34
+ @run_list = run_list
35
+ @chef_config = chef_config
36
+ super(config, run_list, chef_config)
37
+ end
38
+
39
+ def validation_key
40
+ escape_and_echo(super)
41
+ end
42
+
43
+ def encrypted_data_bag_secret
44
+ escape_and_echo(@config[:encrypted_data_bag_secret])
45
+ end
46
+
47
+ def config_content
48
+ client_rb = <<-CONFIG
49
+ log_level :info
50
+ log_location STDOUT
51
+
52
+ chef_server_url "#{@chef_config[:chef_server_url]}"
53
+ validation_client_name "#{@chef_config[:validation_client_name]}"
54
+ client_key "c:/chef/client.pem"
55
+ validation_key "c:/chef/validation.pem"
56
+
57
+ file_cache_path "c:/chef/cache"
58
+ file_backup_path "c:/chef/backup"
59
+ cache_options ({:path => "c:/chef/cache/checksums", :skip_expires => true})
60
+
61
+ CONFIG
62
+ if @config[:chef_node_name]
63
+ client_rb << %Q{node_name "#{@config[:chef_node_name]}"\n}
64
+ else
65
+ client_rb << "# Using default node name (fqdn)\n"
66
+ end
67
+
68
+ if knife_config[:bootstrap_proxy]
69
+ client_rb << "\n"
70
+ client_rb << %Q{http_proxy "#{knife_config[:bootstrap_proxy]}"\n}
71
+ client_rb << %Q{https_proxy "#{knife_config[:bootstrap_proxy]}"\n}
72
+ client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n} if knife_config[:bootstrap_no_proxy]
73
+ end
74
+
75
+ if @config[:encrypted_data_bag_secret]
76
+ client_rb << %Q{encrypted_data_bag_secret "c:/chef/encrypted_data_bag_secret"\n}
77
+ end
78
+
79
+ escape_and_echo(client_rb)
80
+ end
81
+
82
+ def start_chef
83
+ start_chef = "SET \"PATH=%PATH%;C:\\ruby\\bin;C:\\opscode\\chef\\bin;C:\\opscode\\chef\\embedded\\bin\"\n"
84
+ start_chef << "chef-client -c c:/chef/client.rb -j c:/chef/first-boot.json -E #{bootstrap_environment}\n"
85
+ end
86
+
87
+ def latest_current_windows_chef_version_query
88
+ installer_version_string = nil
89
+ if @config[:prerelease]
90
+ installer_version_string = "&prerelease=true"
91
+ else
92
+ chef_version_string = if knife_config[:bootstrap_version]
93
+ knife_config[:bootstrap_version]
94
+ else
95
+ Chef::VERSION.split(".").first
96
+ end
97
+
98
+ installer_version_string = "&v=#{chef_version_string}"
99
+
100
+ # If bootstrapping a pre-release version add the prerelease query string
101
+ if chef_version_string.split(".").length > 3
102
+ installer_version_string << "&prerelease=true"
103
+ end
104
+ end
105
+
106
+ installer_version_string
107
+ end
108
+
109
+ def win_wget
110
+ win_wget = <<-WGET
111
+ url = WScript.Arguments.Named("url")
112
+ path = WScript.Arguments.Named("path")
113
+ proxy = null
114
+ Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP")
115
+ Set wshShell = CreateObject( "WScript.Shell" )
116
+ Set objUserVariables = wshShell.Environment("USER")
117
+
118
+ rem http proxy is optional
119
+ rem attempt to read from HTTP_PROXY env var first
120
+ On Error Resume Next
121
+
122
+ If NOT (objUserVariables("HTTP_PROXY") = "") Then
123
+ proxy = objUserVariables("HTTP_PROXY")
124
+
125
+ rem fall back to named arg
126
+ ElseIf NOT (WScript.Arguments.Named("proxy") = "") Then
127
+ proxy = WScript.Arguments.Named("proxy")
128
+ End If
129
+
130
+ If NOT isNull(proxy) Then
131
+ rem setProxy method is only available on ServerXMLHTTP 6.0+
132
+ Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP.6.0")
133
+ objXMLHTTP.setProxy 2, proxy
134
+ End If
135
+
136
+ On Error Goto 0
137
+
138
+ objXMLHTTP.open "GET", url, false
139
+ objXMLHTTP.send()
140
+ If objXMLHTTP.Status = 200 Then
141
+ Set objADOStream = CreateObject("ADODB.Stream")
142
+ objADOStream.Open
143
+ objADOStream.Type = 1
144
+ objADOStream.Write objXMLHTTP.ResponseBody
145
+ objADOStream.Position = 0
146
+ Set objFSO = Createobject("Scripting.FileSystemObject")
147
+ If objFSO.Fileexists(path) Then objFSO.DeleteFile path
148
+ Set objFSO = Nothing
149
+ objADOStream.SaveToFile path
150
+ objADOStream.Close
151
+ Set objADOStream = Nothing
152
+ End if
153
+ Set objXMLHTTP = Nothing
154
+ WGET
155
+ escape_and_echo(win_wget)
156
+ end
157
+
158
+ def win_wget_ps
159
+ win_wget_ps = <<-WGET_PS
160
+ param(
161
+ [String] $remoteUrl,
162
+ [String] $localPath
163
+ )
164
+
165
+ $webClient = new-object System.Net.WebClient;
166
+
167
+ $webClient.DownloadFile($remoteUrl, $localPath);
168
+ WGET_PS
169
+
170
+ escape_and_echo(win_wget_ps)
171
+ end
172
+
173
+ def install_chef
174
+ # The normal install command uses regular double quotes in
175
+ # the install command, so request such a string from install_command
176
+ install_chef = install_command('"') + "\n" + fallback_install_task_command
177
+ end
178
+
179
+ def bootstrap_directory
180
+ bootstrap_directory = "C:\\chef"
181
+ end
182
+
183
+ def local_download_path
184
+ local_download_path = "%TEMP%\\chef-client-latest.msi"
185
+ end
186
+
187
+ def first_boot
188
+ first_boot_attributes_and_run_list = (@config[:first_boot_attributes] || {}).merge(:run_list => @run_list)
189
+ escape_and_echo(first_boot_attributes_and_run_list.to_json)
190
+ end
191
+
192
+ # escape WIN BATCH special chars
193
+ # and prefixes each line with an
194
+ # echo
195
+ def escape_and_echo(file_contents)
196
+ file_contents.gsub(/^(.*)$/, 'echo.\1').gsub(/([(<|>)^])/, '^\1')
197
+ end
198
+
199
+ private
200
+
201
+ def install_command(executor_quote)
202
+ "msiexec /qn /log #{executor_quote}%CHEF_CLIENT_MSI_LOG_PATH%#{executor_quote} /i #{executor_quote}%LOCAL_DESTINATION_MSI_PATH%#{executor_quote}"
203
+ end
204
+
205
+ def fallback_install_task_command
206
+ # This command will be executed by schtasks.exe in the batch
207
+ # code below. To handle tasks that contain arguments that
208
+ # need to be double quoted, schtasks allows the use of single
209
+ # quotes that will later be converted to double quotes
210
+ command = install_command('\'')
211
+ <<-EOH
212
+ @set MSIERRORCODE=!ERRORLEVEL!
213
+ @if ERRORLEVEL 1 (
214
+ @echo WARNING: Failed to install Chef Client MSI package in remote context with status code !MSIERRORCODE!.
215
+ @echo WARNING: This may be due to a defect in operating system update KB2918614: http://support.microsoft.com/kb/2918614
216
+ @set OLDLOGLOCATION="%CHEF_CLIENT_MSI_LOG_PATH%-fail.log"
217
+ @move "%CHEF_CLIENT_MSI_LOG_PATH%" "!OLDLOGLOCATION!" > NUL
218
+ @echo WARNING: Saving installation log of failure at !OLDLOGLOCATION!
219
+ @echo WARNING: Retrying installation with local context...
220
+ @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\"
221
+
222
+ @if ERRORLEVEL 1 (
223
+ @echo ERROR: Failed to create Chef Client installation scheduled task with status code !ERRORLEVEL! > "&2"
224
+ ) else (
225
+ @echo Successfully created scheduled task to install Chef Client.
226
+ @schtasks /run /tn chefclientbootstraptask
227
+ @if ERRORLEVEL 1 (
228
+ @echo ERROR: Failed to execut Chef Client installation scheduled task with status code !ERRORLEVEL!. > "&2"
229
+ ) else (
230
+ @echo Successfully started Chef Client installation scheduled task.
231
+ @echo Waiting for installation to complete -- this may take a few minutes...
232
+ waitfor chefclientinstalldone /t 600
233
+ if ERRORLEVEL 1 (
234
+ @echo ERROR: Timed out waiting for Chef Client package to install
235
+ ) else (
236
+ @echo Finished waiting for Chef Client package to install.
237
+ )
238
+ @schtasks /delete /f /tn chefclientbootstraptask > NUL
239
+ )
240
+ )
241
+ ) else (
242
+ @echo Successfully installed Chef Client package.
243
+ )
244
+ EOH
245
+ end
246
+ end
247
+ end
248
+ end
249
+ end