From c5f5862c9c645041266378f19fd60efc5c49b415 Mon Sep 17 00:00:00 2001 From: Andy Goldstein Date: Wed, 7 Feb 2018 10:22:40 -0500 Subject: [PATCH] Add --wait support to ark backup create Signed-off-by: Andy Goldstein --- docs/cli-reference/ark_backup_create.md | 1 + docs/cli-reference/ark_create_backup.md | 1 + pkg/cmd/cli/backup/create.go | 78 ++++++++++++++++++++++++- 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/docs/cli-reference/ark_backup_create.md b/docs/cli-reference/ark_backup_create.md index 153e46128..2e5467683 100644 --- a/docs/cli-reference/ark_backup_create.md +++ b/docs/cli-reference/ark_backup_create.md @@ -27,6 +27,7 @@ ark backup create NAME [flags] --show-labels show labels in the last column --snapshot-volumes optionalBool[=true] take snapshots of PersistentVolumes as part of the backup --ttl duration how long before the backup can be garbage collected (default 720h0m0s) + -w, --wait wait for the operation to complete ``` ### Options inherited from parent commands diff --git a/docs/cli-reference/ark_create_backup.md b/docs/cli-reference/ark_create_backup.md index 3e94680e7..f3fd16f2c 100644 --- a/docs/cli-reference/ark_create_backup.md +++ b/docs/cli-reference/ark_create_backup.md @@ -27,6 +27,7 @@ ark create backup NAME [flags] --show-labels show labels in the last column --snapshot-volumes optionalBool[=true] take snapshots of PersistentVolumes as part of the backup --ttl duration how long before the backup can be garbage collected (default 720h0m0s) + -w, --wait wait for the operation to complete ``` ### Options inherited from parent commands diff --git a/pkg/cmd/cli/backup/create.go b/pkg/cmd/cli/backup/create.go index 2d7750361..d899ffacd 100644 --- a/pkg/cmd/cli/backup/create.go +++ b/pkg/cmd/cli/backup/create.go @@ -20,10 +20,12 @@ import ( "fmt" "time" + "github.com/heptio/ark/pkg/generated/informers/externalversions/ark/v1" "github.com/spf13/cobra" "github.com/spf13/pflag" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/cache" api "github.com/heptio/ark/pkg/apis/ark/v1" "github.com/heptio/ark/pkg/client" @@ -47,6 +49,7 @@ func NewCreateCommand(f client.Factory, use string) *cobra.Command { } o.BindFlags(c.Flags()) + o.BindWait(c.Flags()) output.BindFlags(c.Flags()) output.ClearOutputFlagDefault(c) @@ -64,6 +67,7 @@ type CreateOptions struct { Labels flag.Map Selector flag.LabelSelector IncludeClusterResources flag.OptionalBool + Wait bool } func NewCreateOptions() *CreateOptions { @@ -93,6 +97,12 @@ func (o *CreateOptions) BindFlags(flags *pflag.FlagSet) { f.NoOptDefVal = "true" } +// BindWait binds the wait flag separately so it is not called by other create +// commands that reuse CreateOptions's BindFlags method. +func (o *CreateOptions) BindWait(flags *pflag.FlagSet) { + flags.BoolVarP(&o.Wait, "wait", "w", o.Wait, "wait for the operation to complete") +} + func (o *CreateOptions) Validate(c *cobra.Command, args []string) error { if err := output.ValidateFlags(c); err != nil { return err @@ -134,12 +144,78 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error { return err } + var backupInformer cache.SharedIndexInformer + var updates chan *api.Backup + if o.Wait { + stop := make(chan struct{}) + defer close(stop) + + updates = make(chan *api.Backup) + + backupInformer = v1.NewBackupInformer(arkClient, f.Namespace(), 0, nil) + + backupInformer.AddEventHandler( + cache.FilteringResourceEventHandler{ + FilterFunc: func(obj interface{}) bool { + backup, ok := obj.(*api.Backup) + if !ok { + return false + } + return backup.Name == o.Name + }, + Handler: cache.ResourceEventHandlerFuncs{ + UpdateFunc: func(_, obj interface{}) { + backup, ok := obj.(*api.Backup) + if !ok { + return + } + updates <- backup + }, + DeleteFunc: func(obj interface{}) { + backup, ok := obj.(*api.Backup) + if !ok { + return + } + updates <- backup + }, + }, + }, + ) + go backupInformer.Run(stop) + } + _, err = arkClient.ArkV1().Backups(backup.Namespace).Create(backup) if err != nil { return err } fmt.Printf("Backup request %q submitted successfully.\n", backup.Name) - fmt.Printf("Run `ark backup describe %s` for more details.\n", backup.Name) + if o.Wait { + fmt.Println("Waiting for backup to complete. You may safely press ctrl-c to stop waiting - your backup will continue in the background.") + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + fmt.Print(".") + case backup, ok := <-updates: + if !ok { + fmt.Println("\nError waiting: unable to watch backups.") + return nil + } + + if backup.Status.Phase != api.BackupPhaseNew && backup.Status.Phase != api.BackupPhaseInProgress { + fmt.Printf("\nBackup completed with status: %s. You may check for more information using the commands `ark backup describe %s` and `ark backup logs %s`.\n", backup.Status.Phase, backup.Name, backup.Name) + return nil + } + } + } + } + + // Not waiting + + fmt.Printf("Run `ark backup describe %s` or `ark backup logs %s` for more details.\n", backup.Name, backup.Name) + return nil }