feat: Implement early frequent polling for CSI snapshots

Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
Signed-off-by: Scott Seago <sseago@redhat.com>
This commit is contained in:
Scott Seago
2026-07-01 11:56:48 -04:00
co-authored by aider
parent fa20e46016
commit c60a5bcc7c
5 changed files with 60 additions and 28 deletions
+14 -10
View File
@@ -81,6 +81,7 @@ type Options struct {
DefaultVolumesToFsBackup bool
UploaderType string
DefaultSnapshotMoveData bool
CSISnapshotEarlyFrequentPolling bool
DisableInformerCache bool
ScheduleSkipImmediately bool
PodResources kubeutil.PodResources
@@ -141,6 +142,7 @@ func (o *Options) BindFlags(flags *pflag.FlagSet) {
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, supported value: '%s'", 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.")
flags.BoolVar(&o.CSISnapshotEarlyFrequentPolling, "csi-snapshot-early-frequent-polling", o.CSISnapshotEarlyFrequentPolling, "Bool flag to configure Velero server to use early frequent polling by default for all CSI snapshots. Optional.")
flags.BoolVar(&o.DisableInformerCache, "disable-informer-cache", o.DisableInformerCache, "Disable informer cache for Get calls on restore. With this enabled, it will speed up restore in cases where there are backup resources which already exist in the cluster, but for very large clusters this will increase velero memory usage. Default is false (don't disable). Optional.")
flags.BoolVar(&o.ScheduleSkipImmediately, "schedule-skip-immediately", o.ScheduleSkipImmediately, "Skip the first scheduled backup immediately after creating a schedule. Default is false (don't skip).")
flags.BoolVar(&o.NodeAgentDisableHostPath, "node-agent-disable-host-path", o.NodeAgentDisableHostPath, "Don't mount the pod volume host path to node-agent. Optional. Pod volume host path mount is required by fs-backup but could be disabled for other backup methods.")
@@ -238,16 +240,17 @@ func NewInstallOptions() *Options {
NodeAgentPodCPULimit: install.DefaultNodeAgentPodCPULimit,
NodeAgentPodMemLimit: install.DefaultNodeAgentPodMemLimit,
// Default to creating a VSL unless we're told otherwise
UseVolumeSnapshots: true,
NoDefaultBackupLocation: false,
CRDsOnly: false,
DefaultVolumesToFsBackup: false,
UploaderType: uploader.KopiaType,
DefaultSnapshotMoveData: false,
DisableInformerCache: false,
ScheduleSkipImmediately: false,
kubeletRootDir: install.DefaultKubeletRootDir,
NodeAgentDisableHostPath: false,
UseVolumeSnapshots: true,
NoDefaultBackupLocation: false,
CRDsOnly: false,
DefaultVolumesToFsBackup: false,
UploaderType: uploader.KopiaType,
DefaultSnapshotMoveData: false,
CSISnapshotEarlyFrequentPolling: false,
DisableInformerCache: false,
ScheduleSkipImmediately: false,
kubeletRootDir: install.DefaultKubeletRootDir,
NodeAgentDisableHostPath: false,
}
}
@@ -324,6 +327,7 @@ func (o *Options) AsVeleroOptions() (*install.VeleroOptions, error) {
DefaultVolumesToFsBackup: o.DefaultVolumesToFsBackup,
UploaderType: o.UploaderType,
DefaultSnapshotMoveData: o.DefaultSnapshotMoveData,
CSISnapshotEarlyFrequentPolling: o.CSISnapshotEarlyFrequentPolling,
DisableInformerCache: o.DisableInformerCache,
ScheduleSkipImmediately: o.ScheduleSkipImmediately,
PodResources: o.PodResources,
+16
View File
@@ -50,6 +50,7 @@ type podTemplateConfig struct {
serviceAccountName string
uploaderType string
defaultSnapshotMoveData bool
csiSnapshotEarlyFrequentPolling bool
privilegedNodeAgent bool
disableInformerCache bool
scheduleSkipImmediately bool
@@ -166,6 +167,12 @@ func WithDefaultSnapshotMoveData(b bool) podTemplateOption {
}
}
func WithCSISnapshotEarlyFrequentPolling(b bool) podTemplateOption {
return func(c *podTemplateConfig) {
c.csiSnapshotEarlyFrequentPolling = b
}
}
func WithDisableInformerCache(b bool) podTemplateOption {
return func(c *podTemplateConfig) {
c.disableInformerCache = b
@@ -489,6 +496,15 @@ func Deployment(namespace string, opts ...podTemplateOption) *appsv1api.Deployme
}...)
}
if c.csiSnapshotEarlyFrequentPolling {
deployment.Spec.Template.Spec.Containers[0].Env = append(deployment.Spec.Template.Spec.Containers[0].Env, []corev1api.EnvVar{
{
Name: "CSI_SNAPSHOT_EARLY_FREQUENT_POLLING",
Value: "true",
},
}...)
}
deployment.Spec.Template.Spec.Containers[0].Env = append(deployment.Spec.Template.Spec.Containers[0].Env, c.envVars...)
if len(c.plugins) > 0 {
+5
View File
@@ -263,6 +263,7 @@ type VeleroOptions struct {
DefaultVolumesToFsBackup bool
UploaderType string
DefaultSnapshotMoveData bool
CSISnapshotEarlyFrequentPolling bool
DisableInformerCache bool
ScheduleSkipImmediately bool
PodResources kube.PodResources
@@ -390,6 +391,10 @@ func AllResources(o *VeleroOptions) *unstructured.UnstructuredList {
deployOpts = append(deployOpts, WithDefaultSnapshotMoveData(true))
}
if o.CSISnapshotEarlyFrequentPolling {
deployOpts = append(deployOpts, WithCSISnapshotEarlyFrequentPolling(true))
}
if o.DisableInformerCache {
deployOpts = append(deployOpts, WithDisableInformerCache(true))
}
+25 -18
View File
@@ -20,6 +20,8 @@ import (
"context"
"encoding/json"
"fmt"
"os"
"strconv"
"strings"
"time"
@@ -660,25 +662,30 @@ func WaitUntilVSCHandleIsReady(
return true, nil
}
// The short interval for the first ten seconds is due to the fact that
// Microsoft VSS backups have a hard-coded unfreeze call after 10 seconds,
// so we need to minimize waiting time during the first 10 seconds.
// First poll with a short interval and timeout.
interval = 1 * time.Second
timeout := 10 * time.Second
err := wait.PollUntilContextTimeout(
context.Background(),
interval,
timeout,
true,
pollFunc,
)
var err error
frequentPolling, err := strconv.ParseBool(os.Getenv("CSI_SNAPSHOT_EARLY_FREQUENT_POLLING"))
if err == nil {
return vsc, nil
}
if !wait.Interrupted(err) {
return nil, err
if err == nil && frequentPolling {
// The short interval for the first ten seconds is due to the fact that
// Microsoft VSS backups have a hard-coded unfreeze call after 10 seconds,
// so we need to minimize waiting time during the first 10 seconds.
// First poll with a short interval and timeout.
interval = 1 * time.Second
timeout := 10 * time.Second
err = wait.PollUntilContextTimeout(
context.Background(),
interval,
timeout,
true,
pollFunc,
)
if err == nil {
return vsc, nil
}
if !wait.Interrupted(err) {
return nil, err
}
}
// If the first poll timed out, poll with a longer interval and the full timeout.