add bulk deletion support to ark backup delete

Signed-off-by: Steve Kriss <steve@heptio.com>
pull/745/head
Steve Kriss 2018-08-07 16:07:01 -07:00
parent 1f7a4a1665
commit 5acccaa739
5 changed files with 159 additions and 37 deletions

View File

@ -31,7 +31,7 @@ Work with backups
### SEE ALSO
* [ark](ark.md) - Back up and restore Kubernetes cluster resources.
* [ark backup create](ark_backup_create.md) - Create a backup
* [ark backup delete](ark_backup_delete.md) - Delete a backup
* [ark backup delete](ark_backup_delete.md) - Delete backups
* [ark backup describe](ark_backup_describe.md) - Describe backups
* [ark backup download](ark_backup_download.md) - Download a backup
* [ark backup get](ark_backup_get.md) - Get backups

View File

@ -1,21 +1,43 @@
## ark backup delete
Delete a backup
Delete backups
### Synopsis
Delete a backup
Delete backups
```
ark backup delete NAME [flags]
ark backup delete [NAMES] [flags]
```
### Examples
```
# delete a backup named "backup-1"
ark backup delete backup-1
# delete a backup named "backup-1" without prompting for confirmation
ark backup delete backup-1 --confirm
# delete backups named "backup-1" and "backup-2"
ark backup delete backup-1 backup-2
# delete all backups triggered by schedule "schedule-1"
ark backup delete --selector ark-schedule=schedule-1
# delete all backups
ark backup delete --all
```
### Options
```
--confirm Confirm deletion
-h, --help help for delete
--all Delete all backups
--confirm Confirm deletion
-h, --help help for delete
-l, --selector labelSelector Delete all backups matching this label selector (default <none>)
```
### Options inherited from parent commands

View File

@ -30,7 +30,7 @@ Delete ark resources
### SEE ALSO
* [ark](ark.md) - Back up and restore Kubernetes cluster resources.
* [ark delete backup](ark_delete_backup.md) - Delete a backup
* [ark delete backup](ark_delete_backup.md) - Delete backups
* [ark delete restore](ark_delete_restore.md) - Delete a restore
* [ark delete schedule](ark_delete_schedule.md) - Delete a schedule

View File

@ -1,21 +1,43 @@
## ark delete backup
Delete a backup
Delete backups
### Synopsis
Delete a backup
Delete backups
```
ark delete backup NAME [flags]
ark delete backup [NAMES] [flags]
```
### Examples
```
# delete a backup named "backup-1"
ark backup delete backup-1
# delete a backup named "backup-1" without prompting for confirmation
ark backup delete backup-1 --confirm
# delete backups named "backup-1" and "backup-2"
ark backup delete backup-1 backup-2
# delete all backups triggered by schedule "schedule-1"
ark backup delete --selector ark-schedule=schedule-1
# delete all backups
ark backup delete --all
```
### Options
```
--confirm Confirm deletion
-h, --help help for backup
--all Delete all backups
--confirm Confirm deletion
-h, --help help for backup
-l, --selector labelSelector Delete all backups matching this label selector (default <none>)
```
### Options inherited from parent commands

View File

