knife-windows 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -5
  3. data/.travis.yml +26 -26
  4. data/CHANGELOG.md +112 -108
  5. data/DOC_CHANGES.md +14 -14
  6. data/Gemfile +12 -12
  7. data/LICENSE +201 -201
  8. data/README.md +391 -385
  9. data/RELEASE_NOTES.md +34 -34
  10. data/Rakefile +21 -21
  11. data/appveyor.yml +42 -42
  12. data/ci.gemfile +15 -15
  13. data/features/knife_help.feature +20 -20
  14. data/features/support/env.rb +5 -5
  15. data/knife-windows.gemspec +25 -25
  16. data/lib/chef/knife/bootstrap/windows-chef-client-msi.erb +233 -247
  17. data/lib/chef/knife/bootstrap_windows_base.rb +449 -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 +372 -366
  21. data/lib/chef/knife/knife_windows_base.rb +33 -33
  22. data/lib/chef/knife/windows_cert_generate.rb +155 -155
  23. data/lib/chef/knife/windows_cert_install.rb +68 -68
  24. data/lib/chef/knife/windows_helper.rb +36 -36
  25. data/lib/chef/knife/windows_listener_create.rb +107 -107
  26. data/lib/chef/knife/winrm.rb +122 -122
  27. data/lib/chef/knife/winrm_base.rb +117 -117
  28. data/lib/chef/knife/winrm_knife_base.rb +305 -303
  29. data/lib/chef/knife/winrm_session.rb +88 -87
  30. data/lib/chef/knife/winrm_shared_options.rb +47 -47
  31. data/lib/chef/knife/wsman_endpoint.rb +44 -44
  32. data/lib/chef/knife/wsman_test.rb +117 -117
  33. data/lib/knife-windows/path_helper.rb +234 -234
  34. data/lib/knife-windows/version.rb +6 -6
  35. data/spec/assets/win_template_rendered_with_bootstrap_install_command.txt +217 -217
  36. data/spec/assets/win_template_rendered_with_bootstrap_install_command_on_12_5_client.txt +217 -217
  37. data/spec/assets/win_template_rendered_without_bootstrap_install_command.txt +329 -329
  38. data/spec/assets/win_template_rendered_without_bootstrap_install_command_on_12_5_client.txt +329 -329
  39. data/spec/assets/win_template_unrendered.txt +246 -246
  40. data/spec/functional/bootstrap_download_spec.rb +241 -234
  41. data/spec/spec_helper.rb +94 -93
  42. data/spec/unit/knife/bootstrap_options_spec.rb +155 -155
  43. data/spec/unit/knife/bootstrap_template_spec.rb +98 -92
  44. data/spec/unit/knife/bootstrap_windows_winrm_spec.rb +341 -295
  45. data/spec/unit/knife/core/windows_bootstrap_context_spec.rb +177 -177
  46. data/spec/unit/knife/windows_cert_generate_spec.rb +90 -90
  47. data/spec/unit/knife/windows_cert_install_spec.rb +51 -51
  48. data/spec/unit/knife/windows_listener_create_spec.rb +76 -76
  49. data/spec/unit/knife/winrm_session_spec.rb +65 -65
  50. data/spec/unit/knife/winrm_spec.rb +516 -516
  51. data/spec/unit/knife/wsman_test_spec.rb +202 -202
  52. metadata +23 -4
