Skip to content

Commit 69869d2

Browse files
benjaminjbAnthony Landreth
and
Anthony Landreth
authored
Optional backups v2 (#3977)
Make backups optional * Make spec.backups an optional field * Add permissions to delete RBAC K8s objects in pgBackRest cleanup * Pause reconciliation if backups need to be removed and annotation isn't present * Add KUTTL test --------- Co-authored-by: Anthony Landreth <[email protected]>
1 parent b4eb42a commit 69869d2

31 files changed

+1292
-374
lines changed

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4334,8 +4334,6 @@ spec:
43344334
required:
43354335
- volumeSnapshotClassName
43364336
type: object
4337-
required:
4338-
- pgbackrest
43394337
type: object
43404338
config:
43414339
properties:
@@ -16873,7 +16871,6 @@ spec:
1687316871
- name
1687416872
x-kubernetes-list-type: map
1687516873
required:
16876-
- backups
1687716874
- instances
1687816875
- postgresVersion
1687916876
type: object

config/rbac/cluster/role.yaml

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ rules:
1010
- configmaps
1111
- persistentvolumeclaims
1212
- secrets
13+
- serviceaccounts
1314
- services
1415
verbs:
1516
- create
@@ -54,16 +55,6 @@ rules:
5455
- list
5556
- patch
5657
- watch
57-
- apiGroups:
58-
- ''
59-
resources:
60-
- serviceaccounts
61-
verbs:
62-
- create
63-
- get
64-
- list
65-
- patch
66-
- watch
6758
- apiGroups:
6859
- apps
6960
resources:
@@ -167,6 +158,7 @@ rules:
167158
- roles
168159
verbs:
169160
- create
161+
- delete
170162
- get
171163
- list
172164
- patch

config/rbac/namespace/role.yaml

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ rules:
1010
- configmaps
1111
- persistentvolumeclaims
1212
- secrets
13+
- serviceaccounts
1314
- services
1415
verbs:
1516
- create
@@ -54,16 +55,6 @@ rules:
5455
- list
5556
- patch
5657
- watch
57-
- apiGroups:
58-
- ''
59-
resources:
60-
- serviceaccounts
61-
verbs:
62-
- create
63-
- get
64-
- list
65-
- patch
66-
- watch
6758
- apiGroups:
6859
- apps
6960
resources:
@@ -167,6 +158,7 @@ rules:
167158
- roles
168159
verbs:
169160
- create
161+
- delete
170162
- get
171163
- list
172164
- patch

internal/controller/postgrescluster/cluster.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,9 @@ func (r *Reconciler) reconcileClusterReplicaService(
290290
func (r *Reconciler) reconcileDataSource(ctx context.Context,
291291
cluster *v1beta1.PostgresCluster, observed *observedInstances,
292292
clusterVolumes []corev1.PersistentVolumeClaim,
293-
rootCA *pki.RootCertificateAuthority) (bool, error) {
293+
rootCA *pki.RootCertificateAuthority,
294+
backupsSpecFound bool,
295+
) (bool, error) {
294296

295297
// a hash func to hash the pgBackRest restore options
296298
hashFunc := func(jobConfigs []string) (string, error) {
@@ -413,7 +415,8 @@ func (r *Reconciler) reconcileDataSource(ctx context.Context,
413415
switch {
414416
case dataSource != nil:
415417
if err := r.reconcilePostgresClusterDataSource(ctx, cluster, dataSource,
416-
configHash, clusterVolumes, rootCA); err != nil {
418+
configHash, clusterVolumes, rootCA,
419+
backupsSpecFound); err != nil {
417420
return true, err
418421
}
419422
case cloudDataSource != nil:

internal/controller/postgrescluster/controller.go

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -162,21 +162,23 @@ func (r *Reconciler) Reconcile(
162162
}
163163

164164
var (
165-
clusterConfigMap *corev1.ConfigMap
166-
clusterReplicationSecret *corev1.Secret
167-
clusterPodService *corev1.Service
168-
clusterVolumes []corev1.PersistentVolumeClaim
169-
instanceServiceAccount *corev1.ServiceAccount
170-
instances *observedInstances
171-
patroniLeaderService *corev1.Service
172-
primaryCertificate *corev1.SecretProjection
173-
primaryService *corev1.Service
174-
replicaService *corev1.Service
175-
rootCA *pki.RootCertificateAuthority
176-
monitoringSecret *corev1.Secret
177-
exporterQueriesConfig *corev1.ConfigMap
178-
exporterWebConfig *corev1.ConfigMap
179-
err error
165+
clusterConfigMap *corev1.ConfigMap
166+
clusterReplicationSecret *corev1.Secret
167+
clusterPodService *corev1.Service
168+
clusterVolumes []corev1.PersistentVolumeClaim
169+
instanceServiceAccount *corev1.ServiceAccount
170+
instances *observedInstances
171+
patroniLeaderService *corev1.Service
172+
primaryCertificate *corev1.SecretProjection
173+
primaryService *corev1.Service
174+
replicaService *corev1.Service
175+
rootCA *pki.RootCertificateAuthority
176+
monitoringSecret *corev1.Secret
177+
exporterQueriesConfig *corev1.ConfigMap
178+
exporterWebConfig *corev1.ConfigMap
179+
err error
180+
backupsSpecFound bool
181+
backupsReconciliationAllowed bool
180182
)
181183

182184
patchClusterStatus := func() error {
@@ -214,13 +216,34 @@ func (r *Reconciler) Reconcile(
214216
meta.RemoveStatusCondition(&cluster.Status.Conditions, v1beta1.PostgresClusterProgressing)
215217
}
216218

219+
if err == nil {
220+
backupsSpecFound, backupsReconciliationAllowed, err = r.BackupsEnabled(ctx, cluster)
221+
222+
// If we cannot reconcile because the backup reconciliation is paused, set a condition and exit
223+
if !backupsReconciliationAllowed {
224+
meta.SetStatusCondition(&cluster.Status.Conditions, metav1.Condition{
225+
Type: v1beta1.PostgresClusterProgressing,
226+
Status: metav1.ConditionFalse,
227+
Reason: "Paused",
228+
Message: "Reconciliation is paused: please fill in spec.backups " +
229+
"or add the postgres-operator.crunchydata.com/authorizeBackupRemoval " +
230+
"annotation to authorize backup removal.",
231+
232+
ObservedGeneration: cluster.GetGeneration(),
233+
})
234+
return runtime.ErrorWithBackoff(patchClusterStatus())
235+
} else {
236+
meta.RemoveStatusCondition(&cluster.Status.Conditions, v1beta1.PostgresClusterProgressing)
237+
}
238+
}
239+
217240
pgHBAs := postgres.NewHBAs()
218241
pgmonitor.PostgreSQLHBAs(cluster, &pgHBAs)
219242
pgbouncer.PostgreSQL(cluster, &pgHBAs)
220243

221244
pgParameters := postgres.NewParameters()
222245
pgaudit.PostgreSQLParameters(&pgParameters)
223-
pgbackrest.PostgreSQL(cluster, &pgParameters)
246+
pgbackrest.PostgreSQL(cluster, &pgParameters, backupsSpecFound)
224247
pgmonitor.PostgreSQLParameters(cluster, &pgParameters)
225248

226249
// Set huge_pages = try if a hugepages resource limit > 0, otherwise set "off"
@@ -287,7 +310,7 @@ func (r *Reconciler) Reconcile(
287310
// the controller should return early while data initialization is in progress, after
288311
// which it will indicate that an early return is no longer needed, and reconciliation
289312
// can proceed normally.
290-
returnEarly, err := r.reconcileDataSource(ctx, cluster, instances, clusterVolumes, rootCA)
313+
returnEarly, err := r.reconcileDataSource(ctx, cluster, instances, clusterVolumes, rootCA, backupsSpecFound)
291314
if err != nil || returnEarly {
292315
return runtime.ErrorWithBackoff(errors.Join(err, patchClusterStatus()))
293316
}
@@ -329,7 +352,9 @@ func (r *Reconciler) Reconcile(
329352
err = r.reconcileInstanceSets(
330353
ctx, cluster, clusterConfigMap, clusterReplicationSecret, rootCA,
331354
clusterPodService, instanceServiceAccount, instances, patroniLeaderService,
332-
primaryCertificate, clusterVolumes, exporterQueriesConfig, exporterWebConfig)
355+
primaryCertificate, clusterVolumes, exporterQueriesConfig, exporterWebConfig,
356+
backupsSpecFound,
357+
)
333358
}
334359

335360
if err == nil {
@@ -341,7 +366,8 @@ func (r *Reconciler) Reconcile(
341366

342367
if err == nil {
343368
var next reconcile.Result
344-
if next, err = r.reconcilePGBackRest(ctx, cluster, instances, rootCA); err == nil && !next.IsZero() {
369+
if next, err = r.reconcilePGBackRest(ctx, cluster,
370+
instances, rootCA, backupsSpecFound); err == nil && !next.IsZero() {
345371
result.Requeue = result.Requeue || next.Requeue
346372
if next.RequeueAfter > 0 {
347373
result.RequeueAfter = next.RequeueAfter

internal/controller/postgrescluster/instance.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ func (r *Reconciler) observeInstances(
346346
status.DesiredPGDataVolume = make(map[string]string)
347347

348348
for _, instance := range observed.bySet[name] {
349-
status.Replicas += int32(len(instance.Pods))
349+
status.Replicas += int32(len(instance.Pods)) //nolint:gosec
350350

351351
if ready, known := instance.IsReady(); known && ready {
352352
status.ReadyReplicas++
@@ -604,6 +604,7 @@ func (r *Reconciler) reconcileInstanceSets(
604604
primaryCertificate *corev1.SecretProjection,
605605
clusterVolumes []corev1.PersistentVolumeClaim,
606606
exporterQueriesConfig, exporterWebConfig *corev1.ConfigMap,
607+
backupsSpecFound bool,
607608
) error {
608609

609610
// Go through the observed instances and check if a primary has been determined.
@@ -640,7 +641,9 @@ func (r *Reconciler) reconcileInstanceSets(
640641
rootCA, clusterPodService, instanceServiceAccount,
641642
patroniLeaderService, primaryCertificate,
642643
findAvailableInstanceNames(*set, instances, clusterVolumes),
643-
numInstancePods, clusterVolumes, exporterQueriesConfig, exporterWebConfig)
644+
numInstancePods, clusterVolumes, exporterQueriesConfig, exporterWebConfig,
645+
backupsSpecFound,
646+
)
644647

645648
if err == nil {
646649
err = r.reconcileInstanceSetPodDisruptionBudget(ctx, cluster, set)
@@ -1079,6 +1082,7 @@ func (r *Reconciler) scaleUpInstances(
10791082
numInstancePods int,
10801083
clusterVolumes []corev1.PersistentVolumeClaim,
10811084
exporterQueriesConfig, exporterWebConfig *corev1.ConfigMap,
1085+
backupsSpecFound bool,
10821086
) ([]*appsv1.StatefulSet, error) {
10831087
log := logging.FromContext(ctx)
10841088

@@ -1123,6 +1127,7 @@ func (r *Reconciler) scaleUpInstances(
11231127
rootCA, clusterPodService, instanceServiceAccount,
11241128
patroniLeaderService, primaryCertificate, instances[i],
11251129
numInstancePods, clusterVolumes, exporterQueriesConfig, exporterWebConfig,
1130+
backupsSpecFound,
11261131
)
11271132
}
11281133
if err == nil {
@@ -1152,6 +1157,7 @@ func (r *Reconciler) reconcileInstance(
11521157
numInstancePods int,
11531158
clusterVolumes []corev1.PersistentVolumeClaim,
11541159
exporterQueriesConfig, exporterWebConfig *corev1.ConfigMap,
1160+
backupsSpecFound bool,
11551161
) error {
11561162
log := logging.FromContext(ctx).WithValues("instance", instance.Name)
11571163
ctx = logging.NewContext(ctx, log)
@@ -1198,8 +1204,10 @@ func (r *Reconciler) reconcileInstance(
11981204
postgresDataVolume, postgresWALVolume, tablespaceVolumes,
11991205
&instance.Spec.Template.Spec)
12001206

1201-
addPGBackRestToInstancePodSpec(
1202-
ctx, cluster, instanceCertificates, &instance.Spec.Template.Spec)
1207+
if backupsSpecFound {
1208+
addPGBackRestToInstancePodSpec(
1209+
ctx, cluster, instanceCertificates, &instance.Spec.Template.Spec)
1210+
}
12031211

12041212
err = patroni.InstancePod(
12051213
ctx, cluster, clusterConfigMap, clusterPodService, patroniLeaderService,

0 commit comments

Comments
 (0)