github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 "launchpad.net/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 if c.Log != nil { 59 c.Log.AddFlags(f) 60 } 61 } 62 63 var newAPIClient = func(c *CommandBase) (APIClient, error) { 64 root, err := c.NewAPIRoot() 65 if err != nil { 66 return nil, errors.Trace(err) 67 } 68 return backups.NewClient(root) 69 } 70 71 // dumpMetadata writes the formatted backup metadata to stdout. 72 func (c *CommandBase) dumpMetadata(ctx *cmd.Context, result *params.BackupsMetadataResult) { 73 fmt.Fprintf(ctx.Stdout, "backup ID: %q\n", result.ID) 74 fmt.Fprintf(ctx.Stdout, "checksum: %q\n", result.Checksum) 75 fmt.Fprintf(ctx.Stdout, "checksum format: %q\n", result.ChecksumFormat) 76 fmt.Fprintf(ctx.Stdout, "size (B): %d\n", result.Size) 77 fmt.Fprintf(ctx.Stdout, "stored: %v\n", result.Stored) 78 79 fmt.Fprintf(ctx.Stdout, "started: %v\n", result.Started) 80 fmt.Fprintf(ctx.Stdout, "finished: %v\n", result.Finished) 81 fmt.Fprintf(ctx.Stdout, "notes: %q\n", result.Notes) 82 83 fmt.Fprintf(ctx.Stdout, "model ID: %q\n", result.Model) 84 fmt.Fprintf(ctx.Stdout, "machine ID: %q\n", result.Machine) 85 fmt.Fprintf(ctx.Stdout, "created on host: %q\n", result.Hostname) 86 fmt.Fprintf(ctx.Stdout, "juju version: %v\n", result.Version) 87 } 88 89 // ArchiveReader can read a backup archive. 90 type ArchiveReader interface { 91 io.ReadSeeker 92 io.Closer 93 } 94 95 func getArchive(filename string) (rc ArchiveReader, metaResult *params.BackupsMetadataResult, err error) { 96 defer func() { 97 if err != nil && rc != nil { 98 rc.Close() 99 } 100 }() 101 archive, err := os.Open(filename) 102 rc = archive 103 if err != nil { 104 return nil, nil, errors.Trace(err) 105 } 106 107 // Extract the metadata. 108 ad, err := statebackups.NewArchiveDataReader(archive) 109 if err != nil { 110 return nil, nil, errors.Trace(err) 111 } 112 _, err = archive.Seek(0, os.SEEK_SET) 113 if err != nil { 114 return nil, nil, errors.Trace(err) 115 } 116 meta, err := ad.Metadata() 117 if err != nil { 118 if !errors.IsNotFound(err) { 119 return nil, nil, errors.Trace(err) 120 } 121 meta, err = statebackups.BuildMetadata(archive) 122 if err != nil { 123 return nil, nil, errors.Trace(err) 124 } 125 } 126 // Make sure the file info is set. 127 fileMeta, err := statebackups.BuildMetadata(archive) 128 if err != nil { 129 return nil, nil, errors.Trace(err) 130 } 131 if meta.Size() == int64(0) { 132 if err := meta.SetFileInfo(fileMeta.Size(), "", ""); err != nil { 133 return nil, nil, errors.Trace(err) 134 } 135 } 136 if meta.Checksum() == "" { 137 err := meta.SetFileInfo(0, fileMeta.Checksum(), fileMeta.ChecksumFormat()) 138 if err != nil { 139 return nil, nil, errors.Trace(err) 140 } 141 } 142 if meta.Finished == nil || meta.Finished.IsZero() { 143 meta.Finished = fileMeta.Finished 144 } 145 _, err = archive.Seek(0, os.SEEK_SET) 146 if err != nil { 147 return nil, nil, errors.Trace(err) 148 } 149 150 // Pack the metadata into a result. 151 // TODO(perrito666) change the identity of ResultfromMetadata to 152 // return a pointer. 153 mResult := apiserverbackups.ResultFromMetadata(meta) 154 metaResult = &mResult 155 156 return archive, metaResult, nil 157 }