Skip to content

Commit

Permalink
vSphere Fixed missing clustername issue 7878 (influxdata#8026)
Browse files Browse the repository at this point in the history
  • Loading branch information
prydin authored and idohalevi committed Sep 23, 2020
1 parent 50836ed commit 31a024c
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 24 deletions.
26 changes: 18 additions & 8 deletions plugins/inputs/vsphere/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,11 @@ func (e *Endpoint) getMetadata(ctx context.Context, obj *objectRef, sampling int
return metrics, nil
}

func (e *Endpoint) getDatacenterName(ctx context.Context, client *Client, cache map[string]string, r types.ManagedObjectReference) string {
func (e *Endpoint) getDatacenterName(ctx context.Context, client *Client, cache map[string]string, r types.ManagedObjectReference) (string, bool) {
return e.getAncestorName(ctx, client, "Datacenter", cache, r)
}

func (e *Endpoint) getAncestorName(ctx context.Context, client *Client, resourceType string, cache map[string]string, r types.ManagedObjectReference) (string, bool) {
path := make([]string, 0)
returnVal := ""
here := r
Expand All @@ -370,7 +374,7 @@ func (e *Endpoint) getDatacenterName(ctx context.Context, client *Client, cache
e.Parent.Log.Warnf("Error while resolving parent. Assuming no parent exists. Error: %s", err.Error())
return true
}
if result.Reference().Type == "Datacenter" {
if result.Reference().Type == resourceType {
// Populate cache for the entire chain of objects leading here.
returnVal = result.Name
return true
Expand All @@ -386,7 +390,7 @@ func (e *Endpoint) getDatacenterName(ctx context.Context, client *Client, cache
for _, s := range path {
cache[s] = returnVal
}
return returnVal
return returnVal, returnVal != ""
}

func (e *Endpoint) discover(ctx context.Context) error {
Expand Down Expand Up @@ -436,7 +440,7 @@ func (e *Endpoint) discover(ctx context.Context) error {
if res.name != "Datacenter" {
for k, obj := range objects {
if obj.parentRef != nil {
obj.dcname = e.getDatacenterName(ctx, client, dcNameCache, *obj.parentRef)
obj.dcname, _ = e.getDatacenterName(ctx, client, dcNameCache, *obj.parentRef)
objects[k] = obj
}
}
Expand All @@ -449,11 +453,11 @@ func (e *Endpoint) discover(ctx context.Context) error {
} else {
e.complexMetadataSelect(ctx, res, objects)
}
newObjects[k] = objects

SendInternalCounterWithTags("discovered_objects", e.URL.Host, map[string]string{"type": res.name}, int64(len(objects)))
numRes += int64(len(objects))
}
newObjects[k] = objects

SendInternalCounterWithTags("discovered_objects", e.URL.Host, map[string]string{"type": res.name}, int64(len(objects)))
numRes += int64(len(objects))
}
if err != nil {
e.log.Error(err)
Expand Down Expand Up @@ -639,6 +643,12 @@ func getClusters(ctx context.Context, e *Endpoint, filter *ResourceFilter) (obje
cache[r.Parent.Value] = p
}
}
m[r.ExtensibleManagedObject.Reference().Value] = &objectRef{
name: r.Name,
ref: r.ExtensibleManagedObject.Reference(),
parentRef: p,
customValues: e.loadCustomAttributes(&r.ManagedEntity),
}
return nil
}()
if err != nil {
Expand Down
117 changes: 102 additions & 15 deletions plugins/inputs/vsphere/vsphere_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"context"
"crypto/tls"
"fmt"
"os"
"regexp"
"strings"
"testing"
"time"
"unsafe"
Expand Down Expand Up @@ -150,6 +152,7 @@ func defaultVSphere() *VSphere {
ForceDiscoverOnInit: true,
DiscoverConcurrency: 1,
CollectConcurrency: 1,
Separator: ".",
}
}

Expand Down Expand Up @@ -416,9 +419,10 @@ func TestFolders(t *testing.T) {
defer m.Remove()
defer s.Close()

v := defaultVSphere()
ctx := context.Background()

v := defaultVSphere()

c, err := NewClient(ctx, s.URL, v)

f := Finder{c}
Expand All @@ -440,27 +444,110 @@ func TestFolders(t *testing.T) {
testLookupVM(ctx, t, &f, "/F0/DC1/vm/**/F*/**", 4, "")
}

func TestAll(t *testing.T) {
// Don't run test on 32-bit machines due to bug in simulator.
// https://github.com/vmware/govmomi/issues/1330
var i int
if unsafe.Sizeof(i) < 8 {
return
func TestCollection(t *testing.T) {
testCollection(t, false)
}

func TestCollectionNoClusterMetrics(t *testing.T) {
testCollection(t, true)
}

func testCollection(t *testing.T, excludeClusters bool) {
mustHaveMetrics := map[string]struct{}{
"vsphere.vm.cpu": {},
"vsphere.vm.mem": {},
"vsphere.vm.net": {},
"vsphere.host.cpu": {},
"vsphere.host.mem": {},
"vsphere.host.net": {},
"vsphere.datastore.disk": {},
}
vCenter := os.Getenv("VCENTER_URL")
username := os.Getenv("VCENTER_USER")
password := os.Getenv("VCENTER_PASSWORD")
v := defaultVSphere()
if vCenter != "" {
v.Vcenters = []string{vCenter}
v.Username = username
v.Password = password
} else {

// Don't run test on 32-bit machines due to bug in simulator.
// https://github.com/vmware/govmomi/issues/1330
var i int
if unsafe.Sizeof(i) < 8 {
return
}

m, s, err := createSim(0)
if err != nil {
t.Fatal(err)
m, s, err := createSim(0)
if err != nil {
t.Fatal(err)
}
defer m.Remove()
defer s.Close()
v.Vcenters = []string{s.URL.String()}
}
if excludeClusters {
v.ClusterMetricExclude = []string{"*"}
}
defer m.Remove()
defer s.Close()

var acc testutil.Accumulator
v := defaultVSphere()
v.Vcenters = []string{s.URL.String()}
v.Start(&acc)

require.NoError(t, v.Start(&acc))
defer v.Stop()
require.NoError(t, v.Gather(&acc))
require.Equal(t, 0, len(acc.Errors), fmt.Sprintf("Errors found: %s", acc.Errors))
require.True(t, len(acc.Metrics) > 0, "No metrics were collected")
cache := make(map[string]string)
client, err := v.endpoints[0].clientFactory.GetClient(context.Background())
require.NoError(t, err)
hostCache := make(map[string]string)
for _, m := range acc.Metrics {
delete(mustHaveMetrics, m.Measurement)

if strings.HasPrefix(m.Measurement, "vsphere.vm.") {
mustContainAll(t, m.Tags, []string{"esxhostname", "moid", "vmname", "guest", "dcname", "uuid", "vmname"})
hostName := m.Tags["esxhostname"]
hostMoid, ok := hostCache[hostName]
if !ok {
// We have to follow the host parent path to locate a cluster. Look up the host!
finder := Finder{client}
var hosts []mo.HostSystem
finder.Find(context.Background(), "HostSystem", "/**/"+hostName, &hosts)
require.NotEmpty(t, hosts)
hostMoid = hosts[0].Reference().Value
hostCache[hostName] = hostMoid
}
if isInCluster(t, v, client, cache, "HostSystem", hostMoid) { // If the VM lives in a cluster
mustContainAll(t, m.Tags, []string{"clustername"})
}
} else if strings.HasPrefix(m.Measurement, "vsphere.host.") {
if isInCluster(t, v, client, cache, "HostSystem", m.Tags["moid"]) { // If the host lives in a cluster
mustContainAll(t, m.Tags, []string{"esxhostname", "clustername", "moid", "dcname"})
} else {
mustContainAll(t, m.Tags, []string{"esxhostname", "moid", "dcname"})
}
} else if strings.HasPrefix(m.Measurement, "vsphere.cluster.") {
mustContainAll(t, m.Tags, []string{"clustername", "moid", "dcname"})
} else {
mustContainAll(t, m.Tags, []string{"moid", "dcname"})
}
}
require.Empty(t, mustHaveMetrics, "Some metrics were not found")
}

func isInCluster(t *testing.T, v *VSphere, client *Client, cache map[string]string, resourceKind, moid string) bool {
ctx := context.Background()
ref := types.ManagedObjectReference{
Type: resourceKind,
Value: moid,
}
_, ok := v.endpoints[0].getAncestorName(ctx, client, "ClusterComputeResource", cache, ref)
return ok
}

func mustContainAll(t *testing.T, tagMap map[string]string, mustHave []string) {
for _, tag := range mustHave {
require.Contains(t, tagMap, tag)
}
}
2 changes: 1 addition & 1 deletion plugins/outputs/wavefront/wavefront.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ func (w *Wavefront) buildMetrics(m telegraf.Metric) []*MetricPoint {

metricValue, buildError := buildValue(value, metric.Metric, w)
if buildError != nil {
w.Log.Debug("Error building tags: %s\n", buildError.Error())
w.Log.Debugf("Error building tags: %s\n", buildError.Error())
continue
}
metric.Value = metricValue
Expand Down

0 comments on commit 31a024c

Please sign in to comment.