Skip to content

Separate controller client concerns #4253

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

cbandy
Copy link
Member

@cbandy cbandy commented Aug 21, 2025

This separates the client.Client interface in our controllers into three: Reader, Writer, and StatusWriter. The idea is to add a little friction when adding a Client to a test, so we're more intentional about separating reads from writes. During this refactor, I found a number of tests that didn't need Kubernetes at all. This exercise has increased the amount of code covered by make check.

This refactor is one step toward my goal of a single, shared SSA Apply function.

Checklist:

  • Have you added an explanation of what your changes do and why you'd like them to be included?
  • Have you updated or added documentation for the change, as applicable?
  • Have you tested your changes on all related environments with successful results, as applicable?
    • Have you added automated tests?

Type of Changes:

  • Testing enhancement
  • Other

Other Information:

📝 The changes to the PGUpgrade controller are representative and rather small.
📝 The PostgresCluster controller is kinda big, so I'll submit it as a separate PR.

cbandy added 4 commits August 20, 2025 17:37
We want to be mindful of our interactions with the Kubernetes API, and
these interfaces will help keep functions focused. These interfaces are
also narrower than client.Reader and client.Writer and may help us keep
RBAC markers accurate.

A new constructor populates these fields with a single client.Client.
The client.WithFieldOwner constructor allows us to drop our Owner field
and patch method.
We want to be mindful of our interactions with the Kubernetes API, and
these interfaces will help keep functions focused. These interfaces are
also narrower than client.Reader and client.Writer and may help us keep
RBAC markers accurate.

A new constructor populates these fields with a single client.Client.
The client.WithFieldOwner constructor allows us to drop our Owner field
and patch method.

This allows `make check` to cover 47% more of the "crunchybridgecluster"
package.
We want to be mindful of our interactions with the Kubernetes API, and
these interfaces will help keep functions focused. These interfaces are
also narrower than client.Reader and client.Writer and may help us keep
RBAC markers accurate.

A new constructor populates these fields with a single client.Client.
The client.WithFieldOwner constructor allows us to drop our Owner field
and patch method.
@@ -316,8 +316,7 @@ func TestWritePGAdminUsers(t *testing.T) {
assert.Equal(t, calls, 1, "PodExec should be called once")

secret := &corev1.Secret{ObjectMeta: naming.StandalonePGAdmin(pgadmin)}
assert.NilError(t,
reconciler.Get(ctx, client.ObjectKeyFromObject(secret), secret))
assert.NilError(t, cc.Get(ctx, client.ObjectKeyFromObject(secret), secret))
Copy link
Contributor

Choose a reason for hiding this comment

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

but we could use reconciler.Reader.Get, yeah? Which is more indirection but maybe a reminder of separation of client powers?

Copy link
Contributor

Choose a reason for hiding this comment

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

But then -- who cares? This step isn't about what our operator does, this is just a step to get the object. "Getting the object" is not what we're testing here.

Client: tClient,
Owner: "crunchybridgecluster-controller",
}
reconciler := &CrunchyBridgeClusterReconciler{}
Copy link
Contributor

Choose a reason for hiding this comment

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

Kind of want to rename generatePostgresRoleSecret generatePostgresRoleSecretIntent or something

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, there's a few funcs here that, from the name, I would've said call kubernetes.

@@ -5,6 +5,9 @@
package naming

const (
ControllerBridge = "bridge-controller"
ControllerPGAdmin = "pgadmin-controller"
ControllerBridge = "bridge-controller"
Copy link
Contributor

Choose a reason for hiding this comment

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

ah, the bridge installation controller already has this split between reader/writer, but no statuswriter -- and we never touch the status

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.

2 participants