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  }