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