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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e6b07dbe42ab741bdb688bed9f6ce1d09ed2af8643291c57ec9aeedaaad0a19a
4
- data.tar.gz: a39ecf434564157c1e72d98cf840abadc1a406f91988ee7c47cf7c22d9643760
3
+ metadata.gz: 1a1fb83a5d4a7a15d98860a8342f71c5377f5c91ec842883a62cc2b6678baa96
4
+ data.tar.gz: db221756c55c43a5c0492cf8668c36e07f6e58d323b9a1b83b3688a0a9c8c92c
5
5
  SHA512:
6
- metadata.gz: f48c3e374b870a60664cf35838204755a83599a534113309abfecb40e5a5862f10091bd7bc19d8353a8a5716c71fe02dea043f891db998dd521451a998be4419
7
- data.tar.gz: 0c3d1f3e5dfbae5c2aeaec9d18f3eb4f4b99759b4c883e3298691e7cad7a91fa71d03f595cffb9bab07f9191844284a211c5fb76ff7900af56791ea6ed9a6f2a
6
+ metadata.gz: b2a57cbf28230b41b64c6e084511fa45536c8b020c7425b89d504e5ae764b16429911f5a2ff5458b2168b7ae46355e66c14279dad780d8ca38b525da66bd1694
7
+ data.tar.gz: 0bd543003bde4641d2d9527b88a72a550e700bcc65c73b76c2ef5ff0b2811c1eaae8013bb9bff34c5802b1e8fc2aa754557534908672c25eb814c8a281169788
data/.rubocop.yml CHANGED
@@ -46,3 +46,6 @@ Metrics/ParameterLists:
46
46
 
47
47
  Gemspec/RequireMFA:
48
48
  Enabled: false
49
+
50
+ Gemspec/DevelopmentDependencies:
51
+ EnforcedStyle: gemspec
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.1.0)
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.0)
18
+ connection_pool (2.4.1)
19
19
  diff-lcs (1.5.0)
20
20
  erubi (1.12.0)
21
- ffi (1.15.5)
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.1.0)
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.50.2)
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.0)
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.20.0)
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)
@@ -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, and host_pool metadata fields.
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, and host_pool metadata fields.
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(@gateway.host, gateway_cred.user, **gateway_options)
147
- @connection = @gateway.connection.ssh(@host, target_cred.user, **target_options)
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(@host, target_cred.user, **target_options)
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
- @connection&.close
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&.connection&.shutdown! if via_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?(@host, @port)
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 @host != @connection.host
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 @host_pool[:gateway_host] != gateway_session.host
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
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Remotus
4
4
  # Remotus gem version
5
- VERSION = "1.1.0"
5
+ VERSION = "1.2.0"
6
6
  end
@@ -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://#{@host}:#{@port}/wsman",
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?(@host, @port)
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 @host != @base_connection.instance_values["connection_opts"][:endpoint].scan(%r{//(.*):}).flatten.first
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 @host != @connection.connection_opts[:endpoint].scan(%r{//(.*):}).flatten.first
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.1.0
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-05-25 00:00:00.000000000 Z
11
+ date: 2023-10-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: connection_pool