github.com/vmware/govmomi@v0.51.0/cli/flags/datastore.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 flags 6 7 import ( 8 "context" 9 "flag" 10 "fmt" 11 "net/url" 12 "os" 13 14 "github.com/vmware/govmomi/object" 15 "github.com/vmware/govmomi/vapi/library" 16 "github.com/vmware/govmomi/vapi/library/finder" 17 "github.com/vmware/govmomi/vim25/types" 18 ) 19 20 type DatastoreFlag struct { 21 common 22 23 *DatacenterFlag 24 25 Name string 26 27 ds *object.Datastore 28 } 29 30 var datastoreFlagKey = flagKey("datastore") 31 32 // NewCustomDatastoreFlag creates and returns a new DatastoreFlag without 33 // trying to retrieve an existing one from the specified context. 34 func NewCustomDatastoreFlag(ctx context.Context) (*DatastoreFlag, context.Context) { 35 v := &DatastoreFlag{} 36 v.DatacenterFlag, ctx = NewDatacenterFlag(ctx) 37 return v, ctx 38 } 39 40 func NewDatastoreFlag(ctx context.Context) (*DatastoreFlag, context.Context) { 41 if v := ctx.Value(datastoreFlagKey); v != nil { 42 return v.(*DatastoreFlag), ctx 43 } 44 45 v, ctx := NewCustomDatastoreFlag(ctx) 46 ctx = context.WithValue(ctx, datastoreFlagKey, v) 47 return v, ctx 48 } 49 50 func (f *DatastoreFlag) Register(ctx context.Context, fs *flag.FlagSet) { 51 f.RegisterOnce(func() { 52 f.DatacenterFlag.Register(ctx, fs) 53 54 env := "GOVC_DATASTORE" 55 value := os.Getenv(env) 56 usage := fmt.Sprintf("Datastore [%s]", env) 57 fs.StringVar(&f.Name, "ds", value, usage) 58 }) 59 } 60 61 func (f *DatastoreFlag) Process(ctx context.Context) error { 62 return f.ProcessOnce(func() error { 63 if err := f.DatacenterFlag.Process(ctx); err != nil { 64 return err 65 } 66 return nil 67 }) 68 } 69 70 func (flag *DatastoreFlag) IsSet() bool { 71 return flag.Name != "" 72 } 73 74 func (f *DatastoreFlag) Args(args []string) []object.DatastorePath { 75 var files []object.DatastorePath 76 77 for _, arg := range args { 78 var p object.DatastorePath 79 80 if p.FromString(arg) { 81 f.Name = p.Datastore 82 } else { 83 p.Datastore = f.Name 84 p.Path = arg 85 } 86 87 files = append(files, p) 88 } 89 90 return files 91 } 92 93 func (f *DatastoreFlag) Datastore() (*object.Datastore, error) { 94 if f.ds != nil { 95 return f.ds, nil 96 } 97 98 var p object.DatastorePath 99 if p.FromString(f.Name) { 100 // Example use case: 101 // -ds "$(govc object.collect -s vm/foo config.files.logDirectory)" 102 f.Name = p.Datastore 103 } 104 105 finder, err := f.Finder() 106 if err != nil { 107 return nil, err 108 } 109 110 if f.ds, err = finder.DatastoreOrDefault(context.TODO(), f.Name); err != nil { 111 return nil, err 112 } 113 114 return f.ds, nil 115 } 116 117 func (flag *DatastoreFlag) DatastoreIfSpecified() (*object.Datastore, error) { 118 if flag.Name == "" { 119 return nil, nil 120 } 121 return flag.Datastore() 122 } 123 124 func (f *DatastoreFlag) DatastorePath(name string) (string, error) { 125 ds, err := f.Datastore() 126 if err != nil { 127 return "", err 128 } 129 130 return ds.Path(name), nil 131 } 132 133 func (f *DatastoreFlag) Stat(ctx context.Context, file string) (types.BaseFileInfo, error) { 134 ds, err := f.Datastore() 135 if err != nil { 136 return nil, err 137 } 138 139 return ds.Stat(ctx, file) 140 141 } 142 143 func (f *DatastoreFlag) libraryPath(ctx context.Context, p string) (string, error) { 144 vc, err := f.Client() 145 if err != nil { 146 return "", err 147 } 148 149 rc, err := f.RestClient() 150 if err != nil { 151 return "", err 152 } 153 154 m := library.NewManager(rc) 155 156 r, err := finder.NewFinder(m).Find(ctx, p) 157 if err != nil { 158 return "", err 159 } 160 161 if len(r) != 1 { 162 return "", fmt.Errorf("%s: %d found", p, len(r)) 163 } 164 165 return finder.NewPathFinder(m, vc).Path(ctx, r[0]) 166 } 167 168 // FileBacking converts the given file path for use as VirtualDeviceFileBackingInfo.FileName. 169 func (f *DatastoreFlag) FileBacking(ctx context.Context, file string, stat bool) (string, error) { 170 u, err := url.Parse(file) 171 if err != nil { 172 return "", err 173 } 174 175 switch u.Scheme { 176 case "library": 177 return f.libraryPath(ctx, u.Path) 178 case "ds": 179 // datastore url, e.g. ds:///vmfs/volumes/$uuid/... 180 return file, nil 181 } 182 183 var p object.DatastorePath 184 if p.FromString(file) { 185 // datastore is specified 186 return file, nil 187 } 188 189 if stat { 190 // Verify ISO exists 191 if _, err := f.Stat(ctx, file); err != nil { 192 return "", err 193 } 194 } 195 196 return f.DatastorePath(file) 197 }