Skip to content

Commit c829c06

Browse files
authored
Add additional volumes to pgbouncer (#4240)
Add additional volume for pgbouncer pods * Add additional volume for pgbouncer pods Change the API to allow users to specify preexisting PVCs to attach to specified containers in the pgbouncer instance pods. The spec allows users to specify whether to add the volume to - all containers (by omitting the containers list) - no containers (by specifying an empty containers list) - a list of named containers If any of the named containers isn't present, we continue to reconcile, but issue a warning event with the names of the missing containers. * Move additional volumes struct to shared_types * Don't need v1 of volumes struct Issues: [PGO-2557]
1 parent 2bed52d commit c829c06

File tree

10 files changed

+235
-93
lines changed

10 files changed

+235
-93
lines changed

config/crd/bases/postgres-operator.crunchydata.com_postgresclusters.yaml

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16097,6 +16097,58 @@ spec:
1609716097
- whenUnsatisfiable
1609816098
type: object
1609916099
type: array
16100+
volumes:
16101+
description: PGBouncerVolumesSpec defines the configuration
16102+
for pgBouncer additional volumes
16103+
properties:
16104+
additional:
16105+
description: Additional pre-existing volumes to add to
16106+
the pod.
16107+
items:
16108+
properties:
16109+
claimName:
16110+
description: Name of an existing PersistentVolumeClaim.
16111+
maxLength: 253
16112+
minLength: 1
16113+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
16114+
type: string
16115+
containers:
16116+
description: |-
16117+
The names of containers in which to mount this volume.
16118+
The default mounts the volume in *all* containers. An empty list does not mount the volume to any containers.
16119+
items:
16120+
maxLength: 63
16121+
minLength: 1
16122+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
16123+
type: string
16124+
maxItems: 10
16125+
type: array
16126+
x-kubernetes-list-type: set
16127+
name:
16128+
allOf:
16129+
- maxLength: 63
16130+
- maxLength: 55
16131+
description: |-
16132+
The name of the directory in which to mount this volume.
16133+
Volumes are mounted in containers at `/volumes/{name}`.
16134+
minLength: 1
16135+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
16136+
type: string
16137+
readOnly:
16138+
description: When true, mount the volume read-only,
16139+
otherwise read-write. Defaults to false.
16140+
type: boolean
16141+
required:
16142+
- claimName
16143+
- name
16144+
type: object
16145+
x-kubernetes-map-type: atomic
16146+
maxItems: 10
16147+
type: array
16148+
x-kubernetes-list-map-keys:
16149+
- name
16150+
x-kubernetes-list-type: map
16151+
type: object
1610016152
type: object
1610116153
required:
1610216154
- pgBouncer
@@ -34715,6 +34767,58 @@ spec:
3471534767
- whenUnsatisfiable
3471634768
type: object
3471734769
type: array
34770+
volumes:
34771+
description: PGBouncerVolumesSpec defines the configuration
34772+
for pgBouncer additional volumes
34773+
properties:
34774+
additional:
34775+
description: Additional pre-existing volumes to add to
34776+
the pod.
34777+
items:
34778+
properties:
34779+
claimName:
34780+
description: Name of an existing PersistentVolumeClaim.
34781+
maxLength: 253
34782+
minLength: 1
34783+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
34784+
type: string
34785+
containers:
34786+
description: |-
34787+
The names of containers in which to mount this volume.
34788+
The default mounts the volume in *all* containers. An empty list does not mount the volume to any containers.
34789+
items:
34790+
maxLength: 63
34791+
minLength: 1
34792+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
34793+
type: string
34794+
maxItems: 10
34795+
type: array
34796+
x-kubernetes-list-type: set
34797+
name:
34798+
allOf:
34799+
- maxLength: 63
34800+
- maxLength: 55
34801+
description: |-
34802+
The name of the directory in which to mount this volume.
34803+
Volumes are mounted in containers at `/volumes/{name}`.
34804+
minLength: 1
34805+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
34806+
type: string
34807+
readOnly:
34808+
description: When true, mount the volume read-only,
34809+
otherwise read-write. Defaults to false.
34810+
type: boolean
34811+
required:
34812+
- claimName
34813+
- name
34814+
type: object
34815+
x-kubernetes-map-type: atomic
34816+
maxItems: 10
34817+
type: array
34818+
x-kubernetes-list-map-keys:
34819+
- name
34820+
x-kubernetes-list-type: map
34821+
type: object
3471834822
type: object
3471934823
required:
3472034824
- pgBouncer

internal/controller/postgrescluster/instance.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1259,7 +1259,7 @@ func (r *Reconciler) reconcileInstance(
12591259

12601260
if len(missingContainers) > 0 {
12611261
r.Recorder.Eventf(cluster, corev1.EventTypeWarning, "SpecifiedContainerNotFound",
1262-
"The following containers were specified for additional volumes but cannot be found: %s.", missingContainers)
1262+
"The following Postgres pod containers were specified for additional volumes but cannot be found: %s.", missingContainers)
12631263
}
12641264
}
12651265

