active_postgres 0.9.1 → 0.9.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c89909c556964abfe7dbede0550c7fa1fbd60fc332e667fce5de858114ba2146
4
- data.tar.gz: e715719391d53f89cb394203018a5e2951f2602018ef97a417ee369d443e410c
3
+ metadata.gz: e51d5f1214cedf497a9b060e5c667c43711f9ff5e36024bfd8dc926b50fe272f
4
+ data.tar.gz: 618fa70d39a43e1c74ba2ed449b75138670bca92cb6bf418606f772de34c6a7d
5
5
  SHA512:
6
- metadata.gz: 603d5b28ef5730d595b24bf36b517148a882c5889d339675545fc98ffda547d8c1ead15ff8ee6a048fd6b117b5e257309460e7b5e25a9ee5eb4e55c730050ba4
7
- data.tar.gz: 50f632e74185dc90d7da5e6ece125fc625b04665cc4859ca7fd3d136e82df6e295b5fde10d8a2239675ce67a1a527f24ef8ec00cfeff79c57d84601a11168105
6
+ metadata.gz: 254b6fb4342d4e510076d05ebfbeaa0e7990b463df13ad6ddb7d6eb5a70562c23cc4f502ce6c435c6372fc3dd5f695285ee3fdfed522cc188f1b1cc21c6cc90d
7
+ data.tar.gz: d9147a4679529344ccb0ffd3d5c2ffacc3072464b9cf4e1c6e11150a66c142ef0d0b45f9b9cd9d34eceba6f4d0e50baa7c2f227a5b2b1719502972e2b4b39ee4
@@ -49,6 +49,11 @@ module ActivePostgres
49
49
  create_app_user_and_database(config.primary_host)
50
50
  end
51
51
 
52
+ def install_packages_only(host)
53
+ puts " Installing packages on #{host} (cluster will be created by repmgr)..."
54
+ ssh_executor.install_postgres(host, config.version)
55
+ end
56
+
52
57
  private
53
58
 
54
59
  def install_on_host(host, is_primary:)
@@ -96,11 +101,6 @@ module ActivePostgres
96
101
  optimal_settings.merge(user_postgresql)
97
102
  end
98
103
 
99
- def install_packages_only(host)
100
- puts " Installing packages on #{host} (cluster will be created by repmgr)..."
101
- ssh_executor.install_postgres(host, config.version)
102
- end
103
-
104
104
  def cluster_exists?(host)
105
105
  exists = false
106
106
  version = config.version
@@ -85,6 +85,22 @@ module ActivePostgres
85
85
  execute :sudo, 'DEBIAN_FRONTEND=noninteractive', 'apt-get', 'install', '-y', '-qq',
86
86
  "postgresql-#{version}-repmgr"
87
87
  end
88
+ install_postgres_sudoers(host)
89
+ end
90
+ end
91
+
92
+ def install_postgres_sudoers(host)
93
+ version = config.version
94
+ sudoers_line = "postgres ALL=(ALL) NOPASSWD: /usr/bin/systemctl start postgresql@#{version}-main, " \
95
+ "/usr/bin/systemctl stop postgresql@#{version}-main, " \
96
+ "/usr/bin/systemctl restart postgresql@#{version}-main, " \
97
+ "/usr/bin/systemctl reload postgresql@#{version}-main, " \
98
+ "/usr/bin/systemctl status postgresql@#{version}-main"
99
+ ssh_executor.execute_on_host(host) do
100
+ upload! StringIO.new("#{sudoers_line}\n"), '/tmp/postgres-repmgr-sudoers'
101
+ execute :sudo, 'cp', '/tmp/postgres-repmgr-sudoers', '/etc/sudoers.d/postgres-repmgr'
102
+ execute :sudo, 'chmod', '440', '/etc/sudoers.d/postgres-repmgr'
103
+ execute :rm, '-f', '/tmp/postgres-repmgr-sudoers'
88
104
  end
