Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16097,6 +16097,58 @@ spec:
- whenUnsatisfiable
type: object
type: array
volumes:
description: PGBouncerVolumesSpec defines the configuration
for pgBouncer additional volumes
properties:
additional:
description: Additional pre-existing volumes to add to
the pod.
items:
properties:
claimName:
description: Name of an existing PersistentVolumeClaim.
maxLength: 253
minLength: 1
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
containers:
description: |-
The names of containers in which to mount this volume.
The default mounts the volume in *all* containers. An empty list does not mount the volume to any containers.
items:
maxLength: 63
minLength: 1
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
type: string
maxItems: 10
type: array
x-kubernetes-list-type: set
name:
allOf:
- maxLength: 63
- maxLength: 55
description: |-
The name of the directory in which to mount this volume.
Volumes are mounted in containers at `/volumes/{name}`.
minLength: 1
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
type: string
readOnly:
description: When true, mount the volume read-only,
otherwise read-write. Defaults to false.
type: boolean
required:
- claimName
- name
type: object
x-kubernetes-map-type: atomic
maxItems: 10
type: array
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
type: object
type: object
required:
- pgBouncer
Expand Down Expand Up @@ -34715,6 +34767,58 @@ spec:
- whenUnsatisfiable
type: object
type: array
volumes:
description: PGBouncerVolumesSpec defines the configuration
for pgBouncer additional volumes
properties:
additional:
description: Additional pre-existing volumes to add to
the pod.
items:
properties:
claimName:
description: Name of an existing PersistentVolumeClaim.
maxLength: 253
minLength: 1
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
containers:
description: |-
The names of containers in which to mount this volume.
The default mounts the volume in *all* containers. An empty list does not mount the volume to any containers.
items:
maxLength: 63
minLength: 1
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
type: string
maxItems: 10
type: array
x-kubernetes-list-type: set
name:
allOf:
- maxLength: 63
- maxLength: 55
description: |-
The name of the directory in which to mount this volume.
Volumes are mounted in containers at `/volumes/{name}`.
minLength: 1
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
type: string
readOnly:
description: When true, mount the volume read-only,
otherwise read-write. Defaults to false.
type: boolean
required:
- claimName
- name
type: object
x-kubernetes-map-type: atomic
maxItems: 10
type: array
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
type: object
type: object
required:
- pgBouncer
Expand Down
2 changes: 1 addition & 1 deletion internal/controller/postgrescluster/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -1259,7 +1259,7 @@ func (r *Reconciler) reconcileInstance(

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

Expand Down
10 changes: 10 additions & 0 deletions internal/controller/postgrescluster/pgbouncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,16 @@ func (r *Reconciler) generatePGBouncerDeployment(
// Add tmp directory and volume for log files
AddTMPEmptyDir(&deploy.Spec.Template)

// mount additional volumes to the pgbouncer containers
if err == nil && cluster.Spec.Proxy.PGBouncer.Volumes != nil && len(cluster.Spec.Proxy.PGBouncer.Volumes.Additional) > 0 {
missingContainers := addAdditionalVolumesToSpecifiedContainers(&deploy.Spec.Template, cluster.Spec.Proxy.PGBouncer.Volumes.Additional)

if len(missingContainers) > 0 {
r.Recorder.Eventf(cluster, corev1.EventTypeWarning, "SpecifiedContainerNotFound",
"The following PgBouncer pod containers were specified for additional volumes but cannot be found: %s.", missingContainers)
}
}

return deploy, true, err
}

Expand Down
30 changes: 30 additions & 0 deletions internal/controller/postgrescluster/pgbouncer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,36 @@ topologySpreadConstraints:
assert.Assert(t, deploy.Spec.Template.Spec.TopologySpreadConstraints == nil)
})
})

t.Run("PodSpecWithAdditionalVolumes", func(t *testing.T) {
cluster := cluster.DeepCopy()
cluster.Spec.Proxy.PGBouncer.Volumes = &v1beta1.PGBouncerVolumesSpec{
Additional: []v1beta1.AdditionalVolume{{
ClaimName: "required",
Name: "required",
}},
}

deploy, specified, err := reconciler.generatePGBouncerDeployment(
ctx, cluster, primary, configmap, secret)

assert.NilError(t, err)
assert.Assert(t, specified)

for _, container := range deploy.Spec.Template.Spec.Containers {
assert.Assert(t, cmp.MarshalContains(container.VolumeMounts,
`
- mountPath: /volumes/required
name: volumes-required`))
}

assert.Assert(t, cmp.MarshalContains(
deploy.Spec.Template.Spec.Volumes,
`
- name: volumes-required
persistentVolumeClaim:
claimName: required`))
})
}

