mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-08-01 04:46:05 +00:00
Merge branch 'main' into add-e2e-tests-for-PR9452
This commit is contained in:
@@ -0,0 +1 @@
|
||||
If BIA return updateObj with SkipFromBackupAnnotation, treat it as skip the resource from backup.
|
||||
@@ -0,0 +1 @@
|
||||
Add schedule_expected_interval_seconds metric for dynamic backup alerting thresholds (#9559)
|
||||
@@ -102,6 +102,15 @@ const (
|
||||
// even if the resource contains a matching selector label.
|
||||
ExcludeFromBackupLabel = "velero.io/exclude-from-backup"
|
||||
|
||||
// SkipFromBackupAnnotation is the annotation used by internal BackupItemActions
|
||||
// to indicate that a resource should be skipped from backup,
|
||||
// even if it doesn't have the ExcludeFromBackupLabel.
|
||||
// This is used in cases where we want to skip backup of a resource based on some logic in a plugin.
|
||||
//
|
||||
// Notice: SkipFromBackupAnnotation's priority is higher than MustIncludeAdditionalItemAnnotation.
|
||||
// If SkipFromBackupAnnotation is set, the resource will be skipped even if MustIncludeAdditionalItemAnnotation is set.
|
||||
SkipFromBackupAnnotation = "velero.io/skip-from-backup"
|
||||
|
||||
// defaultVGSLabelKey is the default label key used to group PVCs under a VolumeGroupSnapshot
|
||||
DefaultVGSLabelKey = "velero.io/volume-group"
|
||||
|
||||
|
||||
@@ -98,6 +98,14 @@ func (m *backedUpItemsMap) AddItem(key itemKey) {
|
||||
m.totalItems[key] = struct{}{}
|
||||
}
|
||||
|
||||
func (m *backedUpItemsMap) DeleteItem(key itemKey) {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
delete(m.backedUpItems, key)
|
||||
delete(m.totalItems, key)
|
||||
}
|
||||
|
||||
func (m *backedUpItemsMap) AddItemToTotal(key itemKey) {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
@@ -244,6 +244,14 @@ func (ib *itemBackupper) backupItemInternal(logger logrus.FieldLogger, obj runti
|
||||
return false, itemFiles, kubeerrs.NewAggregate(backupErrs)
|
||||
}
|
||||
|
||||
// If err is nil and updatedObj is nil, it means the item is skipped by plugin action,
|
||||
// we should return here to avoid backing up the item, and avoid potential NPE in the following code.
|
||||
if updatedObj == nil {
|
||||
log.Infof("Remove item from the backup's backupItems list and totalItems list because it's skipped by plugin action.")
|
||||
ib.backupRequest.BackedUpItems.DeleteItem(key)
|
||||
return false, itemFiles, nil
|
||||
}
|
||||
|
||||
itemFiles = append(itemFiles, additionalItemFiles...)
|
||||
obj = updatedObj
|
||||
if metadata, err = meta.Accessor(obj); err != nil {
|
||||
@@ -398,6 +406,13 @@ func (ib *itemBackupper) executeActions(
|
||||
}
|
||||
|
||||
u := &unstructured.Unstructured{Object: updatedItem.UnstructuredContent()}
|
||||
|
||||
if _, ok := u.GetAnnotations()[velerov1api.SkipFromBackupAnnotation]; ok {
|
||||
log.Infof("Resource (groupResource=%s, namespace=%s, name=%s) is skipped from backup by action %s.",
|
||||
groupResource.String(), namespace, name, actionName)
|
||||
return nil, itemFiles, nil
|
||||
}
|
||||
|
||||
if actionName == csiBIAPluginName {
|
||||
if additionalItemIdentifiers == nil && u.GetAnnotations()[velerov1api.SkippedNoCSIPVAnnotation] == "true" {
|
||||
// snapshot was skipped by CSI plugin
|
||||
|
||||
@@ -129,6 +129,13 @@ func (c *scheduleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
|
||||
} else {
|
||||
schedule.Status.Phase = velerov1.SchedulePhaseEnabled
|
||||
schedule.Status.ValidationErrors = nil
|
||||
|
||||
// Compute expected interval between consecutive scheduled backup runs.
|
||||
// Only meaningful when the cron expression is valid.
|
||||
now := c.clock.Now()
|
||||
nextRun := cronSchedule.Next(now)
|
||||
nextNextRun := cronSchedule.Next(nextRun)
|
||||
c.metrics.SetScheduleExpectedIntervalSeconds(schedule.Name, nextNextRun.Sub(nextRun).Seconds())
|
||||
}
|
||||
|
||||
scheduleNeedsPatch := false
|
||||
|
||||
@@ -80,6 +80,9 @@ const (
|
||||
DataDownloadFailureTotal = "data_download_failure_total"
|
||||
DataDownloadCancelTotal = "data_download_cancel_total"
|
||||
|
||||
// schedule metrics
|
||||
scheduleExpectedIntervalSeconds = "schedule_expected_interval_seconds"
|
||||
|
||||
// repo maintenance metrics
|
||||
repoMaintenanceSuccessTotal = "repo_maintenance_success_total"
|
||||
repoMaintenanceFailureTotal = "repo_maintenance_failure_total"
|
||||
@@ -347,6 +350,14 @@ func NewServerMetrics() *ServerMetrics {
|
||||
},
|
||||
[]string{scheduleLabel, backupNameLabel},
|
||||
),
|
||||
scheduleExpectedIntervalSeconds: prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: scheduleExpectedIntervalSeconds,
|
||||
Help: "Expected interval between consecutive scheduled backups, in seconds",
|
||||
},
|
||||
[]string{scheduleLabel},
|
||||
),
|
||||
repoMaintenanceSuccessTotal: prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
@@ -644,6 +655,9 @@ func (m *ServerMetrics) RemoveSchedule(scheduleName string) {
|
||||
if c, ok := m.metrics[csiSnapshotFailureTotal].(*prometheus.CounterVec); ok {
|
||||
c.DeleteLabelValues(scheduleName, "")
|
||||
}
|
||||
if g, ok := m.metrics[scheduleExpectedIntervalSeconds].(*prometheus.GaugeVec); ok {
|
||||
g.DeleteLabelValues(scheduleName)
|
||||
}
|
||||
}
|
||||
|
||||
// InitMetricsForNode initializes counter metrics for a node.
|
||||
@@ -758,6 +772,14 @@ func (m *ServerMetrics) SetBackupLastSuccessfulTimestamp(backupSchedule string,
|
||||
}
|
||||
}
|
||||
|
||||
// SetScheduleExpectedIntervalSeconds records the expected interval in seconds,
|
||||
// between consecutive backups for a schedule.
|
||||
func (m *ServerMetrics) SetScheduleExpectedIntervalSeconds(scheduleName string, seconds float64) {
|
||||
if g, ok := m.metrics[scheduleExpectedIntervalSeconds].(*prometheus.GaugeVec); ok {
|
||||
g.WithLabelValues(scheduleName).Set(seconds)
|
||||
}
|
||||
}
|
||||
|
||||
// SetBackupTotal records the current number of existent backups.
|
||||
func (m *ServerMetrics) SetBackupTotal(numberOfBackups int64) {
|
||||
if g, ok := m.metrics[backupTotal].(prometheus.Gauge); ok {
|
||||
|
||||
@@ -259,6 +259,90 @@ func TestMultipleAdhocBackupsShareMetrics(t *testing.T) {
|
||||
assert.Equal(t, float64(1), validationFailureMetric, "All adhoc validation failures should be counted together")
|
||||
}
|
||||
|
||||
// TestSetScheduleExpectedIntervalSeconds verifies that the expected interval metric
|
||||
// is properly recorded for schedules.
|
||||
func TestSetScheduleExpectedIntervalSeconds(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
scheduleName string
|
||||
intervalSeconds float64
|
||||
description string
|
||||
}{
|
||||
{
|
||||
name: "every 5 minutes schedule",
|
||||
scheduleName: "frequent-backup",
|
||||
intervalSeconds: 300,
|
||||
description: "Expected interval should be 5m in seconds",
|
||||
},
|
||||
{
|
||||
name: "daily schedule",
|
||||
scheduleName: "daily-backup",
|
||||
intervalSeconds: 86400,
|
||||
description: "Expected interval should be 24h in seconds",
|
||||
},
|
||||
{
|
||||
name: "monthly schedule",
|
||||
scheduleName: "monthly-backup",
|
||||
intervalSeconds: 2678400, // 31 days in seconds
|
||||
description: "Expected interval should be 31 days in seconds",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
m := NewServerMetrics()
|
||||
m.SetScheduleExpectedIntervalSeconds(tc.scheduleName, tc.intervalSeconds)
|
||||
|
||||
metric := getMetricValue(t, m.metrics[scheduleExpectedIntervalSeconds].(*prometheus.GaugeVec), tc.scheduleName)
|
||||
assert.Equal(t, tc.intervalSeconds, metric, tc.description)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestScheduleExpectedIntervalNotInitializedByDefault verifies that the expected
|
||||
// interval metric is not initialized by InitSchedule, so it only appears for
|
||||
// schedules with a valid cron expression.
|
||||
func TestScheduleExpectedIntervalNotInitializedByDefault(t *testing.T) {
|
||||
m := NewServerMetrics()
|
||||
m.InitSchedule("test-schedule")
|
||||
|
||||
// The metric should not have any values after InitSchedule
|
||||
ch := make(chan prometheus.Metric, 1)
|
||||
m.metrics[scheduleExpectedIntervalSeconds].(*prometheus.GaugeVec).Collect(ch)
|
||||
close(ch)
|
||||
|
||||
count := 0
|
||||
for range ch {
|
||||
count++
|
||||
}
|
||||
assert.Equal(t, 0, count, "scheduleExpectedIntervalSeconds should not be initialized by InitSchedule")
|
||||
}
|
||||
|
||||
// TestRemoveScheduleCleansUpExpectedInterval verifies that RemoveSchedule
|
||||
// cleans up the expected interval metric.
|
||||
func TestRemoveScheduleCleansUpExpectedInterval(t *testing.T) {
|
||||
m := NewServerMetrics()
|
||||
m.InitSchedule("test-schedule")
|
||||
m.SetScheduleExpectedIntervalSeconds("test-schedule", 3600)
|
||||
|
||||
// Verify metric exists
|
||||
metric := getMetricValue(t, m.metrics[scheduleExpectedIntervalSeconds].(*prometheus.GaugeVec), "test-schedule")
|
||||
assert.Equal(t, float64(3600), metric)
|
||||
|
||||
// Remove schedule and verify metric is cleaned up
|
||||
m.RemoveSchedule("test-schedule")
|
||||
|
||||
ch := make(chan prometheus.Metric, 1)
|
||||
m.metrics[scheduleExpectedIntervalSeconds].(*prometheus.GaugeVec).Collect(ch)
|
||||
close(ch)
|
||||
|
||||
count := 0
|
||||
for range ch {
|
||||
count++
|
||||
}
|
||||
assert.Equal(t, 0, count, "scheduleExpectedIntervalSeconds should be removed after RemoveSchedule")
|
||||
}
|
||||
|
||||
// TestInitScheduleWithEmptyName verifies that InitSchedule works correctly
|
||||
// with an empty schedule name (for adhoc backups).
|
||||
func TestInitScheduleWithEmptyName(t *testing.T) {
|
||||
|
||||
@@ -156,7 +156,7 @@ func TestGetVolumesByPod(t *testing.T) {
|
||||
Volumes: []corev1api.Volume{
|
||||
// PVB Volumes
|
||||
{Name: "pvbPV1"}, {Name: "pvbPV2"}, {Name: "pvbPV3"},
|
||||
/// Excluded from PVB because colume mounting default service account token
|
||||
/// Excluded from PVB because volume mounting default service account token
|
||||
{Name: "default-token-5xq45"},
|
||||
},
|
||||
},
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ params:
|
||||
hero:
|
||||
backgroundColor: med-blue
|
||||
versioning: true
|
||||
latest: v1.17
|
||||
latest: v1.18
|
||||
versions:
|
||||
- main
|
||||
- v1.18
|
||||
|
||||
Reference in New Issue
Block a user