Skip to content

Commit

Permalink
[vSphere][datastore_cluster] Add support for new metrics in datastore…
Browse files Browse the repository at this point in the history
…_cluster metricset (#40694)

* initial commit

* add childEntity

* add changelog entry

* resolve review comments

(cherry picked from commit 83a880f)

# Conflicts:
#	filebeat/input/journald/pkg/journalread/mode_test.go
#	metricbeat/docs/fields.asciidoc
#	metricbeat/module/vsphere/datastorecluster/_meta/data.json
#	metricbeat/module/vsphere/datastorecluster/_meta/fields.yml
#	metricbeat/module/vsphere/datastorecluster/data.go
#	metricbeat/module/vsphere/datastorecluster/datastorecluster.go
#	metricbeat/module/vsphere/fields.go
  • Loading branch information
kush-elastic authored and mergify[bot] committed Sep 13, 2024
1 parent ef04f1c commit 6bcd1b4
Show file tree
Hide file tree
Showing 8 changed files with 323 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff]

*Metricbeat*

- Add support for new metrics for vSphere module datastorecluster metricset. {pull}40694[40694]

*Osquerybeat*

Expand Down
15 changes: 15 additions & 0 deletions filebeat/input/journald/pkg/journalread/mode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,16 @@ func TestMode_Unpack(t *testing.T) {
"since": SeekSince,
}

<<<<<<< HEAD:filebeat/input/journald/pkg/journalread/mode_test.go

Check failure on line 33 in filebeat/input/journald/pkg/journalread/mode_test.go

View workflow job for this annotation

GitHub Actions / lint (darwin)

