Skip to content

K8SPG-911: Fix pg_tde status reporting on standbys - #1750

Merged
hors merged 3 commits into
mainfrom
K8SPG-911-standby
Aug 17, 2026
Merged

K8SPG-911: Fix pg_tde status reporting on standbys#1750
hors merged 3 commits into
mainfrom
K8SPG-911-standby

Conversation

@egegunes

Copy link
Copy Markdown
Contributor

CHANGE DESCRIPTION

Problem:
Operator doesn't (and can't) run any SQL statements on standby clusters to enable and configure pg_tde. This results in status conditions related to pg_tde not appear. Consequences of this is bigger than just status reporting: enabling WAL encryption depends on these conditions being true.

Solution:
Reconcile pg_tde on standby clusters separately and observe if pg_tde is enabled and configured in database by read queries.

CHECKLIST

Jira

  • Is the Jira ticket created and referenced properly?
  • Does the Jira ticket have the proper statuses for documentation (Needs Doc) and QA (Needs QA)?
  • Does the Jira ticket link to the proper milestone (Fix Version field)?

Tests

  • Is an E2E test/test case added for the new feature/change?
  • Are unit tests added where appropriate?

Config/Logging/Testability

  • Are all needed new/changed options added to default YAML files?
  • Are all needed new/changed options added to the Helm Chart?
  • Did we add proper logging messages for operator actions?
  • Did we ensure compatibility with the previous version or cluster upgrade process?
  • Does the change support oldest and newest supported PG version?
  • Does the change support oldest and newest supported Kubernetes version?

"the condition should name the Secret that could not be read")
assert.Equal(t, patched, 1,
"the failure condition is useless unless it is written to the API")
assertEvent(t, r.Recorder, "PGTDEVaultProviderChangeFailed")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the deletion intended? I didn't find the logic that affects the event and the test still passes with this line added back

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i deleted it by mistake, will restore

mayankshah1607
mayankshah1607 previously approved these changes Aug 13, 2026

@gkech gkech left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly tests related comments, logic seems ok. let me know if we should defer them for the future.

// K8SPG-911
func TestReconcilePGTDEStandby(t *testing.T) {
t.Parallel()
ctx := context.Background()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some tests of the same PR we use t.context, here we use background. We should be consistent and use t.context everywhere.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +1570 to +1571
Recorder: events.NewRecorder(t, runtime.Scheme),
PodExec: execResponder(&calls, answer(true, nil)),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are not needed for this test case

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't need Recorder: 487ac81

Comment on lines +1603 to +1604
Recorder: events.NewRecorder(t, runtime.Scheme),
PodExec: execResponder(&calls, answer(false, nil)),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again here we dont need these

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't need Recorder: 487ac81

}

r.reconcilePGTDEStandby(ctx, cluster, standbyObserved())
assert.Equal(t, len(calls), 0,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why on some of these check we have messages while on others we do not? In general, I think that they are not very useful

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

¯_(ツ)_/¯

if it's okay, i won't do this change

assert.Equal(t, call.pod, "pgc1-instance1-abcd-0")
assert.Equal(t, call.container, naming.ContainerDatabase)
assert.Equal(t, call.command[0], "psql")
assert.Assert(t, argsContain(call.command, "--tuples-only"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we decided to assert that, why we only check tuples only and not no align?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's claude adding a test for every change, why I use these flags described in comment:

// readOnlyPSQLArgs make psql print a single value and nothing else, so the
// result of a one-row, one-column query is exactly "t" or "f".
var readOnlyPSQLArgs = []string{"--no-align", "--tuples-only"}

Comment on lines +1003 to +1005
assert.NilError(t, r.reconcilePGTDEProviders(ctx, cluster, observed, failPatch(t)))
assert.Equal(t, cluster.Status.PGTDERevision, "")
assert.Assert(t, meta.FindStatusCondition(cluster.Status.Conditions,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still trying to understand why on a file we introduced ourselves we are using gotest.tools/v3/assert instead of github.com/stretchr/testify/assert, which is much more expressive

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all tests in internal directory is using gotest.tools/v3/assert, that's why claude continued to use it

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses pg_tde status reporting for standby (recovery) clusters, where the operator cannot run SQL that writes system catalogs. It introduces a dedicated standby reconcile path that observes (via read-only queries on the standby leader) whether pg_tde is present and whether its principal key is reachable, then reports appropriate status conditions so downstream logic (notably WAL encryption gating) can behave correctly.

Changes:

  • Added PostgresCluster.IsStandby() helper and unit tests for standby detection.
  • Implemented read-only pg_tde observation (ObserveExtension, VerifyPrincipalKey) and standby-specific condition reporting (ReportStandby).
  • Added a standby reconcile path that execs into the Patroni standby leader to observe pg_tde state, while ensuring the writable-only pg_tde provider reconciliation is skipped on standbys.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.

Show a summary per file
File Description
pkg/apis/upstream.pgv2.percona.com/v1beta1/postgrescluster_types.go Adds IsStandby() helper on the API type.
pkg/apis/upstream.pgv2.percona.com/v1beta1/postgrescluster_test.go Adds unit coverage for IsStandby().
internal/pgtde/postgres.go Adds read-only psql helpers plus standby-oriented status reporting logic; adjusts WAL-encryption gating behavior for standby clusters.
internal/pgtde/postgres_test.go Adds tests for standby WAL parameter behavior and new pg_tde observation/reporting helpers.
internal/controller/postgrescluster/postgres.go Adds reconcilePGTDEStandby and prevents writable-only provider reconciliation from running on standbys.
internal/controller/postgrescluster/pgtde_test.go Adds tests validating standby behavior (no writable SQL, correct status reporting) and helper utilities for exec simulation.
internal/controller/postgrescluster/instance.go Adds standbyLeaderPod() selection logic for Patroni standby leader pods.
internal/controller/postgrescluster/instance_test.go Adds unit tests for standbyLeaderPod().
internal/controller/postgrescluster/controller.go Invokes reconcilePGTDEStandby in the main reconcile flow.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@egegunes
egegunes requested a review from gkech August 17, 2026 11:08
@hors
hors merged commit 4ac2e27 into main Aug 17, 2026
17 of 18 checks passed
@hors
hors deleted the K8SPG-911-standby branch August 17, 2026 11:45
egegunes added a commit that referenced this pull request Aug 17, 2026
* K8SPG-911: Fix pg_tde status reporting on standbys

* address review comments
egegunes added a commit that referenced this pull request Aug 17, 2026
* K8SPG-911: Fix pg_tde status reporting on standbys

* address review comments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants