github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/backups/backups.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 "io" 9 "os" 10 11 "github.com/juju/cmd" 12 "github.com/juju/errors" 13 "github.com/juju/gnuflag" 14 15 "github.com/juju/juju/api/backups" 16 apiserverbackups "github.com/juju/juju/apiserver/backups" 17 "github.com/juju/juju/apiserver/params" 18 "github.com/juju/juju/cmd/modelcmd" 19 statebackups "github.com/juju/juju/state/backups" 20 ) 21 22 // APIClient represents the backups API client functionality used by 23 // the backups command. 24 type APIClient interface { 25 io.Closer 26 // Create sends an RPC request to create a new backup. 27 Create(notes string) (*params.BackupsMetadataResult, error) 28 // Info gets the backup's metadata. 29 Info(id string) (*params.BackupsMetadataResult, error) 30 // List gets all stored metadata. 31 List() (*params.BackupsListResult, error) 32 // Download pulls the backup archive file. 33 Download(id string) (io.ReadCloser, error) 34 // Upload pushes a backup archive to storage. 35 Upload(ar io.ReadSeeker, meta params.BackupsMetadataResult) (string, error) 36 // Remove removes the stored backup. 37 Remove(id string) error 38 // Restore will restore a backup with the given id into the controller. 39 Restore(string, backups.ClientConnection) error 40 // RestoreReader will restore a backup file into the controller. 41 RestoreReader(io.ReadSeeker, *params.BackupsMetadataResult, backups.ClientConnection) error 42 } 43 44 // CommandBase is the base type for backups sub-commands. 45 type CommandBase struct { 46 // TODO(wallyworld) - remove Log when backup command is flattened. 47 Log *cmd.Log 48 modelcmd.ModelCommandBase 49 } 50 51 // NewAPIClient returns a client for the backups api endpoint. 52 func (c *CommandBase) NewAPIClient() (APIClient, error) { 53 return newAPIClient(c) 54 } 55 56 // SetFlags implements Command.SetFlags. 57 func (c *CommandBase) SetFlags(f *gnuflag.FlagSet) { 58 c.ModelCommandBase.SetFlags(f) 59 if c.Log != nil { 60 c.Log.AddFlags(f) 61 } 62 } 63 64 var newAPIClient = func(c *CommandBase) (APIClient, error) { 65 root, err := c.NewAPIRoot() 66 if err != nil { 67 return nil, errors.Trace(err) 68 } 69 return backups.NewClient(root) 70 } 71 72 // dumpMetadata writes the formatted backup metadata to stdout. 73 func (c *CommandBase) dumpMetadata(ctx *cmd.Context, result *params.BackupsMetadataResult) { 74 fmt.Fprintf(ctx.Stdout, "backup ID: %q\n", result.ID) 75 fmt.Fprintf(ctx.Stdout, "checksum: %q\n", result.Checksum) 76 fmt.Fprintf(ctx.Stdout, "checksum format: %q\n", result.ChecksumFormat) 77 fmt.Fprintf(ctx.Stdout, "size (B): %d\n", result.Size) 78 fmt.Fprintf(ctx.Stdout, "stored: %v\n", result.Stored) 79 80 fmt.Fprintf(ctx.Stdout, "started: %v\n", result.Started) 81 fmt.Fprintf(ctx.Stdout, "finished: %v\n", result.Finished) 82 fmt.Fprintf(ctx.Stdout, "notes: %q\n", result.Notes) 83 84 fmt.Fprintf(ctx.Stdout, "model ID: %q\n", result.Model) 85 fmt.Fprintf(ctx.Stdout, "machine ID: %q\n", result.Machine) 86 fmt.Fprintf(ctx.Stdout, "created on host: %q\n", result.Hostname) 87 fmt.Fprintf(ctx.Stdout, "juju version: %v\n", result.Version) 88 } 89 90 // ArchiveReader can read a backup archive. 91 type ArchiveReader interface { 92 io.ReadSeeker 93 io.Closer 94 } 95 96 func getArchive(filename string) (rc ArchiveReader, metaResult *params.BackupsMetadataResult, err error) { 97 defer func() { 98 if err != nil && rc != nil { 99 rc.Close() 100 } 101 }() 102 archive, err := os.Open(filename) 103 rc = archive 104 if err != nil { 105 return nil, nil, errors.Trace(err) 106 } 107 108 // Extract the metadata. 109 ad, err := statebackups.NewArchiveDataReader(archive) 110 if err != nil { 111 return nil, nil, errors.Trace(err) 112 } 113 _, err = archive.Seek(0, os.SEEK_SET) 114 if err != nil { 115 return nil, nil, errors.Trace(err) 116 } 117 meta, err := ad.Metadata() 118 if err != nil { 119 if !errors.IsNotFound(err) { 120 return nil, nil, errors.Trace(err) 121 } 122 meta, err = statebackups.BuildMetadata(archive) 123 if err != nil { 124 return nil, nil, errors.Trace(err) 125 } 126 } 127 // Make sure the file info is set. 128 fileMeta, err := statebackups.BuildMetadata(archive) 129 if err != nil { 130 return nil, nil, errors.Trace(err) 131 } 132 if meta.Size() == int64(0) { 133 if err := meta.SetFileInfo(fileMeta.Size(), "", ""); err != nil { 134 return nil, nil, errors.Trace(err) 135 } 136 } 137 if meta.Checksum() == "" { 138 err := meta.SetFileInfo(0, fileMeta.Checksum(), fileMeta.ChecksumFormat()) 139 if err != nil { 140 return nil, nil, errors.Trace(err) 141 } 142 } 143 if meta.Finished == nil || meta.Finished.IsZero() { 144 meta.Finished = fileMeta.Finished 145 } 146 _, err = archive.Seek(0, os.SEEK_SET) 147 if err != nil { 148 return nil, nil, errors.Trace(err) 149 } 150 151 // Pack the metadata into a result. 152 // TODO(perrito666) change the identity of ResultfromMetadata to 153 // return a pointer. 154 mResult := apiserverbackups.ResultFromMetadata(meta) 155 metaResult = &mResult 156 157 return archive, metaResult, nil 158 }