github.com/vmware/govmomi@v0.51.0/simulator/performance_manager_test.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 simulator
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  	"fmt"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/vmware/govmomi/performance"
    15  	"github.com/vmware/govmomi/simulator/esx"
    16  	"github.com/vmware/govmomi/simulator/vpx"
    17  	"github.com/vmware/govmomi/vim25/mo"
    18  	"github.com/vmware/govmomi/vim25/types"
    19  )
    20  
    21  func testMetricsConsistency(counterInfo []types.PerfCounterInfo, ids [][]types.PerfMetricId) error {
    22  
    23  	// Build a lookup table for speed and convenience
    24  	lookup := make(map[int32]bool, len(counterInfo))
    25  	for _, pc := range counterInfo {
    26  		lookup[pc.Key] = true
    27  	}
    28  
    29  	// Check metric ids against map
    30  	for _, list := range ids {
    31  		for _, id := range list {
    32  			if _, ok := lookup[id.CounterId]; !ok {
    33  				return fmt.Errorf("Counter with ID %d not found in PerfCounter", id.CounterId)
    34  			}
    35  		}
    36  	}
    37  	return nil
    38  }
    39  
    40  func TestMetricsConsistency(t *testing.T) {
    41  	esxIds := [][]types.PerfMetricId{esx.VmMetrics, esx.HostMetrics, esx.ResourcePoolMetrics}
    42  	vpxIds := [][]types.PerfMetricId{vpx.VmMetrics, vpx.HostMetrics, vpx.ClusterMetrics,
    43  		vpx.DatastoreMetrics, vpx.ResourcePoolMetrics}
    44  	if err := testMetricsConsistency(esx.PerfCounter, esxIds); err != nil {
    45  		t.Fatal(err)
    46  	}
    47  	if err := testMetricsConsistency(vpx.PerfCounter, vpxIds); err != nil {
    48  		t.Fatal(err)
    49  	}
    50  }
    51  
    52  func checkDuplicates(ids []types.PerfMetricId) error {
    53  	m := make(map[string]bool, len(ids))
    54  	for _, id := range ids {
    55  		k := fmt.Sprintf("%d|%s", id.CounterId, id.Instance)
    56  		if _, ok := m[k]; ok {
    57  			return fmt.Errorf("Duplicate metric key: %s", k)
    58  		}
    59  		m[k] = true
    60  	}
    61  	return nil
    62  }
    63  
    64  func TestMetricsDuplicates(t *testing.T) {
    65  	if err := checkDuplicates(esx.VmMetrics); err != nil {
    66  		t.Fatal(err)
    67  	}
    68  	if err := checkDuplicates(esx.HostMetrics); err != nil {
    69  		t.Fatal(err)
    70  	}
    71  	if err := checkDuplicates(vpx.VmMetrics); err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	if err := checkDuplicates(vpx.HostMetrics); err != nil {
    75  		t.Fatal(err)
    76  	}
    77  	if err := checkDuplicates(vpx.ClusterMetrics); err != nil {
    78  		t.Fatal(err)
    79  	}
    80  	if err := checkDuplicates(vpx.DatastoreMetrics); err != nil {
    81  		t.Fatal(err)
    82  	}
    83  }
    84  
    85  func TestQueryProviderSummary(t *testing.T) {
    86  	m := VPX()
    87  
    88  	err := m.Create()
    89  	if err != nil {
    90  		t.Fatal(err)
    91  	}
    92  
    93  	defer m.Remove()
    94  
    95  	c := m.Service.client()
    96  
    97  	p := performance.NewManager(c)
    98  	ctx := m.Service.Context
    99  
   100  	vm := ctx.Map.Any("VirtualMachine").(*VirtualMachine)
   101  	if info, err := p.ProviderSummary(ctx, vm.Reference()); err != nil {
   102  		t.Fatal(err)
   103  	} else {
   104  		if info.RefreshRate != 20 {
   105  			t.Fatalf("VM wefresh rate is %d, should be 20", info.RefreshRate)
   106  		}
   107  	}
   108  
   109  	host := ctx.Map.Any("HostSystem").(*HostSystem)
   110  	if info, err := p.ProviderSummary(ctx, host.Reference()); err != nil {
   111  		t.Fatal(err)
   112  	} else {
   113  		if info.RefreshRate != 20 {
   114  			t.Fatalf("Host refresh rate is %d, should be 20", info.RefreshRate)
   115  		}
   116  	}
   117  
   118  	pool := ctx.Map.Any("ResourcePool").(*ResourcePool)
   119  	if info, err := p.ProviderSummary(ctx, pool.Reference()); err != nil {
   120  		t.Fatal(err)
   121  	} else {
   122  		if info.RefreshRate != 20 {
   123  			t.Fatalf("ResourcePool refresh rate is %d, should be 20", info.RefreshRate)
   124  		}
   125  	}
   126  
   127  	cluster := ctx.Map.Any("ClusterComputeResource").(*ClusterComputeResource)
   128  	if info, err := p.ProviderSummary(ctx, cluster.Reference()); err != nil {
   129  		t.Fatal(err)
   130  	} else {
   131  		if info.RefreshRate != -1 {
   132  			t.Fatalf("Cluster refresh rate is %d, should be -1", info.RefreshRate)
   133  		}
   134  	}
   135  
   136  	datastore := ctx.Map.Any("Datastore").(*Datastore)
   137  	if info, err := p.ProviderSummary(ctx, datastore.Reference()); err != nil {
   138  		t.Fatal(err)
   139  	} else {
   140  		if info.RefreshRate != -1 {
   141  			t.Fatalf("Datastore refresh rate is %d, should be -1", info.RefreshRate)
   142  		}
   143  	}
   144  
   145  	nonExistent := types.ManagedObjectReference{
   146  		Type:  "Not a valid type",
   147  		Value: "This object doesn't exist",
   148  	}
   149  	if _, err := p.ProviderSummary(ctx, nonExistent); err == nil {
   150  		t.Fatal("This should have failed (nonexistent object)")
   151  	}
   152  }
   153  
   154  func TestQueryAvailablePerfMetric(t *testing.T) {
   155  	m := VPX()
   156  
   157  	err := m.Create()
   158  	if err != nil {
   159  		t.Fatal(err)
   160  	}
   161  
   162  	defer m.Remove()
   163  
   164  	c := m.Service.client()
   165  	p := performance.NewManager(c)
   166  	ctx := m.Service.Context
   167  
   168  	vm := ctx.Map.Any("VirtualMachine").(*VirtualMachine)
   169  	if info, err := p.AvailableMetric(ctx, vm.Reference(), 20); err != nil {
   170  		t.Fatal(err)
   171  	} else {
   172  		if len(info) == 0 {
   173  			t.Fatal("Expected non-empty list of vm")
   174  		}
   175  	}
   176  
   177  	host := ctx.Map.Any("HostSystem").(*HostSystem)
   178  	if info, err := p.AvailableMetric(ctx, host.Reference(), 20); err != nil {
   179  		t.Fatal(err)
   180  	} else {
   181  		if len(info) == 0 {
   182  			t.Fatal("Expected non-empty list of host")
   183  		}
   184  		var ids []int32
   185  		for i := range info {
   186  			ids = append(ids, info[i].CounterId)
   187  		}
   188  		perf, err := p.QueryCounter(ctx, ids)
   189  		if err != nil {
   190  			t.Fatal(err)
   191  		}
   192  		if len(perf) != len(ids) {
   193  			t.Errorf("%d counters", len(perf))
   194  		}
   195  	}
   196  
   197  	pool := ctx.Map.Any("ResourcePool").(*ResourcePool)
   198  	if info, err := p.AvailableMetric(ctx, pool.Reference(), 20); err != nil {
   199  		t.Fatal(err)
   200  	} else {
   201  		if len(info) == 0 {
   202  			t.Fatal("Expected non-empty list of resource pool")
   203  		}
   204  	}
   205  
   206  	cluster := ctx.Map.Any("ClusterComputeResource").(*ClusterComputeResource)
   207  	if info, err := p.AvailableMetric(ctx, cluster.Reference(), 300); err != nil {
   208  		t.Fatal(err)
   209  	} else {
   210  		if len(info) == 0 {
   211  			t.Fatal("Expected non-empty list of clusters")
   212  		}
   213  	}
   214  
   215  	if info, err := p.AvailableMetric(ctx, cluster.Reference(), 20); err != nil {
   216  		t.Fatal(err)
   217  	} else {
   218  		if len(info) != 0 {
   219  			t.Fatal("Expected empty list of clusters")
   220  		}
   221  	}
   222  
   223  	ds := ctx.Map.Any("Datastore").(*Datastore)
   224  	if info, err := p.AvailableMetric(ctx, ds.Reference(), 300); err != nil {
   225  		t.Fatal(err)
   226  	} else {
   227  		if len(info) == 0 {
   228  			t.Fatal("Expected non-empty list of datastores")
   229  		}
   230  	}
   231  
   232  	if info, err := p.AvailableMetric(ctx, ds.Reference(), 20); err != nil {
   233  		t.Fatal(err)
   234  	} else {
   235  		if len(info) != 0 {
   236  			t.Fatal("Expected empty list of datastores")
   237  		}
   238  	}
   239  
   240  	dc := ctx.Map.Any("Datacenter").(*Datacenter)
   241  	if info, err := p.AvailableMetric(ctx, dc.Reference(), 300); err != nil {
   242  		t.Fatal(err)
   243  	} else {
   244  		if len(info) == 0 {
   245  			t.Fatal("Expected non-empty list of datacenters")
   246  		}
   247  	}
   248  
   249  	if info, err := p.AvailableMetric(ctx, dc.Reference(), 20); err != nil {
   250  		t.Fatal(err)
   251  	} else {
   252  		if len(info) != 0 {
   253  			t.Fatal("Expected empty list of datacenters")
   254  		}
   255  	}
   256  
   257  }
   258  
   259  func testPerfQuery(ctx context.Context, m *Model, e mo.Entity, interval int32, maxSample int32) error {
   260  	c := m.Service.client()
   261  
   262  	p := performance.NewManager(c)
   263  
   264  	// Single metric, single VM
   265  	//
   266  	qs := []types.PerfQuerySpec{
   267  		{
   268  			MaxSample:  maxSample,
   269  			IntervalId: interval,
   270  			MetricId:   []types.PerfMetricId{{CounterId: 1, Instance: ""}},
   271  			Entity:     e.Reference(),
   272  		},
   273  	}
   274  	result, err := p.Query(ctx, qs)
   275  	if err != nil {
   276  		return err
   277  	}
   278  	if len(result) == 0 {
   279  		return errors.New("Empty result set")
   280  	}
   281  	ms, err := p.ToMetricSeries(ctx, result)
   282  	if err != nil {
   283  		return err
   284  	}
   285  	if len(ms) == 0 {
   286  		return errors.New("Empty metric series")
   287  	}
   288  	for _, em := range ms {
   289  		if len(em.SampleInfo) == 0 {
   290  			return errors.New("Empty SampleInfo")
   291  		}
   292  	}
   293  
   294  	return nil
   295  }
   296  
   297  func testPerfQueryCSV(ctx context.Context, m *Model, e mo.Entity, interval int32, maxSample int32) error {
   298  	c := m.Service.client()
   299  
   300  	p := performance.NewManager(c)
   301  
   302  	// Single metric, single VM
   303  	//
   304  	qs := []types.PerfQuerySpec{
   305  		{
   306  			MaxSample:  maxSample,
   307  			IntervalId: interval,
   308  			MetricId:   []types.PerfMetricId{{CounterId: 1, Instance: ""}},
   309  			Entity:     e.Reference(),
   310  			Format:     string(types.PerfFormatCsv),
   311  		},
   312  	}
   313  	series, err := p.Query(ctx, qs)
   314  	if err != nil {
   315  		return err
   316  	}
   317  	if len(series) == 0 {
   318  		return errors.New("Empty result set")
   319  	}
   320  	for i := range series {
   321  		s, ok := series[i].(*types.PerfEntityMetricCSV)
   322  		if !ok {
   323  			panic(fmt.Errorf("expected type %T, got: %T", s, series[i]))
   324  		}
   325  		if len(s.SampleInfoCSV) == 0 {
   326  			return errors.New("Empty SampleInfoCSV")
   327  		}
   328  		if len(strings.Split(s.SampleInfoCSV, ",")) == 0 {
   329  			return errors.New("SampleInfoCSV not in CSV format")
   330  		}
   331  		for _, v := range s.Value {
   332  			if len(v.Value) == 0 {
   333  				return errors.New("Empty PerfEntityMetricCSV.Value")
   334  			}
   335  			if len(strings.Split(v.Value, ",")) == 0 {
   336  				return errors.New("PerfEntityMetricCSV.Value not in CSV format")
   337  			}
   338  		}
   339  	}
   340  
   341  	return nil
   342  }
   343  
   344  func TestQueryPerf(t *testing.T) {
   345  	m := VPX()
   346  
   347  	err := m.Create()
   348  	if err != nil {
   349  		t.Fatal(err)
   350  	}
   351  
   352  	defer m.Remove()
   353  
   354  	ctx := m.Service.Context
   355  
   356  	for _, maxSample := range []int32{4, 0} {
   357  		if err := testPerfQuery(ctx, m, ctx.Map.Any("VirtualMachine"), 20, maxSample); err != nil {
   358  			t.Fatal(err)
   359  		}
   360  		if err := testPerfQuery(ctx, m, ctx.Map.Any("HostSystem"), 20, maxSample); err != nil {
   361  			t.Fatal(err)
   362  		}
   363  		if err := testPerfQuery(ctx, m, ctx.Map.Any("ClusterComputeResource"), 300, maxSample); err != nil {
   364  			t.Fatal(err)
   365  		}
   366  		if err := testPerfQuery(ctx, m, ctx.Map.Any("Datastore"), 300, maxSample); err != nil {
   367  			t.Fatal(err)
   368  		}
   369  		if err := testPerfQuery(ctx, m, ctx.Map.Any("Datacenter"), 300, maxSample); err != nil {
   370  			t.Fatal(err)
   371  		}
   372  		if err := testPerfQuery(ctx, m, ctx.Map.Any("ResourcePool"), 300, maxSample); err != nil {
   373  			t.Fatal(err)
   374  		}
   375  
   376  		//csv format
   377  		if err := testPerfQueryCSV(ctx, m, ctx.Map.Any("VirtualMachine"), 20, maxSample); err != nil {
   378  			t.Fatal(err)
   379  		}
   380  		if err := testPerfQueryCSV(ctx, m, ctx.Map.Any("HostSystem"), 20, maxSample); err != nil {
   381  			t.Fatal(err)
   382  		}
   383  		if err := testPerfQueryCSV(ctx, m, ctx.Map.Any("ClusterComputeResource"), 300, maxSample); err != nil {
   384  			t.Fatal(err)
   385  		}
   386  		if err := testPerfQueryCSV(ctx, m, ctx.Map.Any("Datastore"), 300, maxSample); err != nil {
   387  			t.Fatal(err)
   388  		}
   389  		if err := testPerfQueryCSV(ctx, m, ctx.Map.Any("Datacenter"), 300, maxSample); err != nil {
   390  			t.Fatal(err)
   391  		}
   392  		if err := testPerfQueryCSV(ctx, m, ctx.Map.Any("ResourcePool"), 300, maxSample); err != nil {
   393  			t.Fatal(err)
   394  		}
   395  	}
   396  }