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,72 +1,81 @@
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 'winrm'
20
-
21
- class Chef
22
- class Knife
23
- class WinrmSession
24
- attr_reader :host, :endpoint, :port, :output, :error, :exit_code
25
- def initialize(options)
26
- @host = options[:host]
27
- @port = options[:port]
28
- url = "#{options[:host]}:#{options[:port]}/wsman"
29
- scheme = options[:transport] == :ssl ? 'https' : 'http'
30
- @endpoint = "#{scheme}://#{url}"
31
- opts = Hash.new
32
- 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]}
33
-
34
- options[:transport] == :kerberos ? opts.merge!({:service => options[:service], :realm => options[:realm], :keytab => options[:keytab]}) : opts.merge!({:ca_trust_path => options[:ca_trust_path]})
35
-
36
- Chef::Log.debug("WinRM::WinRMWebService options: #{opts}")
37
- Chef::Log.debug("Endpoint: #{endpoint}")
38
- Chef::Log.debug("Transport: #{options[:transport]}")
39
- @winrm_session = WinRM::WinRMWebService.new(@endpoint, options[:transport], opts)
40
- @winrm_session.set_timeout(options[:operation_timeout]) if options[:operation_timeout]
41
- end
42
-
43
- def relay_command(command)
44
- remote_id = @winrm_session.open_shell
45
- command_id = @winrm_session.run_command(remote_id, command)
46
- Chef::Log.debug("#{@host}[#{remote_id}] => :run_command[#{command}]")
47
- session_result = get_output(remote_id, command_id)
48
- @winrm_session.cleanup_command(remote_id, command_id)
49
- Chef::Log.debug("#{@host}[#{remote_id}] => :command_cleanup[#{command}]")
50
- @exit_code = session_result[:exitcode]
51
- @winrm_session.close_shell(remote_id)
52
- Chef::Log.debug("#{@host}[#{remote_id}] => :shell_close")
53
- end
54
-
55
- def get_output(remote_id, command_id)
56
- @winrm_session.get_command_output(remote_id, command_id) do |out,error|
57
- print_data(@host, out) if out
58
- print_data(@host, error, :red) if error
59
- end
60
- end
61
-
62
- def print_data(host, data, color = :cyan)
63
- if data =~ /\n/
64
- data.split(/\n/).each { |d| print_data(host, d, color) }
65
- elsif !data.nil?
66
- print Chef::Knife::Winrm.ui.color(host, color)
67
- puts " #{data}"
68
- end
69
- end
70
- end
71
- end
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 'winrm'
20
+
21
+ class Chef
22
+ class Knife
23
+ class WinrmSession
24
+ attr_reader :host, :endpoint, :port, :output, :error, :exit_code
25
+
26
+ def initialize(options)
27
+ @host = options[:host]
28
+ @port = options[:port]
29
+ url = "#{options[:host]}:#{options[:port]}/wsman"
30
+ scheme = options[:transport] == :ssl ? 'https' : 'http'
31
+ @endpoint = "#{scheme}://#{url}"
32
+
33
+ opts = Hash.new
34
+ 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]}
35
+ options[:transport] == :kerberos ? opts.merge!({:service => options[:service], :realm => options[:realm], :keytab => options[:keytab]}) : opts.merge!({:ca_trust_path => options[:ca_trust_path]})
36
+
37
+ Chef::Log.debug("WinRM::WinRMWebService options: #{opts}")
38
+ Chef::Log.debug("Endpoint: #{endpoint}")
39
+ Chef::Log.debug("Transport: #{options[:transport]}")
40
+
41
+ WinrmSession.load_windows_specific_gems if options[:transport] == :sspinegotiate
42
+ @winrm_session = WinRM::WinRMWebService.new(@endpoint, options[:transport], opts)
43
+ @winrm_session.set_timeout(options[:operation_timeout]) if options[:operation_timeout]
44
+ end
45
+
46
+ def relay_command(command)
47
+ remote_id = @winrm_session.open_shell
48
+ command_id = @winrm_session.run_command(remote_id, command)
49
+ Chef::Log.debug("#{@host}[#{remote_id}] => :run_command[#{command}]")
50
+ session_result = get_output(remote_id, command_id)
51
+ @winrm_session.cleanup_command(remote_id, command_id)
52
+ Chef::Log.debug("#{@host}[#{remote_id}] => :command_cleanup[#{command}]")
53
+ @exit_code = session_result[:exitcode]
54
+ @winrm_session.close_shell(remote_id)
55
+ Chef::Log.debug("#{@host}[#{remote_id}] => :shell_close")
56
+ end
57
+
58
+ def get_output(remote_id, command_id)
59
+ @winrm_session.get_command_output(remote_id, command_id) do |out,error|
60
+ print_data(@host, out) if out
61
+ print_data(@host, error, :red) if error
62
+ end
63
+ end
64
+
65
+ def print_data(host, data, color = :cyan)
66
+ if data =~ /\n/
67
+ data.split(/\n/).each { |d| print_data(host, d, color) }
68
+ elsif !data.nil?
69
+ print Chef::Knife::Winrm.ui.color(host, color)
70
+ puts " #{data}"
71
+ end
72
+ end
73
+
74
+ def self.load_windows_specific_gems
75
+ #checking for windows in case testing on linux
76
+ require 'winrm-s'
77
+ Chef::Log.debug("Applied 'winrm-s' monkey patch and trying WinRM communication with 'sspinegotiate'")
78
+ end
79
+ end
80
+ end
72
81
  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 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 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,96 +1,96 @@
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 'nokogiri'
21
- require 'chef/knife'
22
- require 'chef/knife/winrm_knife_base'
23
- require 'chef/knife/wsman_endpoint'
24
- require 'pry'
25
-
26
- class Chef
27
- class Knife
28
- class WsmanTest < Knife
29
-
30
- include Chef::Knife::WinrmCommandSharedFunctions
31
-
32
- deps do
33
- require 'chef/search/query'
34
- end
35
-
36
- banner "knife wsman test QUERY (options)"
37
-
38
- def run
39
- @config[:winrm_authentication_protocol] = 'basic'
40
- configure_session
41
- verify_wsman_accessiblity_for_nodes
42
- end
43
-
44
- def verify_wsman_accessiblity_for_nodes
45
- error_count = 0
46
- @winrm_sessions.each do |item|
47
- Chef::Log.debug("checking for WSMAN availability at #{item.endpoint}")
48
-
49
- 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>'
50
- header = {
51
- 'WSMANIDENTIFY' => 'unauthenticated',
52
- 'Content-Type' => 'application/soap+xml; charset=UTF-8'
53
- }
54
- output_object = Chef::Knife::WsmanEndpoint.new(item.host, item.port, item.endpoint)
55
- error_message = nil
56
- begin
57
- client = HTTPClient.new
58
- response = client.post(item.endpoint, xml, header)
59
- rescue Exception => e
60
- error_message = e.message
61
- else
62
- ui.msg "Connected successfully to #{item.host} at #{item.endpoint}."
63
- output_object.response_status_code = response.status_code
64
- end
65
-
66
- if response.nil? || output_object.response_status_code != 200
67
- error_message = "No valid WSMan endoint listening at #{item.endpoint}."
68
- else
69
- doc = Nokogiri::XML response.body
70
- namespace = 'http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd'
71
- output_object.protocol_version = doc.xpath('//wsmid:ProtocolVersion', 'wsmid' => namespace).text
72
- output_object.product_version = doc.xpath('//wsmid:ProductVersion', 'wsmid' => namespace).text
73
- output_object.product_vendor = doc.xpath('//wsmid:ProductVendor', 'wsmid' => namespace).text
74
- if output_object.protocol_version.to_s.strip.length == 0
75
- error_message = "Endpoint #{item.endpoint} on #{item.host} does not appear to be a WSMAN endpoint."
76
- end
77
- end
78
-
79
- unless error_message.nil?
80
- ui.warn "Failed to connect to #{item.host} at #{item.endpoint}."
81
- output_object.error_message = error_message
82
- error_count += 1
83
- end
84
-
85
- if config[:verbosity] >= 1
86
- output(output_object)
87
- end
88
- end
89
- if error_count > 0
90
- ui.error "Failed to connect to #{error_count} nodes."
91
- exit 1
92
- end
93
- end
94
- end
95
- end
96
- end
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 'nokogiri'
21
+ require 'chef/knife'
22
+ require 'chef/knife/winrm_knife_base'
23
+ require 'chef/knife/wsman_endpoint'
24
+ require 'pry'
25
+
26
+ class Chef
27
+ class Knife
28
+ class WsmanTest < Knife
29
+
30
+ include Chef::Knife::WinrmCommandSharedFunctions
31
+
32
+ deps do
33
+ require 'chef/search/query'
34
+ end
35
+
36
+ banner "knife wsman test QUERY (options)"
37
+
38
+ def run
39
+ @config[:winrm_authentication_protocol] = 'basic'
40
+ configure_session
41
+ verify_wsman_accessiblity_for_nodes
42
+ end
43
+
44
+ def verify_wsman_accessiblity_for_nodes
45
+ error_count = 0
46
+ @winrm_sessions.each do |item|
47
+ Chef::Log.debug("checking for WSMAN availability at #{item.endpoint}")
48
+
49
+ 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>'
50
+ header = {
51
+ 'WSMANIDENTIFY' => 'unauthenticated',
52
+ 'Content-Type' => 'application/soap+xml; charset=UTF-8'
53
+ }
54
+ output_object = Chef::Knife::WsmanEndpoint.new(item.host, item.port, item.endpoint)
55
+ error_message = nil
56
+ begin
57
+ client = HTTPClient.new
58
+ response = client.post(item.endpoint, xml, header)
59
+ rescue Exception => e
60
+ error_message = e.message
61
+ else
62
+ ui.msg "Connected successfully to #{item.host} at #{item.endpoint}."
63
+ output_object.response_status_code = response.status_code
64
+ end
65
+
66
+ if response.nil? || output_object.response_status_code != 200
67
+ error_message = "No valid WSMan endoint listening at #{item.endpoint}."
68
+ else
69
+ doc = Nokogiri::XML response.body
70
+ namespace = 'http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd'
71
+ output_object.protocol_version = doc.xpath('//wsmid:ProtocolVersion', 'wsmid' => namespace).text
72
+ output_object.product_version = doc.xpath('//wsmid:ProductVersion', 'wsmid' => namespace).text
73
+ output_object.product_vendor = doc.xpath('//wsmid:ProductVendor', 'wsmid' => namespace).text
74
+ if output_object.protocol_version.to_s.strip.length == 0
75
+ error_message = "Endpoint #{item.endpoint} on #{item.host} does not appear to be a WSMAN endpoint."
76
+ end
77
+ end
78
+
79
+ unless error_message.nil?
80
+ ui.warn "Failed to connect to #{item.host} at #{item.endpoint}."
81
+ output_object.error_message = error_message
82
+ error_count += 1
83
+ end
84
+
85
+ if config[:verbosity] >= 1
86
+ output(output_object)
87
+ end
88
+ end
89
+ if error_count > 0
90
+ ui.error "Failed to connect to #{error_count} nodes."
91
+ exit 1
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end