Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ and this project follows [Semantic Versioning](https://semver.org/).
- Make deployment-flow `--dry-run` stop before confirmation or mutation.
- Fail standby setup before mutation when required credentials do not resolve.
- Scope standby rollback to the requested host and keep existing cluster nodes intact.
- Preserve pgBackRest recovery options as one shell-safe argument during remote restore.
- Run component rollback in local Ruby context instead of an SSHKit backend scope.

## 0.9.6 - 2026-08-20

Expand Down
16 changes: 12 additions & 4 deletions lib/active_postgres/components/repmgr.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'shellwords'

module ActivePostgres
module Components
class Repmgr < Base
Expand Down Expand Up @@ -55,7 +57,7 @@ def restart
end

def setup_standby_only(standby_host)
puts "Setting up standby #{standby_host} (primary will not be touched)..."
puts "Setting up standby #{standby_host} (primary stays online)..."

version = config.version
install_apt_packages(standby_host, "postgresql-#{version}-repmgr")
Expand Down Expand Up @@ -909,11 +911,17 @@ def build_primary_conninfo(standby_label)
end

def pgbackrest_restore_arguments(primary_conninfo)
command = Shellwords.join(
[
'pgbackrest', '--stanza=main', '--type=standby',
"--recovery-option=primary_conninfo=#{primary_conninfo}",
'restore'
]
)

[
:sudo, '-u', config.postgres_user,
'pgbackrest', '--stanza=main', '--type=standby',
"--recovery-option=primary_conninfo=#{primary_conninfo}",
'restore'
:bash, '-lc', command
]
end

Expand Down
9 changes: 6 additions & 3 deletions lib/active_postgres/standby_deployment_flow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,17 @@ def deploy_monitoring
end

def register_rollback(component_name, component)
rollback_manager.register("Uninstall #{component_name} on #{standby_host}", host: standby_host) do
target_host = standby_host
captured_logger = logger

rollback_manager.register("Uninstall #{component_name} on #{target_host}") do
if component.respond_to?(:uninstall_from)
component.uninstall_from(standby_host)
component.uninstall_from(target_host)
else
component.uninstall
end
rescue StandardError => e
logger.warn "Failed to uninstall #{component_name} on #{standby_host}: #{e.message}"
captured_logger.warn "Failed to uninstall #{component_name} on #{target_host}: #{e.message}"
end
end

Expand Down
7 changes: 3 additions & 4 deletions test/repmgr_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,11 @@ def test_pgbackrest_restore_uses_standby_mode_and_primary_conninfo
conninfo = 'host=10.0.0.10 user=replication dbname=replication application_name=aws-standby'
arguments = @component.send(:pgbackrest_restore_arguments, conninfo)

assert_equal [:sudo, '-u', 'postgres', :bash, '-lc'], arguments.first(5)
assert_equal [
:sudo, '-u', 'postgres',
'pgbackrest', '--stanza=main', '--type=standby',
"--recovery-option=primary_conninfo=#{conninfo}",
'restore'
], arguments
"--recovery-option=primary_conninfo=#{conninfo}", 'restore'
], Shellwords.split(arguments.fetch(5))
end

def test_manual_failover_policy_disables_repmgrd
Expand Down
6 changes: 4 additions & 2 deletions test/standby_deployment_flow_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

class StandbyDeploymentFlowTest < Minitest::Test
class RollbackRecorder
attr_reader :action
attr_reader :action, :host

def register(*, &block)
def register(*, host: nil, &block)
@action = block
@host = host
end
end

Expand Down Expand Up @@ -36,6 +37,7 @@ def test_repmgr_rollback_targets_only_the_requested_standby
rollback.action.call

assert_equal ['standby.example.com'], removed
assert_nil rollback.host
end

private
Expand Down