knife-windows 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -5
  3. data/.travis.yml +23 -23
  4. data/CHANGELOG.md +104 -101
  5. data/DOC_CHANGES.md +14 -14
  6. data/Gemfile +12 -12
  7. data/LICENSE +201 -201
  8. data/README.md +376 -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 -26
  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 -362
  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 +113 -113
  28. data/lib/chef/knife/winrm_knife_base.rb +298 -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 -95
  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 +154 -150
  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 -151
  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 -178
  52. metadata +2 -16
@@ -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,362 +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
- escape_and_echo(client_rb)
140
- end
141
-
142
- def start_chef
143
- bootstrap_environment_option = bootstrap_environment.nil? ? '' : " -E #{bootstrap_environment}"
144
- start_chef = "SET \"PATH=%PATH%;C:\\ruby\\bin;C:\\opscode\\chef\\bin;C:\\opscode\\chef\\embedded\\bin\"\n"
145
- start_chef << "chef-client -c c:/chef/client.rb -j c:/chef/first-boot.json#{bootstrap_environment_option}\n"
146
- end
147
-
148
- def latest_current_windows_chef_version_query
149
- installer_version_string = nil
150
- if @config[:prerelease]
151
- installer_version_string = "&prerelease=true"
152
- else
153
- chef_version_string = if knife_config[:bootstrap_version]
154
- knife_config[:bootstrap_version]
155
- else
156
- Chef::VERSION.split(".").first
157
- end
158
-
159
- installer_version_string = "&v=#{chef_version_string}"
160
-
161
- # If bootstrapping a pre-release version add the prerelease query string
162
- if chef_version_string.split(".").length > 3
163
- installer_version_string << "&prerelease=true"
164
- end
165
- end
166
-
167
- installer_version_string
168
- end
169
-
170
- def win_wget
171
- # I tried my best to figure out how to properly url decode and switch / to \
172
- # but this is VBScript - so I don't really care that badly.
173
- win_wget = <<-WGET
174
- url = WScript.Arguments.Named("url")
175
- path = WScript.Arguments.Named("path")
176
- proxy = null
177
- '* Vaguely attempt to handle file:// scheme urls by url unescaping and switching all
178
- '* / into \. Also assume that file:/// is a local absolute path and that file://<foo>
179
- '* is possibly a network file path.
180
- If InStr(url, "file://") = 1 Then
181
- url = Unescape(url)
182
- If InStr(url, "file:///") = 1 Then
183
- sourcePath = Mid(url, Len("file:///") + 1)
184
- Else
185
- sourcePath = Mid(url, Len("file:") + 1)
186
- End If
187
- sourcePath = Replace(sourcePath, "/", "\\")
188
-
189
- Set objFSO = CreateObject("Scripting.FileSystemObject")
190
- If objFSO.Fileexists(path) Then objFSO.DeleteFile path
191
- objFSO.CopyFile sourcePath, path, true
192
- Set objFSO = Nothing
193
-
194
- Else
195
- Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP")
196
- Set wshShell = CreateObject( "WScript.Shell" )
197
- Set objUserVariables = wshShell.Environment("USER")
198
-
199
- rem http proxy is optional
200
- rem attempt to read from HTTP_PROXY env var first
201
- On Error Resume Next
202
-
203
- If NOT (objUserVariables("HTTP_PROXY") = "") Then
204
- proxy = objUserVariables("HTTP_PROXY")
205
-
206
- rem fall back to named arg
207
- ElseIf NOT (WScript.Arguments.Named("proxy") = "") Then
208
- proxy = WScript.Arguments.Named("proxy")
209
- End If
210
-
211
- If NOT isNull(proxy) Then
212
- rem setProxy method is only available on ServerXMLHTTP 6.0+
213
- Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP.6.0")
214
- objXMLHTTP.setProxy 2, proxy
215
- End If
216
-
217
- On Error Goto 0
218
-
219
- objXMLHTTP.open "GET", url, false
220
- objXMLHTTP.send()
221
- If objXMLHTTP.Status = 200 Then
222
- Set objADOStream = CreateObject("ADODB.Stream")
223
- objADOStream.Open
224
- objADOStream.Type = 1
225
- objADOStream.Write objXMLHTTP.ResponseBody
226
- objADOStream.Position = 0
227
- Set objFSO = Createobject("Scripting.FileSystemObject")
228
- If objFSO.Fileexists(path) Then objFSO.DeleteFile path
229
- Set objFSO = Nothing
230
- objADOStream.SaveToFile path
231
- objADOStream.Close
232
- Set objADOStream = Nothing
233
- End If
234
- Set objXMLHTTP = Nothing
235
- End If
236
- WGET
237
- escape_and_echo(win_wget)
238
- end
239
-
240
- def win_wget_ps
241
- win_wget_ps = <<-WGET_PS
242
- param(
243
- [String] $remoteUrl,
244
- [String] $localPath
245
- )
246
-
247
- $webClient = new-object System.Net.WebClient;
248
-
249
- $webClient.DownloadFile($remoteUrl, $localPath);
250
- WGET_PS
251
-
252
- escape_and_echo(win_wget_ps)
253
- end
254
-
255
- def install_chef
256
- # The normal install command uses regular double quotes in
257
- # the install command, so request such a string from install_command
258
- install_chef = install_command('"') + "\n" + fallback_install_task_command
259
- end
260
-
261
- def bootstrap_directory
262
- bootstrap_directory = "C:\\chef"
263
- end
264
-
265
- def local_download_path
266
- local_download_path = "%TEMP%\\chef-client-latest.msi"
267
- end
268
-
269
- def msi_url(machine_os=nil, machine_arch=nil, download_context=nil)
270
- # The default msi path has a number of url query parameters - we attempt to substitute
271
- # such parameters in as long as they are provided by the template.
272
-
273
- if @config[:msi_url].nil? || @config[:msi_url].empty?
274
- url = "https://www.chef.io/chef/download?p=windows"
275
- url += "&pv=#{machine_os}" unless machine_os.nil?
276
- url += "&m=#{machine_arch}" unless machine_arch.nil?
277
- url += "&DownloadContext=#{download_context}" unless download_context.nil?
278
- url += latest_current_windows_chef_version_query
279
- else
280
- @config[:msi_url]
281
- end
282
- end
283
-
284
- def first_boot
285
- escape_and_echo(super.to_json)
286
- end
287
-
288
- # escape WIN BATCH special chars
289
- # and prefixes each line with an
290
- # echo
291
- def escape_and_echo(file_contents)
292
- file_contents.gsub(/^(.*)$/, 'echo.\1').gsub(/([(<|>)^])/, '^\1')
293
- end
294
-
295
- private
296
-
297
- def install_command(executor_quote)
298
- if @config[:install_as_service]
299
- "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}"
300
- else
301
- "msiexec /qn /log #{executor_quote}%CHEF_CLIENT_MSI_LOG_PATH%#{executor_quote} /i #{executor_quote}%LOCAL_DESTINATION_MSI_PATH%#{executor_quote}"
302
- end
303
- end
304
-
305
- # Returns a string for copying the trusted certificates on the workstation to the system being bootstrapped
306
- # This string should contain both the commands necessary to both create the files, as well as their content
307
- def trusted_certs_content
308
- content = ""
309
- if @chef_config[:trusted_certs_dir]
310
- Dir.glob(File.join(PathHelper.escape_glob(@chef_config[:trusted_certs_dir]), "*.{crt,pem}")).each do |cert|
311
- content << "> #{bootstrap_directory}/trusted_certs/#{File.basename(cert)} (\n" +
312
- escape_and_echo(IO.read(File.expand_path(cert))) + "\n)\n"
313
- end
314
- end
315
- content
316
- end
317
-
318
- def fallback_install_task_command
319
- # This command will be executed by schtasks.exe in the batch
320
- # code below. To handle tasks that contain arguments that
321
- # need to be double quoted, schtasks allows the use of single
322
- # quotes that will later be converted to double quotes
323
- command = install_command('\'')
324
- <<-EOH
325
- @set MSIERRORCODE=!ERRORLEVEL!
326
- @if ERRORLEVEL 1 (
327
- @echo WARNING: Failed to install Chef Client MSI package in remote context with status code !MSIERRORCODE!.
328
- @echo WARNING: This may be due to a defect in operating system update KB2918614: http://support.microsoft.com/kb/2918614
329
- @set OLDLOGLOCATION="%CHEF_CLIENT_MSI_LOG_PATH%-fail.log"
330
- @move "%CHEF_CLIENT_MSI_LOG_PATH%" "!OLDLOGLOCATION!" > NUL
331
- @echo WARNING: Saving installation log of failure at !OLDLOGLOCATION!
332
- @echo WARNING: Retrying installation with local context...
333
- @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\"
334
-
335
- @if ERRORLEVEL 1 (
336
- @echo ERROR: Failed to create Chef Client installation scheduled task with status code !ERRORLEVEL! > "&2"
337
- ) else (
338
- @echo Successfully created scheduled task to install Chef Client.
339
- @schtasks /run /tn chefclientbootstraptask
340
- @if ERRORLEVEL 1 (
341
- @echo ERROR: Failed to execut Chef Client installation scheduled task with status code !ERRORLEVEL!. > "&2"
342
- ) else (
343
- @echo Successfully started Chef Client installation scheduled task.
344
- @echo Waiting for installation to complete -- this may take a few minutes...
345
- waitfor chefclientinstalldone /t 600
346
- if ERRORLEVEL 1 (
347
- @echo ERROR: Timed out waiting for Chef Client package to install
348
- ) else (
349
- @echo Finished waiting for Chef Client package to install.
350
- )
351
- @schtasks /delete /f /tn chefclientbootstraptask > NUL
352
- )
353
- )
354
- ) else (
355
- @echo Successfully installed Chef Client package.
356
- )
357
- EOH
358
- end
359
- end
360
- end
361
- end
362
- 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