github.com/vmware/govmomi@v0.43.0/govc/library/export.go (about) 1 /* 2 Copyright (c) 2019 VMware, Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package library 18 19 import ( 20 "context" 21 "flag" 22 "fmt" 23 "io" 24 "net/url" 25 "os" 26 "path/filepath" 27 "time" 28 29 "github.com/vmware/govmomi/govc/cli" 30 "github.com/vmware/govmomi/govc/flags" 31 "github.com/vmware/govmomi/vapi/library" 32 "github.com/vmware/govmomi/vim25/soap" 33 ) 34 35 type export struct { 36 *flags.ClientFlag 37 *flags.OutputFlag 38 library.Item 39 } 40 41 func init() { 42 cli.Register("library.export", &export{}) 43 } 44 45 func (cmd *export) Register(ctx context.Context, f *flag.FlagSet) { 46 cmd.ClientFlag, ctx = flags.NewClientFlag(ctx) 47 cmd.ClientFlag.Register(ctx, f) 48 49 cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx) 50 cmd.OutputFlag.Register(ctx, f) 51 } 52 53 func (cmd *export) Usage() string { 54 return "PATH [DEST]" 55 } 56 57 func (cmd *export) Description() string { 58 return `Export library items. 59 60 If the given PATH is a library item, all files will be downloaded. 61 62 If the given PATH is a library item file, only that file will be downloaded. 63 64 By default, files are saved using the library item's file names to the current directory. 65 If DEST is given for a library item, files are saved there instead of the current directory. 66 If DEST is given for a library item file, the file will be saved with that name. 67 If DEST is '-', the file contents are written to stdout instead of saving to a file. 68 69 Examples: 70 govc library.export library_name/item_name 71 govc library.export library_name/item_name/file_name 72 govc library.export library_name/item_name/*.ovf -` 73 } 74 75 func (cmd *export) Process(ctx context.Context) error { 76 if err := cmd.ClientFlag.Process(ctx); err != nil { 77 return err 78 } 79 return cmd.OutputFlag.Process(ctx) 80 } 81 82 func (cmd *export) Run(ctx context.Context, f *flag.FlagSet) error { 83 c, err := cmd.RestClient() 84 if err != nil { 85 return err 86 } 87 cmd.KeepAlive(c) 88 89 var names []string 90 m := library.NewManager(c) 91 res, err := flags.ContentLibraryResult(ctx, c, "", f.Arg(0)) 92 if err != nil { 93 return err 94 } 95 96 switch t := res.GetResult().(type) { 97 case library.Item: 98 cmd.Item = t 99 case library.File: 100 names = []string{t.Name} 101 cmd.Item = res.GetParent().GetResult().(library.Item) 102 default: 103 return fmt.Errorf("%q is a %T", f.Arg(0), t) 104 } 105 106 dst := f.Arg(1) 107 one := len(names) == 1 108 var log io.Writer = os.Stdout 109 isStdout := one && dst == "-" 110 if isStdout { 111 log = io.Discard 112 } 113 114 session, err := m.CreateLibraryItemDownloadSession(ctx, library.Session{ 115 LibraryItemID: cmd.ID, 116 }) 117 if err != nil { 118 return err 119 } 120 121 if len(names) == 0 { 122 files, err := m.ListLibraryItemDownloadSessionFile(ctx, session) 123 if err != nil { 124 return err 125 } 126 127 for _, file := range files { 128 names = append(names, file.Name) 129 } 130 } 131 132 for _, name := range names { 133 _, err = m.PrepareLibraryItemDownloadSessionFile(ctx, session, name) 134 if err != nil { 135 return err 136 } 137 } 138 139 download := func(src *url.URL, name string) error { 140 p := soap.DefaultDownload 141 142 if isStdout { 143 s, _, err := c.Download(ctx, src, &p) 144 if err != nil { 145 return err 146 } 147 _, err = io.Copy(os.Stdout, s) 148 _ = s.Close() 149 return err 150 } 151 152 if cmd.OutputFlag.TTY { 153 logger := cmd.ProgressLogger(fmt.Sprintf("Downloading %s... ", src.String())) 154 defer logger.Wait() 155 p.Progress = logger 156 } 157 158 if one && dst != "" { 159 name = dst 160 } else { 161 name = filepath.Join(dst, name) 162 } 163 return c.DownloadFile(ctx, name, src, &p) 164 } 165 166 for _, name := range names { 167 var info *library.DownloadFile 168 _, _ = fmt.Fprintf(log, "Checking %s... ", name) 169 for { 170 info, err = m.GetLibraryItemDownloadSessionFile(ctx, session, name) 171 if err != nil { 172 return err 173 } 174 if info.Status == "PREPARED" { 175 _, _ = fmt.Fprintln(log, info.Status) 176 break // with this status we have a DownloadEndpoint.URI 177 } 178 time.Sleep(time.Second) 179 } 180 181 src, err := url.Parse(info.DownloadEndpoint.URI) 182 if err != nil { 183 return err 184 } 185 err = download(src, name) 186 if err != nil { 187 return err 188 } 189 } 190 191 return nil 192 }