@@ -1,87 +1,88 @@
1
- #
2
- # Author:: Steven Murawski <smurawski@chef.io>
3
- # Copyright:: Copyright (c) 2015 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
-
22
- class Chef
23
- class Knife
24
- class WinrmSession
25
- attr_reader :host, :endpoint, :port, :output, :error, :exit_code
26
-
27
- def initialize(options)
28
- configure_proxy
29
-
30
- @host = options[:host]
31
- @port = options[:port]
32
- url = "#{options[:host]}:#{options[:port]}/wsman"
33
- scheme = options[:transport] == :ssl ? 'https' : 'http'
34
- @endpoint = "#{scheme}://#{url}"
35
-
36
- opts = Hash.new
37
- opts = {:user => options[:user], :pass => options[:password], :basic_auth_only => options[:basic_auth_only], :disable_sspi => options[:disable_sspi], :no_ssl_peer_verification => options[:no_ssl_peer_verification], :ssl_peer_fingerprint => options[:ssl_peer_fingerprint]}
38
- options[:transport] == :kerberos ? opts.merge!({:service => options[:service], :realm => options[:realm], :keytab => options[:keytab]}) : opts.merge!({:ca_trust_path => options[:ca_trust_path]})
39
-
40
- Chef::Log.debug("WinRM::WinRMWebService options: #{opts}")
41
- Chef::Log.debug("Endpoint: #{endpoint}")
42
- Chef::Log.debug("Transport: #{options[:transport]}")
43
-
44
- @winrm_session = WinRM::WinRMWebService.new(@endpoint, options[:transport], opts)
45
- @winrm_session.set_timeout(options[:operation_timeout]) if options[:operation_timeout]
46
- end
47
-
48
- def relay_command(command)
49
- remote_id = @winrm_session.open_shell
50
- command_id = @winrm_session.run_command(remote_id, command)
51
- Chef::Log.debug("#{@host}[#{remote_id}] => :run_command[#{command}]")
52
- session_result = get_output(remote_id, command_id)
53
- @winrm_session.cleanup_command(remote_id, command_id)
54
- Chef::Log.debug("#{@host}[#{remote_id}] => :command_cleanup[#{command}]")
55
- @exit_code = session_result[:exitcode]
56
- @winrm_session.close_shell(remote_id)
57
- Chef::Log.debug("#{@host}[#{remote_id}] => :shell_close")
58
- end
59
-
60
- private
61
-
62
- def get_output(remote_id, command_id)
63
- @winrm_session.get_command_output(remote_id, command_id) do |out,error|
64
- print_data(@host, out) if out
65
- print_data(@host, error, :red) if error
66
- end
67
- end
68
-
69
- def print_data(host, data, color = :cyan)
70
- if data =~ /\n/
71
- data.split(/\n/).each { |d| print_data(host, d, color) }
72
- elsif !data.nil?
73
- print Chef::Knife::Winrm.ui.color(host, color)
74
- puts " #{data}"
75
- end
76
- end
77
-
78
- def configure_proxy
79
- if Chef::Config.respond_to?(:export_proxies)
80
- Chef::Config.export_proxies
81
- else
82
- Chef::Application.new.configure_proxy_environment_variables
83
- end
84
- end
85
- end
86
- end
87
- end
1
+ #
2
+ # 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
+
22
+ class Chef
23
+ class Knife
24
+ class WinrmSession
25
+ attr_reader :host, :endpoint, :port, :output, :error, :exit_code
26
+
27
+ def initialize(options)
28
+ configure_proxy
29
+
30
+ @host = options[:host]
31
+ @port = options[:port]
32
+ url = "#{options[:host]}:#{options[:port]}/wsman"
33
+ scheme = options[:transport] == :ssl ? 'https' : 'http'
34
+ @endpoint = "#{scheme}://#{url}"
35
+
36
+ opts = Hash.new
37
+ opts = {:user => options[:user], :pass => options[:password], :basic_auth_only => options[:basic_auth_only], :disable_sspi => options[:disable_sspi], :no_ssl_peer_verification => options[:no_ssl_peer_verification], :ssl_peer_fingerprint => options[:ssl_peer_fingerprint]}
38
+ options[:transport] == :kerberos ? opts.merge!({:service => options[:service], :realm => options[:realm], :keytab => options[:keytab]}) : opts.merge!({:ca_trust_path => options[:ca_trust_path]})
39
+
40
+ Chef::Log.debug("WinRM::WinRMWebService options: #{opts}")
41
+ Chef::Log.debug("Endpoint: #{endpoint}")
42
+ Chef::Log.debug("Transport: #{options[:transport]}")
43
+
44
+ @winrm_session = WinRM::WinRMWebService.new(@endpoint, options[:transport], opts)
45
+ @winrm_session.set_timeout(options[:operation_timeout]) if options[:operation_timeout]
46
+ end
47
+
48
+ def relay_command(command)
49
+ remote_id = @winrm_session.open_shell
50
+ command_id = @winrm_session.run_command(remote_id, command)
51
+ Chef::Log.debug("#{@host}[#{remote_id}] => :run_command[#{command}]")
52
+ session_result = get_output(remote_id, command_id)
53
+ @winrm_session.cleanup_command(remote_id, command_id)
54
+ Chef::Log.debug("#{@host}[#{remote_id}] => :command_cleanup[#{command}]")
55
+ @exit_code = session_result[:exitcode]
56
+ @winrm_session.close_shell(remote_id)
57
+ Chef::Log.debug("#{@host}[#{remote_id}] => :shell_close")
58
+ session_result
59
+ end
60
+
61
+ private
62
+
63
+ def get_output(remote_id, command_id)
64
+ @winrm_session.get_command_output(remote_id, command_id) do |out,error|
65
+ print_data(@host, out) if out
66
+ print_data(@host, error, :red) if error
67
+ end
68
+ end
69
+
70
+ def print_data(host, data, color = :cyan)
71
+ if data =~ /\n/
72
+ data.split(/\n/).each { |d| print_data(host, d, color) }
73
+ elsif !data.nil?
74
+ print Chef::Knife::Winrm.ui.color(host, color)
75
+ puts " #{data}"
76
+ end
77
+ end
78
+
79
+ def configure_proxy
80
+ if Chef::Config.respond_to?(:export_proxies)
81
+ Chef::Config.export_proxies
82
+ else
83
+ Chef::Application.new.configure_proxy_environment_variables
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -1,47 +1,47 @@
1
- #
2
- # Author:: Steven Murawski (<smurawski@chef.io)
3
- # Copyright:: Copyright (c) 2015 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 WinrmSharedOptions
26
-
27
- # Shared command line options for knife winrm and knife wsman test
28
- def self.included(includer)
29
- includer.class_eval do
30
- option :manual,
31
- :short => "-m",
32
- :long => "--manual-list",
33
- :boolean => true,
34
- :description => "QUERY is a space separated list of servers",
35
- :default => false
36
-
37
- option :attribute,
38
- :short => "-a ATTR",
39
- :long => "--attribute ATTR",
40
- :description => "The attribute to use for opening the connection - default is fqdn",
41
- :default => "fqdn"
42
- end
43
- end
44
-
45
- end
46
- end
47
- end
1
+ #
2
+ # 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/knife'
20
+ require 'chef/encrypted_data_bag_item'
21
+ require 'kconv'
22
+
23
+ class Chef
24
+ class Knife
25
+ module WinrmSharedOptions
26
+
27
+ # Shared command line options for knife winrm and knife wsman test
28
+ def self.included(includer)
29
+ includer.class_eval do
30
+ option :manual,
31
+ :short => "-m",
32
+ :long => "--manual-list",
33
+ :boolean => true,
34
+ :description => "QUERY is a space separated list of servers",
35
+ :default => false
36
+
37
+ option :attribute,
38
+ :short => "-a ATTR",
39
+ :long => "--attribute ATTR",
40
+ :description => "The attribute to use for opening the connection - default is fqdn",
41
+ :default => "fqdn"
42
+ end
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -1,44 +1,44 @@
1
- #
2
- # Author:: Steven Murawski (<smurawski@chef.io)
3
- # Copyright:: Copyright (c) 2015 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
- class Chef
20
- class Knife
21
- class WsmanEndpoint
22
- attr_accessor :host
23
- attr_accessor :wsman_port
24
- attr_accessor :wsman_url
25
- attr_accessor :product_version
26
- attr_accessor :protocol_version
27
- attr_accessor :product_vendor
28
- attr_accessor :response_status_code
29
- attr_accessor :error_message
30
-
31
- def initialize(name, port, url)
32
- @host = name
33
- @wsman_port = port
34
- @wsman_url = url
35
- end
36
-
37
- def to_hash
38
- hash = {}
39
- instance_variables.each {|var| hash[var.to_s.delete("@")] = instance_variable_get(var) }
40
- hash
41
- end
42
- end
43
- end
44
- end
1
+ #
2
+ # 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
+ class Chef
20
+ class Knife
21
+ class WsmanEndpoint
22
+ attr_accessor :host
23
+ attr_accessor :wsman_port
24
+ attr_accessor :wsman_url
25
+ attr_accessor :product_version
26
+ attr_accessor :protocol_version
27
+ attr_accessor :product_vendor
28
+ attr_accessor :response_status_code
29
+ attr_accessor :error_message
30
+
31
+ def initialize(name, port, url)
32
+ @host = name
33
+ @wsman_port = port
34
+ @wsman_url = url
35
+ end
36
+
37
+ def to_hash
38
+ hash = {}
39
+ instance_variables.each {|var| hash[var.to_s.delete("@")] = instance_variable_get(var) }
40
+ hash
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,117 +1,117 @@
1
- #
2
- # Author:: Steven Murawski (<smurawski@chef.io>)
3
- # Copyright:: Copyright (c) 2015 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 'httpclient'
20
- require 'chef/knife'
21
- require 'chef/knife/winrm_knife_base'
22
- require 'chef/knife/wsman_endpoint'
23
-
24
- class Chef
25
- class Knife
26
- class WsmanTest < Knife
27
-
28
- include Chef::Knife::WinrmCommandSharedFunctions
29
-
30
- deps do
31
- require 'chef/search/query'
32
- end
33
-
34
- banner "knife wsman test QUERY (options)"
35
-
36
- def run
37
- # pass a dummy password to avoid prompt for password
38
- # but it does nothing
39
- @config[:winrm_password] = 'cute_little_kittens'
40
-
41
- configure_session
42
- verify_wsman_accessiblity_for_nodes
43
- end
44
-
45
- private
46
-
47
- def verify_wsman_accessiblity_for_nodes
48
- error_count = 0
49
- @winrm_sessions.each do |item|
50
- Chef::Log.debug("checking for WSMAN availability at #{item.endpoint}")
51
-
52
- ssl_error = nil
53
- begin
54
- response = post_identity_request(item.endpoint)
55
- ui.msg "Connected successfully to #{item.host} at #{item.endpoint}."
56
- rescue Exception => err
57
- end
58
-
59
- output_object = parse_response(item, response)
60
- output_object.error_message += "\r\nError returned from endpoint: #{err.message}" if err
61
-
62
- unless output_object.error_message.nil?
63
- ui.warn "Failed to connect to #{item.host} at #{item.endpoint}."
64
- if err && err.is_a?(OpenSSL::SSL::SSLError)
65
- ui.warn "Failure due to an issue with SSL; likely cause would be unsuccesful certificate verification."
66
- ui.warn "Either ensure your certificate is valid or use '--winrm-ssl-verify-mode verify_none' to ignore verification failures."
67
- end
68
- error_count += 1
69
- end
70
-
71
- if config[:verbosity] >= 1
72
- output(output_object)
73
- end
74
- end
75
- if error_count > 0
76
- ui.error "Failed to connect to #{error_count} nodes."
77
- exit 1
78
- end
79
- end
80
-
81
- def post_identity_request(endpoint)
82
- xml = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsmid="http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd"><s:Header/><s:Body><wsmid:Identify/></s:Body></s:Envelope>'
83
- header = {
84
- 'WSMANIDENTIFY' => 'unauthenticated',
85
- 'Content-Type' => 'application/soap+xml; charset=UTF-8'
86
- }
87
-
88
- client = HTTPClient.new
89
- client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE if resolve_no_ssl_peer_verification
90
- client.post(endpoint, xml, header)
91
- end
92
-
93
- def parse_response(node, response)
94
- output_object = Chef::Knife::WsmanEndpoint.new(node.host, node.port, node.endpoint)
95
- output_object.response_status_code = response.status_code unless response.nil?
96
-
97
- if response.nil? || response.status_code != 200
98
- output_object.error_message = "No valid WSMan endoint listening at #{node.endpoint}."
99
- else
100
- doc = REXML::Document.new(response.body)
101
- output_object.protocol_version = search_xpath(doc, "//wsmid:ProtocolVersion")
102
- output_object.product_version = search_xpath(doc, "//wsmid:ProductVersion")
103
- output_object.product_vendor = search_xpath(doc, "//wsmid:ProductVendor")
104
- if output_object.protocol_version.to_s.strip.length == 0
105
- output_object.error_message = "Endpoint #{node.endpoint} on #{node.host} does not appear to be a WSMAN endpoint. Response body was #{response.body}"
106
- end
107
- end
108
- output_object
109
- end
110
-
111
- def search_xpath(document, property_name)
112
- result = REXML::XPath.match(document, property_name)
113
- result[0].nil? ? '' : result[0].text
114
- end
115
- end
116
- end
117
- end
1
+ #
2
+ # 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 'httpclient'
20
+ require 'chef/knife'
21
+ require 'chef/knife/winrm_knife_base'
22
+ require 'chef/knife/wsman_endpoint'
23
+
24
+ class Chef
25
+ class Knife
26
+ class WsmanTest < Knife
27
+
28
+ include Chef::Knife::WinrmCommandSharedFunctions
29
+
30
+ deps do
31
+ require 'chef/search/query'
32
+ end
33
+
34
+ banner "knife wsman test QUERY (options)"
35
+
36
+ def run
37
+ # pass a dummy password to avoid prompt for password
38
+ # but it does nothing
39
+ @config[:winrm_password] = 'cute_little_kittens'
40
+
41
+ configure_session
42
+ verify_wsman_accessiblity_for_nodes
43
+ end
44
+
45
+ private
46
+
47
+ def verify_wsman_accessiblity_for_nodes
48
+ error_count = 0
49
+ @winrm_sessions.each do |item|
50
+ Chef::Log.debug("checking for WSMAN availability at #{item.endpoint}")
51
+
52
+ ssl_error = nil
53
+ begin
54
+ response = post_identity_request(item.endpoint)
55
+ ui.msg "Connected successfully to #{item.host} at #{item.endpoint}."
56
+ rescue Exception => err
57
+ end
58
+
59
+ output_object = parse_response(item, response)
60
+ output_object.error_message += "\r\nError returned from endpoint: #{err.message}" if err
61
+
62
+ unless output_object.error_message.nil?
63
+ ui.warn "Failed to connect to #{item.host} at #{item.endpoint}."
64
+ if err && err.is_a?(OpenSSL::SSL::SSLError)
65
+ ui.warn "Failure due to an issue with SSL; likely cause would be unsuccesful certificate verification."
66
+ ui.warn "Either ensure your certificate is valid or use '--winrm-ssl-verify-mode verify_none' to ignore verification failures."
67
+ end
68
+ error_count += 1
69
+ end
70
+
71
+ if config[:verbosity] >= 1
72
+ output(output_object)
73
+ end
74
+ end
75
+ if error_count > 0
76
+ ui.error "Failed to connect to #{error_count} nodes."
77
+ exit 1
78
+ end
79
+ end
80
+
81
+ def post_identity_request(endpoint)
82
+ xml = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsmid="http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd"><s:Header/><s:Body><wsmid:Identify/></s:Body></s:Envelope>'
83
+ header = {
84
+ 'WSMANIDENTIFY' => 'unauthenticated',
85
+ 'Content-Type' => 'application/soap+xml; charset=UTF-8'
86
+ }
87
+
88
+ client = HTTPClient.new
89
+ client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE if resolve_no_ssl_peer_verification
90
+ client.post(endpoint, xml, header)
91
+ end
92
+
93
+ def parse_response(node, response)
94
+ output_object = Chef::Knife::WsmanEndpoint.new(node.host, node.port, node.endpoint)
95
+ output_object.response_status_code = response.status_code unless response.nil?
96
+
97
+ if response.nil? || response.status_code != 200
98
+ output_object.error_message = "No valid WSMan endoint listening at #{node.endpoint}."
99
+ else
100
+ doc = REXML::Document.new(response.body)
101
+ output_object.protocol_version = search_xpath(doc, "//wsmid:ProtocolVersion")
102
+ output_object.product_version = search_xpath(doc, "//wsmid:ProductVersion")
103
+ output_object.product_vendor = search_xpath(doc, "//wsmid:ProductVendor")
104
+ if output_object.protocol_version.to_s.strip.length == 0
105
+ output_object.error_message = "Endpoint #{node.endpoint} on #{node.host} does not appear to be a WSMAN endpoint. Response body was #{response.body}"
106
+ end
107
+ end
108
+ output_object
109
+ end
110
+
111
+ def search_xpath(document, property_name)
112
+ result = REXML::XPath.match(document, property_name)
113
+ result[0].nil? ? '' : result[0].text
114
+ end
115
+ end
116
+ end
117
+ end