diff --git a/changelogs/unreleased/9597-blackpiglet b/changelogs/unreleased/9597-blackpiglet new file mode 100644 index 000000000..f1e546be6 --- /dev/null +++ b/changelogs/unreleased/9597-blackpiglet @@ -0,0 +1 @@ +If BIA return updateObj with SkipFromBackupAnnotation, treat it as skip the resource from backup. \ No newline at end of file diff --git a/pkg/apis/velero/v1/labels_annotations.go b/pkg/apis/velero/v1/labels_annotations.go index c1431d3cc..85d8b05aa 100644 --- a/pkg/apis/velero/v1/labels_annotations.go +++ b/pkg/apis/velero/v1/labels_annotations.go @@ -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" diff --git a/pkg/backup/backed_up_items_map.go b/pkg/backup/backed_up_items_map.go index f5764cd8e..174a50e1e 100644 --- a/pkg/backup/backed_up_items_map.go +++ b/pkg/backup/backed_up_items_map.go @@ -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() diff --git a/pkg/backup/item_backupper.go b/pkg/backup/item_backupper.go index feae0e01c..b50f4e119 100644 --- a/pkg/backup/item_backupper.go +++ b/pkg/backup/item_backupper.go @@ -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