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,36 +1,36 @@
1
- #
2
- # Author:: Chirag Jog (<chirag@clogeny.com>)
3
- # Copyright:: Copyright (c) 2013 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'
20
- require 'chef/knife/winrm'
21
- require 'chef/knife/bootstrap_windows_ssh'
22
- require 'chef/knife/bootstrap_windows_winrm'
23
- require 'chef/knife/wsman_test'
24
-
25
- class Chef
26
- class Knife
27
- class WindowsHelper < Knife
28
-
29
- banner "#{BootstrapWindowsWinrm.banner}\n" +
30
- "#{BootstrapWindowsSsh.banner}\n" +
31
- "#{Winrm.banner}\n" +
32
- "#{WsmanTest.banner}"
33
- end
34
- end
35
- end
36
-
1
+ #
2
+ # Author:: Chirag Jog (<chirag@clogeny.com>)
3
+ # Copyright:: Copyright (c) 2013 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'
20
+ require 'chef/knife/winrm'
21
+ require 'chef/knife/bootstrap_windows_ssh'
22
+ require 'chef/knife/bootstrap_windows_winrm'
23
+ require 'chef/knife/wsman_test'
24
+
25
+ class Chef
26
+ class Knife
27
+ class WindowsHelper < Knife
28
+
29
+ banner "#{BootstrapWindowsWinrm.banner}\n" +
30
+ "#{BootstrapWindowsSsh.banner}\n" +
31
+ "#{Winrm.banner}\n" +
32
+ "#{WsmanTest.banner}"
33
+ end
34
+ end
35
+ end
36
+
@@ -1,107 +1,107 @@
1
- # Author:: Mukta Aphale (<mukta.aphale@clogeny.com>)
2
- # Copyright:: Copyright (c) 2014 Opscode, Inc.
3
- # License:: Apache License, Version 2.0
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
- require 'chef/knife'
19
- require 'chef/knife/winrm_base'
20
- require 'openssl'
21
-
22
- class Chef
23
- class Knife
24
- class WindowsListenerCreate < Knife
25
-
26
- banner "knife windows listener create (options)"
27
-
28
- option :cert_install,
29
- :short => "-c CERT_PATH",
30
- :long => "--cert-install CERT_PATH",
31
- :description => "Adds specified certificate to the Windows Certificate Store's Local Machine personal store before creating listener."
32
-
33
- option :port,
34
- :short => "-p PORT",
35
- :long => "--port PORT",
36
- :description => "Specify port. Default is 5986",
37
- :default => "5986"
38
-
39
- option :hostname,
40
- :short => "-h HOSTNAME",
41
- :long => "--hostname HOSTNAME",
42
- :description => "Hostname on the listener. Default is blank",
43
- :default => ""
44
-
45
- option :cert_thumbprint,
46
- :short => "-t THUMBPRINT",
47
- :long => "--cert-thumbprint THUMBPRINT",
48
- :description => "Thumbprint of the certificate. Required only if --cert-install option is not used."
49
-
50
- option :cert_passphrase,
51
- :short => "-cp PASSWORD",
52
- :long => "--cert-passphrase PASSWORD",
53
- :description => "Password for certificate."
54
-
55
- def get_cert_passphrase
56
- print "Enter given certificate's passphrase (empty for no passphrase):"
57
- passphrase = STDIN.gets
58
- passphrase.strip
59
- end
60
-
61
- def run
62
- STDOUT.sync = STDERR.sync = true
63
-
64
- if Chef::Platform.windows?
65
- begin
66
- if config[:cert_install]
67
- config[:cert_passphrase] = get_cert_passphrase unless config[:cert_passphrase]
68
- result = %x{powershell.exe -Command " '#{config[:cert_passphrase]}' | certutil -importPFX '#{config[:cert_install]}' AT_KEYEXCHANGE"}
69
- if $?.exitstatus
70
- ui.info "Certificate installed to Certificate Store"
71
- result = %x{powershell.exe -Command " echo (Get-PfxCertificate #{config[:cert_install]}).thumbprint "}
72
- ui.info "Certificate Thumbprint: #{result}"
73
- config[:cert_thumbprint] = result.strip
74
- else
75
- ui.error "Error installing certificate to Certificate Store"
76
- ui.error result
77
- exit 1
78
- end
79
- end
80
-
81
- unless config[:cert_thumbprint]
82
- ui.error "Please specify the --cert-thumbprint"
83
- exit 1
84
- end
85
-
86
- result = %x{winrm create winrm/config/Listener?Address=*+Transport=HTTPS @{Hostname="#{config[:hostname]}";CertificateThumbprint="#{config[:cert_thumbprint]}";Port="#{config[:port]}"}}
87
- Chef::Log.debug result
88
-
89
- if ($?.exitstatus == 0)
90
- ui.info "WinRM listener created with Port: #{config[:port]} and CertificateThumbprint: #{config[:cert_thumbprint]}"
91
- else
92
- ui.error "Error creating WinRM listener. use -VV for more details."
93
- exit 1
94
- end
95
-
96
- rescue => e
97
- puts "ERROR: + #{e}"
98
- end
99
- else
100
- ui.error "WinRM listener can be created on Windows system only"
101
- exit 1
102
- end
103
- end
104
-
105
- end
106
- end
107
- end
1
+ # Author:: Mukta Aphale (<mukta.aphale@clogeny.com>)
2
+ # Copyright:: Copyright (c) 2014 Opscode, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'chef/knife'
19
+ require 'chef/knife/winrm_base'
20
+ require 'openssl'
21
+
22
+ class Chef
23
+ class Knife
24
+ class WindowsListenerCreate < Knife
25
+
26
+ banner "knife windows listener create (options)"
27
+
28
+ option :cert_install,
29
+ :short => "-c CERT_PATH",
30
+ :long => "--cert-install CERT_PATH",
31
+ :description => "Adds specified certificate to the Windows Certificate Store's Local Machine personal store before creating listener."
32
+
33
+ option :port,
34
+ :short => "-p PORT",
35
+ :long => "--port PORT",
36
+ :description => "Specify port. Default is 5986",
37
+ :default => "5986"
38
+
39
+ option :hostname,
40
+ :short => "-h HOSTNAME",
41
+ :long => "--hostname HOSTNAME",
42
+ :description => "Hostname on the listener. Default is blank",
43
+ :default => ""
44
+
45
+ option :cert_thumbprint,
46
+ :short => "-t THUMBPRINT",
47
+ :long => "--cert-thumbprint THUMBPRINT",
48
+ :description => "Thumbprint of the certificate. Required only if --cert-install option is not used."
49
+
50
+ option :cert_passphrase,
51
+ :short => "-cp PASSWORD",
52
+ :long => "--cert-passphrase PASSWORD",
53
+ :description => "Password for certificate."
54
+
55
+ def get_cert_passphrase
56
+ print "Enter given certificate's passphrase (empty for no passphrase):"
57
+ passphrase = STDIN.gets
58
+ passphrase.strip
59
+ end
60
+
61
+ def run
62
+ STDOUT.sync = STDERR.sync = true
63
+
64
+ if Chef::Platform.windows?
65
+ begin
66
+ if config[:cert_install]
67
+ config[:cert_passphrase] = get_cert_passphrase unless config[:cert_passphrase]
68
+ result = %x{powershell.exe -Command " '#{config[:cert_passphrase]}' | certutil -importPFX '#{config[:cert_install]}' AT_KEYEXCHANGE"}
69
+ if $?.exitstatus
70
+ ui.info "Certificate installed to Certificate Store"
71
+ result = %x{powershell.exe -Command " echo (Get-PfxCertificate #{config[:cert_install]}).thumbprint "}
72
+ ui.info "Certificate Thumbprint: #{result}"
73
+ config[:cert_thumbprint] = result.strip
74
+ else
75
+ ui.error "Error installing certificate to Certificate Store"
76
+ ui.error result
77
+ exit 1
78
+ end
79
+ end
80
+
81
+ unless config[:cert_thumbprint]
82
+ ui.error "Please specify the --cert-thumbprint"
83
+ exit 1
84
+ end
85
+
86
+ result = %x{winrm create winrm/config/Listener?Address=*+Transport=HTTPS @{Hostname="#{config[:hostname]}";CertificateThumbprint="#{config[:cert_thumbprint]}";Port="#{config[:port]}"}}
87
+ Chef::Log.debug result
88
+
89
+ if ($?.exitstatus == 0)
90
+ ui.info "WinRM listener created with Port: #{config[:port]} and CertificateThumbprint: #{config[:cert_thumbprint]}"
91
+ else
92
+ ui.error "Error creating WinRM listener. use -VV for more details."
93
+ exit 1
94
+ end
95
+
96
+ rescue => e
97
+ puts "ERROR: + #{e}"
98
+ end
99
+ else
100
+ ui.error "WinRM listener can be created on Windows system only"
101
+ exit 1
102
+ end
103
+ end
104
+
105
+ end
106
+ end
107
+ end
@@ -1,191 +1,212 @@
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'
20
- require 'chef/knife/winrm_knife_base'
21
- require 'chef/knife/windows_cert_generate'
22
- require 'chef/knife/windows_cert_install'
23
- require 'chef/knife/windows_listener_create'
24
- require 'chef/knife/winrm_session'
25
-
26
- class Chef
27
- class Knife
28
- class Winrm < Knife
29
-
30
- include Chef::Knife::WinrmCommandSharedFunctions
31
-
32
- deps do
33
- require 'readline'
34
- require 'chef/search/query'
35
- end
36
-
37
- attr_writer :password
38
-
39
- banner "knife winrm QUERY COMMAND (options)"
40
-
41
- option :returns,
42
- :long => "--returns CODES",
43
- :description => "A comma delimited list of return codes which indicate success",
44
- :default => "0"
45
-
46
- def run
47
- STDOUT.sync = STDERR.sync = true
48
-
49
- configure_session
50
- validate_password
51
- execute_remote_command
52
- end
53
-
54
- def execute_remote_command
55
- begin
56
- case @name_args[1]
57
- when "interactive"
58
- interactive
59
- else
60
- relay_winrm_command(@name_args[1..-1].join(" "))
61
-
62
- if config[:returns]
63
- check_for_errors!
64
- end
65
-
66
- # Knife seems to ignore the return value of this method,
67
- # so we exit to force the process exit code for this
68
- # subcommand if returns is set
69
- exit @exit_code if @exit_code && @exit_code != 0
70
- @exit_code || 0
71
- end
72
- rescue WinRM::WinRMHTTPTransportError => e
73
- case e.message
74
- when /401/
75
- if ! config[:suppress_auth_failure]
76
- # Display errors if the caller hasn't opted to retry
77
- ui.error "Failed to authenticate to #{@name_args[0].split(" ")} as #{locate_config_value(:winrm_user)}"
78
- ui.info "Response: #{e.message}"
79
- ui.info "Hint: Please check winrm configuration 'winrm get winrm/config/service' AllowUnencrypted flag on remote server."
80
- raise e
81
- end
82
- @exit_code = 401
83
- else
84
- raise e
85
- end
86
- end
87
- end
88
-
89
- def relay_winrm_command(command)
90
- Chef::Log.debug(command)
91
- @winrm_sessions.each do |s|
92
- s.relay_command(command)
93
- end
94
- end
95
-
96
- # TODO: Copied from Knife::Core:GenericPresenter. Should be extracted
97
- def extract_nested_value(data, nested_value_spec)
98
- nested_value_spec.split(".").each do |attr|
99
- if data.nil?
100
- nil # don't get no method error on nil
101
- elsif data.respond_to?(attr.to_sym)
102
- data = data.send(attr.to_sym)
103
- elsif data.respond_to?(:[])
104
- data = data[attr]
105
- else
106
- data = begin
107
- data.send(attr.to_sym)
108
- rescue NoMethodError
109
- nil
110
- end
111
- end
112
- end
113
- ( !data.kind_of?(Array) && data.respond_to?(:to_hash) ) ? data.to_hash : data
114
- end
115
-
116
- private
117
-
118
- def interactive
119
- puts "WARN: Deprecated functionality. This will not be supported in future knife-windows releases."
120
- puts "Connected to #{ui.list(session.servers.collect { |s| ui.color(s.host, :cyan) }, :inline, " and ")}"
121
- puts
122
- puts "To run a command on a list of servers, do:"
123
- puts " on SERVER1 SERVER2 SERVER3; COMMAND"
124
- puts " Example: on latte foamy; echo foobar"
125
- puts
126
- puts "To exit interactive mode, use 'quit!'"
127
- puts
128
- while 1
129
- command = read_line
130
- case command
131
- when 'quit!'
132
- puts 'Bye!'
133
- break
134
- when /^on (.+?); (.+)$/
135
- raw_list = $1.split(" ")
136
- server_list = Array.new
137
- @winrm_sessions.each do |session_server|
138
- server_list << session_server if raw_list.include?(session_server.host)
139
- end
140
- command = $2
141
- relay_winrm_command(command, server_list)
142
- else
143
- relay_winrm_command(command)
144
- end
145
- end
146
- end
147
-
148
- def check_for_errors!
149
- @winrm_sessions.each do |session|
150
- session_exit_code = session.exit_code
151
- unless success_return_codes.include? session_exit_code.to_i
152
- @exit_code = session_exit_code.to_i
153
- ui.error "Failed to execute command on #{session.host} return code #{session_exit_code}"
154
- end
155
- end
156
- end
157
-
158
- # Present the prompt and read a single line from the console. It also
159
- # detects ^D and returns "exit" in that case. Adds the input to the
160
- # history, unless the input is empty. Loops repeatedly until a non-empty
161
- # line is input.
162
- def read_line
163
- loop do
164
- command = reader.readline("#{ui.color('knife-winrm>', :bold)} ", true)
165
-
166
- if command.nil?
167
- command = "exit"
168
- puts(command)
169
- else
170
- command.strip!
171
- end
172
-
173
- unless command.empty?
174
- return command
175
- end
176
- end
177
- end
178
-
179
- def reader
180
- Readline
181
- end
182
-
183
- def success_return_codes
184
- #Redundant if the CLI options parsing occurs
185
- return [0] unless config[:returns]
186
- return @success_return_codes ||= config[:returns].split(',').collect {|item| item.to_i}
187
- end
188
- end
189
- end
190
- end
191
-
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'
20
+ require 'chef/knife/winrm_knife_base'
21
+ require 'chef/knife/windows_cert_generate'
22
+ require 'chef/knife/windows_cert_install'
23
+ require 'chef/knife/windows_listener_create'
24
+ require 'chef/knife/winrm_session'
25
+ require 'chef/knife/knife_windows_base'
26
+
27
+ class Chef
28
+ class Knife
29
+ class Winrm < Knife
30
+
31
+ include Chef::Knife::WinrmCommandSharedFunctions
32
+ include Chef::Knife::KnifeWindowsBase
33
+
34
+ FAILED_BASIC_HINT ||= "Hint: Please check winrm configuration 'winrm get winrm/config/service' AllowUnencrypted flag on remote server."
35
+ FAILED_NOT_BASIC_HINT ||= <<-eos.gsub /^\s+/, ""
36
+ Hint: Make sure to prefix domain usernames with the correct domain name.
37
+ Hint: Local user names should be prefixed with computer name or IP address.
38
+ EXAMPLE: my_domain\\user_namer
39
+ eos
40
+
41
+ deps do
42
+ require 'readline'
43
+ require 'chef/search/query'
44
+ end
45
+
46
+ attr_writer :password
47
+
48
+ banner "knife winrm QUERY COMMAND (options)"
49
+
50
+ option :returns,
51
+ :long => "--returns CODES",
52
+ :description => "A comma delimited list of return codes which indicate success",
53
+ :default => "0"
54
+
55
+ def run
56
+ STDOUT.sync = STDERR.sync = true
57
+
58
+ configure_session
59
+ validate_password
60
+ execute_remote_command
61
+ end
62
+
63
+ def execute_remote_command
64
+ begin
65
+ case @name_args[1]
66
+ when "interactive"
67
+ interactive
68
+ else
69
+ relay_winrm_command(@name_args[1..-1].join(" "))
70
+
71
+ if config[:returns]
72
+ check_for_errors!
73
+ end
74
+
75
+ # Knife seems to ignore the return value of this method,
76
+ # so we exit to force the process exit code for this
77
+ # subcommand if returns is set
78
+ exit @exit_code if @exit_code && @exit_code != 0
79
+ @exit_code || 0
80
+ end
81
+ rescue WinRM::WinRMHTTPTransportError, WinRM::WinRMAuthorizationError => e
82
+ if authorization_error?(e)
83
+ if ! config[:suppress_auth_failure]
84
+ # Display errors if the caller hasn't opted to retry
85
+ ui.error "Failed to authenticate to #{@name_args[0].split(" ")} as #{locate_config_value(:winrm_user)}"
86
+ ui.info "Response: #{e.message}"
87
+ ui.info get_failed_authentication_hint
88
+ raise e
89
+ end
90
+ @exit_code = 401
91
+ else
92
+ raise e
93
+ end
94
+ end
95
+ end
96
+
97
+ def relay_winrm_command(command)
98
+ Chef::Log.debug(command)
99
+ @winrm_sessions.each do |s|
100
+ s.relay_command(command)
101
+ end
102
+ end
103
+
104
+ # TODO: Copied from Knife::Core:GenericPresenter. Should be extracted
105
+ def extract_nested_value(data, nested_value_spec)
106
+ nested_value_spec.split(".").each do |attr|
107
+ if data.nil?
108
+ nil # don't get no method error on nil
109
+ elsif data.respond_to?(attr.to_sym)
110
+ data = data.send(attr.to_sym)
111
+ elsif data.respond_to?(:[])
112
+ data = data[attr]
113
+ else
114
+ data = begin
115
+ data.send(attr.to_sym)
116
+ rescue NoMethodError
117
+ nil
118
+ end
119
+ end
120
+ end
121
+ ( !data.kind_of?(Array) && data.respond_to?(:to_hash) ) ? data.to_hash : data
122
+ end
123
+
124
+ private
125
+
126
+ def interactive
127
+ puts "WARN: Deprecated functionality. This will not be supported in future knife-windows releases."
128
+ puts "Connected to #{ui.list(session.servers.collect { |s| ui.color(s.host, :cyan) }, :inline, " and ")}"
129
+ puts
130
+ puts "To run a command on a list of servers, do:"
131
+ puts " on SERVER1 SERVER2 SERVER3; COMMAND"
132
+ puts " Example: on latte foamy; echo foobar"
133
+ puts
134
+ puts "To exit interactive mode, use 'quit!'"
135
+ puts
136
+ while 1
137
+ command = read_line
138
+ case command
139
+ when 'quit!'
140
+ puts 'Bye!'
141
+ break
142
+ when /^on (.+?); (.+)$/
143
+ raw_list = $1.split(" ")
144
+ server_list = Array.new
145
+ @winrm_sessions.each do |session_server|
146
+ server_list << session_server if raw_list.include?(session_server.host)
147
+ end
148
+ command = $2
149
+ relay_winrm_command(command, server_list)
150
+ else
151
+ relay_winrm_command(command)
152
+ end
153
+ end
154
+ end
155
+
156
+ def check_for_errors!
157
+ @winrm_sessions.each do |session|
158
+ session_exit_code = session.exit_code
159
+ unless success_return_codes.include? session_exit_code.to_i
160
+ @exit_code = session_exit_code.to_i
161
+ ui.error "Failed to execute command on #{session.host} return code #{session_exit_code}"
162
+ end
163
+ end
164
+ end
165
+
166
+ # Present the prompt and read a single line from the console. It also
167
+ # detects ^D and returns "exit" in that case. Adds the input to the
168
+ # history, unless the input is empty. Loops repeatedly until a non-empty
169
+ # line is input.
170
+ def read_line
171
+ loop do
172
+ command = reader.readline("#{ui.color('knife-winrm>', :bold)} ", true)
173
+
174
+ if command.nil?
175
+ command = "exit"
176
+ puts(command)
177
+ else
178
+ command.strip!
179
+ end
180
+
181
+ unless command.empty?
182
+ return command
183
+ end
184
+ end
185
+ end
186
+
187
+ def reader
188
+ Readline
189
+ end
190
+
191
+ def authorization_error?(exception)
192
+ exception.is_a?(WinRM::WinRMAuthorizationError) ||
193
+ exception.message =~ /401/
194
+ end
195
+
196
+ def success_return_codes
197
+ #Redundant if the CLI options parsing occurs
198
+ return [0] unless config[:returns]
199
+ return @success_return_codes ||= config[:returns].split(',').collect {|item| item.to_i}
200
+ end
201
+
202
+ def get_failed_authentication_hint
203
+ if @session_opts[:basic_auth_only]
204
+ FAILED_BASIC_HINT
205
+ else
206
+ FAILED_NOT_BASIC_HINT
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end
212
+