Skip to content

feat: configure k8s recommended labels on subresources#865

Open
GabriFedi97 wants to merge 7 commits intocloudnative-pg:mainfrom
GabriFedi97:dev/545
Open

feat: configure k8s recommended labels on subresources#865
GabriFedi97 wants to merge 7 commits intocloudnative-pg:mainfrom
GabriFedi97:dev/545

Conversation

@GabriFedi97
Copy link
Copy Markdown
Contributor

@GabriFedi97 GabriFedi97 commented Apr 20, 2026

Add Kubernetes recommended labels to Role and RoleBinding managed Objects:

app.kubernetes.io/name: "postgresql"
app.kubernetes.io/instance: "<cluster name>"
app.kubernetes.io/version: "<cluster pg major version>"
app.kubernetes.io/component: "database"
app.kubernetes.io/managed-by: "plugin-barman-cloud"

Notice that some label values are a bit different from what described in the issue.

closes #545

@GabriFedi97 GabriFedi97 force-pushed the dev/545 branch 4 times, most recently from 08fccdc to 51fe8b7 Compare April 21, 2026 09:52
@GabriFedi97 GabriFedi97 marked this pull request as ready for review April 21, 2026 09:52
@GabriFedi97 GabriFedi97 requested a review from a team as a code owner April 21, 2026 09:52
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. enhancement New feature or request go Pull requests that update go code labels Apr 21, 2026
@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Apr 24, 2026
Signed-off-by: Gabriele Fedi <gabriele.fedi@enterprisedb.com>
Signed-off-by: Gabriele Fedi <gabriele.fedi@enterprisedb.com>
Signed-off-by: Gabriele Fedi <gabriele.fedi@enterprisedb.com>
Signed-off-by: Gabriele Fedi <gabriele.fedi@enterprisedb.com>
armru added 3 commits April 28, 2026 10:09
The package is already named specs, the file content is label
construction, and a separate metadata package exists at
internal/cnpgi/metadata; labels.go describes the file directly
without the package-name collision. BuildLabels also matches
the verb convention already used elsewhere in the package
(BuildRole, BuildRoleBinding, BuildRoleRules).

No behavior change.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
The original PR set the recommended labels to:
  app.kubernetes.io/name="postgresql"  (utils.AppName, the cnpg
                                         operator's identity)
  app.kubernetes.io/version=<cluster PG major>

Per issue cloudnative-pg#545 the plugin's RBAC objects should advertise the
plugin's own identity:
  app.kubernetes.io/name="barman-cloud-plugin"
  app.kubernetes.io/version=<plugin semver>

Use metadata.Data.Version for the version value (always set,
never conditional on cluster image), drop the cnpg
GetPostgresqlMajorVersion lookup (irrelevant to plugin RBAC and
fragile against the cnpg PostgresImageName default), and extract
the plugin-local AppLabelValue and ManagedByLabelValue constants
so test and production share a single source of truth. The
labels_test.go helper now also asserts the version's value, not
just the key.

Document on metadata.ClusterLabelName that it's a discovery
contract for objectstore_controller.go (which selects on the
key), so the dual-labeling scheme (the legacy cluster label
alongside the K8s recommended labels) is explicit and the
legacy key cannot be silently removed by a later cleanup.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
Adds the safety and robustness improvements identified during
review of the recommended-labels feature, all on the managed
Role and RoleBinding paths.

Labels: per-key overwrite. Keys the plugin manages overwrite
existing values; unrelated keys (anything outside the desired
set) are left alone. The plugin owns these objects exclusively
— OwnerReference points to the Cluster CR, the Pre hook
reconciles them on every call, and there is no realistic path
for an external manager (Helm, Kustomize, ArgoCD, …) to ever
touch these per-Cluster runtime-generated objects, so per-key
overwrite is the correct policy and version labels follow
plugin upgrades naturally.

Subjects: additive. The plugin guarantees its own ServiceAccount
Subject is bound, but never removes Subjects added by other
actors. A Subject is a grant of access; silently revoking
access an admin granted (e.g. a debugging ServiceAccount) is
the wrong default. This is intentionally asymmetric to the
label policy.

RoleRef: immutable in Kubernetes; a Patch cannot fix it.
Divergence at the canonical name is corruption regardless of
who wrote the existing object — fail loudly so the operator
notices and deletes the RoleBinding, and the next Pre call
recreates it correctly.

AlreadyExists tolerance: EnsureRoleBinding called c.Create
directly when Get returned NotFound and propagated whatever
Create returned. That's noisy on plugin pod startup: the
controller-runtime client is cache-backed by default, and during
the warm-up window the informer cache can return NotFound for a
RoleBinding that is actually present on the API server. The
follow-up Create then hits AlreadyExists and the whole Pre hook
returned an error to the cnpg-i framework. Mirror the pattern
used by ensureRoleExists: split the exists-or-create concern
into getOrCreateRoleBinding, swallow AlreadyExists, and re-Get
to return the racing winner so the caller can fall through to
reconcile.

Optimistic locking on patches: patchRole already wrapped its
Get+Patch in retry.RetryOnConflict, but used client.MergeFrom
which doesn't include resourceVersion — so the API server never
returns 409 and the retry never fires. Switch both Patch sites
to client.MergeFromWithOptions(WithOptimisticLock{}) so the
retry actually does what its caller assumes it does.
EnsureRoleBinding gets the same retry wrapper for parity.

Single-Get steady state: the previous structure did one Get to
check existence and a second Get inside the retry loop, even
when the object was already present and matched desired.
reconcileRoleBinding now receives the existing object as input
and uses it on the first attempt, only Get-ing again on actual
conflict-driven retries.

Helpers: extract mergeLabels (per-key overwrite), mergeSubjects
(additive append), containsSubject (semantic deep-equal), and
keep labelsNeedUpdate / roleBindingNeedsUpdate as no-Patch
short-circuits whose result mirrors the merge helpers exactly.

Tests: cover fresh creation, steady-state no-op (via Patch
interceptor counter, more reliable than the previous
ResourceVersion comparison which depended on fake-client RV
semantics that aren't part of the controller-runtime contract),
unrelated-label preservation, stale-label refresh, additive
subjects with user-added entries, AlreadyExists race during
pod startup (deterministic via interceptor), divergent
RoleRef error path, and the upgrade scenario for objects that
predate the recommended-labels feature.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request go Pull requests that update go code lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Adopt Kubernetes recommended labels

3 participants