Skip to content

Commit b4c3089

Browse files
authored
Add additional volumes to pgadmin (#4255)
Issues: [PGO-2639]
1 parent 1e43226 commit b4c3089

File tree

10 files changed

+188
-11
lines changed

10 files changed

+188
-11
lines changed

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2621,6 +2621,57 @@ spec:
26212621
x-kubernetes-list-map-keys:
26222622
- username
26232623
x-kubernetes-list-type: map
2624+
volumes:
2625+
description: PGAdminVolumesSpec defines the configuration for pgAdmin
2626+
additional volumes
2627+
properties:
2628+
additional:
2629+
description: Additional pre-existing volumes to add to the pod.
2630+
items:
2631+
properties:
2632+
claimName:
2633+
description: Name of an existing PersistentVolumeClaim.
2634+
maxLength: 253
2635+
minLength: 1
2636+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
2637+
type: string
2638+
containers:
2639+
description: |-
2640+
The names of containers in which to mount this volume.
2641+
The default mounts the volume in *all* containers. An empty list does not mount the volume to any containers.
2642+
items:
2643+
maxLength: 63
2644+
minLength: 1
2645+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
2646+
type: string
2647+
maxItems: 10
2648+
type: array
2649+
x-kubernetes-list-type: set
2650+
name:
2651+
allOf:
2652+
- maxLength: 63
2653+
- maxLength: 55
2654+
description: |-
2655+
The name of the directory in which to mount this volume.
2656+
Volumes are mounted in containers at `/volumes/{name}`.
2657+
minLength: 1
2658+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
2659+
type: string
2660+
readOnly:
2661+
description: When true, mount the volume read-only, otherwise
2662+
read-write. Defaults to false.
2663+
type: boolean
2664+
required:
2665+
- claimName
2666+
- name
2667+
type: object
2668+
x-kubernetes-map-type: atomic
2669+
maxItems: 10
2670+
type: array
2671+
x-kubernetes-list-map-keys:
2672+
- name
2673+
x-kubernetes-list-type: map
2674+
type: object
26242675
required:
26252676
- dataVolumeClaimSpec
26262677
type: object

internal/controller/postgrescluster/instance.go

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

11971197
// mount additional volumes to the Postgres instance containers
11981198
if err == nil && spec.Volumes != nil && len(spec.Volumes.Additional) > 0 {
1199-
missingContainers := addAdditionalVolumesToSpecifiedContainers(&instance.Spec.Template, spec.Volumes.Additional)
1199+
missingContainers := AddAdditionalVolumesToSpecifiedContainers(&instance.Spec.Template, spec.Volumes.Additional)
12001200

12011201
if len(missingContainers) > 0 {
12021202
r.Recorder.Eventf(cluster, corev1.EventTypeWarning, "SpecifiedContainerNotFound",

internal/controller/postgrescluster/pgbackrest.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ func (r *Reconciler) generateRepoHostIntent(ctx context.Context, postgresCluster
721721

722722
// mount additional volumes to the repo host containers
723723
if repoHost != nil && repoHost.Volumes != nil && len(repoHost.Volumes.Additional) > 0 {
724-
missingContainers := addAdditionalVolumesToSpecifiedContainers(&repo.Spec.Template, repoHost.Volumes.Additional)
724+
missingContainers := AddAdditionalVolumesToSpecifiedContainers(&repo.Spec.Template, repoHost.Volumes.Additional)
725725

726726
if len(missingContainers) > 0 {
727727
r.Recorder.Eventf(postgresCluster, corev1.EventTypeWarning, "SpecifiedContainerNotFound",
@@ -908,7 +908,7 @@ func (r *Reconciler) generateBackupJobSpecIntent(ctx context.Context, postgresCl
908908

909909
// mount additional volumes to the job containers
910910
if jobs != nil && jobs.Volumes != nil && len(jobs.Volumes.Additional) > 0 {
911-
missingContainers := addAdditionalVolumesToSpecifiedContainers(&jobSpec.Template, jobs.Volumes.Additional)
911+
missingContainers := AddAdditionalVolumesToSpecifiedContainers(&jobSpec.Template, jobs.Volumes.Additional)
912912

913913
if len(missingContainers) > 0 {
914914
r.Recorder.Eventf(postgresCluster, corev1.EventTypeWarning, "SpecifiedContainerNotFound",
@@ -1408,7 +1408,7 @@ func (r *Reconciler) generateRestoreJobIntent(cluster *v1beta1.PostgresCluster,
14081408
job.Spec.Template.Spec.PriorityClassName = initialize.FromPointer(dataSource.PriorityClassName)
14091409

14101410
if dataSource.Volumes != nil && len(dataSource.Volumes.Additional) > 0 {
1411-
missingContainers := addAdditionalVolumesToSpecifiedContainers(&job.Spec.Template, dataSource.Volumes.Additional)
1411+
missingContainers := AddAdditionalVolumesToSpecifiedContainers(&job.Spec.Template, dataSource.Volumes.Additional)
14121412

14131413
if len(missingContainers) > 0 {
14141414
r.Recorder.Eventf(cluster, corev1.EventTypeWarning, "SpecifiedContainerNotFound",

internal/controller/postgrescluster/pgbouncer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ func (r *Reconciler) generatePGBouncerDeployment(
477477

478478
// mount additional volumes to the pgbouncer containers
479479
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)
480+
missingContainers := AddAdditionalVolumesToSpecifiedContainers(&deploy.Spec.Template, cluster.Spec.Proxy.PGBouncer.Volumes.Additional)
481481

482482
if len(missingContainers) > 0 {
483483
r.Recorder.Eventf(cluster, corev1.EventTypeWarning, "SpecifiedContainerNotFound",

internal/controller/postgrescluster/util.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -297,12 +297,12 @@ func AdditionalVolumeMount(name string, readOnly bool) corev1.VolumeMount {
297297
}
298298
}
299299

300-
// addAdditionalVolumesToSpecifiedContainers adds additional volumes to the specified
300+
// AddAdditionalVolumesToSpecifiedContainers adds additional volumes to the specified
301301
// containers in the specified pod
302-
// addAdditionalVolumesToSpecifiedContainers adds the volumes to the pod
302+
// AddAdditionalVolumesToSpecifiedContainers adds the volumes to the pod
303303
// as `volumes-<additionalVolumeRequest.Name>`
304304
// and adds the directory to the path `/volumes/<additionalVolumeRequest.Name>`
305-
func addAdditionalVolumesToSpecifiedContainers(template *corev1.PodTemplateSpec,
305+
func AddAdditionalVolumesToSpecifiedContainers(template *corev1.PodTemplateSpec,
306306
additionalVolumes []v1beta1.AdditionalVolume) []string {
307307

308308
missingContainers := []string{}

internal/controller/postgrescluster/util_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ func TestAddAdditionalVolumesToSpecifiedContainers(t *testing.T) {
619619

620620
copyPodTemplate := podTemplate.DeepCopy()
621621

622-
missingContainers := addAdditionalVolumesToSpecifiedContainers(
622+
missingContainers := AddAdditionalVolumesToSpecifiedContainers(
623623
copyPodTemplate,
624624
tc.additionalVolumes,
625625
)

internal/controller/standalone_pgadmin/statefulset.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func (r *PGAdminReconciler) reconcilePGAdminStatefulSet(
2626
ctx context.Context, pgadmin *v1beta1.PGAdmin,
2727
configmap *corev1.ConfigMap, dataVolume *corev1.PersistentVolumeClaim,
2828
) error {
29-
sts := statefulset(ctx, pgadmin, configmap, dataVolume)
29+
sts := r.statefulset(ctx, pgadmin, configmap, dataVolume)
3030

3131
// Previous versions of PGO used a StatefulSet Pod Management Policy that could leave the Pod
3232
// in a failed state. When we see that it has the wrong policy, we will delete the StatefulSet
@@ -58,7 +58,7 @@ func (r *PGAdminReconciler) reconcilePGAdminStatefulSet(
5858
}
5959

6060
// statefulset defines the StatefulSet needed to run pgAdmin.
61-
func statefulset(
61+
func (r *PGAdminReconciler) statefulset(
6262
ctx context.Context,
6363
pgadmin *v1beta1.PGAdmin,
6464
configmap *corev1.ConfigMap,
@@ -138,5 +138,15 @@ func statefulset(
138138

139139
postgrescluster.AddTMPEmptyDir(&sts.Spec.Template)
140140

141+
// mount additional volumes to the Postgres instance containers
142+
if pgadmin.Spec.Volumes != nil && len(pgadmin.Spec.Volumes.Additional) > 0 {
143+
missingContainers := postgrescluster.AddAdditionalVolumesToSpecifiedContainers(&sts.Spec.Template, pgadmin.Spec.Volumes.Additional)
144+
145+
if len(missingContainers) > 0 {
146+
r.Recorder.Eventf(pgadmin, corev1.EventTypeWarning, "SpecifiedContainerNotFound",
147+
"The following pgAdmin pod containers were specified for additional volumes but cannot be found: %s.", missingContainers)
148+
}
149+
}
150+
141151
return sts
142152
}

internal/controller/standalone_pgadmin/statefulset_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ import (
1414
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1515
"sigs.k8s.io/controller-runtime/pkg/client"
1616

17+
"github.com/crunchydata/postgres-operator/internal/controller/runtime"
1718
"github.com/crunchydata/postgres-operator/internal/initialize"
1819
"github.com/crunchydata/postgres-operator/internal/naming"
1920
"github.com/crunchydata/postgres-operator/internal/testing/cmp"
21+
"github.com/crunchydata/postgres-operator/internal/testing/events"
2022
"github.com/crunchydata/postgres-operator/internal/testing/require"
2123
"github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1"
2224
)
@@ -219,4 +221,78 @@ tolerations:
219221

220222
assert.Assert(t, cmp.MarshalMatches(template.Spec, compare))
221223
})
224+
225+
t.Run("verify additional volumes", func(t *testing.T) {
226+
recorder := events.NewRecorder(t, runtime.Scheme)
227+
reconciler.Recorder = recorder
228+
229+
custompgadmin := new(v1beta1.PGAdmin)
230+
231+
// add pod level customizations
232+
custompgadmin.Name = "custom-volumes"
233+
custompgadmin.Namespace = ns.Name
234+
235+
require.UnmarshalInto(t, &custompgadmin.Spec, `{
236+
dataVolumeClaimSpec: {
237+
accessModes: [ReadWriteOnce],
238+
resources: { requests: { storage: 1Gi } },
239+
},
240+
}`)
241+
require.UnmarshalInto(t, &custompgadmin.Spec, `{
242+
volumes: {
243+
additional: [
244+
{
245+
"name": "required",
246+
"claimName": "required-1"
247+
}
248+
],
249+
},
250+
}`)
251+
252+
assert.NilError(t, cc.Create(ctx, custompgadmin))
253+
t.Cleanup(func() { assert.Check(t, cc.Delete(ctx, custompgadmin)) })
254+
255+
err := reconciler.reconcilePGAdminStatefulSet(ctx, custompgadmin, configmap, pvc)
256+
assert.NilError(t, err)
257+
258+
selector, err := naming.AsSelector(metav1.LabelSelector{
259+
MatchLabels: map[string]string{
260+
naming.LabelStandalonePGAdmin: custompgadmin.Name,
261+
},
262+
})
263+
assert.NilError(t, err)
264+
265+
list := appsv1.StatefulSetList{}
266+
assert.NilError(t, cc.List(ctx, &list, client.InNamespace(custompgadmin.Namespace),
267+
client.MatchingLabelsSelector{Selector: selector}))
268+
assert.Equal(t, len(list.Items), 1)
269+
270+
template := list.Items[0].Spec.Template.DeepCopy()
271+
272+
for _, container := range template.Spec.Containers {
273+
assert.Assert(t, cmp.MarshalContains(container.VolumeMounts,
274+
`- mountPath: /etc/pgadmin/conf.d
275+
name: pgadmin-config
276+
readOnly: true
277+
- mountPath: /var/lib/pgadmin
278+
name: pgadmin-data
279+
- mountPath: /etc/pgadmin
280+
name: pgadmin-config-system
281+
readOnly: true
282+
- mountPath: /tmp
283+
name: tmp
284+
- mountPath: /volumes/required
285+
name: volumes-required`))
286+
}
287+
288+
assert.Assert(t, cmp.MarshalContains(template.Spec.Volumes,
289+
`
290+
- name: volumes-required
291+
persistentVolumeClaim:
292+
claimName: required-1`))
293+
294+
// No events created
295+
assert.Equal(t, len(recorder.Events), 0)
296+
297+
})
222298
}

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,19 @@ type PGAdminSpec struct {
167167
// https://kubernetes.io/docs/concepts/services-networking/service/
168168
// +optional
169169
ServiceName string `json:"serviceName,omitempty"`
170+
171+
Volumes *PGAdminVolumesSpec `json:"volumes,omitempty"`
172+
}
173+
174+
// PGAdminVolumesSpec defines the configuration for pgAdmin additional volumes
175+
type PGAdminVolumesSpec struct {
176+
// Additional pre-existing volumes to add to the pod.
177+
// ---
178+
// +optional
179+
// +listType=map
180+
// +listMapKey=name
181+
// +kubebuilder:validation:MaxItems=10
182+
Additional []AdditionalVolume `json:"additional,omitempty"`
170183
}
171184

172185
// +kubebuilder:validation:XValidation:rule=`[has(self.postgresClusterName),has(self.postgresClusterSelector)].exists_one(x,x)`,message=`exactly one of "postgresClusterName" or "postgresClusterSelector" is required`

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

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

0 commit comments

Comments
 (0)