89
105
  end
90
106
 
@@ -247,6 +263,7 @@ module ActivePostgres
247
263
  effective_replication_password = replication_user == repmgr_user ? repmgr_password : replication_password
248
264
 
249
265
  ensure_primary_registered
266
+ ensure_primary_replication_ready(repmgr_password, effective_replication_password)
250
267
 
251
268
  setup_pgpass_file(standby_host, repmgr_password, replication_password: effective_replication_password,
252
269
  primary_ip: primary_replication_host)
@@ -399,9 +416,42 @@ module ActivePostgres
399
416
  end
400
417
 
401
418
  register_standby_with_primary(standby_host)
419
+ setup_inter_node_ssh
402
420
  enable_repmgrd_if_configured(standby_host, repmgr_config)
403
421
  end
404
422
 
423
+ def setup_inter_node_ssh
424
+ dns_config = dns_failover_config
425
+ key_path = dns_config && dns_config[:ssh_key_path] || '/var/lib/postgresql/.ssh/active_postgres_dns'
426
+ postgres_user = config.postgres_user
427
+ all_hosts = config.all_hosts
428
+ pub_keys = {}
429
+
430
+ all_hosts.each do |host|
431
+ ssh_executor.execute_on_host(host) do
432
+ pub_keys[host] = capture(:sudo, '-u', postgres_user, 'cat', "#{key_path}.pub").strip
433
+ end
434
+ end
435
+
436
+ all_hosts.each do |host|
437
+ ssh_executor.execute_on_host(host) do
438
+ other_keys = pub_keys.reject { |h, _| h == host }.values
439
+ other_keys.each do |key|
440
+ next if key.to_s.empty?
441
+
442
+ upload! StringIO.new("#{key}\n"), '/tmp/pg_peer_key.pub'
443
+ execute :sudo, '-u', postgres_user, 'bash', '-c',
444
+ "grep -qxF -f /tmp/pg_peer_key.pub /var/lib/postgresql/.ssh/authorized_keys 2>/dev/null || cat /tmp/pg_peer_key.pub >> /var/lib/postgresql/.ssh/authorized_keys"
445
+ execute :rm, '-f', '/tmp/pg_peer_key.pub'
446
+ end
447
+
448
+ peer_ips = all_hosts.reject { |h| h == host }.map { |h| config.replication_host_for(h) }
449
+ scan_cmd = "ssh-keyscan #{peer_ips.join(' ')} >> /var/lib/postgresql/.ssh/known_hosts 2>/dev/null || true"
450
+ execute :sudo, '-u', postgres_user, 'bash', '-c', scan_cmd
451
+ end
452
+ end
453
+ end
454
+
405
455
  def setup_dns_failover
406
456
  dns_config = dns_failover_config
407
457
  return unless dns_config
@@ -424,6 +474,8 @@ module ActivePostgres
424
474
  authorize_dns_keys(dns_server, dns_user, pub_keys.values.compact)
425
475
  end
426
476
 
477
+ setup_inter_node_ssh
478
+
427
479
  config.all_hosts.each do |host|
428
480
  install_dns_failover_script(host, dns_config, dns_private_ips, dns_user, dns_ssh_key_path, ssh_strict_host_key)
429
481
  end
@@ -876,6 +928,33 @@ module ActivePostgres
876
928
  is_registered
877
929
  end
878
930
 
