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

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