diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index 642049738fb..185d7f1b962 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -291,6 +291,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Improve logging in Okta Entity Analytics provider. {issue}40106[40106] {pull}40347[40347] - Document `winlog` input. {issue}40074[40074] {pull}40462[40462] - Added retry logic to websocket connections in the streaming input. {issue}40271[40271] {pull}40601[40601] +- Add new metricset cluster for the vSphere module. {pull}40536[40536] - Disable event normalization for netflow input {pull}40635[40635] *Auditbeat* diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index 6a626d44cae..0340311dff3 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -66854,6 +66854,107 @@ vSphere module +[float] +=== cluster + +Cluster information. + + + + +*`vsphere.cluster.datastore.names`*:: ++ +-- +List of all the Datastore names associated with the cluster. + + +type: keyword + +-- + +*`vsphere.cluster.datastore.count`*:: ++ +-- +Number of Datastores associated with the cluster. + + +type: long + +-- + + +*`vsphere.cluster.das_config.admission.control.enabled`*:: ++ +-- +Indicates whether strict admission control is enabled. + + +type: boolean + +-- + +*`vsphere.cluster.das_config.enabled`*:: ++ +-- +Indicates whether vSphere HA feature is enabled. + + +type: boolean + +-- + + +*`vsphere.cluster.host.count`*:: ++ +-- +Number of Hosts associated with the cluster. + + +type: long + +-- + +*`vsphere.cluster.host.names`*:: ++ +-- +List of all the Host names associated with the cluster. + + +type: keyword + +-- + +*`vsphere.cluster.name`*:: ++ +-- +Cluster name. + + +type: keyword + +-- + + +*`vsphere.cluster.network.count`*:: ++ +-- +Number of Networks associated with the cluster. + + +type: long + +-- + +*`vsphere.cluster.network.names`*:: ++ +-- +List of all the Network names associated with the cluster. + + +type: keyword + +-- + [float] === datastore diff --git a/metricbeat/docs/modules/vsphere.asciidoc b/metricbeat/docs/modules/vsphere.asciidoc index 746a3d98dc8..63a10987905 100644 --- a/metricbeat/docs/modules/vsphere.asciidoc +++ b/metricbeat/docs/modules/vsphere.asciidoc @@ -11,7 +11,7 @@ This file is generated! See scripts/mage/docs_collector.go The vSphere module uses the https://github.com/vmware/govmomi[Govmomi] library to collect metrics from any Vmware SDK URL (ESXi/VCenter). This library is built for and tested against ESXi and vCenter 5.5, 6.0 and 6.5. -By default it enables the metricsets `network`, `resourcepool`, `datastore`, `host` and `virtualmachine`. +By default it enables the metricsets `cluster`, `network`, `resourcepool`, `datastore`, `host` and `virtualmachine`. [float] === Dashboard @@ -35,7 +35,7 @@ in <>. Here is an example configuration: metricbeat.modules: - module: vsphere enabled: true - metricsets: ["datastore", "host", "virtualmachine", "network", "resourcepool"] + metricsets: ["cluster", "datastore", "host", "virtualmachine", "network", "resourcepool"] # Real-time data collection – An ESXi Server collects data for each performance counter every 20 seconds. period: 20s hosts: ["https://localhost/sdk"] @@ -53,6 +53,8 @@ metricbeat.modules: The following metricsets are available: +* <> + * <> * <> @@ -63,6 +65,8 @@ The following metricsets are available: * <> +include::vsphere/cluster.asciidoc[] + include::vsphere/datastore.asciidoc[] include::vsphere/host.asciidoc[] diff --git a/metricbeat/docs/modules/vsphere/cluster.asciidoc b/metricbeat/docs/modules/vsphere/cluster.asciidoc new file mode 100644 index 00000000000..1666f6c8dfd --- /dev/null +++ b/metricbeat/docs/modules/vsphere/cluster.asciidoc @@ -0,0 +1,29 @@ +//// +This file is generated! See scripts/mage/docs_collector.go +//// +:edit_url: https://github.com/elastic/beats/edit/main/metricbeat/module/vsphere/cluster/_meta/docs.asciidoc + + +[[metricbeat-metricset-vsphere-cluster]] +=== vSphere cluster metricset + +beta[] + +include::../../../module/vsphere/cluster/_meta/docs.asciidoc[] + +This is a default metricset. If the host module is unconfigured, this metricset is enabled by default. + +:edit_url: + +==== Fields + +For a description of each field in the metricset, see the +<> section. + +Here is an example document generated by this metricset: + +[source,json] +---- +include::../../../module/vsphere/cluster/_meta/data.json[] +---- +:edit_url!: \ No newline at end of file diff --git a/metricbeat/docs/modules_list.asciidoc b/metricbeat/docs/modules_list.asciidoc index 1942747c02c..c50e63f2d3f 100644 --- a/metricbeat/docs/modules_list.asciidoc +++ b/metricbeat/docs/modules_list.asciidoc @@ -311,7 +311,8 @@ This file is generated! See scripts/mage/docs_collector.go |<> |image:./images/icon-yes.png[Prebuilt dashboards are available] | .1+| .1+| |<> |<> |image:./images/icon-yes.png[Prebuilt dashboards are available] | -.5+| .5+| |<> +.6+| .6+| |<> beta[] +|<> |<> |<> beta[] |<> beta[] diff --git a/metricbeat/include/list_common.go b/metricbeat/include/list_common.go index 0b8226ed3ce..89bc495bd8d 100644 --- a/metricbeat/include/list_common.go +++ b/metricbeat/include/list_common.go @@ -181,6 +181,7 @@ import ( _ "github.com/elastic/beats/v7/metricbeat/module/uwsgi" _ "github.com/elastic/beats/v7/metricbeat/module/uwsgi/status" _ "github.com/elastic/beats/v7/metricbeat/module/vsphere" + _ "github.com/elastic/beats/v7/metricbeat/module/vsphere/cluster" _ "github.com/elastic/beats/v7/metricbeat/module/vsphere/datastore" _ "github.com/elastic/beats/v7/metricbeat/module/vsphere/host" _ "github.com/elastic/beats/v7/metricbeat/module/vsphere/network" diff --git a/metricbeat/metricbeat.reference.yml b/metricbeat/metricbeat.reference.yml index c82182c12ea..816e2fcc804 100644 --- a/metricbeat/metricbeat.reference.yml +++ b/metricbeat/metricbeat.reference.yml @@ -1007,7 +1007,7 @@ metricbeat.modules: #------------------------------- VSphere Module ------------------------------- - module: vsphere enabled: true - metricsets: ["datastore", "host", "virtualmachine", "network", "resourcepool"] + metricsets: ["cluster", "datastore", "host", "virtualmachine", "network", "resourcepool"] # Real-time data collection – An ESXi Server collects data for each performance counter every 20 seconds. period: 20s hosts: ["https://localhost/sdk"] diff --git a/metricbeat/module/vsphere/_meta/README.md b/metricbeat/module/vsphere/_meta/README.md index 8af88a660af..06373b27e63 100644 --- a/metricbeat/module/vsphere/_meta/README.md +++ b/metricbeat/module/vsphere/_meta/README.md @@ -28,6 +28,7 @@ Now setup your metricbeat config to connect to Govcsim: ``` - module: vsphere metricsets: + - cluster - datastore - host - virtualmachine diff --git a/metricbeat/module/vsphere/_meta/config.reference.yml b/metricbeat/module/vsphere/_meta/config.reference.yml index d3fc63eb1e2..5e6bfdb488c 100644 --- a/metricbeat/module/vsphere/_meta/config.reference.yml +++ b/metricbeat/module/vsphere/_meta/config.reference.yml @@ -1,6 +1,6 @@ - module: vsphere enabled: true - metricsets: ["datastore", "host", "virtualmachine", "network", "resourcepool"] + metricsets: ["cluster", "datastore", "host", "virtualmachine", "network", "resourcepool"] # Real-time data collection – An ESXi Server collects data for each performance counter every 20 seconds. period: 20s hosts: ["https://localhost/sdk"] diff --git a/metricbeat/module/vsphere/_meta/config.yml b/metricbeat/module/vsphere/_meta/config.yml index dc7617b155b..09927fb3237 100644 --- a/metricbeat/module/vsphere/_meta/config.yml +++ b/metricbeat/module/vsphere/_meta/config.yml @@ -1,5 +1,6 @@ - module: vsphere #metricsets: + # - cluster # - datastore # - host # - virtualmachine diff --git a/metricbeat/module/vsphere/_meta/docs.asciidoc b/metricbeat/module/vsphere/_meta/docs.asciidoc index 96262ffed8d..e1329634c21 100644 --- a/metricbeat/module/vsphere/_meta/docs.asciidoc +++ b/metricbeat/module/vsphere/_meta/docs.asciidoc @@ -1,6 +1,6 @@ The vSphere module uses the https://github.com/vmware/govmomi[Govmomi] library to collect metrics from any Vmware SDK URL (ESXi/VCenter). This library is built for and tested against ESXi and vCenter 5.5, 6.0 and 6.5. -By default it enables the metricsets `network`, `resourcepool`, `datastore`, `host` and `virtualmachine`. +By default it enables the metricsets `cluster`, `network`, `resourcepool`, `datastore`, `host` and `virtualmachine`. [float] === Dashboard diff --git a/metricbeat/module/vsphere/cluster/_meta/data.json b/metricbeat/module/vsphere/cluster/_meta/data.json new file mode 100644 index 00000000000..6e165063e85 --- /dev/null +++ b/metricbeat/module/vsphere/cluster/_meta/data.json @@ -0,0 +1,47 @@ +{ + "@timestamp": "2017-10-12T08:05:34.853Z", + "event": { + "dataset": "vsphere.cluster", + "duration": 115000, + "module": "vsphere" + }, + "metricset": { + "name": "cluster", + "period": 10000 + }, + "service": { + "address": "127.0.0.1:33365", + "type": "vsphere" + }, + "vsphere": { + "cluster": { + "name": "Cluster_1", + "das_config": { + "enabled": false, + "admission": { + "control": { + "enabled": true + } + } + }, + "host": { + "count": 1, + "names": [ + "Host_1" + ] + }, + "datastore": { + "count": 1, + "names": [ + "Datastore_1" + ] + }, + "network": { + "count": 1, + "names": [ + "Network_1" + ] + } + } + } +} \ No newline at end of file diff --git a/metricbeat/module/vsphere/cluster/_meta/docs.asciidoc b/metricbeat/module/vsphere/cluster/_meta/docs.asciidoc new file mode 100644 index 00000000000..e82fdcdccc6 --- /dev/null +++ b/metricbeat/module/vsphere/cluster/_meta/docs.asciidoc @@ -0,0 +1 @@ +This is the `cluster` metricset of the vSphere module. diff --git a/metricbeat/module/vsphere/cluster/_meta/fields.yml b/metricbeat/module/vsphere/cluster/_meta/fields.yml new file mode 100644 index 00000000000..7afce736285 --- /dev/null +++ b/metricbeat/module/vsphere/cluster/_meta/fields.yml @@ -0,0 +1,54 @@ +- name: cluster + type: group + release: beta + description: > + Cluster information. + fields: + - name: datastore + type: group + fields: + - name: names + type: keyword + description: > + List of all the Datastore names associated with the cluster. + - name: count + type: long + description: > + Number of Datastores associated with the cluster. + - name: das_config + type: group + fields: + - name: admission.control.enabled + type: boolean + description: > + Indicates whether strict admission control is enabled. + - name: enabled + type: boolean + description: > + Indicates whether vSphere HA feature is enabled. + - name: host + type: group + fields: + - name: count + type: long + description: > + Number of Hosts associated with the cluster. + - name: names + type: keyword + description: > + List of all the Host names associated with the cluster. + - name: name + type: keyword + description: > + Cluster name. + - name: network + type: group + fields: + - name: count + type: long + description: > + Number of Networks associated with the cluster. + - name: names + type: keyword + description: > + List of all the Network names associated with the cluster. \ No newline at end of file diff --git a/metricbeat/module/vsphere/cluster/cluster.go b/metricbeat/module/vsphere/cluster/cluster.go new file mode 100644 index 00000000000..10184c55c90 --- /dev/null +++ b/metricbeat/module/vsphere/cluster/cluster.go @@ -0,0 +1,174 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package cluster + +import ( + "context" + "fmt" + "strings" + + "github.com/elastic/beats/v7/metricbeat/mb" + "github.com/elastic/beats/v7/metricbeat/module/vsphere" + + "github.com/vmware/govmomi" + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/view" + "github.com/vmware/govmomi/vim25/mo" +) + +// init registers the MetricSet with the central registry as soon as the program +// starts. The New function will be called later to instantiate an instance of +// the MetricSet for each network is defined in the module's configuration. After the +// MetricSet has been created then Fetch will begin to be called periodically. +func init() { + mb.Registry.MustAddMetricSet("vsphere", "cluster", New, + mb.WithHostParser(vsphere.HostParser), + mb.DefaultMetricSet(), + ) +} + +// MetricSet type defines all fields of the MetricSet. +type ClusterMetricSet struct { + *vsphere.MetricSet +} + +type assetNames struct { + outputNetworkNames []string + outputDatastoreNames []string + outputHostNames []string +} + +// New creates a new instance of the MetricSet. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + ms, err := vsphere.NewMetricSet(base) + if err != nil { + return nil, err + } + return &ClusterMetricSet{ms}, nil +} + +// Fetch methods implements the data gathering and data conversion to the right +// format. It publishes the event which is then forwarded to the output. In case +// of an error set the Error field of mb.Event or simply call report.Error(). +func (m *ClusterMetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + client, err := govmomi.NewClient(ctx, m.HostURL, m.Insecure) + if err != nil { + return fmt.Errorf("error in NewClient: %w", err) + } + defer func() { + if err := client.Logout(ctx); err != nil { + m.Logger().Debug(fmt.Errorf("error trying to logout from vSphere: %w", err)) + } + }() + + c := client.Client + + // Create a view of Cluster objects + mgr := view.NewManager(c) + + v, err := mgr.CreateContainerView(ctx, c.ServiceContent.RootFolder, []string{"ClusterComputeResource"}, true) + if err != nil { + return fmt.Errorf("error in CreateContainerView: %w", err) + } + + defer func() { + if err := v.Destroy(ctx); err != nil { + m.Logger().Errorf("error trying to destroy view from vSphere: %w", err) + } + }() + + // Retrieve summary property for all Clusters + var clt []mo.ClusterComputeResource + err = v.Retrieve(ctx, []string{"ClusterComputeResource"}, []string{"name", "host", "network", "datastore", "configuration"}, &clt) + if err != nil { + return fmt.Errorf("error in Retrieve: %w", err) + } + + pc := property.DefaultCollector(c) + for i := range clt { + select { + case <-ctx.Done(): + return ctx.Err() + default: + assetNames, err := getAssetNames(ctx, pc, &clt[i]) + if err != nil { + m.Logger().Errorf("Failed to retrieve object from cluster %s: %v", clt[i].Name, err) + } + + if clt[i].Configuration.DasConfig.AdmissionControlEnabled == nil { + m.Logger().Warn("Metric das_config.admission.control.enabled not found") + } + if clt[i].Configuration.DasConfig.Enabled == nil { + m.Logger().Warn("Metric das_config.enabled not found") + } + + reporter.Event(mb.Event{ + MetricSetFields: m.mapEvent(clt[i], assetNames), + }) + } + } + return nil + +} + +func getAssetNames(ctx context.Context, pc *property.Collector, cl *mo.ClusterComputeResource) (*assetNames, error) { + referenceList := append(cl.Datastore, cl.Host...) + + outputDatastoreNames := make([]string, 0, len(cl.Datastore)) + outputHostNames := make([]string, 0, len(cl.Host)) + if len(referenceList) > 0 { + var objects []mo.ManagedEntity + if err := pc.Retrieve(ctx, referenceList, []string{"name"}, &objects); err != nil { + return nil, fmt.Errorf("failed to retrieve managed entities: %w", err) + } + + for _, ob := range objects { + name := strings.ReplaceAll(ob.Name, ".", "_") + switch ob.Reference().Type { + case "Datastore": + outputDatastoreNames = append(outputDatastoreNames, name) + case "HostSystem": + outputHostNames = append(outputHostNames, name) + } + } + } + + // calling network explicitly because of mo.Network's ManagedEntityObject.Name does not store Network name + // instead mo.Network.Name contains correct value of Network name + outputNetworkNames := make([]string, 0, len(cl.Network)) + if len(cl.Network) > 0 { + var netObjects []mo.Network + if err := pc.Retrieve(ctx, cl.Network, []string{"name"}, &netObjects); err != nil { + return nil, fmt.Errorf("failed to retrieve network objects: %w", err) + } + + for _, ob := range netObjects { + name := strings.ReplaceAll(ob.Name, ".", "_") + outputNetworkNames = append(outputNetworkNames, name) + } + } + + return &assetNames{ + outputNetworkNames: outputNetworkNames, + outputDatastoreNames: outputDatastoreNames, + outputHostNames: outputHostNames, + }, nil +} diff --git a/metricbeat/module/vsphere/cluster/cluster_test.go b/metricbeat/module/vsphere/cluster/cluster_test.go new file mode 100644 index 00000000000..37e286c113d --- /dev/null +++ b/metricbeat/module/vsphere/cluster/cluster_test.go @@ -0,0 +1,97 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package cluster + +import ( + "testing" + + mbtest "github.com/elastic/beats/v7/metricbeat/mb/testing" + "github.com/elastic/elastic-agent-libs/mapstr" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/vmware/govmomi/simulator" +) + +func TestFetchEventContents(t *testing.T) { + // Creating a new simulator model with VPX server to collect broad range of data. + model := simulator.VPX() + err := model.Create() + require.NoError(t, err, "failed to create model") + t.Cleanup(func() { model.Remove() }) + + ts := model.Service.NewServer() + t.Cleanup(func() { ts.Close() }) + + f := mbtest.NewReportingMetricSetV2WithContext(t, getConfig(ts)) + + events, errs := mbtest.ReportingFetchV2WithContext(f) + require.Empty(t, errs, "expected no error") + + require.NotEmpty(t, events, "didn't get any event, should have gotten at least X") + + event := events[0].MetricSetFields + + t.Logf("Fetched event from %s/%s event: %+v", f.Module().Name(), f.Name(), event) + + testEvent := mapstr.M{ + "name": "DC0_C0", + "host": mapstr.M{ + "count": 3, + "names": []string{"DC0_C0_H0", "DC0_C0_H1", "DC0_C0_H2"}, + }, + "datastore": mapstr.M{ + "count": 1, + "names": []string{"LocalDS_0"}, + }, + "network": mapstr.M{ + "count": 3, + "names": []string{"VM Network", "DVS0-DVUplinks-9", "DC0_DVPG0"}, + }, + } + + assert.Exactly(t, event, testEvent) +} + +func TestClusterMetricSetData(t *testing.T) { + model := simulator.VPX() + err := model.Create() + require.NoError(t, err, "failed to create model") + t.Cleanup(func() { model.Remove() }) + + ts := model.Service.NewServer() + t.Cleanup(func() { ts.Close() }) + + f := mbtest.NewReportingMetricSetV2WithContext(t, getConfig(ts)) + + err = mbtest.WriteEventsReporterV2WithContext(f, t, "") + assert.NoError(t, err, "failed to write events with reporter") +} + +func getConfig(ts *simulator.Server) map[string]interface{} { + urlSimulator := ts.URL.Scheme + "://" + ts.URL.Host + ts.URL.Path + + return map[string]interface{}{ + "module": "vsphere", + "metricsets": []string{"cluster"}, + "hosts": []string{urlSimulator}, + "username": "user", + "password": "pass", + "insecure": true, + } +} diff --git a/metricbeat/module/vsphere/cluster/data.go b/metricbeat/module/vsphere/cluster/data.go new file mode 100644 index 00000000000..37c2ac5c319 --- /dev/null +++ b/metricbeat/module/vsphere/cluster/data.go @@ -0,0 +1,52 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package cluster + +import ( + "github.com/vmware/govmomi/vim25/mo" + + "github.com/elastic/elastic-agent-libs/mapstr" +) + +func (m *ClusterMetricSet) mapEvent(cl mo.ClusterComputeResource, data *assetNames) mapstr.M { + event := mapstr.M{ + "host": mapstr.M{ + "count": len(data.outputHostNames), + "names": data.outputHostNames, + }, + "datastore": mapstr.M{ + "count": len(data.outputDatastoreNames), + "names": data.outputDatastoreNames, + }, + "network": mapstr.M{ + "count": len(data.outputNetworkNames), + "names": data.outputNetworkNames, + }, + "name": cl.Name, + } + + if cl.Configuration.DasConfig.Enabled != nil { + event.Put("das_config.enabled", *cl.Configuration.DasConfig.Enabled) + } + + if cl.Configuration.DasConfig.AdmissionControlEnabled != nil { + event.Put("das_config.admission.control.enabled", *cl.Configuration.DasConfig.AdmissionControlEnabled) + } + + return event +} diff --git a/metricbeat/module/vsphere/cluster/data_test.go b/metricbeat/module/vsphere/cluster/data_test.go new file mode 100644 index 00000000000..097b7254283 --- /dev/null +++ b/metricbeat/module/vsphere/cluster/data_test.go @@ -0,0 +1,79 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package cluster + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" + + "github.com/elastic/elastic-agent-libs/mapstr" +) + +func TestEventMapping(t *testing.T) { + var m *ClusterMetricSet + var ClusterTest = mo.ClusterComputeResource{ + ComputeResource: mo.ComputeResource{ + ManagedEntity: mo.ManagedEntity{ + Name: "Cluster_0", + }, + }, + Configuration: types.ClusterConfigInfo{ + DasConfig: types.ClusterDasConfigInfo{ + Enabled: types.NewBool(false), + AdmissionControlEnabled: types.NewBool(true), + }, + }, + } + + var assetNames = assetNames{ + outputHostNames: []string{"Host_0"}, + outputDatastoreNames: []string{"Datastore_0"}, + outputNetworkNames: []string{"Network_0"}, + } + + outputEvent := m.mapEvent(ClusterTest, &assetNames) + testEvent := mapstr.M{ + "das_config": mapstr.M{ + "enabled": false, + "admission": mapstr.M{ + "control": mapstr.M{ + "enabled": true, + }, + }, + }, + "name": "Cluster_0", + "host": mapstr.M{ + "count": 1, + "names": []string{"Host_0"}, + }, + "datastore": mapstr.M{ + "count": 1, + "names": []string{"Datastore_0"}, + }, + "network": mapstr.M{ + "count": 1, + "names": []string{"Network_0"}, + }, + } + + assert.Exactly(t, outputEvent, testEvent) + +} diff --git a/metricbeat/module/vsphere/datastore/_meta/data.json b/metricbeat/module/vsphere/datastore/_meta/data.json index 48d6940708a..1e1a1691219 100644 --- a/metricbeat/module/vsphere/datastore/_meta/data.json +++ b/metricbeat/module/vsphere/datastore/_meta/data.json @@ -1,64 +1,64 @@ { "@timestamp": "2017-10-12T08:05:34.853Z", "event": { - "dataset": "vsphere.datastore", - "duration": 115000, - "module": "vsphere" + "dataset": "vsphere.datastore", + "duration": 115000, + "module": "vsphere" }, "metricset": { - "name": "datastore", - "period": 10000 + "name": "datastore", + "period": 10000 }, "service": { - "address": "127.0.0.1:33365", - "type": "vsphere" + "address": "127.0.0.1:33365", + "type": "vsphere" }, "vsphere": { - "datastore": { - "iops": 0, - "host": { - "count": 1, - "names": [ - "DC3_H0" - ] - }, - "status": "green", - "vm": { - "count": 6, - "names": [ - "DC3_H0_VM0" - ] - }, - "capacity": { - "free": { - "bytes": 37120094208 - }, - "total": { - "bytes": 74686664704 - }, - "used": { - "bytes": 37566570496, - "pct": 0.502988996026061 - }, - "read": { - "bytes": 0, - "latency": { - "total": { - "ms": 0 - } - } - }, - "write": { - "bytes": 337000, - "latency": { - "total": { - "ms": 0 - } - } - } - }, - "fstype": "local", - "name": "LocalDS_0" - } + "datastore": { + "iops": 0, + "host": { + "count": 1, + "names": [ + "DC3_H0" + ] + }, + "status": "green", + "vm": { + "count": 6, + "names": [ + "DC3_H0_VM0" + ] + }, + "read": { + "bytes": 0, + "latency": { + "total": { + "ms": 0 + } + } + }, + "write": { + "bytes": 337000, + "latency": { + "total": { + "ms": 0 + } + } + }, + "capacity": { + "free": { + "bytes": 37120094208 + }, + "total": { + "bytes": 74686664704 + }, + "used": { + "bytes": 37566570496, + "pct": 0.502988996026061 + } + }, + "fstype": "local", + "name": "LocalDS_0" + } } } \ No newline at end of file diff --git a/metricbeat/module/vsphere/datastore/data.go b/metricbeat/module/vsphere/datastore/data.go index 90820f7f5d5..0b438f96268 100644 --- a/metricbeat/module/vsphere/datastore/data.go +++ b/metricbeat/module/vsphere/datastore/data.go @@ -23,16 +23,18 @@ import ( "github.com/elastic/elastic-agent-libs/mapstr" ) -func (m *MetricSet) eventMapping(ds mo.Datastore, data *metricData) mapstr.M { +func (m *DataStoreMetricSet) mapEvent(ds mo.Datastore, data *metricData) mapstr.M { event := mapstr.M{ "name": ds.Summary.Name, "fstype": ds.Summary.Type, "status": ds.OverallStatus, "host": mapstr.M{ - "count": len(data.assetNames.outputHsNames), + "count": len(data.assetNames.outputHostNames), + "names": data.assetNames.outputHostNames, }, "vm": mapstr.M{ "count": len(data.assetNames.outputVmNames), + "names": data.assetNames.outputVmNames, }, "capacity": mapstr.M{ "total": mapstr.M{ @@ -52,21 +54,13 @@ func (m *MetricSet) eventMapping(ds mo.Datastore, data *metricData) mapstr.M { event.Put("capacity.used.pct", usedSpacePercent) } - if len(data.assetNames.outputHsNames) > 0 { - event.Put("host.names", data.assetNames.outputHsNames) - } - - if len(data.assetNames.outputVmNames) > 0 { - event.Put("vm.names", data.assetNames.outputVmNames) - } - mapPerfMetricToEvent(event, data.perfMetrics) return event } func mapPerfMetricToEvent(event mapstr.M, perfMetricMap map[string]interface{}) { - const bytesMultiplier = 1000 + const bytesMultiplier int64 = 1024 if val, exist := perfMetricMap["datastore.read.average"]; exist { event.Put("read.bytes", val.(int64)*bytesMultiplier) diff --git a/metricbeat/module/vsphere/datastore/data_test.go b/metricbeat/module/vsphere/datastore/data_test.go index d57d2ab1319..4ecc091794c 100644 --- a/metricbeat/module/vsphere/datastore/data_test.go +++ b/metricbeat/module/vsphere/datastore/data_test.go @@ -28,7 +28,7 @@ import ( ) func TestEventMapping(t *testing.T) { - var m *MetricSet + var m *DataStoreMetricSet var datastoreTest = mo.Datastore{ Summary: types.DatastoreSummary{ Name: "datastore-test", @@ -54,12 +54,12 @@ func TestEventMapping(t *testing.T) { "datastore.totalWriteLatency.average": int64(100), }, assetNames: assetNames{ - outputHsNames: []string{"DC3_H0"}, - outputVmNames: []string{"DC3_H0_VM0"}, + outputHostNames: []string{"DC3_H0"}, + outputVmNames: []string{"DC3_H0_VM0"}, }, } - outputEvent := m.eventMapping(datastoreTest, &metricDataTest) + outputEvent := m.mapEvent(datastoreTest, &metricDataTest) testEvent := mapstr.M{ "fstype": "local", "status": types.ManagedEntityStatus("green"), @@ -74,7 +74,7 @@ func TestEventMapping(t *testing.T) { "names": []string{"DC3_H0_VM0"}, }, "read": mapstr.M{ - "bytes": int64(100000), + "bytes": int64(102400), "latency": mapstr.M{ "total": mapstr.M{ "ms": int64(100), @@ -82,7 +82,7 @@ func TestEventMapping(t *testing.T) { }, }, "write": mapstr.M{ - "bytes": int64(200000), + "bytes": int64(204800), "latency": mapstr.M{ "total": mapstr.M{ "ms": int64(100), diff --git a/metricbeat/module/vsphere/datastore/datastore.go b/metricbeat/module/vsphere/datastore/datastore.go index 280d7da9369..ee2d08feff1 100644 --- a/metricbeat/module/vsphere/datastore/datastore.go +++ b/metricbeat/module/vsphere/datastore/datastore.go @@ -41,7 +41,7 @@ func init() { } // MetricSet type defines all fields of the MetricSet. -type MetricSet struct { +type DataStoreMetricSet struct { *vsphere.MetricSet } @@ -51,7 +51,7 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { if err != nil { return nil, err } - return &MetricSet{ms}, nil + return &DataStoreMetricSet{ms}, nil } type metricData struct { @@ -60,14 +60,23 @@ type metricData struct { } type assetNames struct { - outputVmNames []string - outputHsNames []string + outputVmNames []string + outputHostNames []string +} + +// Define metrics to be collected +var metricSet = map[string]struct{}{ + "datastore.read.average": {}, + "datastore.write.average": {}, + "datastore.datastoreIops.average": {}, + "datastore.totalReadLatency.average": {}, + "datastore.totalWriteLatency.average": {}, } // Fetch methods implements the data gathering and data conversion to the right // format. It publishes the event which is then forwarded to the output. In case // of an error set the Error field of mb.Event or simply call report.Error(). -func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error { +func (m *DataStoreMetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error { ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -115,20 +124,12 @@ func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error { // Filter for required metrics var metricIds []types.PerfMetricId - - // Define metrics to be collected - for metricName := range map[string]struct{}{ - "datastore.read.average": {}, - "datastore.write.average": {}, - "datastore.datastoreIops.average": {}, - "datastore.totalReadLatency.average": {}, - "datastore.totalWriteLatency.average": {}, - } { + for metricName := range metricSet { if metric, ok := metrics[metricName]; ok { metricIds = append(metricIds, types.PerfMetricId{CounterId: metric.Key}) - continue + } else { + m.Logger().Warnf("Metric %s not found", metricName) } - m.Logger().Warnf("Metric %s not found", metricName) } pc := property.DefaultCollector(c) @@ -178,7 +179,7 @@ func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error { } reporter.Event(mb.Event{ - MetricSetFields: m.eventMapping(dst[i], &metricData{ + MetricSetFields: m.mapEvent(dst[i], &metricData{ perfMetrics: metricMap, assetNames: *assetNames, }), @@ -204,9 +205,8 @@ func getAssetNames(ctx context.Context, pc *property.Collector, ds *mo.Datastore } } } - - // calling Host explicitly because of mo.Datastore.hHost has types.DatastoreHostMount instead of mo.ManagedEntity - outputHsNames := make([]string, 0, len(ds.Host)) + // calling Host explicitly because of mo.Datastore.Host has types.DatastoreHostMount instead of mo.ManagedEntity + outputHostNames := make([]string, 0, len(ds.Host)) if len(ds.Host) > 0 { hsRefs := make([]types.ManagedObjectReference, 0, len(ds.Host)) for _, obj := range ds.Host { @@ -226,12 +226,12 @@ func getAssetNames(ctx context.Context, pc *property.Collector, ds *mo.Datastore for _, host := range hosts { name := strings.ReplaceAll(host.Name, ".", "_") - outputHsNames = append(outputHsNames, name) + outputHostNames = append(outputHostNames, name) } } return &assetNames{ - outputHsNames: outputHsNames, - outputVmNames: outputVmNames, + outputHostNames: outputHostNames, + outputVmNames: outputVmNames, }, nil } diff --git a/metricbeat/module/vsphere/datastore/datastore_test.go b/metricbeat/module/vsphere/datastore/datastore_test.go index f860a2d228a..e94989f1055 100644 --- a/metricbeat/module/vsphere/datastore/datastore_test.go +++ b/metricbeat/module/vsphere/datastore/datastore_test.go @@ -23,30 +23,32 @@ import ( mbtest "github.com/elastic/beats/v7/metricbeat/mb/testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/vmware/govmomi/simulator" ) func TestFetchEventContents(t *testing.T) { // Creating a new simulator model with VPX server to collect broad range of data. model := simulator.VPX() - if err := model.Create(); err != nil { - t.Fatal(err) - } - defer model.Remove() + err := model.Create() + require.NoError(t, err, "failed to create model") + t.Cleanup(func() { model.Remove() }) ts := model.Service.NewServer() - defer ts.Close() + t.Cleanup(func() { ts.Close() }) f := mbtest.NewReportingMetricSetV2WithContext(t, getConfig(ts)) events, errs := mbtest.ReportingFetchV2WithContext(f) if len(errs) > 0 { t.Fatalf("Expected 0 error, had %d. %v\n", len(errs), errs) } - assert.NotEmpty(t, events) + require.Empty(t, errs, "expected no error") + + require.NotEmpty(t, events, "didn't get any event, should have gotten at least X") event := events[0].MetricSetFields - t.Logf("%s/%s event: %+v", f.Module().Name(), f.Name(), event.StringToPrint()) + t.Logf("Fetched event from %s/%s event: %+v", f.Module().Name(), f.Name(), event) assert.EqualValues(t, "LocalDS_0", event["name"]) assert.EqualValues(t, "OTHER", event["fstype"]) @@ -78,20 +80,19 @@ func TestFetchEventContents(t *testing.T) { } } -func TestData(t *testing.T) { +func TestDataStoreMetricSetData(t *testing.T) { model := simulator.ESX() - if err := model.Create(); err != nil { - t.Fatal(err) - } + err := model.Create() + require.NoError(t, err, "failed to create model") + t.Cleanup(func() { model.Remove() }) ts := model.Service.NewServer() - defer ts.Close() + t.Cleanup(func() { ts.Close() }) f := mbtest.NewReportingMetricSetV2WithContext(t, getConfig(ts)) - if err := mbtest.WriteEventsReporterV2WithContext(f, t, ""); err != nil { - t.Fatal("write", err) - } + err = mbtest.WriteEventsReporterV2WithContext(f, t, "") + assert.NoError(t, err, "failed to write events with reporter") } func getConfig(ts *simulator.Server) map[string]interface{} { diff --git a/metricbeat/module/vsphere/fields.go b/metricbeat/module/vsphere/fields.go index 62941aa3afc..c662eb7e840 100644 --- a/metricbeat/module/vsphere/fields.go +++ b/metricbeat/module/vsphere/fields.go @@ -32,5 +32,5 @@ func init() { // AssetVsphere returns asset data. // This is the base64 encoded zlib format compressed contents of module/vsphere. func AssetVsphere() string { - return "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" + return "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" } diff --git a/metricbeat/modules.d/vsphere.yml.disabled b/metricbeat/modules.d/vsphere.yml.disabled index 4a05170dd05..87c916cc6e5 100644 --- a/metricbeat/modules.d/vsphere.yml.disabled +++ b/metricbeat/modules.d/vsphere.yml.disabled @@ -3,6 +3,7 @@ - module: vsphere #metricsets: + # - cluster # - datastore # - host # - virtualmachine diff --git a/x-pack/metricbeat/metricbeat.reference.yml b/x-pack/metricbeat/metricbeat.reference.yml index ce703584877..71541d491fd 100644 --- a/x-pack/metricbeat/metricbeat.reference.yml +++ b/x-pack/metricbeat/metricbeat.reference.yml @@ -1568,7 +1568,7 @@ metricbeat.modules: #------------------------------- VSphere Module ------------------------------- - module: vsphere enabled: true - metricsets: ["datastore", "host", "virtualmachine", "network", "resourcepool"] + metricsets: ["cluster", "datastore", "host", "virtualmachine", "network", "resourcepool"] # Real-time data collection – An ESXi Server collects data for each performance counter every 20 seconds. period: 20s hosts: ["https://localhost/sdk"]