github.com/vmware/govmomi@v0.51.0/cli/pool/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 pool 6 7 import ( 8 "context" 9 "flag" 10 "fmt" 11 "io" 12 "text/tabwriter" 13 14 "github.com/vmware/govmomi/cli" 15 "github.com/vmware/govmomi/cli/flags" 16 "github.com/vmware/govmomi/find" 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.DatacenterFlag 25 *flags.OutputFlag 26 27 pools bool 28 apps bool 29 } 30 31 func init() { 32 cli.Register("pool.info", &info{}) 33 } 34 35 func (cmd *info) Register(ctx context.Context, f *flag.FlagSet) { 36 cmd.DatacenterFlag, ctx = flags.NewDatacenterFlag(ctx) 37 cmd.DatacenterFlag.Register(ctx, f) 38 cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx) 39 cmd.OutputFlag.Register(ctx, f) 40 41 f.BoolVar(&cmd.pools, "p", true, "List resource pools") 42 f.BoolVar(&cmd.apps, "a", false, "List virtual app resource pools") 43 } 44 45 func (cmd *info) Process(ctx context.Context) error { 46 if err := cmd.DatacenterFlag.Process(ctx); err != nil { 47 return err 48 } 49 if err := cmd.OutputFlag.Process(ctx); err != nil { 50 return err 51 } 52 return nil 53 } 54 55 func (cmd *info) Usage() string { 56 return "POOL..." 57 } 58 59 func (cmd *info) Description() string { 60 return "Retrieve information about one or more resource POOLs.\n" + poolNameHelp 61 } 62 63 func (cmd *info) Run(ctx context.Context, f *flag.FlagSet) error { 64 if f.NArg() == 0 { 65 return flag.ErrHelp 66 } 67 68 c, err := cmd.Client() 69 if err != nil { 70 return err 71 } 72 73 finder, err := cmd.Finder() 74 if err != nil { 75 return err 76 } 77 78 var res infoResult 79 var props []string 80 81 if cmd.OutputFlag.All() { 82 props = nil 83 } else { 84 props = []string{ 85 "name", 86 "config.cpuAllocation", 87 "config.memoryAllocation", 88 "runtime.cpu", 89 "runtime.memory", 90 } 91 } 92 93 var vapps []*object.VirtualApp 94 95 for _, arg := range f.Args() { 96 if cmd.pools { 97 objects, err := finder.ResourcePoolList(ctx, arg) 98 if err != nil { 99 if _, ok := err.(*find.NotFoundError); !ok { 100 return err 101 } 102 } 103 res.objects = append(res.objects, objects...) 104 } 105 106 if cmd.apps { 107 apps, err := finder.VirtualAppList(ctx, arg) 108 if err != nil { 109 if _, ok := err.(*find.NotFoundError); !ok { 110 return err 111 } 112 } 113 vapps = append(vapps, apps...) 114 } 115 } 116 117 if len(res.objects) != 0 { 118 refs := make([]types.ManagedObjectReference, 0, len(res.objects)) 119 for _, o := range res.objects { 120 refs = append(refs, o.Reference()) 121 } 122 123 pc := property.DefaultCollector(c) 124 err = pc.Retrieve(ctx, refs, props, &res.ResourcePools) 125 if err != nil { 126 return err 127 } 128 } 129 130 if len(vapps) != 0 { 131 var apps []mo.VirtualApp 132 refs := make([]types.ManagedObjectReference, 0, len(vapps)) 133 for _, o := range vapps { 134 refs = append(refs, o.Reference()) 135 p := object.NewResourcePool(c, o.Reference()) 136 p.InventoryPath = o.InventoryPath 137 res.objects = append(res.objects, p) 138 } 139 140 pc := property.DefaultCollector(c) 141 err = pc.Retrieve(ctx, refs, props, &apps) 142 if err != nil { 143 return err 144 } 145 146 for _, app := range apps { 147 res.ResourcePools = append(res.ResourcePools, app.ResourcePool) 148 } 149 } 150 151 return cmd.WriteResult(&res) 152 } 153 154 type infoResult struct { 155 ResourcePools []mo.ResourcePool `json:"resourcePools"` 156 objects []*object.ResourcePool 157 } 158 159 func (r *infoResult) Write(w io.Writer) error { 160 // Maintain order via r.objects as Property collector does not always return results in order. 161 objects := make(map[types.ManagedObjectReference]mo.ResourcePool, len(r.ResourcePools)) 162 for _, o := range r.ResourcePools { 163 objects[o.Reference()] = o 164 } 165 166 tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0) 167 168 for _, o := range r.objects { 169 pool := objects[o.Reference()] 170 fmt.Fprintf(tw, "Name:\t%s\n", pool.Name) 171 fmt.Fprintf(tw, " Path:\t%s\n", o.InventoryPath) 172 173 writeInfo(tw, "CPU", "MHz", &pool.Runtime.Cpu, pool.Config.CpuAllocation) 174 pool.Runtime.Memory.MaxUsage >>= 20 175 pool.Runtime.Memory.OverallUsage >>= 20 176 writeInfo(tw, "Mem", "MB", &pool.Runtime.Memory, pool.Config.MemoryAllocation) 177 } 178 179 return tw.Flush() 180 } 181 182 func writeInfo(w io.Writer, name string, units string, ru *types.ResourcePoolResourceUsage, ra types.ResourceAllocationInfo) { 183 usage := 100.0 * float64(ru.OverallUsage) / float64(ru.MaxUsage) 184 shares := "" 185 limit := "unlimited" 186 187 if ra.Shares.Level == types.SharesLevelCustom { 188 shares = fmt.Sprintf(" (%d)", ra.Shares.Shares) 189 } 190 191 if ra.Limit != nil { 192 limit = fmt.Sprintf("%d%s", *ra.Limit, units) 193 } 194 195 fmt.Fprintf(w, " %s Usage:\t%d%s (%0.1f%%)\n", name, ru.OverallUsage, units, usage) 196 fmt.Fprintf(w, " %s Shares:\t%s%s\n", name, ra.Shares.Level, shares) 197 fmt.Fprintf(w, " %s Reservation:\t%d%s (expandable=%v)\n", name, *ra.Reservation, units, *ra.ExpandableReservation) 198 fmt.Fprintf(w, " %s Limit:\t%s\n", name, limit) 199 }