knife-windows 0.8.6 → 1.0.0.rc.0
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +17 -3
- data/CHANGELOG.md +25 -6
- data/DOC_CHANGES.md +323 -0
- data/Gemfile +2 -1
- data/README.md +160 -29
- data/RELEASE_NOTES.md +59 -6
- data/appveyor.yml +42 -0
- data/ci.gemfile +15 -0
- data/knife-windows.gemspec +4 -2
- data/lib/chef/knife/bootstrap/windows-chef-client-msi.erb +35 -21
- data/lib/chef/knife/bootstrap_windows_base.rb +155 -31
- data/lib/chef/knife/bootstrap_windows_ssh.rb +1 -1
- data/lib/chef/knife/bootstrap_windows_winrm.rb +17 -10
- data/lib/chef/knife/core/windows_bootstrap_context.rb +67 -16
- data/lib/chef/knife/windows_cert_generate.rb +155 -0
- data/lib/chef/knife/windows_cert_install.rb +62 -0
- data/lib/chef/knife/windows_helper.rb +3 -1
- data/lib/chef/knife/windows_listener_create.rb +100 -0
- data/lib/chef/knife/winrm.rb +84 -208
- data/lib/chef/knife/winrm_base.rb +36 -10
- data/lib/chef/knife/winrm_knife_base.rb +201 -0
- data/lib/chef/knife/winrm_session.rb +72 -0
- data/lib/chef/knife/winrm_shared_options.rb +47 -0
- data/lib/chef/knife/wsman_endpoint.rb +44 -0
- data/lib/chef/knife/wsman_test.rb +96 -0
- data/lib/knife-windows/path_helper.rb +77 -0
- data/lib/knife-windows/version.rb +1 -1
- data/spec/functional/bootstrap_download_spec.rb +41 -23
- data/spec/spec_helper.rb +11 -1
- data/spec/unit/knife/bootstrap_template_spec.rb +27 -27
- data/spec/unit/knife/bootstrap_windows_winrm_spec.rb +67 -23
- data/spec/unit/knife/core/windows_bootstrap_context_spec.rb +47 -0
- data/spec/unit/knife/windows_cert_generate_spec.rb +90 -0
- data/spec/unit/knife/windows_cert_install_spec.rb +35 -0
- data/spec/unit/knife/windows_listener_create_spec.rb +61 -0
- data/spec/unit/knife/winrm_session_spec.rb +47 -0
- data/spec/unit/knife/winrm_spec.rb +222 -56
- data/spec/unit/knife/wsman_test_spec.rb +176 -0
- metadata +51 -20
data/RELEASE_NOTES.md
CHANGED
@@ -6,14 +6,67 @@ Example Note:
|
|
6
6
|
## Example Heading
|
7
7
|
Details about the thing that changed that needs to get included in the Release Notes in markdown.
|
8
8
|
-->
|
9
|
-
# knife-windows 0.
|
10
|
-
This release of knife-windows
|
9
|
+
# knife-windows 1.0.0.rc.0 release notes:
|
10
|
+
This release of knife-windows includes new features to improve authentication,
|
11
|
+
simplify use of the WinRM SSL transport, and addresses compatibility issues with Chef Client 12.0.
|
11
12
|
|
12
|
-
|
13
|
-
None.
|
13
|
+
You can install the new features using the `gem` command:
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
gem install knife-windows --pre
|
16
|
+
|
17
|
+
## Reporting issues and contributing
|
18
|
+
|
19
|
+
`knife-windows` issues like those addressed in this release should be reported in the ticketing system at https://github.com/chef/knife-windows/issues. You can learn more about how to contribute features and bug fixes to `knife-windows` in the [Chef Contributions document](http://docs.chef.io/community_contributions.html).
|
20
|
+
|
21
|
+
## Breaking changes
|
22
|
+
|
23
|
+
### Negotiate as the default authentication protocol
|
24
|
+
With this release, the default authentication protocol for WinRM
|
25
|
+
communication is negotiate, which is the same as that for tools built-in to
|
26
|
+
the Windows operating system. Prior to this release, the protocol depended
|
27
|
+
on the format of the `--winrm-user` option -- the basic authentication
|
28
|
+
protocol would be assumed unless that option had the format `domain\user`.
|
29
|
+
|
30
|
+
To revert to the behavior of previous releases or otherwise force `knife-windows` to use a specific authentication protocol such as
|
31
|
+
basic, use the `--winrm-authentication-protocol` option.
|
32
|
+
|
33
|
+
### Default WinRM port depends on the transport
|
34
|
+
The default port for WinRM communication is now **5986** when the SSL transport is used (the transport is
|
35
|
+
configured by the `winrm_transport` option), otherwise it is **5985**. In
|
36
|
+
previous releases, if the port was not specified, it was always 5985.
|
37
|
+
|
38
|
+
To override this behavior, explicitly specify the desired port using the
|
39
|
+
`winrm_port` (`-p`) option.
|
40
|
+
|
41
|
+
### Kerberos Keytab short option is now -T
|
42
|
+
The short option flag for --keytab-file is now -T to fix a conflict with the --identity-file option.
|
43
|
+
|
44
|
+
## Features added in knife-windows 1.0.0.rc.0
|
45
|
+
* New `--winrm-authentication-protocol` option for explicit control of WinRM authentication
|
46
|
+
* `knife windows cert generate` subcommand:
|
47
|
+
Generates a certificate and related public key file for use in configuring a WinRM listener and validating communication involving it.
|
48
|
+
* `knife windows cert install` subcommand:
|
49
|
+
Installs a certificate such as one generated by the `cert generate`
|
50
|
+
subcommand into the Windows certificate store's LocalMachine personal store
|
51
|
+
so that it can be used as part of the configuration for a WinRM SSL listener
|
52
|
+
* `knife windows listener create` subcommand:
|
53
|
+
Creates a WinRM SSL listener on a Windows system
|
54
|
+
* Added `--hint` option for creating Ohai hints on bootstrap
|
55
|
+
* Validatorless bootstrapping is now supported
|
56
|
+
* New `--install-as-service` option will have Chef Client be installed as a service on bootstrap
|
57
|
+
* Added `--msi_url` option for providing an alternate URL to the Chef Client installation package
|
58
|
+
* `knife wsman test` subcommaned:
|
59
|
+
Verifies winrm functionality on a remote system, e.g. `knife wsman test 192.168.1.10 -m --winrm-transport ssl`
|
60
|
+
|
61
|
+
## Issues fixed in knife-windows 1.0.0.rc.0
|
62
|
+
* [knife-windows #159](https://github.com/chef/knife-windows/issues/159) `winrm_port` option should default to 5986 if `winrm_transport` option is `ssl`
|
63
|
+
* [knife-windows #139](https://github.com/chef/knife-windows/issues/139) Force dev dependency on Chef 11 for test scenarios to avoid Ohai 8 conflict on Ruby 1.9.x
|
64
|
+
* [knife-windows #133](https://github.com/chef/knife-windows/issues/133) Bootstrap failure -- unable to validate SSL chef server endpoints
|
65
|
+
* [knife-windows #125](https://github.com/chef/knife-windows/issues/125) knife-windows should use PowerShell first before cscript to download the Chef Client msi
|
66
|
+
* [knife-windows #92](https://github.com/chef/knife-windows/issues/92) EventMachine issue: knife bootstrap windows winrm error
|
67
|
+
* [knife-windows #94](https://github.com/chef/knife-windows/issues/94) Remove Eventmachine dependency
|
68
|
+
* [knife-windows #213](https://github.com/chef/knife-windows/pull/213) Search possibilities of HOME for bootstrap templates
|
69
|
+
* [knife-windows #227](https://github.com/chef/knife-windows/issues/227) Exception: NoMethodError: undefined method 'gsub' for false:FalseClass
|
17
70
|
|
18
71
|
## knife-windows on RubyGems and Github
|
19
72
|
https://rubygems.org/gems/knife-windows
|
data/appveyor.yml
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
version: "master-{build}"
|
2
|
+
|
3
|
+
os: Windows Server 2012
|
4
|
+
platform:
|
5
|
+
- x64
|
6
|
+
|
7
|
+
environment:
|
8
|
+
bundle_gemfile: ci.gemfile
|
9
|
+
|
10
|
+
matrix:
|
11
|
+
- ruby_version: "193"
|
12
|
+
chef_version: "< 12"
|
13
|
+
|
14
|
+
- ruby_version: "200"
|
15
|
+
chef_version: "< 12"
|
16
|
+
|
17
|
+
- ruby_version: "200"
|
18
|
+
chef_version: "~> 12.0"
|
19
|
+
|
20
|
+
- ruby_version: "200"
|
21
|
+
chef_version: "master"
|
22
|
+
|
23
|
+
clone_folder: c:\projects\knife-windows
|
24
|
+
clone_depth: 1
|
25
|
+
branches:
|
26
|
+
only:
|
27
|
+
- master
|
28
|
+
|
29
|
+
install:
|
30
|
+
- winrm quickconfig -q
|
31
|
+
- SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
|
32
|
+
- echo %PATH%
|
33
|
+
- ruby --version
|
34
|
+
- gem --version
|
35
|
+
- gem install bundler --quiet --no-ri --no-rdoc
|
36
|
+
- bundler --version
|
37
|
+
|
38
|
+
build_script:
|
39
|
+
- bundle install || bundle install || bundle install
|
40
|
+
|
41
|
+
test_script:
|
42
|
+
- bundle exec rake spec
|
data/ci.gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in knife-windows.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
if ENV['CHEF_VERSION'] == 'master'
|
7
|
+
gem 'chef', github: 'chef/chef'
|
8
|
+
else
|
9
|
+
gem 'chef', ENV['CHEF_VERSION']
|
10
|
+
end
|
11
|
+
|
12
|
+
gem "rspec", '~> 3.0'
|
13
|
+
gem "ruby-wmi"
|
14
|
+
gem "httpclient"
|
15
|
+
gem 'rake'
|
data/knife-windows.gemspec
CHANGED
@@ -14,8 +14,9 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.description = s.summary
|
15
15
|
|
16
16
|
s.required_ruby_version = ">= 1.9.1"
|
17
|
-
s.add_dependency "winrm
|
18
|
-
s.add_dependency "
|
17
|
+
s.add_dependency "winrm", "~> 1.3"
|
18
|
+
s.add_dependency "winrm-s", "~> 0.3.0.dev.0"
|
19
|
+
s.add_dependency "nokogiri"
|
19
20
|
|
20
21
|
s.add_development_dependency 'pry'
|
21
22
|
|
@@ -24,3 +25,4 @@ Gem::Specification.new do |s|
|
|
24
25
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
25
26
|
s.require_paths = ["lib"]
|
26
27
|
end
|
28
|
+
|
@@ -107,12 +107,8 @@ goto install
|
|
107
107
|
:install
|
108
108
|
@rem Install Chef using chef-client MSI installer
|
109
109
|
|
110
|
-
<% url="https://www.opscode.com/chef/download?p=windows&pv=%MACHINE_OS%&m=%MACHINE_ARCH%" -%>
|
111
|
-
<% url += latest_current_windows_chef_version_query -%>
|
112
|
-
@set "REMOTE_SOURCE_MSI_URL=<%= url %>"
|
113
110
|
@set "LOCAL_DESTINATION_MSI_PATH=<%= local_download_path %>"
|
114
111
|
@set "CHEF_CLIENT_MSI_LOG_PATH=%TEMP%\chef-client-msi%RANDOM%.log"
|
115
|
-
@set "FALLBACK_QUERY_STRING=&DownloadContext=PowerShell"
|
116
112
|
|
117
113
|
@rem Clear any pre-existing downloads
|
118
114
|
@echo Checking for existing downloaded package at "%LOCAL_DESTINATION_MSI_PATH%"
|
@@ -129,15 +125,16 @@ goto install
|
|
129
125
|
@rem If there is somehow a name collision, remove pre-existing log
|
130
126
|
@if EXIST "%CHEF_CLIENT_MSI_LOG_PATH%" del /f /q "%CHEF_CLIENT_MSI_LOG_PATH%"
|
131
127
|
|
132
|
-
@echo Attempting to download client package using
|
133
|
-
|
128
|
+
@echo Attempting to download client package using PowerShell if available...
|
129
|
+
@set "REMOTE_SOURCE_MSI_URL=<%= msi_url('%MACHINE_OS%', '%MACHINE_ARCH%', 'PowerShell') %>"
|
130
|
+
@set powershell_download=powershell.exe -ExecutionPolicy Unrestricted -NoProfile -NonInteractive -File <%= bootstrap_directory %>\wget.ps1 "%REMOTE_SOURCE_MSI_URL%" "%LOCAL_DESTINATION_MSI_PATH%"
|
131
|
+
@echo !powershell_download!
|
132
|
+
@call !powershell_download!
|
134
133
|
|
135
|
-
@rem Work around issues found in Windows Server 2012 around job objects not respecting WSMAN memory quotas
|
136
|
-
@rem that cause the MSI download process to exceed the quota even when it is increased by administrators.
|
137
|
-
@rem Retry the download using a more memory-efficient mechanism that only works if PowerShell is available.
|
138
134
|
@set DOWNLOAD_ERROR_STATUS=!ERRORLEVEL!
|
135
|
+
|
139
136
|
@if ERRORLEVEL 1 (
|
140
|
-
@echo Failed
|
137
|
+
@echo Failed PowerShell download with status code !DOWNLOAD_ERROR_STATUS! > "&2"
|
141
138
|
@if !DOWNLOAD_ERROR_STATUS!==0 set DOWNLOAD_ERROR_STATUS=2
|
142
139
|
) else (
|
143
140
|
@rem Sometimes the error level is not set even when the download failed,
|
@@ -146,21 +143,29 @@ cscript /nologo <%= bootstrap_directory %>\wget.vbs /url:"%REMOTE_SOURCE_MSI_URL
|
|
146
143
|
echo Failed download: download completed, but downloaded file not found > "&2"
|
147
144
|
set DOWNLOAD_ERROR_STATUS=2
|
148
145
|
) else (
|
149
|
-
echo Download via
|
146
|
+
echo Download via PowerShell succeeded.
|
150
147
|
)
|
151
148
|
)
|
152
149
|
|
153
150
|
@if NOT %DOWNLOAD_ERROR_STATUS%==0 (
|
154
151
|
@echo Warning: Failed to download "%REMOTE_SOURCE_MSI_URL%" to "%LOCAL_DESTINATION_MSI_PATH%"
|
155
|
-
@echo Warning: Retrying download with
|
152
|
+
@echo Warning: Retrying download with cscript ...
|
156
153
|
|
157
154
|
@if EXIST "%LOCAL_DESTINATION_MSI_PATH%" del /f /q "%LOCAL_DESTINATION_MSI_PATH%"
|
158
155
|
|
159
|
-
@set
|
160
|
-
|
161
|
-
|
156
|
+
@set "REMOTE_SOURCE_MSI_URL=<%= msi_url('%MACHINE_OS%', '%MACHINE_ARCH%') %>"
|
157
|
+
cscript /nologo <%= bootstrap_directory %>\wget.vbs /url:"%REMOTE_SOURCE_MSI_URL%" /path:"%LOCAL_DESTINATION_MSI_PATH%"
|
158
|
+
|
162
159
|
@if NOT ERRORLEVEL 1 (
|
163
|
-
|
160
|
+
@rem Sometimes the error level is not set even when the download failed,
|
161
|
+
@rem so check for the file to be sure it is there.
|
162
|
+
@if NOT EXIST "%LOCAL_DESTINATION_MSI_PATH%" (
|
163
|
+
echo Failed download: download completed, but downloaded file not found > "&2"
|
164
|
+
echo Exiting without bootstrapping due to download failure. > "&2"
|
165
|
+
exit /b 1
|
166
|
+
) else (
|
167
|
+
echo Download via cscript succeeded.
|
168
|
+
)
|
164
169
|
) else (
|
165
170
|
echo Failed to download "%REMOTE_SOURCE_MSI_URL%" with status code !ERRORLEVEL!. > "&2"
|
166
171
|
echo Exiting without bootstrapping due to download failure. > "&2"
|
@@ -183,24 +188,33 @@ cscript /nologo <%= bootstrap_directory %>\wget.vbs /url:"%REMOTE_SOURCE_MSI_URL
|
|
183
188
|
@endlocal
|
184
189
|
|
185
190
|
@echo off
|
191
|
+
|
192
|
+
<% if client_pem -%>
|
193
|
+
> <%= bootstrap_directory %>\client.pem (
|
194
|
+
<%= escape_and_echo(::File.read(::File.expand_path(client_pem))) %>
|
195
|
+
)
|
196
|
+
<% end -%>
|
197
|
+
|
186
198
|
echo Writing validation key...
|
187
199
|
|
200
|
+
<% if validation_key -%>
|
188
201
|
> <%= bootstrap_directory %>\validation.pem (
|
189
|
-
<%= validation_key %>
|
202
|
+
<%= escape_and_echo(validation_key) %>
|
190
203
|
)
|
204
|
+
<% end -%>
|
191
205
|
|
192
206
|
echo Validation key written.
|
193
207
|
@echo on
|
194
208
|
|
195
|
-
<% if @config[:
|
209
|
+
<% if @config[:secret] -%>
|
196
210
|
> <%= bootstrap_directory %>\encrypted_data_bag_secret (
|
197
|
-
<%=
|
211
|
+
<%= secret %>
|
198
212
|
)
|
199
213
|
<% end -%>
|
200
214
|
|
201
|
-
<% unless
|
215
|
+
<% unless trusted_certs_script.empty? -%>
|
202
216
|
mkdir <%= bootstrap_directory %>\trusted_certs
|
203
|
-
<%=
|
217
|
+
<%= trusted_certs_script %>
|
204
218
|
<% end -%>
|
205
219
|
|
206
220
|
<%# Generate Ohai Hints -%>
|
@@ -20,6 +20,8 @@ require 'chef/knife'
|
|
20
20
|
require 'chef/knife/bootstrap'
|
21
21
|
require 'chef/encrypted_data_bag_item'
|
22
22
|
require 'chef/knife/core/windows_bootstrap_context'
|
23
|
+
# Chef 11 PathHelper doesn't have #home
|
24
|
+
#require 'chef/util/path_helper'
|
23
25
|
|
24
26
|
class Chef
|
25
27
|
class Knife
|
@@ -60,16 +62,28 @@ class Chef
|
|
60
62
|
:description => "Avoid a proxy server for the given addresses",
|
61
63
|
:proc => Proc.new { |np| Chef::Config[:knife][:bootstrap_no_proxy] = np }
|
62
64
|
|
65
|
+
# DEPR: Remove this option in Chef 13
|
63
66
|
option :distro,
|
64
67
|
:short => "-d DISTRO",
|
65
68
|
:long => "--distro DISTRO",
|
66
|
-
:description => "Bootstrap a distro using a template",
|
67
|
-
:
|
69
|
+
:description => "Bootstrap a distro using a template. [DEPRECATED] Use --bootstrap-template option instead.",
|
70
|
+
:proc => Proc.new { |v|
|
71
|
+
Chef::Log.warn("[DEPRECATED] -d / --distro option is deprecated. Use --bootstrap-template option instead.")
|
72
|
+
v
|
73
|
+
}
|
74
|
+
|
75
|
+
option :bootstrap_template,
|
76
|
+
:long => "--bootstrap-template TEMPLATE",
|
77
|
+
:description => "Bootstrap Chef using a built-in or custom template. Set to the full path of an erb template or use one of the built-in templates."
|
68
78
|
|
79
|
+
# DEPR: Remove this option in Chef 13
|
69
80
|
option :template_file,
|
70
81
|
:long => "--template-file TEMPLATE",
|
71
|
-
:description => "Full path to location of template to use",
|
72
|
-
:
|
82
|
+
:description => "Full path to location of template to use. [DEPRECATED] Use --bootstrap-template option instead.",
|
83
|
+
:proc => Proc.new { |v|
|
84
|
+
Chef::Log.warn("[DEPRECATED] --template-file option is deprecated. Use --bootstrap-template option instead.")
|
85
|
+
v
|
86
|
+
}
|
73
87
|
|
74
88
|
option :run_list,
|
75
89
|
:short => "-r RUN_LIST",
|
@@ -78,6 +92,15 @@ class Chef
|
|
78
92
|
:proc => lambda { |o| o.split(",") },
|
79
93
|
:default => []
|
80
94
|
|
95
|
+
option :hint,
|
96
|
+
:long => "--hint HINT_NAME[=HINT_FILE]",
|
97
|
+
:description => "Specify Ohai Hint to be set on the bootstrap target. Use multiple --hint options to specify multiple hints.",
|
98
|
+
:proc => Proc.new { |h|
|
99
|
+
Chef::Config[:knife][:hints] ||= Hash.new
|
100
|
+
name, path = h.split("=")
|
101
|
+
Chef::Config[:knife][:hints][name] = path ? Chef::JSONCompat.parse(::File.read(path)) : Hash.new
|
102
|
+
}
|
103
|
+
|
81
104
|
option :first_boot_attributes,
|
82
105
|
:short => "-j JSON_ATTRIBS",
|
83
106
|
:long => "--json-attributes",
|
@@ -85,12 +108,14 @@ class Chef
|
|
85
108
|
:proc => lambda { |o| JSON.parse(o) },
|
86
109
|
:default => {}
|
87
110
|
|
111
|
+
# Mismatch between option 'encrypted_data_bag_secret' and it's long value '--secret' is by design for compatibility
|
88
112
|
option :encrypted_data_bag_secret,
|
89
113
|
:short => "-s SECRET",
|
90
114
|
:long => "--secret ",
|
91
115
|
:description => "The secret key to use to decrypt data bag item values. Will be rendered on the node at c:/chef/encrypted_data_bag_secret and set in the rendered client config.",
|
92
116
|
:default => false
|
93
117
|
|
118
|
+
# Mismatch between option 'encrypted_data_bag_secret_file' and it's long value '--secret-file' is by design for compatibility
|
94
119
|
option :encrypted_data_bag_secret_file,
|
95
120
|
:long => "--secret-file SECRET_FILE",
|
96
121
|
:description => "A file containing the secret key to use to encrypt data bag item values. Will be rendered on the node at c:/chef/encrypted_data_bag_secret and set in the rendered client config."
|
@@ -114,23 +139,51 @@ class Chef
|
|
114
139
|
:long => "--[no-]node-verify-api-cert",
|
115
140
|
:description => "Verify the SSL cert for HTTPS requests to the Chef server API.",
|
116
141
|
:boolean => true
|
142
|
+
|
143
|
+
option :msi_url,
|
144
|
+
:short => "-u URL",
|
145
|
+
:long => "--msi_url URL",
|
146
|
+
:description => "Location of the Chef Client MSI. The default templates will prefer to download from this location. The MSI will be downloaded from chef.io if not provided.",
|
147
|
+
:default => ''
|
148
|
+
|
149
|
+
option :install_as_service,
|
150
|
+
:long => "--install-as-service",
|
151
|
+
:description => "Install chef-client as service in windows machine",
|
152
|
+
:default => false
|
117
153
|
end
|
118
154
|
end
|
119
155
|
|
120
|
-
|
156
|
+
def default_bootstrap_template
|
157
|
+
"windows-chef-client-msi"
|
158
|
+
end
|
159
|
+
|
160
|
+
def bootstrap_template
|
161
|
+
# The order here is important. We want to check if we have the new Chef 12 option is set first.
|
162
|
+
# Knife cloud plugins unfortunately all set a default option for the :distro so it should be at
|
163
|
+
# the end.
|
164
|
+
config[:bootstrap_template] || config[:template_file] || config[:distro] || default_bootstrap_template
|
165
|
+
end
|
166
|
+
|
167
|
+
# TODO: This should go away when CHEF-2193 is fixed
|
121
168
|
def load_template(template=nil)
|
122
169
|
# Are we bootstrapping using an already shipped template?
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
bootstrap_files << Gem.find_files(File.join("chef","knife","bootstrap","#{config[:distro]}.erb"))
|
131
|
-
bootstrap_files.flatten!
|
170
|
+
|
171
|
+
template = bootstrap_template
|
172
|
+
|
173
|
+
# Use the template directly if it's a path to an actual file
|
174
|
+
if File.exists?(template)
|
175
|
+
Chef::Log.debug("Using the specified bootstrap template: #{File.dirname(template)}")
|
176
|
+
return IO.read(template).chomp
|
132
177
|
end
|
133
178
|
|
179
|
+
# Otherwise search the template directories until we find the right one
|
180
|
+
bootstrap_files = []
|
181
|
+
bootstrap_files << File.join(File.dirname(__FILE__), 'bootstrap/templates', "#{template}.erb")
|
182
|
+
bootstrap_files << File.join(Knife.chef_config_dir, "bootstrap", "#{template}.erb") if Chef::Knife.chef_config_dir
|
183
|
+
::Knife::Windows::PathHelper.all_homes('.chef', 'bootstrap', "#{template}.erb") { |p| bootstrap_files << p }
|
184
|
+
bootstrap_files << Gem.find_files(File.join("chef","knife","bootstrap","#{template}.erb"))
|
185
|
+
bootstrap_files.flatten!
|
186
|
+
|
134
187
|
template = Array(bootstrap_files).find do |bootstrap_template|
|
135
188
|
Chef::Log.debug("Looking for bootstrap template in #{File.dirname(bootstrap_template)}")
|
136
189
|
::File.exists?(bootstrap_template)
|
@@ -146,15 +199,24 @@ class Chef
|
|
146
199
|
IO.read(template).chomp
|
147
200
|
end
|
148
201
|
|
202
|
+
def bootstrap_context
|
203
|
+
@bootstrap_context ||= Knife::Core::WindowsBootstrapContext.new(config, config[:run_list], Chef::Config)
|
204
|
+
end
|
205
|
+
|
149
206
|
def render_template(template=nil)
|
150
|
-
if config[:
|
151
|
-
config[:
|
207
|
+
if config[:secret_file]
|
208
|
+
config[:secret] = Chef::EncryptedDataBagItem.load_secret(config[:secret_file])
|
152
209
|
end
|
153
|
-
|
154
|
-
Erubis::Eruby.new(template).evaluate(context)
|
210
|
+
Erubis::Eruby.new(template).evaluate(bootstrap_context)
|
155
211
|
end
|
156
212
|
|
157
213
|
def bootstrap(proto=nil)
|
214
|
+
if Chef::Config[:knife][:encrypted_data_bag_secret_file] || Chef::Config[:knife][:encrypted_data_bag_secret]
|
215
|
+
warn_chef_config_secret_key
|
216
|
+
config[:secret_file] ||= Chef::Config[:knife][:encrypted_data_bag_secret_file]
|
217
|
+
config[:secret] ||= Chef::Config[:knife][:encrypted_data_bag_secret]
|
218
|
+
end
|
219
|
+
|
158
220
|
validate_name_args!
|
159
221
|
|
160
222
|
@node_name = Array(@name_args).first
|
@@ -163,13 +225,32 @@ class Chef
|
|
163
225
|
|
164
226
|
STDOUT.sync = STDERR.sync = true
|
165
227
|
|
228
|
+
if (Chef::Config[:validation_key] && !File.exist?(File.expand_path(Chef::Config[:validation_key])))
|
229
|
+
if Chef::VERSION.split('.').first.to_i == 11
|
230
|
+
ui.error("Unable to find validation key. Please verify your configuration file for validation_key config value.")
|
231
|
+
exit 1
|
232
|
+
end
|
233
|
+
|
234
|
+
unless locate_config_value(:chef_node_name)
|
235
|
+
ui.error("You must pass a node name with -N when bootstrapping with user credentials")
|
236
|
+
exit 1
|
237
|
+
end
|
238
|
+
|
239
|
+
client_builder.run
|
240
|
+
bootstrap_context.client_pem = client_builder.client_path
|
241
|
+
else
|
242
|
+
ui.info("Doing old-style registration with the validation key at #{Chef::Config[:validation_key]}...")
|
243
|
+
ui.info("Delete your validation key in order to use your user credentials instead")
|
244
|
+
ui.info("")
|
245
|
+
end
|
246
|
+
|
166
247
|
wait_for_remote_response( config[:auth_timeout].to_i )
|
167
248
|
ui.info("Bootstrapping Chef on #{ui.color(@node_name, :bold)}")
|
168
249
|
# create a bootstrap.bat file on the node
|
169
250
|
# we have to run the remote commands in 2047 char chunks
|
170
|
-
create_bootstrap_bat_command do |command_chunk
|
251
|
+
create_bootstrap_bat_command do |command_chunk|
|
171
252
|
begin
|
172
|
-
render_command_result = run_command(
|
253
|
+
render_command_result = run_command(command_chunk)
|
173
254
|
ui.error("Batch render command returned #{render_command_result}") if render_command_result != 0
|
174
255
|
render_command_result
|
175
256
|
rescue SystemExit => e
|
@@ -180,6 +261,7 @@ class Chef
|
|
180
261
|
# execute the bootstrap.bat file
|
181
262
|
bootstrap_command_result = run_command(bootstrap_command)
|
182
263
|
ui.error("Bootstrap command returned #{bootstrap_command_result}") if bootstrap_command_result != 0
|
264
|
+
|
183
265
|
bootstrap_command_result
|
184
266
|
end
|
185
267
|
|
@@ -193,20 +275,48 @@ class Chef
|
|
193
275
|
@bootstrap_command ||= "cmd.exe /C #{bootstrap_bat_file}"
|
194
276
|
end
|
195
277
|
|
196
|
-
def
|
197
|
-
|
278
|
+
def bootstrap_render_banner_command(chunk_num)
|
279
|
+
"cmd.exe /C echo Rendering #{bootstrap_bat_file} chunk #{chunk_num}"
|
280
|
+
end
|
281
|
+
|
282
|
+
def escape_windows_batch_characters(line)
|
283
|
+
# TODO: The commands are going to get redirected - do we need to escape &?
|
284
|
+
line.gsub!(/[(<|>)^]/).each{|m| "^#{m}"}
|
285
|
+
end
|
286
|
+
|
287
|
+
def create_bootstrap_bat_command()
|
198
288
|
chunk_num = 0
|
289
|
+
bootstrap_bat = ""
|
290
|
+
banner = bootstrap_render_banner_command(chunk_num += 1)
|
199
291
|
render_template(load_template(config[:bootstrap_template])).each_line do |line|
|
200
|
-
|
201
|
-
|
202
|
-
#
|
203
|
-
|
204
|
-
|
205
|
-
|
292
|
+
escape_windows_batch_characters(line)
|
293
|
+
# We are guaranteed to have a prefix "banner" command that echo's chunk number. We can
|
294
|
+
# confidently prefix every actual command with &&.
|
295
|
+
# TODO: Why does ^\n&& work directly through the commandline but not through SOAP?
|
296
|
+
render_line = " && >> #{bootstrap_bat_file} (echo.#{line.chomp.strip})"
|
297
|
+
# Windows commands are limited to 8191 characters for machines running XP or higher but
|
298
|
+
# this includes the length of environment variables after they have been expanded.
|
299
|
+
# Since we don't actually know how long %TEMP% (and it's used twice - once in the banner
|
300
|
+
# and once in every command redirection), we simply guess and set the max to 5000.
|
301
|
+
# TODO: When a more accurate method is available, fix this.
|
302
|
+
if bootstrap_bat.length + render_line.length + banner.length > 5000
|
303
|
+
# Can't fit it into this chunk? - flush (if necessary) and then try.
|
304
|
+
# Do this first because banner.length might change (e.g. due to an extra digit) and
|
305
|
+
# prevent a fit.
|
306
|
+
unless bootstrap_bat.empty?
|
307
|
+
yield banner + bootstrap_bat
|
308
|
+
bootstrap_bat = ""
|
309
|
+
banner = bootstrap_render_banner_command(chunk_num += 1)
|
310
|
+
end
|
311
|
+
# Will this ever fit?
|
312
|
+
if render_line.length + banner.length > 5000
|
313
|
+
raise "Command in bootstrap template too long by #{render_line.length + banner.length - 5000} characters : #{line}"
|
314
|
+
end
|
206
315
|
end
|
207
|
-
bootstrap_bat <<
|
316
|
+
bootstrap_bat << render_line
|
208
317
|
end
|
209
|
-
|
318
|
+
raise "Bootstrap template was empty! Check #{config[:bootstrap_template]}" if bootstrap_bat.empty?
|
319
|
+
yield banner + bootstrap_bat
|
210
320
|
end
|
211
321
|
|
212
322
|
def bootstrap_bat_file
|
@@ -215,7 +325,21 @@ class Chef
|
|
215
325
|
|
216
326
|
def locate_config_value(key)
|
217
327
|
key = key.to_sym
|
218
|
-
Chef::Config[:knife][key]
|
328
|
+
config[key] || Chef::Config[:knife][key]
|
329
|
+
end
|
330
|
+
|
331
|
+
def warn_chef_config_secret_key
|
332
|
+
ui.info "* " * 40
|
333
|
+
ui.warn(<<-WARNING)
|
334
|
+
\nSpecifying the encrypted data bag secret key using an 'encrypted_data_bag_secret'
|
335
|
+
entry in 'knife.rb' is deprecated. Please use the '--secret' or '--secret-file'
|
336
|
+
options of this command instead.
|
337
|
+
|
338
|
+
#{ui.color('IMPORTANT:', :red, :bold)} In a future version of Chef, this
|
339
|
+
behavior will be removed and any 'encrypted_data_bag_secret' entries in
|
340
|
+
'knife.rb' will be ignored completely.
|
341
|
+
WARNING
|
342
|
+
ui.info "* " * 40
|
219
343
|
end
|
220
344
|
end
|
221
345
|
end
|