Update CRDs and CLI to support in-place restore (#10038)

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-27 17:46:52 +08:00
parent 1711094110
commit e030d4c0eb
18 changed files with 207 additions and 39 deletions
+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) {