feat(spike): backup method

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
This commit is contained in:
Armando Ruocco 2024-10-01 16:13:09 +02:00
parent dd6548c4a2
commit 57160bb6bf
6 changed files with 155 additions and 40 deletions

View File

@ -62,12 +62,13 @@ func main() {
}
if err := mgr.Add(&instance.CNPGI{
Client: mgr.GetClient(),
Client: mgr.GetClient(),
Recorder: mgr.GetEventRecorderFor("cnpg-i"),
ClusterObjectKey: client.ObjectKey{
Namespace: namespace,
Name: clusterName,
},
BarmanObjectKey: client.ObjectKey{
WALConfigurationKey: client.ObjectKey{
Namespace: namespace,
Name: boName,
},

12
go.mod
View File

@ -4,9 +4,9 @@ go 1.22.0
require (
github.com/cloudnative-pg/barman-cloud v0.0.0-20240924124724-92831d48562a
github.com/cloudnative-pg/cloudnative-pg v1.24.0
github.com/cloudnative-pg/cloudnative-pg v1.24.1-0.20241001084914-829808376542
github.com/cloudnative-pg/cnpg-i v0.0.0-20240924030516-c5636170f248
github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20240926153929-09e2c6f6689b
github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20241001135556-db88a95a39eb
github.com/cloudnative-pg/machinery v0.0.0-20241001075747-34c8797af80f
github.com/onsi/ginkgo/v2 v2.20.2
github.com/onsi/gomega v1.34.2
@ -114,12 +114,12 @@ require (
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.31.0 // indirect
k8s.io/apiserver v0.31.0 // indirect
k8s.io/component-base v0.31.0 // indirect
k8s.io/apiextensions-apiserver v0.31.1 // indirect
k8s.io/apiserver v0.31.1 // indirect
k8s.io/component-base v0.31.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38 // indirect
k8s.io/utils v0.0.0-20240902221715-702e33fdd3c3 // indirect
k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect

24
go.sum
View File

@ -16,12 +16,12 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudnative-pg/barman-cloud v0.0.0-20240924124724-92831d48562a h1:0v1ML9Eibfq3helbT9GtU0EstqFtG91k/MPO9azY5ME=
github.com/cloudnative-pg/barman-cloud v0.0.0-20240924124724-92831d48562a/go.mod h1:Jm0tOp5oB7utpt8wz6RfSv31h1mThOtffjfyxVupriE=
github.com/cloudnative-pg/cloudnative-pg v1.24.0 h1:lY9IP/Gnh5ogNcFGoPnbD2eOiHdSdbdEp0PaUdOAMDQ=
github.com/cloudnative-pg/cloudnative-pg v1.24.0/go.mod h1:n7Qqax6os+x3+7Qu/GojUUeKlL1ELGV63dcO/tzIfB4=
github.com/cloudnative-pg/cloudnative-pg v1.24.1-0.20241001084914-829808376542 h1:IXf5lj+m4CBqzckQ9L/9hJ01JUoVw5N0FuPex0sVdVo=
github.com/cloudnative-pg/cloudnative-pg v1.24.1-0.20241001084914-829808376542/go.mod h1:L8M+kTGpz/eaLZj46+4sARvO/vDYlo/m1xOigI/ghBA=
github.com/cloudnative-pg/cnpg-i v0.0.0-20240924030516-c5636170f248 h1:eUGzb7YNjVLilwhgZoe4hDOO70fci3oqb/ZzQFbN3xg=
github.com/cloudnative-pg/cnpg-i v0.0.0-20240924030516-c5636170f248/go.mod h1:K9/4eAT3rh2bKIWyujoN8BIPRXa4d1Ls+eBY8PE8y6w=
github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20240926153929-09e2c6f6689b h1:T9G61tzOBoB5yvlDPULUoiUl6QxPmti3pkNFhQYGGQY=
github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20240926153929-09e2c6f6689b/go.mod h1:dV1+nE7jWENm/fcnKBeKsaScMz685rQPbPCCDydJgsY=
github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20241001135556-db88a95a39eb h1:fDZ4mOSwgEUKaXJI3a37Bw0bPa8bl3DqZ9nPu/6CiJ4=
github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20241001135556-db88a95a39eb/go.mod h1:mHEVy/Guae+rij1qlgwHg+lyFKDX48qjTL4lAqE7OJs=
github.com/cloudnative-pg/machinery v0.0.0-20241001075747-34c8797af80f h1:RgPmQJkuSu3eTdfd4T2K95RYQi57LHB2+Jfsu/faKOM=
github.com/cloudnative-pg/machinery v0.0.0-20241001075747-34c8797af80f/go.mod h1:bWp1Es5zlxElg4Z/c5f0RKOkDcyNvDHdYIvNcPQU4WM=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
@ -286,22 +286,22 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU=
k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI=
k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk=
k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk=
k8s.io/apiextensions-apiserver v0.31.1 h1:L+hwULvXx+nvTYX/MKM3kKMZyei+UiSXQWciX/N6E40=
k8s.io/apiextensions-apiserver v0.31.1/go.mod h1:tWMPR3sgW+jsl2xm9v7lAyRF1rYEK71i9G5dRtkknoQ=
k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U=
k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/apiserver v0.31.0 h1:p+2dgJjy+bk+B1Csz+mc2wl5gHwvNkC9QJV+w55LVrY=
k8s.io/apiserver v0.31.0/go.mod h1:KI9ox5Yu902iBnnyMmy7ajonhKnkeZYJhTZ/YI+WEMk=
k8s.io/apiserver v0.31.1 h1:Sars5ejQDCRBY5f7R3QFHdqN3s61nhkpaX8/k1iEw1c=
k8s.io/apiserver v0.31.1/go.mod h1:lzDhpeToamVZJmmFlaLwdYZwd7zB+WYRYIboqA1kGxM=
k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0=
k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg=
k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs=
k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo=
k8s.io/component-base v0.31.1 h1:UpOepcrX3rQ3ab5NB6g5iP0tvsgJWzxTyAo20sgYSy8=
k8s.io/component-base v0.31.1/go.mod h1:WGeaw7t/kTsqpVTaCoVEtillbqAhF2/JgvO0LDOMa0w=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38 h1:1dWzkmJrrprYvjGwh9kEUxmcUV/CtNU8QM7h1FLWQOo=
k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA=
k8s.io/utils v0.0.0-20240902221715-702e33fdd3c3 h1:b2FmK8YH+QEwq/Sy2uAEhmqL5nPfGYbJOcaqjeYYZoA=
k8s.io/utils v0.0.0-20240902221715-702e33fdd3c3/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 h1:MDF6h2H/h4tbzmtIKTuctcwZmY0tY9mD9fNT47QO6HI=
k8s.io/utils v0.0.0-20240921022957-49e7df575cb6/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q=

View File

@ -2,13 +2,30 @@ package instance
import (
"context"
"os"
barmanBackup "github.com/cloudnative-pg/barman-cloud/pkg/backup"
barmanCapabilities "github.com/cloudnative-pg/barman-cloud/pkg/capabilities"
barmanCredentials "github.com/cloudnative-pg/barman-cloud/pkg/credentials"
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
"github.com/cloudnative-pg/cloudnative-pg/pkg/conditions"
"github.com/cloudnative-pg/cloudnative-pg/pkg/postgres"
"github.com/cloudnative-pg/cloudnative-pg/pkg/resources"
"github.com/cloudnative-pg/cnpg-i-machinery/pkg/pluginhelper/decoder"
"github.com/cloudnative-pg/cnpg-i/pkg/backup"
"github.com/cloudnative-pg/machinery/pkg/fileutils"
"github.com/cloudnative-pg/machinery/pkg/log"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/record"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// BackupServiceImplementation is the implementation
// of the Backup CNPG capability
type BackupServiceImplementation struct {
Client client.Client
Recorder record.EventRecorder
InstanceName string
backup.UnimplementedBackupServer
}
@ -30,7 +47,98 @@ func (b BackupServiceImplementation) GetCapabilities(
}
// Backup implements the Backup interface
func (b BackupServiceImplementation) Backup(_ context.Context, _ *backup.BackupRequest) (*backup.BackupResult, error) {
// TODO implement me
panic("implement me")
func (b BackupServiceImplementation) Backup(
ctx context.Context,
req *backup.BackupRequest,
) (*backup.BackupResult, error) {
contextLogger := log.FromContext(ctx)
backupObj, err := decoder.DecodeBackup(req.BackupDefinition)
if err != nil {
return nil, err
}
cluster, err := decoder.DecodeClusterJSON(req.ClusterDefinition)
if err != nil {
return nil, err
}
// Update backup status in cluster conditions on startup
if err := b.retryWithRefreshedCluster(ctx, cluster, func() error {
// TODO: this condition is set only here, never removed or handled?
return conditions.Patch(ctx, b.Client, cluster, cnpgv1.BackupStartingCondition)
}); err != nil {
contextLogger.Error(err, "Error changing backup condition (backup started)")
// We do not terminate here because we could still have a good backup
// even if we are unable to communicate with the Kubernetes API server
}
if err := fileutils.EnsureDirectoryExists(postgres.BackupTemporaryDirectory); err != nil {
contextLogger.Error(err, "Cannot create backup temporary directory", "err", err)
return nil, err
}
capabilities, err := barmanCapabilities.CurrentCapabilities()
if err != nil {
return nil, err
}
backupCmd := barmanBackup.NewBackupCommand(
cluster.Spec.Backup.BarmanObjectStore,
capabilities,
)
env := os.Environ()
env, err = barmanCredentials.EnvSetBackupCloudCredentials(
ctx,
b.Client,
cluster.Namespace,
cluster.Spec.Backup.BarmanObjectStore,
env)
if err != nil {
return nil, err
}
if err = backupCmd.Take(
ctx,
backupObj.Status.BackupName,
backupObj.Status.ServerName,
env,
cluster,
postgres.BackupTemporaryDirectory,
); err != nil {
return nil, err
}
contextLogger.Info("Backup completed")
b.Recorder.Event(backupObj, "Normal", "Completed", "Backup completed")
// Set the status to completed
backupObj.Status.SetAsCompleted()
executedBackupInfo, err := backupCmd.GetExecutedBackupInfo(
ctx, backupObj.Status.BackupName, backupObj.Status.ServerName, cluster, env)
if err != nil {
return nil, err
}
return &backup.BackupResult{
BackupId: executedBackupInfo.ID,
BackupName: executedBackupInfo.BackupName,
StartedAt: metav1.Time{Time: executedBackupInfo.BeginTime}.Unix(),
StoppedAt: metav1.Time{Time: executedBackupInfo.EndTime}.Unix(),
BeginWal: executedBackupInfo.BeginWal,
EndWal: executedBackupInfo.EndWal,
BeginLsn: executedBackupInfo.BeginLSN,
EndLsn: executedBackupInfo.EndLSN,
BackupLabelFile: nil,
TablespaceMapFile: nil,
InstanceId: b.InstanceName,
Online: true,
Metadata: nil,
}, nil
}
func (b *BackupServiceImplementation) retryWithRefreshedCluster(
ctx context.Context,
cluster *cnpgv1.Cluster,
cb func() error,
) error {
return resources.RetryWithRefreshedResource(ctx, b.Client, cluster, cb)
}

View File

@ -14,8 +14,8 @@ import (
// IdentityImplementation implements IdentityServer
type IdentityImplementation struct {
identity.UnimplementedIdentityServer
BarmanObjectKey client.ObjectKey
Client client.Client
WALConfigurationKey client.ObjectKey
Client client.Client
}
// GetPluginMetadata implements IdentityServer
@ -57,8 +57,8 @@ func (i IdentityImplementation) Probe(
_ *identity.ProbeRequest,
) (*identity.ProbeResponse, error) {
var obj barmancloudv1.ObjectStore
if err := i.Client.Get(ctx, i.BarmanObjectKey, &obj); err != nil {
return nil, fmt.Errorf("while fetching object store %s: %w", i.BarmanObjectKey.Name, err)
if err := i.Client.Get(ctx, i.WALConfigurationKey, &obj); err != nil {
return nil, fmt.Errorf("while fetching object store %s: %w", i.WALConfigurationKey.Name, err)
}
return &identity.ProbeResponse{

View File

@ -7,20 +7,22 @@ import (
"github.com/cloudnative-pg/cnpg-i/pkg/backup"
"github.com/cloudnative-pg/cnpg-i/pkg/wal"
"google.golang.org/grpc"
"k8s.io/client-go/tools/record"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// CNPGI is the implementation of the PostgreSQL sidecar
type CNPGI struct {
Client client.Client
BarmanObjectKey client.ObjectKey
ClusterObjectKey client.ObjectKey
PGDataPath string
PGWALPath string
SpoolDirectory string
ServerCertPath string
ServerKeyPath string
ClientCertPath string
Client client.Client
Recorder record.EventRecorder
WALConfigurationKey client.ObjectKey
ClusterObjectKey client.ObjectKey
PGDataPath string
PGWALPath string
SpoolDirectory string
ServerCertPath string
ServerKeyPath string
ClientCertPath string
// mutually exclusive with pluginPath
ServerAddress string
// mutually exclusive with serverAddress
@ -32,7 +34,7 @@ type CNPGI struct {
func (c *CNPGI) Start(ctx context.Context) error {
enrich := func(server *grpc.Server) error {
wal.RegisterWALServer(server, WALServiceImplementation{
BarmanObjectKey: c.BarmanObjectKey,
BarmanObjectKey: c.WALConfigurationKey,
ClusterObjectKey: c.ClusterObjectKey,
InstanceName: c.InstanceName,
Client: c.Client,
@ -40,14 +42,18 @@ func (c *CNPGI) Start(ctx context.Context) error {
PGDataPath: c.PGDataPath,
PGWALPath: c.PGWALPath,
})
backup.RegisterBackupServer(server, BackupServiceImplementation{})
backup.RegisterBackupServer(server, BackupServiceImplementation{
Client: c.Client,
Recorder: c.Recorder,
InstanceName: c.InstanceName,
})
return nil
}
srv := http.Server{
IdentityImpl: IdentityImplementation{
Client: c.Client,
BarmanObjectKey: c.BarmanObjectKey,
Client: c.Client,
WALConfigurationKey: c.WALConfigurationKey,
},
Enrichers: []http.ServerEnricher{enrich},
ServerCertPath: c.ServerCertPath,