expected statement, found '<<' (typecheck)
for str, want := range tests {

Check failure on line 34 in filebeat/input/journald/pkg/journalread/mode_test.go

View workflow job for this annotation

GitHub Actions / lint (darwin)

expected operand, found 'for' (typecheck)
t.Run(str, func(t *testing.T) {
var m SeekMode
if err := m.Unpack(str); err != nil {
t.Fatal(err)
}
=======

Check failure on line 40 in filebeat/input/journald/pkg/journalread/mode_test.go

View workflow job for this annotation

GitHub Actions / lint (darwin)

expected statement, found '==' (typecheck)
event := (&DatastoreClusterMetricSet{}).mapEvent(datastoreClusterTest, &metricData{assetNames: assetNames{outputDsNames: []string{"DCS_0"}}})
>>>>>>> 83a880f47b ([vSphere][datastore_cluster] Add support for new metrics in datastore_cluster metricset (#40694)):metricbeat/module/vsphere/datastorecluster/data_test.go

Check failure on line 42 in filebeat/input/journald/pkg/journalread/mode_test.go

View workflow job for this annotation

GitHub Actions / lint (darwin)

expected '{', found metrics (typecheck)

if m != want {

Check failure on line 44 in filebeat/input/journald/pkg/journalread/mode_test.go

View workflow job for this annotation

GitHub Actions / lint (darwin)

expected operand, found 'if' (typecheck)
t.Errorf("wrong mode, expected %v, got %v", want, m)
Expand All @@ -47,6 +51,7 @@ func TestMode_Unpack(t *testing.T) {
t.Run("failing", func(t *testing.T) {
cases := []string{"invalid", "", "unknown"}

<<<<<<< HEAD:filebeat/input/journald/pkg/journalread/mode_test.go
for _, str := range cases {

Check failure on line 55 in filebeat/input/journald/pkg/journalread/mode_test.go

View workflow job for this annotation

GitHub Actions / lint (darwin)

expected operand, found 'for' (typecheck)
t.Run(str, func(t *testing.T) {
var m SeekMode
Expand All @@ -56,4 +61,14 @@ func TestMode_Unpack(t *testing.T) {
})
}
})
=======

Check failure on line 64 in filebeat/input/journald/pkg/journalread/mode_test.go

View workflow job for this annotation

GitHub Actions / lint (darwin)

expected statement, found '==' (typecheck)
freeSpace, _ := event.GetValue("free_space.bytes")
assert.Equal(t, int64(50), freeSpace)

datastoreNames, _ := event.GetValue("datastore.names")
assert.Equal(t, []string{"DCS_0"}, datastoreNames)

datastoreCount, _ := event.GetValue("datastore.count")
assert.Equal(t, 1, datastoreCount)
>>>>>>> 83a880f47b ([vSphere][datastore_cluster] Add support for new metrics in datastore_cluster metricset (#40694)):metricbeat/module/vsphere/datastorecluster/data_test.go

Check failure on line 73 in filebeat/input/journald/pkg/journalread/mode_test.go

View workflow job for this annotation

GitHub Actions / lint (darwin)

expected '{', found metrics (typecheck)
}
64 changes: 64 additions & 0 deletions metricbeat/docs/fields.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -67034,6 +67034,70 @@ type: long
--

[float]
<<<<<<< HEAD
=======
=== 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

--

[float]
>>>>>>> 83a880f47b ([vSphere][datastore_cluster] Add support for new metrics in datastore_cluster metricset (#40694))
=== host

Host information from vSphere environment.
Expand Down
33 changes: 33 additions & 0 deletions metricbeat/module/vsphere/datastorecluster/_meta/data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"@timestamp": "2016-05-23T08:05:34.853Z",
"service": {
"address": "https://localhost:8980/sdk",
"type": "vsphere"
},
"event": {
"dataset": "vsphere.datastorecluster",
"module": "vsphere",
"duration": 15443161
},
"metricset": {
"period": 20000,
"name": "datastorecluster"
},
"vsphere": {
"datastorecluster": {
"name": "datastore_cluster1",
"capacity": {
"bytes": 8795019280384
},
"free_space": {
"bytes": 8788836876288
},
"datastore": {
"count": 1,
"names": [
"LocalDS_0"
]
}
}
}
}
28 changes: 28 additions & 0 deletions metricbeat/module/vsphere/datastorecluster/_meta/fields.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
- name: datastorecluster
type: group
release: beta
description: >
Datastore Cluster
fields:
- name: name
type: keyword
description: >
The Datastore Cluster name.
- name: capacity.bytes
type: long
description: >
Total capacity of this storage pod, in bytes.
format: bytes
- name: free_space.bytes
type: long
description: >
Total free space on this storage pod, in bytes.
format: bytes
- name: datastore.names
type: keyword
description: >
List of all the Datastore names associated with the Datastore Cluster.
- name: datastore.count
type: long
description: >
Number of datastores in the Datastore Cluster.
40 changes: 40 additions & 0 deletions metricbeat/module/vsphere/datastorecluster/data.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// 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 datastorecluster

import (
"github.com/vmware/govmomi/vim25/mo"

"github.com/elastic/elastic-agent-libs/mapstr"
)

func (m *DatastoreClusterMetricSet) mapEvent(datastoreCluster mo.StoragePod, data *metricData) mapstr.M {
return mapstr.M{
"name": datastoreCluster.Name,
"capacity": mapstr.M{
"bytes": datastoreCluster.Summary.Capacity,
},
"free_space": mapstr.M{
"bytes": datastoreCluster.Summary.FreeSpace,
},
"datastore": mapstr.M{
"names": data.assetNames.outputDsNames,
"count": len(data.assetNames.outputDsNames),
},
}
}
138 changes: 138 additions & 0 deletions metricbeat/module/vsphere/datastorecluster/datastorecluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// 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 datastorecluster

import (
"context"
"fmt"
"strings"

"github.com/vmware/govmomi"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/view"
"github.com/vmware/govmomi/vim25/mo"

"github.com/elastic/beats/v7/metricbeat/mb"
"github.com/elastic/beats/v7/metricbeat/module/vsphere"
)

// 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", "datastorecluster", New,
mb.WithHostParser(vsphere.HostParser),
mb.DefaultMetricSet(),
)
}

// MetricSet type defines all fields of the MetricSet.
type DatastoreClusterMetricSet struct {
*vsphere.MetricSet
}

// 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, fmt.Errorf("failed to create vSphere metricset: %w", err)
}
return &DatastoreClusterMetricSet{ms}, nil
}

type metricData struct {
assetNames assetNames
}

type assetNames struct {
outputDsNames []string
}

func (m *DatastoreClusterMetricSet) 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().Errorf("error trying to logout from vSphere: %w", err)
}
}()

c := client.Client

v, err := view.NewManager(c).CreateContainerView(ctx, c.ServiceContent.RootFolder, []string{"StoragePod"}, true)
if err != nil {
return fmt.Errorf("error in creating container view: %w", err)
}

defer func() {
if err := v.Destroy(ctx); err != nil {
m.Logger().Errorf("error trying to destroy view from vSphere: %w", err)
}
}()

var datastoreCluster []mo.StoragePod
err = v.Retrieve(ctx, []string{"StoragePod"}, []string{"name", "summary", "childEntity"}, &datastoreCluster)
if err != nil {
return fmt.Errorf("error in retrieve from vsphere: %w", err)
}

pc := property.DefaultCollector(c)
for i := range datastoreCluster {
if ctx.Err() != nil {
return ctx.Err()
}

assetNames, err := getAssetNames(ctx, pc, &datastoreCluster[i])
if err != nil {
m.Logger().Errorf("Failed to retrieve object from host %s: %w", datastoreCluster[i].Name, err)
}

reporter.Event(mb.Event{MetricSetFields: m.mapEvent(datastoreCluster[i], &metricData{assetNames: assetNames})})
}

return nil
}

func getAssetNames(ctx context.Context, pc *property.Collector, dsc *mo.StoragePod) (assetNames, error) {
var objects []mo.ManagedEntity
if len(dsc.ChildEntity) > 0 {
if err := pc.Retrieve(ctx, dsc.ChildEntity, []string{"name"}, &objects); err != nil {
return assetNames{}, err
}
}

outputDsNames := make([]string, 0)
for _, ob := range objects {
if ob.Reference().Type == "Datastore" {
name := strings.ReplaceAll(ob.Name, ".", "_")
outputDsNames = append(outputDsNames, name)
}
}

return assetNames{
outputDsNames: outputDsNames,
}, nil
}
4 changes: 4 additions & 0 deletions metricbeat/module/vsphere/fields.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 6bcd1b4

Please sign in to comment.