mirror of
https://github.com/vmware-tanzu/velero.git
synced 2025-12-23 06:15:21 +00:00
Merge pull request #9206 from Joeavaikath/label-cleanup
Some checks failed
Run the E2E test on kind / get-go-version (push) Failing after 1m0s
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
Main CI / get-go-version (push) Successful in 14s
Main CI / Build (push) Failing after 42s
Close stale issues and PRs / stale (push) Successful in 11s
Trivy Nightly Scan / Trivy nightly scan (velero, main) (push) Failing after 1m33s
Trivy Nightly Scan / Trivy nightly scan (velero-plugin-for-aws, main) (push) Failing after 1m13s
Trivy Nightly Scan / Trivy nightly scan (velero-plugin-for-gcp, main) (push) Failing after 1m14s
Trivy Nightly Scan / Trivy nightly scan (velero-plugin-for-microsoft-azure, main) (push) Failing after 1m15s
Some checks failed
Run the E2E test on kind / get-go-version (push) Failing after 1m0s
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
Main CI / get-go-version (push) Successful in 14s
Main CI / Build (push) Failing after 42s
Close stale issues and PRs / stale (push) Successful in 11s
Trivy Nightly Scan / Trivy nightly scan (velero, main) (push) Failing after 1m33s
Trivy Nightly Scan / Trivy nightly scan (velero-plugin-for-aws, main) (push) Failing after 1m13s
Trivy Nightly Scan / Trivy nightly scan (velero-plugin-for-gcp, main) (push) Failing after 1m14s
Trivy Nightly Scan / Trivy nightly scan (velero-plugin-for-microsoft-azure, main) (push) Failing after 1m15s
Remove labels associated with previous backups
This commit is contained in:
1
changelogs/unreleased/9206-Joeavaikath
Normal file
1
changelogs/unreleased/9206-Joeavaikath
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Remove labels associated with previous backups
|
||||||
@@ -76,14 +76,8 @@ func (a *PVCAction) Execute(item runtime.Unstructured, backup *v1.Backup) (runti
|
|||||||
pvc.Spec.Selector = nil
|
pvc.Spec.Selector = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove label selectors with "velero.io/" prefixing in the key which is left by Velero restore
|
// Clean stale Velero labels from PVC metadata and selector
|
||||||
if pvc.Spec.Selector != nil && pvc.Spec.Selector.MatchLabels != nil {
|
a.cleanupStaleVeleroLabels(pvc, backup)
|
||||||
for k := range pvc.Spec.Selector.MatchLabels {
|
|
||||||
if strings.HasPrefix(k, "velero.io/") {
|
|
||||||
delete(pvc.Spec.Selector.MatchLabels, k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pvcMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&pvc)
|
pvcMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&pvc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -92,3 +86,50 @@ func (a *PVCAction) Execute(item runtime.Unstructured, backup *v1.Backup) (runti
|
|||||||
|
|
||||||
return &unstructured.Unstructured{Object: pvcMap}, actionhelpers.RelatedItemsForPVC(pvc, a.log), nil
|
return &unstructured.Unstructured{Object: pvcMap}, actionhelpers.RelatedItemsForPVC(pvc, a.log), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cleanupStaleVeleroLabels removes stale Velero labels from both the PVC metadata
|
||||||
|
// and the selector's match labels to ensure clean backups
|
||||||
|
func (a *PVCAction) cleanupStaleVeleroLabels(pvc *corev1api.PersistentVolumeClaim, backup *v1.Backup) {
|
||||||
|
// Clean stale Velero labels from selector match labels
|
||||||
|
if pvc.Spec.Selector != nil && pvc.Spec.Selector.MatchLabels != nil {
|
||||||
|
for k := range pvc.Spec.Selector.MatchLabels {
|
||||||
|
if strings.HasPrefix(k, "velero.io/") {
|
||||||
|
a.log.Infof("Deleting stale Velero label %s from PVC %s selector", k, pvc.Name)
|
||||||
|
delete(pvc.Spec.Selector.MatchLabels, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean stale Velero labels from main metadata
|
||||||
|
if pvc.Labels != nil {
|
||||||
|
for k, v := range pvc.Labels {
|
||||||
|
// Only remove labels that are clearly stale from previous operations
|
||||||
|
shouldRemove := false
|
||||||
|
|
||||||
|
// Always remove restore-name labels as these are from previous restores
|
||||||
|
if k == v1.RestoreNameLabel {
|
||||||
|
shouldRemove = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if k == v1.MustIncludeAdditionalItemAnnotation {
|
||||||
|
shouldRemove = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove backup-name labels that don't match current backup
|
||||||
|
if k == v1.BackupNameLabel && v != backup.Name {
|
||||||
|
shouldRemove = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove volume-snapshot-name labels from previous CSI backups
|
||||||
|
// Note: If this backup creates new CSI snapshots, the CSI action will add them back
|
||||||
|
if k == v1.VolumeSnapshotLabel {
|
||||||
|
shouldRemove = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if shouldRemove {
|
||||||
|
a.log.Infof("Deleting stale Velero label %s=%s from PVC %s", k, v, pvc.Name)
|
||||||
|
delete(pvc.Labels, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -149,3 +149,176 @@ func TestBackupPVAction(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Empty(t, additional)
|
assert.Empty(t, additional)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCleanupStaleVeleroLabels(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
inputPVC *corev1api.PersistentVolumeClaim
|
||||||
|
backup *v1.Backup
|
||||||
|
expectedLabels map[string]string
|
||||||
|
expectedSelector *metav1.LabelSelector
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "removes restore-name labels",
|
||||||
|
inputPVC: &corev1api.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-pvc",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"velero.io/restore-name": "old-restore",
|
||||||
|
"app": "myapp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
backup: &v1.Backup{ObjectMeta: metav1.ObjectMeta{Name: "current-backup"}},
|
||||||
|
expectedLabels: map[string]string{
|
||||||
|
"app": "myapp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "removes backup-name labels that don't match current backup",
|
||||||
|
inputPVC: &corev1api.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-pvc",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"velero.io/backup-name": "old-backup",
|
||||||
|
"app": "myapp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
backup: &v1.Backup{ObjectMeta: metav1.ObjectMeta{Name: "current-backup"}},
|
||||||
|
expectedLabels: map[string]string{
|
||||||
|
"app": "myapp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "keeps backup-name labels that match current backup",
|
||||||
|
inputPVC: &corev1api.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-pvc",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"velero.io/backup-name": "current-backup",
|
||||||
|
"app": "myapp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
backup: &v1.Backup{ObjectMeta: metav1.ObjectMeta{Name: "current-backup"}},
|
||||||
|
expectedLabels: map[string]string{
|
||||||
|
"velero.io/backup-name": "current-backup",
|
||||||
|
"app": "myapp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "removes volume-snapshot-name labels",
|
||||||
|
inputPVC: &corev1api.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-pvc",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"velero.io/volume-snapshot-name": "old-snapshot",
|
||||||
|
"app": "myapp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
backup: &v1.Backup{ObjectMeta: metav1.ObjectMeta{Name: "current-backup"}},
|
||||||
|
expectedLabels: map[string]string{
|
||||||
|
"app": "myapp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "removes velero labels from selector match labels",
|
||||||
|
inputPVC: &corev1api.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-pvc",
|
||||||
|
},
|
||||||
|
Spec: corev1api.PersistentVolumeClaimSpec{
|
||||||
|
Selector: &metav1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{
|
||||||
|
"velero.io/restore-name": "old-restore",
|
||||||
|
"velero.io/backup-name": "old-backup",
|
||||||
|
"app": "myapp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
backup: &v1.Backup{ObjectMeta: metav1.ObjectMeta{Name: "current-backup"}},
|
||||||
|
expectedLabels: nil,
|
||||||
|
expectedSelector: &metav1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{
|
||||||
|
"app": "myapp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "handles PVC with no labels",
|
||||||
|
inputPVC: &corev1api.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-pvc",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
backup: &v1.Backup{ObjectMeta: metav1.ObjectMeta{Name: "current-backup"}},
|
||||||
|
expectedLabels: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "handles PVC with no selector",
|
||||||
|
inputPVC: &corev1api.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-pvc",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"app": "myapp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
backup: &v1.Backup{ObjectMeta: metav1.ObjectMeta{Name: "current-backup"}},
|
||||||
|
expectedLabels: map[string]string{
|
||||||
|
"app": "myapp",
|
||||||
|
},
|
||||||
|
expectedSelector: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "removes multiple stale velero labels",
|
||||||
|
inputPVC: &corev1api.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-pvc",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"velero.io/restore-name": "old-restore",
|
||||||
|
"velero.io/backup-name": "old-backup",
|
||||||
|
"velero.io/volume-snapshot-name": "old-snapshot",
|
||||||
|
"app": "myapp",
|
||||||
|
"env": "prod",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: corev1api.PersistentVolumeClaimSpec{
|
||||||
|
Selector: &metav1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{
|
||||||
|
"velero.io/restore-name": "old-restore",
|
||||||
|
"app": "myapp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
backup: &v1.Backup{ObjectMeta: metav1.ObjectMeta{Name: "current-backup"}},
|
||||||
|
expectedLabels: map[string]string{
|
||||||
|
"app": "myapp",
|
||||||
|
"env": "prod",
|
||||||
|
},
|
||||||
|
expectedSelector: &metav1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{
|
||||||
|
"app": "myapp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
action := NewPVCAction(velerotest.NewLogger())
|
||||||
|
|
||||||
|
// Create a copy of the input PVC to avoid modifying the test case
|
||||||
|
pvcCopy := tc.inputPVC.DeepCopy()
|
||||||
|
|
||||||
|
action.cleanupStaleVeleroLabels(pvcCopy, tc.backup)
|
||||||
|
|
||||||
|
assert.Equal(t, tc.expectedLabels, pvcCopy.Labels, "Labels should match expected values")
|
||||||
|
assert.Equal(t, tc.expectedSelector, pvcCopy.Spec.Selector, "Selector should match expected values")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user