github.com/vmware/govmomi@v0.37.1/govc/library/import.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 "errors" 22 "flag" 23 "fmt" 24 "net/url" 25 "os" 26 "path/filepath" 27 "strings" 28 "time" 29 30 "github.com/vmware/govmomi/govc/cli" 31 "github.com/vmware/govmomi/govc/flags" 32 "github.com/vmware/govmomi/govc/importx" 33 "github.com/vmware/govmomi/vapi/library" 34 "github.com/vmware/govmomi/vim25/soap" 35 ) 36 37 type item struct { 38 *flags.ClientFlag 39 *flags.OutputFlag 40 library.Item 41 42 manifest bool 43 pull bool 44 } 45 46 func init() { 47 cli.Register("library.import", &item{}) 48 } 49 50 func (cmd *item) Register(ctx context.Context, f *flag.FlagSet) { 51 cmd.ClientFlag, ctx = flags.NewClientFlag(ctx) 52 cmd.ClientFlag.Register(ctx, f) 53 54 cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx) 55 cmd.OutputFlag.Register(ctx, f) 56 57 f.StringVar(&cmd.Name, "n", "", "Library item name") 58 f.StringVar(&cmd.Type, "t", "", "Library item type") 59 f.BoolVar(&cmd.manifest, "m", false, "Require ova manifest") 60 f.BoolVar(&cmd.pull, "pull", false, "Pull library item from http endpoint") 61 } 62 63 func (cmd *item) Usage() string { 64 return "LIBRARY ITEM" 65 } 66 67 func (cmd *item) Description() string { 68 return `Import library items. 69 70 Examples: 71 govc library.import library_name file.ova 72 govc library.import library_name file.ovf 73 govc library.import library_name file.iso 74 govc library.import library_id file.iso # Use library id if multiple libraries have the same name 75 govc library.import library_name/item_name file.ova # update existing item 76 govc library.import library_name http://example.com/file.ovf # download and push to vCenter 77 govc library.import -pull library_name http://example.com/file.ova # direct pull from vCenter` 78 } 79 80 func (cmd *item) Process(ctx context.Context) error { 81 if err := cmd.ClientFlag.Process(ctx); err != nil { 82 return err 83 } 84 return cmd.OutputFlag.Process(ctx) 85 } 86 87 func (cmd *item) Run(ctx context.Context, f *flag.FlagSet) error { 88 if f.NArg() != 2 { 89 return flag.ErrHelp 90 } 91 92 file := f.Arg(1) 93 base := filepath.Base(file) 94 ext := filepath.Ext(base) 95 mf := strings.Replace(base, ext, ".mf", 1) 96 kind := "" 97 client, err := cmd.Client() 98 if err != nil { 99 return err 100 } 101 opener := importx.Opener{Client: client} 102 archive := &importx.ArchiveFlag{Archive: &importx.FileArchive{Path: file, Opener: opener}} 103 104 manifest := make(map[string]*library.Checksum) 105 if cmd.Name == "" { 106 cmd.Name = strings.TrimSuffix(base, ext) 107 } 108 109 switch ext { 110 case ".ova": 111 archive.Archive = &importx.TapeArchive{Path: file, Opener: opener} 112 base = "*.ovf" 113 mf = "*.mf" 114 kind = library.ItemTypeOVF 115 case ".ovf": 116 kind = library.ItemTypeOVF 117 case ".iso": 118 kind = library.ItemTypeISO 119 } 120 121 if cmd.Type == "" { 122 cmd.Type = kind 123 } 124 125 if !cmd.pull && cmd.Type == library.ItemTypeOVF { 126 f, _, err := archive.Open(mf) 127 if err == nil { 128 sums, err := library.ReadManifest(f) 129 _ = f.Close() 130 if err != nil { 131 return err 132 } 133 manifest = sums 134 } else { 135 msg := fmt.Sprintf("manifest %q: %s", mf, err) 136 if cmd.manifest { 137 return errors.New(msg) 138 } 139 fmt.Fprintln(os.Stderr, msg) 140 } 141 } 142 143 c, err := cmd.RestClient() 144 if err != nil { 145 return err 146 } 147 cmd.KeepAlive(c) 148 149 m := library.NewManager(c) 150 res, err := flags.ContentLibraryResult(ctx, c, "", f.Arg(0)) 151 if err != nil { 152 return err 153 } 154 155 switch t := res.GetResult().(type) { 156 case library.Library: 157 cmd.LibraryID = t.ID 158 cmd.ID, err = m.CreateLibraryItem(ctx, cmd.Item) 159 if err != nil { 160 return err 161 } 162 case library.Item: 163 cmd.Item = t 164 default: 165 return fmt.Errorf("%q is a %T", f.Arg(0), t) 166 } 167 168 session, err := m.CreateLibraryItemUpdateSession(ctx, library.Session{ 169 LibraryItemID: cmd.ID, 170 }) 171 if err != nil { 172 return err 173 } 174 if cmd.pull { 175 _, err = m.AddLibraryItemFileFromURI(ctx, session, filepath.Base(file), file) 176 if err != nil { 177 return err 178 } 179 180 err = m.CompleteLibraryItemUpdateSession(ctx, session) 181 if err != nil { 182 return err 183 } 184 185 return m.WaitOnLibraryItemUpdateSession(ctx, session, 3*time.Second, nil) 186 } 187 188 upload := func(name string) error { 189 f, size, err := archive.Open(name) 190 if err != nil { 191 return err 192 } 193 defer f.Close() 194 195 if e, ok := f.(*importx.TapeArchiveEntry); ok { 196 name = e.Name // expand path.Match's (e.g. "*.ovf" -> "name.ovf") 197 } 198 199 info := library.UpdateFile{ 200 Name: name, 201 SourceType: "PUSH", 202 Checksum: manifest[name], 203 Size: size, 204 } 205 206 update, err := m.AddLibraryItemFile(ctx, session, info) 207 if err != nil { 208 return err 209 } 210 211 p := soap.DefaultUpload 212 p.ContentLength = size 213 u, err := url.Parse(update.UploadEndpoint.URI) 214 if err != nil { 215 return err 216 } 217 if cmd.OutputFlag.TTY { 218 logger := cmd.ProgressLogger(fmt.Sprintf("Uploading %s... ", name)) 219 p.Progress = logger 220 defer logger.Wait() 221 } 222 return c.Upload(ctx, f, u, &p) 223 } 224 225 if err = upload(base); err != nil { 226 return err 227 } 228 229 if cmd.Type == library.ItemTypeOVF { 230 o, err := archive.ReadOvf(base) 231 if err != nil { 232 return err 233 } 234 235 e, err := archive.ReadEnvelope(o) 236 if err != nil { 237 return fmt.Errorf("failed to parse ovf: %s", err) 238 } 239 240 for i := range e.References { 241 if err = upload(e.References[i].Href); err != nil { 242 return err 243 } 244 } 245 } 246 247 return m.CompleteLibraryItemUpdateSession(ctx, session) 248 }