func TestReconcilePGBouncerDisruptionBudget(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -525,23 +525,7 @@ type PostgresInstanceSetSpec struct {
// +optional
TablespaceVolumes []TablespaceVolume `json:"tablespaceVolumes,omitempty"`

Volumes *PostgresVolumesSpec `json:"volumes,omitempty"`
}

type PostgresVolumesSpec struct {
// Additional pre-existing volumes to add to the pod.
// ---
// +optional
// +listType=map
// +listMapKey=name
// +kubebuilder:validation:MaxItems=10
Additional []v1beta1.AdditionalVolume `json:"additional,omitempty"`

// An ephemeral volume for temporary files.
// More info: https://kubernetes.io/docs/concepts/storage/ephemeral-volumes
// ---
// +optional
Temp *v1beta1.VolumeClaimSpec `json:"temp,omitempty"`
Volumes *v1beta1.PostgresVolumesSpec `json:"volumes,omitempty"`
}

type TablespaceVolume struct {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,19 @@ type PGBouncerPodSpec struct {
// More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
// +optional
TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty"`

Volumes *PGBouncerVolumesSpec `json:"volumes,omitempty"`
}

// PGBouncerVolumesSpec defines the configuration for pgBouncer additional volumes
type PGBouncerVolumesSpec struct {
// Additional pre-existing volumes to add to the pod.
// ---
// +optional
// +listType=map
// +listMapKey=name
// +kubebuilder:validation:MaxItems=10
Additional []AdditionalVolume `json:"additional,omitempty"`
}

// PGBouncerSidecars defines the configuration for pgBouncer sidecar containers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -541,54 +541,6 @@ type PostgresVolumesSpec struct {
Temp *VolumeClaimSpec `json:"temp,omitempty"`
}

// ---
// Only one applier should be managing each volume definition.
// https://docs.k8s.io/reference/using-api/server-side-apply#merge-strategy
// +structType=atomic
type AdditionalVolume struct {
// Name of an existing PersistentVolumeClaim.
// ---
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePersistentVolumeClaim
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePersistentVolumeName
//
// +required
ClaimName DNS1123Subdomain `json:"claimName"`

// The names of containers in which to mount this volume.
// The default mounts the volume in *all* containers. An empty list does not mount the volume to any containers.
// ---
// These are matched against [corev1.Container.Name] in a PodSpec, which is a [DNS1123Label].
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePodSpec
//
// Container names are unique within a Pod, so this list can be, too.
// +listType=set
//
// +kubebuilder:validation:MaxItems=10
// +optional
Containers []DNS1123Label `json:"containers"`

// The name of the directory in which to mount this volume.
// Volumes are mounted in containers at `/volumes/{name}`.
// ---
// This also goes into the [corev1.Volume.Name] field, which is a [DNS1123Label].
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePodSpec
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidateVolumes
//
// We prepend "volumes-" to avoid collisions with other [corev1.PodSpec.Volumes],
// so the maximum is 8 less than the inherited 63.
// +kubebuilder:validation:MaxLength=55
//
// +required
Name DNS1123Label `json:"name"`

// When true, mount the volume read-only, otherwise read-write. Defaults to false.
// ---
// [corev1.VolumeMount.ReadOnly]
//
// +optional
ReadOnly bool `json:"readOnly,omitempty"`
}

type TablespaceVolume struct {
// This value goes into
// a. the name of a corev1.PersistentVolumeClaim,
Expand Down
48 changes: 48 additions & 0 deletions pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,51 @@ func (meta *Metadata) GetAnnotationsOrNil() map[string]string {
}
return meta.Annotations
}

// ---
// Only one applier should be managing each volume definition.
// https://docs.k8s.io/reference/using-api/server-side-apply#merge-strategy
// +structType=atomic
type AdditionalVolume struct {
Copy link
Member

Choose a reason for hiding this comment

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

👍🏻 to this move. Watch out for conflict with 6b01868.

// Name of an existing PersistentVolumeClaim.
// ---
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePersistentVolumeClaim
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePersistentVolumeName
//
// +required
ClaimName DNS1123Subdomain `json:"claimName"`

// The names of containers in which to mount this volume.
// The default mounts the volume in *all* containers. An empty list does not mount the volume to any containers.
// ---
// These are matched against [corev1.Container.Name] in a PodSpec, which is a [DNS1123Label].
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePodSpec
//
// Container names are unique within a Pod, so this list can be, too.
// +listType=set
//
// +kubebuilder:validation:MaxItems=10
// +optional
Containers []DNS1123Label `json:"containers"`

// The name of the directory in which to mount this volume.
// Volumes are mounted in containers at `/volumes/{name}`.
// ---
// This also goes into the [corev1.Volume.Name] field, which is a [DNS1123Label].
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidatePodSpec
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidateVolumes
//
// We prepend "volumes-" to avoid collisions with other [corev1.PodSpec.Volumes],
// so the maximum is 8 less than the inherited 63.
// +kubebuilder:validation:MaxLength=55
//
// +required
Name DNS1123Label `json:"name"`

// When true, mount the volume read-only, otherwise read-write. Defaults to false.
// ---
// [corev1.VolumeMount.ReadOnly]
//
// +optional
ReadOnly bool `json:"readOnly,omitempty"`
}
Loading
Loading