knife-winops 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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