Conversation
| if cluster.CompareVersion("2.9.0") >= 0 { | ||
| for _, p := range spec.SidecarPVCs { | ||
| instance.Spec.VolumeClaimTemplates = append(instance.Spec.VolumeClaimTemplates, corev1.PersistentVolumeClaim{ | ||
| ObjectMeta: metav1.ObjectMeta{Name: p.Name}, | ||
| Spec: p.Spec, | ||
| }) | ||
| } | ||
| } |
There was a problem hiding this comment.
does this mean that users can only add sidecar PVCs while creating clusters? i guess we had the same limitation in other operators.
percona/controller/pgcluster/pvc.go
Outdated
There was a problem hiding this comment.
but if we are creating PVCs ourselves why don't we just add them into statefulset volumes so they can also be added after cluster creation?
There was a problem hiding this comment.
ok, i now realized we're doing this only for pgbouncer because it's a deployment. but if we do this for all, we'd overcome the limitation of adding sidecar pvcs after creation
There was a problem hiding this comment.
i don't think we should downgrade
hack/tools/.gitignore
Outdated
percona/controller/pgcluster/pvc.go
Outdated
There was a problem hiding this comment.
should we have some sort of labels added here so that we know that these pvcs are created by the operator?
| err := cl.Get(ctx, client.ObjectKeyFromObject(pvc), &corev1.PersistentVolumeClaim{}) | ||
| if err == nil { | ||
| // already exists | ||
| continue |
There was a problem hiding this comment.
What should happen if the pvcs are updated in terms of specs? should we update them of skip?
|
let's check also why unit tests are failing on this pr |
There was a problem hiding this comment.
Pull request overview
Adds support for configuring extra volumes and operator-managed PVCs for sidecar containers across instance pods, pgBouncer, and pgBackRest repoHost, along with the necessary API/plumbing, RBAC, and tests.
Changes:
- Extend CRDs/types with
sidecarVolumesandsidecarPVCsfor instances, pgBouncer, and pgBackRest repoHost. - Reconcile pod specs to mount the configured sidecar volumes/PVCs, and add a controller reconciler to create/update the defined PVCs.
- Update RBAC and sidecar-related unit/E2E tests to cover the new fields.
Reviewed changes
Copilot reviewed 20 out of 28 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/apis/postgres-operator.crunchydata.com/v1beta1/zz_generated.deepcopy.go | Deepcopy updates for new fields and new SidecarPVC type. |
| pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgrescluster_types.go | Adds sidecarVolumes/sidecarPVCs to instance set spec + defines SidecarPVC. |
| pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgbouncer_types.go | Adds sidecarVolumes/sidecarPVCs to pgBouncer pod spec. |
| pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgbackrest_types.go | Adds sidecarVolumes/sidecarPVCs to pgBackRest repoHost spec. |
| pkg/apis/pgv2.percona.com/v2/zz_generated.deepcopy.go | Deepcopy updates for new Percona API fields. |
| pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go | Adds Percona-level fields and maps them through ToCrunchy(). |
| percona/controller/pgcluster/pvc.go | New reconciler to create/update PVCs declared via sidecarPVCs. |
| percona/controller/pgcluster/controller_test.go | Extends sidecar tests to assert volumes + PVC-backed volumes are present. |
| percona/controller/pgcluster/controller.go | Calls PVC reconciler and adds PVC RBAC marker. |
| internal/postgres/reconcile.go | Adds sidecarVolumes to instance pods (version-gated). |
| internal/pgbouncer/reconcile.go | Adds sidecarVolumes and PVC-backed volumes to pgBouncer pod spec (version-gated). |
| internal/controller/postgrescluster/pgbackrest.go | Adds sidecarVolumes and PVC-backed volumes to repoHost pod template (version-gated). |
| internal/controller/postgrescluster/instance.go | Adds PVC-backed volumes to instance StatefulSet pod template (version-gated). |
| e2e-tests/tests/sidecars/01-create-cluster.yaml | Sets sidecarVolumes/sidecarPVCs fields in the sidecars E2E test. |
| e2e-tests/tests/sidecars/01-assert.yaml | Adds assertions for PVC creation/binding in the sidecars E2E test. |
| deploy/rbac.yaml | Grants PVC verbs in deployment RBAC. |
| deploy/cw-rbac.yaml | Same RBAC updates for cw deployment. |
| config/rbac/namespace/role.yaml | Grants PVC verbs in generated namespace Role. |
| config/rbac/cluster/role.yaml | Grants PVC verbs in generated cluster Role. |
| Makefile | Minor formatting/line fix in after-release target. |
pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgrescluster_types.go
Show resolved
Hide resolved
| | yq eval '.spec.instances[0].sidecarVolumes = [{"name": "sidecar-secret", "secret": {"secretName": "mysecret"}}]' - \ | ||
| | yq eval '.spec.instances[0].sidecarPVCs = [{"name": "sidecar-instance-claim", "spec": {"resources": {"requests": {"storage": "1Gi"}}, "volumeMode": "Filesystem", "accessModes": ["ReadWriteOnce"]}}]' - \ | ||
| | yq eval '.spec.proxy.pgBouncer.sidecars = [{"name": "sidecar1", "image": "busybox", "command": ["sleep", "30d"]}]' - \ | ||
| | yq eval '.spec.proxy.pgBouncer.sidecarVolumes = [{"name": "sidecar-secret", "secret": {"secretName": "mysecret"}}]' - \ | ||
| | yq eval '.spec.proxy.pgBouncer.sidecarPVCs = [{"name": "sidecar-pgbouncer-claim", "spec": {"resources": {"requests": {"storage": "1Gi"}}, "volumeMode": "Filesystem", "accessModes": ["ReadWriteOnce"]}}]' - \ | ||
| | yq eval '.spec.backups.pgbackrest.repoHost.sidecars = [{"name": "sidecar1", "image": "busybox", "command": ["sleep", "30d"]}]' - \ | ||
| | yq eval '.spec.backups.pgbackrest.repoHost.sidecarVolumes = [{"name": "sidecar-secret", "secret": {"secretName": "mysecret"}}]' - \ | ||
| | yq eval '.spec.backups.pgbackrest.repoHost.sidecarPVCs = [{"name": "sidecar-repohost-claim", "spec": {"resources": {"requests": {"storage": "1Gi"}}, "volumeMode": "Filesystem", "accessModes": ["ReadWriteOnce"]}}]' - \ |
There was a problem hiding this comment.
Problem: The E2E test references a secret named "mysecret" that doesn't appear to be created in the test setup.
Why it matters: If the secret doesn't exist, the sidecarVolumes configuration will fail when Kubernetes tries to mount it, causing pods to be stuck in a pending or error state. The test may pass if the volume is defined but never actually mounted by a sidecar container, masking this issue.
Fix: Either create the secret "mysecret" in the test setup (e.g., in 00-deploy-operator.yaml or a new 00-create-secret.yaml step), or use a volume type that doesn't require external resources (like emptyDir) if the test is only validating that volumes are properly added to the pod spec.
| for _, sidecarPVC := range pvcs { | ||
| pvc := new(corev1.PersistentVolumeClaim) | ||
| pvc.Name = sidecarPVC.Name | ||
| pvc.Namespace = cr.Namespace | ||
|
|
||
| if err := cl.Get(ctx, client.ObjectKeyFromObject(pvc), pvc); err != nil { | ||
| if !k8serrors.IsNotFound(err) { | ||
| return errors.Wrapf(err, "get %s", client.ObjectKeyFromObject(pvc).String()) | ||
| } | ||
| pvc.Spec = sidecarPVC.Spec | ||
| pvc.Labels = ls | ||
| if err := cl.Create(ctx, pvc); err != nil { | ||
| return errors.Wrap(err, "failed to create pvc") | ||
| } | ||
| continue |
There was a problem hiding this comment.
Problem: PVCs created by this function do not have a controller reference set.
Why it matters: Without a controller reference, these PVCs will not be garbage-collected when the cluster is deleted. This leads to resource leaks where PVCs persist after cluster deletion, potentially causing issues with storage quotas and requiring manual cleanup.
Fix: Add a controller reference using controllerutil.SetControllerReference before creating the PVC. This ensures proper ownership and automatic cleanup. See percona/controller/pgcluster/backup.go:191 and percona/controller/pgcluster/patroniversion.go:180 for examples of this pattern in the codebase.
| func ensureSidecarPVCs( | ||
| ctx context.Context, | ||
| cl client.Client, | ||
| cr *v2.PerconaPGCluster, | ||
| pvcs []v1beta1.SidecarPVC, | ||
| ls map[string]string, | ||
| ) error { | ||
| for _, sidecarPVC := range pvcs { | ||
| pvc := new(corev1.PersistentVolumeClaim) | ||
| pvc.Name = sidecarPVC.Name | ||
| pvc.Namespace = cr.Namespace | ||
|
|
||
| if err := cl.Get(ctx, client.ObjectKeyFromObject(pvc), pvc); err != nil { | ||
| if !k8serrors.IsNotFound(err) { | ||
| return errors.Wrapf(err, "get %s", client.ObjectKeyFromObject(pvc).String()) | ||
| } | ||
| pvc.Spec = sidecarPVC.Spec | ||
| pvc.Labels = ls | ||
| if err := cl.Create(ctx, pvc); err != nil { | ||
| return errors.Wrap(err, "failed to create pvc") | ||
| } | ||
| continue | ||
| } | ||
| if v := pvc.Labels[naming.LabelPerconaManagedBy]; v != "percona-postgresql-operator" { | ||
| return errors.Errorf("PersistentVolumeClaim %s already exists and not managed by percona-postgresql-operator: %s", client.ObjectKeyFromObject(pvc).String(), v) | ||
| } | ||
| if v := pvc.Labels[naming.LabelPerconaInstance]; v != cr.Name { | ||
| return errors.Errorf("PersistentVolumeClaim %s already exists and belongs to another cluster %s", client.ObjectKeyFromObject(pvc).String(), v) | ||
| } | ||
|
|
||
| if err := retry.RetryOnConflict(retry.DefaultRetry, func() error { | ||
| if err := cl.Get(ctx, client.ObjectKeyFromObject(pvc), pvc); err != nil { | ||
| return err | ||
| } | ||
| maps.Copy(pvc.Labels, ls) | ||
|
|
||
| // It's only allowed to update resources.requests and volumeAttributesClassName | ||
| pvc.Spec.Resources.Requests = sidecarPVC.Spec.Resources.Requests | ||
| pvc.Spec.VolumeAttributesClassName = sidecarPVC.Spec.VolumeAttributesClassName | ||
|
|
||
| return cl.Update(ctx, pvc) | ||
| }); err != nil { | ||
| return errors.Wrapf(err, "update PersistentVolumeClaim %s", client.ObjectKeyFromObject(pvc).String()) | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| } |
There was a problem hiding this comment.
Problem: Missing logging for important operator actions during PVC reconciliation.
Why it matters: According to the coding guideline "Add logging for important operator actions (reconcile steps, errors, retries)", logging helps track operator behavior and debug issues in production. PVC creation, updates, and conflicts are important reconcile steps that should be logged.
Fix: Add structured logging using logging.FromContext(ctx) with appropriate log levels (Info for creation/updates, Error for failures). For example, log when creating a PVC, when updating an existing PVC, and when encountering conflicts.
| // K8SPG-864 | ||
| type SidecarPVC struct { | ||
| Name string `json:"name"` | ||
|
|
There was a problem hiding this comment.
Problem: Missing documentation comments for the SidecarPVC type.
Why it matters: The SidecarPVC type is a new public API type that will be used by end-users in their CR YAML files. Following codebase conventions, API types should have documentation describing their purpose and fields.
Fix: Add a documentation comment above the SidecarPVC type definition explaining what it is and how it's used, similar to other type definitions in this file. Also add comments for the Name and Spec fields.
| // K8SPG-864 | |
| type SidecarPVC struct { | |
| Name string `json:"name"` | |
| // K8SPG-864 | |
| // SidecarPVC describes a PersistentVolumeClaim that should be created and | |
| // mounted for a sidecar container. | |
| type SidecarPVC struct { | |
| // Name is the name of the PersistentVolumeClaim used by the sidecar. | |
| Name string `json:"name"` | |
| // Spec defines the desired specification of the PersistentVolumeClaim. |
| type SidecarPVC struct { | ||
| Name string `json:"name"` | ||
|
|
||
| Spec corev1.PersistentVolumeClaimSpec `json:"spec"` | ||
| } |
There was a problem hiding this comment.
Problem: The SidecarPVC type lacks validation annotations.
Why it matters: Other API types in this codebase use kubebuilder validation annotations (e.g., +kubebuilder:validation:Required) to enforce constraints and provide clear error messages to users. The Name field should be validated (e.g., pattern, required) to ensure proper resource naming in Kubernetes.
Fix: Add appropriate validation annotations. At minimum, the Name field should have +kubebuilder:validation:Required and likely a pattern constraint similar to other name fields in the codebase (e.g., see postgrescluster_types.go:480).
commit: 4866e97 |
https://perconadev.atlassian.net/browse/K8SPG-864
DESCRIPTION
This PR adds the following fields to the
cr.yaml:.spec.instances[].sidecarPVCs.spec.instances[].sidecarVolumes.spec.proxy.pgBouncer.sidecarPVCs.spec.proxy.pgBouncer.sidecarVolumes.spec.backups.pgbackrest.repoHost.sidecarPVCs.spec.backups.pgbackrest.repoHost.sidecarVolumesThe
sidecarPVCsfield definesPersistentVolumeClaimsthat should be created and associated with a specific resource. Example:The
sidecarVolumesfield defines volumes that should be attached to a specific resource. Example:Helm PR: percona/percona-helm-charts#783
CHECKLIST
Jira
Needs Doc) and QA (Needs QA)?Tests
Config/Logging/Testability