knife-winops 2.0.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 (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +30 -0
  5. data/CHANGELOG.md +147 -0
  6. data/DOC_CHANGES.md +22 -0
  7. data/Gemfile +13 -0
  8. data/LICENSE +201 -0
  9. data/README.md +430 -0
  10. data/RELEASE_NOTES.md +17 -0
  11. data/Rakefile +21 -0
  12. data/appveyor.yml +36 -0
  13. data/ci.gemfile +15 -0
  14. data/knife-winops.gemspec +26 -0
  15. data/lib/chef/knife/bootstrap/Chef_bootstrap.erb +44 -0
  16. data/lib/chef/knife/bootstrap/bootstrap.ps1 +134 -0
  17. data/lib/chef/knife/bootstrap/tail.cmd +15 -0
  18. data/lib/chef/knife/bootstrap/windows-chef-client-msi.erb +302 -0
  19. data/lib/chef/knife/bootstrap_windows_base.rb +473 -0
  20. data/lib/chef/knife/bootstrap_windows_ssh.rb +115 -0
  21. data/lib/chef/knife/bootstrap_windows_winrm.rb +102 -0
  22. data/lib/chef/knife/core/windows_bootstrap_context.rb +356 -0
  23. data/lib/chef/knife/knife_windows_base.rb +33 -0
  24. data/lib/chef/knife/windows_cert_generate.rb +155 -0
  25. data/lib/chef/knife/windows_cert_install.rb +68 -0
  26. data/lib/chef/knife/windows_helper.rb +36 -0
  27. data/lib/chef/knife/windows_listener_create.rb +107 -0
  28. data/lib/chef/knife/winrm.rb +127 -0
  29. data/lib/chef/knife/winrm_base.rb +128 -0
  30. data/lib/chef/knife/winrm_knife_base.rb +315 -0
  31. data/lib/chef/knife/winrm_session.rb +101 -0
  32. data/lib/chef/knife/winrm_shared_options.rb +54 -0
  33. data/lib/chef/knife/wsman_endpoint.rb +44 -0
  34. data/lib/chef/knife/wsman_test.rb +118 -0
  35. data/lib/knife-winops/path_helper.rb +242 -0
  36. data/lib/knife-winops/version.rb +6 -0
  37. data/spec/assets/fake_trusted_certs/excluded.txt +2 -0
  38. data/spec/assets/fake_trusted_certs/github.pem +42 -0
  39. data/spec/assets/fake_trusted_certs/google.crt +41 -0
  40. data/spec/assets/win_fake_trusted_cert_script.txt +89 -0
  41. data/spec/dummy_winrm_connection.rb +21 -0
  42. data/spec/functional/bootstrap_download_spec.rb +229 -0
  43. data/spec/spec_helper.rb +93 -0
  44. data/spec/unit/knife/bootstrap_options_spec.rb +164 -0
  45. data/spec/unit/knife/bootstrap_template_spec.rb +98 -0
  46. data/spec/unit/knife/bootstrap_windows_winrm_spec.rb +410 -0
  47. data/spec/unit/knife/core/windows_bootstrap_context_spec.rb +292 -0
  48. data/spec/unit/knife/windows_cert_generate_spec.rb +90 -0
  49. data/spec/unit/knife/windows_cert_install_spec.rb +51 -0
  50. data/spec/unit/knife/windows_listener_create_spec.rb +76 -0
  51. data/spec/unit/knife/winrm_session_spec.rb +101 -0
  52. data/spec/unit/knife/winrm_spec.rb +494 -0
  53. data/spec/unit/knife/wsman_test_spec.rb +209 -0
  54. metadata +157 -0
@@ -0,0 +1,128 @@
1
+ #
2
+ # Original knife-windows author:: Seth Chisamore (<schisamo@chef.io>)
3
+ # Copyright:: Copyright (c) 2011-2016 Chef Software, 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'
20
+ require 'chef/encrypted_data_bag_item'
21
+ require 'kconv'
22
+
23
+ class Chef
24
+ class Knife
25
+ module WinrmBase
26
+
27
+ # It includes supported WinRM authentication protocol.
28
+ WINRM_AUTH_PROTOCOL_LIST ||= %w{basic negotiate kerberos}
29
+
30
+ # :nodoc:
31
+ # Would prefer to do this in a rational way, but can't be done b/c of
32
+ # Mixlib::CLI's design :(
33
+ def self.included(includer)
34
+ includer.class_eval do
35
+
36
+ deps do
37
+ require 'readline'
38
+ require 'chef/json_compat'
39
+ end
40
+
41
+ option :winrm_user,
42
+ :short => "-x USERNAME",
43
+ :long => "--winrm-user USERNAME",
44
+ :description => "The WinRM username",
45
+ :default => "Administrator",
46
+ :proc => Proc.new { |key| Chef::Config[:knife][:winrm_user] = key }
47
+
48
+ option :winrm_password,
49
+ :short => "-P PASSWORD",
50
+ :long => "--winrm-password PASSWORD",
51
+ :description => "The WinRM password",
52
+ :proc => Proc.new { |key| Chef::Config[:knife][:winrm_password] = key }
53
+
54
+ option :winrm_shell,
55
+ :long => "--winrm-shell SHELL",
56
+ :description => "The WinRM shell type. Valid choices are [cmd, powershell, elevated]. 'elevated' runs powershell in a scheduled task",
57
+ :default => :cmd,
58
+ :proc => Proc.new { |shell| shell.to_sym }
59
+
60
+ option :winrm_transport,
61
+ :short => "-w TRANSPORT",
62
+ :long => "--winrm-transport TRANSPORT",
63
+ :description => "The WinRM transport type. Valid choices are [ssl, plaintext]",
64
+ :default => 'plaintext',
65
+ :proc => Proc.new { |transport| Chef::Config[:knife][:winrm_port] = '5986' if transport == 'ssl'
66
+ Chef::Config[:knife][:winrm_transport] = transport }
67
+
68
+ option :winrm_port,
69
+ :short => "-p PORT",
70
+ :long => "--winrm-port PORT",
71
+ :description => "The WinRM port, by default this is '5985' for 'plaintext' and '5986' for 'ssl' winrm transport",
72
+ :default => '5985',
73
+ :proc => Proc.new { |key| Chef::Config[:knife][:winrm_port] = key }
74
+
75
+ option :kerberos_keytab_file,
76
+ :short => "-T KEYTAB_FILE",
77
+ :long => "--keytab-file KEYTAB_FILE",
78
+ :description => "The Kerberos keytab file used for authentication",
79
+ :proc => Proc.new { |keytab| Chef::Config[:knife][:kerberos_keytab_file] = keytab }
80
+
81
+ option :kerberos_realm,
82
+ :short => "-R KERBEROS_REALM",
83
+ :long => "--kerberos-realm KERBEROS_REALM",
84
+ :description => "The Kerberos realm used for authentication",
85
+ :proc => Proc.new { |realm| Chef::Config[:knife][:kerberos_realm] = realm }
86
+
87
+ option :kerberos_service,
88
+ :short => "-S KERBEROS_SERVICE",
89
+ :long => "--kerberos-service KERBEROS_SERVICE",
90
+ :description => "The Kerberos service used for authentication",
91
+ :proc => Proc.new { |service| Chef::Config[:knife][:kerberos_service] = service }
92
+
93
+ option :ca_trust_file,
94
+ :short => "-f CA_TRUST_FILE",
95
+ :long => "--ca-trust-file CA_TRUST_FILE",
96
+ :description => "The Certificate Authority (CA) trust file used for SSL transport",
97
+ :proc => Proc.new { |trust| Chef::Config[:knife][:ca_trust_file] = trust }
98
+
99
+ option :winrm_ssl_verify_mode,
100
+ :long => "--winrm-ssl-verify-mode SSL_VERIFY_MODE",
101
+ :description => "The WinRM peer verification mode. Valid choices are [verify_peer, verify_none]",
102
+ :default => :verify_peer,
103
+ :proc => Proc.new { |verify_mode| verify_mode.to_sym }
104
+
105
+ option :ssl_peer_fingerprint,
106
+ :long => "--ssl-peer-fingerprint FINGERPRINT",
107
+ :description => "ssl Cert Fingerprint to bypass normal cert chain checks"
108
+
109
+ option :winrm_authentication_protocol,
110
+ :long => "--winrm-authentication-protocol AUTHENTICATION_PROTOCOL",
111
+ :description => "The authentication protocol used during WinRM communication. The supported protocols are #{WINRM_AUTH_PROTOCOL_LIST.join(',')}. Default is 'negotiate'.",
112
+ :default => "negotiate",
113
+ :proc => Proc.new { |protocol| Chef::Config[:knife][:winrm_authentication_protocol] = protocol }
114
+
115
+ option :session_timeout,
116
+ :long => "--session-timeout Minutes",
117
+ :description => "The timeout for the client for the maximum length of the WinRM session",
118
+ :default => 30
119
+
120
+ option :winrm_codepage,
121
+ :long => "--winrm-codepage Codepage",
122
+ :description => "The codepage to use for the winrm cmd shell",
123
+ :default => 65001
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,315 @@
1
+ #
2
+ # Original knife-windows author:: Steven Murawski (<smurawski@chef.io)
3
+ # Copyright:: Copyright (c) 2015-2016 Chef Software, 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
+
20
+ require 'chef/knife'
21
+ require 'chef/knife/winrm_base'
22
+ require 'chef/knife/winrm_shared_options'
23
+ require 'chef/knife/knife_windows_base'
24
+
25
+ class Chef
26
+ class Knife
27
+ module WinrmCommandSharedFunctions
28
+
29
+ FAILED_BASIC_HINT ||= "Hint: Please check winrm configuration 'winrm get winrm/config/service' AllowUnencrypted flag on remote server."
30
+ FAILED_NOT_BASIC_HINT ||= <<-eos.gsub /^\s+/, ""
31
+ Hint: Make sure to prefix domain usernames with the correct domain name.
32
+ Hint: Local user names should be prefixed with computer name or IP address.
33
+ EXAMPLE: my_domain\\user_namer
34
+ eos
35
+
36
+ def self.included(includer)
37
+ includer.class_eval do
38
+
39
+ @@ssl_warning_given = false
40
+
41
+ include Chef::Knife::WinrmBase
42
+ include Chef::Knife::WinrmSharedOptions
43
+ include Chef::Knife::KnifeWindowsBase
44
+
45
+ def validate_winrm_options!
46
+ winrm_auth_protocol = locate_config_value(:winrm_authentication_protocol)
47
+
48
+ if ! Chef::Knife::WinrmBase::WINRM_AUTH_PROTOCOL_LIST.include?(winrm_auth_protocol)
49
+ ui.error "Invalid value '#{winrm_auth_protocol}' for --winrm-authentication-protocol option."
50
+ ui.info "Valid values are #{Chef::Knife::WinrmBase::WINRM_AUTH_PROTOCOL_LIST.join(",")}."
51
+ exit 1
52
+ end
53
+
54
+ warn_no_ssl_peer_verification if resolve_no_ssl_peer_verification
55
+ end
56
+
57
+ #Overrides Chef::Knife#configure_session, as that code is tied to the SSH implementation
58
+ #Tracked by Issue # 3042 / https://github.com/chef/chef/issues/3042
59
+ def configure_session
60
+ validate_winrm_options!
61
+ resolve_session_options
62
+ resolve_target_nodes
63
+ session_from_list
64
+ end
65
+
66
+ def resolve_target_nodes
67
+ @list = case config[:manual]
68
+ when true
69
+ @name_args[0].split(" ")
70
+ when false
71
+ r = Array.new
72
+ q = Chef::Search::Query.new
73
+ @action_nodes = q.search(:node, @name_args[0])[0]
74
+ @action_nodes.each do |item|
75
+ i = extract_nested_value(item, config[:attribute])
76
+ r.push(i) unless i.nil?
77
+ end
78
+ r
79
+ end
80
+
81
+ if @list.length == 0
82
+ if @action_nodes.length == 0
83
+ ui.fatal("No nodes returned from search!")
84
+ else
85
+ ui.fatal("#{@action_nodes.length} #{@action_nodes.length > 1 ? "nodes":"node"} found, " +
86
+ "but does not have the required attribute (#{config[:attribute]}) to establish the connection. " +
87
+ "Try setting another attribute to open the connection using --attribute.")
88
+ end
89
+ exit 10
90
+ end
91
+ end
92
+
93
+ # TODO: Copied from Knife::Core:GenericPresenter. Should be extracted
94
+ def extract_nested_value(data, nested_value_spec)
95
+ nested_value_spec.split(".").each do |attr|
96
+ if data.nil?
97
+ nil # don't get no method error on nil
98
+ elsif data.respond_to?(attr.to_sym)
99
+ data = data.send(attr.to_sym)
100
+ elsif data.respond_to?(:[])
101
+ data = data[attr]
102
+ else
103
+ data = begin
104
+ data.send(attr.to_sym)
105
+ rescue NoMethodError
106
+ nil
107
+ end
108
+ end
109
+ end
110
+ ( !data.kind_of?(Array) && data.respond_to?(:to_hash) ) ? data.to_hash : data
111
+ end
112
+
113
+ def run_command(command = '')
114
+ relay_winrm_command(command)
115
+ check_for_errors!
116
+ @exit_code
117
+ end
118
+
119
+ def relay_winrm_command(command)
120
+ Chef::Log.debug(command)
121
+ @session_results = []
122
+
123
+ queue = Queue.new
124
+ @winrm_sessions.each { |s| queue << s }
125
+ # These nils will kill the Threads once no more sessions are left
126
+ locate_config_value(:concurrency).times { queue << nil }
127
+
128
+ threads = []
129
+ locate_config_value(:concurrency).times do
130
+ threads << Thread.new do
131
+ while session = queue.pop
132
+ run_command_in_thread(session, command)
133
+ end
134
+ end
135
+ end
136
+ threads.map(&:join)
137
+ @session_results
138
+ end
139
+
140
+ private
141
+
142
+ def run_command_in_thread(s, command)
143
+ @session_results << s.relay_command(command)
144
+ rescue WinRM::WinRMHTTPTransportError, WinRM::WinRMAuthorizationError => e
145
+ if authorization_error?(e)
146
+ if ! config[:suppress_auth_failure]
147
+ # Display errors if the caller hasn't opted to retry
148
+ ui.error "Failed to authenticate to #{s.host} as #{locate_config_value(:winrm_user)}"
149
+ ui.info "Response: #{e.message}"
150
+ ui.info get_failed_authentication_hint
151
+ raise e
152
+ end
153
+ else
154
+ raise e
155
+ end
156
+ end
157
+
158
+ def get_failed_authentication_hint
159
+ if @session_opts[:basic_auth_only]
160
+ FAILED_BASIC_HINT
161
+ else
162
+ FAILED_NOT_BASIC_HINT
163
+ end
164
+ end
165
+
166
+ def authorization_error?(exception)
167
+ exception.is_a?(WinRM::WinRMAuthorizationError) ||
168
+ exception.message =~ /401/
169
+ end
170
+
171
+ def check_for_errors!
172
+ @exit_code ||= 0
173
+ @winrm_sessions.each do |session|
174
+ session_exit_code = session.exit_code
175
+ unless success_return_codes.include? session_exit_code.to_i
176
+ @exit_code = [@exit_code, session_exit_code.to_i].max
177
+ ui.error "Failed to execute command on #{session.host} return code #{session_exit_code}"
178
+ end
179
+ end
180
+ end
181
+
182
+ def success_return_codes
183
+ #Redundant if the CLI options parsing occurs
184
+ return [0] unless config[:returns]
185
+ return @success_return_codes ||= config[:returns].split(',').collect {|item| item.to_i}
186
+ end
187
+
188
+ def session_from_list
189
+ @list.each do |item|
190
+ Chef::Log.debug("Adding #{item}")
191
+ @session_opts[:host] = item
192
+ create_winrm_session(@session_opts)
193
+ end
194
+ end
195
+
196
+ def create_winrm_session(options={})
197
+ session = Chef::Knife::WinrmSession.new(options)
198
+ @winrm_sessions ||= []
199
+ @winrm_sessions.push(session)
200
+ end
201
+
202
+ def resolve_session_options
203
+ @session_opts = {
204
+ user: resolve_winrm_user,
205
+ password: locate_config_value(:winrm_password),
206
+ port: locate_config_value(:winrm_port),
207
+ operation_timeout: resolve_winrm_session_timeout,
208
+ basic_auth_only: resolve_winrm_basic_auth,
209
+ disable_sspi: resolve_winrm_disable_sspi,
210
+ transport: resolve_winrm_transport,
211
+ no_ssl_peer_verification: resolve_no_ssl_peer_verification,
212
+ ssl_peer_fingerprint: resolve_ssl_peer_fingerprint,
213
+ shell: locate_config_value(:winrm_shell),
214
+ codepage: locate_config_value(:winrm_codepage)
215
+ }
216
+
217
+ if @session_opts[:user] and (not @session_opts[:password])
218
+ @session_opts[:password] = Chef::Config[:knife][:winrm_password] = config[:winrm_password] = get_password
219
+ end
220
+
221
+ if @session_opts[:transport] == :kerberos
222
+ @session_opts.merge!(resolve_winrm_kerberos_options)
223
+ end
224
+
225
+ @session_opts[:ca_trust_path] = locate_config_value(:ca_trust_file) if locate_config_value(:ca_trust_file)
226
+ end
227
+
228
+ def resolve_winrm_user
229
+ user = locate_config_value(:winrm_user)
230
+
231
+ # Prefixing with '.\' when using negotiate
232
+ # to auth user against local machine domain
233
+ if resolve_winrm_basic_auth ||
234
+ resolve_winrm_transport == :kerberos ||
235
+ user.include?("\\") ||
236
+ user.include?("@")
237
+ user
238
+ else
239
+ ".\\#{user}"
240
+ end
241
+ end
242
+
243
+ def resolve_winrm_session_timeout
244
+ #30 min (Default) OperationTimeout for long bootstraps fix for KNIFE_WINDOWS-8
245
+ locate_config_value(:session_timeout).to_i * 60 if locate_config_value(:session_timeout)
246
+ end
247
+
248
+ def resolve_winrm_basic_auth
249
+ locate_config_value(:winrm_authentication_protocol) == "basic"
250
+ end
251
+
252
+ def resolve_winrm_kerberos_options
253
+ kerberos_opts = {}
254
+ kerberos_opts[:keytab] = locate_config_value(:kerberos_keytab_file) if locate_config_value(:kerberos_keytab_file)
255
+ kerberos_opts[:realm] = locate_config_value(:kerberos_realm) if locate_config_value(:kerberos_realm)
256
+ kerberos_opts[:service] = locate_config_value(:kerberos_service) if locate_config_value(:kerberos_service)
257
+ kerberos_opts
258
+ end
259
+
260
+ def resolve_winrm_transport
261
+ transport = locate_config_value(:winrm_transport).to_sym
262
+ if config.any? {|k,v| k.to_s =~ /kerberos/ && !v.nil? }
263
+ transport = :kerberos
264
+ elsif transport != :ssl && negotiate_auth?
265
+ transport = :negotiate
266
+ end
267
+
268
+ transport
269
+ end
270
+
271
+ def resolve_no_ssl_peer_verification
272
+ locate_config_value(:ca_trust_file).nil? && config[:winrm_ssl_verify_mode] == :verify_none && resolve_winrm_transport == :ssl
273
+ end
274
+
275
+ def resolve_ssl_peer_fingerprint
276
+ locate_config_value(:ssl_peer_fingerprint)
277
+ end
278
+
279
+ def resolve_winrm_disable_sspi
280
+ resolve_winrm_transport != :negotiate
281
+ end
282
+
283
+ def get_password
284
+ @password ||= ui.ask("Enter your password: ") { |q| q.echo = false }
285
+ end
286
+
287
+ def negotiate_auth?
288
+ locate_config_value(:winrm_authentication_protocol) == "negotiate"
289
+ end
290
+
291
+ def warn_no_ssl_peer_verification
292
+ if ! @@ssl_warning_given
293
+ @@ssl_warning_given = true
294
+ ui.warn(<<-WARN)
295
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
296
+ SSL validation of HTTPS requests for the WinRM transport is disabled. HTTPS WinRM
297
+ connections are still encrypted, but knife is not able to detect forged replies
298
+ or spoofing attacks.
299
+
300
+ To fix this issue add an entry like this to your knife configuration file:
301
+
302
+ ```
303
+ # Verify all WinRM HTTPS connections (default, recommended)
304
+ knife[:winrm_ssl_verify_mode] = :verify_peer
305
+ ```
306
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
307
+ WARN
308
+ end
309
+ end
310
+
311
+ end
312
+ end
313
+ end
314
+ end
315
+ end
@@ -0,0 +1,101 @@
1
+ #
2
+ # Original knife-windows author:: Steven Murawski <smurawski@chef.io>
3
+ # Copyright:: Copyright (c) 2015-2016 Chef Software, 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/application'
20
+ require 'winrm'
21
+ require 'winrm-elevated'
22
+
23
+ class Chef
24
+ class Knife
25
+ class WinrmSession
26
+ attr_reader :host, :endpoint, :port, :output, :error, :exit_code
27
+
28
+ def initialize(options)
29
+ configure_proxy
30
+
31
+ @host = options[:host]
32
+ @port = options[:port]
33
+ @user = options[:user]
34
+ @shell_args = [ options[:shell] ]
35
+ @shell_args << { codepage: options[:codepage] } if options[:shell] == :cmd
36
+ url = "#{options[:host]}:#{options[:port]}/wsman"
37
+ scheme = options[:transport] == :ssl ? 'https' : 'http'
38
+ @endpoint = "#{scheme}://#{url}"
39
+
40
+ opts = Hash.new
41
+ opts = {
42
+ user: @user,
43
+ password: options[:password],
44
+ basic_auth_only: options[:basic_auth_only],
45
+ disable_sspi: options[:disable_sspi],
46
+ no_ssl_peer_verification: options[:no_ssl_peer_verification],
47
+ ssl_peer_fingerprint: options[:ssl_peer_fingerprint],
48
+ endpoint: endpoint,
49
+ transport: options[:transport]
50
+ }
51
+ options[:transport] == :kerberos ? opts.merge!({:service => options[:service], :realm => options[:realm]}) : opts.merge!({:ca_trust_path => options[:ca_trust_path]})
52
+ opts[:operation_timeout] = options[:operation_timeout] if options[:operation_timeout]
53
+ Chef::Log.debug("WinRM::WinRMWebService options: #{opts}")
54
+ Chef::Log.debug("Endpoint: #{endpoint}")
55
+ Chef::Log.debug("Transport: #{options[:transport]}")
56
+
57
+ @winrm_session = WinRM::Connection.new(opts)
58
+ @winrm_session.logger = Chef::Log
59
+
60
+ transport = @winrm_session.send(:transport)
61
+ http_client = transport.instance_variable_get(:@httpcli)
62
+ Chef::HTTP::DefaultSSLPolicy.new(http_client.ssl_config).set_custom_certs
63
+ end
64
+
65
+ def relay_command(command)
66
+ session_result = WinRM::Output.new
67
+ @winrm_session.shell(*@shell_args) do |shell|
68
+ shell.username = @user.split("\\").last if shell.respond_to?(:username)
69
+ session_result = shell.run(command) do |stdout, stderr|
70
+ print_data(@host, stdout) if stdout
71
+ print_data(@host, stderr, :red) if stderr
72
+ end
73
+ end
74
+ @exit_code = session_result.exitcode
75
+ session_result
76
+ rescue WinRM::WinRMHTTPTransportError, WinRM::WinRMAuthorizationError => e
77
+ @exit_code = 401
78
+ raise e
79
+ end
80
+
81
+ private
82
+
83
+ def print_data(host, data, color = :cyan)
84
+ if data =~ /\n/
85
+ data.split(/\n/).each { |d| print_data(host, d, color) }
86
+ elsif !data.nil?
87
+ print Chef::Knife::Winrm.ui.color(host, color)
88
+ puts " #{data}"
89
+ end
90
+ end
91
+
92
+ def configure_proxy
93
+ if Chef::Config.respond_to?(:export_proxies)
94
+ Chef::Config.export_proxies
95
+ else
96
+ Chef::Application.new.configure_proxy_environment_variables
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end