github.com/vmware/govmomi@v0.51.0/cli/metric/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 metric
     6  
     7  import (
     8  	"context"
     9  	"encoding/json"
    10  	"flag"
    11  	"fmt"
    12  	"io"
    13  	"strings"
    14  	"text/tabwriter"
    15  
    16  	"github.com/vmware/govmomi/cli"
    17  	"github.com/vmware/govmomi/vim25/types"
    18  )
    19  
    20  type info struct {
    21  	*PerformanceFlag
    22  	group string
    23  }
    24  
    25  func init() {
    26  	cli.Register("metric.info", &info{})
    27  }
    28  
    29  func (cmd *info) Register(ctx context.Context, f *flag.FlagSet) {
    30  	cmd.PerformanceFlag, ctx = NewPerformanceFlag(ctx)
    31  	cmd.PerformanceFlag.Register(ctx, f)
    32  
    33  	f.StringVar(&cmd.group, "g", "", "Show info for a specific Group")
    34  }
    35  
    36  func (cmd *info) Usage() string {
    37  	return "PATH [NAME]..."
    38  }
    39  
    40  func (cmd *info) Description() string {
    41  	return `Metric info for NAME.
    42  
    43  If PATH is a value other than '-', provider summary and instance list are included
    44  for the given object type.
    45  
    46  If NAME is not specified, all available metrics for the given INTERVAL are listed.
    47  An object PATH must be provided in this case.
    48  
    49  Examples:
    50    govc metric.info vm/my-vm
    51    govc metric.info -i 300 vm/my-vm
    52    govc metric.info - cpu.usage.average
    53    govc metric.info /dc1/host/cluster cpu.usage.average`
    54  }
    55  
    56  func (cmd *info) Process(ctx context.Context) error {
    57  	if err := cmd.PerformanceFlag.Process(ctx); err != nil {
    58  		return err
    59  	}
    60  	return nil
    61  }
    62  
    63  type EntityDetail struct {
    64  	Realtime   bool     `json:"realtime"`
    65  	Historical bool     `json:"historical"`
    66  	Instance   []string `json:"instance"`
    67  }
    68  
    69  type MetricInfo struct {
    70  	Counter          *types.PerfCounterInfo `json:"counter"`
    71  	Enabled          []string               `json:"enabled"`
    72  	PerDeviceEnabled []string               `json:"perDeviceEnabled"`
    73  	Detail           *EntityDetail          `json:"detail"`
    74  }
    75  
    76  type infoResult struct {
    77  	Info []*MetricInfo `json:"info"`
    78  	cmd  *info
    79  }
    80  
    81  func (r *infoResult) Write(w io.Writer) error {
    82  	tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0)
    83  
    84  	for _, info := range r.Info {
    85  		counter := info.Counter
    86  
    87  		fmt.Fprintf(tw, "Name:\t%s\n", counter.Name())
    88  		fmt.Fprintf(tw, "  Label:\t%s\n", counter.NameInfo.GetElementDescription().Label)
    89  		fmt.Fprintf(tw, "  Summary:\t%s\n", counter.NameInfo.GetElementDescription().Summary)
    90  		fmt.Fprintf(tw, "  Group:\t%s\n", counter.GroupInfo.GetElementDescription().Label)
    91  		fmt.Fprintf(tw, "  Unit:\t%s\n", counter.UnitInfo.GetElementDescription().Label)
    92  		fmt.Fprintf(tw, "  Rollup type:\t%s\n", counter.RollupType)
    93  		fmt.Fprintf(tw, "  Stats type:\t%s\n", counter.StatsType)
    94  		fmt.Fprintf(tw, "  Level:\t%d\n", counter.Level)
    95  		fmt.Fprintf(tw, "    Intervals:\t%s\n", strings.Join(info.Enabled, ","))
    96  		fmt.Fprintf(tw, "  Per-device level:\t%d\n", counter.PerDeviceLevel)
    97  		fmt.Fprintf(tw, "    Intervals:\t%s\n", strings.Join(info.PerDeviceEnabled, ","))
    98  
    99  		summary := info.Detail
   100  		if summary == nil {
   101  			continue
   102  		}
   103  
   104  		fmt.Fprintf(tw, "  Realtime:\t%t\n", summary.Realtime)
   105  		fmt.Fprintf(tw, "  Historical:\t%t\n", summary.Historical)
   106  		fmt.Fprintf(tw, "  Instances:\t%s\n", strings.Join(summary.Instance, ","))
   107  	}
   108  
   109  	return tw.Flush()
   110  }
   111  
   112  func (r *infoResult) MarshalJSON() ([]byte, error) {
   113  	m := make(map[string]*MetricInfo)
   114  
   115  	for _, info := range r.Info {
   116  		m[info.Counter.Name()] = info
   117  	}
   118  
   119  	return json.Marshal(m)
   120  }
   121  
   122  func (cmd *info) Run(ctx context.Context, f *flag.FlagSet) error {
   123  	if f.NArg() == 0 {
   124  		return flag.ErrHelp
   125  	}
   126  
   127  	names := f.Args()[1:]
   128  
   129  	m, err := cmd.Manager(ctx)
   130  	if err != nil {
   131  		return err
   132  	}
   133  
   134  	counters, err := m.CounterInfoByName(ctx)
   135  	if err != nil {
   136  		return err
   137  	}
   138  
   139  	intervals, err := m.HistoricalInterval(ctx)
   140  	if err != nil {
   141  		return err
   142  	}
   143  	enabled := intervals.Enabled()
   144  
   145  	var summary *types.PerfProviderSummary
   146  	var mids map[int32][]*types.PerfMetricId
   147  
   148  	if f.Arg(0) == "-" {
   149  		if len(names) == 0 {
   150  			return flag.ErrHelp
   151  		}
   152  	} else {
   153  		objs, err := cmd.ManagedObjects(ctx, f.Args()[:1])
   154  		if err != nil {
   155  			return err
   156  		}
   157  
   158  		summary, err = m.ProviderSummary(ctx, objs[0])
   159  		if err != nil {
   160  			return err
   161  		}
   162  
   163  		all, err := m.AvailableMetric(ctx, objs[0], cmd.Interval(summary.RefreshRate))
   164  		if err != nil {
   165  			return err
   166  		}
   167  
   168  		mids = all.ByKey()
   169  
   170  		if len(names) == 0 {
   171  			nc, _ := m.CounterInfoByKey(ctx)
   172  
   173  			seen := make(map[int32]bool)
   174  			for i := range all {
   175  				id := &all[i]
   176  				info, ok := nc[id.CounterId]
   177  				if !ok || seen[id.CounterId] {
   178  					continue
   179  				}
   180  				seen[id.CounterId] = true
   181  
   182  				names = append(names, info.Name())
   183  			}
   184  		}
   185  	}
   186  
   187  	var metrics []*MetricInfo
   188  
   189  	for _, name := range names {
   190  		counter, ok := counters[name]
   191  		if !ok {
   192  			return cmd.ErrNotFound(name)
   193  		}
   194  
   195  		if cmd.group != "" {
   196  			if counter.GroupInfo.GetElementDescription().Label != cmd.group {
   197  				continue
   198  			}
   199  		}
   200  
   201  		info := &MetricInfo{
   202  			Counter:          counter,
   203  			Enabled:          enabled[counter.Level],
   204  			PerDeviceEnabled: enabled[counter.PerDeviceLevel],
   205  		}
   206  
   207  		metrics = append(metrics, info)
   208  
   209  		if summary == nil {
   210  			continue
   211  		}
   212  
   213  		var instances []string
   214  
   215  		for _, id := range mids[counter.Key] {
   216  			if id.Instance != "" {
   217  				instances = append(instances, id.Instance)
   218  			}
   219  		}
   220  
   221  		info.Detail = &EntityDetail{
   222  			Realtime:   summary.CurrentSupported,
   223  			Historical: summary.SummarySupported,
   224  			Instance:   instances,
   225  		}
   226  
   227  	}
   228  
   229  	return cmd.WriteResult(&infoResult{metrics, cmd})
   230  }