mirror of
https://github.com/cloudnative-pg/plugin-barman-cloud.git
synced 2026-01-11 21:23:12 +01:00
feat: separate recovery and cluster object store (#76)
Signed-off-by: Leonardo Cecchi <leonardo.cecchi@enterprisedb.com> Signed-off-by: Francesco Canovai <francesco.canovai@enterprisedb.com> Co-authored-by: Francesco Canovai <francesco.canovai@enterprisedb.com>
This commit is contained in:
parent
af60a15837
commit
e30edd2318
27
docs/examples/cluster-restore-archive.yaml
Normal file
27
docs/examples/cluster-restore-archive.yaml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: Cluster
|
||||||
|
metadata:
|
||||||
|
name: cluster-restore
|
||||||
|
spec:
|
||||||
|
instances: 3
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
bootstrap:
|
||||||
|
recovery:
|
||||||
|
source: source
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- name: barman-cloud.cloudnative-pg.io
|
||||||
|
parameters:
|
||||||
|
barmanObjectName: minio-store-bis
|
||||||
|
|
||||||
|
externalClusters:
|
||||||
|
- name: source
|
||||||
|
plugin:
|
||||||
|
name: barman-cloud.cloudnative-pg.io
|
||||||
|
parameters:
|
||||||
|
barmanObjectName: minio-store
|
||||||
|
serverName: cluster-example
|
||||||
|
|
||||||
|
storage:
|
||||||
|
size: 1Gi
|
||||||
@ -36,12 +36,16 @@ func NewCmd() *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ = viper.BindEnv("namespace", "NAMESPACE")
|
_ = viper.BindEnv("namespace", "NAMESPACE")
|
||||||
_ = viper.BindEnv("barman-object-name", "BARMAN_OBJECT_NAME")
|
|
||||||
_ = viper.BindEnv("cluster-name", "CLUSTER_NAME")
|
_ = viper.BindEnv("cluster-name", "CLUSTER_NAME")
|
||||||
_ = viper.BindEnv("pod-name", "POD_NAME")
|
_ = viper.BindEnv("pod-name", "POD_NAME")
|
||||||
_ = viper.BindEnv("pgdata", "PGDATA")
|
_ = viper.BindEnv("pgdata", "PGDATA")
|
||||||
_ = viper.BindEnv("spool-directory", "SPOOL_DIRECTORY")
|
_ = viper.BindEnv("spool-directory", "SPOOL_DIRECTORY")
|
||||||
|
|
||||||
|
_ = viper.BindEnv("barman-object-name", "BARMAN_OBJECT_NAME")
|
||||||
_ = viper.BindEnv("server-name", "SERVER_NAME")
|
_ = viper.BindEnv("server-name", "SERVER_NAME")
|
||||||
|
|
||||||
|
_ = viper.BindEnv("recovery-barman-object-name", "RECOVERY_BARMAN_OBJECT_NAME")
|
||||||
|
_ = viper.BindEnv("recovery-server-name", "RECOVERY_SERVER_NAME")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,8 +23,11 @@ func NewCmd() *cobra.Command {
|
|||||||
"cluster-name",
|
"cluster-name",
|
||||||
"pod-name",
|
"pod-name",
|
||||||
"spool-directory",
|
"spool-directory",
|
||||||
"barman-object-name",
|
|
||||||
"server-name",
|
// IMPORTANT: barman-object-name and server-name are not required
|
||||||
|
// to restore a cluster.
|
||||||
|
"recovery-barman-object-name",
|
||||||
|
"recovery-server-name",
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, k := range requiredSettings {
|
for _, k := range requiredSettings {
|
||||||
@ -42,8 +45,12 @@ func NewCmd() *cobra.Command {
|
|||||||
_ = viper.BindEnv("pod-name", "POD_NAME")
|
_ = viper.BindEnv("pod-name", "POD_NAME")
|
||||||
_ = viper.BindEnv("pgdata", "PGDATA")
|
_ = viper.BindEnv("pgdata", "PGDATA")
|
||||||
_ = viper.BindEnv("spool-directory", "SPOOL_DIRECTORY")
|
_ = viper.BindEnv("spool-directory", "SPOOL_DIRECTORY")
|
||||||
|
|
||||||
_ = viper.BindEnv("barman-object-name", "BARMAN_OBJECT_NAME")
|
_ = viper.BindEnv("barman-object-name", "BARMAN_OBJECT_NAME")
|
||||||
_ = viper.BindEnv("server-name", "SERVER_NAME")
|
_ = viper.BindEnv("server-name", "SERVER_NAME")
|
||||||
|
|
||||||
|
_ = viper.BindEnv("recovery-barman-object-name", "RECOVERY_BARMAN_OBJECT_NAME")
|
||||||
|
_ = viper.BindEnv("recovery-server-name", "RECOVERY_SERVER_NAME")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,15 +24,19 @@ import (
|
|||||||
|
|
||||||
// WALServiceImplementation is the implementation of the WAL Service
|
// WALServiceImplementation is the implementation of the WAL Service
|
||||||
type WALServiceImplementation struct {
|
type WALServiceImplementation struct {
|
||||||
ServerName string
|
wal.UnimplementedWALServer
|
||||||
BarmanObjectKey client.ObjectKey
|
|
||||||
ClusterObjectKey client.ObjectKey
|
ClusterObjectKey client.ObjectKey
|
||||||
Client client.Client
|
Client client.Client
|
||||||
InstanceName string
|
InstanceName string
|
||||||
SpoolDirectory string
|
SpoolDirectory string
|
||||||
PGDataPath string
|
PGDataPath string
|
||||||
PGWALPath string
|
PGWALPath string
|
||||||
wal.UnimplementedWALServer
|
|
||||||
|
BarmanObjectKey client.ObjectKey
|
||||||
|
ServerName string
|
||||||
|
|
||||||
|
RecoveryBarmanObjectKey client.ObjectKey
|
||||||
|
RecoveryServerName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCapabilities implements the WALService interface
|
// GetCapabilities implements the WALService interface
|
||||||
@ -123,8 +127,9 @@ func (w WALServiceImplementation) Restore(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
request *wal.WALRestoreRequest,
|
request *wal.WALRestoreRequest,
|
||||||
) (*wal.WALRestoreResult, error) {
|
) (*wal.WALRestoreResult, error) {
|
||||||
contextLogger := log.FromContext(ctx)
|
// TODO: build full paths
|
||||||
startTime := time.Now()
|
walName := request.GetSourceWalName()
|
||||||
|
destinationPath := request.GetDestinationFileName()
|
||||||
|
|
||||||
var cluster cnpgv1.Cluster
|
var cluster cnpgv1.Cluster
|
||||||
if err := w.Client.Get(ctx, w.ClusterObjectKey, &cluster); err != nil {
|
if err := w.Client.Get(ctx, w.ClusterObjectKey, &cluster); err != nil {
|
||||||
@ -132,13 +137,45 @@ func (w WALServiceImplementation) Restore(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var objectStore barmancloudv1.ObjectStore
|
var objectStore barmancloudv1.ObjectStore
|
||||||
if err := w.Client.Get(ctx, w.BarmanObjectKey, &objectStore); err != nil {
|
var serverName string
|
||||||
return nil, err
|
|
||||||
|
switch {
|
||||||
|
case cluster.IsReplica() && cluster.Status.CurrentPrimary == w.InstanceName:
|
||||||
|
// Designated primary on replica cluster, using recovery object store
|
||||||
|
serverName = w.RecoveryServerName
|
||||||
|
if err := w.Client.Get(ctx, w.RecoveryBarmanObjectKey, &objectStore); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case cluster.Status.CurrentPrimary == "":
|
||||||
|
// Recovery from object store, using recovery object store
|
||||||
|
serverName = w.RecoveryServerName
|
||||||
|
if err := w.Client.Get(ctx, w.RecoveryBarmanObjectKey, &objectStore); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Using cluster object store
|
||||||
|
serverName = w.ServerName
|
||||||
|
if err := w.Client.Get(ctx, w.BarmanObjectKey, &objectStore); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: build full paths
|
return &wal.WALRestoreResult{}, w.restoreFromBarmanObjectStore(
|
||||||
walName := request.GetSourceWalName()
|
ctx, &cluster, &objectStore, serverName, walName, destinationPath)
|
||||||
destinationPath := request.GetDestinationFileName()
|
}
|
||||||
|
|
||||||
|
func (w WALServiceImplementation) restoreFromBarmanObjectStore(
|
||||||
|
ctx context.Context,
|
||||||
|
cluster *cnpgv1.Cluster,
|
||||||
|
objectStore *barmancloudv1.ObjectStore,
|
||||||
|
serverName string,
|
||||||
|
walName string,
|
||||||
|
destinationPath string,
|
||||||
|
) error {
|
||||||
|
contextLogger := log.FromContext(ctx)
|
||||||
|
startTime := time.Now()
|
||||||
|
|
||||||
barmanConfiguration := &objectStore.Spec.Configuration
|
barmanConfiguration := &objectStore.Spec.Configuration
|
||||||
|
|
||||||
@ -151,37 +188,37 @@ func (w WALServiceImplementation) Restore(
|
|||||||
os.Environ(),
|
os.Environ(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("while getting recover credentials: %w", err)
|
return fmt.Errorf("while getting recover credentials: %w", err)
|
||||||
}
|
}
|
||||||
env = MergeEnv(env, credentialsEnv)
|
env = MergeEnv(env, credentialsEnv)
|
||||||
|
|
||||||
options, err := barmanCommand.CloudWalRestoreOptions(ctx, barmanConfiguration, w.ServerName)
|
options, err := barmanCommand.CloudWalRestoreOptions(ctx, barmanConfiguration, serverName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("while getting barman-cloud-wal-restore options: %w", err)
|
return fmt.Errorf("while getting barman-cloud-wal-restore options: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the restorer
|
// Create the restorer
|
||||||
var walRestorer *barmanRestorer.WALRestorer
|
var walRestorer *barmanRestorer.WALRestorer
|
||||||
if walRestorer, err = barmanRestorer.New(ctx, env, w.SpoolDirectory); err != nil {
|
if walRestorer, err = barmanRestorer.New(ctx, env, w.SpoolDirectory); err != nil {
|
||||||
return nil, fmt.Errorf("while creating the restorer: %w", err)
|
return fmt.Errorf("while creating the restorer: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 1: check if this WAL file is not already in the spool
|
// Step 1: check if this WAL file is not already in the spool
|
||||||
var wasInSpool bool
|
var wasInSpool bool
|
||||||
if wasInSpool, err = walRestorer.RestoreFromSpool(walName, destinationPath); err != nil {
|
if wasInSpool, err = walRestorer.RestoreFromSpool(walName, destinationPath); err != nil {
|
||||||
return nil, fmt.Errorf("while restoring a file from the spool directory: %w", err)
|
return fmt.Errorf("while restoring a file from the spool directory: %w", err)
|
||||||
}
|
}
|
||||||
if wasInSpool {
|
if wasInSpool {
|
||||||
contextLogger.Info("Restored WAL file from spool (parallel)",
|
contextLogger.Info("Restored WAL file from spool (parallel)",
|
||||||
"walName", walName,
|
"walName", walName,
|
||||||
)
|
)
|
||||||
return nil, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// We skip this step if streaming connection is not available
|
// We skip this step if streaming connection is not available
|
||||||
if isStreamingAvailable(&cluster, w.InstanceName) {
|
if isStreamingAvailable(cluster, w.InstanceName) {
|
||||||
if err := checkEndOfWALStreamFlag(walRestorer); err != nil {
|
if err := checkEndOfWALStreamFlag(walRestorer); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +231,7 @@ func (w WALServiceImplementation) Restore(
|
|||||||
if IsWALFile(walName) {
|
if IsWALFile(walName) {
|
||||||
// If this is a regular WAL file, we try to prefetch
|
// If this is a regular WAL file, we try to prefetch
|
||||||
if walFilesList, err = gatherWALFilesToRestore(walName, maxParallel); err != nil {
|
if walFilesList, err = gatherWALFilesToRestore(walName, maxParallel); err != nil {
|
||||||
return nil, fmt.Errorf("while generating the list of WAL files to restore: %w", err)
|
return fmt.Errorf("while generating the list of WAL files to restore: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This is not a regular WAL file, we fetch it directly
|
// This is not a regular WAL file, we fetch it directly
|
||||||
@ -209,18 +246,18 @@ func (w WALServiceImplementation) Restore(
|
|||||||
// is the one that PostgreSQL has requested to restore.
|
// is the one that PostgreSQL has requested to restore.
|
||||||
// The failure has already been logged in walRestorer.RestoreList method
|
// The failure has already been logged in walRestorer.RestoreList method
|
||||||
if walStatus[0].Err != nil {
|
if walStatus[0].Err != nil {
|
||||||
return nil, walStatus[0].Err
|
return walStatus[0].Err
|
||||||
}
|
}
|
||||||
|
|
||||||
// We skip this step if streaming connection is not available
|
// We skip this step if streaming connection is not available
|
||||||
endOfWALStream := isEndOfWALStream(walStatus)
|
endOfWALStream := isEndOfWALStream(walStatus)
|
||||||
if isStreamingAvailable(&cluster, w.InstanceName) && endOfWALStream {
|
if isStreamingAvailable(cluster, w.InstanceName) && endOfWALStream {
|
||||||
contextLogger.Info(
|
contextLogger.Info(
|
||||||
"Set end-of-wal-stream flag as one of the WAL files to be prefetched was not found")
|
"Set end-of-wal-stream flag as one of the WAL files to be prefetched was not found")
|
||||||
|
|
||||||
err = walRestorer.SetEndOfWALStream()
|
err = walRestorer.SetEndOfWALStream()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +278,7 @@ func (w WALServiceImplementation) Restore(
|
|||||||
"downloadTotalTime", time.Since(downloadStartTime),
|
"downloadTotalTime", time.Since(downloadStartTime),
|
||||||
"totalTime", time.Since(startTime))
|
"totalTime", time.Since(startTime))
|
||||||
|
|
||||||
return &wal.WALRestoreResult{}, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status implements the WALService interface
|
// Status implements the WALService interface
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package client
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -21,32 +22,41 @@ type cachedSecret struct {
|
|||||||
// ExtendedClient is an extended client that is capable of caching multiple secrets without relying on informers
|
// ExtendedClient is an extended client that is capable of caching multiple secrets without relying on informers
|
||||||
type ExtendedClient struct {
|
type ExtendedClient struct {
|
||||||
client.Client
|
client.Client
|
||||||
barmanObjectKey client.ObjectKey
|
barmanObjectKeys []client.ObjectKey
|
||||||
cachedSecrets []*cachedSecret
|
cachedSecrets []*cachedSecret
|
||||||
mux *sync.Mutex
|
mux *sync.Mutex
|
||||||
ttl int
|
ttl int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewExtendedClient returns an extended client capable of caching secrets on the 'Get' operation
|
// NewExtendedClient returns an extended client capable of caching secrets on the 'Get' operation
|
||||||
func NewExtendedClient(
|
func NewExtendedClient(
|
||||||
baseClient client.Client,
|
baseClient client.Client,
|
||||||
objectStoreKey client.ObjectKey,
|
objectStoreKeys []client.ObjectKey,
|
||||||
) client.Client {
|
) client.Client {
|
||||||
return &ExtendedClient{
|
return &ExtendedClient{
|
||||||
Client: baseClient,
|
Client: baseClient,
|
||||||
barmanObjectKey: objectStoreKey,
|
barmanObjectKeys: objectStoreKeys,
|
||||||
mux: &sync.Mutex{},
|
mux: &sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ExtendedClient) refreshTTL(ctx context.Context) error {
|
func (e *ExtendedClient) refreshTTL(ctx context.Context) error {
|
||||||
var object v1.ObjectStore
|
minTTL := math.MaxInt
|
||||||
if err := e.Get(ctx, e.barmanObjectKey, &object); err != nil {
|
|
||||||
return fmt.Errorf("failed to get the object store while refreshing the TTL parameter: %w", err)
|
for _, key := range e.barmanObjectKeys {
|
||||||
|
var object v1.ObjectStore
|
||||||
|
|
||||||
|
if err := e.Get(ctx, key, &object); err != nil {
|
||||||
|
return fmt.Errorf("failed to get the object store while refreshing the TTL parameter: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentTTL := object.Spec.InstanceSidecarConfiguration.GetCacheTTL()
|
||||||
|
if currentTTL < minTTL {
|
||||||
|
minTTL = currentTTL
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e.ttl = object.Spec.InstanceSidecarConfiguration.GetCacheTTL()
|
e.ttl = minTTL
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -55,7 +55,9 @@ var _ = Describe("ExtendedClient Get", func() {
|
|||||||
baseClient := fake.NewClientBuilder().
|
baseClient := fake.NewClientBuilder().
|
||||||
WithScheme(scheme).
|
WithScheme(scheme).
|
||||||
WithObjects(secretInClient, objectStore).Build()
|
WithObjects(secretInClient, objectStore).Build()
|
||||||
extendedClient = NewExtendedClient(baseClient, client.ObjectKeyFromObject(objectStore)).(*ExtendedClient)
|
extendedClient = NewExtendedClient(baseClient, []client.ObjectKey{
|
||||||
|
client.ObjectKeyFromObject(objectStore),
|
||||||
|
}).(*ExtendedClient)
|
||||||
})
|
})
|
||||||
|
|
||||||
It("returns secret from cache if not expired", func(ctx SpecContext) {
|
It("returns secret from cache if not expired", func(ctx SpecContext) {
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import (
|
|||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/fields"
|
"k8s.io/apimachinery/pkg/fields"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
@ -33,20 +34,16 @@ func Start(ctx context.Context) error {
|
|||||||
setupLog := log.FromContext(ctx)
|
setupLog := log.FromContext(ctx)
|
||||||
setupLog.Info("Starting barman cloud instance plugin")
|
setupLog.Info("Starting barman cloud instance plugin")
|
||||||
namespace := viper.GetString("namespace")
|
namespace := viper.GetString("namespace")
|
||||||
boName := viper.GetString("barman-object-name")
|
|
||||||
clusterName := viper.GetString("cluster-name")
|
clusterName := viper.GetString("cluster-name")
|
||||||
podName := viper.GetString("pod-name")
|
podName := viper.GetString("pod-name")
|
||||||
|
|
||||||
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
barmanObjectName := viper.GetString("barman-object-name")
|
||||||
|
recoveryBarmanObjectName := viper.GetString("recovery-barman-object-name")
|
||||||
|
|
||||||
|
controllerOptions := ctrl.Options{
|
||||||
Scheme: scheme,
|
Scheme: scheme,
|
||||||
Cache: cache.Options{
|
Cache: cache.Options{
|
||||||
ByObject: map[client.Object]cache.ByObject{
|
ByObject: map[client.Object]cache.ByObject{
|
||||||
&barmancloudv1.ObjectStore{}: {
|
|
||||||
Field: fields.OneTermEqualSelector("metadata.name", boName),
|
|
||||||
Namespaces: map[string]cache.Config{
|
|
||||||
namespace: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&cnpgv1.Cluster{}: {
|
&cnpgv1.Cluster{}: {
|
||||||
Field: fields.OneTermEqualSelector("metadata.name", clusterName),
|
Field: fields.OneTermEqualSelector("metadata.name", clusterName),
|
||||||
Namespaces: map[string]cache.Config{
|
Namespaces: map[string]cache.Config{
|
||||||
@ -62,7 +59,23 @@ func Start(ctx context.Context) error {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
}
|
||||||
|
|
||||||
|
if len(recoveryBarmanObjectName) == 0 {
|
||||||
|
controllerOptions.Cache.ByObject[&barmancloudv1.ObjectStore{}] = cache.ByObject{
|
||||||
|
Field: fields.OneTermEqualSelector("metadata.name", barmanObjectName),
|
||||||
|
Namespaces: map[string]cache.Config{
|
||||||
|
namespace: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
controllerOptions.Client.Cache.DisableFor = append(
|
||||||
|
controllerOptions.Client.Cache.DisableFor,
|
||||||
|
&barmancloudv1.ObjectStore{},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), controllerOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
setupLog.Error(err, "unable to start manager")
|
setupLog.Error(err, "unable to start manager")
|
||||||
return err
|
return err
|
||||||
@ -70,23 +83,39 @@ func Start(ctx context.Context) error {
|
|||||||
|
|
||||||
barmanObjectKey := client.ObjectKey{
|
barmanObjectKey := client.ObjectKey{
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Name: boName,
|
Name: barmanObjectName,
|
||||||
|
}
|
||||||
|
recoveryBarmanObjectKey := client.ObjectKey{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: recoveryBarmanObjectName,
|
||||||
|
}
|
||||||
|
|
||||||
|
involvedObjectStores := make([]types.NamespacedName, 0, 2)
|
||||||
|
if len(barmanObjectName) > 0 {
|
||||||
|
involvedObjectStores = append(involvedObjectStores, barmanObjectKey)
|
||||||
|
}
|
||||||
|
if len(recoveryBarmanObjectName) > 0 {
|
||||||
|
involvedObjectStores = append(involvedObjectStores, recoveryBarmanObjectKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := mgr.Add(&CNPGI{
|
if err := mgr.Add(&CNPGI{
|
||||||
Client: extendedclient.NewExtendedClient(mgr.GetClient(), barmanObjectKey),
|
Client: extendedclient.NewExtendedClient(mgr.GetClient(), involvedObjectStores),
|
||||||
ClusterObjectKey: client.ObjectKey{
|
ClusterObjectKey: client.ObjectKey{
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Name: clusterName,
|
Name: clusterName,
|
||||||
},
|
},
|
||||||
BarmanObjectKey: barmanObjectKey,
|
InstanceName: podName,
|
||||||
ServerName: viper.GetString("server-name"),
|
|
||||||
InstanceName: podName,
|
|
||||||
// TODO: improve
|
// TODO: improve
|
||||||
PGDataPath: viper.GetString("pgdata"),
|
PGDataPath: viper.GetString("pgdata"),
|
||||||
PGWALPath: path.Join(viper.GetString("pgdata"), "pg_wal"),
|
PGWALPath: path.Join(viper.GetString("pgdata"), "pg_wal"),
|
||||||
SpoolDirectory: viper.GetString("spool-directory"),
|
SpoolDirectory: viper.GetString("spool-directory"),
|
||||||
PluginPath: viper.GetString("plugin-path"),
|
PluginPath: viper.GetString("plugin-path"),
|
||||||
|
|
||||||
|
BarmanObjectKey: barmanObjectKey,
|
||||||
|
ServerName: viper.GetString("server-name"),
|
||||||
|
|
||||||
|
RecoveryBarmanObjectKey: recoveryBarmanObjectKey,
|
||||||
|
RecoveryServerName: viper.GetString("recovery-server-name"),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
setupLog.Error(err, "unable to create CNPGI runnable")
|
setupLog.Error(err, "unable to create CNPGI runnable")
|
||||||
return err
|
return err
|
||||||
|
|||||||
@ -15,8 +15,6 @@ import (
|
|||||||
// CNPGI is the implementation of the PostgreSQL sidecar
|
// CNPGI is the implementation of the PostgreSQL sidecar
|
||||||
type CNPGI struct {
|
type CNPGI struct {
|
||||||
Client client.Client
|
Client client.Client
|
||||||
BarmanObjectKey client.ObjectKey
|
|
||||||
ServerName string
|
|
||||||
ClusterObjectKey client.ObjectKey
|
ClusterObjectKey client.ObjectKey
|
||||||
PGDataPath string
|
PGDataPath string
|
||||||
PGWALPath string
|
PGWALPath string
|
||||||
@ -24,20 +22,30 @@ type CNPGI struct {
|
|||||||
// mutually exclusive with serverAddress
|
// mutually exclusive with serverAddress
|
||||||
PluginPath string
|
PluginPath string
|
||||||
InstanceName string
|
InstanceName string
|
||||||
|
|
||||||
|
BarmanObjectKey client.ObjectKey
|
||||||
|
ServerName string
|
||||||
|
|
||||||
|
RecoveryBarmanObjectKey client.ObjectKey
|
||||||
|
RecoveryServerName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start starts the GRPC service
|
// Start starts the GRPC service
|
||||||
func (c *CNPGI) Start(ctx context.Context) error {
|
func (c *CNPGI) Start(ctx context.Context) error {
|
||||||
enrich := func(server *grpc.Server) error {
|
enrich := func(server *grpc.Server) error {
|
||||||
wal.RegisterWALServer(server, common.WALServiceImplementation{
|
wal.RegisterWALServer(server, common.WALServiceImplementation{
|
||||||
BarmanObjectKey: c.BarmanObjectKey,
|
|
||||||
ClusterObjectKey: c.ClusterObjectKey,
|
ClusterObjectKey: c.ClusterObjectKey,
|
||||||
ServerName: c.ServerName,
|
|
||||||
InstanceName: c.InstanceName,
|
InstanceName: c.InstanceName,
|
||||||
Client: c.Client,
|
Client: c.Client,
|
||||||
SpoolDirectory: c.SpoolDirectory,
|
SpoolDirectory: c.SpoolDirectory,
|
||||||
PGDataPath: c.PGDataPath,
|
PGDataPath: c.PGDataPath,
|
||||||
PGWALPath: c.PGWALPath,
|
PGWALPath: c.PGWALPath,
|
||||||
|
|
||||||
|
BarmanObjectKey: c.BarmanObjectKey,
|
||||||
|
ServerName: c.ServerName,
|
||||||
|
|
||||||
|
RecoveryBarmanObjectKey: c.RecoveryBarmanObjectKey,
|
||||||
|
RecoveryServerName: c.RecoveryServerName,
|
||||||
})
|
})
|
||||||
backup.RegisterBackupServer(server, BackupServiceImplementation{
|
backup.RegisterBackupServer(server, BackupServiceImplementation{
|
||||||
Client: c.Client,
|
Client: c.Client,
|
||||||
|
|||||||
@ -47,7 +47,7 @@ type PluginConfiguration struct {
|
|||||||
BarmanObjectName string
|
BarmanObjectName string
|
||||||
ServerName string
|
ServerName string
|
||||||
RecoveryBarmanObjectName string
|
RecoveryBarmanObjectName string
|
||||||
RecoveryBarmanServerName string
|
RecoveryServerName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFromCluster extracts the configuration from the cluster
|
// NewFromCluster extracts the configuration from the cluster
|
||||||
@ -82,7 +82,7 @@ func NewFromCluster(cluster *cnpgv1.Cluster) *PluginConfiguration {
|
|||||||
BarmanObjectName: helper.Parameters["barmanObjectName"],
|
BarmanObjectName: helper.Parameters["barmanObjectName"],
|
||||||
ServerName: serverName,
|
ServerName: serverName,
|
||||||
// used for restore/wal_restore
|
// used for restore/wal_restore
|
||||||
RecoveryBarmanServerName: recoveryServerName,
|
RecoveryServerName: recoveryServerName,
|
||||||
RecoveryBarmanObjectName: recoveryBarmanObjectName,
|
RecoveryBarmanObjectName: recoveryBarmanObjectName,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -115,13 +115,6 @@ func reconcileJob(
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since we're recovering from an existing object store,
|
|
||||||
// we set our primary object store name to the recovery one.
|
|
||||||
// This won't be needed anymore when wal-restore will be able
|
|
||||||
// to check two object stores
|
|
||||||
pluginConfiguration.BarmanObjectName = pluginConfiguration.RecoveryBarmanObjectName
|
|
||||||
pluginConfiguration.ServerName = pluginConfiguration.RecoveryBarmanServerName
|
|
||||||
|
|
||||||
var job batchv1.Job
|
var job batchv1.Job
|
||||||
if err := decoder.DecodeObject(
|
if err := decoder.DecodeObject(
|
||||||
request.GetObjectDefinition(),
|
request.GetObjectDefinition(),
|
||||||
@ -219,14 +212,6 @@ func reconcilePodSpec(
|
|||||||
Name: "CLUSTER_NAME",
|
Name: "CLUSTER_NAME",
|
||||||
Value: cluster.Name,
|
Value: cluster.Name,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: "BARMAN_OBJECT_NAME",
|
|
||||||
Value: cfg.BarmanObjectName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "SERVER_NAME",
|
|
||||||
Value: cfg.ServerName,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
// TODO: should we really use this one?
|
// TODO: should we really use this one?
|
||||||
// should we mount an emptyDir volume just for that?
|
// should we mount an emptyDir volume just for that?
|
||||||
@ -235,6 +220,32 @@ func reconcilePodSpec(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(cfg.BarmanObjectName) > 0 {
|
||||||
|
envs = append(envs,
|
||||||
|
corev1.EnvVar{
|
||||||
|
Name: "BARMAN_OBJECT_NAME",
|
||||||
|
Value: cfg.BarmanObjectName,
|
||||||
|
},
|
||||||
|
corev1.EnvVar{
|
||||||
|
Name: "SERVER_NAME",
|
||||||
|
Value: cfg.ServerName,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cfg.RecoveryBarmanObjectName) > 0 {
|
||||||
|
envs = append(envs,
|
||||||
|
corev1.EnvVar{
|
||||||
|
Name: "RECOVERY_BARMAN_OBJECT_NAME",
|
||||||
|
Value: cfg.RecoveryBarmanObjectName,
|
||||||
|
},
|
||||||
|
corev1.EnvVar{
|
||||||
|
Name: "RECOVERY_SERVER_NAME",
|
||||||
|
Value: cfg.RecoveryServerName,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
baseProbe := &corev1.Probe{
|
baseProbe := &corev1.Probe{
|
||||||
FailureThreshold: 3,
|
FailureThreshold: 3,
|
||||||
ProbeHandler: corev1.ProbeHandler{
|
ProbeHandler: corev1.ProbeHandler{
|
||||||
|
|||||||
@ -15,7 +15,6 @@ import (
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
|
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
|
||||||
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
|
|
||||||
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
|
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
|
||||||
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/specs"
|
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/specs"
|
||||||
)
|
)
|
||||||
@ -78,7 +77,6 @@ func (r ReconcilerImplementation) Pre(
|
|||||||
|
|
||||||
var barmanObjects []barmancloudv1.ObjectStore
|
var barmanObjects []barmancloudv1.ObjectStore
|
||||||
|
|
||||||
// this could be empty during recoveries
|
|
||||||
if pluginConfiguration.BarmanObjectName != "" {
|
if pluginConfiguration.BarmanObjectName != "" {
|
||||||
var barmanObject barmancloudv1.ObjectStore
|
var barmanObject barmancloudv1.ObjectStore
|
||||||
if err := r.Client.Get(ctx, client.ObjectKey{
|
if err := r.Client.Get(ctx, client.ObjectKey{
|
||||||
@ -86,7 +84,10 @@ func (r ReconcilerImplementation) Pre(
|
|||||||
Name: pluginConfiguration.BarmanObjectName,
|
Name: pluginConfiguration.BarmanObjectName,
|
||||||
}, &barmanObject); err != nil {
|
}, &barmanObject); err != nil {
|
||||||
if apierrs.IsNotFound(err) {
|
if apierrs.IsNotFound(err) {
|
||||||
contextLogger.Info("barman object configuration not found, requeuing")
|
contextLogger.Info(
|
||||||
|
"barman object configuration not found, requeuing",
|
||||||
|
"name", pluginConfiguration.BarmanObjectName,
|
||||||
|
"namespace", cluster.Namespace)
|
||||||
return &reconciler.ReconcilerHooksResult{
|
return &reconciler.ReconcilerHooksResult{
|
||||||
Behavior: reconciler.ReconcilerHooksResult_BEHAVIOR_REQUEUE,
|
Behavior: reconciler.ReconcilerHooksResult_BEHAVIOR_REQUEUE,
|
||||||
}, nil
|
}, nil
|
||||||
@ -98,15 +99,26 @@ func (r ReconcilerImplementation) Pre(
|
|||||||
barmanObjects = append(barmanObjects, barmanObject)
|
barmanObjects = append(barmanObjects, barmanObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
if barmanObject, err := r.getRecoveryBarmanObject(ctx, &cluster); err != nil {
|
if pluginConfiguration.RecoveryBarmanObjectName != "" {
|
||||||
if apierrs.IsNotFound(err) {
|
var barmanObject barmancloudv1.ObjectStore
|
||||||
contextLogger.Info("barman recovery object configuration not found, requeuing")
|
if err := r.Client.Get(ctx, client.ObjectKey{
|
||||||
return &reconciler.ReconcilerHooksResult{
|
Namespace: cluster.Namespace,
|
||||||
Behavior: reconciler.ReconcilerHooksResult_BEHAVIOR_REQUEUE,
|
Name: pluginConfiguration.RecoveryBarmanObjectName,
|
||||||
}, nil
|
}, &barmanObject); err != nil {
|
||||||
|
if apierrs.IsNotFound(err) {
|
||||||
|
contextLogger.Info(
|
||||||
|
"barman recovery object configuration not found, requeuing",
|
||||||
|
"name", pluginConfiguration.RecoveryBarmanObjectName,
|
||||||
|
"namespace", cluster.Namespace,
|
||||||
|
)
|
||||||
|
return &reconciler.ReconcilerHooksResult{
|
||||||
|
Behavior: reconciler.ReconcilerHooksResult_BEHAVIOR_REQUEUE,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
} else if barmanObject != nil {
|
|
||||||
barmanObjects = append(barmanObjects, *barmanObject)
|
barmanObjects = append(barmanObjects, barmanObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
var additionalSecretNames []string
|
var additionalSecretNames []string
|
||||||
@ -124,30 +136,6 @@ func (r ReconcilerImplementation) Pre(
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r ReconcilerImplementation) getRecoveryBarmanObject(
|
|
||||||
ctx context.Context,
|
|
||||||
cluster *cnpgv1.Cluster,
|
|
||||||
) (*barmancloudv1.ObjectStore, error) {
|
|
||||||
recoveryConfig := cluster.GetRecoverySourcePlugin()
|
|
||||||
if recoveryConfig != nil && recoveryConfig.Name == metadata.PluginName {
|
|
||||||
// TODO: refactor -> cnpg-i-machinery should be able to help us on getting
|
|
||||||
// the configuration for a recovery plugin
|
|
||||||
if recoveryObjectStore, ok := recoveryConfig.Parameters["barmanObjectName"]; ok {
|
|
||||||
var barmanObject barmancloudv1.ObjectStore
|
|
||||||
if err := r.Client.Get(ctx, client.ObjectKey{
|
|
||||||
Namespace: cluster.Namespace,
|
|
||||||
Name: recoveryObjectStore,
|
|
||||||
}, &barmanObject); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &barmanObject, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Post implements the reconciler interface
|
// Post implements the reconciler interface
|
||||||
func (r ReconcilerImplementation) Post(
|
func (r ReconcilerImplementation) Post(
|
||||||
_ context.Context,
|
_ context.Context,
|
||||||
|
|||||||
@ -27,24 +27,10 @@ func BuildRole(
|
|||||||
}
|
}
|
||||||
|
|
||||||
secretsSet := stringset.New()
|
secretsSet := stringset.New()
|
||||||
for _, barmanObject := range barmanObjects {
|
barmanObjectsSet := stringset.New()
|
||||||
role.Rules = append(role.Rules, rbacv1.PolicyRule{
|
|
||||||
APIGroups: []string{
|
|
||||||
"barmancloud.cnpg.io",
|
|
||||||
},
|
|
||||||
Verbs: []string{
|
|
||||||
"get",
|
|
||||||
"watch",
|
|
||||||
"list",
|
|
||||||
},
|
|
||||||
Resources: []string{
|
|
||||||
"objectstores",
|
|
||||||
},
|
|
||||||
ResourceNames: []string{
|
|
||||||
barmanObject.Name,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
|
for _, barmanObject := range barmanObjects {
|
||||||
|
barmanObjectsSet.Put(barmanObject.Name)
|
||||||
for _, secret := range CollectSecretNamesFromCredentials(&barmanObject.Spec.Configuration.BarmanCredentials) {
|
for _, secret := range CollectSecretNamesFromCredentials(&barmanObject.Spec.Configuration.BarmanCredentials) {
|
||||||
secretsSet.Put(secret)
|
secretsSet.Put(secret)
|
||||||
}
|
}
|
||||||
@ -54,6 +40,21 @@ func BuildRole(
|
|||||||
secretsSet.Put(secret)
|
secretsSet.Put(secret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
role.Rules = append(role.Rules, rbacv1.PolicyRule{
|
||||||
|
APIGroups: []string{
|
||||||
|
"barmancloud.cnpg.io",
|
||||||
|
},
|
||||||
|
Verbs: []string{
|
||||||
|
"get",
|
||||||
|
"watch",
|
||||||
|
"list",
|
||||||
|
},
|
||||||
|
Resources: []string{
|
||||||
|
"objectstores",
|
||||||
|
},
|
||||||
|
ResourceNames: barmanObjectsSet.ToSortedList(),
|
||||||
|
})
|
||||||
|
|
||||||
role.Rules = append(role.Rules, rbacv1.PolicyRule{
|
role.Rules = append(role.Rules, rbacv1.PolicyRule{
|
||||||
APIGroups: []string{
|
APIGroups: []string{
|
||||||
"",
|
"",
|
||||||
|
|||||||
@ -32,7 +32,12 @@ func Start(ctx context.Context) error {
|
|||||||
setupLog.Info("Starting barman cloud instance plugin")
|
setupLog.Info("Starting barman cloud instance plugin")
|
||||||
namespace := viper.GetString("namespace")
|
namespace := viper.GetString("namespace")
|
||||||
clusterName := viper.GetString("cluster-name")
|
clusterName := viper.GetString("cluster-name")
|
||||||
boName := viper.GetString("barman-object-name")
|
|
||||||
|
recoveryBarmanObjectName := viper.GetString("recovery-barman-object-name")
|
||||||
|
recoveryServerName := viper.GetString("recovery-server-name")
|
||||||
|
|
||||||
|
barmanObjectName := viper.GetString("barman-object-name")
|
||||||
|
serverName := viper.GetString("server-name")
|
||||||
|
|
||||||
objs := map[client.Object]cache.ByObject{
|
objs := map[client.Object]cache.ByObject{
|
||||||
&cnpgv1.Cluster{}: {
|
&cnpgv1.Cluster{}: {
|
||||||
@ -43,9 +48,9 @@ func Start(ctx context.Context) error {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if boName != "" {
|
if recoveryBarmanObjectName != "" {
|
||||||
objs[&barmancloudv1.ObjectStore{}] = cache.ByObject{
|
objs[&barmancloudv1.ObjectStore{}] = cache.ByObject{
|
||||||
Field: fields.OneTermEqualSelector("metadata.name", boName),
|
Field: fields.OneTermEqualSelector("metadata.name", recoveryBarmanObjectName),
|
||||||
Namespaces: map[string]cache.Config{
|
Namespaces: map[string]cache.Config{
|
||||||
namespace: {},
|
namespace: {},
|
||||||
},
|
},
|
||||||
@ -74,10 +79,6 @@ func Start(ctx context.Context) error {
|
|||||||
if err := mgr.Add(&CNPGI{
|
if err := mgr.Add(&CNPGI{
|
||||||
PluginPath: viper.GetString("plugin-path"),
|
PluginPath: viper.GetString("plugin-path"),
|
||||||
SpoolDirectory: viper.GetString("spool-directory"),
|
SpoolDirectory: viper.GetString("spool-directory"),
|
||||||
BarmanObjectKey: client.ObjectKey{
|
|
||||||
Namespace: namespace,
|
|
||||||
Name: boName,
|
|
||||||
},
|
|
||||||
ClusterObjectKey: client.ObjectKey{
|
ClusterObjectKey: client.ObjectKey{
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Name: clusterName,
|
Name: clusterName,
|
||||||
@ -85,7 +86,18 @@ func Start(ctx context.Context) error {
|
|||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
PGDataPath: viper.GetString("pgdata"),
|
PGDataPath: viper.GetString("pgdata"),
|
||||||
InstanceName: viper.GetString("pod-name"),
|
InstanceName: viper.GetString("pod-name"),
|
||||||
ServerName: viper.GetString("server-name"),
|
|
||||||
|
ServerName: serverName,
|
||||||
|
BarmanObjectKey: client.ObjectKey{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: barmanObjectName,
|
||||||
|
},
|
||||||
|
|
||||||
|
RecoveryServerName: recoveryServerName,
|
||||||
|
RecoveryBarmanObjectKey: client.ObjectKey{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: recoveryBarmanObjectName,
|
||||||
|
},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
setupLog.Error(err, "unable to create CNPGI runnable")
|
setupLog.Error(err, "unable to create CNPGI runnable")
|
||||||
return err
|
return err
|
||||||
|
|||||||
@ -43,9 +43,16 @@ const (
|
|||||||
// JobHookImpl is the implementation of the restore job hooks
|
// JobHookImpl is the implementation of the restore job hooks
|
||||||
type JobHookImpl struct {
|
type JobHookImpl struct {
|
||||||
restore.UnimplementedRestoreJobHooksServer
|
restore.UnimplementedRestoreJobHooksServer
|
||||||
Client client.Client
|
|
||||||
ClusterObjectKey client.ObjectKey
|
Client client.Client
|
||||||
BackupToRestore client.ObjectKey
|
ClusterObjectKey client.ObjectKey
|
||||||
|
|
||||||
|
BarmanObjectKey types.NamespacedName
|
||||||
|
ServerName string
|
||||||
|
|
||||||
|
RecoveryBarmanObjectKey types.NamespacedName
|
||||||
|
RecoveryServerName string
|
||||||
|
|
||||||
SpoolDirectory string
|
SpoolDirectory string
|
||||||
PgDataPath string
|
PgDataPath string
|
||||||
PgWalFolderToSymlink string
|
PgWalFolderToSymlink string
|
||||||
@ -80,38 +87,17 @@ func (impl JobHookImpl) Restore(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
recoveryPluginConfiguration := cluster.GetRecoverySourcePlugin()
|
|
||||||
|
|
||||||
var recoveryObjectStore barmancloudv1.ObjectStore
|
var recoveryObjectStore barmancloudv1.ObjectStore
|
||||||
if err := impl.Client.Get(ctx, types.NamespacedName{
|
if err := impl.Client.Get(ctx, impl.RecoveryBarmanObjectKey, &recoveryObjectStore); err != nil {
|
||||||
Namespace: cluster.Namespace,
|
|
||||||
// TODO: refactor -> cnpg-i-machinery should be able to help us on getting
|
|
||||||
// the configuration for a recovery plugin
|
|
||||||
Name: recoveryPluginConfiguration.Parameters["barmanObjectName"],
|
|
||||||
}, &recoveryObjectStore); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetObjectStoreName types.NamespacedName
|
if impl.BarmanObjectKey.Name != "" {
|
||||||
for _, plugin := range cluster.Spec.Plugins {
|
var targetObjectStore barmancloudv1.ObjectStore
|
||||||
if plugin.IsEnabled() && plugin.Name == metadata.PluginName {
|
if err := impl.Client.Get(ctx, impl.BarmanObjectKey, &targetObjectStore); err != nil {
|
||||||
targetObjectStoreName = types.NamespacedName{
|
|
||||||
Namespace: cluster.Namespace,
|
|
||||||
Name: plugin.Parameters["barmanObjectName"],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var targetObjectStore barmancloudv1.ObjectStore
|
|
||||||
if targetObjectStoreName.Name != "" {
|
|
||||||
if err := impl.Client.Get(ctx, targetObjectStoreName, &targetObjectStore); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Before starting the restore we check if the archive destination is safe to use,
|
|
||||||
// otherwise we stop creating the cluster
|
|
||||||
if targetObjectStoreName.Name != "" {
|
|
||||||
if err := impl.checkBackupDestination(ctx, &cluster, &targetObjectStore.Spec.Configuration); err != nil {
|
if err := impl.checkBackupDestination(ctx, &cluster, &targetObjectStore.Spec.Configuration); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -123,6 +109,7 @@ func (impl JobHookImpl) Restore(
|
|||||||
impl.Client,
|
impl.Client,
|
||||||
&cluster,
|
&cluster,
|
||||||
&recoveryObjectStore.Spec.Configuration,
|
&recoveryObjectStore.Spec.Configuration,
|
||||||
|
impl.RecoveryServerName,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -353,30 +340,13 @@ func loadBackupObjectFromExternalCluster(
|
|||||||
typedClient client.Client,
|
typedClient client.Client,
|
||||||
cluster *cnpgv1.Cluster,
|
cluster *cnpgv1.Cluster,
|
||||||
recoveryObjectStore *api.BarmanObjectStoreConfiguration,
|
recoveryObjectStore *api.BarmanObjectStoreConfiguration,
|
||||||
|
serverName string,
|
||||||
) (*cnpgv1.Backup, []string, error) {
|
) (*cnpgv1.Backup, []string, error) {
|
||||||
contextLogger := log.FromContext(ctx)
|
contextLogger := log.FromContext(ctx)
|
||||||
sourceName := cluster.Spec.Bootstrap.Recovery.Source
|
|
||||||
|
|
||||||
if sourceName == "" {
|
|
||||||
return nil, nil, fmt.Errorf("recovery source not specified")
|
|
||||||
}
|
|
||||||
|
|
||||||
server, found := cluster.ExternalCluster(sourceName)
|
|
||||||
if !found {
|
|
||||||
return nil, nil, fmt.Errorf("missing external cluster: %v", sourceName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: document this, should this be in the helper?
|
|
||||||
var serverName string
|
|
||||||
if pluginServerName, ok := server.PluginConfiguration.Parameters["serverName"]; ok {
|
|
||||||
serverName = pluginServerName
|
|
||||||
} else {
|
|
||||||
serverName = server.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
contextLogger.Info("Recovering from external cluster",
|
contextLogger.Info("Recovering from external cluster",
|
||||||
"sourceName", sourceName,
|
"serverName", serverName,
|
||||||
"serverName", serverName)
|
"objectStore", recoveryObjectStore)
|
||||||
|
|
||||||
env, err := barmanCredentials.EnvSetRestoreCloudCredentials(
|
env, err := barmanCredentials.EnvSetRestoreCloudCredentials(
|
||||||
ctx,
|
ctx,
|
||||||
|
|||||||
@ -15,14 +15,20 @@ import (
|
|||||||
|
|
||||||
// CNPGI is the implementation of the PostgreSQL sidecar
|
// CNPGI is the implementation of the PostgreSQL sidecar
|
||||||
type CNPGI struct {
|
type CNPGI struct {
|
||||||
PluginPath string
|
PluginPath string
|
||||||
SpoolDirectory string
|
SpoolDirectory string
|
||||||
BarmanObjectKey client.ObjectKey
|
|
||||||
|
BarmanObjectKey client.ObjectKey
|
||||||
|
ServerName string
|
||||||
|
|
||||||
|
RecoveryBarmanObjectKey client.ObjectKey
|
||||||
|
RecoveryServerName string
|
||||||
|
|
||||||
ClusterObjectKey client.ObjectKey
|
ClusterObjectKey client.ObjectKey
|
||||||
Client client.Client
|
|
||||||
PGDataPath string
|
Client client.Client
|
||||||
InstanceName string
|
PGDataPath string
|
||||||
ServerName string
|
InstanceName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start starts the GRPC service
|
// Start starts the GRPC service
|
||||||
@ -32,14 +38,18 @@ func (c *CNPGI) Start(ctx context.Context) error {
|
|||||||
|
|
||||||
enrich := func(server *grpc.Server) error {
|
enrich := func(server *grpc.Server) error {
|
||||||
wal.RegisterWALServer(server, common.WALServiceImplementation{
|
wal.RegisterWALServer(server, common.WALServiceImplementation{
|
||||||
BarmanObjectKey: c.BarmanObjectKey,
|
|
||||||
ClusterObjectKey: c.ClusterObjectKey,
|
ClusterObjectKey: c.ClusterObjectKey,
|
||||||
InstanceName: c.InstanceName,
|
InstanceName: c.InstanceName,
|
||||||
Client: c.Client,
|
Client: c.Client,
|
||||||
SpoolDirectory: c.SpoolDirectory,
|
SpoolDirectory: c.SpoolDirectory,
|
||||||
PGDataPath: c.PGDataPath,
|
PGDataPath: c.PGDataPath,
|
||||||
PGWALPath: path.Join(c.PGDataPath, "pg_wal"),
|
PGWALPath: path.Join(c.PGDataPath, "pg_wal"),
|
||||||
ServerName: c.ServerName,
|
|
||||||
|
BarmanObjectKey: c.BarmanObjectKey,
|
||||||
|
ServerName: c.ServerName,
|
||||||
|
|
||||||
|
RecoveryBarmanObjectKey: c.RecoveryBarmanObjectKey,
|
||||||
|
RecoveryServerName: c.RecoveryServerName,
|
||||||
})
|
})
|
||||||
|
|
||||||
restore.RegisterRestoreJobHooksServer(server, &JobHookImpl{
|
restore.RegisterRestoreJobHooksServer(server, &JobHookImpl{
|
||||||
@ -48,6 +58,12 @@ func (c *CNPGI) Start(ctx context.Context) error {
|
|||||||
SpoolDirectory: c.SpoolDirectory,
|
SpoolDirectory: c.SpoolDirectory,
|
||||||
PgDataPath: c.PGDataPath,
|
PgDataPath: c.PGDataPath,
|
||||||
PgWalFolderToSymlink: PgWalVolumePgWalPath,
|
PgWalFolderToSymlink: PgWalVolumePgWalPath,
|
||||||
|
|
||||||
|
BarmanObjectKey: c.BarmanObjectKey,
|
||||||
|
ServerName: c.ServerName,
|
||||||
|
|
||||||
|
RecoveryBarmanObjectKey: c.RecoveryBarmanObjectKey,
|
||||||
|
RecoveryServerName: c.RecoveryServerName,
|
||||||
})
|
})
|
||||||
|
|
||||||
common.AddHealthCheck(server)
|
common.AddHealthCheck(server)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user