remotus 1.1.0 → 1.2.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 +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +10 -7
- data/lib/remotus/host_pool.rb +6 -2
- data/lib/remotus/pool.rb +3 -0
- data/lib/remotus/ssh_connection.rb +64 -9
- data/lib/remotus/version.rb +1 -1
- data/lib/remotus/winrm_connection.rb +22 -4
- data/lib/remotus.rb +3 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a1fb83a5d4a7a15d98860a8342f71c5377f5c91ec842883a62cc2b6678baa96
|
4
|
+
data.tar.gz: db221756c55c43a5c0492cf8668c36e07f6e58d323b9a1b83b3688a0a9c8c92c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2a57cbf28230b41b64c6e084511fa45536c8b020c7425b89d504e5ae764b16429911f5a2ff5458b2168b7ae46355e66c14279dad780d8ca38b525da66bd1694
|
7
|
+
data.tar.gz: 0bd543003bde4641d2d9527b88a72a550e700bcc65c73b76c2ef5ff0b2811c1eaae8013bb9bff34c5802b1e8fc2aa754557534908672c25eb814c8a281169788
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## [1.2.0] - 2023-10-23
|
2
|
+
* Add `:ip` option to connection methods to accommodate credential stores that require the hostname where DNS is not available.
|
3
|
+
|
4
|
+
## [1.1.1] - 2023-05-26
|
5
|
+
* Handle close failures and improve logging around connection status.
|
6
|
+
|
1
7
|
## [1.1.0] - 2023-05-25
|
2
8
|
* Improve exponential backoff during SSH retries.
|
3
9
|
* Force connection close on IOError (closed stream).
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
remotus (1.
|
4
|
+
remotus (1.2.0)
|
5
5
|
connection_pool (~> 2.4)
|
6
6
|
net-scp (~> 4.0)
|
7
7
|
net-ssh (~> 7.1)
|
@@ -15,10 +15,10 @@ GEM
|
|
15
15
|
specs:
|
16
16
|
ast (2.4.2)
|
17
17
|
builder (3.2.4)
|
18
|
-
connection_pool (2.4.
|
18
|
+
connection_pool (2.4.1)
|
19
19
|
diff-lcs (1.5.0)
|
20
20
|
erubi (1.12.0)
|
21
|
-
ffi (1.
|
21
|
+
ffi (1.16.3)
|
22
22
|
gssapi (1.3.1)
|
23
23
|
ffi (>= 1.0.1)
|
24
24
|
gyoku (1.4.0)
|
@@ -33,7 +33,7 @@ GEM
|
|
33
33
|
multi_json (1.15.0)
|
34
34
|
net-scp (4.0.0)
|
35
35
|
net-ssh (>= 2.6.5, < 8.0.0)
|
36
|
-
net-ssh (7.
|
36
|
+
net-ssh (7.2.0)
|
37
37
|
net-ssh-gateway (2.0.0)
|
38
38
|
net-ssh (>= 4.0.0)
|
39
39
|
nori (2.6.0)
|
@@ -57,7 +57,7 @@ GEM
|
|
57
57
|
diff-lcs (>= 1.2.0, < 2.0)
|
58
58
|
rspec-support (~> 3.12.0)
|
59
59
|
rspec-support (3.12.0)
|
60
|
-
rubocop (1.
|
60
|
+
rubocop (1.51.0)
|
61
61
|
json (~> 2.3)
|
62
62
|
parallel (~> 1.10)
|
63
63
|
parser (>= 3.2.0.0)
|
@@ -67,15 +67,18 @@ GEM
|
|
67
67
|
rubocop-ast (>= 1.28.0, < 2.0)
|
68
68
|
ruby-progressbar (~> 1.7)
|
69
69
|
unicode-display_width (>= 2.4.0, < 3.0)
|
70
|
-
rubocop-ast (1.28.
|
70
|
+
rubocop-ast (1.28.1)
|
71
71
|
parser (>= 3.2.1.0)
|
72
72
|
rubocop-capybara (2.18.0)
|
73
73
|
rubocop (~> 1.41)
|
74
|
+
rubocop-factory_bot (2.23.1)
|
75
|
+
rubocop (~> 1.33)
|
74
76
|
rubocop-rake (0.6.0)
|
75
77
|
rubocop (~> 1.0)
|
76
|
-
rubocop-rspec (2.
|
78
|
+
rubocop-rspec (2.22.0)
|
77
79
|
rubocop (~> 1.33)
|
78
80
|
rubocop-capybara (~> 2.17)
|
81
|
+
rubocop-factory_bot (~> 2.22)
|
79
82
|
ruby-progressbar (1.13.0)
|
80
83
|
rubyntlm (0.6.3)
|
81
84
|
rubyzip (2.3.2)
|
data/lib/remotus/host_pool.rb
CHANGED
@@ -42,12 +42,16 @@ module Remotus
|
|
42
42
|
# @param [Hash] metadata metadata for this connection. Useful for providing additional information to various authentication stores
|
43
43
|
# should be specified using snake_case symbol keys. If keys are not snake_case, they will be converted.
|
44
44
|
#
|
45
|
+
# To connect to a host via IP, the following metadata entry can be provided to the host pool:
|
46
|
+
# :ip
|
47
|
+
#
|
45
48
|
# To configure a connection gateway, the following metadata entries can be provided to the host pool:
|
46
|
-
# :gateway_host
|
49
|
+
# :gateway_host (required to use gateway)
|
47
50
|
# :gateway_port
|
48
51
|
# :gateway_metadata
|
52
|
+
# :gateway_ip
|
49
53
|
#
|
50
|
-
# These function similarly to the host, port,
|
54
|
+
# These function similarly to the host, port, host_pool metadata, and ip fields.
|
51
55
|
#
|
52
56
|
def initialize(host, size: DEFAULT_POOL_SIZE, timeout: DEFAULT_EXPIRATION_SECONDS, port: nil, proto: nil, **metadata)
|
53
57
|
Remotus.logger.debug { "Creating host pool for #{host}" }
|
data/lib/remotus/pool.rb
CHANGED
@@ -20,6 +20,9 @@ module Remotus
|
|
20
20
|
# @option options [Integer] :timeout amount of time to wait for a connection from the pool
|
21
21
|
# @option options [Integer] :port port to use for the connection
|
22
22
|
# @option options [Symbol] :proto protocol to use for the connection (:winrm, :ssh), must be specified if port is specified
|
23
|
+
# @option options [String] :ip IP to use for the connection, preferred over the hostname if set.
|
24
|
+
# This should be used if the hostname is required for credential retrieval
|
25
|
+
# but the hostname cannot be resolved by DNS.
|
23
26
|
#
|
24
27
|
# @return [Remotus::HostPool] Host pool for the given host
|
25
28
|
#
|
@@ -74,13 +74,18 @@ module Remotus
|
|
74
74
|
# @param [String] host hostname
|
75
75
|
# @param [Integer] port remote port
|
76
76
|
# @param [Remotus::HostPool] host_pool associated host pool
|
77
|
+
# To connect to a host via IP, the following metadata
|
78
|
+
# entry can be provided to the host pool:
|
79
|
+
# :ip
|
80
|
+
#
|
77
81
|
# To configure the gateway, the following metadata
|
78
82
|
# entries can be provided to the host pool:
|
79
83
|
# :gateway_host
|
80
84
|
# :gateway_port
|
81
85
|
# :gateway_metadata
|
86
|
+
# :gateway_ip
|
82
87
|
#
|
83
|
-
# These function similarly to the host, port,
|
88
|
+
# These function similarly to the host, port, host_pool metadata, and ip fields.
|
84
89
|
#
|
85
90
|
def initialize(host, port = REMOTE_PORT, host_pool: nil)
|
86
91
|
Remotus.logger.debug { "Creating SshConnection #{object_id} for #{host}" }
|
@@ -143,10 +148,10 @@ module Remotus
|
|
143
148
|
|
144
149
|
Remotus.logger.debug { "Initializing SSH gateway connection to #{gateway_cred.user}@#{@gateway.host}:#{gateway_options[:port]}" }
|
145
150
|
|
146
|
-
@gateway.connection = Net::SSH::Gateway.new(
|
147
|
-
@connection = @gateway.connection.ssh(
|
151
|
+
@gateway.connection = Net::SSH::Gateway.new(remote_gateway_host, gateway_cred.user, **gateway_options)
|
152
|
+
@connection = @gateway.connection.ssh(remote_host, target_cred.user, **target_options)
|
148
153
|
else
|
149
|
-
@connection = Net::SSH.start(
|
154
|
+
@connection = Net::SSH.start(remote_host, target_cred.user, **target_options)
|
150
155
|
end
|
151
156
|
end
|
152
157
|
|
@@ -154,9 +159,21 @@ module Remotus
|
|
154
159
|
# Closes the current SSH connection if it is active
|
155
160
|
#
|
156
161
|
def close
|
157
|
-
|
162
|
+
Remotus.logger.debug { "Closing SSH connection." }
|
163
|
+
|
164
|
+
begin
|
165
|
+
@connection&.close
|
166
|
+
rescue StandardError => e
|
167
|
+
Remotus.logger.warn { "Failed to close existing SSH connection with error #{e}" }
|
168
|
+
end
|
169
|
+
|
170
|
+
begin
|
171
|
+
@gateway&.connection&.shutdown! if via_gateway?
|
172
|
+
rescue StandardError => e
|
173
|
+
Remotus.logger.warn { "Failed to close existing SSH gateway connection with error #{e}" }
|
174
|
+
end
|
158
175
|
|
159
|
-
@gateway
|
176
|
+
Remotus.logger.debug { "Setting @gateway and @connection to nil." }
|
160
177
|
|
161
178
|
@gateway = nil
|
162
179
|
@connection = nil
|
@@ -168,7 +185,7 @@ module Remotus
|
|
168
185
|
# @return [Boolean] true if available, false otherwise
|
169
186
|
#
|
170
187
|
def port_open?
|
171
|
-
Remotus.port_open?(
|
188
|
+
Remotus.port_open?(remote_host, @port)
|
172
189
|
end
|
173
190
|
|
174
191
|
#
|
@@ -465,7 +482,7 @@ module Remotus
|
|
465
482
|
def restart_connection?
|
466
483
|
return true unless @connection
|
467
484
|
return true if @connection.closed?
|
468
|
-
return true if
|
485
|
+
return true if remote_host != @connection.host
|
469
486
|
|
470
487
|
target_cred = Remotus::Auth.credential(self)
|
471
488
|
|
@@ -481,7 +498,7 @@ module Remotus
|
|
481
498
|
gateway_session = @gateway.connection.instance_variable_get(:@session)
|
482
499
|
|
483
500
|
return true if gateway_session.closed?
|
484
|
-
return true if
|
501
|
+
return true if remote_gateway_host != gateway_session.host
|
485
502
|
|
486
503
|
gateway_cred = Remotus::Auth.credential(@gateway)
|
487
504
|
|
@@ -572,5 +589,43 @@ module Remotus
|
|
572
589
|
def via_gateway?
|
573
590
|
host_pool && host_pool[:gateway_host]
|
574
591
|
end
|
592
|
+
|
593
|
+
#
|
594
|
+
# Whether connecting via IP instead of hostname
|
595
|
+
#
|
596
|
+
# @return [Boolean] true if using an IP, false otherwise
|
597
|
+
#
|
598
|
+
def via_ip?
|
599
|
+
host_pool && !host_pool[:ip].to_s.empty?
|
600
|
+
end
|
601
|
+
|
602
|
+
#
|
603
|
+
# Remote host used for the connection. Will use the ip if specified, otherwise uses the hostname.
|
604
|
+
#
|
605
|
+
# @return [String] Remote host
|
606
|
+
#
|
607
|
+
def remote_host
|
608
|
+
via_ip? ? host_pool[:ip] : @host
|
609
|
+
end
|
610
|
+
|
611
|
+
#
|
612
|
+
# Whether connecting via gateway IP instead of gateway hostname
|
613
|
+
#
|
614
|
+
# @return [Boolean] true if using an IP, false otherwise
|
615
|
+
#
|
616
|
+
def via_gateway_ip?
|
617
|
+
host_pool && !host_pool[:gateway_ip].to_s.empty?
|
618
|
+
end
|
619
|
+
|
620
|
+
#
|
621
|
+
# Remote gateway host used for the connection. Will use the gateway_ip if specified, otherwise uses the hostname.
|
622
|
+
#
|
623
|
+
# @return [String] Remote gateway host
|
624
|
+
#
|
625
|
+
def remote_gateway_host
|
626
|
+
return nil unless via_gateway?
|
627
|
+
|
628
|
+
via_gateway_ip? ? host_pool[:gateway_ip] : host_pool[:gateway_host]
|
629
|
+
end
|
575
630
|
end
|
576
631
|
end
|
data/lib/remotus/version.rb
CHANGED
@@ -69,7 +69,7 @@ module Remotus
|
|
69
69
|
|
70
70
|
Remotus.logger.debug { "Initializing WinRM connection to #{Remotus::Auth.credential(self).user}@#{@host}:#{@port}" }
|
71
71
|
@base_connection = WinRM::Connection.new(
|
72
|
-
endpoint: "http://#{
|
72
|
+
endpoint: "http://#{remote_host}:#{@port}/wsman",
|
73
73
|
transport: :negotiate,
|
74
74
|
user: Remotus::Auth.credential(self).user,
|
75
75
|
password: Remotus::Auth.credential(self).password
|
@@ -106,7 +106,7 @@ module Remotus
|
|
106
106
|
# @return [Boolean] true if available, false otherwise
|
107
107
|
#
|
108
108
|
def port_open?
|
109
|
-
Remotus.port_open?(
|
109
|
+
Remotus.port_open?(remote_host, @port)
|
110
110
|
end
|
111
111
|
|
112
112
|
#
|
@@ -195,7 +195,7 @@ module Remotus
|
|
195
195
|
def restart_base_connection?
|
196
196
|
return restart_connection?(shell: @shell) if @connection
|
197
197
|
return true unless @base_connection
|
198
|
-
return true if
|
198
|
+
return true if remote_host != @base_connection.instance_values["connection_opts"][:endpoint].scan(%r{//(.*):}).flatten.first
|
199
199
|
return true if Remotus::Auth.credential(self).user != @base_connection.instance_values["connection_opts"][:user]
|
200
200
|
return true if Remotus::Auth.credential(self).password != @base_connection.instance_values["connection_opts"][:password]
|
201
201
|
|
@@ -213,11 +213,29 @@ module Remotus
|
|
213
213
|
def restart_connection?(**options)
|
214
214
|
return true unless @connection
|
215
215
|
return true if shell && !options[:shell].casecmp?(@shell)
|
216
|
-
return true if
|
216
|
+
return true if remote_host != @connection.connection_opts[:endpoint].scan(%r{//(.*):}).flatten.first
|
217
217
|
return true if Remotus::Auth.credential(self).user != @connection.connection_opts[:user]
|
218
218
|
return true if Remotus::Auth.credential(self).password != @connection.connection_opts[:password]
|
219
219
|
|
220
220
|
false
|
221
221
|
end
|
222
|
+
|
223
|
+
#
|
224
|
+
# Whether connecting via IP instead of hostname
|
225
|
+
#
|
226
|
+
# @return [Boolean] true if using an IP, false otherwise
|
227
|
+
#
|
228
|
+
def via_ip?
|
229
|
+
host_pool && !host_pool[:ip].to_s.empty?
|
230
|
+
end
|
231
|
+
|
232
|
+
#
|
233
|
+
# Remote host used for the connection. Will use the ip if specified, otherwise uses the hostname.
|
234
|
+
#
|
235
|
+
# @return [String] Remote host
|
236
|
+
#
|
237
|
+
def remote_host
|
238
|
+
via_ip? ? host_pool[:ip] : @host
|
239
|
+
end
|
222
240
|
end
|
223
241
|
end
|
data/lib/remotus.rb
CHANGED
@@ -18,6 +18,9 @@ module Remotus
|
|
18
18
|
# @option options [Integer] :timeout amount of time to wait for a connection from the pool
|
19
19
|
# @option options [Integer] :port port to use for the connection
|
20
20
|
# @option options [Symbol] :proto protocol to use for the connection (:winrm, :ssh), must be specified if port is specified
|
21
|
+
# @option options [String] :ip IP to use for the connection, preferred over the hostname if set.
|
22
|
+
# This should be used if the hostname is required for credential retrieval
|
23
|
+
# but the hostname cannot be resolved by DNS.
|
21
24
|
#
|
22
25
|
# @return [Remotus::HostPool] Newly created or retrieved host pool
|
23
26
|
#
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: remotus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Newell
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: connection_pool
|