knife-windows 1.0.0.rc.1 → 1.0.0.rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -5
  3. data/.travis.yml +20 -20
  4. data/CHANGELOG.md +75 -74
  5. data/DOC_CHANGES.md +323 -323
  6. data/Gemfile +12 -12
  7. data/LICENSE +201 -201
  8. data/README.md +393 -292
  9. data/RELEASE_NOTES.md +79 -74
  10. data/Rakefile +21 -16
  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 -241
  17. data/lib/chef/knife/bootstrap_windows_base.rb +388 -368
  18. data/lib/chef/knife/bootstrap_windows_ssh.rb +110 -110
  19. data/lib/chef/knife/bootstrap_windows_winrm.rb +102 -113
  20. data/lib/chef/knife/core/windows_bootstrap_context.rb +361 -362
  21. data/lib/chef/knife/knife_windows_base.rb +33 -0
  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 +212 -191
  27. data/lib/chef/knife/winrm_base.rb +118 -125
  28. data/lib/chef/knife/winrm_knife_base.rb +218 -201
  29. data/lib/chef/knife/winrm_session.rb +80 -71
  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 +96 -96
  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 -0
  36. data/spec/assets/win_template_rendered_without_bootstrap_install_command.txt +329 -0
  37. data/spec/assets/win_template_unrendered.txt +246 -0
  38. data/spec/functional/bootstrap_download_spec.rb +216 -140
  39. data/spec/spec_helper.rb +87 -72
  40. data/spec/unit/knife/bootstrap_options_spec.rb +146 -146
  41. data/spec/unit/knife/bootstrap_template_spec.rb +92 -92
  42. data/spec/unit/knife/bootstrap_windows_winrm_spec.rb +240 -161
  43. data/spec/unit/knife/core/windows_bootstrap_context_spec.rb +151 -101
  44. data/spec/unit/knife/windows_cert_generate_spec.rb +90 -90
  45. data/spec/unit/knife/windows_cert_install_spec.rb +51 -51
  46. data/spec/unit/knife/windows_listener_create_spec.rb +76 -76
  47. data/spec/unit/knife/winrm_session_spec.rb +55 -46
  48. data/spec/unit/knife/winrm_spec.rb +504 -376
  49. data/spec/unit/knife/wsman_test_spec.rb +175 -175
  50. metadata +28 -8