internal/controller/postgrescluster/pgbouncer.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,16 @@ func (r *Reconciler) generatePGBouncerDeployment(
475475
// Add tmp directory and volume for log files
476476
AddTMPEmptyDir(&deploy.Spec.Template)
477477

478+
// mount additional volumes to the pgbouncer containers
479+
if err == nil && cluster.Spec.Proxy.PGBouncer.Volumes != nil && len(cluster.Spec.Proxy.PGBouncer.Volumes.Additional) > 0 {
480+
missingContainers := addAdditionalVolumesToSpecifiedContainers(&deploy.Spec.Template, cluster.Spec.Proxy.PGBouncer.Volumes.Additional)
481+
482+
if len(missingContainers) > 0 {
483+
r.Recorder.Eventf(cluster, corev1.EventTypeWarning, "SpecifiedContainerNotFound",
484+
"The following PgBouncer pod containers were specified for additional volumes but cannot be found: %s.", missingContainers)
485+
}
486+
}
487+
478488
return deploy, true, err
479489
}
480490

internal/controller/postgrescluster/pgbouncer_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,36 @@ topologySpreadConstraints:
509509
assert.Assert(t, deploy.Spec.Template.Spec.TopologySpreadConstraints == nil)
510510
})
511511
})
512+
513+
t.Run("PodSpecWithAdditionalVolumes", func(t *testing.T) {
514+
cluster := cluster.DeepCopy()
515+
cluster.Spec.Proxy.PGBouncer.Volumes = &v1beta1.PGBouncerVolumesSpec{
516+
Additional: []v1beta1.AdditionalVolume{{
517+
ClaimName: "required",
518+
Name: "required",
519+
}},
520+
}
521+
522+
deploy, specified, err := reconciler.generatePGBouncerDeployment(
523+
ctx, cluster, primary, configmap, secret)
524+
525+
assert.NilError(t, err)
526+
assert.Assert(t, specified)
527+
528+
for _, container := range deploy.Spec.Template.Spec.Containers {
529+
assert.Assert(t, cmp.MarshalContains(container.VolumeMounts,
530+
`
531+
- mountPath: /volumes/required
532+
name: volumes-required`))
533+
}
534+
535+
assert.Assert(t, cmp.MarshalContains(
536+
deploy.Spec.Template.Spec.Volumes,
537+
`
538+
- name: volumes-required
539+
persistentVolumeClaim:
540+
claimName: required`))
541+
})
512542
}
513543

