Update CRDs and CLI to support in-place restore (#10038)
Run the E2E test on kind / get-go-version (push) Failing after 1m12s
Run the E2E test on kind / build (push) Has been skipped
Run the E2E test on kind / setup-test-matrix (push) Successful in 3s
Run the E2E test on kind / run-e2e-test (push) Has been skipped

Update CRDs(Restore, DataDownload, PodVolumeRestore) and restore create CLI to support in-place restore

Signed-off-by: Wenkai Yin(尹文开) <yinw@vmware.com>
This commit is contained in:
Wenkai Yin(尹文开)
2026-07-23 14:57:10 +08:00
committed by GitHub
parent d69f6abe5c
commit 5f101a4bea
18 changed files with 207 additions and 39 deletions
@@ -132,6 +132,9 @@ spec:
repoIdentifier:
description: RepoIdentifier is the backup repository identifier.
type: string
restoreType:
description: RestoreType indicates the type of the restore.
type: string
snapshotID:
description: SnapshotID is the ID of the volume snapshot to be restored.
type: string
@@ -167,6 +170,7 @@ spec:
- backupStorageLocation
- pod
- repoIdentifier
- restoreType
- snapshotID
- sourceNamespace
- volume
@@ -69,6 +69,11 @@ spec:
for the Kubernetes resource to be restored
nullable: true
type: string
existingVolumeDataPolicy:
description: ExistingVolumeDataPolicy specifies the restore behavior
for the volume data to be restored
nullable: true
type: string
hooks:
description: Hooks represent custom behaviors that should be executed
during or post restore.
@@ -471,6 +476,12 @@ spec:
description: UploaderConfig specifies the configuration for the restore.
nullable: true
properties:
deleteExtraFiles:
description: |-
DeleteExtraFiles specifies whether to delete the extra files in the target volume that do not exist in the backup.
This setting is only applicable to File System restores (PodVolumeBackup or CSI File System Data Move) and has no effect on Block Data Move restores.
nullable: true
type: boolean
parallelFilesDownload:
description: ParallelFilesDownload is the concurrency number setting
for restore.
File diff suppressed because one or more lines are too long
@@ -83,6 +83,30 @@ spec:
Cancel indicates request to cancel the ongoing DataDownload. It can be set
when the DataDownload is in InProgress phase
type: boolean
csiSnapshot:
description: CSISnapshot provides the information of the CSI snapshot
used to do the incremental restore.
nullable: true
properties:
driver:
description: Driver is the driver used by the VolumeSnapshotContent
type: string
snapshotClass:
description: SnapshotClass is the name of the snapshot class that
the volume snapshot is created with
type: string
storageClass:
description: StorageClass is the name of the storage class of
the PVC that the volume snapshot is created from
type: string
volumeSnapshot:
description: VolumeSnapshot is the name of the volume snapshot
to be backed up
type: string
required:
- storageClass
- volumeSnapshot
type: object
dataMoverConfig:
additionalProperties:
type: string
@@ -106,6 +130,9 @@ spec:
OperationTimeout specifies the time used to wait internal operations,
before returning error as timeout.
type: string
restoreType:
description: RestoreType indicates the type of the restore.
type: string
snapshotID:
description: SnapshotID is the ID of the Velero backup snapshot to
be restored from.
@@ -145,6 +172,7 @@ spec:
required:
- backupStorageLocation
- operationTimeout
- restoreType
- snapshotID
- sourceNamespace
- targetVolume
File diff suppressed because one or more lines are too long
@@ -46,6 +46,9 @@ type PodVolumeRestoreSpec struct {
// SnapshotID is the ID of the volume snapshot to be restored.
SnapshotID string `json:"snapshotID"`
// RestoreType indicates the type of the restore.
RestoreType string `json:"restoreType"`
// SourceNamespace is the original namespace for namaspace mapping.
SourceNamespace string `json:"sourceNamespace"`
+33 -7
View File
@@ -113,7 +113,12 @@ type RestoreSpec struct {
// ExistingResourcePolicy specifies the restore behavior for the Kubernetes resource to be restored
// +optional
// +nullable
ExistingResourcePolicy PolicyType `json:"existingResourcePolicy,omitempty"`
ExistingResourcePolicy ResourcePolicyType `json:"existingResourcePolicy,omitempty"`
// ExistingVolumeDataPolicy specifies the restore behavior for the volume data to be restored
// +optional
// +nullable
ExistingVolumeDataPolicy VolumeDataPolicyType `json:"existingVolumeDataPolicy,omitempty"`
// ItemOperationTimeout specifies the time used to wait for RestoreItemAction operations
// The default value is 4 hour.
@@ -141,6 +146,10 @@ type RestoreSpec struct {
UploaderConfig *UploaderConfigForRestore `json:"uploaderConfig,omitempty"`
}
func (r *RestoreSpec) IsVolumeDataInplaceRestore() bool {
return r.ExistingVolumeDataPolicy == VolumeDataPolicyTypeFull || r.ExistingVolumeDataPolicy == VolumeDataPolicyTypeIncremental
}
// UploaderConfigForRestore defines the configuration for the restore.
type UploaderConfigForRestore struct {
// WriteSparseFiles is a flag to indicate whether write files sparsely or not.
@@ -150,6 +159,11 @@ type UploaderConfigForRestore struct {
// ParallelFilesDownload is the concurrency number setting for restore.
// +optional
ParallelFilesDownload int `json:"parallelFilesDownload,omitempty"`
// DeleteExtraFiles specifies whether to delete the extra files in the target volume that do not exist in the backup.
// This setting is only applicable to File System restores (PodVolumeBackup or CSI File System Data Move) and has no effect on Block Data Move restores.
// +optional
// +nullable
DeleteExtraFiles *bool `json:"deleteExtraFiles,omitempty"`
}
// RestoreHooks contains custom behaviors that should be executed during or post restore.
@@ -316,13 +330,22 @@ const (
// The failing error is recorded in status.FailureReason.
RestorePhaseFailed RestorePhase = "Failed"
// PolicyTypeNone means velero will not overwrite the resource
// ResourcePolicyTypeNone means velero will not overwrite the resource
// in cluster with the one in backup whether changed/unchanged.
PolicyTypeNone PolicyType = "none"
ResourcePolicyTypeNone ResourcePolicyType = "none"
// PolicyTypeUpdate means velero will try to attempt a patch on
// ResourcePolicyTypeUpdate means velero will try to attempt a patch on
// the changed resources.
PolicyTypeUpdate PolicyType = "update"
ResourcePolicyTypeUpdate ResourcePolicyType = "update"
// VolumeDataPolicyTypeNone means velero will skip and not overwrite the volume data if the volume already exists
VolumeDataPolicyTypeNone VolumeDataPolicyType = "none"
// VolumeDataPolicyTypeFull means velero will try to restore the volume data fully if the volume already exists.
VolumeDataPolicyTypeFull VolumeDataPolicyType = "full"
// VolumeDataPolicyTypeIncremental means velero will try to restore the volume data incrementally if the volume already exists.
VolumeDataPolicyTypeIncremental VolumeDataPolicyType = "incremental"
)
// RestoreStatus captures the current status of a Velero restore
@@ -440,5 +463,8 @@ type RestoreList struct {
Items []Restore `json:"items"`
}
// PolicyType helps specify the ExistingResourcePolicy
type PolicyType string
// ResourcePolicyType helps specify the ExistingResourcePolicy
type ResourcePolicyType string
// VolumeDataPolicyType helps specify the ExistingVolumeDataPolicy
type VolumeDataPolicyType string
@@ -1754,6 +1754,11 @@ func (in *UploaderConfigForRestore) DeepCopyInto(out *UploaderConfigForRestore)
*out = new(bool)
**out = **in
}
if in.DeleteExtraFiles != nil {
in, out := &in.DeleteExtraFiles, &out.DeleteExtraFiles
*out = new(bool)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UploaderConfigForRestore.
@@ -39,6 +39,14 @@ type DataDownloadSpec struct {
// SnapshotID is the ID of the Velero backup snapshot to be restored from.
SnapshotID string `json:"snapshotID"`
// RestoreType indicates the type of the restore.
RestoreType string `json:"restoreType"`
// CSISnapshot provides the information of the CSI snapshot used to do the incremental restore.
// +optional
// +nullable
CSISnapshot *CSISnapshotSpec `json:"csiSnapshot"`
// SourceNamespace is the original namespace where the volume is backed up from.
// It may be different from SourcePVC's namespace if namespace is remapped during restore.
SourceNamespace string `json:"sourceNamespace"`
@@ -86,6 +86,11 @@ func (in *DataDownloadList) DeepCopyObject() runtime.Object {
func (in *DataDownloadSpec) DeepCopyInto(out *DataDownloadSpec) {
*out = *in
out.TargetVolume = in.TargetVolume
if in.CSISnapshot != nil {
in, out := &in.CSISnapshot, &out.CSISnapshot
*out = new(CSISnapshotSpec)
**out = **in
}
if in.DataMoverConfig != nil {
in, out := &in.DataMoverConfig, &out.DataMoverConfig
*out = make(map[string]string, len(*in))
+7 -1
View File
@@ -98,7 +98,13 @@ func (b *RestoreBuilder) ExcludedResources(resources ...string) *RestoreBuilder
// ExistingResourcePolicy sets the Restore's resource policy.
func (b *RestoreBuilder) ExistingResourcePolicy(policy string) *RestoreBuilder {
b.object.Spec.ExistingResourcePolicy = velerov1api.PolicyType(policy)
b.object.Spec.ExistingResourcePolicy = velerov1api.ResourcePolicyType(policy)
return b
}
// ExistingVolumeDataPolicy sets the Restore's volume data policy.
func (b *RestoreBuilder) ExistingVolumeDataPolicy(policy string) *RestoreBuilder {
b.object.Spec.ExistingVolumeDataPolicy = velerov1api.VolumeDataPolicyType(policy)
return b
}
+29 -16
View File
@@ -95,6 +95,7 @@ type CreateOptions struct {
IncludeNamespaces flag.StringArray
ExcludeNamespaces flag.StringArray
ExistingResourcePolicy string
ExistingVolumeDataPolicy string
IncludeResources flag.StringArray
ExcludeResources flag.StringArray
StatusIncludeResources flag.StringArray
@@ -110,6 +111,7 @@ type CreateOptions struct {
ResourcePoliciesConfigMap string
WriteSparseFiles flag.OptionalBool
ParallelFilesDownload int
DeleteExtraFiles flag.OptionalBool
client kbclient.WithWatch
}
@@ -123,6 +125,7 @@ func NewCreateOptions() *CreateOptions {
PreserveNodePorts: flag.NewOptionalBool(nil),
IncludeClusterResources: flag.NewOptionalBool(nil),
WriteSparseFiles: flag.NewOptionalBool(nil),
DeleteExtraFiles: flag.NewOptionalBool(nil),
}
}
@@ -136,7 +139,8 @@ func (o *CreateOptions) BindFlags(flags *pflag.FlagSet) {
flags.Var(&o.Annotations, "annotations", "Annotations to apply to the restore.")
flags.Var(&o.IncludeResources, "include-resources", "Resources to include in the restore, formatted as resource.group, such as storageclasses.storage.k8s.io (use '*' for all resources).")
flags.Var(&o.ExcludeResources, "exclude-resources", "Resources to exclude from the restore, formatted as resource.group, such as storageclasses.storage.k8s.io.")
flags.StringVar(&o.ExistingResourcePolicy, "existing-resource-policy", "", "Restore Policy to be used during the restore workflow, can be - none or update")
flags.StringVar(&o.ExistingResourcePolicy, "existing-resource-policy", "", "Restore Policy to be used during the restore workflow for Kubernetes resources, can be - none or update")
flags.StringVar(&o.ExistingVolumeDataPolicy, "existing-volume-data-policy", "", "Restore Policy to be used during the restore workflow for volume data, can be - none, full or incremental")
flags.Var(&o.StatusIncludeResources, "status-include-resources", "Resources to include in the restore status, formatted as resource.group, such as storageclasses.storage.k8s.io.")
flags.Var(&o.StatusExcludeResources, "status-exclude-resources", "Resources to exclude from the restore status, formatted as resource.group, such as storageclasses.storage.k8s.io.")
flags.VarP(&o.Selector, "selector", "l", "Only restore resources matching this label selector.")
@@ -168,6 +172,9 @@ func (o *CreateOptions) BindFlags(flags *pflag.FlagSet) {
f.NoOptDefVal = cmd.TRUE
flags.IntVar(&o.ParallelFilesDownload, "parallel-files-download", 0, "The number of restore operations to run in parallel. If set to 0, the default parallelism will be the number of CPUs for the node that node agent pod is running.")
f = flags.VarPF(&o.DeleteExtraFiles, "delete-extra-files", "", "Whether to delete extra files in the target volume that do not exist in the backup during file system restore. This setting is only applicable to File System restores (PodVolumeBackup or CSI File System Data Move) and has no effect on Block Data Move restores.")
f.NoOptDefVal = cmd.TRUE
}
func (o *CreateOptions) Complete(args []string, f client.Factory) error {
@@ -217,6 +224,10 @@ func (o *CreateOptions) Validate(c *cobra.Command, args []string, f client.Facto
return errors.New("existing-resource-policy has invalid value, it accepts only none, update as value")
}
if len(o.ExistingVolumeDataPolicy) > 0 && !restore.IsVolumeDataPolicyValid(o.ExistingVolumeDataPolicy) {
return errors.New("existing-volume-data-policy has invalid value, it accepts only none, full, incremental as value")
}
if o.ParallelFilesDownload < 0 {
return errors.New("parallel-files-download cannot be negative")
}
@@ -337,27 +348,29 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error {
Annotations: o.Annotations.Data(),
},
Spec: api.RestoreSpec{
BackupName: o.BackupName,
ScheduleName: o.ScheduleName,
IncludedNamespaces: o.IncludeNamespaces,
ExcludedNamespaces: o.ExcludeNamespaces,
IncludedResources: o.IncludeResources,
ExcludedResources: o.ExcludeResources,
ExistingResourcePolicy: api.PolicyType(o.ExistingResourcePolicy),
NamespaceMapping: o.NamespaceMappings.Data(),
LabelSelector: o.Selector.LabelSelector,
OrLabelSelectors: o.OrSelector.OrLabelSelectors,
RestorePVs: o.RestoreVolumes.Value,
PreserveNodePorts: o.PreserveNodePorts.Value,
IncludeClusterResources: o.IncludeClusterResources.Value,
ResourceModifier: resModifiers,
ResourcePolicy: resPolicies,
BackupName: o.BackupName,
ScheduleName: o.ScheduleName,
IncludedNamespaces: o.IncludeNamespaces,
ExcludedNamespaces: o.ExcludeNamespaces,
IncludedResources: o.IncludeResources,
ExcludedResources: o.ExcludeResources,
ExistingResourcePolicy: api.ResourcePolicyType(o.ExistingResourcePolicy),
ExistingVolumeDataPolicy: api.VolumeDataPolicyType(o.ExistingVolumeDataPolicy),
NamespaceMapping: o.NamespaceMappings.Data(),
LabelSelector: o.Selector.LabelSelector,
OrLabelSelectors: o.OrSelector.OrLabelSelectors,
RestorePVs: o.RestoreVolumes.Value,
PreserveNodePorts: o.PreserveNodePorts.Value,
IncludeClusterResources: o.IncludeClusterResources.Value,
ResourceModifier: resModifiers,
ResourcePolicy: resPolicies,
ItemOperationTimeout: metav1.Duration{
Duration: o.ItemOperationTimeout,
},
UploaderConfig: &api.UploaderConfigForRestore{
WriteSparseFiles: o.WriteSparseFiles.Value,
ParallelFilesDownload: o.ParallelFilesDownload,
DeleteExtraFiles: o.DeleteExtraFiles.Value,
},
},
}
+6
View File
@@ -68,6 +68,7 @@ func TestCreateCommand(t *testing.T) {
includeNamespaces := "app1,app2"
excludeNamespaces := "pod1,pod2,pod3"
existingResourcePolicy := "none"
existingVolumeDataPolicy := "none"
includeResources := "sc,sts"
excludeResources := "job"
statusIncludeResources := "sc,sts"
@@ -80,6 +81,7 @@ func TestCreateCommand(t *testing.T) {
resourceModifierConfigMap := "modifier-cm"
ResourcePoliciesConfigMap := "policies-cm"
writeSparseFiles := "true"
deleteExtraFiles := "true"
parallel := 2
flags := new(pflag.FlagSet)
o := NewCreateOptions()
@@ -92,6 +94,7 @@ func TestCreateCommand(t *testing.T) {
flags.Parse([]string{"--labels", labels})
flags.Parse([]string{"--annotations", annotations})
flags.Parse([]string{"--existing-resource-policy", existingResourcePolicy})
flags.Parse([]string{"--existing-volume-data-policy", existingVolumeDataPolicy})
flags.Parse([]string{"--include-namespaces", includeNamespaces})
flags.Parse([]string{"--exclude-namespaces", excludeNamespaces})
flags.Parse([]string{"--include-resources", includeResources})
@@ -106,6 +109,7 @@ func TestCreateCommand(t *testing.T) {
flags.Parse([]string{"--resource-modifier-configmap", resourceModifierConfigMap})
flags.Parse([]string{"--resource-policies-configmap", ResourcePoliciesConfigMap})
flags.Parse([]string{"--write-sparse-files", writeSparseFiles})
flags.Parse([]string{"--delete-extra-files", deleteExtraFiles})
flags.Parse([]string{"--parallel-files-download", "2"})
client := velerotest.NewFakeControllerRuntimeClient(t).(kbclient.WithWatch)
@@ -133,6 +137,7 @@ func TestCreateCommand(t *testing.T) {
require.Equal(t, includeNamespaces, o.IncludeNamespaces.String())
require.Equal(t, excludeNamespaces, o.ExcludeNamespaces.String())
require.Equal(t, existingResourcePolicy, o.ExistingResourcePolicy)
require.Equal(t, existingVolumeDataPolicy, o.ExistingVolumeDataPolicy)
require.Equal(t, includeResources, o.IncludeResources.String())
require.Equal(t, excludeResources, o.ExcludeResources.String())
@@ -147,6 +152,7 @@ func TestCreateCommand(t *testing.T) {
require.Equal(t, ResourcePoliciesConfigMap, o.ResourcePoliciesConfigMap)
require.Equal(t, writeSparseFiles, o.WriteSparseFiles.String())
require.Equal(t, parallel, o.ParallelFilesDownload)
require.Equal(t, deleteExtraFiles, o.DeleteExtraFiles.String())
})
t.Run("create a restore from schedule", func(t *testing.T) {
+6 -1
View File
@@ -361,10 +361,15 @@ func (r *restoreReconciler) validateAndComplete(ctx context.Context, restore *ap
}
// validate ExistingResourcePolicy
if restore.Spec.ExistingResourcePolicy != "" && !pkgrestoreUtil.IsResourcePolicyValid(string(restore.Spec.ExistingResourcePolicy)) {
if !pkgrestoreUtil.IsResourcePolicyValid(string(restore.Spec.ExistingResourcePolicy)) {
restore.Status.ValidationErrors = append(restore.Status.ValidationErrors, fmt.Sprintf("Invalid ExistingResourcePolicy: %s", restore.Spec.ExistingResourcePolicy))
}
// validate ExistingVolumeDataPolicy
if !pkgrestoreUtil.IsVolumeDataPolicyValid(string(restore.Spec.ExistingVolumeDataPolicy)) {
restore.Status.ValidationErrors = append(restore.Status.ValidationErrors, fmt.Sprintf("Invalid ExistingVolumeDataPolicy: %s", restore.Spec.ExistingVolumeDataPolicy))
}
// if ScheduleName is specified, fill in BackupName with the most recent successful backup from
// the schedule
if restore.Spec.ScheduleName != "" {
+33
View File
@@ -348,6 +348,39 @@ func TestRestoreReconcile(t *testing.T) {
expectedCompletedTime: &timestamp,
expectedRestorerCall: nil, // this restore should fail validation and not be passed to the restorer
},
{
name: "valid restore with update existingvolumedatapolicy(full) gets executed",
location: defaultStorageLocation,
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "", velerov1api.RestorePhaseNew).ExistingVolumeDataPolicy("full").Result(),
backup: defaultBackup().StorageLocation("default").Phase(velerov1api.BackupPhaseCompleted).Result(),
expectedErr: false,
expectedPhase: string(velerov1api.RestorePhaseInProgress),
expectedStartTime: &timestamp,
expectedCompletedTime: &timestamp,
expectedRestorerCall: NewRestore("foo", "bar", "backup-1", "ns-1", "", velerov1api.RestorePhaseInProgress).ExistingVolumeDataPolicy("full").Result(),
},
{
name: "valid restore with update existingvolumedatapolicy(incremental) gets executed",
location: defaultStorageLocation,
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "", velerov1api.RestorePhaseNew).ExistingVolumeDataPolicy("incremental").Result(),
backup: defaultBackup().StorageLocation("default").Phase(velerov1api.BackupPhaseCompleted).Result(),
expectedErr: false,
expectedPhase: string(velerov1api.RestorePhaseInProgress),
expectedStartTime: &timestamp,
expectedCompletedTime: &timestamp,
expectedRestorerCall: NewRestore("foo", "bar", "backup-1", "ns-1", "", velerov1api.RestorePhaseInProgress).ExistingVolumeDataPolicy("incremental").Result(),
},
{
name: "invalid restore with invalid existingvolumedatapolicy errors",
location: defaultStorageLocation,
restore: NewRestore("foo", "invalidexistingvolumedatapolicy", "backup-1", "ns-1", "", velerov1api.RestorePhaseNew).ExistingVolumeDataPolicy("invalid").Result(),
backup: defaultBackup().StorageLocation("default").Result(),
expectedErr: false,
expectedPhase: string(velerov1api.RestorePhaseFailedValidation),
expectedStartTime: &timestamp,
expectedCompletedTime: &timestamp,
expectedRestorerCall: nil, // this restore should fail validation and not be passed to the restorer
},
{
name: "valid restore gets executed",
location: defaultStorageLocation,
+4 -4
View File
@@ -1890,7 +1890,7 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso
if err != nil {
warnings.Add(namespace, err)
// check if there is existingResourcePolicy and if it is set to update policy
if len(ctx.restore.Spec.ExistingResourcePolicy) > 0 && ctx.restore.Spec.ExistingResourcePolicy == velerov1api.PolicyTypeUpdate {
if len(ctx.restore.Spec.ExistingResourcePolicy) > 0 && ctx.restore.Spec.ExistingResourcePolicy == velerov1api.ResourcePolicyTypeUpdate {
// remove restore labels so that we apply the latest backup/restore names on the object via patch
removeRestoreLabels(fromCluster)
//try patching just the backup/restore labels
@@ -1910,12 +1910,12 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso
restoreLogger.Infof("restore API has resource policy defined %s, executing restore workflow accordingly for changed resource %s %s", resourcePolicy, fromCluster.GroupVersionKind().Kind, kube.NamespaceAndName(fromCluster))
// existingResourcePolicy is set as none, add warning
if resourcePolicy == velerov1api.PolicyTypeNone {
if resourcePolicy == velerov1api.ResourcePolicyTypeNone {
e := errors.Errorf("could not restore, %s %q already exists. Warning: the in-cluster version is different than the backed-up version",
obj.GetKind(), obj.GetName())
warnings.Add(namespace, e)
// existingResourcePolicy is set as update, attempt patch on the resource and add warning if it fails
} else if resourcePolicy == velerov1api.PolicyTypeUpdate {
} else if resourcePolicy == velerov1api.ResourcePolicyTypeUpdate {
// processing update as existingResourcePolicy
warningsFromUpdateRP, errsFromUpdateRP := ctx.processUpdateResourcePolicy(fromCluster, fromClusterWithLabels, obj, namespace, resourceClient)
if warningsFromUpdateRP.IsEmpty() && errsFromUpdateRP.IsEmpty() {
@@ -1936,7 +1936,7 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso
}
//update backup/restore labels on the unchanged resources if existingResourcePolicy is set as update
if ctx.restore.Spec.ExistingResourcePolicy == velerov1api.PolicyTypeUpdate {
if ctx.restore.Spec.ExistingResourcePolicy == velerov1api.ResourcePolicyTypeUpdate {
resourcePolicy := ctx.restore.Spec.ExistingResourcePolicy
restoreLogger.Infof("restore API has resource policy defined %s, executing restore workflow accordingly for unchanged resource %s %s ", resourcePolicy, obj.GroupVersionKind().Kind, kube.NamespaceAndName(fromCluster))
// remove restore labels so that we apply the latest backup/restore names on the object via patch
+10 -4
View File
@@ -5,8 +5,14 @@ import (
)
func IsResourcePolicyValid(resourcePolicy string) bool {
if resourcePolicy == string(api.PolicyTypeNone) || resourcePolicy == string(api.PolicyTypeUpdate) {
return true
}
return false
return resourcePolicy == "" ||
resourcePolicy == string(api.ResourcePolicyTypeNone) ||
resourcePolicy == string(api.ResourcePolicyTypeUpdate)
}
func IsVolumeDataPolicyValid(volumeDataPolicy string) bool {
return volumeDataPolicy == "" ||
volumeDataPolicy == string(api.VolumeDataPolicyTypeNone) ||
volumeDataPolicy == string(api.VolumeDataPolicyTypeFull) ||
volumeDataPolicy == string(api.VolumeDataPolicyTypeIncremental)
}
+12 -3
View File
@@ -9,7 +9,16 @@ import (
)
func TestIsResourcePolicyValid(t *testing.T) {
require.True(t, IsResourcePolicyValid(string(velerov1api.PolicyTypeNone)))
require.True(t, IsResourcePolicyValid(string(velerov1api.PolicyTypeUpdate)))
require.False(t, IsResourcePolicyValid(""))
require.True(t, IsResourcePolicyValid(string(velerov1api.ResourcePolicyTypeNone)))
require.True(t, IsResourcePolicyValid(string(velerov1api.ResourcePolicyTypeUpdate)))
require.True(t, IsResourcePolicyValid(""))
require.False(t, IsResourcePolicyValid("invalid"))
}
func TestIsVolumeDataPolicyValid(t *testing.T) {
require.True(t, IsVolumeDataPolicyValid(string(velerov1api.VolumeDataPolicyTypeNone)))
require.True(t, IsVolumeDataPolicyValid(string(velerov1api.VolumeDataPolicyTypeFull)))
require.True(t, IsVolumeDataPolicyValid(string(velerov1api.VolumeDataPolicyTypeIncremental)))
require.True(t, IsVolumeDataPolicyValid(""))
require.False(t, IsVolumeDataPolicyValid("invalid"))
}