@ -18,20 +18,24 @@ package backup
import (
"bufio"
"errors"
"fmt"
"os"
"strings"
"github.com/heptio/ark/pkg/apis/ark/v1"
"github.com/heptio/ark/pkg/backup"
clientset "github.com/heptio/ark/pkg/generated/clientset/versioned"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
kubeerrs "k8s.io/apimachinery/pkg/util/errors"
arkv1api "github.com/heptio/ark/pkg/apis/ark/v1"
"github.com/heptio/ark/pkg/backup"
"github.com/heptio/ark/pkg/client"
"github.com/heptio/ark/pkg/cmd"
"github.com/heptio/ark/pkg/cmd/util/flag"
clientset "github.com/heptio/ark/pkg/generated/clientset/versioned"
)
// NewDeleteCommand creates a new command that deletes a backup.
@ -39,9 +43,23 @@ func NewDeleteCommand(f client.Factory, use string) *cobra.Command {
o := &DeleteOptions{}
c := &cobra.Command{
Use: fmt.Sprintf("%s NAME", use),
Short: "Delete a backup",
Args: cobra.ExactArgs(1),
Use: fmt.Sprintf("%s [NAMES]", use),
Short: "Delete backups",
Example: ` # delete a backup named "backup-1"
ark backup delete backup-1
# delete a backup named "backup-1" without prompting for confirmation
ark backup delete backup-1 --confirm
# delete backups named "backup-1" and "backup-2"
ark backup delete backup-1 backup-2
# delete all backups triggered by schedule "schedule-1"
ark backup delete --selector ark-schedule=schedule-1
# delete all backups
ark backup delete --all
`,
Run: func(c *cobra.Command, args []string) {
cmd.CheckError(o.Complete(f, args))
cmd.CheckError(o.Validate(c, args, f))
@ -56,23 +74,24 @@ func NewDeleteCommand(f client.Factory, use string) *cobra.Command {
// DeleteOptions contains parameters for deleting a backup.
type DeleteOptions struct {
Name string
Confirm bool
Names []string
All bool
Selector flag.LabelSelector
Confirm bool
client clientset.Interface
namespace string
backup *v1.Backup
}
// BindFlags binds options for this command to flags.
func (o *DeleteOptions) BindFlags(flags *pflag.FlagSet) {
flags.BoolVar(&o.Confirm, "confirm", o.Confirm, "Confirm deletion")
flags.BoolVar(&o.All, "all", o.All, "Delete all backups")
flags.VarP(&o.Selector, "selector", "l", "Delete all backups matching this label selector")
}
// Complete fills out the remainder of the parameters based on user input.
func (o *DeleteOptions) Complete(f client.Factory, args []string) error {
o.Name = args[0]
o.namespace = f.Namespace()
client, err := f.Client()
@ -81,11 +100,7 @@ func (o *DeleteOptions) Complete(f client.Factory, args []string) error {
}
o.client = client
backup, err := o.client.ArkV1().Backups(f.Namespace()).Get(o.Name, metav1.GetOptions{})
if err != nil {
return err
}
o.backup = backup
o.Names = args
return nil
}
@ -96,13 +111,34 @@ func (o *DeleteOptions) Validate(c *cobra.Command, args []string, f client.Facto
return errors.New("Ark client is not set; unable to proceed")
}
if o.backup == nil {
return errors.New("backup is not set; unable to proceed")
var (
hasNames = len(o.Names) > 0
hasAll = o.All
hasSelector = o.Selector.LabelSelector != nil
)
if !xor(hasNames, hasAll, hasSelector) {
return errors.New("you must specify exactly one of: specific backup name(s), the --all flag, or the --selector flag")
}
return nil
}
// xor returns true if exactly one of the provided values is true,
// or false otherwise.
func xor(val bool, vals ...bool) bool {
res := val
for _, v := range vals {
if res && v {
return false
}
res = res || v
}
return res
}
// Run performs the delete backup operation.
func (o *DeleteOptions) Run() error {
if !o.Confirm && !getConfirmation() {
@ -110,14 +146,56 @@ func (o *DeleteOptions) Run() error {
return nil
}
deleteRequest := backup.NewDeleteBackupRequest(o.backup.Name, string(o.backup.UID))
var (
backups []*arkv1api.Backup
errs []error
)
if _, err := o.client.ArkV1().DeleteBackupRequests(o.namespace).Create(deleteRequest); err != nil {
return err
// get the list of backups to delete
switch {
case len(o.Names) > 0:
for _, name := range o.Names {
backup, err := o.client.ArkV1().Backups(o.namespace).Get(name, metav1.GetOptions{})
if err != nil {
errs = append(errs, errors.WithStack(err))
continue
}
backups = append(backups, backup)
}
default:
selector := labels.Everything().String()
if o.Selector.LabelSelector != nil {
selector = o.Selector.String()
}
res, err := o.client.ArkV1().Backups(o.namespace).List(metav1.ListOptions{LabelSelector: selector})
if err != nil {
return errors.WithStack(err)
}
for i := range res.Items {
backups = append(backups, &res.Items[i])
}
}
fmt.Printf("Request to delete backup %q submitted successfully.\nThe backup will be fully deleted after all associated data (disk snapshots, backup files, restores) are removed.\n", o.backup.Name)
return nil
if len(backups) == 0 {
fmt.Println("No backups found")
return nil
}
// create a backup deletion request for each
for _, b := range backups {
deleteRequest := backup.NewDeleteBackupRequest(b.Name, string(b.UID))
if _, err := o.client.ArkV1().DeleteBackupRequests(o.namespace).Create(deleteRequest); err != nil {
errs = append(errs, err)
continue
}
fmt.Printf("Request to delete backup %q submitted successfully.\nThe backup will be fully deleted after all associated data (disk snapshots, backup files, restores) are removed.\n", b.Name)
}
return kubeerrs.NewAggregate(errs)
}
func getConfirmation() bool {