514544
func TestReconcilePGBouncerDisruptionBudget(t *testing.T) {

pkg/apis/postgres-operator.crunchydata.com/v1/postgrescluster_types.go

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -525,23 +525,7 @@ type PostgresInstanceSetSpec struct {
525525
// +optional
526526
TablespaceVolumes []TablespaceVolume `json:"tablespaceVolumes,omitempty"`
527527

528-
Volumes *PostgresVolumesSpec `json:"volumes,omitempty"`
529-
}
530-
531-
type PostgresVolumesSpec struct {
532-
// Additional pre-existing volumes to add to the pod.
533-
// ---
534-
// +optional
535-
// +listType=map
536-
// +listMapKey=name
537-
// +kubebuilder:validation:MaxItems=10
538-
Additional []v1beta1.AdditionalVolume `json:"additional,omitempty"`
539-
540-
// An ephemeral volume for temporary files.
541-
// More info: https://kubernetes.io/docs/concepts/storage/ephemeral-volumes
542-
// ---
543-
// +optional
544-
Temp *v1beta1.VolumeClaimSpec `json:"temp,omitempty"`
528+
Volumes *v1beta1.PostgresVolumesSpec `json:"volumes,omitempty"`
545529
}
546530

547531
type TablespaceVolume struct {

pkg/apis/postgres-operator.crunchydata.com/v1/zz_generated.deepcopy.go

Lines changed: 1 addition & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgbouncer_types.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,19 @@ type PGBouncerPodSpec struct {
131131
// More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
132132
// +optional
133133
TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty"`
134+
135+
Volumes *PGBouncerVolumesSpec `json:"volumes,omitempty"`
136+
}
137+
138+
// PGBouncerVolumesSpec defines the configuration for pgBouncer additional volumes
139+
type PGBouncerVolumesSpec struct {
140+
// Additional pre-existing volumes to add to the pod.
141+
// ---
142+
// +optional
143+
// +listType=map
144+
// +listMapKey=name
145+
// +kubebuilder:validation:MaxItems=10
146+
Additional []AdditionalVolume `json:"additional,omitempty"`
134147
}
135148

136149
// PGBouncerSidecars defines the configuration for pgBouncer sidecar containers

pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgrescluster_types.go

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -541,54 +541,6 @@ type PostgresVolumesSpec struct {
541541
Temp *VolumeClaimSpec `json:"temp,omitempty"`
542542
}
543543

544-
// ---
545-
// Only one applier should be managing each volume definition.
546-
// https://docs.k8s.io/reference/using-api/server-side-apply#merge-strategy
547-
// +structType=atomic
548-
type AdditionalVolume struct {
549-
// Name of an existing PersistentVolumeClaim.
550-
// ---
551-
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePersistentVolumeClaim
552-
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePersistentVolumeName
553-
//
554-
// +required
555-
ClaimName DNS1123Subdomain `json:"claimName"`
556-
557-
// The names of containers in which to mount this volume.
558-
// The default mounts the volume in *all* containers. An empty list does not mount the volume to any containers.
559-
// ---
560-
// These are matched against [corev1.Container.Name] in a PodSpec, which is a [DNS1123Label].
561-
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePodSpec
562-
//
563-
// Container names are unique within a Pod, so this list can be, too.
564-
// +listType=set
565-
//
566-
// +kubebuilder:validation:MaxItems=10
567-
// +optional
568-
Containers []DNS1123Label `json:"containers"`
569-
570-
// The name of the directory in which to mount this volume.
571-
// Volumes are mounted in containers at `/volumes/{name}`.
572-
// ---
573-
// This also goes into the [corev1.Volume.Name] field, which is a [DNS1123Label].
574-
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePodSpec
575-
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidateVolumes
576-
//
577-
// We prepend "volumes-" to avoid collisions with other [corev1.PodSpec.Volumes],
578-
// so the maximum is 8 less than the inherited 63.
579-
// +kubebuilder:validation:MaxLength=55
580-
//
581-
// +required
582-
Name DNS1123Label `json:"name"`
583-
584-
// When true, mount the volume read-only, otherwise read-write. Defaults to false.
585-
// ---
586-
// [corev1.VolumeMount.ReadOnly]
587-
//
588-
// +optional
589-
ReadOnly bool `json:"readOnly,omitempty"`
590-
}
591-
592544
type TablespaceVolume struct {
593545
// This value goes into
594546
// a. the name of a corev1.PersistentVolumeClaim,

pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,51 @@ func (meta *Metadata) GetAnnotationsOrNil() map[string]string {
256256
}
257257
return meta.Annotations
258258
}
259+
260+
// ---
261+
// Only one applier should be managing each volume definition.
262+
// https://docs.k8s.io/reference/using-api/server-side-apply#merge-strategy
263+
// +structType=atomic
264+
type AdditionalVolume struct {
265+
// Name of an existing PersistentVolumeClaim.
266+
// ---
267+
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePersistentVolumeClaim
268+
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePersistentVolumeName
269+
//
270+
// +required
271+
ClaimName DNS1123Subdomain `json:"claimName"`
272+
273+
// The names of containers in which to mount this volume.
274+
// The default mounts the volume in *all* containers. An empty list does not mount the volume to any containers.
275+
// ---
276+
// These are matched against [corev1.Container.Name] in a PodSpec, which is a [DNS1123Label].
277+
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePodSpec
278+
//
279+
// Container names are unique within a Pod, so this list can be, too.
280+
// +listType=set
281+
//
282+
// +kubebuilder:validation:MaxItems=10
283+
// +optional
284+
Containers []DNS1123Label `json:"containers"`
285+
286+
// The name of the directory in which to mount this volume.
287+
// Volumes are mounted in containers at `/volumes/{name}`.
288+
// ---
289+
// This also goes into the [corev1.Volume.Name] field, which is a [DNS1123Label].
290+
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePodSpec
291+
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidateVolumes
292+
//
293+
// We prepend "volumes-" to avoid collisions with other [corev1.PodSpec.Volumes],
294+
// so the maximum is 8 less than the inherited 63.
295+
// +kubebuilder:validation:MaxLength=55
296+
//
297+
// +required
298+
Name DNS1123Label `json:"name"`
299+
300+
// When true, mount the volume read-only, otherwise read-write. Defaults to false.
301+
// ---
302+
// [corev1.VolumeMount.ReadOnly]
303+
//
304+
// +optional
305+
ReadOnly bool `json:"readOnly,omitempty"`
306+
}

0 commit comments

Comments
 (0)