active_postgres 0.7.0 → 0.8.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: 503ec5557f2365458cfe544af059bb5636e82be153a58926978c62ff43384b6f
4
- data.tar.gz: 20d9bad0c0cbde26d214d304f379854d8d8dd548f06f86462840dad56f0f4580
3
+ metadata.gz: 0266b3f7dabc2d844b30aa6410cfd7c59131a7fb77a2dea85f01f9a66c2a2443
4
+ data.tar.gz: fd720306229f1ddea1d4e01a9dc3a5df3b7a60a620c38e86779e82f9698ebcbc
5
5
  SHA512:
6
- metadata.gz: 26ad8c310458b4e4ecdce1586b98cce9b062260b060e8779481e965c3d2c3d092a93691956372dbf62bd3e138d2b68e97b9dc135748da8a5f4481b683d739c1b
7
- data.tar.gz: c9ee9f54f725cf43398815a79c621579ac1dad70b36ab997a413905a8cd5222eea42ca0e3397928f26ccf48fc1f1c10da18d9aef31cabfd62eff4ab3aadd0f84
6
+ metadata.gz: bb3bc17966f9ebe98a55f09f678fe2bc2e57b92615c45848c347a7568f6e3bb61d15788d6bb16008e4498a9b944a3f53241f2e2579b204d28679341b041f4978
7
+ data.tar.gz: 3863cace22d1ba3aea901d312d26152de067c7ca898ddff5b654a75702a9e6b4c01f6ffbac820fed338fc5db8ce011ad39676143f81f785f66f7fec72cd72ae5
@@ -8,7 +8,6 @@ module ActivePostgres
8
8
  @environment = environment
9
9
  env_config = config_hash[environment] || {}
10
10
 
11
- # Check if deployment should be skipped (e.g., for development)
12
11
  @skip_deployment = env_config['skip_deployment'] == true
13
12
 
14
13
  @version = env_config['version'] || 18
@@ -65,6 +64,16 @@ module ActivePostgres
65
64
  private_ip_for(node) || host
66
65
  end
67
66
 
67
+ # Returns the host to use for direct PostgreSQL connections (private_ip preferred)
68
+ def connection_host_for(host)
69
+ node = node_config_for(host)
70
+ private_ip_for(node) || host
71
+ end
72
+
73
+ def primary_connection_host
74
+ connection_host_for(primary_host)
75
+ end
76
+
68
77
  def standby_config_for(host)
69
78
  @standbys.find { |s| s['host'] == host }
70
79
  end
@@ -0,0 +1,92 @@
1
+ require 'pg'
2
+
3
+ module ActivePostgres
4
+ class DirectExecutor
5
+ attr_reader :config
6
+
7
+ def initialize(config, quiet: false)
8
+ @config = config
9
+ @quiet = quiet
10
+ end
11
+
12
+ def quiet?
13
+ @quiet
14
+ end
15
+
16
+ def postgres_running?(host)
17
+ with_connection(host) do |conn|
18
+ conn.exec('SELECT 1')
19
+ true
20
+ end
21
+ rescue PG::Error
22
+ false
23
+ end
24
+
25
+ def run_sql(host, sql)
26
+ with_connection(host) do |conn|
27
+ result = conn.exec(sql)
28
+ result.values.flatten.join("\n")
29
+ end
30
+ rescue PG::Error => e
31
+ raise Error, "Failed to execute SQL on #{host}: #{e.message}"
32
+ end
33
+
34
+ def get_postgres_status(host)
35
+ run_sql(host, 'SELECT version();')
36
+ end
37
+
38
+ private
39
+
40
+ def with_connection(host)
41
+ connection_host = config.connection_host_for(host)
42
+ superuser_password = resolve_secret(config.secrets_config['superuser_password'])
43
+
44
+ conn = PG.connect(
45
+ host: connection_host,
46
+ port: 5432,
47
+ dbname: 'postgres',
48
+ user: config.postgres_user,
49
+ password: superuser_password,
50
+ connect_timeout: 10,
51
+ sslmode: config.component_enabled?(:ssl) ? 'require' : 'prefer'
52
+ )
53
+
54
+ begin
55
+ yield conn
56
+ ensure
57
+ conn.close
58
+ end
59
+ end
60
+
61
+ def resolve_secret(value)
62
+ return nil if value.nil?
63
+
64
+ # Handle Rails credentials
65
+ if value.start_with?('rails_credentials:')
66
+ return resolve_rails_credentials(value)
67
+ end
68
+
69
+ # Handle environment variables
70
+ if value.start_with?('$')
71
+ return ENV[value[1..]]
72
+ end
73
+
74
+ # Handle shell commands
75
+ if value.start_with?('$(') && value.end_with?(')')
76
+ return `#{value[2..-2]}`.strip
77
+ end
78
+
79
+ value
80
+ end
81
+
82
+ def resolve_rails_credentials(value)
83
+ path = value.sub('rails_credentials:', '')
84
+ keys = path.split('.').map(&:to_sym)
85
+
86
+ credentials = Rails.application.credentials
87
+ keys.reduce(credentials) { |obj, key| obj&.dig(key) }
88
+ rescue NameError
89
+ nil
90
+ end
91
+ end
92
+ end
@@ -1,10 +1,19 @@
1
1
  module ActivePostgres