931
+ def ensure_primary_replication_ready(repmgr_password, effective_replication_password)
932
+ host = config.primary_host
933
+ repmgr_user = config.repmgr_user
934
+ repmgr_db = config.repmgr_database
935
+ replication_user = config.replication_user
936
+ repmgr_component = self
937
+ executor = ssh_executor
938
+
939
+ puts ' Ensuring repmgr user has correct password and privileges on primary...'
940
+
941
+ ssh_executor.execute_on_host(host) do
942
+ repmgr_sql = repmgr_component.send(:build_repmgr_setup_sql, repmgr_user, repmgr_db, repmgr_password)
943
+ executor.run_sql_on_backend(self, repmgr_sql, postgres_user: 'postgres', port: 5432, tuples_only: false,
944
+ capture: false)
945
+
946
+ if replication_user != repmgr_user
947
+ repl_sql = repmgr_component.send(:build_replication_user_sql, replication_user, effective_replication_password)
948
+ executor.run_sql_on_backend(self, repl_sql, postgres_user: 'postgres', port: 5432, tuples_only: false,
949
+ capture: false)
950
+ end
951
+
952
+ info '✓ Primary replication user is ready'
953
+ end
954
+
955
+ setup_pgpass_file(host, repmgr_password, replication_password: effective_replication_password)
956
+ end
957
+
879
958
  def regenerate_ssl_certs(host, version)
880
959
  ssl_config = config.component_config(:ssl)
881
960
  ssl_cert = secrets.resolve('ssl_cert')
@@ -1011,9 +1090,9 @@ module ActivePostgres
1011
1090
  'DO $$',
1012
1091
  'BEGIN',
1013
1092
  " IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '#{repmgr_user}') THEN",
1014
- " CREATE USER #{repmgr_user} WITH SUPERUSER PASSWORD '#{escaped_password}';",
1093
+ " CREATE USER #{repmgr_user} WITH SUPERUSER REPLICATION PASSWORD '#{escaped_password}';",
1015
1094
  ' ELSE',
1016
- " ALTER USER #{repmgr_user} WITH SUPERUSER PASSWORD '#{escaped_password}';",
1095
+ " ALTER USER #{repmgr_user} WITH SUPERUSER REPLICATION PASSWORD '#{escaped_password}';",
1017
1096
  ' END IF;',
1018
1097
  'END $$;',
1019
1098
  '',
@@ -81,6 +81,8 @@ module ActivePostgres
81
81
  end
82
82
 
83
83
  def fetch_from_rails_credentials(key_path)
84
+ ensure_rails_credentials_available
85
+
84
86
  return nil unless defined?(::Rails) && ::Rails.respond_to?(:application) && ::Rails.application
85
87
 
86
88
  keys = key_path.split('.').map(&:to_sym)
@@ -89,6 +91,22 @@ module ActivePostgres
89
91
  nil
90
92
  end
91
93
 
94
+ def ensure_rails_credentials_available
95
+ return if @rails_boot_attempted
96
+ return if defined?(::Rails) && ::Rails.respond_to?(:application) && ::Rails.application
97
+
98
+ @rails_boot_attempted = true
99
+
100
+ # Try loading just the Rails application (without full initialization)
101
+ # This makes Rails.application available for credential access
102
+ if File.exist?('./config/application.rb')
103
+ require './config/application'
104
+ end
105
+ rescue StandardError
106
+ # Rails boot failed — CLI running outside a Rails project
107
+ nil
108
+ end
109
+
92
110
  def execute_command(command)
93
111
  # Preserve RAILS_ENV if set
94
112
  env_prefix = ENV['RAILS_ENV'] ? "RAILS_ENV=#{ENV['RAILS_ENV']} " : ''
@@ -1,6 +1,7 @@
1
1
  require 'sshkit'
2
2
  require 'sshkit/dsl'
3
3
  require 'securerandom'
4
+ require 'stringio'
4
5
 
5
6
  module ActivePostgres
6
7
  class SSHExecutor
@@ -1,3 +1,3 @@
1
1
  module ActivePostgres
2
- VERSION = '0.9.1'.freeze
2
+ VERSION = '0.9.2'.freeze
3
3
  end
@@ -30,6 +30,13 @@ follow_command='repmgr standby follow -f /etc/repmgr.conf --upstream-node-id=%n'
30
30
 
31
31
  reconnect_attempts=<%= repmgr_config[:reconnect_attempts] || 6 %>
