Skip to content

Commit

Permalink
[receiver/vcenterreceiver] Optimize vCenter VM network calls (open-te…
Browse files Browse the repository at this point in the history
…lemetry#32201)

**Description:** <Describe what has changed.>
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue.
Ex. Adding a feature - Explain what this achieves.-->
Changes the method for collecting VMs used by the `vccenterreceiver` to
the more time-efficient `CreateContainerView` method. This is the first
step to addressing the issue linked below.

**Link to tracking Issue:** open-telemetry#31837

**Testing:** These changes were tested on an environment with 200+
virtual machines. The original collection time was ~80 seconds.
Collection times with these changes are ~40 seconds.

**Documentation:** N/A

---------

Co-authored-by: Stefan Kurek <[email protected]>
  • Loading branch information
Caleb-Hurshman and StefanKurek authored Apr 17, 2024
1 parent 0ad3cc9 commit 11d2988
Show file tree
Hide file tree
Showing 16 changed files with 307 additions and 1,578 deletions.
27 changes: 27 additions & 0 deletions .chloggen/feat_faster-vcenter-vm-network-calls.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: vcenterreceiver

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: "Changes process for collecting VMs & VM perf metrics used by the `vccenterreceiver` to be more efficient (one call now for all VMs)"

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [31837]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: [user]
76 changes: 71 additions & 5 deletions receiver/vcenterreceiver/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import (
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/performance"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/view"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/mo"
vt "github.com/vmware/govmomi/vim25/types"
)

Expand All @@ -24,6 +26,7 @@ type vcenterClient struct {
finder *find.Finder
pc *property.Collector
pm *performance.Manager
vm *view.Manager
cfg *Config
}

Expand Down Expand Up @@ -69,6 +72,7 @@ func (vc *vcenterClient) EnsureConnection(ctx context.Context) error {
vc.pc = property.DefaultCollector(vc.vimDriver)
vc.finder = find.NewFinder(vc.vimDriver)
vc.pm = performance.NewManager(vc.vimDriver)
vc.vm = view.NewManager(vc.vimDriver)
return nil
}

Expand All @@ -89,6 +93,7 @@ func (vc *vcenterClient) Datacenters(ctx context.Context) ([]*object.Datacenter,
return datacenters, nil
}

// Computes returns the ComputeResources (and ClusterComputeResources) of the vSphere SDK for a given datacenter
func (vc *vcenterClient) Computes(ctx context.Context, datacenter *object.Datacenter) ([]*object.ComputeResource, error) {
vc.finder = vc.finder.SetDatacenter(datacenter)
computes, err := vc.finder.ComputeResourceList(ctx, "*")
Expand All @@ -98,7 +103,7 @@ func (vc *vcenterClient) Computes(ctx context.Context, datacenter *object.Datace
return computes, nil
}

// ResourcePools returns the resourcePools in the vSphere SDK
// ResourcePools returns the ResourcePools in the vSphere SDK
func (vc *vcenterClient) ResourcePools(ctx context.Context) ([]*object.ResourcePool, error) {
rps, err := vc.finder.ResourcePoolList(ctx, "*")
if err != nil {
Expand All @@ -107,19 +112,47 @@ func (vc *vcenterClient) ResourcePools(ctx context.Context) ([]*object.ResourceP
return rps, err
}

func (vc *vcenterClient) VMs(ctx context.Context) ([]*object.VirtualMachine, error) {
vms, err := vc.finder.VirtualMachineList(ctx, "*")
func (vc *vcenterClient) VMs(ctx context.Context) ([]mo.VirtualMachine, error) {
v, err := vc.vm.CreateContainerView(ctx, vc.vimDriver.ServiceContent.RootFolder, []string{"VirtualMachine"}, true)
if err != nil {
return nil, fmt.Errorf("unable to retrieve vms: %w", err)
return nil, fmt.Errorf("unable to retrieve VMs: %w", err)
}
return vms, err

var vms []mo.VirtualMachine
err = v.Retrieve(ctx, []string{"VirtualMachine"}, []string{
"config.hardware.numCPU",
"config.instanceUuid",
"runtime.powerState",
"runtime.maxCpuUsage",
"summary.quickStats.guestMemoryUsage",
"summary.quickStats.balloonedMemory",
"summary.quickStats.swappedMemory",
"summary.quickStats.ssdSwappedMemory",
"summary.quickStats.overallCpuUsage",
"summary.config.memorySizeMB",
"summary.config.name",
"summary.storage.committed",
"summary.storage.uncommitted",
"summary.runtime.host",
"resourcePool",
}, &vms)
if err != nil {
return nil, fmt.Errorf("unable to retrieve VMs: %w", err)
}

return vms, nil
}

type perfSampleResult struct {
counters map[string]*vt.PerfCounterInfo
results []performance.EntityMetric
}

type perfMetricsQueryResult struct {
counters map[string]*vt.PerfCounterInfo
resultsByMoRef map[string]*performance.EntityMetric
}

func (vc *vcenterClient) performanceQuery(
ctx context.Context,
spec vt.PerfQuerySpec,
Expand Down Expand Up @@ -147,3 +180,36 @@ func (vc *vcenterClient) performanceQuery(
results: result,
}, nil
}

func (vc *vcenterClient) perfMetricsQuery(
ctx context.Context,
spec vt.PerfQuerySpec,
names []string,
objs []vt.ManagedObjectReference,
) (*perfMetricsQueryResult, error) {
if vc.pm == nil {
return &perfMetricsQueryResult{}, nil
}
vc.pm.Sort = true
sample, err := vc.pm.SampleByName(ctx, spec, names, objs)
if err != nil {
return nil, err
}
result, err := vc.pm.ToMetricSeries(ctx, sample)
if err != nil {
return nil, err
}
counterInfoByName, err := vc.pm.CounterInfoByName(ctx)
if err != nil {
return nil, err
}

resultsByMoRef := map[string]*performance.EntityMetric{}
for i := range result {
resultsByMoRef[result[i].Entity.Value] = &result[i]
}
return &perfMetricsQueryResult{
counters: counterInfoByName,
resultsByMoRef: resultsByMoRef,
}, nil
}
3 changes: 3 additions & 0 deletions receiver/vcenterreceiver/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/session"
"github.com/vmware/govmomi/simulator"
"github.com/vmware/govmomi/view"
"github.com/vmware/govmomi/vim25"
"go.opentelemetry.io/collector/config/configopaque"
"go.opentelemetry.io/collector/config/configtls"
Expand Down Expand Up @@ -48,10 +49,12 @@ func TestGetResourcePools(t *testing.T) {

func TestGetVMs(t *testing.T) {
simulator.Test(func(ctx context.Context, c *vim25.Client) {
viewManager := view.NewManager(c)
finder := find.NewFinder(c)
client := vcenterClient{
vimDriver: c,
finder: finder,
vm: viewManager,
}
vms, err := client.VMs(ctx)
require.NoError(t, err)
Expand Down
32 changes: 10 additions & 22 deletions receiver/vcenterreceiver/internal/mockserver/client_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ func routeBody(t *testing.T, requestType string, body map[string]any) ([]byte, e
return routeRetreiveProperties(t, body)
case "QueryPerf":
return routePerformanceQuery(t, body)
case "CreateContainerView":
return loadResponse("create-container-view.xml")
}

return []byte{}, errNotFound
Expand Down Expand Up @@ -163,7 +165,7 @@ func routeRetreiveProperties(t *testing.T, body map[string]any) ([]byte, error)
case contentType == "HostSystem":
if ps, ok := propSet["pathSet"].([]any); ok {
for _, v := range ps {
if v == "summary.hardware" {
if v == "summary.hardware" || v == "summary.hardware.cpuMhz" {
return loadResponse("host-properties.xml")
}
}
Expand All @@ -179,26 +181,8 @@ func routeRetreiveProperties(t *testing.T, body map[string]any) ([]byte, error)

}

case content == "group-v4" && contentType == "Folder":
if propSetArray {
return loadResponse("vm-group.xml")
}
if propSet == nil {
return loadResponse("vm-folder.xml")
}
return loadResponse("vm-folder-parent.xml")

case content == "vm-1040" && contentType == "VirtualMachine":
if propSet["pathSet"] == "summary.runtime.host" {
return loadResponse("vm-host.xml")
}
if propSet["pathSet"] == "resourcePool" {
return loadResponse("vm-resource-pool.xml")
}
return loadResponse("vm-properties.xml")

case (content == "group-v1034" || content == "group-v1001") && contentType == "Folder":
return loadResponse("vm-empty-folder.xml")
case contentType == "ContainerView" && propSet["type"] == "VirtualMachine":
return loadResponse("vm-default-properties.xml")

case contentType == "ResourcePool":
if ps, ok := propSet["pathSet"].([]any); ok {
Expand Down Expand Up @@ -238,7 +222,11 @@ func routeRetreiveProperties(t *testing.T, body map[string]any) ([]byte, error)
func routePerformanceQuery(t *testing.T, body map[string]any) ([]byte, error) {
queryPerf := body["QueryPerf"].(map[string]any)
require.NotNil(t, queryPerf)
querySpec := queryPerf["querySpec"].(map[string]any)
querySpec, ok := queryPerf["querySpec"].(map[string]any)
if !ok {
querySpecs := queryPerf["querySpec"].([]any)
querySpec = querySpecs[0].(map[string]any)
}
entity := querySpec["entity"].(map[string]any)
switch entity["-type"] {
case "HostSystem":
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<RetrievePropertiesResponse xmlns="urn:vim25"></RetrievePropertiesResponse>
<CreateContainerViewResponse xmlns="urn:vim25">
<returnval type="ContainerView">session[5279c748-1a9c-e5f0-cc05-71b15da3a8a6]529d3b1c-0a03-30d0-f0c8-8cae2cc07d25</returnval>
</CreateContainerViewResponse>
</soapenv:Body>
</soapenv:Envelope>
</soapenv:Envelope>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
<RetrievePropertiesResponse xmlns="urn:vim25">
<returnval>
<obj type="HostSystem">host-1002</obj>
<propSet>
<name>name</name>
<val xsi:type="xsd:string">esxi-27971.cf5e88ac.australia-southeast1.gve.goog</val>
</propSet>
<propSet>
<name>summary.hardware.cpuMhz</name>
<val xsi:type="xsd:int">2593</val>
</propSet>
<propSet>
<name>config</name>
<val xsi:type="HostConfigInfo">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<RetrievePropertiesResponse xmlns="urn:vim25">
<returnval>
<obj type="VirtualMachine">vm-1040</obj>
<propSet>
<name>config.hardware.numCPU</name>
<val xsi:type="xsd:int">4</val>
</propSet>
<propSet>
<name>config.instanceUuid</name>
<val xsi:type="xsd:string">5000bbe0-993e-5813-c56a-198eaa62fb61</val>
</propSet>
<propSet>
<name>resourcePool</name>
<val type="ResourcePool" xsi:type="ManagedObjectReference">resgroup-9</val>
</propSet>
<propSet>
<name>runtime.maxCpuUsage</name>
<val xsi:type="xsd:int">10372</val>
</propSet>
<propSet>
<name>runtime.powerState</name>
<val xsi:type="VirtualMachinePowerState">poweredOn</val>
</propSet>
<propSet>
<name>summary.config.memorySizeMB</name>
<val xsi:type="xsd:int">16384</val>
</propSet>
<propSet>
<name>summary.config.name</name>
<val xsi:type="xsd:string">CentOS 7</val>
</propSet>
<propSet>
<name>summary.quickStats.balloonedMemory</name>
<val xsi:type="xsd:int">0</val>
</propSet>
<propSet>
<name>summary.quickStats.guestMemoryUsage</name>
<val xsi:type="xsd:int">163</val>
</propSet>
<propSet>
<name>summary.quickStats.overallCpuUsage</name>
<val xsi:type="xsd:int">12</val>
</propSet>
<propSet>
<name>summary.quickStats.ssdSwappedMemory</name>
<val xsi:type="xsd:long">0</val>
</propSet>
<propSet>
<name>summary.quickStats.swappedMemory</name>
<val xsi:type="xsd:int">0</val>
</propSet>
<propSet>
<name>summary.runtime.host</name>
<val type="HostSystem" xsi:type="ManagedObjectReference">host-1002</val>
</propSet>
<propSet>
<name>summary.storage.committed</name>
<val xsi:type="xsd:long">16311648256</val>
</propSet>
<propSet>
<name>summary.storage.uncommitted</name>
<val xsi:type="xsd:long">258847277056</val>
</propSet>
</returnval>
</RetrievePropertiesResponse>
</soapenv:Body>
</soapenv:Envelope>

This file was deleted.

Loading

0 comments on commit 11d2988

Please sign in to comment.