2
2
  class HealthChecker
3
- attr_reader :config, :ssh_executor
3
+ attr_reader :config, :executor
4
4
 
5
5
  def initialize(config)
6
6
  @config = config
7
- @ssh_executor = SSHExecutor.new(config, quiet: true)
7
+ @executor = create_executor
8
+ end
9
+
10
+ # Backwards compatibility alias
11
+ def ssh_executor
12
+ @executor
13
+ end
14
+
15
+ private def create_executor
16
+ DirectExecutor.new(config, quiet: true)
8
17
  end
9
18
 
10
19
  def show_status
@@ -287,31 +296,29 @@ module ActivePostgres
287
296
  def check_pgbouncer_status(host)
288
297
  return '-' unless config.component_enabled?(:pgbouncer)
289
298
 
290
- ssh_executor.execute_on_host(host) do
291
- result = capture(:sudo, 'systemctl', 'is-active', 'pgbouncer').strip
292
- result == 'active' ? '✓ running' : '✗ down'
293
- end
299
+ check_pgbouncer_direct(host) ? '✓ running' : '✗ down'
294
300
  rescue StandardError
295
301
  '✗ down'
296
302
  end
297
303
 
298
304
  def check_pgbouncer_running(host)
299
- ssh_executor.execute_on_host(host) do
300
- result = capture(:sudo, 'systemctl', 'is-active', 'pgbouncer').strip
301
- result == 'active'
302
- end
305
+ check_pgbouncer_direct(host)
303
306
  rescue StandardError
304
307
  false
305
308
  end
306
309
 
307
- def check_pgbouncer_userlist(host)
308
- app_user = config.app_user
309
- return true unless app_user # No app user configured, skip check
310
+ def check_pgbouncer_userlist(_host)
311
+ true
312
+ end
313
+
314
+ def check_pgbouncer_direct(host)
315
+ require 'socket'
316
+ connection_host = config.connection_host_for(host)
317
+ pgbouncer_port = config.component_config(:pgbouncer)[:listen_port] || 6432
310
318
 
311
- ssh_executor.execute_on_host(host) do
312
- userlist = capture(:sudo, 'cat', '/etc/pgbouncer/userlist.txt').strip
313
- userlist.include?(app_user)
314
- end
319
+ socket = TCPSocket.new(connection_host, pgbouncer_port)
320
+ socket.close
321
+ true
315
322
  rescue StandardError
316
323
  false
317
324
  end
@@ -1,3 +1,3 @@
1
1
  module ActivePostgres
2
- VERSION = '0.7.0'.freeze
2
+ VERSION = '0.8.0'.freeze
3
3
  end
@@ -21,6 +21,7 @@ require_relative 'active_postgres/standby_deployment_flow'
21
21
  require_relative 'active_postgres/cli'
22
22
  require_relative 'active_postgres/installer'
23
23
  require_relative 'active_postgres/ssh_executor'
24
+ require_relative 'active_postgres/direct_executor'
24
25
  require_relative 'active_postgres/health_checker'
25
26
  require_relative 'active_postgres/failover'
26
27
  require_relative 'active_postgres/performance_tuner'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_postgres
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - BoringCache
@@ -169,6 +169,7 @@ files:
169
169
  - lib/active_postgres/connection_pooler.rb
170
170
  - lib/active_postgres/credentials.rb
171
171
  - lib/active_postgres/deployment_flow.rb
172
+ - lib/active_postgres/direct_executor.rb
172
173
  - lib/active_postgres/error_handler.rb
173
174
  - lib/active_postgres/failover.rb
174
175
  - lib/active_postgres/generators/active_postgres/install_generator.rb
@@ -220,7 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
220
221
  - !ruby/object:Gem::Version
221
222
  version: '0'
222
223
  requirements: []
223
- rubygems_version: 3.7.2
224
+ rubygems_version: 3.6.9
224
225
  specification_version: 4
225
226
  summary: PostgreSQL High Availability for Rails, made simple
226
227
  test_files: []