github.com/vmware/govmomi@v0.37.2/simulator/performance_manager_test.go (about)

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