commit
8cb04d4f69
|
@ -0,0 +1 @@
|
|||
Fix issue #6647, add the --default-snapshot-move-data parameter to Velero install, so that users don't need to specify --snapshot-move-data per backup when they want to move snapshot data for all backups
|
|
@ -79,6 +79,7 @@ type Options struct {
|
|||
Features string
|
||||
DefaultVolumesToFsBackup bool
|
||||
UploaderType string
|
||||
DefaultSnapshotMoveData bool
|
||||
}
|
||||
|
||||
// BindFlags adds command line values to the options struct.
|
||||
|
@ -118,6 +119,7 @@ func (o *Options) BindFlags(flags *pflag.FlagSet) {
|
|||
flags.StringVar(&o.Features, "features", o.Features, "Comma separated list of Velero feature flags to be set on the Velero deployment and the node-agent daemonset, if node-agent is enabled")
|
||||
flags.BoolVar(&o.DefaultVolumesToFsBackup, "default-volumes-to-fs-backup", o.DefaultVolumesToFsBackup, "Bool flag to configure Velero server to use pod volume file system backup by default for all volumes on all backups. Optional.")
|
||||
flags.StringVar(&o.UploaderType, "uploader-type", o.UploaderType, fmt.Sprintf("The type of uploader to transfer the data of pod volumes, the supported values are '%s', '%s'", uploader.ResticType, uploader.KopiaType))
|
||||
flags.BoolVar(&o.DefaultSnapshotMoveData, "default-snapshot-move-data", o.DefaultSnapshotMoveData, "Bool flag to configure Velero server to move data by default for all snapshots supporting data movement. Optional.")
|
||||
}
|
||||
|
||||
// NewInstallOptions instantiates a new, default InstallOptions struct.
|
||||
|
@ -144,6 +146,7 @@ func NewInstallOptions() *Options {
|
|||
CRDsOnly: false,
|
||||
DefaultVolumesToFsBackup: false,
|
||||
UploaderType: uploader.KopiaType,
|
||||
DefaultSnapshotMoveData: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,6 +209,7 @@ func (o *Options) AsVeleroOptions() (*install.VeleroOptions, error) {
|
|||
Features: strings.Split(o.Features, ","),
|
||||
DefaultVolumesToFsBackup: o.DefaultVolumesToFsBackup,
|
||||
UploaderType: o.UploaderType,
|
||||
DefaultSnapshotMoveData: o.DefaultSnapshotMoveData,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -135,6 +135,7 @@ type serverConfig struct {
|
|||
defaultVolumesToFsBackup bool
|
||||
uploaderType string
|
||||
maxConcurrentK8SConnections int
|
||||
defaultSnapshotMoveData bool
|
||||
}
|
||||
|
||||
func NewCommand(f client.Factory) *cobra.Command {
|
||||
|
@ -163,6 +164,7 @@ func NewCommand(f client.Factory) *cobra.Command {
|
|||
defaultVolumesToFsBackup: podvolume.DefaultVolumesToFsBackup,
|
||||
uploaderType: uploader.ResticType,
|
||||
maxConcurrentK8SConnections: defaultMaxConcurrentK8SConnections,
|
||||
defaultSnapshotMoveData: false,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -233,6 +235,7 @@ func NewCommand(f client.Factory) *cobra.Command {
|
|||
command.Flags().DurationVar(&config.defaultItemOperationTimeout, "default-item-operation-timeout", config.defaultItemOperationTimeout, "How long to wait on asynchronous BackupItemActions and RestoreItemActions to complete before timing out. Default is 4 hours")
|
||||
command.Flags().DurationVar(&config.resourceTimeout, "resource-timeout", config.resourceTimeout, "How long to wait for resource processes which are not covered by other specific timeout parameters. Default is 10 minutes.")
|
||||
command.Flags().IntVar(&config.maxConcurrentK8SConnections, "max-concurrent-k8s-connections", config.maxConcurrentK8SConnections, "Max concurrent connections number that Velero can create with kube-apiserver. Default is 30.")
|
||||
command.Flags().BoolVar(&config.defaultSnapshotMoveData, "default-snapshot-move-data", config.defaultSnapshotMoveData, "Move data by default for all snapshots supporting data movement.")
|
||||
|
||||
return command
|
||||
}
|
||||
|
@ -756,6 +759,7 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string
|
|||
s.csiSnapshotClient,
|
||||
s.credentialFileStore,
|
||||
s.config.maxConcurrentK8SConnections,
|
||||
s.config.defaultSnapshotMoveData,
|
||||
).SetupWithManager(s.mgr); err != nil {
|
||||
s.logger.Fatal(err, "unable to create controller", "controller", controller.Backup)
|
||||
}
|
||||
|
|
|
@ -88,6 +88,7 @@ type backupReconciler struct {
|
|||
volumeSnapshotClient snapshotterClientSet.Interface
|
||||
credentialFileStore credentials.FileStore
|
||||
maxConcurrentK8SConnections int
|
||||
defaultSnapshotMoveData bool
|
||||
}
|
||||
|
||||
func NewBackupReconciler(
|
||||
|
@ -113,6 +114,7 @@ func NewBackupReconciler(
|
|||
volumeSnapshotClient snapshotterClientSet.Interface,
|
||||
credentialStore credentials.FileStore,
|
||||
maxConcurrentK8SConnections int,
|
||||
defaultSnapshotMoveData bool,
|
||||
) *backupReconciler {
|
||||
b := &backupReconciler{
|
||||
ctx: ctx,
|
||||
|
@ -138,6 +140,7 @@ func NewBackupReconciler(
|
|||
volumeSnapshotClient: volumeSnapshotClient,
|
||||
credentialFileStore: credentialStore,
|
||||
maxConcurrentK8SConnections: maxConcurrentK8SConnections,
|
||||
defaultSnapshotMoveData: defaultSnapshotMoveData,
|
||||
}
|
||||
b.updateTotalBackupMetric()
|
||||
return b
|
||||
|
@ -353,6 +356,10 @@ func (b *backupReconciler) prepareBackupRequest(backup *velerov1api.Backup, logg
|
|||
request.Spec.DefaultVolumesToFsBackup = &b.defaultVolumesToFsBackup
|
||||
}
|
||||
|
||||
if request.Spec.SnapshotMoveData == nil {
|
||||
request.Spec.SnapshotMoveData = &b.defaultSnapshotMoveData
|
||||
}
|
||||
|
||||
// find which storage location to use
|
||||
var serverSpecified bool
|
||||
if request.Spec.StorageLocation == "" {
|
||||
|
|
|
@ -583,6 +583,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
backup *velerov1api.Backup
|
||||
backupLocation *velerov1api.BackupStorageLocation
|
||||
defaultVolumesToFsBackup bool
|
||||
defaultSnapshotMoveData bool
|
||||
expectedResult *velerov1api.Backup
|
||||
backupExists bool
|
||||
existenceCheckError error
|
||||
|
@ -615,6 +616,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
Spec: velerov1api.BackupSpec{
|
||||
StorageLocation: defaultBackupLocation.Name,
|
||||
DefaultVolumesToFsBackup: boolptr.True(),
|
||||
SnapshotMoveData: boolptr.False(),
|
||||
},
|
||||
Status: velerov1api.BackupStatus{
|
||||
Phase: velerov1api.BackupPhaseFinalizing,
|
||||
|
@ -651,6 +653,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
Spec: velerov1api.BackupSpec{
|
||||
StorageLocation: "alt-loc",
|
||||
DefaultVolumesToFsBackup: boolptr.False(),
|
||||
SnapshotMoveData: boolptr.False(),
|
||||
},
|
||||
Status: velerov1api.BackupStatus{
|
||||
Phase: velerov1api.BackupPhaseFinalizing,
|
||||
|
@ -690,6 +693,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
Spec: velerov1api.BackupSpec{
|
||||
StorageLocation: "read-write",
|
||||
DefaultVolumesToFsBackup: boolptr.True(),
|
||||
SnapshotMoveData: boolptr.False(),
|
||||
},
|
||||
Status: velerov1api.BackupStatus{
|
||||
Phase: velerov1api.BackupPhaseFinalizing,
|
||||
|
@ -727,6 +731,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
TTL: metav1.Duration{Duration: 10 * time.Minute},
|
||||
StorageLocation: defaultBackupLocation.Name,
|
||||
DefaultVolumesToFsBackup: boolptr.False(),
|
||||
SnapshotMoveData: boolptr.False(),
|
||||
},
|
||||
Status: velerov1api.BackupStatus{
|
||||
Phase: velerov1api.BackupPhaseFinalizing,
|
||||
|
@ -764,6 +769,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
Spec: velerov1api.BackupSpec{
|
||||
StorageLocation: defaultBackupLocation.Name,
|
||||
DefaultVolumesToFsBackup: boolptr.True(),
|
||||
SnapshotMoveData: boolptr.False(),
|
||||
},
|
||||
Status: velerov1api.BackupStatus{
|
||||
Phase: velerov1api.BackupPhaseFinalizing,
|
||||
|
@ -802,6 +808,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
Spec: velerov1api.BackupSpec{
|
||||
StorageLocation: defaultBackupLocation.Name,
|
||||
DefaultVolumesToFsBackup: boolptr.False(),
|
||||
SnapshotMoveData: boolptr.False(),
|
||||
},
|
||||
Status: velerov1api.BackupStatus{
|
||||
Phase: velerov1api.BackupPhaseFinalizing,
|
||||
|
@ -840,6 +847,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
Spec: velerov1api.BackupSpec{
|
||||
StorageLocation: defaultBackupLocation.Name,
|
||||
DefaultVolumesToFsBackup: boolptr.True(),
|
||||
SnapshotMoveData: boolptr.False(),
|
||||
},
|
||||
Status: velerov1api.BackupStatus{
|
||||
Phase: velerov1api.BackupPhaseFinalizing,
|
||||
|
@ -878,6 +886,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
Spec: velerov1api.BackupSpec{
|
||||
StorageLocation: defaultBackupLocation.Name,
|
||||
DefaultVolumesToFsBackup: boolptr.True(),
|
||||
SnapshotMoveData: boolptr.False(),
|
||||
},
|
||||
Status: velerov1api.BackupStatus{
|
||||
Phase: velerov1api.BackupPhaseFinalizing,
|
||||
|
@ -916,6 +925,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
Spec: velerov1api.BackupSpec{
|
||||
StorageLocation: defaultBackupLocation.Name,
|
||||
DefaultVolumesToFsBackup: boolptr.False(),
|
||||
SnapshotMoveData: boolptr.False(),
|
||||
},
|
||||
Status: velerov1api.BackupStatus{
|
||||
Phase: velerov1api.BackupPhaseFinalizing,
|
||||
|
@ -955,6 +965,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
Spec: velerov1api.BackupSpec{
|
||||
StorageLocation: defaultBackupLocation.Name,
|
||||
DefaultVolumesToFsBackup: boolptr.True(),
|
||||
SnapshotMoveData: boolptr.False(),
|
||||
},
|
||||
Status: velerov1api.BackupStatus{
|
||||
Phase: velerov1api.BackupPhaseFailed,
|
||||
|
@ -994,6 +1005,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
Spec: velerov1api.BackupSpec{
|
||||
StorageLocation: defaultBackupLocation.Name,
|
||||
DefaultVolumesToFsBackup: boolptr.True(),
|
||||
SnapshotMoveData: boolptr.False(),
|
||||
},
|
||||
Status: velerov1api.BackupStatus{
|
||||
Phase: velerov1api.BackupPhaseFailed,
|
||||
|
@ -1113,6 +1125,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
Spec: velerov1api.BackupSpec{
|
||||
StorageLocation: defaultBackupLocation.Name,
|
||||
DefaultVolumesToFsBackup: boolptr.False(),
|
||||
SnapshotMoveData: boolptr.False(),
|
||||
},
|
||||
Status: velerov1api.BackupStatus{
|
||||
Phase: velerov1api.BackupPhaseFinalizing,
|
||||
|
@ -1126,6 +1139,129 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
},
|
||||
volumeSnapshot: builder.ForVolumeSnapshot("velero", "testVS").ObjectMeta(builder.WithLabels(velerov1api.BackupNameLabel, "backup-1")).Result(),
|
||||
},
|
||||
{
|
||||
name: "backup with snapshot data movement set to true and defaultSnapshotMoveData set to false",
|
||||
backup: defaultBackup().SnapshotMoveData(true).Result(),
|
||||
backupLocation: defaultBackupLocation,
|
||||
defaultVolumesToFsBackup: false,
|
||||
defaultSnapshotMoveData: false,
|
||||
expectedResult: &velerov1api.Backup{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Backup",
|
||||
APIVersion: "velero.io/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: velerov1api.DefaultNamespace,
|
||||
Name: "backup-1",
|
||||
Annotations: map[string]string{
|
||||
"velero.io/source-cluster-k8s-major-version": "1",
|
||||
"velero.io/source-cluster-k8s-minor-version": "16",
|
||||
"velero.io/source-cluster-k8s-gitversion": "v1.16.4",
|
||||
"velero.io/resource-timeout": "0s",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
"velero.io/storage-location": "loc-1",
|
||||
},
|
||||
},
|
||||
Spec: velerov1api.BackupSpec{
|
||||
StorageLocation: defaultBackupLocation.Name,
|
||||
DefaultVolumesToFsBackup: boolptr.False(),
|
||||
SnapshotMoveData: boolptr.True(),
|
||||
},
|
||||
Status: velerov1api.BackupStatus{
|
||||
Phase: velerov1api.BackupPhaseFinalizing,
|
||||
Version: 1,
|
||||
FormatVersion: "1.1.0",
|
||||
StartTimestamp: ×tamp,
|
||||
Expiration: ×tamp,
|
||||
CSIVolumeSnapshotsAttempted: 0,
|
||||
CSIVolumeSnapshotsCompleted: 0,
|
||||
},
|
||||
},
|
||||
volumeSnapshot: builder.ForVolumeSnapshot("velero", "testVS").ObjectMeta(builder.WithLabels(velerov1api.BackupNameLabel, "backup-1")).Result(),
|
||||
},
|
||||
{
|
||||
name: "backup with snapshot data movement set to false and defaultSnapshotMoveData set to true",
|
||||
backup: defaultBackup().SnapshotMoveData(false).Result(),
|
||||
backupLocation: defaultBackupLocation,
|
||||
defaultVolumesToFsBackup: false,
|
||||
defaultSnapshotMoveData: true,
|
||||
expectedResult: &velerov1api.Backup{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Backup",
|
||||
APIVersion: "velero.io/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: velerov1api.DefaultNamespace,
|
||||
Name: "backup-1",
|
||||
Annotations: map[string]string{
|
||||
"velero.io/source-cluster-k8s-major-version": "1",
|
||||
"velero.io/source-cluster-k8s-minor-version": "16",
|
||||
"velero.io/source-cluster-k8s-gitversion": "v1.16.4",
|
||||
"velero.io/resource-timeout": "0s",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
"velero.io/storage-location": "loc-1",
|
||||
},
|
||||
},
|
||||
Spec: velerov1api.BackupSpec{
|
||||
StorageLocation: defaultBackupLocation.Name,
|
||||
DefaultVolumesToFsBackup: boolptr.False(),
|
||||
SnapshotMoveData: boolptr.False(),
|
||||
},
|
||||
Status: velerov1api.BackupStatus{
|
||||
Phase: velerov1api.BackupPhaseFinalizing,
|
||||
Version: 1,
|
||||
FormatVersion: "1.1.0",
|
||||
StartTimestamp: ×tamp,
|
||||
Expiration: ×tamp,
|
||||
CSIVolumeSnapshotsAttempted: 1,
|
||||
CSIVolumeSnapshotsCompleted: 0,
|
||||
},
|
||||
},
|
||||
volumeSnapshot: builder.ForVolumeSnapshot("velero", "testVS").ObjectMeta(builder.WithLabels(velerov1api.BackupNameLabel, "backup-1")).Result(),
|
||||
},
|
||||
{
|
||||
name: "backup with snapshot data movement not set and defaultSnapshotMoveData set to true",
|
||||
backup: defaultBackup().Result(),
|
||||
backupLocation: defaultBackupLocation,
|
||||
defaultVolumesToFsBackup: false,
|
||||
defaultSnapshotMoveData: true,
|
||||
expectedResult: &velerov1api.Backup{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Backup",
|
||||
APIVersion: "velero.io/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: velerov1api.DefaultNamespace,
|
||||
Name: "backup-1",
|
||||
Annotations: map[string]string{
|
||||
"velero.io/source-cluster-k8s-major-version": "1",
|
||||
"velero.io/source-cluster-k8s-minor-version": "16",
|
||||
"velero.io/source-cluster-k8s-gitversion": "v1.16.4",
|
||||
"velero.io/resource-timeout": "0s",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
"velero.io/storage-location": "loc-1",
|
||||
},
|
||||
},
|
||||
Spec: velerov1api.BackupSpec{
|
||||
StorageLocation: defaultBackupLocation.Name,
|
||||
DefaultVolumesToFsBackup: boolptr.False(),
|
||||
SnapshotMoveData: boolptr.True(),
|
||||
},
|
||||
Status: velerov1api.BackupStatus{
|
||||
Phase: velerov1api.BackupPhaseFinalizing,
|
||||
Version: 1,
|
||||
FormatVersion: "1.1.0",
|
||||
StartTimestamp: ×tamp,
|
||||
Expiration: ×tamp,
|
||||
CSIVolumeSnapshotsAttempted: 0,
|
||||
CSIVolumeSnapshotsCompleted: 0,
|
||||
},
|
||||
},
|
||||
volumeSnapshot: builder.ForVolumeSnapshot("velero", "testVS").ObjectMeta(builder.WithLabels(velerov1api.BackupNameLabel, "backup-1")).Result(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
@ -1178,6 +1314,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
kbClient: fakeClient,
|
||||
defaultBackupLocation: defaultBackupLocation.Name,
|
||||
defaultVolumesToFsBackup: test.defaultVolumesToFsBackup,
|
||||
defaultSnapshotMoveData: test.defaultSnapshotMoveData,
|
||||
backupTracker: NewBackupTracker(),
|
||||
metrics: metrics.NewServerMetrics(),
|
||||
clock: testclocks.NewFakeClock(now),
|
||||
|
|
|
@ -46,6 +46,7 @@ type podTemplateConfig struct {
|
|||
defaultVolumesToFsBackup bool
|
||||
serviceAccountName string
|
||||
uploaderType string
|
||||
defaultSnapshotMoveData bool
|
||||
}
|
||||
|
||||
func WithImage(image string) podTemplateOption {
|
||||
|
@ -136,6 +137,12 @@ func WithDefaultVolumesToFsBackup() podTemplateOption {
|
|||
}
|
||||
}
|
||||
|
||||
func WithDefaultSnapshotMoveData() podTemplateOption {
|
||||
return func(c *podTemplateConfig) {
|
||||
c.defaultSnapshotMoveData = true
|
||||
}
|
||||
}
|
||||
|
||||
func WithServiceAccountName(sa string) podTemplateOption {
|
||||
return func(c *podTemplateConfig) {
|
||||
c.serviceAccountName = sa
|
||||
|
@ -167,6 +174,10 @@ func Deployment(namespace string, opts ...podTemplateOption) *appsv1.Deployment
|
|||
args = append(args, "--default-volumes-to-fs-backup=true")
|
||||
}
|
||||
|
||||
if c.defaultSnapshotMoveData {
|
||||
args = append(args, "--default-snapshot-move-data=true")
|
||||
}
|
||||
|
||||
if len(c.uploaderType) > 0 {
|
||||
args = append(args, fmt.Sprintf("--uploader-type=%s", c.uploaderType))
|
||||
}
|
||||
|
|
|
@ -243,6 +243,7 @@ type VeleroOptions struct {
|
|||
Features []string
|
||||
DefaultVolumesToFsBackup bool
|
||||
UploaderType string
|
||||
DefaultSnapshotMoveData bool
|
||||
}
|
||||
|
||||
func AllCRDs() *unstructured.UnstructuredList {
|
||||
|
@ -343,6 +344,10 @@ func AllResources(o *VeleroOptions) *unstructured.UnstructuredList {
|
|||
deployOpts = append(deployOpts, WithDefaultVolumesToFsBackup())
|
||||
}
|
||||
|
||||
if o.DefaultSnapshotMoveData {
|
||||
deployOpts = append(deployOpts, WithDefaultSnapshotMoveData())
|
||||
}
|
||||
|
||||
deploy := Deployment(o.Namespace, deployOpts...)
|
||||
|
||||
if err := appendUnstructured(resources, deploy); err != nil {
|
||||
|
|
Loading…
Reference in New Issue