From d3c7ef09cbb7ca90ec184823b055a131ac84429b Mon Sep 17 00:00:00 2001 From: Frangipani Gold <17328443+codegold79@users.noreply.github.com> Date: Mon, 13 Dec 2021 16:09:24 -0800 Subject: [PATCH] Remove backups and restic repos associated with deleted BSL(s) (#4377) * Remove backups and restic repos associated with deleted BSL(s) Signed-off-by: F. Gold * add changelog Signed-off-by: F. Gold * Add PR number to changelog Signed-off-by: F. Gold * Fix typo Signed-off-by: F. Gold * Only delete backups and restic repos and report success when without errors Signed-off-by: F. Gold --- changelogs/unreleased/4377-codegold79 | 1 + pkg/cmd/cli/backuplocation/delete.go | 63 ++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/4377-codegold79 diff --git a/changelogs/unreleased/4377-codegold79 b/changelogs/unreleased/4377-codegold79 new file mode 100644 index 000000000..27bc88d2f --- /dev/null +++ b/changelogs/unreleased/4377-codegold79 @@ -0,0 +1 @@ +Delete backups and Restic repos associated with deleted BSL(s) \ No newline at end of file diff --git a/pkg/cmd/cli/backuplocation/delete.go b/pkg/cmd/cli/backuplocation/delete.go index eecd08f47..daedf77cd 100644 --- a/pkg/cmd/cli/backuplocation/delete.go +++ b/pkg/cmd/cli/backuplocation/delete.go @@ -1,5 +1,5 @@ /* -Copyright 2020 the Velero contributors. +Copyright The Velero Contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,7 +22,6 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" kubeerrs "k8s.io/apimachinery/pkg/util/errors" @@ -34,6 +33,8 @@ import ( "github.com/vmware-tanzu/velero/pkg/cmd/cli" ) +const bslLabelKey = "velero.io/storage-location" + // NewDeleteCommand creates and returns a new cobra command for deleting backup-locations. func NewDeleteCommand(f client.Factory, use string) *cobra.Command { o := cli.NewDeleteOptions("backup-location") @@ -120,7 +121,65 @@ func Run(f client.Factory, o *cli.DeleteOptions) error { continue } fmt.Printf("Backup storage location %q deleted successfully.\n", location.Name) + + // Delete backups associated with the deleted BSL. + backupList, err := findAssociatedBackups(kbClient, location.Name, f.Namespace()) + if err != nil { + errs = append(errs, fmt.Errorf("find backups associated with BSL %q: %w", location.Name, err)) + } else if deleteErrs := deleteBackups(kbClient, backupList); deleteErrs != nil { + errs = append(errs, deleteErrs...) + } + + // Delete Restic repositories associated with the deleted BSL. + resticRepoList, err := findAssociatedResticRepos(kbClient, location.Name, f.Namespace()) + if err != nil { + errs = append(errs, fmt.Errorf("find Restic repositories associated with BSL %q: %w", location.Name, err)) + } else if deleteErrs := deleteResticRepos(kbClient, resticRepoList); deleteErrs != nil { + errs = append(errs, deleteErrs...) + } } return kubeerrs.NewAggregate(errs) } + +func findAssociatedBackups(client kbclient.Client, bslName, ns string) (velerov1api.BackupList, error) { + var backups velerov1api.BackupList + err := client.List(context.Background(), &backups, &kbclient.ListOptions{ + Namespace: ns, + Raw: &metav1.ListOptions{LabelSelector: bslLabelKey + "=" + bslName}, + }) + return backups, err +} + +func findAssociatedResticRepos(client kbclient.Client, bslName, ns string) (velerov1api.ResticRepositoryList, error) { + var repos velerov1api.ResticRepositoryList + err := client.List(context.Background(), &repos, &kbclient.ListOptions{ + Namespace: ns, + Raw: &metav1.ListOptions{LabelSelector: bslLabelKey + "=" + bslName}, + }) + return repos, err +} + +func deleteBackups(client kbclient.Client, backups velerov1api.BackupList) []error { + var errs []error + for _, backup := range backups.Items { + if err := client.Delete(context.Background(), &backup, &kbclient.DeleteOptions{}); err != nil { + errs = append(errs, errors.WithStack(fmt.Errorf("delete backup %q associated with deleted BSL: %w", backup.Name, err))) + continue + } + fmt.Printf("Backup associated with deleted BSL(s) %q deleted successfully.\n", backup.Name) + } + return errs +} + +func deleteResticRepos(client kbclient.Client, repos velerov1api.ResticRepositoryList) []error { + var errs []error + for _, repo := range repos.Items { + if err := client.Delete(context.Background(), &repo, &kbclient.DeleteOptions{}); err != nil { + errs = append(errs, errors.WithStack(fmt.Errorf("delete Restic repository %q associated with deleted BSL: %w", repo.Name, err))) + continue + } + fmt.Printf("Restic repository associated with deleted BSL(s) %q deleted successfully.\n", repo.Name) + } + return errs +}