Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[vSphere][virtualmachine] Add metrics to virtualmachine metricset #40485

Merged
merged 21 commits into from
Aug 28, 2024

Conversation

ishleenk17
Copy link
Contributor

@ishleenk17 ishleenk17 commented Aug 12, 2024

  • Enhancement

This PR adds the below metrics to the VirtualMachine

Metrics API Field Mappings
VirtualMachine.Summary.QuickStats.UptimeSeconds Summary virtualmachine.uptime
VirtualMachine.Summary.OverallStatus Summary virtualmachine.status
VirtualMachine.Summary.Datastore Summary virtualmachine.datastore.names

Checklist

  • My code follows the style guidelines of this project
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have made corresponding change to the default configuration files
  • I have added tests that prove my fix is effective or that my feature works
  • I have added an entry in CHANGELOG.next.asciidoc or CHANGELOG-developer.next.asciidoc.

Related issues

@botelastic botelastic bot added the needs_team Indicates that the issue/PR needs a Team:* label label Aug 12, 2024
Copy link
Contributor

mergify bot commented Aug 12, 2024

This pull request does not have a backport label.
If this is a bug or security fix, could you label this PR @ishleenk17? 🙏.
For such, you'll need to label your PR with:

  • The upcoming major version of the Elastic Stack
  • The upcoming minor version of the Elastic Stack (if you're not pushing a breaking change)

To fixup this pull request, you need to add the backport labels for the needed
branches, such as:

  • backport-v8./d.0 is the label to automatically backport to the 8./d branch. /d is the digit

@ishleenk17 ishleenk17 marked this pull request as ready for review August 12, 2024 10:34
@ishleenk17 ishleenk17 requested a review from a team as a code owner August 12, 2024 10:34
@shmsr
Copy link
Member

shmsr commented Aug 13, 2024

@ishleenk17 Here's the diff patch:

diff --git a/metricbeat/module/vsphere/virtualmachine/data.go b/metricbeat/module/vsphere/virtualmachine/data.go
index 7a7ae1eefd..8b41667d83 100644
--- a/metricbeat/module/vsphere/virtualmachine/data.go
+++ b/metricbeat/module/vsphere/virtualmachine/data.go
@@ -22,32 +22,13 @@ import (
 )
 
 func (m *MetricSet) eventMapping(data VMData) mapstr.M {
-
-	var (
-		freeCPU    int32
-		freeMemory int64
-	)
-
 	usedMemory := int64(data.VM.Summary.QuickStats.GuestMemoryUsage) * 1024 * 1024
 	usedCPU := data.VM.Summary.QuickStats.OverallCpuUsage
 	totalCPU := data.VM.Summary.Config.CpuReservation
 	totalMemory := int64(data.VM.Summary.Config.MemorySizeMB) * 1024 * 1024
 
-	if totalCPU > 0 {
-		freeCPU = totalCPU - usedCPU
-		// Avoid negative values if reported used CPU is slightly over total configured.
-		if freeCPU < 0 {
-			freeCPU = 0
-		}
-	}
-
-	if totalMemory > 0 {
-		freeMemory = totalMemory - usedMemory
-		// Avoid negative values if reported used memory is slightly over total configured.
-		if freeMemory < 0 {
-			freeMemory = 0
-		}
-	}
+	freeCPU := max(0, totalCPU-usedCPU)
+	freeMemory := max(0, totalMemory-usedMemory)
 
 	event := mapstr.M{
 		"name":          data.VM.Summary.Config.Name,
@@ -74,6 +55,7 @@ func (m *MetricSet) eventMapping(data VMData) mapstr.M {
 			},
 		},
 	}
+
 	if len(data.CustomFields) > 0 {
 		event["custom_fields"] = data.CustomFields
 	}
@@ -83,5 +65,13 @@ func (m *MetricSet) eventMapping(data VMData) mapstr.M {
 	if len(data.DatastoreNames) > 0 {
 		event["datastore.names"] = data.DatastoreNames
 	}
+
 	return event
 }
+
+func max[T ~int32 | ~int64](a T, b T) T {
+	if a > b {
+		return a
+	}
+	return b
+}
diff --git a/metricbeat/module/vsphere/virtualmachine/virtualmachine.go b/metricbeat/module/vsphere/virtualmachine/virtualmachine.go
index 331ee1ad07..3dff84b288 100644
--- a/metricbeat/module/vsphere/virtualmachine/virtualmachine.go
+++ b/metricbeat/module/vsphere/virtualmachine/virtualmachine.go
@@ -89,38 +89,38 @@ func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error {
 
 	client, err := govmomi.NewClient(ctx, m.HostURL, m.Insecure)
 	if err != nil {
-		return fmt.Errorf("error in NewClient: %w", err)
+		return fmt.Errorf("virtualmachine: error in NewClient: %w", err)
 	}
 
 	defer func() {
 		if err := client.Logout(ctx); err != nil {
-			m.Logger().Debug(fmt.Errorf("error trying to logout from vshphere: %w", err))
+			m.Logger().Debugf("Error logging out from vsphere: %v", err)
 		}
 	}()
 
 	c := client.Client
 
-	// Get custom fields (attributes) names if get_custom_fields is true.
+	// Get custom fields if enabled
 	customFieldsMap := make(map[int32]string)
 	if m.GetCustomFields {
 		var err error
 		customFieldsMap, err = setCustomFieldsMap(ctx, c)
 		if err != nil {
-			return fmt.Errorf("error in setCustomFieldsMap: %w", err)
+			return fmt.Errorf("virtualmachine: error in setCustomFieldsMap: %w", err)
 		}
 	}
 
 	// Create view of VirtualMachine objects
 	mgr := view.NewManager(c)
-
 	v, err := mgr.CreateContainerView(ctx, c.ServiceContent.RootFolder, []string{"VirtualMachine"}, true)
 	if err != nil {
-		return fmt.Errorf("error in CreateContainerView: %w", err)
+		return fmt.Errorf("virtualmachine: error in CreateContainerView: %w", err)
 	}
 
+	// Ensure view is destroyed on function exit
 	defer func() {
 		if err := v.Destroy(ctx); err != nil {
-			m.Logger().Debug(fmt.Errorf("error trying to destroy view from vshphere: %w", err))
+			m.Logger().Debugf("Error destroying view from vsphere: %v", err)
 		}
 	}()
 
@@ -128,7 +128,7 @@ func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error {
 	var vmt []mo.VirtualMachine
 	err = v.Retrieve(ctx, []string{"VirtualMachine"}, []string{"summary", "datastore"}, &vmt)
 	if err != nil {
-		return fmt.Errorf("error in Retrieve: %w", err)
+		return fmt.Errorf("virtualmachine: error in Retrieve: %w", err)
 	}
 
 	pc := property.DefaultCollector(c)
@@ -137,13 +137,14 @@ func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error {
 		var networkNames, datastoreNames []string
 		var customFields mapstr.M
 
+		// Get host information
 		if host := vm.Summary.Runtime.Host; host != nil {
 			hostID = host.Value
 			hostSystem, err := getHostSystem(ctx, c, host.Reference())
 			if err == nil {
 				hostName = hostSystem.Summary.Config.Name
 			} else {
-				m.Logger().Debug(err.Error())
+				m.Logger().Debugf("Error getting host system: %v", err)
 			}
 		} else {
 			m.Logger().Debug("'Host', 'Runtime' or 'Summary' data not found. This is either a parsing error " +
@@ -161,10 +162,11 @@ func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error {
 				"information returned from host/guest")
 		}
 
+		// Get network names
 		if vm.Summary.Vm != nil {
 			networkNames, err = getNetworkNames(ctx, c, vm.Summary.Vm.Reference())
 			if err != nil {
-				m.Logger().Debug(err.Error())
+				m.Logger().Debugf("Error getting network names: %v", err)
 			}
 		}
 
@@ -175,7 +177,7 @@ func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) error {
 			if err == nil {
 				datastoreNames = append(datastoreNames, ds.Name)
 			} else {
-				m.Logger().Debug(fmt.Sprintf("error retrieving datastore name for VM %s: %v", vm.Summary.Config.Name, err))
+				m.Logger().Debugf("Error retrieving datastore name for VM %s: %v", vm.Summary.Config.Name, err)
 			}
 		}
 
@@ -218,8 +220,7 @@ func getNetworkNames(ctx context.Context, c *vim25.Client, ref types.ManagedObje
 	pc := property.DefaultCollector(c)
 
 	var vm mo.VirtualMachine
-	err := pc.RetrieveOne(ctx, ref, []string{"network"}, &vm)
-	if err != nil {
+	if err := pc.RetrieveOne(ctx, ref, []string{"network"}, &vm); err != nil {
 		return nil, fmt.Errorf("error retrieving virtual machine information: %w", err)
 	}
 
@@ -227,8 +228,11 @@ func getNetworkNames(ctx context.Context, c *vim25.Client, ref types.ManagedObje
 		return nil, errors.New("no networks found")
 	}
 
-	var networkRefs []types.ManagedObjectReference
+	networkRefs := make([]types.ManagedObjectReference, 0, len(vm.Network))
 	for _, obj := range vm.Network {
+		// NOTE(SS): See: https://github.com/KubeOperator/KubeOperator/blob/master/pkg/cloud_provider/client/vsphere.go#L135
+		// To get the network names obj.Type == "DistributedVirtualPortgroup" is also considered. Please
+		// check if it is required!
 		if obj.Type == "Network" {
 			networkRefs = append(networkRefs, obj)
 		}
@@ -236,18 +240,17 @@ func getNetworkNames(ctx context.Context, c *vim25.Client, ref types.ManagedObje
 
 	// If only "Distributed port group" was found, for example.
 	if len(networkRefs) == 0 {
-		return nil, errors.New("no networks found")
+		return nil, errors.New("no supported networks found")
 	}
 
 	var nets []mo.Network
-	err = pc.Retrieve(ctx, networkRefs, []string{"name"}, &nets)
-	if err != nil {
+	if err := pc.Retrieve(ctx, networkRefs, []string{"name"}, &nets); err != nil {
 		return nil, fmt.Errorf("error retrieving network from virtual machine: %w", err)
 	}
-	outputNetworkNames := make([]string, 0, len(nets))
-	for _, net := range nets {
-		name := strings.Replace(net.Name, ".", "_", -1)
-		outputNetworkNames = append(outputNetworkNames, name)
+
+	outputNetworkNames := make([]string, len(nets))
+	for i, net := range nets {
+		outputNetworkNames[i] = strings.ReplaceAll(net.Name, ".", "_")
 	}
 
 	return outputNetworkNames, nil

There is one comment I left in the code itself that needs to be addressed (DistributedVirtualPortgroup related in getNetworkNames function.)

@shmsr shmsr changed the title Add metrics to virtualmachine metricset [vSphere][virtualmachine] Add metrics to virtualmachine metricset Aug 13, 2024
@ishleenk17 ishleenk17 requested a review from a team as a code owner August 14, 2024 05:18
Copy link
Contributor

mergify bot commented Aug 14, 2024

This pull request is now in conflicts. Could you fix it? 🙏
To fixup this pull request, you can check out it locally. See documentation: https://help.github.com/articles/checking-out-pull-requests-locally/

git fetch upstream
git checkout -b vm_vsphere upstream/vm_vsphere
git merge upstream/main
git push upstream vm_vsphere

@ishleenk17
Copy link
Contributor Author

ishleenk17 commented Aug 14, 2024

@shmsr : Regarding DistributedVirtualPortgroup object type for Network names, yes we should support this.
We will have to add this support for all metricsets.
So I have created a separate task in the Meta.
Will use that to address it for all existing metricsets.

Copy link
Member

@cmacknz cmacknz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving go.mod changes.

@lalit-satapathy lalit-satapathy added the Team:Integrations Label for the Integrations team label Aug 19, 2024
@elasticmachine
Copy link
Collaborator

Pinging @elastic/integrations (Team:Integrations)

@botelastic botelastic bot removed the needs_team Indicates that the issue/PR needs a Team:* label label Aug 19, 2024
Copy link
Contributor

mergify bot commented Aug 22, 2024

This pull request is now in conflicts. Could you fix it? 🙏
To fixup this pull request, you can check out it locally. See documentation: https://help.github.com/articles/checking-out-pull-requests-locally/

git fetch upstream
git checkout -b vm_vsphere upstream/vm_vsphere
git merge upstream/main
git push upstream vm_vsphere

Copy link
Contributor

mergify bot commented Aug 23, 2024

This pull request is now in conflicts. Could you fix it? 🙏
To fixup this pull request, you can check out it locally. See documentation: https://help.github.com/articles/checking-out-pull-requests-locally/

git fetch upstream
git checkout -b vm_vsphere upstream/vm_vsphere
git merge upstream/main
git push upstream vm_vsphere

@ishleenk17 ishleenk17 merged commit e1bbe05 into elastic:main Aug 28, 2024
29 checks passed
@ishleenk17 ishleenk17 added the backport-8.15 Automated backport to the 8.15 branch with mergify label Sep 12, 2024
mergify bot pushed a commit that referenced this pull request Sep 12, 2024
…0485)

* Add metrics to virtualmachine

* Lint changes

* Address lint errors

* Update data file

* Address review comments

* Resolve lint issues

* Address lint error

* Update the field definitions

* Update network code and address review comment

* mage update

* mage update

* Update tests

* Update metricbeat/module/vsphere/virtualmachine/virtualmachine.go

Co-authored-by: niraj-elastic <[email protected]>

* Address review comments

* Change event

---------

Co-authored-by: niraj-elastic <[email protected]>
(cherry picked from commit e1bbe05)

# Conflicts:
#	metricbeat/module/vsphere/fields.go
ishleenk17 added a commit that referenced this pull request Sep 13, 2024
…ualmachine metricset (#40783)

* [vSphere][virtualmachine] Add metrics to virtualmachine metricset (#40485)

* Add metrics to virtualmachine

* Lint changes

* Address lint errors

* Update data file

* Address review comments

* Resolve lint issues

* Address lint error

* Update the field definitions

* Update network code and address review comment

* mage update

* mage update

* Update tests

* Update metricbeat/module/vsphere/virtualmachine/virtualmachine.go

Co-authored-by: niraj-elastic <[email protected]>

* Address review comments

* Change event

---------

Co-authored-by: niraj-elastic <[email protected]>
(cherry picked from commit e1bbe05)

# Conflicts:
#	metricbeat/module/vsphere/fields.go

* Update fields.go

---------

Co-authored-by: Ishleen Kaur <[email protected]>
Co-authored-by: ishleenk17 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport-8.15 Automated backport to the 8.15 branch with mergify enhancement Team:Integrations Label for the Integrations team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants