github.com/vmware/govmomi@v0.37.1/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 }