winrm 2.2.3 → 2.3.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.
- checksums.yaml +5 -5
- data/.rubocop.yml +13 -1
- data/.travis.yml +10 -11
- data/Gemfile +2 -3
- data/README.md +1 -1
- data/Rakefile +3 -4
- data/appveyor.yml +1 -2
- data/bin/rwinrm +90 -97
- data/changelog.md +5 -0
- data/lib/winrm.rb +3 -5
- data/lib/winrm/connection.rb +84 -86
- data/lib/winrm/connection_opts.rb +90 -91
- data/lib/winrm/exceptions.rb +14 -2
- data/lib/winrm/http/response_handler.rb +127 -96
- data/lib/winrm/http/transport.rb +462 -427
- data/lib/winrm/http/transport_factory.rb +1 -5
- data/lib/winrm/output.rb +1 -2
- data/lib/winrm/psrp/fragment.rb +0 -2
- data/lib/winrm/psrp/message.rb +1 -3
- data/lib/winrm/psrp/message_data.rb +0 -2
- data/lib/winrm/psrp/message_data/base.rb +0 -2
- data/lib/winrm/psrp/message_data/error_record.rb +0 -2
- data/lib/winrm/psrp/message_data/pipeline_host_call.rb +0 -2
- data/lib/winrm/psrp/message_data/pipeline_output.rb +48 -54
- data/lib/winrm/psrp/message_data/pipeline_state.rb +0 -2
- data/lib/winrm/psrp/message_data/runspacepool_host_call.rb +0 -2
- data/lib/winrm/psrp/message_data/runspacepool_state.rb +0 -2
- data/lib/winrm/psrp/message_data/session_capability.rb +0 -2
- data/lib/winrm/psrp/message_defragmenter.rb +2 -2
- data/lib/winrm/psrp/message_factory.rb +2 -3
- data/lib/winrm/psrp/message_fragmenter.rb +1 -3
- data/lib/winrm/psrp/powershell_output_decoder.rb +0 -2
- data/lib/winrm/psrp/receive_response_reader.rb +3 -5
- data/lib/winrm/psrp/uuid.rb +1 -2
- data/lib/winrm/shells/base.rb +6 -4
- data/lib/winrm/shells/cmd.rb +63 -65
- data/lib/winrm/shells/power_shell.rb +207 -202
- data/lib/winrm/shells/retryable.rb +44 -45
- data/lib/winrm/shells/shell_factory.rb +0 -2
- data/lib/winrm/version.rb +1 -3
- data/lib/winrm/wsmv/base.rb +0 -2
- data/lib/winrm/wsmv/cleanup_command.rb +1 -2
- data/lib/winrm/wsmv/close_shell.rb +1 -2
- data/lib/winrm/wsmv/command.rb +2 -3
- data/lib/winrm/wsmv/command_output.rb +2 -3
- data/lib/winrm/wsmv/command_output_decoder.rb +1 -2
- data/lib/winrm/wsmv/configuration.rb +0 -2
- data/lib/winrm/wsmv/create_pipeline.rb +0 -2
- data/lib/winrm/wsmv/create_shell.rb +2 -6
- data/lib/winrm/wsmv/header.rb +213 -215
- data/lib/winrm/wsmv/init_runspace_pool.rb +96 -95
- data/lib/winrm/wsmv/iso8601_duration.rb +0 -2
- data/lib/winrm/wsmv/keep_alive.rb +0 -2
- data/lib/winrm/wsmv/receive_response_reader.rb +128 -126
- data/lib/winrm/wsmv/send_data.rb +0 -2
- data/lib/winrm/wsmv/soap.rb +0 -2
- data/lib/winrm/wsmv/wql_pull.rb +54 -56
- data/lib/winrm/wsmv/wql_query.rb +98 -99
- data/lib/winrm/wsmv/write_stdin.rb +0 -2
- data/tests/integration/auth_timeout_spec.rb +0 -1
- data/tests/integration/cmd_spec.rb +2 -3
- data/tests/integration/issue_59_spec.rb +0 -1
- data/tests/integration/powershell_spec.rb +4 -5
- data/tests/integration/spec_helper.rb +3 -6
- data/tests/integration/transport_spec.rb +0 -1
- data/tests/integration/wql_spec.rb +33 -34
- data/tests/matchers.rb +2 -3
- data/tests/spec/configuration_spec.rb +0 -1
- data/tests/spec/connection_spec.rb +0 -2
- data/tests/spec/exception_spec.rb +0 -1
- data/tests/spec/http/transport_factory_spec.rb +1 -3
- data/tests/spec/http/transport_spec.rb +0 -1
- data/tests/spec/output_spec.rb +4 -3
- data/tests/spec/psrp/fragment_spec.rb +0 -2
- data/tests/spec/psrp/message_data/base_spec.rb +0 -2
- data/tests/spec/psrp/message_data/error_record_spec.rb +0 -2
- data/tests/spec/psrp/message_data/pipeline_host_call_spec.rb +0 -2
- data/tests/spec/psrp/message_data/pipeline_output_spec.rb +0 -2
- data/tests/spec/psrp/message_data/pipeline_state_spec.rb +0 -2
- data/tests/spec/psrp/message_data/runspace_pool_host_call_spec.rb +0 -2
- data/tests/spec/psrp/message_data/runspacepool_state_spec.rb +0 -2
- data/tests/spec/psrp/message_data/session_capability_spec.rb +0 -2
- data/tests/spec/psrp/message_data_spec.rb +0 -2
- data/tests/spec/psrp/message_defragmenter_spec.rb +0 -2
- data/tests/spec/psrp/message_fragmenter_spec.rb +0 -2
- data/tests/spec/psrp/powershell_output_decoder_spec.rb +0 -2
- data/tests/spec/psrp/psrp_message_spec.rb +10 -7
- data/tests/spec/psrp/recieve_response_reader_spec.rb +0 -2
- data/tests/spec/psrp/uuid_spec.rb +2 -2
- data/tests/spec/response_handler_spec.rb +69 -61
- data/tests/spec/shells/base_spec.rb +7 -5
- data/tests/spec/shells/cmd_spec.rb +4 -4
- data/tests/spec/shells/powershell_spec.rb +221 -175
- data/tests/spec/spec_helper.rb +0 -1
- data/tests/spec/stubs/responses/get_omi_command_output_response.xml.erb +23 -0
- data/tests/spec/stubs/responses/get_omi_command_output_response_not_done.xml.erb +24 -0
- data/tests/spec/stubs/responses/get_omi_config_response.xml +45 -0
- data/tests/spec/stubs/responses/get_omi_powershell_keepalive_response.xml.erb +33 -0
- data/tests/spec/stubs/responses/open_shell_omi.xml +43 -0
- data/tests/spec/stubs/responses/soap_fault_omi.xml +31 -0
- data/tests/spec/wsmv/cleanup_command_spec.rb +0 -2
- data/tests/spec/wsmv/close_shell_spec.rb +0 -2
- data/tests/spec/wsmv/command_output_decoder_spec.rb +0 -2
- data/tests/spec/wsmv/command_output_spec.rb +1 -3
- data/tests/spec/wsmv/command_spec.rb +0 -2
- data/tests/spec/wsmv/configuration_spec.rb +0 -2
- data/tests/spec/wsmv/create_pipeline_spec.rb +2 -3
- data/tests/spec/wsmv/create_shell_spec.rb +6 -5
- data/tests/spec/wsmv/init_runspace_pool_spec.rb +38 -36
- data/tests/spec/wsmv/keep_alive_spec.rb +4 -4
- data/tests/spec/wsmv/receive_response_reader_spec.rb +124 -123
- data/tests/spec/wsmv/send_data_spec.rb +4 -4
- data/tests/spec/wsmv/wql_query_spec.rb +11 -13
- data/tests/spec/wsmv/write_stdin_spec.rb +0 -2
- data/winrm.gemspec +11 -12
- metadata +73 -67
@@ -1,202 +1,207 @@
|
|
1
|
-
#
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
require_relative '
|
19
|
-
require_relative '../
|
20
|
-
require_relative '../
|
21
|
-
require_relative '../wsmv/
|
22
|
-
require_relative '../wsmv/
|
23
|
-
require_relative '../wsmv/
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
#
|
49
|
-
# @param
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
#
|
58
|
-
# @
|
59
|
-
# @
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
# - determine the
|
72
|
-
# - subtract the
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
#
|
84
|
-
#
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
command_id
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
shell_id
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
'00000000-0000-0000-0000-000000000000'
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
1
|
+
# Copyright 2016 Shawn Neal <sneal@sneal.net>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'securerandom'
|
16
|
+
require_relative 'base'
|
17
|
+
require_relative '../psrp/message_fragmenter'
|
18
|
+
require_relative '../psrp/receive_response_reader'
|
19
|
+
require_relative '../wsmv/configuration'
|
20
|
+
require_relative '../wsmv/create_pipeline'
|
21
|
+
require_relative '../wsmv/send_data'
|
22
|
+
require_relative '../wsmv/init_runspace_pool'
|
23
|
+
require_relative '../wsmv/keep_alive'
|
24
|
+
|
25
|
+
module WinRM
|
26
|
+
module Shells
|
27
|
+
# Proxy to a remote PowerShell instance
|
28
|
+
class Powershell < Base
|
29
|
+
include WinRM::WSMV::SOAP
|
30
|
+
|
31
|
+
class << self
|
32
|
+
def finalize(connection_opts, transport, shell_id)
|
33
|
+
proc { Powershell.close_shell(connection_opts, transport, shell_id) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def close_shell(connection_opts, transport, shell_id)
|
37
|
+
msg = WinRM::WSMV::CloseShell.new(
|
38
|
+
connection_opts,
|
39
|
+
shell_id: shell_id,
|
40
|
+
shell_uri: WinRM::WSMV::Header::RESOURCE_URI_POWERSHELL
|
41
|
+
)
|
42
|
+
transport.send_request(msg.build)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Create a new powershell shell
|
47
|
+
# @param connection_opts [ConnectionOpts] The WinRM connection options
|
48
|
+
# @param transport [HttpTransport] The WinRM SOAP transport
|
49
|
+
# @param logger [Logger] The logger to log diagnostic messages to
|
50
|
+
def initialize(connection_opts, transport, logger)
|
51
|
+
super
|
52
|
+
@shell_uri = WinRM::WSMV::Header::RESOURCE_URI_POWERSHELL
|
53
|
+
end
|
54
|
+
|
55
|
+
# Runs the specified command
|
56
|
+
# @param command [String] The powershell script to run
|
57
|
+
# @param block [&block] The optional callback for any realtime output
|
58
|
+
# @yield [Message] PSRP Message in response
|
59
|
+
# @yieldreturn [Array<Message>] All messages in response
|
60
|
+
def send_pipeline_command(command, &block)
|
61
|
+
with_command_shell(command) do |shell, cmd|
|
62
|
+
response_reader.read_message(command_output_message(shell, cmd), true, &block)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# calculate the maimum fragment size so that they will be as large as possible yet
|
67
|
+
# no greater than the max_envelope_size_kb on the end point. To calculate this
|
68
|
+
# threshold, we:
|
69
|
+
# - determine the maximum number of bytes accepted on the endpoint
|
70
|
+
# - subtract the non-fragment characters in the SOAP envelope
|
71
|
+
# - determine the number of bytes that could be base64 encded to the above length
|
72
|
+
# - subtract the fragment header bytes (ids, length, etc)
|
73
|
+
def max_fragment_blob_size
|
74
|
+
@max_fragment_blob_size ||= begin
|
75
|
+
fragment_header_length = 21
|
76
|
+
|
77
|
+
begin
|
78
|
+
max_fragment_bytes = (max_envelope_size_kb * 1024) - empty_pipeline_envelope.length
|
79
|
+
base64_deflated(max_fragment_bytes) - fragment_header_length
|
80
|
+
rescue WinRMWSManFault => e
|
81
|
+
# A non administrator user will encounter an access denied
|
82
|
+
# error attempting to query winrm configuration.
|
83
|
+
# we will assin a small default and adjust to a protocol
|
84
|
+
# appropriate max length when that info is available
|
85
|
+
raise unless e.fault_code == '5'
|
86
|
+
|
87
|
+
WinRM::PSRP::MessageFragmenter::DEFAULT_BLOB_LENGTH
|
88
|
+
rescue WinRMSoapFault
|
89
|
+
WinRM::PSRP::MessageFragmenter::DEFAULT_BLOB_LENGTH
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
protected
|
95
|
+
|
96
|
+
def response_reader
|
97
|
+
@response_reader ||= WinRM::PSRP::ReceiveResponseReader.new(transport, logger)
|
98
|
+
end
|
99
|
+
|
100
|
+
def send_command(command, _arguments)
|
101
|
+
command_id = SecureRandom.uuid.to_s.upcase
|
102
|
+
command += "\r\nif (!$?) { if($LASTEXITCODE) { exit $LASTEXITCODE } else { exit 1 } }"
|
103
|
+
message = PSRP::MessageFactory.create_pipeline_message(@runspace_id, command_id, command)
|
104
|
+
fragmenter.fragment(message) do |fragment|
|
105
|
+
command_args = [connection_opts, shell_id, command_id, fragment]
|
106
|
+
if fragment.start_fragment
|
107
|
+
resp_doc = transport.send_request(WinRM::WSMV::CreatePipeline.new(*command_args).build)
|
108
|
+
command_id = REXML::XPath.first(resp_doc, "//*[local-name() = 'CommandId']").text
|
109
|
+
else
|
110
|
+
transport.send_request(WinRM::WSMV::SendData.new(*command_args).build)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
logger.debug("[WinRM] Command created for #{command} with id: #{command_id}")
|
115
|
+
command_id
|
116
|
+
end
|
117
|
+
|
118
|
+
def open_shell
|
119
|
+
@runspace_id = SecureRandom.uuid.to_s.upcase
|
120
|
+
runspace_msg = WinRM::WSMV::InitRunspacePool.new(
|
121
|
+
connection_opts,
|
122
|
+
@runspace_id,
|
123
|
+
open_shell_payload(@runspace_id)
|
124
|
+
)
|
125
|
+
resp_doc = transport.send_request(runspace_msg.build)
|
126
|
+
shell_id = REXML::XPath.first(resp_doc, "//*[@Name='ShellId']").text
|
127
|
+
wait_for_running(shell_id)
|
128
|
+
shell_id
|
129
|
+
end
|
130
|
+
|
131
|
+
def out_streams
|
132
|
+
%w[stdout]
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def base64_deflated(inflated_length)
|
138
|
+
inflated_length / 4 * 3
|
139
|
+
end
|
140
|
+
|
141
|
+
def empty_pipeline_envelope
|
142
|
+
WinRM::WSMV::CreatePipeline.new(
|
143
|
+
connection_opts,
|
144
|
+
'00000000-0000-0000-0000-000000000000',
|
145
|
+
'00000000-0000-0000-0000-000000000000'
|
146
|
+
).build
|
147
|
+
end
|
148
|
+
|
149
|
+
def max_envelope_size_kb
|
150
|
+
# rubocop:disable Layout/RescueEnsureAlignment
|
151
|
+
@max_envelope_size_kb ||= begin
|
152
|
+
config_msg = WinRM::WSMV::Configuration.new(connection_opts)
|
153
|
+
msg = config_msg.build
|
154
|
+
resp_doc = transport.send_request(msg)
|
155
|
+
REXML::XPath.first(resp_doc, "//*[local-name() = 'MaxEnvelopeSizekb']").text.to_i
|
156
|
+
ensure
|
157
|
+
logger.debug("[WinRM] Endpoint doesn't support config request for MaxEnvelopsizekb")
|
158
|
+
end
|
159
|
+
# rubocop:enable Layout/RescueEnsureAlignment
|
160
|
+
end
|
161
|
+
|
162
|
+
def open_shell_payload(shell_id)
|
163
|
+
[
|
164
|
+
WinRM::PSRP::MessageFactory.session_capability_message(shell_id),
|
165
|
+
WinRM::PSRP::MessageFactory.init_runspace_pool_message(shell_id)
|
166
|
+
].map do |message|
|
167
|
+
fragmenter.fragment(message).bytes
|
168
|
+
end.flatten
|
169
|
+
end
|
170
|
+
|
171
|
+
def wait_for_running(shell_id)
|
172
|
+
state = WinRM::PSRP::MessageData::RunspacepoolState::OPENING
|
173
|
+
keepalive_msg = WinRM::WSMV::KeepAlive.new(connection_opts, shell_id)
|
174
|
+
|
175
|
+
# 2 is "openned". if we start issuing commands while in "openning" the runspace
|
176
|
+
# seems to hang
|
177
|
+
until state == WinRM::PSRP::MessageData::RunspacepoolState::OPENED
|
178
|
+
response_reader.read_message(keepalive_msg) do |message|
|
179
|
+
logger.debug("[WinRM] polling for pipeline state. message: #{message.inspect}")
|
180
|
+
parsed = message.parsed_data
|
181
|
+
case parsed
|
182
|
+
when WinRM::PSRP::MessageData::RunspacepoolState
|
183
|
+
state = parsed.runspace_state
|
184
|
+
when WinRM::PSRP::MessageData::SessionCapability
|
185
|
+
# if the user lacks admin privileges, we cannot query the MaxEnvelopeSizeKB
|
186
|
+
# on the server and will assign to a "best effort" default based on protocol version
|
187
|
+
if fragmenter.max_blob_length == WinRM::PSRP::MessageFragmenter::DEFAULT_BLOB_LENGTH
|
188
|
+
fragmenter.max_blob_length = default_protocol_envelope_size(parsed.protocol_version)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Powershell v2.0 has a protocol version of 2.1
|
196
|
+
# which defaults to a 150 MaxEnvelopeSizeKB
|
197
|
+
# later versions default to 500
|
198
|
+
def default_protocol_envelope_size(protocol_version)
|
199
|
+
protocol_version > '2.1' ? 512000 : 153600
|
200
|
+
end
|
201
|
+
|
202
|
+
def fragmenter
|
203
|
+
@fragmenter ||= WinRM::PSRP::MessageFragmenter.new(max_fragment_blob_size)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -1,45 +1,44 @@
|
|
1
|
-
#
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
#
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
1
|
+
# Copyright 2016 Shawn Neal <sneal@sneal.net>
|
2
|
+
# Copyright 2015 Matt Wrock <matt@mattwrock.com>
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require_relative '../exceptions'
|
17
|
+
|
18
|
+
module WinRM
|
19
|
+
module Shells
|
20
|
+
# Shell mixin for retrying an operation
|
21
|
+
module Retryable
|
22
|
+
RETRYABLE_EXCEPTIONS = lambda do
|
23
|
+
[
|
24
|
+
Errno::EACCES, Errno::EADDRINUSE, Errno::ECONNREFUSED, Errno::ETIMEDOUT,
|
25
|
+
Errno::ECONNRESET, Errno::ENETUNREACH, Errno::EHOSTUNREACH, ::WinRM::WinRMWSManFault,
|
26
|
+
::WinRM::WinRMHTTPTransportError, ::WinRM::WinRMAuthorizationError,
|
27
|
+
HTTPClient::KeepAliveDisconnected, HTTPClient::ConnectTimeoutError
|
28
|
+
].freeze
|
29
|
+
end
|
30
|
+
|
31
|
+
# Retries the operation a specified number of times with a delay between
|
32
|
+
# @param retries [Integer] The number of times to retry
|
33
|
+
# @param delay [Integer] The number of seconds to wait between retry attempts
|
34
|
+
def retryable(retries, delay)
|
35
|
+
yield
|
36
|
+
rescue *RETRYABLE_EXCEPTIONS.call
|
37
|
+
raise unless (retries -= 1) > 0
|
38
|
+
|
39
|
+
sleep(delay)
|
40
|
+
retry
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|