summaryrefslogtreecommitdiffstats
path: root/src/go/collectors/go.d.plugin/modules/vsphere/discover
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 11:19:16 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-07-24 09:53:24 +0000
commitb5f8ee61a7f7e9bd291dd26b0585d03eb686c941 (patch)
treed4d31289c39fc00da064a825df13a0b98ce95b10 /src/go/collectors/go.d.plugin/modules/vsphere/discover
parentAdding upstream version 1.44.3. (diff)
downloadnetdata-b5f8ee61a7f7e9bd291dd26b0585d03eb686c941.tar.xz
netdata-b5f8ee61a7f7e9bd291dd26b0585d03eb686c941.zip
Adding upstream version 1.46.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/go/collectors/go.d.plugin/modules/vsphere/discover')
-rw-r--r--src/go/collectors/go.d.plugin/modules/vsphere/discover/build.go180
-rw-r--r--src/go/collectors/go.d.plugin/modules/vsphere/discover/discover.go163
-rw-r--r--src/go/collectors/go.d.plugin/modules/vsphere/discover/discover_test.go179
-rw-r--r--src/go/collectors/go.d.plugin/modules/vsphere/discover/filter.go60
-rw-r--r--src/go/collectors/go.d.plugin/modules/vsphere/discover/hierarchy.go100
-rw-r--r--src/go/collectors/go.d.plugin/modules/vsphere/discover/metric_lists.go135
6 files changed, 817 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/vsphere/discover/build.go b/src/go/collectors/go.d.plugin/modules/vsphere/discover/build.go
new file mode 100644
index 000000000..3bf9bfb48
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/vsphere/discover/build.go
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package discover
+
+import (
+ "time"
+
+ rs "github.com/netdata/netdata/go/go.d.plugin/modules/vsphere/resources"
+
+ "github.com/vmware/govmomi/vim25/mo"
+)
+
+func (d Discoverer) build(raw *resources) *rs.Resources {
+ d.Debug("discovering : building : starting building resources process")
+ t := time.Now()
+
+ var res rs.Resources
+ res.DataCenters = d.buildDatacenters(raw.dcs)
+ res.Folders = d.buildFolders(raw.folders)
+ res.Clusters = d.buildClusters(raw.clusters)
+ fixClustersParentID(&res)
+ res.Hosts = d.buildHosts(raw.hosts)
+ res.VMs = d.buildVMs(raw.vms)
+
+ d.Infof("discovering : building : built %d/%d dcs, %d/%d folders, %d/%d clusters, %d/%d hosts, %d/%d vms, process took %s",
+ len(res.DataCenters),
+ len(raw.dcs),
+ len(res.Folders),
+ len(raw.folders),
+ len(res.Clusters),
+ len(raw.clusters),
+ len(res.Hosts),
+ len(raw.hosts),
+ len(res.VMs),
+ len(raw.vms),
+ time.Since(t),
+ )
+ return &res
+}
+
+// cluster parent is folder by default
+// should be called after buildDatacenters, buildFolders and buildClusters
+func fixClustersParentID(res *rs.Resources) {
+ for _, c := range res.Clusters {
+ c.ParentID = findClusterDcID(c.ParentID, res.Folders)
+ }
+}
+
+func findClusterDcID(parentID string, folders rs.Folders) string {
+ f := folders.Get(parentID)
+ if f == nil {
+ return parentID
+ }
+ return findClusterDcID(f.ParentID, folders)
+}
+
+func (Discoverer) buildDatacenters(raw []mo.Datacenter) rs.DataCenters {
+ dcs := make(rs.DataCenters)
+ for _, d := range raw {
+ dcs.Put(newDC(d))
+ }
+ return dcs
+}
+
+func newDC(raw mo.Datacenter) *rs.Datacenter {
+ // Datacenter1 datacenter-2 group-h4 group-v3
+ return &rs.Datacenter{
+ Name: raw.Name,
+ ID: raw.Reference().Value,
+ }
+}
+
+func (Discoverer) buildFolders(raw []mo.Folder) rs.Folders {
+ fs := make(rs.Folders)
+ for _, d := range raw {
+ fs.Put(newFolder(d))
+ }
+ return fs
+}
+
+func newFolder(raw mo.Folder) *rs.Folder {
+ // vm group-v55 datacenter-54
+ // host group-h56 datacenter-54
+ // datastore group-s57 datacenter-54
+ // network group-n58 datacenter-54
+ return &rs.Folder{
+ Name: raw.Name,
+ ID: raw.Reference().Value,
+ ParentID: raw.Parent.Value,
+ }
+}
+
+func (Discoverer) buildClusters(raw []mo.ComputeResource) rs.Clusters {
+ clusters := make(rs.Clusters)
+ for _, c := range raw {
+ clusters.Put(newCluster(c))
+ }
+ return clusters
+}
+
+func newCluster(raw mo.ComputeResource) *rs.Cluster {
+ // s - dummy cluster, c - created by user cluster
+ // 192.168.0.201 domain-s61 group-h4
+ // New Cluster1 domain-c52 group-h67
+ return &rs.Cluster{
+ Name: raw.Name,
+ ID: raw.Reference().Value,
+ ParentID: raw.Parent.Value,
+ }
+}
+
+const (
+ poweredOn = "poweredOn"
+)
+
+func (d Discoverer) buildHosts(raw []mo.HostSystem) rs.Hosts {
+ var num int
+ hosts := make(rs.Hosts)
+ for _, h := range raw {
+ // poweredOn | poweredOff | standBy | unknown
+ if h.Runtime.PowerState != poweredOn {
+ num++
+ continue
+ }
+ // connected | notResponding | disconnected
+ //if v.Runtime.ConnectionState == "" {
+ //
+ //}
+ hosts.Put(newHost(h))
+ }
+ if num > 0 {
+ d.Infof("discovering : building : removed %d hosts (not powered on)", num)
+ }
+ return hosts
+}
+
+func newHost(raw mo.HostSystem) *rs.Host {
+ // 192.168.0.201 host-22 domain-s61
+ // 192.168.0.202 host-28 domain-c52
+ // 192.168.0.203 host-33 domain-c52
+ return &rs.Host{
+ Name: raw.Name,
+ ID: raw.Reference().Value,
+ ParentID: raw.Parent.Value,
+ OverallStatus: string(raw.Summary.OverallStatus),
+ Ref: raw.Reference(),
+ }
+}
+
+func (d Discoverer) buildVMs(raw []mo.VirtualMachine) rs.VMs {
+ var num int
+ vms := make(rs.VMs)
+ for _, v := range raw {
+ // poweredOff | poweredOn | suspended
+ if v.Runtime.PowerState != poweredOn {
+ num++
+ continue
+ }
+ // connected | disconnected | orphaned | inaccessible | invalid
+ //if v.Runtime.ConnectionState == "" {
+ //
+ //}
+ vms.Put(newVM(v))
+ }
+ if num > 0 {
+ d.Infof("discovering : building : removed %d vms (not powered on)", num)
+ }
+ return vms
+}
+
+func newVM(raw mo.VirtualMachine) *rs.VM {
+ // deb91 vm-25 group-v3 host-22
+ return &rs.VM{
+ Name: raw.Name,
+ ID: raw.Reference().Value,
+ ParentID: raw.Runtime.Host.Value,
+ OverallStatus: string(raw.Summary.OverallStatus),
+ Ref: raw.Reference(),
+ }
+}
diff --git a/src/go/collectors/go.d.plugin/modules/vsphere/discover/discover.go b/src/go/collectors/go.d.plugin/modules/vsphere/discover/discover.go
new file mode 100644
index 000000000..0d68b71c3
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/vsphere/discover/discover.go
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package discover
+
+import (
+ "fmt"
+ "strings"
+ "time"
+
+ "github.com/netdata/netdata/go/go.d.plugin/modules/vsphere/match"
+ rs "github.com/netdata/netdata/go/go.d.plugin/modules/vsphere/resources"
+
+ "github.com/netdata/netdata/go/go.d.plugin/logger"
+ "github.com/vmware/govmomi/vim25/mo"
+ "github.com/vmware/govmomi/vim25/types"
+)
+
+type Client interface {
+ Datacenters(pathSet ...string) ([]mo.Datacenter, error)
+ Folders(pathSet ...string) ([]mo.Folder, error)
+ ComputeResources(pathSet ...string) ([]mo.ComputeResource, error)
+ Hosts(pathSet ...string) ([]mo.HostSystem, error)
+ VirtualMachines(pathSet ...string) ([]mo.VirtualMachine, error)
+
+ CounterInfoByName() (map[string]*types.PerfCounterInfo, error)
+}
+
+func New(client Client) *Discoverer {
+ return &Discoverer{
+ Client: client,
+ }
+}
+
+type Discoverer struct {
+ *logger.Logger
+ Client
+ match.HostMatcher
+ match.VMMatcher
+}
+
+type resources struct {
+ dcs []mo.Datacenter
+ folders []mo.Folder
+ clusters []mo.ComputeResource
+ hosts []mo.HostSystem
+ vms []mo.VirtualMachine
+}
+
+func (d Discoverer) Discover() (*rs.Resources, error) {
+ startTime := time.Now()
+ raw, err := d.discover()
+ if err != nil {
+ return nil, fmt.Errorf("discovering resources : %v", err)
+ }
+
+ res := d.build(raw)
+
+ err = d.setHierarchy(res)
+ if err != nil {
+ // TODO: handle objects w/o hier?
+ d.Error(err)
+ }
+
+ numH := len(res.Hosts)
+ numV := len(res.VMs)
+ removed := d.removeUnmatched(res)
+ if removed == (numH + numV) {
+ return nil, fmt.Errorf("all resoursces were filtered (%d hosts, %d vms)", numH, numV)
+ }
+
+ err = d.collectMetricLists(res)
+ if err != nil {
+ return nil, fmt.Errorf("collecting metric lists : %v", err)
+ }
+
+ d.Infof("discovering : discovered %d/%d hosts, %d/%d vms, the whole process took %s",
+ len(res.Hosts),
+ len(raw.hosts),
+ len(res.VMs),
+ len(raw.vms),
+ time.Since(startTime))
+
+ return res, nil
+}
+
+var (
+ // properties to set
+ datacenterPathSet = []string{"name", "parent"}
+ folderPathSet = []string{"name", "parent"}
+ clusterPathSet = []string{"name", "parent"}
+ hostPathSet = []string{"name", "parent", "runtime.powerState", "summary.overallStatus"}
+ vmPathSet = []string{"name", "runtime.host", "runtime.powerState", "summary.overallStatus"}
+)
+
+func (d Discoverer) discover() (*resources, error) {
+ d.Debug("discovering : starting resource discovering process")
+
+ start := time.Now()
+ t := start
+ datacenters, err := d.Datacenters(datacenterPathSet...)
+ if err != nil {
+ return nil, err
+ }
+ d.Debugf("discovering : found %d dcs, process took %s", len(datacenters), time.Since(t))
+
+ t = time.Now()
+ folders, err := d.Folders(folderPathSet...)
+ if err != nil {
+ return nil, err
+ }
+ d.Debugf("discovering : found %d folders, process took %s", len(folders), time.Since(t))
+
+ t = time.Now()
+ clusters, err := d.ComputeResources(clusterPathSet...)
+ if err != nil {
+ return nil, err
+ }
+ d.Debugf("discovering : found %d clusters, process took %s", len(clusters), time.Since(t))
+
+ t = time.Now()
+ hosts, err := d.Hosts(hostPathSet...)
+ if err != nil {
+ return nil, err
+ }
+ d.Debugf("discovering : found %d hosts, process took %s", len(hosts), time.Since(t))
+
+ t = time.Now()
+ vms, err := d.VirtualMachines(vmPathSet...)
+ if err != nil {
+ return nil, err
+ }
+ d.Debugf("discovering : found %d vms, process took %s", len(hosts), time.Since(t))
+
+ raw := resources{
+ dcs: datacenters,
+ folders: folders,
+ clusters: clusters,
+ hosts: hosts,
+ vms: vms,
+ }
+
+ d.Infof("discovering : found %d dcs, %d folders, %d clusters (%d dummy), %d hosts, %d vms, process took %s",
+ len(raw.dcs),
+ len(raw.folders),
+ len(clusters),
+ numOfDummyClusters(clusters),
+ len(raw.hosts),
+ len(raw.vms),
+ time.Since(start),
+ )
+
+ return &raw, nil
+}
+
+func numOfDummyClusters(clusters []mo.ComputeResource) (num int) {
+ for _, c := range clusters {
+ // domain-s61 | domain-c52
+ if strings.HasPrefix(c.Reference().Value, "domain-s") {
+ num++
+ }
+ }
+ return num
+}
diff --git a/src/go/collectors/go.d.plugin/modules/vsphere/discover/discover_test.go b/src/go/collectors/go.d.plugin/modules/vsphere/discover/discover_test.go
new file mode 100644
index 000000000..01f83fd38
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/vsphere/discover/discover_test.go
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package discover
+
+import (
+ "crypto/tls"
+ "net/url"
+ "testing"
+ "time"
+
+ "github.com/netdata/netdata/go/go.d.plugin/modules/vsphere/client"
+ rs "github.com/netdata/netdata/go/go.d.plugin/modules/vsphere/resources"
+ "github.com/netdata/netdata/go/go.d.plugin/pkg/tlscfg"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "github.com/vmware/govmomi/simulator"
+)
+
+func TestDiscoverer_Discover(t *testing.T) {
+ d, _, teardown := prepareDiscovererSim(t)
+ defer teardown()
+
+ res, err := d.Discover()
+
+ require.NoError(t, err)
+ assert.True(t, len(res.DataCenters) > 0)
+ assert.True(t, len(res.Folders) > 0)
+ assert.True(t, len(res.Clusters) > 0)
+ assert.True(t, len(res.Hosts) > 0)
+ assert.True(t, len(res.VMs) > 0)
+ assert.True(t, isHierarchySet(res))
+ assert.True(t, isMetricListsCollected(res))
+}
+
+func TestDiscoverer_discover(t *testing.T) {
+ d, model, teardown := prepareDiscovererSim(t)
+ defer teardown()
+
+ raw, err := d.discover()
+
+ require.NoError(t, err)
+ count := model.Count()
+ assert.Lenf(t, raw.dcs, count.Datacenter, "datacenters")
+ assert.Lenf(t, raw.folders, count.Folder-1, "folders") // minus root folder
+ dummyClusters := model.Host * count.Datacenter
+ assert.Lenf(t, raw.clusters, count.Cluster+dummyClusters, "clusters")
+ assert.Lenf(t, raw.hosts, count.Host, "hosts")
+ assert.Lenf(t, raw.vms, count.Machine, "hosts")
+}
+
+func TestDiscoverer_build(t *testing.T) {
+ d, _, teardown := prepareDiscovererSim(t)
+ defer teardown()
+
+ raw, err := d.discover()
+ require.NoError(t, err)
+
+ res := d.build(raw)
+
+ assert.Lenf(t, res.DataCenters, len(raw.dcs), "datacenters")
+ assert.Lenf(t, res.Folders, len(raw.folders), "folders")
+ assert.Lenf(t, res.Clusters, len(raw.clusters), "clusters")
+ assert.Lenf(t, res.Hosts, len(raw.hosts), "hosts")
+ assert.Lenf(t, res.VMs, len(raw.vms), "hosts")
+}
+
+func TestDiscoverer_setHierarchy(t *testing.T) {
+ d, _, teardown := prepareDiscovererSim(t)
+ defer teardown()
+
+ raw, err := d.discover()
+ require.NoError(t, err)
+ res := d.build(raw)
+
+ err = d.setHierarchy(res)
+
+ require.NoError(t, err)
+ assert.True(t, isHierarchySet(res))
+}
+
+func TestDiscoverer_removeUnmatched(t *testing.T) {
+ d, _, teardown := prepareDiscovererSim(t)
+ defer teardown()
+
+ d.HostMatcher = falseHostMatcher{}
+ d.VMMatcher = falseVMMatcher{}
+ raw, err := d.discover()
+ require.NoError(t, err)
+ res := d.build(raw)
+
+ numVMs, numHosts := len(res.VMs), len(res.Hosts)
+ assert.Equal(t, numVMs+numHosts, d.removeUnmatched(res))
+ assert.Lenf(t, res.Hosts, 0, "hosts")
+ assert.Lenf(t, res.VMs, 0, "vms")
+}
+
+func TestDiscoverer_collectMetricLists(t *testing.T) {
+ d, _, teardown := prepareDiscovererSim(t)
+ defer teardown()
+
+ raw, err := d.discover()
+ require.NoError(t, err)
+
+ res := d.build(raw)
+ err = d.collectMetricLists(res)
+
+ require.NoError(t, err)
+ assert.True(t, isMetricListsCollected(res))
+}
+
+func prepareDiscovererSim(t *testing.T) (d *Discoverer, model *simulator.Model, teardown func()) {
+ model, srv := createSim(t)
+ teardown = func() { model.Remove(); srv.Close() }
+ c := newClient(t, srv.URL)
+
+ return New(c), model, teardown
+}
+
+func newClient(t *testing.T, vCenterURL *url.URL) *client.Client {
+ c, err := client.New(client.Config{
+ URL: vCenterURL.String(),
+ User: "admin",
+ Password: "password",
+ Timeout: time.Second * 3,
+ TLSConfig: tlscfg.TLSConfig{InsecureSkipVerify: true},
+ })
+ require.NoError(t, err)
+ return c
+}
+
+func createSim(t *testing.T) (*simulator.Model, *simulator.Server) {
+ model := simulator.VPX()
+ err := model.Create()
+ require.NoError(t, err)
+ model.Service.TLS = new(tls.Config)
+ return model, model.Service.NewServer()
+}
+
+func isHierarchySet(res *rs.Resources) bool {
+ for _, c := range res.Clusters {
+ if !c.Hier.IsSet() {
+ return false
+ }
+ }
+ for _, h := range res.Hosts {
+ if !h.Hier.IsSet() {
+ return false
+ }
+ }
+ for _, v := range res.VMs {
+ if !v.Hier.IsSet() {
+ return false
+ }
+ }
+ return true
+}
+
+func isMetricListsCollected(res *rs.Resources) bool {
+ for _, h := range res.Hosts {
+ if h.MetricList == nil {
+ return false
+ }
+ }
+ for _, v := range res.VMs {
+ if v.MetricList == nil {
+ return false
+ }
+ }
+ return true
+}
+
+type falseHostMatcher struct{}
+
+func (falseHostMatcher) Match(*rs.Host) bool { return false }
+
+type falseVMMatcher struct{}
+
+func (falseVMMatcher) Match(*rs.VM) bool { return false }
diff --git a/src/go/collectors/go.d.plugin/modules/vsphere/discover/filter.go b/src/go/collectors/go.d.plugin/modules/vsphere/discover/filter.go
new file mode 100644
index 000000000..73c1481e3
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/vsphere/discover/filter.go
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package discover
+
+import (
+ "time"
+
+ rs "github.com/netdata/netdata/go/go.d.plugin/modules/vsphere/resources"
+)
+
+func (d Discoverer) matchHost(host *rs.Host) bool {
+ if d.HostMatcher == nil {
+ return true
+ }
+ return d.HostMatcher.Match(host)
+}
+
+func (d Discoverer) matchVM(vm *rs.VM) bool {
+ if d.VMMatcher == nil {
+ return true
+ }
+ return d.VMMatcher.Match(vm)
+}
+
+func (d Discoverer) removeUnmatched(res *rs.Resources) (removed int) {
+ d.Debug("discovering : filtering : starting filtering resources process")
+ t := time.Now()
+ numH, numV := len(res.Hosts), len(res.VMs)
+ removed += d.removeUnmatchedHosts(res.Hosts)
+ removed += d.removeUnmatchedVMs(res.VMs)
+ d.Infof("discovering : filtering : filtered %d/%d hosts, %d/%d vms, process took %s",
+ numH-len(res.Hosts),
+ numH,
+ numV-len(res.VMs),
+ numV,
+ time.Since(t))
+ return
+}
+
+func (d Discoverer) removeUnmatchedHosts(hosts rs.Hosts) (removed int) {
+ for _, v := range hosts {
+ if !d.matchHost(v) {
+ removed++
+ hosts.Remove(v.ID)
+ }
+ }
+ d.Debugf("discovering : filtering : removed %d unmatched hosts", removed)
+ return removed
+}
+
+func (d Discoverer) removeUnmatchedVMs(vms rs.VMs) (removed int) {
+ for _, v := range vms {
+ if !d.matchVM(v) {
+ removed++
+ vms.Remove(v.ID)
+ }
+ }
+ d.Debugf("discovering : filtering : removed %d unmatched vms", removed)
+ return removed
+}
diff --git a/src/go/collectors/go.d.plugin/modules/vsphere/discover/hierarchy.go b/src/go/collectors/go.d.plugin/modules/vsphere/discover/hierarchy.go
new file mode 100644
index 000000000..4cea75dcd
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/vsphere/discover/hierarchy.go
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package discover
+
+import (
+ "time"
+
+ rs "github.com/netdata/netdata/go/go.d.plugin/modules/vsphere/resources"
+)
+
+func (d Discoverer) setHierarchy(res *rs.Resources) error {
+ d.Debug("discovering : hierarchy : start setting resources hierarchy process")
+ t := time.Now()
+
+ c := d.setClustersHierarchy(res)
+ h := d.setHostsHierarchy(res)
+ v := d.setVMsHierarchy(res)
+
+ // notSet := len(res.Clusters) + len(res.Hosts) + len(res.VMs) - (c + h + v)
+ d.Infof("discovering : hierarchy : set %d/%d clusters, %d/%d hosts, %d/%d vms, process took %s",
+ c, len(res.Clusters),
+ h, len(res.Hosts),
+ v, len(res.VMs),
+ time.Since(t),
+ )
+
+ return nil
+}
+
+func (d Discoverer) setClustersHierarchy(res *rs.Resources) (set int) {
+ for _, cluster := range res.Clusters {
+ if setClusterHierarchy(cluster, res) {
+ set++
+ }
+ }
+ return set
+}
+
+func (d Discoverer) setHostsHierarchy(res *rs.Resources) (set int) {
+ for _, host := range res.Hosts {
+ if setHostHierarchy(host, res) {
+ set++
+ }
+ }
+ return set
+}
+
+func (d Discoverer) setVMsHierarchy(res *rs.Resources) (set int) {
+ for _, vm := range res.VMs {
+ if setVMHierarchy(vm, res) {
+ set++
+ }
+ }
+ return set
+}
+
+func setClusterHierarchy(cluster *rs.Cluster, res *rs.Resources) bool {
+ dc := res.DataCenters.Get(cluster.ParentID)
+ if dc == nil {
+ return false
+ }
+ cluster.Hier.DC.Set(dc.ID, dc.Name)
+ return cluster.Hier.IsSet()
+}
+
+func setHostHierarchy(host *rs.Host, res *rs.Resources) bool {
+ cr := res.Clusters.Get(host.ParentID)
+ if cr == nil {
+ return false
+ }
+ host.Hier.Cluster.Set(cr.ID, cr.Name)
+
+ dc := res.DataCenters.Get(cr.ParentID)
+ if dc == nil {
+ return false
+ }
+ host.Hier.DC.Set(dc.ID, dc.Name)
+ return host.Hier.IsSet()
+}
+
+func setVMHierarchy(vm *rs.VM, res *rs.Resources) bool {
+ h := res.Hosts.Get(vm.ParentID)
+ if h == nil {
+ return false
+ }
+ vm.Hier.Host.Set(h.ID, h.Name)
+
+ cr := res.Clusters.Get(h.ParentID)
+ if cr == nil {
+ return false
+ }
+ vm.Hier.Cluster.Set(cr.ID, cr.Name)
+
+ dc := res.DataCenters.Get(cr.ParentID)
+ if dc == nil {
+ return false
+ }
+ vm.Hier.DC.Set(dc.ID, dc.Name)
+ return vm.Hier.IsSet()
+}
diff --git a/src/go/collectors/go.d.plugin/modules/vsphere/discover/metric_lists.go b/src/go/collectors/go.d.plugin/modules/vsphere/discover/metric_lists.go
new file mode 100644
index 000000000..0eecb81ea
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/vsphere/discover/metric_lists.go
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package discover
+
+import (
+ "sort"
+ "time"
+
+ rs "github.com/netdata/netdata/go/go.d.plugin/modules/vsphere/resources"
+
+ "github.com/vmware/govmomi/performance"
+ "github.com/vmware/govmomi/vim25/types"
+)
+
+func (d Discoverer) collectMetricLists(res *rs.Resources) error {
+ d.Debug("discovering : metric lists : starting resources metric lists collection process")
+ t := time.Now()
+ perfCounters, err := d.CounterInfoByName()
+ if err != nil {
+ return err
+ }
+
+ hostML := simpleHostMetricList(perfCounters)
+ for _, h := range res.Hosts {
+ h.MetricList = hostML
+ }
+ vmML := simpleVMMetricList(perfCounters)
+ for _, v := range res.VMs {
+ v.MetricList = vmML
+ }
+
+ d.Infof("discovering : metric lists : collected metric lists for %d/%d hosts, %d/%d vms, process took %s",
+ len(res.Hosts),
+ len(res.Hosts),
+ len(res.VMs),
+ len(res.VMs),
+ time.Since(t),
+ )
+
+ return nil
+}
+
+func simpleHostMetricList(pci map[string]*types.PerfCounterInfo) performance.MetricList {
+ return simpleMetricList(hostMetrics, pci)
+}
+
+func simpleVMMetricList(pci map[string]*types.PerfCounterInfo) performance.MetricList {
+ return simpleMetricList(vmMetrics, pci)
+}
+
+func simpleMetricList(metrics []string, pci map[string]*types.PerfCounterInfo) performance.MetricList {
+ sort.Strings(metrics)
+
+ var pml performance.MetricList
+ for _, v := range metrics {
+ m, ok := pci[v]
+ if !ok {
+ // TODO: should be logged
+ continue
+ }
+ // TODO: only summary metrics for now
+ // TODO: some metrics only appear if Instance is *, for example
+ // virtualDisk.totalWriteLatency.average.scsi0:0
+ // virtualDisk.numberWriteAveraged.average.scsi0:0
+ // virtualDisk.write.average.scsi0:0
+ // virtualDisk.totalReadLatency.average.scsi0:0
+ // virtualDisk.numberReadAveraged.average.scsi0:0
+ // virtualDisk.read.average.scsi0:0
+ // disk.numberReadAveraged.average
+ // disk.numberWriteAveraged.average
+ // TODO: metrics will be unsorted after if at least one Instance is *
+ pml = append(pml, types.PerfMetricId{CounterId: m.Key, Instance: ""})
+ }
+ return pml
+}
+
+var (
+ vmMetrics = []string{
+ "cpu.usage.average",
+
+ "mem.usage.average",
+ "mem.granted.average",
+ "mem.consumed.average",
+ "mem.active.average",
+ "mem.shared.average",
+ // Refers to VMkernel swapping!
+ "mem.swapinRate.average",
+ "mem.swapoutRate.average",
+ "mem.swapped.average",
+
+ "net.bytesRx.average",
+ "net.bytesTx.average",
+ "net.packetsRx.summation",
+ "net.packetsTx.summation",
+ "net.droppedRx.summation",
+ "net.droppedTx.summation",
+
+ // the only summary disk metrics
+ "disk.read.average",
+ "disk.write.average",
+ "disk.maxTotalLatency.latest",
+
+ "sys.uptime.latest",
+ }
+
+ hostMetrics = []string{
+ "cpu.usage.average",
+
+ "mem.usage.average",
+ "mem.granted.average",
+ "mem.consumed.average",
+ "mem.active.average",
+ "mem.shared.average",
+ "mem.sharedcommon.average",
+ // Refers to VMkernel swapping!
+ "mem.swapinRate.average",
+ "mem.swapoutRate.average",
+
+ "net.bytesRx.average",
+ "net.bytesTx.average",
+ "net.packetsRx.summation",
+ "net.packetsTx.summation",
+ "net.droppedRx.summation",
+ "net.droppedTx.summation",
+ "net.errorsRx.summation",
+ "net.errorsTx.summation",
+
+ // the only summary disk metrics
+ "disk.read.average",
+ "disk.write.average",
+ "disk.maxTotalLatency.latest",
+
+ "sys.uptime.latest",
+ }
+)