@@ -0,0 +1,246 @@
1
+ @rem
2
+ @rem Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ @rem Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ @rem License:: Apache License, Version 2.0
5
+ @rem
6
+ @rem Licensed under the Apache License, Version 2.0 (the "License");
7
+ @rem you may not use this file except in compliance with the License.
8
+ @rem You may obtain a copy of the License at
9
+ @rem
10
+ @rem http://www.apache.org/licenses/LICENSE-2.0
11
+ @rem
12
+ @rem Unless required by applicable law or agreed to in writing, software
13
+ @rem distributed under the License is distributed on an "AS IS" BASIS,
14
+ @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ @rem See the License for the specific language governing permissions and
16
+ @rem limitations under the License.
17
+ @rem
18
+
19
+ @rem Use delayed environment expansion so that ERRORLEVEL can be evaluated with the
20
+ @rem !ERRORLEVEL! syntax which evaluates at execution of the line of script, not when
21
+ @rem the line is read. See help for the /E switch from cmd.exe /? .
22
+ @setlocal ENABLEDELAYEDEXPANSION
23
+
24
+ <%= "SETX HTTP_PROXY \"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] %>
25
+
26
+ @set BOOTSTRAP_DIRECTORY=<%= bootstrap_directory %>
27
+ @echo Checking for existing directory "%BOOTSTRAP_DIRECTORY%"...
28
+ @if NOT EXIST %BOOTSTRAP_DIRECTORY% (
29
+ @echo Existing directory not found, creating.
30
+ @mkdir %BOOTSTRAP_DIRECTORY%
31
+ ) else (
32
+ @echo Existing directory found, skipping creation.
33
+ )
34
+
35
+ > <%= bootstrap_directory %>\wget.vbs (
36
+ <%= win_wget %>
37
+ )
38
+
39
+ > <%= bootstrap_directory %>\wget.ps1 (
40
+ <%= win_wget_ps %>
41
+ )
42
+
43
+ @rem Determine the version and the architecture
44
+
45
+ @FOR /F "usebackq tokens=1-8 delims=.[] " %%A IN (`ver`) DO (
46
+ @set WinMajor=%%D
47
+ @set WinMinor=%%E
48
+ @set WinBuild=%%F
49
+ )
50
+
51
+ @echo Detected Windows Version %WinMajor%.%WinMinor% Build %WinBuild%
52
+
53
+ @set LATEST_OS_VERSION_MAJOR=6
54
+ @set LATEST_OS_VERSION_MINOR=3
55
+
56
+ @if /i %WinMajor% GTR %LATEST_OS_VERSION_MAJOR% goto VersionUnknown
57
+ @if /i %WinMajor% EQU %LATEST_OS_VERSION_MAJOR% (
58
+ @if /i %WinMinor% GTR %LATEST_OS_VERSION_MINOR% goto VersionUnknown
59
+ )
60
+
61
+ goto Version%WinMajor%.%WinMinor%
62
+
63
+ :VersionUnknown
64
+ @rem If this is an unknown version of windows set the default
65
+ @set MACHINE_OS=2008r2
66
+ @echo Warning: Unknown version of Windows, assuming default of Windows %MACHINE_OS%
67
+ goto architecture_select
68
+
69
+ :Version6.0
70
+ @set MACHINE_OS=2008
71
+ goto architecture_select
72
+
73
+ :Version5.2
74
+ @set MACHINE_OS=2003r2
75
+ goto architecture_select
76
+
77
+ :Version6.1
78
+ @set MACHINE_OS=2008r2
79
+ goto architecture_select
80
+
81
+ :Version6.2
82
+ @set MACHINE_OS=2012
83
+ goto architecture_select
84
+
85
+ @rem Currently Windows Server 2012 R2 is treated as equivalent to Windows Server 2012
86
+ :Version6.3
87
+ goto Version6.2
88
+
89
+ :architecture_select
90
+ goto Architecture%PROCESSOR_ARCHITEW6432%
91
+
92
+ :Architecture
93
+ goto Architecture%PROCESSOR_ARCHITECTURE%
94
+
95
+ @rem If this is an unknown architecture set the default
96
+ @set MACHINE_ARCH=i686
97
+ goto install
98
+
99
+ :Architecturex86
100
+ @set MACHINE_ARCH=i686
101
+ goto install
102
+
103
+ :Architectureamd64
104
+ @set MACHINE_ARCH=x86_64
105
+ goto install
106
+
107
+ :install
108
+ @rem If user has provided the custom installation command for chef-client then execute it
109
+ <% if @chef_config[:knife][:bootstrap_install_command] %>
110
+ <%= @chef_config[:knife][:bootstrap_install_command] %>
111
+ <% else %>
112
+ @rem Install Chef using chef-client MSI installer
113
+
114
+ @set "LOCAL_DESTINATION_MSI_PATH=<%= local_download_path %>"
115
+ @set "CHEF_CLIENT_MSI_LOG_PATH=%TEMP%\chef-client-msi%RANDOM%.log"
116
+
117
+ @rem Clear any pre-existing downloads
118
+ @echo Checking for existing downloaded package at "%LOCAL_DESTINATION_MSI_PATH%"
119
+ @if EXIST "%LOCAL_DESTINATION_MSI_PATH%" (
120
+ @echo Found existing downloaded package, deleting.
121
+ @del /f /q "%LOCAL_DESTINATION_MSI_PATH%"
122
+ @if ERRORLEVEL 1 (
123
+ echo Warning: Failed to delete pre-existing package with status code !ERRORLEVEL! > "&2"
124
+ )
125
+ ) else (
126
+ echo No existing downloaded packages to delete.
127
+ )
128
+
129
+ @rem If there is somehow a name collision, remove pre-existing log
130
+ @if EXIST "%CHEF_CLIENT_MSI_LOG_PATH%" del /f /q "%CHEF_CLIENT_MSI_LOG_PATH%"
131
+
132
+ @echo Attempting to download client package using PowerShell if available...
133
+ @set "REMOTE_SOURCE_MSI_URL=<%= msi_url('%MACHINE_OS%', '%MACHINE_ARCH%', 'PowerShell') %>"
134
+ @set powershell_download=powershell.exe -ExecutionPolicy Unrestricted -NoProfile -NonInteractive -File <%= bootstrap_directory %>\wget.ps1 "%REMOTE_SOURCE_MSI_URL%" "%LOCAL_DESTINATION_MSI_PATH%"
135
+ @echo !powershell_download!
136
+ @call !powershell_download!
137
+
138
+ @set DOWNLOAD_ERROR_STATUS=!ERRORLEVEL!
139
+
140
+ @if ERRORLEVEL 1 (
141
+ @echo Failed PowerShell download with status code !DOWNLOAD_ERROR_STATUS! > "&2"
142
+ @if !DOWNLOAD_ERROR_STATUS!==0 set DOWNLOAD_ERROR_STATUS=2
143
+ ) else (
144
+ @rem Sometimes the error level is not set even when the download failed,
145
+ @rem so check for the file to be sure it is there -- if it is not, we will retry
146
+ @if NOT EXIST "%LOCAL_DESTINATION_MSI_PATH%" (
147
+ echo Failed download: download completed, but downloaded file not found > "&2"
148
+ set DOWNLOAD_ERROR_STATUS=2
149
+ ) else (
150
+ echo Download via PowerShell succeeded.
151
+ )
152
+ )
153
+
154
+ @if NOT %DOWNLOAD_ERROR_STATUS%==0 (
155
+ @echo Warning: Failed to download "%REMOTE_SOURCE_MSI_URL%" to "%LOCAL_DESTINATION_MSI_PATH%"
156
+ @echo Warning: Retrying download with cscript ...
157
+
158
+ @if EXIST "%LOCAL_DESTINATION_MSI_PATH%" del /f /q "%LOCAL_DESTINATION_MSI_PATH%"
159
+
160
+ @set "REMOTE_SOURCE_MSI_URL=<%= msi_url('%MACHINE_OS%', '%MACHINE_ARCH%') %>"
161
+ cscript /nologo <%= bootstrap_directory %>\wget.vbs /url:"%REMOTE_SOURCE_MSI_URL%" /path:"%LOCAL_DESTINATION_MSI_PATH%"
162
+
163
+ @if NOT ERRORLEVEL 1 (
164
+ @rem Sometimes the error level is not set even when the download failed,
165
+ @rem so check for the file to be sure it is there.
166
+ @if NOT EXIST "%LOCAL_DESTINATION_MSI_PATH%" (
167
+ echo Failed download: download completed, but downloaded file not found > "&2"
168
+ echo Exiting without bootstrapping due to download failure. > "&2"
169
+ exit /b 1
170
+ ) else (
171
+ echo Download via cscript succeeded.
172
+ )
173
+ ) else (
174
+ echo Failed to download "%REMOTE_SOURCE_MSI_URL%" with status code !ERRORLEVEL!. > "&2"
175
+ echo Exiting without bootstrapping due to download failure. > "&2"
176
+ exit /b 1
177
+ )
178
+ )
179
+
180
+ @echo Installing downloaded client package...
181
+
182
+ <%= install_chef %>
183
+
184
+ @if ERRORLEVEL 1 (
185
+ echo Chef-client package failed to install with status code !ERRORLEVEL!. > "&2"
186
+ echo See installation log for additional detail: %CHEF_CLIENT_MSI_LOG_PATH%. > "&2"
187
+ ) else (
188
+ @echo Installation completed successfully
189
+ del /f /q "%CHEF_CLIENT_MSI_LOG_PATH%"
190
+ )
191
+
192
+ <% end %>
193
+
194
+ @endlocal
195
+
196
+ @echo off
197
+
198
+ <% if client_pem -%>
199
+ > <%= bootstrap_directory %>\client.pem (
200
+ <%= escape_and_echo(::File.read(::File.expand_path(client_pem))) %>
201
+ )
202
+ <% end -%>
203
+
204
+ echo Writing validation key...
205
+
206
+ <% if validation_key -%>
207
+ > <%= bootstrap_directory %>\validation.pem (
208
+ <%= escape_and_echo(validation_key) %>
209
+ )
210
+ <% end -%>
211
+
212
+ echo Validation key written.
213
+ @echo on
214
+
215
+ <% if @config[:secret] -%>
216
+ > <%= bootstrap_directory %>\encrypted_data_bag_secret (
217
+ <%= secret %>
218
+ )
219
+ <% end -%>
220
+
221
+ <% unless trusted_certs_script.empty? -%>
222
+ mkdir <%= bootstrap_directory %>\trusted_certs
223
+ <%= trusted_certs_script %>
224
+ <% end -%>
225
+
226
+ <%# Generate Ohai Hints -%>
227
+ <% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%>
228
+ mkdir <%= bootstrap_directory %>\ohai\hints
229
+
230
+ <% @chef_config[:knife][:hints].each do |name, hash| -%>
231
+ > <%= bootstrap_directory %>\ohai\hints\<%= name %>.json (
232
+ <%= escape_and_echo(hash.to_json) %>
233
+ )
234
+ <% end -%>
235
+ <% end -%>
236
+
237
+ > <%= bootstrap_directory %>\client.rb (
238
+ <%= config_content %>
239
+ )
240
+
241
+ > <%= bootstrap_directory %>\first-boot.json (
242
+ <%= first_boot %>
243
+ )
244
+
245
+ @echo Starting chef to bootstrap the node...
246
+ <%= start_chef %>
@@ -1,140 +1,216 @@
1
- #
2
- # Author:: Adam Edwards (<adamed@opscode.com>)
3
- # Copyright:: Copyright (c) 2012 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
15
- # implied.
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
- #
19
-
20
- require 'spec_helper'
21
- require 'tmpdir'
22
-
23
- # These test cases exercise the Knife::Windows knife plugin's ability
24
- # to download a bootstrap msi as part of the bootstrap process on
25
- # Windows nodes. The test modifies the Windows batch file generated
26
- # from an erb template in the plugin source in order to enable execution
27
- # of only the download functionality contained in the bootstrap template.
28
- # The test relies on knowledge of the fields of the template itself and
29
- # also on knowledge of the contents and structure of the Windows batch
30
- # file generated by the template.
31
- #
32
- # Note that if the bootstrap template changes substantially, the tests
33
- # should fail and will require re-implementation. If such changes
34
- # occur, the bootstrap code should be refactored to explicitly expose
35
- # the download funcitonality separately from other tasks to make the
36
- # test more robust.
37
- describe 'Knife::Windows::Core msi download functionality for knife Windows winrm bootstrap template' do
38
-
39
- before(:all) do
40
- # Since we're always running 32-bit Ruby, fix the
41
- # PROCESSOR_ARCHITECTURE environment variable.
42
-
43
- if ENV["PROCESSOR_ARCHITEW6432"]
44
- ENV["PROCESSOR_ARCHITECTURE"] = ENV["PROCESSOR_ARCHITEW6432"]
45
- end
46
-
47
- # All file artifacts from this test will be written into this directory
48
- @temp_directory = Dir.mktmpdir("bootstrap_test")
49
-
50
- # Location to which the download script will be modified to write
51
- # the downloaded msi
52
- @local_file_download_destination = "#{@temp_directory}/chef-client-latest.msi"
53
-
54
- source_code_directory = File.dirname(__FILE__)
55
- @template_file_path ="#{source_code_directory}/../../lib/chef/knife/bootstrap/windows-chef-client-msi.erb"
56
- end
57
-
58
- after(:all) do
59
- # Clear the temp directory upon exit
60
- if Dir.exists?(@temp_directory)
61
- FileUtils::remove_dir(@temp_directory)
62
- end
63
- end
64
-
65
- describe "running on any version of the Windows OS", :windows_only do
66
- let(:mock_bootstrap_context) { Chef::Knife::Core::WindowsBootstrapContext.new({ }, nil, { :knife => {} }) }
67
- let(:mock_winrm) { Chef::Knife::Winrm.new }
68
-
69
- before do
70
- # Stub the bootstrap context and prevent config related sections
71
- # from being populated, i.e. chef installation and first chef
72
- # run sections
73
- allow(mock_bootstrap_context).to receive(:validation_key).and_return("echo.validation_key")
74
- allow(mock_bootstrap_context).to receive(:secret).and_return("echo.encrypted_data_bag_secret")
75
- allow(mock_bootstrap_context).to receive(:config_content).and_return("echo.config_content")
76
- allow(mock_bootstrap_context).to receive(:start_chef).and_return("echo.echo start_chef_command")
77
- allow(mock_bootstrap_context).to receive(:run_list).and_return("echo.run_list")
78
- allow(mock_bootstrap_context).to receive(:install_chef).and_return("echo.echo install_chef_command")
79
-
80
- # Change the directories where bootstrap files will be created
81
- allow(mock_bootstrap_context).to receive(:bootstrap_directory).and_return(@temp_directory.gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR))
82
- allow(mock_bootstrap_context).to receive(:local_download_path).and_return(@local_file_download_destination.gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR))
83
-
84
- # Prevent password prompt during bootstrap process
85
- allow(mock_winrm).to receive(:get_password).and_return(nil)
86
- allow(Chef::Knife::Winrm).to receive(:new).and_return(mock_winrm)
87
-
88
- allow(Chef::Knife::Core::WindowsBootstrapContext).to receive(:new).and_return(mock_bootstrap_context)
89
- Chef::Config[:knife] = {:winrm_transport => 'plaintext', :chef_node_name => 'foo.example.com', :winrm_authentication_protocol => 'negotiate'}
90
- end
91
-
92
- it "downloads the chef-client MSI from the default location during winrm bootstrap" do
93
- run_download_scenario
94
- end
95
-
96
- context "when provided a custom msi_url to fetch from" do
97
- let(:mock_bootstrap_context) { Chef::Knife::Core::WindowsBootstrapContext.new(
98
- { :msi_url => "file:///C:/Windows/System32/xcopy.exe" }, nil, { :knife => {} }) }
99
- it "downloads the chef-client MSI from a custom path during winrm bootstrap" do
100
- run_download_scenario
101
- end
102
- end
103
- end
104
-
105
- def download_succeeded?
106
- File.exists?(@local_file_download_destination) && ! File.zero?(@local_file_download_destination)
107
- end
108
-
109
- # Remove file artifacts generated by individual test cases
110
- def clean_test_case
111
- if File.exists?(@local_file_download_destination)
112
- File.delete(@local_file_download_destination)
113
- end
114
- end
115
-
116
- def run_download_scenario
117
- clean_test_case
118
-
119
- winrm_bootstrapper = Chef::Knife::BootstrapWindowsWinrm.new([ "127.0.0.1" ])
120
-
121
- if chef_gte_12?
122
- winrm_bootstrapper.client_builder = instance_double("Chef::Knife::Bootstrap::ClientBuilder", :run => nil, :client_path => nil)
123
- elsif chef_lt_12?
124
- allow(File).to receive(:exist?).with(File.expand_path(Chef::Config[:validation_key])).and_return(true)
125
- end
126
-
127
- allow(winrm_bootstrapper).to receive(:wait_for_remote_response)
128
- winrm_bootstrapper.config[:template_file] = @template_file_path
129
-
130
- # Execute the commands locally that would normally be executed via WinRM
131
- allow(winrm_bootstrapper).to receive(:run_command) do |command|
132
- system(command)
133
- end
134
-
135
- winrm_bootstrapper.run
136
-
137
- # Download should succeed
138
- expect(download_succeeded?).to be true
139
- end
140
- end
1
+ #
2
+ # Author:: Adam Edwards (<adamed@opscode.com>)
3
+ # Copyright:: Copyright (c) 2012 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
15
+ # implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'spec_helper'
21
+ require 'tmpdir'
22
+
23
+ # These test cases exercise the Knife::Windows knife plugin's ability
24
+ # to download a bootstrap msi as part of the bootstrap process on
25
+ # Windows nodes. The test modifies the Windows batch file generated
26
+ # from an erb template in the plugin source in order to enable execution
27
+ # of only the download functionality contained in the bootstrap template.
28
+ # The test relies on knowledge of the fields of the template itself and
29
+ # also on knowledge of the contents and structure of the Windows batch
30
+ # file generated by the template.
31
+ #
32
+ # Note that if the bootstrap template changes substantially, the tests
33
+ # should fail and will require re-implementation. If such changes
34
+ # occur, the bootstrap code should be refactored to explicitly expose
35
+ # the download funcitonality separately from other tasks to make the
36
+ # test more robust.
37
+ describe 'Knife::Windows::Core msi download functionality for knife Windows winrm bootstrap template' do
38
+
39
+ before(:all) do
40
+ # Since we're always running 32-bit Ruby, fix the
41
+ # PROCESSOR_ARCHITECTURE environment variable.
42
+
43
+ if ENV["PROCESSOR_ARCHITEW6432"]
44
+ ENV["PROCESSOR_ARCHITECTURE"] = ENV["PROCESSOR_ARCHITEW6432"]
45
+ end
46
+
47
+ # All file artifacts from this test will be written into this directory
48
+ @temp_directory = Dir.mktmpdir("bootstrap_test")
49
+
50
+ # Location to which the download script will be modified to write
51
+ # the downloaded msi
52
+ @local_file_download_destination = "#{@temp_directory}/chef-client-latest.msi"
53
+
54
+ source_code_directory = File.dirname(__FILE__)
55
+ @template_file_path ="#{source_code_directory}/../../lib/chef/knife/bootstrap/windows-chef-client-msi.erb"
56
+ end
57
+
58
+ after(:all) do
59
+ # Clear the temp directory upon exit
60
+ if Dir.exists?(@temp_directory)
61
+ FileUtils::remove_dir(@temp_directory)
62
+ end
63
+ end
64
+
65
+ describe "running on any version of the Windows OS", :windows_only do
66
+ let(:mock_bootstrap_context) { Chef::Knife::Core::WindowsBootstrapContext.new({ }, nil, { :knife => {} }) }
67
+ let(:mock_winrm) { Chef::Knife::Winrm.new }
68
+
69
+ before do
70
+ # Stub the bootstrap context and prevent config related sections
71
+ # from being populated, i.e. chef installation and first chef
72
+ # run sections
73
+ allow(mock_bootstrap_context).to receive(:validation_key).and_return("echo.validation_key")
74
+ allow(mock_bootstrap_context).to receive(:secret).and_return("echo.encrypted_data_bag_secret")
75
+ allow(mock_bootstrap_context).to receive(:config_content).and_return("echo.config_content")
76
+ allow(mock_bootstrap_context).to receive(:start_chef).and_return("echo.echo start_chef_command")
77
+ allow(mock_bootstrap_context).to receive(:run_list).and_return("echo.run_list")
78
+ allow(mock_bootstrap_context).to receive(:install_chef).and_return("echo.echo install_chef_command")
79
+
80
+ # Change the directories where bootstrap files will be created
81
+ allow(mock_bootstrap_context).to receive(:bootstrap_directory).and_return(@temp_directory.gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR))
82
+ allow(mock_bootstrap_context).to receive(:local_download_path).and_return(@local_file_download_destination.gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR))
83
+
84
+ # Prevent password prompt during bootstrap process
85
+ allow(mock_winrm).to receive(:get_password).and_return(nil)
86
+ allow(Chef::Knife::Winrm).to receive(:new).and_return(mock_winrm)
87
+
88
+ allow(Chef::Knife::Core::WindowsBootstrapContext).to receive(:new).and_return(mock_bootstrap_context)
89
+ Chef::Config[:knife] = {:winrm_transport => 'plaintext', :chef_node_name => 'foo.example.com', :winrm_authentication_protocol => 'negotiate'}
90
+ end
91
+
92
+ it "downloads the chef-client MSI from the default location during winrm bootstrap" do
93
+ run_download_scenario
94
+ end
95
+
96
+ context "when provided a custom msi_url to fetch from" do
97
+ let(:mock_bootstrap_context) { Chef::Knife::Core::WindowsBootstrapContext.new(
98
+ { :msi_url => "file:///C:/Windows/System32/xcopy.exe" }, nil, { :knife => {} }) }
99
+ it "downloads the chef-client MSI from a custom path during winrm bootstrap" do
100
+ run_download_scenario
101
+ end
102
+ end
103
+
104
+ context "when provided a custom msi_url with space in path to fetch from" do
105
+ let(:mock_bootstrap_context) { Chef::Knife::Core::WindowsBootstrapContext.new(
106
+ { :msi_url => "file:///C:/Program Files/Windows NT/Accessories/wordpad.exe" }, nil, { :knife => {} }) }
107
+ it "downloads the chef-client MSI from a custom path with spaces during winrm bootstrap" do
108
+ run_download_scenario
109
+ end
110
+ end
111
+ end
112
+
113
+ def download_succeeded?
114
+ File.exists?(@local_file_download_destination) && ! File.zero?(@local_file_download_destination)
115
+ end
116
+
117
+ # Remove file artifacts generated by individual test cases
118
+ def clean_test_case
119
+ if File.exists?(@local_file_download_destination)
120
+ File.delete(@local_file_download_destination)
121
+ end
122
+ end
123
+
124
+ def run_download_scenario
125
+ clean_test_case
126
+
127
+ winrm_bootstrapper = Chef::Knife::BootstrapWindowsWinrm.new([ "127.0.0.1" ])
128
+
129
+ if chef_gte_12?
130
+ winrm_bootstrapper.client_builder = instance_double("Chef::Knife::Bootstrap::ClientBuilder", :run => nil, :client_path => nil)
131
+ elsif chef_lt_12?
132
+ allow(File).to receive(:exist?).with(File.expand_path(Chef::Config[:validation_key])).and_return(true)
133
+ end
134
+
135
+ allow(winrm_bootstrapper).to receive(:wait_for_remote_response)
136
+ winrm_bootstrapper.config[:template_file] = @template_file_path
137
+
138
+ # Execute the commands locally that would normally be executed via WinRM
139
+ allow(winrm_bootstrapper).to receive(:run_command) do |command|
140
+ system(command)
141
+ end
142
+
143
+ winrm_bootstrapper.run
144
+
145
+ # Download should succeed
146
+ expect(download_succeeded?).to be true
147
+ end
148
+ end
149
+
150
+ describe "bootstrap_install_command functionality through WinRM protocol", :if_chef_11 => true do
151
+ context "bootstrap_install_command option is not specified" do
152
+ let(:bootstrap) { Chef::Knife::BootstrapWindowsWinrm.new([]) }
153
+ before do
154
+ @template_input = sample_data('win_template_unrendered.txt')
155
+ @template_output = sample_data('win_template_rendered_without_bootstrap_install_command.txt')
156
+ end
157
+
158
+ it "bootstrap_install_command option is not rendered in the windows-chef-client-msi.erb template as its value is nil" do
159
+ expect(bootstrap.send(:render_template,@template_input)).to eq(
160
+ @template_output)
161
+ end
162
+ end
163
+
164
+ context "bootstrap_install_command option is specified" do
165
+ let(:bootstrap) { Chef::Knife::BootstrapWindowsWinrm.new(['--bootstrap-install-command', 'chef-client -o recipe[cbk1::rec2]']) }
166
+ before do
167
+ bootstrap.config[:bootstrap_install_command] = "chef-client -o recipe[cbk1::rec2]"
168
+ @template_input = sample_data('win_template_unrendered.txt')
169
+ @template_output = sample_data('win_template_rendered_with_bootstrap_install_command.txt')
170
+ end
171
+
172
+ it "bootstrap_install_command option is rendered in the windows-chef-client-msi.erb template" do
173
+ expect(bootstrap.send(:render_template,@template_input)).to eq(
174
+ @template_output)
175
+ end
176
+
177
+ after do
178
+ bootstrap.config.delete(:bootstrap_install_command)
179
+ Chef::Config[:knife].delete(:bootstrap_install_command)
180
+ end
181
+ end
182
+ end
183
+
184
+ describe "bootstrap_install_command functionality through SSH protocol", :if_chef_11 => true do
185
+ context "bootstrap_install_command option is not specified" do
186
+ let(:bootstrap) { Chef::Knife::BootstrapWindowsSsh.new([]) }
187
+ before do
188
+ @template_input = sample_data('win_template_unrendered.txt')
189
+ @template_output = sample_data('win_template_rendered_without_bootstrap_install_command.txt')
190
+ end
191
+
192
+ it "bootstrap_install_command option is not rendered in the windows-chef-client-msi.erb template as its value is nil" do
193
+ expect(bootstrap.send(:render_template,@template_input)).to eq(
194
+ @template_output)
195
+ end
196
+ end
197
+
198
+ context "bootstrap_install_command option is specified" do
199
+ let(:bootstrap) { Chef::Knife::BootstrapWindowsSsh.new(['--bootstrap-install-command', 'chef-client -o recipe[cbk1::rec2]']) }
200
+ before do
201
+ bootstrap.config[:bootstrap_install_command] = "chef-client -o recipe[cbk1::rec2]"
202
+ @template_input = sample_data('win_template_unrendered.txt')
203
+ @template_output = sample_data('win_template_rendered_with_bootstrap_install_command.txt')
204
+ end
205
+
206
+ it "bootstrap_install_command option is rendered in the windows-chef-client-msi.erb template" do
207
+ expect(bootstrap.send(:render_template,@template_input)).to eq(
208
+ @template_output)
209
+ end
210
+
211
+ after do
212
+ bootstrap.config.delete(:bootstrap_install_command)
213
+ Chef::Config[:knife].delete(:bootstrap_install_command)
214
+ end
215
+ end
216
+ end