Skip to content

Commit

Permalink
kopia pvbr
Browse files Browse the repository at this point in the history
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
  • Loading branch information
Lyndon-Li committed Aug 30, 2022
1 parent c8818ec commit b108b6b
Show file tree
Hide file tree
Showing 19 changed files with 395 additions and 82 deletions.
2 changes: 1 addition & 1 deletion config/crd/v1/bases/velero.io_backuprepositories.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ spec:
repositoryType:
description: RepositoryType indicates the type of the backend repository
enum:
- kopia
- unified
- restic
- ""
type: string
Expand Down
2 changes: 1 addition & 1 deletion config/crd/v1/crds/crds.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pkg/apis/velero/v1/backup_repository_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type BackupRepositorySpec struct {
BackupStorageLocation string `json:"backupStorageLocation"`

// RepositoryType indicates the type of the backend repository
// +kubebuilder:validation:Enum=kopia;restic;""
// +kubebuilder:validation:Enum=unified;restic;""
// +optional
RepositoryType string `json:"repositoryType"`

Expand Down
11 changes: 7 additions & 4 deletions pkg/apis/velero/v1/labels_annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,19 @@ const (

// PodVolumeOperationTimeoutAnnotation is the annotation key used to apply
// a backup/restore-specific timeout value for pod volume operations (i.e.
// restic backups/restores).
// pod volume backups/restores).
PodVolumeOperationTimeoutAnnotation = "velero.io/pod-volume-timeout"

// StorageLocationLabel is the label key used to identify the storage
// location of a backup.
StorageLocationLabel = "velero.io/storage-location"

// ResticVolumeNamespaceLabel is the label key used to identify which
// namespace a restic repository stores pod volume backups for.
ResticVolumeNamespaceLabel = "velero.io/volume-namespace"
// VolumeNamespaceLabel is the label key used to identify which
// namespace a repository stores backups for.
VolumeNamespaceLabel = "velero.io/volume-namespace"

// RepositoryTypeLabel is the label key used to identify the type of a repository
RepositoryTypeLabel = "velero.io/repository-type"

// SourceClusterK8sVersionAnnotation is the label key used to identify the k8s
// git version of the backup , i.e. v1.16.4
Expand Down
5 changes: 4 additions & 1 deletion pkg/backup/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type kubernetesBackupper struct {
resticTimeout time.Duration
defaultVolumesToRestic bool
clientPageSize int
pvbrUploaderType string
}

func (i *itemKey) String() string {
Expand All @@ -104,6 +105,7 @@ func NewKubernetesBackupper(
resticTimeout time.Duration,
defaultVolumesToRestic bool,
clientPageSize int,
pvbrUploaderType string,
) (Backupper, error) {
return &kubernetesBackupper{
backupClient: backupClient,
Expand All @@ -114,6 +116,7 @@ func NewKubernetesBackupper(
resticTimeout: resticTimeout,
defaultVolumesToRestic: defaultVolumesToRestic,
clientPageSize: clientPageSize,
pvbrUploaderType: pvbrUploaderType,
}, nil
}

Expand Down Expand Up @@ -236,7 +239,7 @@ func (kb *kubernetesBackupper) BackupWithResolvers(log logrus.FieldLogger,

var resticBackupper podvolume.Backupper
if kb.resticBackupperFactory != nil {
resticBackupper, err = kb.resticBackupperFactory.NewBackupper(ctx, backupRequest.Backup)
resticBackupper, err = kb.resticBackupperFactory.NewBackupper(ctx, backupRequest.Backup, kb.pvbrUploaderType)
if err != nil {
return errors.WithStack(err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/backup/backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2595,7 +2595,7 @@ func TestBackupWithHooks(t *testing.T) {

type fakeResticBackupperFactory struct{}

func (f *fakeResticBackupperFactory) NewBackupper(context.Context, *velerov1.Backup) (podvolume.Backupper, error) {
func (f *fakeResticBackupperFactory) NewBackupper(context.Context, *velerov1.Backup, string) (podvolume.Backupper, error) {
return &fakeResticBackupper{}, nil
}

Expand Down
50 changes: 27 additions & 23 deletions pkg/cmd/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ type serverConfig struct {
clientPageSize int
profilerAddress string
formatFlag *logging.FormatFlag
defaultResticMaintenanceFrequency time.Duration
repoMaintenanceFrequency time.Duration
garbageCollectionFrequency time.Duration
defaultVolumesToRestic bool
uploaderType string
Expand All @@ -147,25 +147,24 @@ func NewCommand(f client.Factory) *cobra.Command {
volumeSnapshotLocations = flag.NewMap().WithKeyValueDelimiter(':')
logLevelFlag = logging.LogLevelFlag(logrus.InfoLevel)
config = serverConfig{
pluginDir: "/plugins",
metricsAddress: defaultMetricsAddress,
defaultBackupLocation: "default",
defaultVolumeSnapshotLocations: make(map[string]string),
backupSyncPeriod: defaultBackupSyncPeriod,
defaultBackupTTL: defaultBackupTTL,
defaultCSISnapshotTimeout: defaultCSISnapshotTimeout,
storeValidationFrequency: defaultStoreValidationFrequency,
podVolumeOperationTimeout: defaultPodVolumeOperationTimeout,
restoreResourcePriorities: defaultRestorePriorities,
clientQPS: defaultClientQPS,
clientBurst: defaultClientBurst,
clientPageSize: defaultClientPageSize,
profilerAddress: defaultProfilerAddress,
resourceTerminatingTimeout: defaultResourceTerminatingTimeout,
formatFlag: logging.NewFormatFlag(),
defaultResticMaintenanceFrequency: restic.DefaultMaintenanceFrequency,
defaultVolumesToRestic: restic.DefaultVolumesToRestic,
uploaderType: uploader.ResticType,
pluginDir: "/plugins",
metricsAddress: defaultMetricsAddress,
defaultBackupLocation: "default",
defaultVolumeSnapshotLocations: make(map[string]string),
backupSyncPeriod: defaultBackupSyncPeriod,
defaultBackupTTL: defaultBackupTTL,
defaultCSISnapshotTimeout: defaultCSISnapshotTimeout,
storeValidationFrequency: defaultStoreValidationFrequency,
podVolumeOperationTimeout: defaultPodVolumeOperationTimeout,
restoreResourcePriorities: defaultRestorePriorities,
clientQPS: defaultClientQPS,
clientBurst: defaultClientBurst,
clientPageSize: defaultClientPageSize,
profilerAddress: defaultProfilerAddress,
resourceTerminatingTimeout: defaultResourceTerminatingTimeout,
formatFlag: logging.NewFormatFlag(),
defaultVolumesToRestic: restic.DefaultVolumesToRestic,
uploaderType: uploader.ResticType,
}
)

Expand Down Expand Up @@ -228,7 +227,7 @@ func NewCommand(f client.Factory) *cobra.Command {
command.Flags().StringVar(&config.profilerAddress, "profiler-address", config.profilerAddress, "The address to expose the pprof profiler.")
command.Flags().DurationVar(&config.resourceTerminatingTimeout, "terminating-resource-timeout", config.resourceTerminatingTimeout, "How long to wait on persistent volumes and namespaces to terminate during a restore before timing out.")
command.Flags().DurationVar(&config.defaultBackupTTL, "default-backup-ttl", config.defaultBackupTTL, "How long to wait by default before backups can be garbage collected.")
command.Flags().DurationVar(&config.defaultResticMaintenanceFrequency, "default-restic-prune-frequency", config.defaultResticMaintenanceFrequency, "How often 'restic prune' is run for restic repositories by default.")
command.Flags().DurationVar(&config.repoMaintenanceFrequency, "default-restic-prune-frequency", config.repoMaintenanceFrequency, "How often 'restic prune' is run for restic repositories by default.")
command.Flags().DurationVar(&config.garbageCollectionFrequency, "garbage-collection-frequency", config.garbageCollectionFrequency, "How often garbage collection is run for expired backups.")
command.Flags().BoolVar(&config.defaultVolumesToRestic, "default-volumes-to-restic", config.defaultVolumesToRestic, "Backup all volumes with restic by default.")
command.Flags().StringVar(&config.uploaderType, "uploader-type", config.uploaderType, "Type of uploader to handle the transfer of data of pod volumes")
Expand Down Expand Up @@ -260,6 +259,7 @@ type server struct {
config serverConfig
mgr manager.Manager
credentialFileStore credentials.FileStore
credentialSecretStore credentials.SecretStore
}

func newServer(f client.Factory, config serverConfig, logger *logrus.Logger) (*server, error) {
Expand Down Expand Up @@ -349,6 +349,8 @@ func newServer(f client.Factory, config serverConfig, logger *logrus.Logger) (*s
return nil, err
}

credentialSecretStore, err := credentials.NewNamespacedSecretStore(mgr.GetClient(), f.Namespace())

s := &server{
namespace: f.Namespace(),
metricsAddress: config.metricsAddress,
Expand All @@ -368,6 +370,7 @@ func newServer(f client.Factory, config serverConfig, logger *logrus.Logger) (*s
config: config,
mgr: mgr,
credentialFileStore: credentialFileStore,
credentialSecretStore: credentialSecretStore,
}

return s, nil
Expand Down Expand Up @@ -546,7 +549,7 @@ func (s *server) initRestic() error {
s.repoLocker = repository.NewRepoLocker()
s.repoEnsurer = repository.NewRepositoryEnsurer(s.sharedInformerFactory.Velero().V1().BackupRepositories(), s.veleroClient.VeleroV1(), s.logger)

s.repoManager = repository.NewManager(s.namespace, s.mgr.GetClient(), s.repoLocker, s.repoEnsurer, s.credentialFileStore, s.logger)
s.repoManager = repository.NewManager(s.namespace, s.mgr.GetClient(), s.repoLocker, s.repoEnsurer, s.credentialFileStore, s.credentialSecretStore, s.logger)

return nil
}
Expand Down Expand Up @@ -643,6 +646,7 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string
s.config.podVolumeOperationTimeout,
s.config.defaultVolumesToRestic,
s.config.clientPageSize,
s.config.uploaderType,
)
cmd.CheckError(err)

Expand Down Expand Up @@ -799,7 +803,7 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string
}

if _, ok := enabledRuntimeControllers[controller.ResticRepo]; ok {
if err := controller.NewResticRepoReconciler(s.namespace, s.logger, s.mgr.GetClient(), s.config.defaultResticMaintenanceFrequency, s.repoManager).SetupWithManager(s.mgr); err != nil {
if err := controller.NewResticRepoReconciler(s.namespace, s.logger, s.mgr.GetClient(), s.config.repoMaintenanceFrequency, s.repoManager).SetupWithManager(s.mgr); err != nil {
s.logger.Fatal(err, "unable to create controller", "controller", controller.ResticRepo)
}
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/controller/backup_deletion_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ import (
"github.com/vmware-tanzu/velero/pkg/util/kube"

"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/vmware-tanzu/velero/pkg/podvolume"
)

const (
Expand Down Expand Up @@ -515,6 +517,7 @@ func getSnapshotsInBackup(ctx context.Context, backup *velerov1api.Backup, kbCli
VolumeNamespace: item.Spec.Pod.Namespace,
BackupStorageLocation: backup.Spec.StorageLocation,
SnapshotID: item.Status.SnapshotID,
RepositoryType: podvolume.GetRepositoryTypeFromUploaderType(item.Spec.UploaderType),
})
}

Expand Down
44 changes: 28 additions & 16 deletions pkg/controller/restic_repository_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,39 +32,34 @@ import (
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/repository"
repoconfig "github.com/vmware-tanzu/velero/pkg/repository/config"
"github.com/vmware-tanzu/velero/pkg/restic"
"github.com/vmware-tanzu/velero/pkg/util/kube"
)

const (
repoSyncPeriod = 5 * time.Minute
repoSyncPeriod = 5 * time.Minute
defaultMaintainFrequency = 7 * 24 * time.Hour
)

type ResticRepoReconciler struct {
client.Client
namespace string
logger logrus.FieldLogger
clock clock.Clock
defaultMaintenanceFrequency time.Duration
repositoryManager repository.Manager
namespace string
logger logrus.FieldLogger
clock clock.Clock
maintenanceFrequency time.Duration
repositoryManager repository.Manager
}

func NewResticRepoReconciler(namespace string, logger logrus.FieldLogger, client client.Client,
defaultMaintenanceFrequency time.Duration, repositoryManager repository.Manager) *ResticRepoReconciler {
maintenanceFrequency time.Duration, repositoryManager repository.Manager) *ResticRepoReconciler {
c := &ResticRepoReconciler{
client,
namespace,
logger,
clock.RealClock{},
defaultMaintenanceFrequency,
maintenanceFrequency,
repositoryManager,
}

if c.defaultMaintenanceFrequency <= 0 {
logger.Infof("Invalid default restic maintenance frequency, setting to %v", restic.DefaultMaintenanceFrequency)
c.defaultMaintenanceFrequency = restic.DefaultMaintenanceFrequency
}

return c
}

Expand Down Expand Up @@ -135,7 +130,7 @@ func (r *ResticRepoReconciler) initializeRepo(ctx context.Context, req *velerov1
rr.Status.Phase = velerov1api.BackupRepositoryPhaseNotReady

if rr.Spec.MaintenanceFrequency.Duration <= 0 {
rr.Spec.MaintenanceFrequency = metav1.Duration{Duration: r.defaultMaintenanceFrequency}
rr.Spec.MaintenanceFrequency = metav1.Duration{Duration: r.getRepositoryMaintenanceFrequency(req)}
}
})
}
Expand All @@ -145,7 +140,7 @@ func (r *ResticRepoReconciler) initializeRepo(ctx context.Context, req *velerov1
rr.Spec.ResticIdentifier = repoIdentifier

if rr.Spec.MaintenanceFrequency.Duration <= 0 {
rr.Spec.MaintenanceFrequency = metav1.Duration{Duration: r.defaultMaintenanceFrequency}
rr.Spec.MaintenanceFrequency = metav1.Duration{Duration: r.getRepositoryMaintenanceFrequency(req)}
}
}); err != nil {
return err
Expand All @@ -161,6 +156,23 @@ func (r *ResticRepoReconciler) initializeRepo(ctx context.Context, req *velerov1
})
}

func (r *ResticRepoReconciler) getRepositoryMaintenanceFrequency(req *velerov1api.BackupRepository) time.Duration {
if r.maintenanceFrequency > 0 {
r.logger.WithField("frequency", r.maintenanceFrequency).Info("Set user defined maintenance frequency")
return r.maintenanceFrequency
} else {
frequency, err := r.repositoryManager.DefaultMaintenanceFrequency(req)
if err != nil || frequency <= 0 {
r.logger.WithError(err).WithField("returned frequency", frequency).Warn("Failed to get maitanance frequency, use the default one")
frequency = defaultMaintainFrequency
} else {
r.logger.WithField("frequency", frequency).Info("Set matainenance according to repository suggestion")
}

return frequency
}
}

// ensureRepo checks to see if a repository exists, and attempts to initialize it if
// it does not exist. An error is returned if the repository can't be connected to
// or initialized.
Expand Down
Loading

0 comments on commit b108b6b

Please sign in to comment.