diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index 15541fc6a6f..4ed7c841c78 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -203,6 +203,20 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Add SSL support to mysql module {pull}37997[37997] - Add SSL support for aerospike module {pull}38126[38126] +- Add `use_kubeadm` config option in kubernetes module in order to toggle kubeadm-config api requests {pull}40086[40086] +- Log the total time taken for GCP `ListTimeSeries` and `AggregatedList` requests {pull}40661[40661] +- Add new metrics for the vSphere Host metricset. {pull}40429[40429] +- Add new metrics for the vSphere Datastore metricset. {pull}40441[40441] +- Add new metricset cluster for the vSphere module. {pull}40536[40536] +- Add new metricset network for the vSphere module. {pull}40559[40559] +- Add new metricset resourcepool for the vSphere module. {pull}40456[40456] +- Add new metricset datastorecluster for vSphere module. {pull}40634[40634] {pull}40694[40694] +- Add new metrics for the vSphere Virtualmachine metricset. {pull}40485[40485] +- Add support for snapshot in vSphere virtualmachine metricset {pull}40683[40683] +- Update fields to use mapstr in vSphere virtualmachine metricset {pull}40707[40707] +- Add support for period based intervalID in vSphere host and datastore metricsets {pull}40678[40678] +- Add new metrics fot datastore and minor changes to overall vSphere metrics {pull}40766[40766] +- Add `metrics_count` to Prometheus module if `metrics_count: true` is set. {pull}40411[40411] *Metricbeat* diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index df93b4a6d8c..14d2b61436f 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -66929,6 +66929,200 @@ format: percent -- +<<<<<<< HEAD +======= +*`vsphere.datastore.disk.capacity.bytes`*:: ++ +-- +Configured size of the datastore. + + +type: long + +format: bytes + +-- + +*`vsphere.datastore.disk.capacity.usage.bytes`*:: ++ +-- +The amount of storage capacity currently being consumed by datastore. + + +type: long + +format: bytes + +-- + +*`vsphere.datastore.disk.provisioned.bytes`*:: ++ +-- +Amount of storage set aside for use by a datastore. + + +type: long + +format: bytes + +-- + +*`vsphere.datastore.fstype`*:: ++ +-- +Filesystem type. + + +type: keyword + +-- + +*`vsphere.datastore.host.count`*:: ++ +-- +Number of hosts. + + +type: long + +-- + +*`vsphere.datastore.host.names`*:: ++ +-- +List of all the host names. + + +type: keyword + +-- + +*`vsphere.datastore.name`*:: ++ +-- +Datastore name. + + +type: keyword + +-- + +*`vsphere.datastore.read.bytes`*:: ++ +-- +Rate of reading data from the datastore. + + +type: long + +format: bytes + +-- + +*`vsphere.datastore.status`*:: ++ +-- +Status of the datastore. + + +type: keyword + +-- + +*`vsphere.datastore.vm.count`*:: ++ +-- +Number of VMs. + + +type: long + +-- + +*`vsphere.datastore.vm.names`*:: ++ +-- +List of all the VM names. + + +type: keyword + +-- + +*`vsphere.datastore.write.bytes`*:: ++ +-- +Rate of writing data to the datastore. + + +type: long + +format: bytes + +-- + +[float] +=== datastorecluster + +Datastore Cluster + + + +*`vsphere.datastorecluster.name`*:: ++ +-- +The Datastore Cluster name. + + +type: keyword + +-- + +*`vsphere.datastorecluster.capacity.bytes`*:: ++ +-- +Total capacity of this storage pod, in bytes. + + +type: long + +format: bytes + +-- + +*`vsphere.datastorecluster.free_space.bytes`*:: ++ +-- +Total free space on this storage pod, in bytes. + + +type: long + +format: bytes + +-- + +*`vsphere.datastorecluster.datastore.names`*:: ++ +-- +List of all the Datastore names associated with the Datastore Cluster. + + +type: keyword + +-- + +*`vsphere.datastorecluster.datastore.count`*:: ++ +-- +Number of datastores in the Datastore Cluster. + + +type: long + +-- + +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) [float] === host @@ -67167,6 +67361,90 @@ type: keyword -- +<<<<<<< HEAD +======= + +*`vsphere.virtualmachine.datastore.names`*:: ++ +-- +Names of the datastore associated to this virtualmachine. + + +type: keyword + +-- + +*`vsphere.virtualmachine.datastore.count`*:: ++ +-- +Number of datastores associated to this virtualmachine. + + +type: long + +-- + + +*`vsphere.virtualmachine.network.names`*:: ++ +-- +Names of the networks associated to this virtualmachine. + + +type: keyword + +-- + +*`vsphere.virtualmachine.network.count`*:: ++ +-- +Number of networks associated to this virtualmachine. + + +type: long + +-- + +*`vsphere.virtualmachine.status`*:: ++ +-- +Overall health and status of a virtual machine. + + +type: keyword + +-- + +*`vsphere.virtualmachine.uptime`*:: ++ +-- +The uptime of the VM in seconds. + + +type: long + +-- + + +*`vsphere.virtualmachine.snapshot.info.*`*:: ++ +-- +Details of the snapshots of this virtualmachine. + +type: object + +-- + +*`vsphere.virtualmachine.snapshot.count`*:: ++ +-- +The number of snapshots of this virtualmachine. + +type: long + +-- + +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) [[exported-fields-windows]] == Windows fields diff --git a/metricbeat/module/vsphere/datastore/_meta/data.json b/metricbeat/module/vsphere/datastore/_meta/data.json index 944ecb1189f..f7937a10418 100644 --- a/metricbeat/module/vsphere/datastore/_meta/data.json +++ b/metricbeat/module/vsphere/datastore/_meta/data.json @@ -15,6 +15,39 @@ }, "vsphere": { "datastore": { +<<<<<<< HEAD +======= + "host": { + "count": 1, + "names": [ + "DC3_H0" + ] + }, + "status": "green", + "vm": { + "count": 6, + "names": [ + "DC3_H0_VM0" + ] + }, + "read": { + "bytes": 0 + }, + "write": { + "bytes": 337000 + }, + "disk": { + "capacity": { + "usage": { + "bytes": 520505786368 + }, + "bytes": 1610344300544 + }, + "provisioned": { + "bytes": 520505786368 + } + }, +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) "capacity": { "free": { "bytes": 37120094208 diff --git a/metricbeat/module/vsphere/datastore/_meta/fields.yml b/metricbeat/module/vsphere/datastore/_meta/fields.yml index 632bb13cfe2..4241da378b0 100644 --- a/metricbeat/module/vsphere/datastore/_meta/fields.yml +++ b/metricbeat/module/vsphere/datastore/_meta/fields.yml @@ -32,4 +32,60 @@ description: > Used percent of the datastore format: percent +<<<<<<< HEAD +======= + - name: disk.capacity.bytes + type: long + description: > + Configured size of the datastore. + format: bytes + - name: disk.capacity.usage.bytes + type: long + description: > + The amount of storage capacity currently being consumed by datastore. + format: bytes + - name: disk.provisioned.bytes + type: long + description: > + Amount of storage set aside for use by a datastore. + format: bytes + - name: fstype + type: keyword + description: > + Filesystem type. + - name: host.count + type: long + description: > + Number of hosts. + - name: host.names + type: keyword + description: > + List of all the host names. + - name: name + type: keyword + description: > + Datastore name. + - name: read.bytes + type: long + description: > + Rate of reading data from the datastore. + format: bytes + - name: status + type: keyword + description: > + Status of the datastore. + - name: vm.count + type: long + description: > + Number of VMs. + - name: vm.names + type: keyword + description: > + List of all the VM names. + - name: write.bytes + type: long + description: > + Rate of writing data to the datastore. + format: bytes +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) diff --git a/metricbeat/module/vsphere/datastore/data.go b/metricbeat/module/vsphere/datastore/data.go new file mode 100644 index 00000000000..413854cafa7 --- /dev/null +++ b/metricbeat/module/vsphere/datastore/data.go @@ -0,0 +1,80 @@ +// 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 datastore + +import ( + "github.com/vmware/govmomi/vim25/mo" + + "github.com/elastic/elastic-agent-libs/mapstr" +) + +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.outputHostNames), + "names": data.assetNames.outputHostNames, + }, + "vm": mapstr.M{ + "count": len(data.assetNames.outputVmNames), + "names": data.assetNames.outputVmNames, + }, + "capacity": mapstr.M{ + "total": mapstr.M{ + "bytes": ds.Summary.Capacity, + }, + "free": mapstr.M{ + "bytes": ds.Summary.FreeSpace, + }, + "used": mapstr.M{ + "bytes": ds.Summary.Capacity - ds.Summary.FreeSpace, + }, + }, + } + + if ds.Summary.Capacity > 0 { + usedSpacePercent := float64(ds.Summary.Capacity-ds.Summary.FreeSpace) / float64(ds.Summary.Capacity) + event.Put("capacity.used.pct", usedSpacePercent) + } + + mapPerfMetricToEvent(event, data.perfMetrics) + + return event +} + +func mapPerfMetricToEvent(event mapstr.M, perfMetricMap map[string]interface{}) { + const bytesMultiplier int64 = 1024 + + if val, exist := perfMetricMap["datastore.read.average"]; exist { + event.Put("read.bytes", val.(int64)*bytesMultiplier) + } + if val, exist := perfMetricMap["datastore.write.average"]; exist { + event.Put("write.bytes", val.(int64)*bytesMultiplier) + } + if val, exist := perfMetricMap["disk.capacity.latest"]; exist { + event.Put("disk.capacity.bytes", val.(int64)*bytesMultiplier) + } + if val, exist := perfMetricMap["disk.capacity.usage.average"]; exist { + event.Put("disk.capacity.usage.bytes", val.(int64)*bytesMultiplier) + } + if val, exist := perfMetricMap["disk.provisioned.latest"]; exist { + event.Put("disk.provisioned.bytes", val.(int64)*bytesMultiplier) + } +} diff --git a/metricbeat/module/vsphere/datastore/data_test.go b/metricbeat/module/vsphere/datastore/data_test.go new file mode 100644 index 00000000000..23189e3e49f --- /dev/null +++ b/metricbeat/module/vsphere/datastore/data_test.go @@ -0,0 +1,106 @@ +// 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 datastore + +import ( + "testing" + + "github.com/elastic/elastic-agent-libs/mapstr" + + "github.com/stretchr/testify/assert" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +func TestEventMapping(t *testing.T) { + var datastoreTest = mo.Datastore{ + Summary: types.DatastoreSummary{ + Name: "datastore-test", + Type: "local", + Capacity: 5000000, + FreeSpace: 5000000, + }, + ManagedEntity: mo.ManagedEntity{ + OverallStatus: "green", + }, + Host: []types.DatastoreHostMount{}, + Vm: []types.ManagedObjectReference{ + {Type: "VirtualMachine", Value: "vm-test"}, + }, + } + + var metricDataTest = metricData{ + perfMetrics: map[string]interface{}{ + "datastore.read.average": int64(100), + "datastore.write.average": int64(200), + "disk.capacity.latest": int64(10000), + "disk.capacity.usage.average": int64(5000), + "disk.provisioned.latest": int64(5000), + }, + assetNames: assetNames{ + outputHostNames: []string{"DC3_H0"}, + outputVmNames: []string{"DC3_H0_VM0"}, + }, + } + + outputEvent := (&DataStoreMetricSet{}).mapEvent(datastoreTest, &metricDataTest) + testEvent := mapstr.M{ + "fstype": "local", + "status": types.ManagedEntityStatus("green"), + "name": "datastore-test", + "host": mapstr.M{ + "count": 1, + "names": []string{"DC3_H0"}, + }, + "vm": mapstr.M{ + "count": 1, + "names": []string{"DC3_H0_VM0"}, + }, + "read": mapstr.M{ + "bytes": int64(102400), + }, + "write": mapstr.M{ + "bytes": int64(204800), + }, + "disk": mapstr.M{ + "capacity": mapstr.M{ + "bytes": int64(10240000), + "usage": mapstr.M{ + "bytes": int64(5120000), + }, + }, + "provisioned": mapstr.M{ + "bytes": int64(5120000), + }, + }, + "capacity": mapstr.M{ + "free": mapstr.M{ + "bytes": int64(5000000), + }, + "total": mapstr.M{ + "bytes": int64(5000000), + }, + "used": mapstr.M{ + "bytes": int64(0), + "pct": float64(0), + }, + }, + } + + assert.Exactly(t, outputEvent, testEvent) +} diff --git a/metricbeat/module/vsphere/datastore/datastore.go b/metricbeat/module/vsphere/datastore/datastore.go index 4ec84b4b74e..1c10863f38e 100644 --- a/metricbeat/module/vsphere/datastore/datastore.go +++ b/metricbeat/module/vsphere/datastore/datastore.go @@ -48,7 +48,30 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { if err != nil { return nil, err } +<<<<<<< HEAD return &MetricSet{ms}, nil +======= + return &DataStoreMetricSet{ms}, nil +} + +type metricData struct { + perfMetrics map[string]interface{} + assetNames assetNames +} + +type assetNames struct { + outputVmNames []string + outputHostNames []string +} + +// Define metrics to be collected +var metricSet = map[string]struct{}{ + "datastore.read.average": {}, + "datastore.write.average": {}, + "disk.capacity.latest": {}, + "disk.capacity.usage.average": {}, + "disk.provisioned.latest": {}, +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) } // Fetch methods implements the data gathering and data conversion to the right @@ -76,7 +99,7 @@ func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error { v, err := mgr.CreateContainerView(ctx, c.ServiceContent.RootFolder, []string{"Datastore"}, true) if err != nil { - return fmt.Errorf("error in CreateContainerView: %w", err) + return fmt.Errorf("error in creating container view: %w", err) } defer func() { @@ -91,6 +114,7 @@ func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error { return fmt.Errorf("error in Retrieve: %w", err) } +<<<<<<< HEAD for _, ds := range dst { var usedSpacePercent float64 if ds.Summary.Capacity > 0 { @@ -117,8 +141,159 @@ func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error { reporter.Event(mb.Event{ MetricSetFields: event, +======= + // Create a performance manager + perfManager := performance.NewManager(c) + + // Retrieve all available metrics + metrics, err := perfManager.CounterInfoByName(ctx) + if err != nil { + return fmt.Errorf("failed to retrieve metrics: %w", err) + } + + pc := property.DefaultCollector(client.Client) + for i := range dst { + if ctx.Err() != nil { + return ctx.Err() + } + + assetNames, err := getAssetNames(ctx, pc, &dst[i]) + if err != nil { + m.Logger().Errorf("Failed to retrieve object from datastore %s: %v", dst[i].Name, err) + } + + metricMap, err := m.getPerfMetrics(ctx, perfManager, dst[i], metrics) + if err != nil { + m.Logger().Errorf("Failed to retrieve performance metrics from datastore %s: %v", dst[i].Name, err) + } + + reporter.Event(mb.Event{ + MetricSetFields: m.mapEvent(dst[i], &metricData{ + perfMetrics: metricMap, + assetNames: assetNames, + }), +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) }) } return nil } +<<<<<<< HEAD +======= + +func getAssetNames(ctx context.Context, pc *property.Collector, ds *mo.Datastore) (assetNames, error) { + outputVmNames := make([]string, 0, len(ds.Vm)) + if len(ds.Vm) > 0 { + var objects []mo.ManagedEntity + if err := pc.Retrieve(ctx, ds.Vm, []string{"name"}, &objects); err != nil { + return assetNames{}, err + } + + for _, ob := range objects { + if ob.Reference().Type == "VirtualMachine" { + name := strings.ReplaceAll(ob.Name, ".", "_") + outputVmNames = append(outputVmNames, name) + } + } + } + + // 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 { + if obj.Key.Type == "HostSystem" { + hsRefs = append(hsRefs, obj.Key) + } + } + + // Retrieve Host names + var hosts []mo.HostSystem + if len(hsRefs) > 0 { + err := pc.Retrieve(ctx, hsRefs, []string{"name"}, &hosts) + if err != nil { + return assetNames{}, err + } + } + + for _, host := range hosts { + name := strings.ReplaceAll(host.Name, ".", "_") + outputHostNames = append(outputHostNames, name) + } + } + + return assetNames{ + outputHostNames: outputHostNames, + outputVmNames: outputVmNames, + }, nil +} + +func (m *DataStoreMetricSet) getPerfMetrics(ctx context.Context, perfManager *performance.Manager, dst mo.Datastore, metrics map[string]*types.PerfCounterInfo) (metricMap map[string]interface{}, err error) { + metricMap = make(map[string]interface{}) + + period := int32(m.Module().Config().Period.Seconds()) + availableMetric, err := perfManager.AvailableMetric(ctx, dst.Reference(), period) + if err != nil { + return nil, fmt.Errorf("failed to get available metrics: %w", err) + } + + availableMetricByKey := availableMetric.ByKey() + + // Filter for required metrics + var metricIDs []types.PerfMetricId + for key, metric := range metricSet { + if counter, ok := metrics[key]; ok { + if _, exists := availableMetricByKey[counter.Key]; exists { + metricIDs = append(metricIDs, types.PerfMetricId{ + CounterId: counter.Key, + Instance: "*", + }) + } + } else { + m.Logger().Warnf("Metric %s not found", metric) + } + } + + spec := types.PerfQuerySpec{ + Entity: dst.Reference(), + MetricId: metricIDs, + MaxSample: 1, + IntervalId: period, // using refreshRate as interval + } + + // Query performance data + samples, err := perfManager.Query(ctx, []types.PerfQuerySpec{spec}) + if err != nil { + if strings.Contains(err.Error(), "ServerFaultCode: A specified parameter was not correct: querySpec.interval") { + return metricMap, fmt.Errorf("failed to query performance data: use one of the system's supported interval. consider adjusting period: %w", err) + } + + return metricMap, fmt.Errorf("failed to query performance data: %w", err) + } + + if len(samples) == 0 { + m.Logger().Debug("No samples returned from performance manager") + return metricMap, nil + } + + results, err := perfManager.ToMetricSeries(ctx, samples) + if err != nil { + return metricMap, fmt.Errorf("failed to convert performance data to metric series: %w", err) + } + + if len(results) == 0 { + m.Logger().Debug("No results returned from metric series conversion") + return metricMap, nil + } + + for _, result := range results[0].Value { + if len(result.Value) > 0 { + metricMap[result.Name] = result.Value[0] + continue + } + m.Logger().Debugf("For datastore %s, Metric %s: No result found", dst.Name, result.Name) + } + + return metricMap, nil +} +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) diff --git a/metricbeat/module/vsphere/datastore/datastore_test.go b/metricbeat/module/vsphere/datastore/datastore_test.go index 88f5b772b5a..ebd2422dba9 100644 --- a/metricbeat/module/vsphere/datastore/datastore_test.go +++ b/metricbeat/module/vsphere/datastore/datastore_test.go @@ -27,6 +27,7 @@ import ( ) func TestFetchEventContents(t *testing.T) { +<<<<<<< HEAD model := simulator.ESX() if err := model.Create(); err != nil { t.Fatal(err) @@ -42,6 +43,21 @@ func TestFetchEventContents(t *testing.T) { } assert.NotEmpty(t, events) +======= + // 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(model.Remove) + + ts := model.Service.NewServer() + t.Cleanup(ts.Close) + + f := mbtest.NewReportingMetricSetV2WithContext(t, getConfig(ts)) + events, errs := mbtest.ReportingFetchV2WithContext(f) + require.Empty(t, errs, "Expected no errors during fetch") + require.NotEmpty(t, events, "Expected to receive at least one event") +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) event := events[0].MetricSetFields @@ -51,8 +67,23 @@ func TestFetchEventContents(t *testing.T) { assert.EqualValues(t, "local", event["fstype"]) // Values are based on the result 'df -k'. +<<<<<<< HEAD fields := []string{"capacity.total.bytes", "capacity.free.bytes", "capacity.used.bytes"} +======= + fields := []string{ + "capacity.total.bytes", + "capacity.free.bytes", + "status", + "host.count", + "vm.count", + "write.bytes", + "capacity.used.bytes", + "disk.capacity.usage.bytes", + "disk.capacity.bytes", + "disk.provisioned.bytes", + } +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) for _, field := range fields { value, err := event.GetValue(field) if err != nil { @@ -78,12 +109,21 @@ func isNonNegativeInt64(t testing.TB, field string, v interface{}) { func TestData(t *testing.T) { model := simulator.ESX() +<<<<<<< HEAD if err := model.Create(); err != nil { t.Fatal(err) } ts := model.Service.NewServer() defer ts.Close() +======= + err := model.Create() + require.NoError(t, err, "failed to create model") + t.Cleanup(model.Remove) + + ts := model.Service.NewServer() + t.Cleanup(ts.Close) +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) f := mbtest.NewReportingMetricSetV2WithContext(t, getConfig(ts)) @@ -93,12 +133,10 @@ func TestData(t *testing.T) { } 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{"datastore"}, - "hosts": []string{urlSimulator}, + "hosts": []string{ts.URL.String()}, "username": "user", "password": "pass", "insecure": true, diff --git a/metricbeat/module/vsphere/fields.go b/metricbeat/module/vsphere/fields.go index fae0b2cc264..9a4e06f7a81 100644 --- a/metricbeat/module/vsphere/fields.go +++ b/metricbeat/module/vsphere/fields.go @@ -32,5 +32,9 @@ func init() { // AssetVsphere returns asset data. // This is the base64 encoded zlib format compressed contents of module/vsphere. func AssetVsphere() string { +<<<<<<< HEAD return "eJzsl8+OmzAQxu95itHedx+AQ6Vqq20vaSttt9fIgSG4MQyyh6zo01e2IeKP002KaS/1ASnYfN8PzHxD7uGIbQInUxeocQPAkhUmcHd6dmfuNgAZmlTLmiVVCbzbAAB0s1BS1ih7mUaFwmACB7EByCWqzCRu6T1UosShhR3c1naxpqbuzgRcxkJDsUywMExnubDkRdluKiAyvo9+TDGGKPY4muhJjti+ks4mc7/hseNDzzTX7Q1zY/XjWT5JhaY1jCXMhHvPVNQildw+MLFQD/uW0QQJFFWH2+y/WUVwikA5cIHBjbEjJ10KTmBuP+PMNWJUzCeNGJ2yMZhFpXwxmK1DWaccZDSpUJjtckViuuAa1hp1ihVfS9stP8/OgqEgw0syYXL9v46DT2T4chKkdeM3pyx+xnyBHr++gKxgO1Ed2vociOfrU+AKY1fY8XxdWb9hW2JJeq1i3Tpxax+SfrtKO7i1cjkS3jpxvBSuQn4lfdzZX2GwPyraz14WxrLn7yCpuRGqFGkhq0XfLxeVbk8tG3sPcnqfS4NrIjgys4eVsrJvJpMsXyujv/ttgK3fh8txTRHfsanplxq1YFkd4Nl/yv1vGus1jfcnIZXYq5s6x6FBw6v1D8rhozVYnNSO1VXoiqg+HaK0vPiPddT4oj1X9wrGhx32weWsaWOYyp3vFEFC2v/A2T8Bf3K3IM4enTEEjP9qr/4VAAD//9YITTs=" +======= + return "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" +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) } diff --git a/metricbeat/module/vsphere/host/_meta/data.json b/metricbeat/module/vsphere/host/_meta/data.json index b2df68bd4f6..d8cc4cbb05d 100644 --- a/metricbeat/module/vsphere/host/_meta/data.json +++ b/metricbeat/module/vsphere/host/_meta/data.json @@ -5,6 +5,7 @@ "period": 10000 }, "service": { +<<<<<<< HEAD "address": "https://localhost:8989/sdk", "type": "vsphere" }, @@ -12,8 +13,18 @@ "module": "vsphere", "duration": 23519250, "dataset": "vsphere.host" +======= + "address": "https://localhost:8989/sdk", + "type": "vsphere" +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) + }, + "event": { + "module": "vsphere", + "duration": 23519250, + "dataset": "vsphere.host" }, "vsphere": { +<<<<<<< HEAD "host": { "cpu": { "used": { @@ -42,5 +53,130 @@ ], "name": "DC0_H0" } +======= + "host": { + "cpu": { + "used": { + "mhz": 67 + }, + "total": { + "mhz": 4588 + }, + "free": { + "mhz": 4521 + } + }, + "disk": { + "capacity": { + "usage": { + "bytes": 0 + } + }, + "devicelatency": { + "average": { + "ms": 0 + } + }, + "latency": { + "total": { + "ms": 18 + } + }, + "total": { + "bytes": 262000 + }, + "read": { + "bytes": 13000 + }, + "write": { + "bytes": 248000 + } + }, + "memory": { + "free": { + "bytes": 2822230016 + }, + "total": { + "bytes": 4294430720 + }, + "used": { + "bytes": 1472200704 + } + }, + "network": { + "bandwidth": { + "total": { + "bytes": 372000 + }, + "transmitted": { + "bytes": 0 + }, + "received": { + "bytes": 371000 + } + }, + "packets": { + "received": { + "count": 9463 + }, + "errors": { + "transmitted": { + "count": 0 + }, + "received": { + "count": 0 + }, + "total": { + "count": 0 + } + }, + "multicast": { + "total": { + "count": 6679 + }, + "transmitted": { + "count": 0 + }, + "received": { + "count": 6679 + } + }, + "dropped": { + "received": { + "count": 0 + }, + "total": { + "count": 0 + }, + "transmitted": { + "count": 0 + } + }, + "transmitted": { + "count": 54 + } + } + }, + "vm": { + "count": 2, + "names": [ + "DC0_H0_VM0", + "DC0_H0_VM1" + ] + }, + "datastore": { + "count": 1, + "names": [ + "LocalDS_0" + ] + }, + "network_names": [ + "VM Network" + ], + "name": "DC0_H0", + "status": "green", + "uptime": 1728865 + } +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) } } \ No newline at end of file diff --git a/metricbeat/module/vsphere/host/host.go b/metricbeat/module/vsphere/host/host.go index 457d4a65452..37d825644f6 100644 --- a/metricbeat/module/vsphere/host/host.go +++ b/metricbeat/module/vsphere/host/host.go @@ -101,6 +101,7 @@ func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error { event := mapstr.M{} +<<<<<<< HEAD event["name"] = hs.Summary.Config.Name event.Put("cpu.used.mhz", hs.Summary.QuickStats.OverallCpuUsage) event.Put("memory.used.bytes", int64(hs.Summary.QuickStats.OverallMemoryUsage)*1024*1024) @@ -127,6 +128,28 @@ func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error { } reporter.Event(mb.Event{ MetricSetFields: event, +======= + pc := property.DefaultCollector(c) + for i := range hst { + if ctx.Err() != nil { + return ctx.Err() + } + assetNames, err := getAssetNames(ctx, pc, &hst[i]) + if err != nil { + m.Logger().Errorf("Failed to retrieve object from host %s: %v", hst[i].Name, err) + } + + metricMap, err := m.getPerfMetrics(ctx, perfManager, hst[i], metrics) + if err != nil { + m.Logger().Errorf("Failed to retrieve performance metrics from host %s: %v", hst[i].Name, err) + } + + reporter.Event(mb.Event{ + MetricSetFields: m.mapEvent(hst[i], &metricData{ + perfMetrics: metricMap, + assetNames: assetNames, + }), +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) }) } @@ -138,8 +161,78 @@ func getNetworkNames(ctx context.Context, c *vim25.Client, ref types.ManagedObje pc := property.DefaultCollector(c) +<<<<<<< HEAD var hs mo.HostSystem err := pc.RetrieveOne(ctx, ref, []string{"network"}, &hs) +======= + outputDsNames := make([]string, 0, len(hs.Datastore)) + outputVmNames := make([]string, 0, len(hs.Vm)) + for _, ob := range objects { + name := strings.ReplaceAll(ob.Name, ".", "_") + switch ob.Reference().Type { + case "Datastore": + outputDsNames = append(outputDsNames, name) + case "VirtualMachine": + outputVmNames = append(outputVmNames, 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(hs.Network)) + if len(hs.Network) > 0 { + var netObjects []mo.Network + if err := pc.Retrieve(ctx, hs.Network, []string{"name"}, &netObjects); err != nil { + return assetNames{}, err + } + for _, ob := range netObjects { + outputNetworkNames = append(outputNetworkNames, strings.ReplaceAll(ob.Name, ".", "_")) + } + } + + return assetNames{ + outputNetworkNames: outputNetworkNames, + outputDsNames: outputDsNames, + outputVmNames: outputVmNames, + }, nil +} + +func (m *HostMetricSet) getPerfMetrics(ctx context.Context, perfManager *performance.Manager, hst mo.HostSystem, metrics map[string]*types.PerfCounterInfo) (metricMap map[string]interface{}, err error) { + metricMap = make(map[string]interface{}) + + period := int32(m.Module().Config().Period.Seconds()) + availableMetric, err := perfManager.AvailableMetric(ctx, hst.Reference(), period) + if err != nil { + return nil, fmt.Errorf("failed to get available metrics: %w", err) + } + + availableMetricByKey := availableMetric.ByKey() + + // Filter for required metrics + var metricIDs []types.PerfMetricId + for key, metric := range metricSet { + if counter, ok := metrics[key]; ok { + if _, exists := availableMetricByKey[counter.Key]; exists { + metricIDs = append(metricIDs, types.PerfMetricId{ + CounterId: counter.Key, + Instance: "*", + }) + } + } else { + m.Logger().Warnf("Metric %s not found", metric) + } + } + + spec := types.PerfQuerySpec{ + Entity: hst.Reference(), + MetricId: metricIDs, + MaxSample: 1, + IntervalId: period, + } + + // Query performance data + samples, err := perfManager.Query(ctx, []types.PerfQuerySpec{spec}) +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) if err != nil { return nil, fmt.Errorf("error retrieving host information: %v", err) } diff --git a/metricbeat/module/vsphere/virtualmachine/_meta/data.json b/metricbeat/module/vsphere/virtualmachine/_meta/data.json index 2dea5c91363..cd21609518c 100644 --- a/metricbeat/module/vsphere/virtualmachine/_meta/data.json +++ b/metricbeat/module/vsphere/virtualmachine/_meta/data.json @@ -15,6 +15,7 @@ }, "vsphere": { "virtualmachine": { +<<<<<<< HEAD "cpu": { "used": { "mhz": 0 @@ -44,6 +45,81 @@ }, "name": "ha-host_VM0", "os": "otherGuest" +======= + "name": "xt0nmfpv9", + "uptime": 5348978, + "status": "green", + "host": { + "id": "host-32", + "hostname": "phx-w1c1-esxi04.com" + }, + "cpu": { + "free": { + "mhz": 0 + }, + "used": { + "mhz": 161 + }, + "total": { + "mhz": 0 + } + }, + "network": { + "names": [ + "PROD_VCF_VMS" + ], + "count": 1 + }, + "memory": { + "used": { + "guest": { + "bytes": 686817280 + }, + "host": { + "bytes": 29027729408 + } + }, + "total": { + "guest": { + "bytes": 68719476736 + } + }, + "free": { + "guest": { + "bytes": 68032659456 + } + } + }, + "network_names": [ + "PROD_VCF_VMS" + ], + "datastore": { + "count": 1, + "names": [ + "VxRailtoup-Virtual-Datastore-bc1d-5aa310fb" + ] + }, + "os": "CentOS 4/5/6/7 (64-bit)", + "snapshot": { + "info": [ + { + "id": 1, + "name": "VM Snapshot 7%2f3%2f2024, 4:01:21 PM", + "description": "Created to demo", + "createtime": "2024-07-03T20:01:34.329Z", + "state": "poweredOn" + }, + { + "createtime": "2024-07-05T23:35:40.859Z", + "state": "poweredOn", + "id": 2, + "name": "VM Snapshot 7%2f5%2f2024, 7:35:37 PM", + "description": "backup" + } + ], + "count": 2 + } +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) } } } \ No newline at end of file diff --git a/metricbeat/module/vsphere/virtualmachine/_meta/fields.yml b/metricbeat/module/vsphere/virtualmachine/_meta/fields.yml index 723d611b2e1..90147345a51 100644 --- a/metricbeat/module/vsphere/virtualmachine/_meta/fields.yml +++ b/metricbeat/module/vsphere/virtualmachine/_meta/fields.yml @@ -60,4 +60,50 @@ - name: network_names type: keyword description: > +<<<<<<< HEAD Network names +======= + Network names. + - name: datastore + type: group + fields: + - name: names + type: keyword + description: > + Names of the datastore associated to this virtualmachine. + - name: count + type: long + description: > + Number of datastores associated to this virtualmachine. + - name: network + type: group + fields: + - name: names + type: keyword + description: > + Names of the networks associated to this virtualmachine. + - name: count + type: long + description: > + Number of networks associated to this virtualmachine. + - name: status + type: keyword + description: > + Overall health and status of a virtual machine. + - name: uptime + type: long + description: > + The uptime of the VM in seconds. + - name: snapshot + type: group + fields: + - name: info.* + type: object + object_type: keyword + description: Details of the snapshots of this virtualmachine. + - name: count + type: long + description: The number of snapshots of this virtualmachine. + + +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) diff --git a/metricbeat/module/vsphere/virtualmachine/data_test.go b/metricbeat/module/vsphere/virtualmachine/data_test.go new file mode 100644 index 00000000000..32abe001c39 --- /dev/null +++ b/metricbeat/module/vsphere/virtualmachine/data_test.go @@ -0,0 +1,154 @@ +// 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 virtualmachine + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" + + "github.com/elastic/beats/v7/libbeat/common" + "github.com/elastic/elastic-agent-libs/mapstr" +) + +func TestEventMapping(t *testing.T) { + var m MetricSet + + VirtualMachineTest := mo.VirtualMachine{ + Summary: types.VirtualMachineSummary{ + OverallStatus: types.ManagedEntityStatus("green"), + Config: types.VirtualMachineConfigSummary{ + Name: "localhost.localdomain", + GuestFullName: "otherGuest", + MemorySizeMB: 70, + CpuReservation: 2294, // MHz + }, + QuickStats: types.VirtualMachineQuickStats{ + UptimeSeconds: 10, + OverallCpuUsage: 30, // MHz + GuestMemoryUsage: 40, // MB + HostMemoryUsage: 50, // MB + }, + }, + } + + data := VMData{ + VM: VirtualMachineTest, + HostID: "host-1234", + HostName: "test-host", + NetworkNames: []string{"network-1", "network-2"}, + DatastoreNames: []string{"ds1", "ds2"}, + CustomFields: mapstr.M{ + "customField1": "value1", + "customField2": "value2", + }, + Snapshots: []VMSnapshotData{ + { + ID: 123, + Name: "Snapshot_1", + Description: "Test snapshot 1", + CreateTime: common.Time{}, + State: types.VirtualMachinePowerStatePoweredOff, + }, + { + ID: 745, + Name: "Snapshot_2", + Description: "Test snapshot 2", + CreateTime: common.Time{}, + State: types.VirtualMachinePowerStatePoweredOn, + }, + }, + } + + event := m.mapEvent(data) + + // Expected event structure + expectedEvent := mapstr.M{ + "name": "localhost.localdomain", + "os": "otherGuest", + "uptime": int32(10), + "status": types.ManagedEntityStatus("green"), + "cpu": mapstr.M{ + "used": mapstr.M{"mhz": int32(30)}, + "total": mapstr.M{"mhz": int32(2294)}, + "free": mapstr.M{"mhz": int32(2264)}, + }, + "memory": mapstr.M{ + "used": mapstr.M{ + "guest": mapstr.M{ + "bytes": int64(40 * 1024 * 1024), + }, + "host": mapstr.M{ + "bytes": int64(50 * 1024 * 1024), + }, + }, + "total": mapstr.M{ + "guest": mapstr.M{ + "bytes": int64(70 * 1024 * 1024), + }, + }, + "free": mapstr.M{ + "guest": mapstr.M{ + "bytes": int64(30 * 1024 * 1024), + }, + }, + }, + "host": mapstr.M{ + "id": "host-1234", + "hostname": "test-host", + }, + "network": mapstr.M{ + "count": 2, + "names": []string{"network-1", "network-2"}, + }, + "datastore": mapstr.M{ + "count": 2, + "names": []string{"ds1", "ds2"}, + }, + "custom_fields": mapstr.M{ + "customField1": "value1", + "customField2": "value2", + }, + "network_names": []string{"network-1", "network-2"}, + "snapshot": mapstr.M{ + "info": []VMSnapshotData{ + { + ID: 123, + Name: "Snapshot_1", + Description: "Test snapshot 1", + CreateTime: common.Time{}, + State: types.VirtualMachinePowerStatePoweredOff, + }, + { + ID: 745, + Name: "Snapshot_2", + Description: "Test snapshot 2", + CreateTime: common.Time{}, + State: types.VirtualMachinePowerStatePoweredOn, + }, + }, + "count": 2, + }, + } + + // Assert that the output event matches the expected event + assert.Exactly(t, expectedEvent, event) + +} diff --git a/metricbeat/module/vsphere/virtualmachine/virtualmachine.go b/metricbeat/module/vsphere/virtualmachine/virtualmachine.go index fd1a20ee3a7..0bea2b4e9d6 100644 --- a/metricbeat/module/vsphere/virtualmachine/virtualmachine.go +++ b/metricbeat/module/vsphere/virtualmachine/virtualmachine.go @@ -23,6 +23,7 @@ import ( "fmt" "strings" + "github.com/elastic/beats/v7/libbeat/common" "github.com/elastic/beats/v7/metricbeat/mb" "github.com/elastic/beats/v7/metricbeat/module/vsphere" "github.com/elastic/elastic-agent-libs/mapstr" @@ -49,6 +50,27 @@ type MetricSet struct { GetCustomFields bool } +<<<<<<< HEAD +======= +type VMData struct { + VM mo.VirtualMachine + HostID string + HostName string + NetworkNames []string + DatastoreNames []string + CustomFields mapstr.M + Snapshots []VMSnapshotData +} + +type VMSnapshotData struct { + ID int32 `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + CreateTime common.Time `json:"createtime"` + State types.VirtualMachinePowerState `json:"state"` +} + +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) // New creates a new instance of the MetricSet. func New(base mb.BaseMetricSet) (mb.MetricSet, error) { ms, err := vsphere.NewMetricSet(base) @@ -117,7 +139,11 @@ func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error { // Retrieve summary property for all machines var vmt []mo.VirtualMachine +<<<<<<< HEAD err = v.Retrieve(ctx, []string{"VirtualMachine"}, []string{"summary"}, &vmt) +======= + err = v.Retrieve(ctx, []string{"VirtualMachine"}, []string{"summary", "datastore", "snapshot"}, &vmt) +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766)) if err != nil { return fmt.Errorf("error in Retrieve: %w", err) } @@ -302,3 +328,25 @@ func getHostSystem(ctx context.Context, c *vim25.Client, ref types.ManagedObject } return &hs, nil } +<<<<<<< HEAD +======= + +func fetchSnapshots(snapshotTree []types.VirtualMachineSnapshotTree) []VMSnapshotData { + snapshots := make([]VMSnapshotData, 0, len(snapshotTree)) + for _, snapshot := range snapshotTree { + snapshots = append(snapshots, VMSnapshotData{ + ID: snapshot.Id, + Name: snapshot.Name, + Description: snapshot.Description, + CreateTime: common.Time(snapshot.CreateTime), + State: snapshot.State, + }) + + // Recursively add child snapshots + if len(snapshot.ChildSnapshotList) > 0 { + snapshots = append(snapshots, fetchSnapshots(snapshot.ChildSnapshotList)...) + } + } + return snapshots +} +>>>>>>> 3f44bd1f9b ([Metricbeat][vSphere] New metrics support and minor changes to existing metricsets (#40766))