Skip to content

Commit 7844fe2

Browse files
Attach additional volume for postgres, (#4210)
* Add additional volume for postgres pods Change the API to allow users to specify preexisting PVCs to attach to specified containers in the postgres 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. Issues: [PGO-2556] Co-authored-by: Drew Sessler <[email protected]>
1 parent 0c2ca1b commit 7844fe2

File tree

9 files changed

+539
-0
lines changed

9 files changed

+539
-0
lines changed

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

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11027,6 +11027,50 @@ spec:
1102711027
type: array
1102811028
volumes:
1102911029
properties:
11030+
additional:
11031+
description: Additional pre-existing volumes to add to the
11032+
pod.
11033+
items:
11034+
properties:
11035+
claimName:
11036+
description: A reference to a preexisting PVC.
11037+
maxLength: 253
11038+
minLength: 1
11039+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
11040+
type: string
11041+
containers:
11042+
description: |-
11043+
The containers to attach this volume to.
11044+
An omitted `Containers` field matches all containers.
11045+
An empty `Containers` field matches no containers.
11046+
items:
11047+
type: string
11048+
maxItems: 10
11049+
type: array
11050+
x-kubernetes-list-type: atomic
11051+
name:
11052+
allOf:
11053+
- maxLength: 63
11054+
- maxLength: 55
11055+
description: |-
11056+
The name of the volume used for mounting path.
11057+
Volumes are mounted in the pods at `volumes/<NAME>`
11058+
Must be unique.
11059+
minLength: 1
11060+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
11061+
type: string
11062+
readOnly:
11063+
description: Sets the write/read mode of the volume
11064+
type: boolean
11065+
required:
11066+
- claimName
11067+
- name
11068+
type: object
11069+
maxItems: 10
11070+
type: array
11071+
x-kubernetes-list-map-keys:
11072+
- name
11073+
x-kubernetes-list-type: map
1103011074
temp:
1103111075
description: |-
1103211076
An ephemeral volume for temporary files.
@@ -29598,6 +29642,50 @@ spec:
2959829642
type: array
2959929643
volumes:
2960029644
properties:
29645+
additional:
29646+
description: Additional pre-existing volumes to add to the
29647+
pod.
29648+
items:
29649+
properties:
29650+
claimName:
29651+
description: A reference to a preexisting PVC.
29652+
maxLength: 253
29653+
minLength: 1
29654+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
29655+
type: string
29656+
containers:
29657+
description: |-
29658+
The containers to attach this volume to.
29659+
An omitted `Containers` field matches all containers.
29660+
An empty `Containers` field matches no containers.
29661+
items:
29662+
type: string
29663+
maxItems: 10
29664+
type: array
29665+
x-kubernetes-list-type: atomic
29666+
name:
29667+
allOf:
29668+
- maxLength: 63
29669+
- maxLength: 55
29670+
description: |-
29671+
The name of the volume used for mounting path.
29672+
Volumes are mounted in the pods at `volumes/<NAME>`
29673+
Must be unique.
29674+
minLength: 1
29675+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
29676+
type: string
29677+
readOnly:
29678+
description: Sets the write/read mode of the volume
29679+
type: boolean
29680+
required:
29681+
- claimName
29682+
- name
29683+
type: object
29684+
maxItems: 10
29685+
type: array
29686+
x-kubernetes-list-map-keys:
29687+
- name
29688+
x-kubernetes-list-type: map
2960129689
temp:
2960229690
description: |-
2960329691
An ephemeral volume for temporary files.

internal/controller/postgrescluster/instance.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,16 @@ func (r *Reconciler) reconcileInstance(
12531253
addDevSHM(&instance.Spec.Template)
12541254
}
12551255

1256+
// mount additional volumes to the Postgres instance containers
1257+
if err == nil && spec.Volumes != nil && len(spec.Volumes.Additional) > 0 {
1258+
missingContainers := addAdditionalVolumesToSpecifiedContainers(&instance.Spec.Template, spec.Volumes.Additional)
1259+
1260+
if len(missingContainers) > 0 {
1261+
r.Recorder.Eventf(cluster, corev1.EventTypeWarning, "SpecifiedContainerNotFound",
1262+
"The following containers were specified for additional volumes but cannot be found: %s.", missingContainers)
1263+
}
1264+
}
1265+
12561266
if err == nil {
12571267
err = errors.WithStack(r.apply(ctx, instance))
12581268
}

internal/controller/postgrescluster/util.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ import (
1313
corev1 "k8s.io/api/core/v1"
1414
"k8s.io/apimachinery/pkg/api/resource"
1515
"k8s.io/apimachinery/pkg/util/rand"
16+
"k8s.io/apimachinery/pkg/util/sets"
1617

1718
"github.com/crunchydata/postgres-operator/internal/initialize"
1819
"github.com/crunchydata/postgres-operator/internal/naming"
20+
"github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1"
1921
)
2022

2123
var tmpDirSizeLimit = resource.MustParse("16Mi")
@@ -285,3 +287,81 @@ func safeHash32(content func(w io.Writer) error) (string, error) {
285287
}
286288
return rand.SafeEncodeString(fmt.Sprint(hash.Sum32())), nil
287289
}
290+
291+
// AdditionalVolumeMount returns the name and mount path of the additional volume.
292+
func AdditionalVolumeMount(name string, readOnly bool) corev1.VolumeMount {
293+
return corev1.VolumeMount{
294+
Name: fmt.Sprintf("volumes-%s", name),
295+
MountPath: "/volumes/" + name,
296+
ReadOnly: readOnly,
297+
}
298+
}
299+
300+
// addAdditionalVolumesToSpecifiedContainers adds additional volumes to the specified
301+
// containers in the specified pod
302+
// addAdditionalVolumesToSpecifiedContainers adds the volumes to the pod
303+
// as `volumes-<additionalVolumeRequest.Name>`
304+
// and adds the directory to the path `/volumes/<additionalVolumeRequest.Name>`
305+
func addAdditionalVolumesToSpecifiedContainers(template *corev1.PodTemplateSpec,
306+
additionalVolumes []v1beta1.AdditionalVolume) []string {
307+
308+
missingContainers := []string{}
309+
for _, additionalVolumeRequest := range additionalVolumes {
310+
311+
additionalVolumeMount := AdditionalVolumeMount(
312+
additionalVolumeRequest.Name,
313+
additionalVolumeRequest.ReadOnly,
314+
)
315+
316+
additionalVolume := corev1.Volume{
317+
Name: additionalVolumeMount.Name,
318+
VolumeSource: corev1.VolumeSource{
319+
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
320+
ClaimName: additionalVolumeRequest.ClaimName,
321+
ReadOnly: additionalVolumeMount.ReadOnly,
322+
},
323+
},
324+
}
325+
326+
// Create a set of all the requested containers,
327+
// then in the loops below when we attach the volume to a container,
328+
// we can safely remove that container name from the set.
329+
// This gives us a way to track the containers that are requested but not found.
330+
// This relies on `containers` and `initContainers` together being unique.
331+
// - https://github.com/kubernetes/api/blob/b40c1cacbb902b21a7e0c7bf0967321860c1a632/core/v1/types.go#L3895C27-L3896C33
332+
names := sets.New(additionalVolumeRequest.Containers...)
333+
allContainers := false
334+
// If the containers list is omitted, we add the volume to all containers
335+
if additionalVolumeRequest.Containers == nil {
336+
allContainers = true
337+
}
338+
339+
for i := range template.Spec.Containers {
340+
if allContainers || names.Has(template.Spec.Containers[i].Name) {
341+
template.Spec.Containers[i].VolumeMounts = append(
342+
template.Spec.Containers[i].VolumeMounts,
343+
additionalVolumeMount)
344+
345+
names.Delete(template.Spec.Containers[i].Name)
346+
}
347+
}
348+
349+
for i := range template.Spec.InitContainers {
350+
if allContainers || names.Has(template.Spec.InitContainers[i].Name) {
351+
template.Spec.InitContainers[i].VolumeMounts = append(
352+
template.Spec.InitContainers[i].VolumeMounts,
353+
additionalVolumeMount)
354+
355+
names.Delete(template.Spec.InitContainers[i].Name)
356+
357+
}
358+
}
359+
360+
missingContainers = append(missingContainers, names.UnsortedList()...)
361+
362+
template.Spec.Volumes = append(
363+
template.Spec.Volumes,
364+
additionalVolume)
365+
}
366+
return missingContainers
367+
}

0 commit comments

Comments
 (0)