Skip to content

Commit fecd1e9

Browse files
leonardocearmrumnencia
authored
feat: retention policy (#191)
This commit makes the Barman cloud plugin support the enforcement of retention policy as provided by the barman-cloud tool suite. The first recoverability point and the last successful backup are shown in the status of the ObjectStore resource for each involved server name. Signed-off-by: Leonardo Cecchi <[email protected]> Signed-off-by: Armando Ruocco <[email protected]> Signed-off-by: Marco Nenciarini <[email protected]> Co-authored-by: Armando Ruocco <[email protected]> Co-authored-by: Marco Nenciarini <[email protected]>
1 parent f520079 commit fecd1e9

File tree

15 files changed

+572
-49
lines changed

15 files changed

+572
-49
lines changed

api/v1/objectstore_types.go

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,48 @@ type InstanceSidecarConfiguration struct {
2727
// The environment to be explicitly passed to the sidecar
2828
// +optional
2929
Env []corev1.EnvVar `json:"env,omitempty"`
30+
31+
// The retentionCheckInterval defines the frequency at which the
32+
// system checks and enforces retention policies.
33+
// +kubebuilder:default:=1800
34+
// +optional
35+
RetentionPolicyIntervalSeconds int `json:"retentionPolicyIntervalSeconds,omitempty"`
3036
}
3137

3238
// ObjectStoreSpec defines the desired state of ObjectStore.
3339
type ObjectStoreSpec struct {
40+
// The configuration for the barman-cloud tool suite
3441
Configuration barmanapi.BarmanObjectStoreConfiguration `json:"configuration"`
3542

43+
// RetentionPolicy is the retention policy to be used for backups
44+
// and WALs (i.e. '60d'). The retention policy is expressed in the form
45+
// of `XXu` where `XX` is a positive integer and `u` is in `[dwm]` -
46+
// days, weeks, months.
47+
// +kubebuilder:validation:Pattern=^[1-9][0-9]*[dwm]$
48+
// +optional
49+
RetentionPolicy string `json:"retentionPolicy,omitempty"`
50+
3651
// +optional
3752
InstanceSidecarConfiguration InstanceSidecarConfiguration `json:"instanceSidecarConfiguration,omitempty"`
3853
}
3954

4055
// ObjectStoreStatus defines the observed state of ObjectStore.
4156
type ObjectStoreStatus struct {
42-
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
43-
// Important: Run "make" to regenerate code after modifying this file
57+
// ServerRecoveryWindow maps each server to its recovery window
58+
ServerRecoveryWindow map[string]RecoveryWindow `json:"serverRecoveryWindow,omitempty"`
59+
}
60+
61+
// RecoveryWindow represents the time span between the first
62+
// recoverability point and the last successful backup of a PostgreSQL
63+
// server, defining the period during which data can be restored.
64+
type RecoveryWindow struct {
65+
// The first recoverability point in a PostgreSQL server refers to
66+
// the earliest point in time to which the database can be
67+
// restored.
68+
FirstRecoverabilityPoint *metav1.Time `json:"firstRecoverabilityPoint,omitempty"`
69+
70+
// The last successful backup time
71+
LastSuccessfulBackupTime *metav1.Time `json:"lastSuccussfulBackupTime,omitempty"`
4472
}
4573

4674
// +kubebuilder:object:root=true

api/v1/zz_generated.deepcopy.go

Lines changed: 31 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/barmancloud.cnpg.io_objectstores.yaml

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ spec:
4040
description: ObjectStoreSpec defines the desired state of ObjectStore.
4141
properties:
4242
configuration:
43-
description: |-
44-
BarmanObjectStoreConfiguration contains the backup configuration
45-
using Barman against an S3-compatible object storage
43+
description: The configuration for the barman-cloud tool suite
4644
properties:
4745
azureCredentials:
4846
description: The credentials to use to upload data to Azure Blob
@@ -502,12 +500,49 @@ spec:
502500
- name
503501
type: object
504502
type: array
503+
retentionPolicyIntervalSeconds:
504+
default: 1800
505+
description: |-
506+
The retentionCheckInterval defines the frequency at which the
507+
system checks and enforces retention policies.
508+
type: integer
505509
type: object
510+
retentionPolicy:
511+
description: |-
512+
RetentionPolicy is the retention policy to be used for backups
513+
and WALs (i.e. '60d'). The retention policy is expressed in the form
514+
of `XXu` where `XX` is a positive integer and `u` is in `[dwm]` -
515+
days, weeks, months.
516+
pattern: ^[1-9][0-9]*[dwm]$
517+
type: string
506518
required:
507519
- configuration
508520
type: object
509521
status:
510522
description: ObjectStoreStatus defines the observed state of ObjectStore.
523+
properties:
524+
serverRecoveryWindow:
525+
additionalProperties:
526+
description: |-
527+
RecoveryWindow represents the time span between the first
528+
recoverability point and the last successful backup of a PostgreSQL
529+
server, defining the period during which data can be restored.
530+
properties:
531+
firstRecoverabilityPoint:
532+
description: |-
533+
The first recoverability point in a PostgreSQL server refers to
534+
the earliest point in time to which the database can be
535+
restored.
536+
format: date-time
537+
type: string
538+
lastSuccussfulBackupTime:
539+
description: The last successful backup time
540+
format: date-time
541+
type: string
542+
type: object
543+
description: ServerRecoveryWindow maps each server to its recovery
544+
window
545+
type: object
511546
type: object
512547
required:
513548
- metadata
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
apiVersion: postgresql.cnpg.io/v1
2+
kind: Cluster
3+
metadata:
4+
name: cluster-example
5+
spec:
6+
instances: 3
7+
imagePullPolicy: Always
8+
9+
backup:
10+
barmanObjectStore:
11+
destinationPath: s3://backups/
12+
endpointURL: http://minio:9000
13+
s3Credentials:
14+
accessKeyId:
15+
name: minio
16+
key: ACCESS_KEY_ID
17+
secretAccessKey:
18+
name: minio
19+
key: ACCESS_SECRET_KEY
20+
wal:
21+
compression: gzip
22+
data:
23+
additionalCommandArgs:
24+
- "--min-chunk-size=5MB"
25+
- "--read-timeout=60"
26+
- "-vv"
27+
28+
storage:
29+
size: 1Gi

docs/examples/minio-store.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ kind: ObjectStore
33
metadata:
44
name: minio-store
55
spec:
6+
retentionPolicy: "1m"
7+
instanceSidecarConfiguration:
8+
retentionPolicyIntervalSeconds: 30
69
configuration:
710
endpointCA:
811
name: minio-server-tls

hack/build-dev-image.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env sh
2+
3+
# This script builds the images of the barman cloud plugin, to be used
4+
# to quickly test images in a development environment.
5+
#
6+
# After each run, the built images will have these names:
7+
#
8+
# - `plugin-barman-cloud:dev`
9+
# - `plugin-barman-cloud-sidecar:dev`
10+
11+
set -eu
12+
13+
docker build -t plugin-barman-cloud:dev --file containers/Dockerfile.plugin .
14+
docker build -t plugin-barman-cloud-sidecar:dev --file containers/Dockerfile.sidecar .

internal/cmd/instance/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ func NewCmd() *cobra.Command {
1818
RunE: func(cmd *cobra.Command, _ []string) error {
1919
requiredSettings := []string{
2020
"namespace",
21+
"cluster-name",
2122
"pod-name",
2223
"spool-directory",
2324
}
@@ -33,6 +34,7 @@ func NewCmd() *cobra.Command {
3334
}
3435

3536
_ = viper.BindEnv("namespace", "NAMESPACE")
37+
_ = viper.BindEnv("cluster-name", "CLUSTER_NAME")
3638
_ = viper.BindEnv("pod-name", "POD_NAME")
3739
_ = viper.BindEnv("pgdata", "PGDATA")
3840
_ = viper.BindEnv("spool-directory", "SPOOL_DIRECTORY")

internal/cnpgi/instance/backup.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"fmt"
66
"os"
7-
"strconv"
87
"time"
98

109
barmanBackup "github.com/cloudnative-pg/barman-cloud/pkg/backup"
@@ -20,7 +19,6 @@ import (
2019

2120
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
2221
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/common"
23-
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
2422
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
2523
)
2624

@@ -148,11 +146,6 @@ func (b BackupServiceImplementation) Backup(
148146
EndLsn: executedBackupInfo.EndLSN,
149147
InstanceId: b.InstanceName,
150148
Online: true,
151-
Metadata: map[string]string{
152-
"timeline": strconv.Itoa(executedBackupInfo.TimeLine),
153-
"version": metadata.Data.Version,
154-
"name": metadata.Data.Name,
155-
"displayName": metadata.Data.DisplayName,
156-
},
149+
Metadata: newBackupResultMetadata(configuration.Cluster.ObjectMeta.UID, executedBackupInfo.TimeLine).toMap(),
157150
}, nil
158151
}

internal/cnpgi/instance/manager.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@ import (
55
"path"
66

77
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
8+
"github.com/cloudnative-pg/machinery/pkg/log"
89
"github.com/spf13/viper"
910
corev1 "k8s.io/api/core/v1"
1011
"k8s.io/apimachinery/pkg/runtime"
1112
"k8s.io/apimachinery/pkg/runtime/schema"
13+
"k8s.io/apimachinery/pkg/types"
1214
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
1315
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
1416
ctrl "sigs.k8s.io/controller-runtime"
1517
"sigs.k8s.io/controller-runtime/pkg/client"
16-
"sigs.k8s.io/controller-runtime/pkg/log"
1718
"sigs.k8s.io/controller-runtime/pkg/scheme"
1819

1920
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
@@ -26,7 +27,10 @@ func Start(ctx context.Context) error {
2627

2728
setupLog := log.FromContext(ctx)
2829
setupLog.Info("Starting barman cloud instance plugin")
30+
2931
podName := viper.GetString("pod-name")
32+
clusterName := viper.GetString("cluster-name")
33+
namespace := viper.GetString("namespace")
3034

3135
controllerOptions := ctrl.Options{
3236
Scheme: scheme,
@@ -36,6 +40,7 @@ func Start(ctx context.Context) error {
3640
&corev1.Secret{},
3741
&barmancloudv1.ObjectStore{},
3842
&cnpgv1.Cluster{},
43+
&cnpgv1.Backup{},
3944
},
4045
},
4146
},
@@ -47,10 +52,11 @@ func Start(ctx context.Context) error {
4752
return err
4853
}
4954

55+
customCacheClient := extendedclient.NewExtendedClient(mgr.GetClient())
56+
5057
if err := mgr.Add(&CNPGI{
51-
Client: extendedclient.NewExtendedClient(mgr.GetClient()),
52-
InstanceName: podName,
53-
// TODO: improve
58+
Client: customCacheClient,
59+
InstanceName: podName,
5460
PGDataPath: viper.GetString("pgdata"),
5561
PGWALPath: path.Join(viper.GetString("pgdata"), "pg_wal"),
5662
SpoolDirectory: viper.GetString("spool-directory"),
@@ -60,6 +66,19 @@ func Start(ctx context.Context) error {
6066
return err
6167
}
6268

69+
if err := mgr.Add(&CatalogMaintenanceRunnable{
70+
Client: customCacheClient,
71+
Recorder: mgr.GetEventRecorderFor("policy-runnable"),
72+
ClusterKey: types.NamespacedName{
73+
Namespace: namespace,
74+
Name: clusterName,
75+
},
76+
CurrentPodName: podName,
77+
}); err != nil {
78+
setupLog.Error(err, "unable to policy enforcement runnable")
79+
return err
80+
}
81+
6382
if err := mgr.Start(ctx); err != nil {
6483
return err
6584
}

0 commit comments

Comments
 (0)