github.com/vmware/govmomi@v0.43.0/govc/flags/search.go (about)

     1  /*
     2  Copyright (c) 2014-2016 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 flags
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"flag"
    23  	"fmt"
    24  	"strings"
    25  
    26  	"github.com/vmware/govmomi/find"
    27  	"github.com/vmware/govmomi/object"
    28  	"github.com/vmware/govmomi/vim25"
    29  	"github.com/vmware/govmomi/vim25/soap"
    30  	"github.com/vmware/govmomi/vim25/types"
    31  )
    32  
    33  const (
    34  	SearchVirtualMachines = iota + 1
    35  	SearchHosts
    36  	SearchVirtualApps
    37  )
    38  
    39  type SearchFlag struct {
    40  	common
    41  
    42  	*ClientFlag
    43  	*DatacenterFlag
    44  
    45  	t      int
    46  	entity string
    47  
    48  	byDatastorePath string
    49  	byDNSName       string
    50  	byInventoryPath string
    51  	byIP            string
    52  	byUUID          string
    53  
    54  	isset bool
    55  }
    56  
    57  func NewSearchFlag(ctx context.Context, t int) (*SearchFlag, context.Context) {
    58  	searchFlagKey := flagKey(fmt.Sprintf("search%d", t))
    59  
    60  	if v := ctx.Value(searchFlagKey); v != nil {
    61  		return v.(*SearchFlag), ctx
    62  	}
    63  
    64  	v := &SearchFlag{
    65  		t: t,
    66  	}
    67  
    68  	v.ClientFlag, ctx = NewClientFlag(ctx)
    69  	v.DatacenterFlag, ctx = NewDatacenterFlag(ctx)
    70  
    71  	switch t {
    72  	case SearchVirtualMachines:
    73  		v.entity = "VM"
    74  	case SearchHosts:
    75  		v.entity = "host"
    76  	case SearchVirtualApps:
    77  		v.entity = "vapp"
    78  	default:
    79  		panic("invalid search type")
    80  	}
    81  
    82  	ctx = context.WithValue(ctx, searchFlagKey, v)
    83  	return v, ctx
    84  }
    85  
    86  func (flag *SearchFlag) Register(ctx context.Context, fs *flag.FlagSet) {
    87  	flag.RegisterOnce(func() {
    88  		flag.ClientFlag.Register(ctx, fs)
    89  		flag.DatacenterFlag.Register(ctx, fs)
    90  
    91  		register := func(v *string, f string, d string) {
    92  			f = fmt.Sprintf("%s.%s", strings.ToLower(flag.entity), f)
    93  			d = fmt.Sprintf(d, flag.entity)
    94  			fs.StringVar(v, f, "", d)
    95  		}
    96  
    97  		switch flag.t {
    98  		case SearchVirtualMachines:
    99  			register(&flag.byDatastorePath, "path", "Find %s by path to .vmx file")
   100  		}
   101  
   102  		switch flag.t {
   103  		case SearchVirtualMachines, SearchHosts:
   104  			register(&flag.byDNSName, "dns", "Find %s by FQDN")
   105  			register(&flag.byIP, "ip", "Find %s by IP address")
   106  			register(&flag.byUUID, "uuid", "Find %s by UUID")
   107  		}
   108  
   109  		register(&flag.byInventoryPath, "ipath", "Find %s by inventory path")
   110  	})
   111  }
   112  
   113  func (flag *SearchFlag) Process(ctx context.Context) error {
   114  	return flag.ProcessOnce(func() error {
   115  		if err := flag.ClientFlag.Process(ctx); err != nil {
   116  			return err
   117  		}
   118  		if err := flag.DatacenterFlag.Process(ctx); err != nil {
   119  			return err
   120  		}
   121  
   122  		flags := []string{
   123  			flag.byDatastorePath,
   124  			flag.byDNSName,
   125  			flag.byInventoryPath,
   126  			flag.byIP,
   127  			flag.byUUID,
   128  		}
   129  
   130  		flag.isset = false
   131  		for _, f := range flags {
   132  			if f != "" {
   133  				if flag.isset {
   134  					return errors.New("cannot use more than one search flag")
   135  				}
   136  				flag.isset = true
   137  			}
   138  		}
   139  
   140  		return nil
   141  	})
   142  }
   143  
   144  func (flag *SearchFlag) IsSet() bool {
   145  	return flag.isset
   146  }
   147  
   148  func (flag *SearchFlag) searchIndex(c *vim25.Client) *object.SearchIndex {
   149  	return object.NewSearchIndex(c)
   150  }
   151  
   152  func (flag *SearchFlag) searchByDatastorePath(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) {
   153  	ctx := context.TODO()
   154  	switch flag.t {
   155  	case SearchVirtualMachines:
   156  		return flag.searchIndex(c).FindByDatastorePath(ctx, dc, flag.byDatastorePath)
   157  	default:
   158  		panic("unsupported type")
   159  	}
   160  }
   161  
   162  func (flag *SearchFlag) searchByDNSName(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) {
   163  	ctx := context.TODO()
   164  	switch flag.t {
   165  	case SearchVirtualMachines:
   166  		return flag.searchIndex(c).FindByDnsName(ctx, dc, flag.byDNSName, true)
   167  	case SearchHosts:
   168  		return flag.searchIndex(c).FindByDnsName(ctx, dc, flag.byDNSName, false)
   169  	default:
   170  		panic("unsupported type")
   171  	}
   172  }
   173  
   174  func (flag *SearchFlag) searchByInventoryPath(c *vim25.Client) (object.Reference, error) {
   175  	ctx := context.TODO()
   176  	return flag.searchIndex(c).FindByInventoryPath(ctx, flag.byInventoryPath)
   177  }
   178  
   179  func (flag *SearchFlag) searchByIP(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) {
   180  	ctx := context.TODO()
   181  	switch flag.t {
   182  	case SearchVirtualMachines:
   183  		return flag.searchIndex(c).FindByIp(ctx, dc, flag.byIP, true)
   184  	case SearchHosts:
   185  		return flag.searchIndex(c).FindByIp(ctx, dc, flag.byIP, false)
   186  	default:
   187  		panic("unsupported type")
   188  	}
   189  }
   190  
   191  func (flag *SearchFlag) searchByUUID(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) {
   192  	ctx := context.TODO()
   193  	isVM := false
   194  	switch flag.t {
   195  	case SearchVirtualMachines:
   196  		isVM = true
   197  	case SearchHosts:
   198  	default:
   199  		panic("unsupported type")
   200  	}
   201  
   202  	var ref object.Reference
   203  	var err error
   204  
   205  	for _, iu := range []*bool{nil, types.NewBool(true)} {
   206  		ref, err = flag.searchIndex(c).FindByUuid(ctx, dc, flag.byUUID, isVM, iu)
   207  		if err != nil {
   208  			if soap.IsSoapFault(err) {
   209  				fault := soap.ToSoapFault(err).VimFault()
   210  				if _, ok := fault.(types.InvalidArgument); ok {
   211  					continue
   212  				}
   213  			}
   214  			return nil, err
   215  		}
   216  		if ref != nil {
   217  			break
   218  		}
   219  	}
   220  
   221  	return ref, nil
   222  }
   223  
   224  func (flag *SearchFlag) search() (object.Reference, error) {
   225  	ctx := context.TODO()
   226  	var ref object.Reference
   227  	var err error
   228  	var dc *object.Datacenter
   229  
   230  	c, err := flag.Client()
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  
   235  	isPath := flag.byInventoryPath != ""
   236  	if !isPath {
   237  		// All other SearchIndex methods require a Datacenter param
   238  		dc, err = flag.Datacenter()
   239  		if err != nil {
   240  			return nil, err
   241  		}
   242  	}
   243  
   244  	switch {
   245  	case isPath:
   246  		ref, err = flag.searchByInventoryPath(c)
   247  	case flag.byDatastorePath != "":
   248  		ref, err = flag.searchByDatastorePath(c, dc)
   249  	case flag.byDNSName != "":
   250  		ref, err = flag.searchByDNSName(c, dc)
   251  	case flag.byIP != "":
   252  		ref, err = flag.searchByIP(c, dc)
   253  	case flag.byUUID != "":
   254  		ref, err = flag.searchByUUID(c, dc)
   255  	default:
   256  		err = errors.New("no search flag specified")
   257  	}
   258  
   259  	if err != nil {
   260  		return nil, err
   261  	}
   262  
   263  	if ref == nil {
   264  		return nil, fmt.Errorf("no such %s", flag.entity)
   265  	}
   266  
   267  	// set the InventoryPath field
   268  	finder, err := flag.Finder()
   269  	if err != nil {
   270  		return nil, err
   271  	}
   272  	ref, err = finder.ObjectReference(ctx, ref.Reference())
   273  	if err != nil {
   274  		return nil, err
   275  	}
   276  
   277  	return ref, nil
   278  }
   279  
   280  func (flag *SearchFlag) VirtualMachine() (*object.VirtualMachine, error) {
   281  	ref, err := flag.search()
   282  	if err != nil {
   283  		return nil, err
   284  	}
   285  
   286  	vm, ok := ref.(*object.VirtualMachine)
   287  	if !ok {
   288  		return nil, fmt.Errorf("expected VirtualMachine entity, got %s", ref.Reference().Type)
   289  	}
   290  
   291  	return vm, nil
   292  }
   293  
   294  func (flag *SearchFlag) VirtualMachines(args []string) ([]*object.VirtualMachine, error) {
   295  	ctx := context.TODO()
   296  	var out []*object.VirtualMachine
   297  
   298  	if flag.IsSet() {
   299  		vm, err := flag.VirtualMachine()
   300  		if err != nil {
   301  			return nil, err
   302  		}
   303  
   304  		out = append(out, vm)
   305  		return out, nil
   306  	}
   307  
   308  	// List virtual machines
   309  	if len(args) == 0 {
   310  		return nil, errors.New("no argument")
   311  	}
   312  
   313  	finder, err := flag.Finder()
   314  	if err != nil {
   315  		return nil, err
   316  	}
   317  
   318  	var nfe error
   319  
   320  	// List virtual machines for every argument
   321  	for _, arg := range args {
   322  		vms, err := finder.VirtualMachineList(ctx, arg)
   323  		if err != nil {
   324  			if _, ok := err.(*find.NotFoundError); ok {
   325  				// Let caller decide how to handle NotFoundError
   326  				nfe = err
   327  				continue
   328  			}
   329  			return nil, err
   330  		}
   331  
   332  		out = append(out, vms...)
   333  	}
   334  
   335  	return out, nfe
   336  }
   337  
   338  func (flag *SearchFlag) VirtualApp() (*object.VirtualApp, error) {
   339  	ref, err := flag.search()
   340  	if err != nil {
   341  		return nil, err
   342  	}
   343  
   344  	app, ok := ref.(*object.VirtualApp)
   345  	if !ok {
   346  		return nil, fmt.Errorf("expected VirtualApp entity, got %s", ref.Reference().Type)
   347  	}
   348  
   349  	return app, nil
   350  }
   351  
   352  func (flag *SearchFlag) VirtualApps(args []string) ([]*object.VirtualApp, error) {
   353  	ctx := context.TODO()
   354  	var out []*object.VirtualApp
   355  
   356  	if flag.IsSet() {
   357  		app, err := flag.VirtualApp()
   358  		if err != nil {
   359  			return nil, err
   360  		}
   361  
   362  		out = append(out, app)
   363  		return out, nil
   364  	}
   365  
   366  	// List virtual apps
   367  	if len(args) == 0 {
   368  		return nil, errors.New("no argument")
   369  	}
   370  
   371  	finder, err := flag.Finder()
   372  	if err != nil {
   373  		return nil, err
   374  	}
   375  
   376  	// List virtual apps for every argument
   377  	for _, arg := range args {
   378  		apps, err := finder.VirtualAppList(ctx, arg)
   379  		if err != nil {
   380  			return nil, err
   381  		}
   382  
   383  		out = append(out, apps...)
   384  	}
   385  
   386  	return out, nil
   387  }
   388  
   389  func (flag *SearchFlag) HostSystem() (*object.HostSystem, error) {
   390  	ref, err := flag.search()
   391  	if err != nil {
   392  		return nil, err
   393  	}
   394  
   395  	host, ok := ref.(*object.HostSystem)
   396  	if !ok {
   397  		return nil, fmt.Errorf("expected HostSystem entity, got %s", ref.Reference().Type)
   398  	}
   399  
   400  	return host, nil
   401  }
   402  
   403  func (flag *SearchFlag) HostSystems(args []string) ([]*object.HostSystem, error) {
   404  	ctx := context.TODO()
   405  	var out []*object.HostSystem
   406  
   407  	if flag.IsSet() {
   408  		host, err := flag.HostSystem()
   409  		if err != nil {
   410  			return nil, err
   411  		}
   412  
   413  		out = append(out, host)
   414  		return out, nil
   415  	}
   416  
   417  	// List host system
   418  	if len(args) == 0 {
   419  		return nil, errors.New("no argument")
   420  	}
   421  
   422  	finder, err := flag.Finder()
   423  	if err != nil {
   424  		return nil, err
   425  	}
   426  
   427  	// List host systems for every argument
   428  	for _, arg := range args {
   429  		vms, err := finder.HostSystemList(ctx, arg)
   430  		if err != nil {
   431  			return nil, err
   432  		}
   433  
   434  		out = append(out, vms...)
   435  	}
   436  
   437  	return out, nil
   438  }