github.com/vmware/govmomi@v0.37.2/govc/datastore/info.go (about)

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