knife-windows 0.8.5 → 0.8.6.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,307 +1,311 @@
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
- class Chef
26
- class Knife
27
- module Core
28
- # Instances of BootstrapContext are the context objects (i.e., +self+) for
29
- # bootstrap templates. For backwards compatability, they +must+ set the
30
- # following instance variables:
31
- # * @config - a hash of knife's config values
32
- # * @run_list - the run list for the node to boostrap
33
- #
34
- class WindowsBootstrapContext < BootstrapContext
35
- PathHelper = ::Knife::Windows::PathHelper
36
-
37
- def initialize(config, run_list, chef_config)
38
- @config = config
39
- @run_list = run_list
40
- @chef_config = chef_config
41
- super(config, run_list, chef_config)
42
- end
43
-
44
- def validation_key
45
- escape_and_echo(super)
46
- end
47
-
48
- def encrypted_data_bag_secret
49
- escape_and_echo(@config[:encrypted_data_bag_secret])
50
- end
51
-
52
- def trusted_certs
53
- @trusted_certs ||= trusted_certs_content
54
- end
55
-
56
- def config_content
57
- client_rb = <<-CONFIG
58
- log_level :info
59
- log_location STDOUT
60
-
61
- chef_server_url "#{@chef_config[:chef_server_url]}"
62
- validation_client_name "#{@chef_config[:validation_client_name]}"
63
- client_key "c:/chef/client.pem"
64
- validation_key "c:/chef/validation.pem"
65
-
66
- file_cache_path "c:/chef/cache"
67
- file_backup_path "c:/chef/backup"
68
- cache_options ({:path => "c:/chef/cache/checksums", :skip_expires => true})
69
-
70
- CONFIG
71
- if @config[:chef_node_name]
72
- client_rb << %Q{node_name "#{@config[:chef_node_name]}"\n}
73
- else
74
- client_rb << "# Using default node name (fqdn)\n"
75
- end
76
-
77
- # We configure :verify_api_cert only when it's overridden on the CLI
78
- # or when specified in the knife config.
79
- if !@config[:node_verify_api_cert].nil? || knife_config.has_key?(:verify_api_cert)
80
- value = @config[:node_verify_api_cert].nil? ? knife_config[:verify_api_cert] : @config[:node_verify_api_cert]
81
- client_rb << %Q{verify_api_cert #{value}\n}
82
- end
83
-
84
- # We configure :ssl_verify_mode only when it's overridden on the CLI
85
- # or when specified in the knife config.
86
- if @config[:node_ssl_verify_mode] || knife_config.has_key?(:ssl_verify_mode)
87
- value = case @config[:node_ssl_verify_mode]
88
- when "peer"
89
- :verify_peer
90
- when "none"
91
- :verify_none
92
- when nil
93
- knife_config[:ssl_verify_mode]
94
- else
95
- nil
96
- end
97
-
98
- if value
99
- client_rb << %Q{ssl_verify_mode :#{value}\n}
100
- end
101
- end
102
-
103
- if @config[:ssl_verify_mode]
104
- client_rb << %Q{ssl_verify_mode :#{knife_config[:ssl_verify_mode]}\n}
105
- end
106
-
107
- if knife_config[:bootstrap_proxy]
108
- client_rb << "\n"
109
- client_rb << %Q{http_proxy "#{knife_config[:bootstrap_proxy]}"\n}
110
- client_rb << %Q{https_proxy "#{knife_config[:bootstrap_proxy]}"\n}
111
- client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n} if knife_config[:bootstrap_no_proxy]
112
- end
113
-
114
- if knife_config[:bootstrap_no_proxy]
115
- client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n}
116
- end
117
-
118
- if @config[:encrypted_data_bag_secret]
119
- client_rb << %Q{encrypted_data_bag_secret "c:/chef/encrypted_data_bag_secret"\n}
120
- end
121
-
122
- unless trusted_certs.empty?
123
- client_rb << %Q{trusted_certs_dir "C:/chef/trusted_certs"\n}
124
- end
125
-
126
- escape_and_echo(client_rb)
127
- end
128
-
129
- def start_chef
130
- start_chef = "SET \"PATH=%PATH%;C:\\ruby\\bin;C:\\opscode\\chef\\bin;C:\\opscode\\chef\\embedded\\bin\"\n"
131
- start_chef << "chef-client -c c:/chef/client.rb -j c:/chef/first-boot.json -E #{bootstrap_environment}\n"
132
- end
133
-
134
- def latest_current_windows_chef_version_query
135
- installer_version_string = nil
136
- if @config[:prerelease]
137
- installer_version_string = "&prerelease=true"
138
- else
139
- chef_version_string = if knife_config[:bootstrap_version]
140
- knife_config[:bootstrap_version]
141
- else
142
- Chef::VERSION.split(".").first
143
- end
144
-
145
- installer_version_string = "&v=#{chef_version_string}"
146
-
147
- # If bootstrapping a pre-release version add the prerelease query string
148
- if chef_version_string.split(".").length > 3
149
- installer_version_string << "&prerelease=true"
150
- end
151
- end
152
-
153
- installer_version_string
154
- end
155
-
156
- def win_wget
157
- win_wget = <<-WGET
158
- url = WScript.Arguments.Named("url")
159
- path = WScript.Arguments.Named("path")
160
- proxy = null
161
- Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP")
162
- Set wshShell = CreateObject( "WScript.Shell" )
163
- Set objUserVariables = wshShell.Environment("USER")
164
-
165
- rem http proxy is optional
166
- rem attempt to read from HTTP_PROXY env var first
167
- On Error Resume Next
168
-
169
- If NOT (objUserVariables("HTTP_PROXY") = "") Then
170
- proxy = objUserVariables("HTTP_PROXY")
171
-
172
- rem fall back to named arg
173
- ElseIf NOT (WScript.Arguments.Named("proxy") = "") Then
174
- proxy = WScript.Arguments.Named("proxy")
175
- End If
176
-
177
- If NOT isNull(proxy) Then
178
- rem setProxy method is only available on ServerXMLHTTP 6.0+
179
- Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP.6.0")
180
- objXMLHTTP.setProxy 2, proxy
181
- End If
182
-
183
- On Error Goto 0
184
-
185
- objXMLHTTP.open "GET", url, false
186
- objXMLHTTP.send()
187
- If objXMLHTTP.Status = 200 Then
188
- Set objADOStream = CreateObject("ADODB.Stream")
189
- objADOStream.Open
190
- objADOStream.Type = 1
191
- objADOStream.Write objXMLHTTP.ResponseBody
192
- objADOStream.Position = 0
193
- Set objFSO = Createobject("Scripting.FileSystemObject")
194
- If objFSO.Fileexists(path) Then objFSO.DeleteFile path
195
- Set objFSO = Nothing
196
- objADOStream.SaveToFile path
197
- objADOStream.Close
198
- Set objADOStream = Nothing
199
- End if
200
- Set objXMLHTTP = Nothing
201
- WGET
202
- escape_and_echo(win_wget)
203
- end
204
-
205
- def win_wget_ps
206
- win_wget_ps = <<-WGET_PS
207
- param(
208
- [String] $remoteUrl,
209
- [String] $localPath
210
- )
211
-
212
- $webClient = new-object System.Net.WebClient;
213
-
214
- $webClient.DownloadFile($remoteUrl, $localPath);
215
- WGET_PS
216
-
217
- escape_and_echo(win_wget_ps)
218
- end
219
-
220
- def install_chef
221
- # The normal install command uses regular double quotes in
222
- # the install command, so request such a string from install_command
223
- install_chef = install_command('"') + "\n" + fallback_install_task_command
224
- end
225
-
226
- def bootstrap_directory
227
- bootstrap_directory = "C:\\chef"
228
- end
229
-
230
- def local_download_path
231
- local_download_path = "%TEMP%\\chef-client-latest.msi"
232
- end
233
-
234
- def first_boot
235
- first_boot_attributes_and_run_list = (@config[:first_boot_attributes] || {}).merge(:run_list => @run_list)
236
- escape_and_echo(first_boot_attributes_and_run_list.to_json)
237
- end
238
-
239
- # escape WIN BATCH special chars
240
- # and prefixes each line with an
241
- # echo
242
- def escape_and_echo(file_contents)
243
- file_contents.gsub(/^(.*)$/, 'echo.\1').gsub(/([(<|>)^])/, '^\1')
244
- end
245
-
246
- private
247
-
248
- def install_command(executor_quote)
249
- "msiexec /qn /log #{executor_quote}%CHEF_CLIENT_MSI_LOG_PATH%#{executor_quote} /i #{executor_quote}%LOCAL_DESTINATION_MSI_PATH%#{executor_quote}"
250
- end
251
-
252
- def trusted_certs_content
253
- content = ""
254
- if @chef_config[:trusted_certs_dir]
255
- Dir.glob(File.join(PathHelper.escape_glob(@chef_config[:trusted_certs_dir]), "*.{crt,pem}")).each do |cert|
256
- content << "> #{bootstrap_directory}/trusted_certs/#{File.basename(cert)} (\n" +
257
- escape_and_echo(IO.read(File.expand_path(cert))) + "\n)\n"
258
- end
259
- end
260
- content
261
- end
262
-
263
- def fallback_install_task_command
264
- # This command will be executed by schtasks.exe in the batch
265
- # code below. To handle tasks that contain arguments that
266
- # need to be double quoted, schtasks allows the use of single
267
- # quotes that will later be converted to double quotes
268
- command = install_command('\'')
269
- <<-EOH
270
- @set MSIERRORCODE=!ERRORLEVEL!
271
- @if ERRORLEVEL 1 (
272
- @echo WARNING: Failed to install Chef Client MSI package in remote context with status code !MSIERRORCODE!.
273
- @echo WARNING: This may be due to a defect in operating system update KB2918614: http://support.microsoft.com/kb/2918614
274
- @set OLDLOGLOCATION="%CHEF_CLIENT_MSI_LOG_PATH%-fail.log"
275
- @move "%CHEF_CLIENT_MSI_LOG_PATH%" "!OLDLOGLOCATION!" > NUL
276
- @echo WARNING: Saving installation log of failure at !OLDLOGLOCATION!
277
- @echo WARNING: Retrying installation with local context...
278
- @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\"
279
-
280
- @if ERRORLEVEL 1 (
281
- @echo ERROR: Failed to create Chef Client installation scheduled task with status code !ERRORLEVEL! > "&2"
282
- ) else (
283
- @echo Successfully created scheduled task to install Chef Client.
284
- @schtasks /run /tn chefclientbootstraptask
285
- @if ERRORLEVEL 1 (
286
- @echo ERROR: Failed to execut Chef Client installation scheduled task with status code !ERRORLEVEL!. > "&2"
287
- ) else (
288
- @echo Successfully started Chef Client installation scheduled task.
289
- @echo Waiting for installation to complete -- this may take a few minutes...
290
- waitfor chefclientinstalldone /t 600
291
- if ERRORLEVEL 1 (
292
- @echo ERROR: Timed out waiting for Chef Client package to install
293
- ) else (
294
- @echo Finished waiting for Chef Client package to install.
295
- )
296
- @schtasks /delete /f /tn chefclientbootstraptask > NUL
297
- )
298
- )
299
- ) else (
300
- @echo Successfully installed Chef Client package.
301
- )
302
- EOH
303
- end
304
- end
305
- end
306
- end
307
- 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
+ class Chef
26
+ class Knife
27
+ module Core
28
+ # Instances of BootstrapContext are the context objects (i.e., +self+) for
29
+ # bootstrap templates. For backwards compatability, they +must+ set the
30
+ # following instance variables:
31
+ # * @config - a hash of knife's config values
32
+ # * @run_list - the run list for the node to boostrap
33
+ #
34
+ class WindowsBootstrapContext < BootstrapContext
35
+ PathHelper = ::Knife::Windows::PathHelper
36
+
37
+ def initialize(config, run_list, chef_config)
38
+ @config = config
39
+ @run_list = run_list
40
+ @chef_config = chef_config
41
+ super(config, run_list, chef_config)
42
+ end
43
+
44
+ def validation_key
45
+ if super
46
+ escape_and_echo(super)
47
+ else
48
+ raise 'Knife-Windows < 1.0 does not support validatorless bootstraps'
49
+ end
50
+ end
51
+
52
+ def encrypted_data_bag_secret
53
+ escape_and_echo(@config[:encrypted_data_bag_secret])
54
+ end
55
+
56
+ def trusted_certs
57
+ @trusted_certs ||= trusted_certs_content
58
+ end
59
+
60
+ def config_content
61
+ client_rb = <<-CONFIG
62
+ log_level :info
63
+ log_location STDOUT
64
+
65
+ chef_server_url "#{@chef_config[:chef_server_url]}"
66
+ validation_client_name "#{@chef_config[:validation_client_name]}"
67
+ client_key "c:/chef/client.pem"
68
+ validation_key "c:/chef/validation.pem"
69
+
70
+ file_cache_path "c:/chef/cache"
71
+ file_backup_path "c:/chef/backup"
72
+ cache_options ({:path => "c:/chef/cache/checksums", :skip_expires => true})
73
+
74
+ CONFIG
75
+ if @config[:chef_node_name]
76
+ client_rb << %Q{node_name "#{@config[:chef_node_name]}"\n}
77
+ else
78
+ client_rb << "# Using default node name (fqdn)\n"
79
+ end
80
+
81
+ # We configure :verify_api_cert only when it's overridden on the CLI
82
+ # or when specified in the knife config.
83
+ if !@config[:node_verify_api_cert].nil? || knife_config.has_key?(:verify_api_cert)
84
+ value = @config[:node_verify_api_cert].nil? ? knife_config[:verify_api_cert] : @config[:node_verify_api_cert]
85
+ client_rb << %Q{verify_api_cert #{value}\n}
86
+ end
87
+
88
+ # We configure :ssl_verify_mode only when it's overridden on the CLI
89
+ # or when specified in the knife config.
90
+ if @config[:node_ssl_verify_mode] || knife_config.has_key?(:ssl_verify_mode)
91
+ value = case @config[:node_ssl_verify_mode]
92
+ when "peer"
93
+ :verify_peer
94
+ when "none"
95
+ :verify_none
96
+ when nil
97
+ knife_config[:ssl_verify_mode]
98
+ else
99
+ nil
100
+ end
101
+
102
+ if value
103
+ client_rb << %Q{ssl_verify_mode :#{value}\n}
104
+ end
105
+ end
106
+
107
+ if @config[:ssl_verify_mode]
108
+ client_rb << %Q{ssl_verify_mode :#{knife_config[:ssl_verify_mode]}\n}
109
+ end
110
+
111
+ if knife_config[:bootstrap_proxy]
112
+ client_rb << "\n"
113
+ client_rb << %Q{http_proxy "#{knife_config[:bootstrap_proxy]}"\n}
114
+ client_rb << %Q{https_proxy "#{knife_config[:bootstrap_proxy]}"\n}
115
+ client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n} if knife_config[:bootstrap_no_proxy]
116
+ end
117
+
118
+ if knife_config[:bootstrap_no_proxy]
119
+ client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n}
120
+ end
121
+
122
+ if @config[:encrypted_data_bag_secret]
123
+ client_rb << %Q{encrypted_data_bag_secret "c:/chef/encrypted_data_bag_secret"\n}
124
+ end
125
+
126
+ unless trusted_certs.empty?
127
+ client_rb << %Q{trusted_certs_dir "C:/chef/trusted_certs"\n}
128
+ end
129
+
130
+ escape_and_echo(client_rb)
131
+ end
132
+
133
+ def start_chef
134
+ start_chef = "SET \"PATH=%PATH%;C:\\ruby\\bin;C:\\opscode\\chef\\bin;C:\\opscode\\chef\\embedded\\bin\"\n"
135
+ start_chef << "chef-client -c c:/chef/client.rb -j c:/chef/first-boot.json -E #{bootstrap_environment}\n"
136
+ end
137
+
138
+ def latest_current_windows_chef_version_query
139
+ installer_version_string = nil
140
+ if @config[:prerelease]
141
+ installer_version_string = "&prerelease=true"
142
+ else
143
+ chef_version_string = if knife_config[:bootstrap_version]
144
+ knife_config[:bootstrap_version]
145
+ else
146
+ Chef::VERSION.split(".").first
147
+ end
148
+
149
+ installer_version_string = "&v=#{chef_version_string}"
150
+
151
+ # If bootstrapping a pre-release version add the prerelease query string
152
+ if chef_version_string.split(".").length > 3
153
+ installer_version_string << "&prerelease=true"
154
+ end
155
+ end
156
+
157
+ installer_version_string
158
+ end
159
+
160
+ def win_wget
161
+ win_wget = <<-WGET
162
+ url = WScript.Arguments.Named("url")
163
+ path = WScript.Arguments.Named("path")
164
+ proxy = null
165
+ Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP")
166
+ Set wshShell = CreateObject( "WScript.Shell" )
167
+ Set objUserVariables = wshShell.Environment("USER")
168
+
169
+ rem http proxy is optional
170
+ rem attempt to read from HTTP_PROXY env var first
171
+ On Error Resume Next
172
+
173
+ If NOT (objUserVariables("HTTP_PROXY") = "") Then
174
+ proxy = objUserVariables("HTTP_PROXY")
175
+
176
+ rem fall back to named arg
177
+ ElseIf NOT (WScript.Arguments.Named("proxy") = "") Then
178
+ proxy = WScript.Arguments.Named("proxy")
179
+ End If
180
+
181
+ If NOT isNull(proxy) Then
182
+ rem setProxy method is only available on ServerXMLHTTP 6.0+
183
+ Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP.6.0")
184
+ objXMLHTTP.setProxy 2, proxy
185
+ End If
186
+
187
+ On Error Goto 0
188
+
189
+ objXMLHTTP.open "GET", url, false
190
+ objXMLHTTP.send()
191
+ If objXMLHTTP.Status = 200 Then
192
+ Set objADOStream = CreateObject("ADODB.Stream")
193
+ objADOStream.Open
194
+ objADOStream.Type = 1
195
+ objADOStream.Write objXMLHTTP.ResponseBody
196
+ objADOStream.Position = 0
197
+ Set objFSO = Createobject("Scripting.FileSystemObject")
198
+ If objFSO.Fileexists(path) Then objFSO.DeleteFile path
199
+ Set objFSO = Nothing
200
+ objADOStream.SaveToFile path
201
+ objADOStream.Close
202
+ Set objADOStream = Nothing
203
+ End if
204
+ Set objXMLHTTP = Nothing
205
+ WGET
206
+ escape_and_echo(win_wget)
207
+ end
208
+
209
+ def win_wget_ps
210
+ win_wget_ps = <<-WGET_PS
211
+ param(
212
+ [String] $remoteUrl,
213
+ [String] $localPath
214
+ )
215
+
216
+ $webClient = new-object System.Net.WebClient;
217
+
218
+ $webClient.DownloadFile($remoteUrl, $localPath);
219
+ WGET_PS
220
+
221
+ escape_and_echo(win_wget_ps)
222
+ end
223
+
224
+ def install_chef
225
+ # The normal install command uses regular double quotes in
226
+ # the install command, so request such a string from install_command
227
+ install_chef = install_command('"') + "\n" + fallback_install_task_command
228
+ end
229
+
230
+ def bootstrap_directory
231
+ bootstrap_directory = "C:\\chef"
232
+ end
233
+
234
+ def local_download_path
235
+ local_download_path = "%TEMP%\\chef-client-latest.msi"
236
+ end
237
+
238
+ def first_boot
239
+ first_boot_attributes_and_run_list = (@config[:first_boot_attributes] || {}).merge(:run_list => @run_list)
240
+ escape_and_echo(first_boot_attributes_and_run_list.to_json)
241
+ end
242
+
243
+ # escape WIN BATCH special chars
244
+ # and prefixes each line with an
245
+ # echo
246
+ def escape_and_echo(file_contents)
247
+ file_contents.gsub(/^(.*)$/, 'echo.\1').gsub(/([(<|>)^])/, '^\1')
248
+ end
249
+
250
+ private
251
+
252
+ def install_command(executor_quote)
253
+ "msiexec /qn /log #{executor_quote}%CHEF_CLIENT_MSI_LOG_PATH%#{executor_quote} /i #{executor_quote}%LOCAL_DESTINATION_MSI_PATH%#{executor_quote}"
254
+ end
255
+
256
+ def trusted_certs_content
257
+ content = ""
258
+ if @chef_config[:trusted_certs_dir]
259
+ Dir.glob(File.join(PathHelper.escape_glob(@chef_config[:trusted_certs_dir]), "*.{crt,pem}")).each do |cert|
260
+ content << "> #{bootstrap_directory}/trusted_certs/#{File.basename(cert)} (\n" +
261
+ escape_and_echo(IO.read(File.expand_path(cert))) + "\n)\n"
262
+ end
263
+ end
264
+ content
265
+ end
266
+
267
+ def fallback_install_task_command
268
+ # This command will be executed by schtasks.exe in the batch
269
+ # code below. To handle tasks that contain arguments that
270
+ # need to be double quoted, schtasks allows the use of single
271
+ # quotes that will later be converted to double quotes
272
+ command = install_command('\'')
273
+ <<-EOH
274
+ @set MSIERRORCODE=!ERRORLEVEL!
275
+ @if ERRORLEVEL 1 (
276
+ @echo WARNING: Failed to install Chef Client MSI package in remote context with status code !MSIERRORCODE!.
277
+ @echo WARNING: This may be due to a defect in operating system update KB2918614: http://support.microsoft.com/kb/2918614
278
+ @set OLDLOGLOCATION="%CHEF_CLIENT_MSI_LOG_PATH%-fail.log"
279
+ @move "%CHEF_CLIENT_MSI_LOG_PATH%" "!OLDLOGLOCATION!" > NUL
280
+ @echo WARNING: Saving installation log of failure at !OLDLOGLOCATION!
281
+ @echo WARNING: Retrying installation with local context...
282
+ @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\"
283
+
284
+ @if ERRORLEVEL 1 (
285
+ @echo ERROR: Failed to create Chef Client installation scheduled task with status code !ERRORLEVEL! > "&2"
286
+ ) else (
287
+ @echo Successfully created scheduled task to install Chef Client.
288
+ @schtasks /run /tn chefclientbootstraptask
289
+ @if ERRORLEVEL 1 (
290
+ @echo ERROR: Failed to execut Chef Client installation scheduled task with status code !ERRORLEVEL!. > "&2"
291
+ ) else (
292
+ @echo Successfully started Chef Client installation scheduled task.
293
+ @echo Waiting for installation to complete -- this may take a few minutes...
294
+ waitfor chefclientinstalldone /t 600
295
+ if ERRORLEVEL 1 (
296
+ @echo ERROR: Timed out waiting for Chef Client package to install
297
+ ) else (
298
+ @echo Finished waiting for Chef Client package to install.
299
+ )
300
+ @schtasks /delete /f /tn chefclientbootstraptask > NUL
301
+ )
302
+ )
303
+ ) else (
304
+ @echo Successfully installed Chef Client package.
305
+ )
306
+ EOH
307
+ end
308
+ end
309
+ end
310
+ end
311
+ end