github.com/vmware/govmomi@v0.51.0/cli/datastore/info.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 datastore
     6  
     7  import (
     8  	"context"
     9  	"flag"
    10  	"fmt"
    11  	"io"
    12  	"os"
    13  	"text/tabwriter"
    14  
    15  	"github.com/vmware/govmomi/cli"
    16  	"github.com/vmware/govmomi/cli/flags"
    17  	"github.com/vmware/govmomi/object"
    18  	"github.com/vmware/govmomi/property"
    19  	"github.com/vmware/govmomi/vim25/mo"
    20  	"github.com/vmware/govmomi/vim25/types"
    21  )
    22  
    23  type info struct {
    24  	*flags.ClientFlag
    25  	*flags.OutputFlag
    26  	*flags.DatacenterFlag
    27  
    28  	host bool
    29  }
    30  
    31  func init() {
    32  	cli.Register("datastore.info", &info{})
    33  }
    34  
    35  func (cmd *info) Register(ctx context.Context, f *flag.FlagSet) {
    36  	cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
    37  	cmd.ClientFlag.Register(ctx, f)
    38  
    39  	cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
    40  	cmd.OutputFlag.Register(ctx, f)
    41  
    42  	cmd.DatacenterFlag, ctx = flags.NewDatacenterFlag(ctx)
    43  	cmd.DatacenterFlag.Register(ctx, f)
    44  
    45  	f.BoolVar(&cmd.host, "H", false, "Display info for Datastores shared between hosts")
    46  }
    47  
    48  func (cmd *info) Process(ctx context.Context) error {
    49  	if err := cmd.ClientFlag.Process(ctx); err != nil {
    50  		return err
    51  	}
    52  	if err := cmd.OutputFlag.Process(ctx); err != nil {
    53  		return err
    54  	}
    55  	if err := cmd.DatacenterFlag.Process(ctx); err != nil {
    56  		return err
    57  	}
    58  	return nil
    59  }
    60  
    61  func (cmd *info) Usage() string {
    62  	return "[PATH]..."
    63  }
    64  
    65  func (cmd *info) Description() string {
    66  	return `Display info for Datastores.
    67  
    68  Examples:
    69    govc datastore.info
    70    govc datastore.info vsanDatastore
    71    # info on Datastores shared between cluster hosts:
    72    govc collect -s -d " " /dc1/host/k8s-cluster host | xargs govc datastore.info -H
    73    # info on Datastores shared between VM hosts:
    74    govc ls /dc1/vm/*k8s* | xargs -n1 -I% govc collect -s % summary.runtime.host | xargs govc datastore.info -H`
    75  }
    76  
    77  func intersect(common []types.ManagedObjectReference, refs []types.ManagedObjectReference) []types.ManagedObjectReference {
    78  	var shared []types.ManagedObjectReference
    79  	for i := range common {
    80  		for j := range refs {
    81  			if common[i] == refs[j] {
    82  				shared = append(shared, common[i])
    83  				break
    84  			}
    85  		}
    86  	}
    87  	return shared
    88  }
    89  
    90  func (cmd *info) Run(ctx context.Context, f *flag.FlagSet) error {
    91  	c, err := cmd.Client()
    92  	if err != nil {
    93  		return err
    94  	}
    95  	pc := property.DefaultCollector(c)
    96  
    97  	finder, err := cmd.Finder()
    98  	if err != nil {
    99  		return err
   100  	}
   101  
   102  	args := f.Args()
   103  	if len(args) == 0 {
   104  		args = []string{"*"}
   105  	}
   106  
   107  	var res infoResult
   108  	var props []string
   109  
   110  	if cmd.OutputFlag.All() {
   111  		props = nil // Load everything
   112  	} else {
   113  		props = []string{"info", "summary"} // Load summary
   114  	}
   115  
   116  	if cmd.host {
   117  		if f.NArg() == 0 {
   118  			return flag.ErrHelp
   119  		}
   120  		refs, err := cmd.ManagedObjects(ctx, args)
   121  		if err != nil {
   122  			return err
   123  		}
   124  
   125  		var hosts []mo.HostSystem
   126  		err = pc.Retrieve(ctx, refs, []string{"name", "datastore"}, &hosts)
   127  		if err != nil {
   128  			return err
   129  		}
   130  
   131  		refs = hosts[0].Datastore
   132  		for _, host := range hosts[1:] {
   133  			refs = intersect(refs, host.Datastore)
   134  			if len(refs) == 0 {
   135  				return fmt.Errorf("host %s (%s) has no shared datastores", host.Name, host.Reference())
   136  			}
   137  		}
   138  		for i := range refs {
   139  			ds, err := finder.ObjectReference(ctx, refs[i])
   140  			if err != nil {
   141  				return err
   142  			}
   143  			res.objects = append(res.objects, ds.(*object.Datastore))
   144  		}
   145  	} else {
   146  		for _, arg := range args {
   147  			objects, err := finder.DatastoreList(ctx, arg)
   148  			if err != nil {
   149  				return err
   150  			}
   151  			res.objects = append(res.objects, objects...)
   152  		}
   153  	}
   154  
   155  	if len(res.objects) != 0 {
   156  		refs := make([]types.ManagedObjectReference, 0, len(res.objects))
   157  		for _, o := range res.objects {
   158  			refs = append(refs, o.Reference())
   159  		}
   160  
   161  		err = pc.Retrieve(ctx, refs, props, &res.Datastores)
   162  		if err != nil {
   163  			return err
   164  		}
   165  	}
   166  
   167  	return cmd.WriteResult(&res)
   168  }
   169  
   170  type infoResult struct {
   171  	Datastores []mo.Datastore `json:"datastores"`
   172  	objects    []*object.Datastore
   173  }
   174  
   175  func (r *infoResult) Write(w io.Writer) error {
   176  	// Maintain order via r.objects as Property collector does not always return results in order.
   177  	objects := make(map[types.ManagedObjectReference]mo.Datastore, len(r.Datastores))
   178  	for _, o := range r.Datastores {
   179  		objects[o.Reference()] = o
   180  	}
   181  
   182  	tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0)
   183  
   184  	for _, o := range r.objects {
   185  		ds := objects[o.Reference()]
   186  		s := ds.Summary
   187  		fmt.Fprintf(tw, "Name:\t%s\n", s.Name)
   188  		fmt.Fprintf(tw, "  Path:\t%s\n", o.InventoryPath)
   189  		fmt.Fprintf(tw, "  Type:\t%s\n", s.Type)
   190  		fmt.Fprintf(tw, "  URL:\t%s\n", s.Url)
   191  		fmt.Fprintf(tw, "  Capacity:\t%.1f GB\n", float64(s.Capacity)/(1<<30))
   192  		fmt.Fprintf(tw, "  Free:\t%.1f GB\n", float64(s.FreeSpace)/(1<<30))
   193  
   194  		switch info := ds.Info.(type) {
   195  		case *types.NasDatastoreInfo:
   196  			fmt.Fprintf(tw, "  Remote:\t%s:%s\n", info.Nas.RemoteHost, info.Nas.RemotePath)
   197  		}
   198  	}
   199  
   200  	return tw.Flush()
   201  }