github.com/vmware/govmomi@v0.37.2/govc/cluster/usage.go (about)

     1  /*
     2  Copyright (c) 2020-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 cluster
    18  
    19  import (
    20  	"context"
    21  	"flag"
    22  	"fmt"
    23  	"io"
    24  	"text/tabwriter"
    25  
    26  	"github.com/vmware/govmomi/govc/cli"
    27  	"github.com/vmware/govmomi/govc/flags"
    28  	"github.com/vmware/govmomi/property"
    29  	"github.com/vmware/govmomi/units"
    30  	"github.com/vmware/govmomi/vim25/mo"
    31  )
    32  
    33  type usage struct {
    34  	*flags.DatacenterFlag
    35  
    36  	shared bool
    37  }
    38  
    39  func init() {
    40  	cli.Register("cluster.usage", &usage{})
    41  }
    42  
    43  func (cmd *usage) Register(ctx context.Context, f *flag.FlagSet) {
    44  	cmd.DatacenterFlag, ctx = flags.NewDatacenterFlag(ctx)
    45  	cmd.DatacenterFlag.Register(ctx, f)
    46  
    47  	f.BoolVar(&cmd.shared, "S", false, "Exclude host local storage")
    48  }
    49  
    50  func (cmd *usage) Usage() string {
    51  	return "CLUSTER"
    52  }
    53  
    54  func (cmd *usage) Description() string {
    55  	return `Cluster resource usage summary.
    56  
    57  Examples:
    58    govc cluster.usage ClusterName
    59    govc cluster.usage -S ClusterName # summarize shared storage only
    60    govc cluster.usage -json ClusterName | jq -r .cpu.summary.usage`
    61  }
    62  
    63  func (cmd *usage) Run(ctx context.Context, f *flag.FlagSet) error {
    64  	finder, err := cmd.Finder()
    65  	if err != nil {
    66  		return err
    67  	}
    68  
    69  	obj, err := finder.ClusterComputeResource(ctx, f.Arg(0))
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	var res Usage
    75  	var cluster mo.ClusterComputeResource
    76  	var hosts []mo.HostSystem
    77  	var datastores []mo.Datastore
    78  
    79  	pc := property.DefaultCollector(obj.Client())
    80  
    81  	err = pc.RetrieveOne(ctx, obj.Reference(), []string{"datastore", "host"}, &cluster)
    82  	if err != nil {
    83  		return err
    84  	}
    85  
    86  	err = pc.Retrieve(ctx, cluster.Host, []string{"summary"}, &hosts)
    87  	if err != nil {
    88  		return err
    89  	}
    90  
    91  	for _, host := range hosts {
    92  		res.CPU.Capacity += int64(int32(host.Summary.Hardware.NumCpuCores) * host.Summary.Hardware.CpuMhz)
    93  		res.CPU.Used += int64(host.Summary.QuickStats.OverallCpuUsage)
    94  
    95  		res.Memory.Capacity += host.Summary.Hardware.MemorySize
    96  		res.Memory.Used += int64(host.Summary.QuickStats.OverallMemoryUsage) << 20
    97  	}
    98  
    99  	err = pc.Retrieve(ctx, cluster.Datastore, []string{"summary"}, &datastores)
   100  	if err != nil {
   101  		return err
   102  	}
   103  
   104  	for _, datastore := range datastores {
   105  		shared := datastore.Summary.MultipleHostAccess
   106  		if cmd.shared && shared != nil && *shared == false {
   107  			continue
   108  		}
   109  
   110  		res.Storage.Capacity += datastore.Summary.Capacity
   111  		res.Storage.Free += datastore.Summary.FreeSpace
   112  	}
   113  
   114  	res.CPU.Free = res.CPU.Capacity - res.CPU.Used
   115  	res.CPU.summarize(ghz)
   116  
   117  	res.Memory.Free = res.Memory.Capacity - res.Memory.Used
   118  	res.Memory.summarize(size)
   119  
   120  	res.Storage.Used = res.Storage.Capacity - res.Storage.Free
   121  	res.Storage.summarize(size)
   122  
   123  	return cmd.WriteResult(&res)
   124  }
   125  
   126  type ResourceUsageSummary struct {
   127  	Used     string `json:"used"`
   128  	Free     string `json:"free"`
   129  	Capacity string `json:"capacity"`
   130  	Usage    string `json:"usage"`
   131  }
   132  
   133  type ResourceUsage struct {
   134  	Used     int64                `json:"used"`
   135  	Free     int64                `json:"free"`
   136  	Capacity int64                `json:"capacity"`
   137  	Usage    float64              `json:"usage"`
   138  	Summary  ResourceUsageSummary `json:"summary"`
   139  }
   140  
   141  func (r *ResourceUsage) summarize(f func(int64) string) {
   142  	r.Usage = 100 * float64(r.Used) / float64(r.Capacity)
   143  
   144  	r.Summary.Usage = fmt.Sprintf("%.1f", r.Usage)
   145  	r.Summary.Capacity = f(r.Capacity)
   146  	r.Summary.Used = f(r.Used)
   147  	r.Summary.Free = f(r.Free)
   148  }
   149  
   150  func (r *ResourceUsage) write(w io.Writer, label string) {
   151  	fmt.Fprintf(w, "%s usage:\t%s%%\n", label, r.Summary.Usage)
   152  	fmt.Fprintf(w, "%s capacity:\t%s\n", label, r.Summary.Capacity)
   153  	fmt.Fprintf(w, "%s used:\t%s\n", label, r.Summary.Used)
   154  	fmt.Fprintf(w, "%s free:\t%s\n", label, r.Summary.Free)
   155  }
   156  
   157  func ghz(val int64) string {
   158  	return fmt.Sprintf("%.1fGHz", float64(val)/1000)
   159  }
   160  
   161  func size(val int64) string {
   162  	return units.ByteSize(val).String()
   163  }
   164  
   165  type Usage struct {
   166  	Memory  ResourceUsage `json:"memory"`
   167  	CPU     ResourceUsage `json:"cpu"`
   168  	Storage ResourceUsage `json:"storage"`
   169  }
   170  
   171  func (r *Usage) Write(w io.Writer) error {
   172  	tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0)
   173  
   174  	r.CPU.write(tw, "CPU")
   175  	fmt.Fprintf(tw, "\t\n")
   176  
   177  	r.Memory.write(tw, "Memory")
   178  	fmt.Fprintf(tw, "\t\n")
   179  
   180  	r.Storage.write(tw, "Storage")
   181  
   182  	return tw.Flush()
   183  }