32
32
  reconnect_interval=<%= repmgr_config[:reconnect_interval] || 10 %>
33
+
34
+ service_start_command='sudo systemctl start postgresql@<%= config.version %>-main'
35
+ service_stop_command='sudo systemctl stop postgresql@<%= config.version %>-main'
36
+ service_restart_command='sudo systemctl restart postgresql@<%= config.version %>-main'
37
+ service_reload_command='sudo systemctl reload postgresql@<%= config.version %>-main'
38
+
39
+ ssh_options='-i /var/lib/postgresql/.ssh/active_postgres_dns -o StrictHostKeyChecking=no'
33
40
  <% if repmgr_config.key?(:use_rewind) %>
34
41
  use_rewind=<%= repmgr_config[:use_rewind] ? 'yes' : 'no' %>
35
42
  <% end %>
@@ -12,13 +12,17 @@ SSH_STRICT_HOST_KEY="<%= ssh_strict_host_key %>"
12
12
  SSH_KNOWN_HOSTS="/var/lib/postgresql/.ssh/known_hosts"
13
13
  LOG_TAG="active_postgres_dns"
14
14
 
15
- cluster_csv=$(repmgr -f "$REPMGR_CONF" cluster show --csv 2>/dev/null || true)
16
- if [[ -z "$cluster_csv" ]]; then
15
+ REPMGR_DB=$(grep -oP "dbname=\K[^ ']+" "$REPMGR_CONF" | head -1)
16
+ REPMGR_USER=$(grep -oP "user=\K[^ ']+" "$REPMGR_CONF" 2>/dev/null | head -1)
17
+ REPMGR_USER="${REPMGR_USER:-repmgr}"
18
+
19
+ cluster_data=$(sudo -u postgres psql -h /var/run/postgresql -d "$REPMGR_DB" -tAF',' -c "SELECT type, conninfo FROM repmgr.nodes WHERE active = true" 2>/dev/null || true)
20
+ if [[ -z "$cluster_data" ]]; then
17
21
  exit 0
18
22
  fi
19
23
 
20
- primary_host=$(printf "%s\n" "$cluster_csv" | awk -F',' 'NR>1 && tolower($3) ~ /primary/ {print $NF; exit}' | sed -n 's/.*host=\\([^ ]*\\).*/\\1/p')
21
- standby_hosts=$(printf "%s\n" "$cluster_csv" | awk -F',' 'NR>1 && tolower($3) ~ /standby/ {print $NF}' | sed -n 's/.*host=\\([^ ]*\\).*/\\1/p' | sort -u)
24
+ primary_host=$(printf "%s\n" "$cluster_data" | awk -F',' '$1 == "primary" {print $2; exit}' | sed -n 's/.*host=\([^ ]*\).*/\1/p')
25
+ standby_hosts=$(printf "%s\n" "$cluster_data" | awk -F',' '$1 == "standby" {print $2}' | sed -n 's/.*host=\([^ ]*\).*/\1/p' | sort -u)
22
26
 
23
27
  if [[ -z "$primary_host" ]]; then
24
28
  exit 0
@@ -51,7 +55,7 @@ for server in "${DNS_SERVERS[@]}"; do
51
55
  fi
52
56
 
53
57
  if ! /usr/bin/ssh "${ssh_opts[@]}" "${DNS_USER}@${server}" \
54
- "sudo bash -c 'cat > ${DNSMASQ_FILE} << \"EOF\"\\n${content}EOF\\n' && (sudo systemctl reload dnsmasq || sudo systemctl restart dnsmasq)"; then
58
+ "sudo bash -c 'cat > ${DNSMASQ_FILE} << \"EOF\"\\n${content}EOF\\n' && sudo systemctl restart dnsmasq"; then
55
59
  /usr/bin/logger -t "$LOG_TAG" "Failed updating dnsmasq on ${server}"
56
60
  fi
57
61
  done
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.9.1
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - BoringCache