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 }