github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/cmd/juju/backups/upload.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 apiserverbackups "github.com/juju/juju/apiserver/backups" 16 "github.com/juju/juju/apiserver/params" 17 "github.com/juju/juju/state/backups" 18 ) 19 20 const uploadDoc = ` 21 "upload" sends a backup archive file to remote storage. 22 ` 23 24 // UploadCommand is the sub-command for uploading a backup archive. 25 type UploadCommand struct { 26 CommandBase 27 // Filename is where to find the archive to upload. 28 Filename string 29 // ShowMeta indicates that the uploaded metadata should be printed. 30 ShowMeta bool 31 // Quiet indicates that the new backup ID should not be printed. 32 Quiet bool 33 } 34 35 // SetFlags implements Command.SetFlags. 36 func (c *UploadCommand) SetFlags(f *gnuflag.FlagSet) { 37 f.BoolVar(&c.ShowMeta, "verbose", false, "show the uploaded metadata") 38 f.BoolVar(&c.Quiet, "quiet", false, "do not print the new backup ID") 39 } 40 41 // Info implements Command.Info. 42 func (c *UploadCommand) Info() *cmd.Info { 43 return &cmd.Info{ 44 Name: "upload", 45 Args: "<filename>", 46 Purpose: "store a backup archive file remotely in juju", 47 Doc: uploadDoc, 48 } 49 } 50 51 // Init implements Command.Init. 52 func (c *UploadCommand) Init(args []string) error { 53 if len(args) == 0 { 54 return errors.New("backup filename not specified") 55 } 56 filename, args := args[0], args[1:] 57 if err := cmd.CheckEmpty(args); err != nil { 58 return errors.Trace(err) 59 } 60 c.Filename = filename 61 return nil 62 } 63 64 // Run implements Command.Run. 65 func (c *UploadCommand) Run(ctx *cmd.Context) error { 66 client, err := c.NewAPIClient() 67 if err != nil { 68 return errors.Trace(err) 69 } 70 defer client.Close() 71 72 archive, meta, err := c.getArchive(c.Filename) 73 if err != nil { 74 return errors.Trace(err) 75 } 76 defer archive.Close() 77 78 if c.ShowMeta { 79 fmt.Fprintln(ctx.Stdout, "Uploaded metadata:") 80 c.dumpMetadata(ctx, meta) 81 fmt.Fprintln(ctx.Stdout) 82 } 83 84 // Upload the archive. 85 id, err := client.Upload(archive, *meta) 86 if err != nil { 87 return errors.Trace(err) 88 } 89 90 if c.Quiet { 91 fmt.Fprintln(ctx.Stdout, id) 92 return nil 93 } 94 95 // Pull the stored metadata. 96 stored, err := c.getStoredMetadata(id) 97 if err != nil { 98 return errors.Trace(err) 99 } 100 101 c.dumpMetadata(ctx, stored) 102 return nil 103 } 104 105 func (c *UploadCommand) getStoredMetadata(id string) (*params.BackupsMetadataResult, error) { 106 // TODO(ericsnow) lp-1399722 This should be addressed. 107 // There is at least anecdotal evidence that we cannot use an API 108 // client for more than a single request. So we use a new client 109 // for download. 110 client, err := c.NewAPIClient() 111 if err != nil { 112 return nil, errors.Trace(err) 113 } 114 defer client.Close() 115 116 stored, err := client.Info(id) 117 return stored, errors.Trace(err) 118 } 119 120 func (c *UploadCommand) getArchive(filename string) (io.ReadCloser, *params.BackupsMetadataResult, error) { 121 122 archive, err := os.Open(filename) 123 if err != nil { 124 return nil, nil, errors.Trace(err) 125 } 126 127 // Extract the metadata. 128 ad, err := backups.NewArchiveDataReader(archive) 129 if err != nil { 130 return nil, nil, errors.Trace(err) 131 } 132 _, err = archive.Seek(0, os.SEEK_SET) 133 if err != nil { 134 return nil, nil, errors.Trace(err) 135 } 136 meta, err := ad.Metadata() 137 if err != nil { 138 if !errors.IsNotFound(err) { 139 return nil, nil, errors.Trace(err) 140 } 141 meta, err = backups.BuildMetadata(archive) 142 if err != nil { 143 return nil, nil, errors.Trace(err) 144 } 145 } else { 146 // Make sure the file info is set. 147 fileMeta, err := backups.BuildMetadata(archive) 148 if err != nil { 149 return nil, nil, errors.Trace(err) 150 } 151 if meta.Size() == int64(0) { 152 if err := meta.SetFileInfo(fileMeta.Size(), "", ""); err != nil { 153 return nil, nil, errors.Trace(err) 154 } 155 } 156 if meta.Checksum() == "" { 157 err := meta.SetFileInfo(0, fileMeta.Checksum(), fileMeta.ChecksumFormat()) 158 if err != nil { 159 return nil, nil, errors.Trace(err) 160 } 161 } 162 if meta.Finished == nil || meta.Finished.IsZero() { 163 meta.Finished = fileMeta.Finished 164 } 165 } 166 _, err = archive.Seek(0, os.SEEK_SET) 167 if err != nil { 168 return nil, nil, errors.Trace(err) 169 } 170 171 // Pack the metadata into a result. 172 metaResult := apiserverbackups.ResultFromMetadata(meta) 173 174 return archive, &metaResult, nil 175 }