Skip to content

Commit 080f1b9

Browse files
committed
feat: retention policy
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. feat: implement recovery window Signed-off-by: Leonardo Cecchi <[email protected]>
1 parent 0872cf2 commit 080f1b9

File tree

12 files changed

+510
-38
lines changed

12 files changed

+510
-38
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
destinationPath: s3://backups/
811
endpointURL: http://minio:9000

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: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ func (b BackupServiceImplementation) Backup(
151151
"version": metadata.Data.Version,
152152
"name": metadata.Data.Name,
153153
"displayName": metadata.Data.DisplayName,
154+
"clusterUID": string(configuration.Cluster.ObjectMeta.UID),
155+
"pluginName": metadata.PluginName,
154156
},
155157
}, nil
156158
}

internal/cnpgi/instance/manager.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/spf13/viper"
99
corev1 "k8s.io/api/core/v1"
1010
"k8s.io/apimachinery/pkg/runtime"
11+
"k8s.io/apimachinery/pkg/types"
1112
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
1213
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
1314
ctrl "sigs.k8s.io/controller-runtime"
@@ -30,7 +31,10 @@ func init() {
3031
func Start(ctx context.Context) error {
3132
setupLog := log.FromContext(ctx)
3233
setupLog.Info("Starting barman cloud instance plugin")
34+
3335
podName := viper.GetString("pod-name")
36+
clusterName := viper.GetString("cluster-name")
37+
namespace := viper.GetString("namespace")
3438

3539
controllerOptions := ctrl.Options{
3640
Scheme: scheme,
@@ -40,6 +44,7 @@ func Start(ctx context.Context) error {
4044
&corev1.Secret{},
4145
&barmancloudv1.ObjectStore{},
4246
&cnpgv1.Cluster{},
47+
&cnpgv1.Backup{},
4348
},
4449
},
4550
},
@@ -51,10 +56,11 @@ func Start(ctx context.Context) error {
5156
return err
5257
}
5358

59+
customCacheClient := extendedclient.NewExtendedClient(mgr.GetClient())
60+
5461
if err := mgr.Add(&CNPGI{
55-
Client: extendedclient.NewExtendedClient(mgr.GetClient()),
56-
InstanceName: podName,
57-
// TODO: improve
62+
Client: customCacheClient,
63+
InstanceName: podName,
5864
PGDataPath: viper.GetString("pgdata"),
5965
PGWALPath: path.Join(viper.GetString("pgdata"), "pg_wal"),
6066
SpoolDirectory: viper.GetString("spool-directory"),
@@ -64,6 +70,19 @@ func Start(ctx context.Context) error {
6470
return err
6571
}
6672

73+
if err := mgr.Add(&RetentionPolicyRunnable{
74+
Client: customCacheClient,
75+
Recorder: mgr.GetEventRecorderFor("policy-runnable"),
76+
ClusterKey: types.NamespacedName{
77+
Namespace: namespace,
78+
Name: clusterName,
79+
},
80+
PodName: podName,
81+
}); err != nil {
82+
setupLog.Error(err, "unable to policy enforcement runnable")
83+
return err
84+
}
85+
6786
if err := mgr.Start(ctx); err != nil {
6887
return err
6988
}

0 commit comments

Comments
 (0)