github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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/facades/client/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 // 25 // To regenerate the mocks for the APIClient used by this package, 26 // run "go generate" from the package directory. 27 //go:generate mockgen -package backups_test -destination mock_test.go github.com/juju/juju/cmd/juju/backups ArchiveReader,APIClient 28 type APIClient interface { 29 io.Closer 30 // Create sends an RPC request to create a new backup. 31 Create(notes string, keepCopy, noDownload bool) (*params.BackupsMetadataResult, error) 32 // Info gets the backup's metadata. 33 Info(id string) (*params.BackupsMetadataResult, error) 34 // List gets all stored metadata. 35 List() (*params.BackupsListResult, error) 36 // Download pulls the backup archive file. 37 Download(id string) (io.ReadCloser, error) 38 // Upload pushes a backup archive to storage. 39 Upload(ar io.ReadSeeker, meta params.BackupsMetadataResult) (string, error) 40 // Remove removes the stored backups. 41 Remove(ids ...string) ([]params.ErrorResult, error) 42 // Restore will restore a backup with the given id into the controller. 43 Restore(string, backups.ClientConnection) error 44 // RestoreReader will restore a backup file into the controller. 45 RestoreReader(io.ReadSeeker, *params.BackupsMetadataResult, backups.ClientConnection) error 46 } 47 48 // CommandBase is the base type for backups sub-commands. 49 type CommandBase struct { 50 // TODO(wallyworld) - remove Log when backup command is flattened. 51 Log *cmd.Log 52 modelcmd.ModelCommandBase 53 } 54 55 // NewAPIClient returns a client for the backups api endpoint. 56 func (c *CommandBase) NewAPIClient() (APIClient, error) { 57 return newAPIClient(c) 58 } 59 60 // NewAPIClient returns a client for the backups api endpoint. 61 func (c *CommandBase) NewGetAPI() (APIClient, int, error) { 62 return getAPI(c) 63 } 64 65 // SetFlags implements Command.SetFlags. 66 func (c *CommandBase) SetFlags(f *gnuflag.FlagSet) { 67 c.ModelCommandBase.SetFlags(f) 68 if c.Log != nil { 69 c.Log.AddFlags(f) 70 } 71 } 72 73 var newAPIClient = func(c *CommandBase) (APIClient, error) { 74 root, err := c.NewAPIRoot() 75 if err != nil { 76 return nil, errors.Trace(err) 77 } 78 return backups.NewClient(root) 79 } 80 81 // GetAPI returns a client and the api version of the controller 82 var getAPI = func(c *CommandBase) (APIClient, int, error) { 83 root, err := c.NewAPIRoot() 84 if err != nil { 85 return nil, -1, errors.Trace(err) 86 } 87 version := root.BestFacadeVersion("Backups") 88 client, err := backups.NewClient(root) 89 return client, version, nil 90 } 91 92 // dumpMetadata writes the formatted backup metadata to stdout. 93 func (c *CommandBase) dumpMetadata(ctx *cmd.Context, result *params.BackupsMetadataResult) { 94 // TODO: (hml) 2018-04-26 95 // fix how --quiet and --verbose are handled with backup/restore commands 96 // should be ctx.Verbosef() here 97 fmt.Fprintf(ctx.Stdout, "backup ID: %q\n", result.ID) 98 fmt.Fprintf(ctx.Stdout, "checksum: %q\n", result.Checksum) 99 fmt.Fprintf(ctx.Stdout, "checksum format: %q\n", result.ChecksumFormat) 100 fmt.Fprintf(ctx.Stdout, "size (B): %d\n", result.Size) 101 fmt.Fprintf(ctx.Stdout, "stored: %v\n", result.Stored) 102 103 fmt.Fprintf(ctx.Stdout, "started: %v\n", result.Started) 104 fmt.Fprintf(ctx.Stdout, "finished: %v\n", result.Finished) 105 fmt.Fprintf(ctx.Stdout, "notes: %q\n", result.Notes) 106 107 fmt.Fprintf(ctx.Stdout, "model ID: %q\n", result.Model) 108 fmt.Fprintf(ctx.Stdout, "machine ID: %q\n", result.Machine) 109 fmt.Fprintf(ctx.Stdout, "created on host: %q\n", result.Hostname) 110 fmt.Fprintf(ctx.Stdout, "juju version: %v\n", result.Version) 111 } 112 113 // ArchiveReader can read a backup archive. 114 // 115 // To regenerate the mocks for the ArchiveReader used by this package, 116 // run "go generate" from the package directory. 117 //go:generate mockgen -package backups_test -destination mock_test.go github.com/juju/juju/cmd/juju/backups ArchiveReader,APIClient 118 type ArchiveReader interface { 119 io.ReadSeeker 120 io.Closer 121 } 122 123 var getArchive = func(filename string) (rc ArchiveReader, metaResult *params.BackupsMetadataResult, err error) { 124 defer func() { 125 if err != nil && rc != nil { 126 rc.Close() 127 } 128 }() 129 archive, err := os.Open(filename) 130 rc = archive 131 if err != nil { 132 return nil, nil, errors.Trace(err) 133 } 134 135 // Extract the metadata. 136 ad, err := statebackups.NewArchiveDataReader(archive) 137 if err != nil { 138 return nil, nil, errors.Trace(err) 139 } 140 _, err = archive.Seek(0, os.SEEK_SET) 141 if err != nil { 142 return nil, nil, errors.Trace(err) 143 } 144 meta, err := ad.Metadata() 145 if err != nil { 146 if !errors.IsNotFound(err) { 147 return nil, nil, errors.Trace(err) 148 } 149 meta, err = statebackups.BuildMetadata(archive) 150 if err != nil { 151 return nil, nil, errors.Trace(err) 152 } 153 } 154 // Make sure the file info is set. 155 fileMeta, err := statebackups.BuildMetadata(archive) 156 if err != nil { 157 return nil, nil, errors.Trace(err) 158 } 159 if meta.Size() == int64(0) { 160 if err := meta.SetFileInfo(fileMeta.Size(), "", ""); err != nil { 161 return nil, nil, errors.Trace(err) 162 } 163 } 164 if meta.Checksum() == "" { 165 err := meta.SetFileInfo(0, fileMeta.Checksum(), fileMeta.ChecksumFormat()) 166 if err != nil { 167 return nil, nil, errors.Trace(err) 168 } 169 } 170 if meta.Finished == nil || meta.Finished.IsZero() { 171 meta.Finished = fileMeta.Finished 172 } 173 _, err = archive.Seek(0, os.SEEK_SET) 174 if err != nil { 175 return nil, nil, errors.Trace(err) 176 } 177 178 // Pack the metadata into a result. 179 // TODO(perrito666) change the identity of ResultfromMetadata to 180 // return a pointer. 181 mResult := apiserverbackups.CreateResult(meta, "") 182 metaResult = &mResult 183 184 return archive, metaResult, nil 185 }