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