github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/backups/remove.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package backups 5 6 import ( 7 "fmt" 8 9 "github.com/juju/cmd" 10 "github.com/juju/errors" 11 "github.com/juju/gnuflag" 12 "github.com/juju/utils/set" 13 14 "github.com/juju/juju/apiserver/params" 15 jujucmd "github.com/juju/juju/cmd" 16 "github.com/juju/juju/cmd/modelcmd" 17 ) 18 19 const removeDoc = ` 20 remove-backup removes a backup from remote storage. 21 ` 22 23 // NewRemoveCommand returns a command used to remove a 24 // backup from remote storage. 25 func NewRemoveCommand() cmd.Command { 26 return modelcmd.Wrap(&removeCommand{}) 27 } 28 29 type removeCommand struct { 30 CommandBase 31 // ID refers to the backup to be removed. 32 ID string 33 KeepLatest bool 34 } 35 36 // Info implements Command.Info. 37 func (c *removeCommand) Info() *cmd.Info { 38 return jujucmd.Info(&cmd.Info{ 39 Name: "remove-backup", 40 Args: "[--keep-latest|<ID>]", 41 Purpose: "Remove the specified backup from remote storage.", 42 Doc: removeDoc, 43 }) 44 } 45 46 // SetFlags implements Command.SetFlags. 47 func (c *removeCommand) SetFlags(f *gnuflag.FlagSet) { 48 c.CommandBase.SetFlags(f) 49 f.BoolVar(&c.KeepLatest, "keep-latest", false, 50 "Remove all backups on remote storage except for the latest.") 51 } 52 53 // Init implements Command.Init. 54 func (c *removeCommand) Init(args []string) error { 55 switch { 56 case len(args) == 0 && !c.KeepLatest: 57 return errors.New("missing ID or --keep-latest option") 58 case len(args) != 0: 59 id, args := args[0], args[1:] 60 if err := cmd.CheckEmpty(args); err != nil { 61 return errors.Trace(err) 62 } 63 c.ID = id 64 case c.KeepLatest: 65 default: 66 return errors.New("unknown error parsing arguments") 67 } 68 return nil 69 } 70 71 // Run implements Command.Run. 72 func (c *removeCommand) Run(ctx *cmd.Context) error { 73 if c.Log != nil { 74 if err := c.Log.Start(ctx); err != nil { 75 return err 76 } 77 } 78 79 client, apiVersion, err := c.NewGetAPI() 80 if err != nil { 81 return errors.Trace(err) 82 } 83 defer client.Close() 84 85 if apiVersion < 2 && c.KeepLatest { 86 return errors.New("--keep-latest is not supported by this controller") 87 } 88 //ctx.Infof("apiversion %d", apiVersion) 89 90 ids := []string{} 91 var keep string 92 if c.KeepLatest { 93 list, err := client.List() 94 if err != nil { 95 return errors.Trace(err) 96 } 97 98 ids, keep, err = parseList(list.List) 99 switch { 100 case err != nil: 101 return errors.Trace(err) 102 case len(ids) > 0: 103 break 104 case keep != "": 105 ctx.Warningf("no backups to remove, %v most current", keep) 106 return nil 107 default: 108 ctx.Warningf("no backups to remove") 109 return nil 110 } 111 } else { 112 ids = append(ids, c.ID) 113 } 114 //ctx.Infof("%s; %+v", keep, ids) 115 116 results, err := client.Remove(ids...) 117 if err != nil { 118 return errors.Trace(err) 119 } 120 121 for i, err := range results { 122 if err.Error != nil { 123 // Some errors do not provide enough info, let's try to fix that here. 124 err.Error.Message = fmt.Sprintf("failed to remove %v: %s", ids[i], err.Error.Message) 125 continue 126 } 127 ctx.Infof("successfully removed: %v\n", ids[i]) 128 } 129 if c.KeepLatest { 130 ctx.Infof("kept: %v", keep) 131 } 132 return errors.Trace(params.ErrorResults{results}.Combine()) 133 } 134 135 // parseList returns a list of IDs to be removed and the one ID to be kept. 136 // Keep the latest ID based on Started. 137 func parseList(list []params.BackupsMetadataResult) ([]string, string, error) { 138 if len(list) == 0 { 139 return nil, "", nil 140 } 141 latest := list[0] 142 retList := set.NewStrings() 143 // Start looking for a new latest with the 2nd item in the slice. 144 for _, entry := range list[1:] { 145 if entry.Started.After(latest.Started) { 146 // Found a new latest, add the old one to the set 147 retList.Add(latest.ID) 148 latest = entry 149 continue 150 } 151 // Not the latest, add to the set 152 retList.Add(entry.ID) 153 } 154 return retList.SortedValues(), latest.ID, nil 155 }