diff --git a/.chloggen/fix_vcenter-vapp-attrs-on-vms.yaml b/.chloggen/fix_vcenter-vapp-attrs-on-vms.yaml
new file mode 100644
index 000000000000..c95fcd4a8e1c
--- /dev/null
+++ b/.chloggen/fix_vcenter-vapp-attrs-on-vms.yaml
@@ -0,0 +1,27 @@
+# Use this changelog template to create an entry for release notes.
+
+# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
+change_type: bug_fix
+
+# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
+component: vcenterreceiver
+
+# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
+note: "Adds new `vcenter.virtual_app.name` and `vcenter.virtual_app.inventory_path` resource attributes to appropriate VM Resources"
+
+# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
+issues: [32557]
+
+# (Optional) One or more lines of additional information to render under the primary note.
+# These lines will be padded with 2 spaces and then inserted directly into the document.
+# Use pipe (|) for multiline entries.
+subtext:
+
+# If your change doesn't affect end users or the exported elements of any package,
+# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
+# Optional: The change log or logs in which this entry should be included.
+# e.g. '[user]' or '[user, api]'
+# Include 'user' if the change is relevant to end users.
+# Include 'api' if there is a change to a library API.
+# Default: '[user]'
+change_logs: [user]
diff --git a/receiver/vcenterreceiver/client.go b/receiver/vcenterreceiver/client.go
index 6d459e164961..14686a5e9acb 100644
--- a/receiver/vcenterreceiver/client.go
+++ b/receiver/vcenterreceiver/client.go
@@ -5,6 +5,7 @@ package vcenterreceiver // import "github.com/open-telemetry/opentelemetry-colle
import (
"context"
+ "errors"
"fmt"
"net/url"
@@ -112,6 +113,20 @@ func (vc *vcenterClient) ResourcePools(ctx context.Context) ([]*object.ResourceP
return rps, err
}
+// VirtualApps returns the VirtualApps in the vSphere SDK
+func (vc *vcenterClient) VirtualApps(ctx context.Context) ([]*object.VirtualApp, error) {
+ vApps, err := vc.finder.VirtualAppList(ctx, "*")
+ if err != nil {
+ var notFoundErr *find.NotFoundError
+ if errors.As(err, ¬FoundErr) {
+ return []*object.VirtualApp{}, nil
+ }
+
+ return nil, fmt.Errorf("unable to retrieve vApps: %w", err)
+ }
+ return vApps, err
+}
+
func (vc *vcenterClient) VMs(ctx context.Context) ([]mo.VirtualMachine, error) {
v, err := vc.vm.CreateContainerView(ctx, vc.vimDriver.ServiceContent.RootFolder, []string{"VirtualMachine"}, true)
if err != nil {
@@ -135,6 +150,7 @@ func (vc *vcenterClient) VMs(ctx context.Context) ([]mo.VirtualMachine, error) {
"summary.storage.uncommitted",
"summary.runtime.host",
"resourcePool",
+ "parentVApp",
}, &vms)
if err != nil {
return nil, fmt.Errorf("unable to retrieve VMs: %w", err)
diff --git a/receiver/vcenterreceiver/client_test.go b/receiver/vcenterreceiver/client_test.go
index c9f2ae7837f7..426a84e9f541 100644
--- a/receiver/vcenterreceiver/client_test.go
+++ b/receiver/vcenterreceiver/client_test.go
@@ -47,6 +47,25 @@ func TestGetResourcePools(t *testing.T) {
})
}
+func TestGetVirtualApps(t *testing.T) {
+ // Currently some issue with how the simulator creates vApps.
+ // It is created (VMs show up with it in the inventory path)
+ // but it is not returned by the finder call in this tested method.
+ t.Skip()
+ model := simulator.VPX()
+ model.App = 1
+ simulator.Test(func(ctx context.Context, c *vim25.Client) {
+ finder := find.NewFinder(c)
+ client := vcenterClient{
+ vimDriver: c,
+ finder: finder,
+ }
+ vApps, err := client.VirtualApps(ctx)
+ require.NoError(t, err)
+ require.NotEmpty(t, vApps)
+ }, model)
+}
+
func TestGetVMs(t *testing.T) {
simulator.Test(func(ctx context.Context, c *vim25.Client) {
viewManager := view.NewManager(c)
diff --git a/receiver/vcenterreceiver/documentation.md b/receiver/vcenterreceiver/documentation.md
index 619bcfc09569..01f095513bd4 100644
--- a/receiver/vcenterreceiver/documentation.md
+++ b/receiver/vcenterreceiver/documentation.md
@@ -471,5 +471,7 @@ The memory utilization of the VM.
| vcenter.host.name | The hostname of the vCenter ESXi host. | Any Str | true |
| vcenter.resource_pool.inventory_path | The inventory path of the resource pool. | Any Str | true |
| vcenter.resource_pool.name | The name of the resource pool. | Any Str | true |
+| vcenter.virtual_app.inventory_path | The inventory path of the vApp. | Any Str | false |
+| vcenter.virtual_app.name | The name of the vApp. | Any Str | false |
| vcenter.vm.id | The instance UUID of the virtual machine. | Any Str | true |
| vcenter.vm.name | The name of the virtual machine. | Any Str | true |
diff --git a/receiver/vcenterreceiver/internal/metadata/generated_config.go b/receiver/vcenterreceiver/internal/metadata/generated_config.go
index 2ce12cd0acb5..98561ed3378c 100644
--- a/receiver/vcenterreceiver/internal/metadata/generated_config.go
+++ b/receiver/vcenterreceiver/internal/metadata/generated_config.go
@@ -225,6 +225,8 @@ type ResourceAttributesConfig struct {
VcenterHostName ResourceAttributeConfig `mapstructure:"vcenter.host.name"`
VcenterResourcePoolInventoryPath ResourceAttributeConfig `mapstructure:"vcenter.resource_pool.inventory_path"`
VcenterResourcePoolName ResourceAttributeConfig `mapstructure:"vcenter.resource_pool.name"`
+ VcenterVirtualAppInventoryPath ResourceAttributeConfig `mapstructure:"vcenter.virtual_app.inventory_path"`
+ VcenterVirtualAppName ResourceAttributeConfig `mapstructure:"vcenter.virtual_app.name"`
VcenterVMID ResourceAttributeConfig `mapstructure:"vcenter.vm.id"`
VcenterVMName ResourceAttributeConfig `mapstructure:"vcenter.vm.name"`
}
@@ -249,6 +251,12 @@ func DefaultResourceAttributesConfig() ResourceAttributesConfig {
VcenterResourcePoolName: ResourceAttributeConfig{
Enabled: true,
},
+ VcenterVirtualAppInventoryPath: ResourceAttributeConfig{
+ Enabled: false,
+ },
+ VcenterVirtualAppName: ResourceAttributeConfig{
+ Enabled: false,
+ },
VcenterVMID: ResourceAttributeConfig{
Enabled: true,
},
diff --git a/receiver/vcenterreceiver/internal/metadata/generated_config_test.go b/receiver/vcenterreceiver/internal/metadata/generated_config_test.go
index 8e80f896727b..1702cf3dab73 100644
--- a/receiver/vcenterreceiver/internal/metadata/generated_config_test.go
+++ b/receiver/vcenterreceiver/internal/metadata/generated_config_test.go
@@ -73,6 +73,8 @@ func TestMetricsBuilderConfig(t *testing.T) {
VcenterHostName: ResourceAttributeConfig{Enabled: true},
VcenterResourcePoolInventoryPath: ResourceAttributeConfig{Enabled: true},
VcenterResourcePoolName: ResourceAttributeConfig{Enabled: true},
+ VcenterVirtualAppInventoryPath: ResourceAttributeConfig{Enabled: true},
+ VcenterVirtualAppName: ResourceAttributeConfig{Enabled: true},
VcenterVMID: ResourceAttributeConfig{Enabled: true},
VcenterVMName: ResourceAttributeConfig{Enabled: true},
},
@@ -129,6 +131,8 @@ func TestMetricsBuilderConfig(t *testing.T) {
VcenterHostName: ResourceAttributeConfig{Enabled: false},
VcenterResourcePoolInventoryPath: ResourceAttributeConfig{Enabled: false},
VcenterResourcePoolName: ResourceAttributeConfig{Enabled: false},
+ VcenterVirtualAppInventoryPath: ResourceAttributeConfig{Enabled: false},
+ VcenterVirtualAppName: ResourceAttributeConfig{Enabled: false},
VcenterVMID: ResourceAttributeConfig{Enabled: false},
VcenterVMName: ResourceAttributeConfig{Enabled: false},
},
@@ -173,6 +177,8 @@ func TestResourceAttributesConfig(t *testing.T) {
VcenterHostName: ResourceAttributeConfig{Enabled: true},
VcenterResourcePoolInventoryPath: ResourceAttributeConfig{Enabled: true},
VcenterResourcePoolName: ResourceAttributeConfig{Enabled: true},
+ VcenterVirtualAppInventoryPath: ResourceAttributeConfig{Enabled: true},
+ VcenterVirtualAppName: ResourceAttributeConfig{Enabled: true},
VcenterVMID: ResourceAttributeConfig{Enabled: true},
VcenterVMName: ResourceAttributeConfig{Enabled: true},
},
@@ -186,6 +192,8 @@ func TestResourceAttributesConfig(t *testing.T) {
VcenterHostName: ResourceAttributeConfig{Enabled: false},
VcenterResourcePoolInventoryPath: ResourceAttributeConfig{Enabled: false},
VcenterResourcePoolName: ResourceAttributeConfig{Enabled: false},
+ VcenterVirtualAppInventoryPath: ResourceAttributeConfig{Enabled: false},
+ VcenterVirtualAppName: ResourceAttributeConfig{Enabled: false},
VcenterVMID: ResourceAttributeConfig{Enabled: false},
VcenterVMName: ResourceAttributeConfig{Enabled: false},
},
diff --git a/receiver/vcenterreceiver/internal/metadata/generated_metrics.go b/receiver/vcenterreceiver/internal/metadata/generated_metrics.go
index 5eb8d9bab669..1eff1d22e8d6 100644
--- a/receiver/vcenterreceiver/internal/metadata/generated_metrics.go
+++ b/receiver/vcenterreceiver/internal/metadata/generated_metrics.go
@@ -2219,6 +2219,12 @@ func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.CreateSetting
if !mbc.ResourceAttributes.VcenterDatacenterName.enabledSetByUser {
settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `vcenter.datacenter.name`: this attribute will be enabled by default starting in release v0.101.0")
}
+ if !mbc.ResourceAttributes.VcenterVirtualAppInventoryPath.enabledSetByUser {
+ settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `vcenter.virtual_app.inventory_path`: this attribute will be enabled by default starting in release v0.101.0")
+ }
+ if !mbc.ResourceAttributes.VcenterVirtualAppName.enabledSetByUser {
+ settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `vcenter.virtual_app.name`: this attribute will be enabled by default starting in release v0.101.0")
+ }
mb := &MetricsBuilder{
config: mbc,
startTime: pcommon.NewTimestampFromTime(time.Now()),
@@ -2302,6 +2308,18 @@ func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.CreateSetting
if mbc.ResourceAttributes.VcenterResourcePoolName.MetricsExclude != nil {
mb.resourceAttributeExcludeFilter["vcenter.resource_pool.name"] = filter.CreateFilter(mbc.ResourceAttributes.VcenterResourcePoolName.MetricsExclude)
}
+ if mbc.ResourceAttributes.VcenterVirtualAppInventoryPath.MetricsInclude != nil {
+ mb.resourceAttributeIncludeFilter["vcenter.virtual_app.inventory_path"] = filter.CreateFilter(mbc.ResourceAttributes.VcenterVirtualAppInventoryPath.MetricsInclude)
+ }
+ if mbc.ResourceAttributes.VcenterVirtualAppInventoryPath.MetricsExclude != nil {
+ mb.resourceAttributeExcludeFilter["vcenter.virtual_app.inventory_path"] = filter.CreateFilter(mbc.ResourceAttributes.VcenterVirtualAppInventoryPath.MetricsExclude)
+ }
+ if mbc.ResourceAttributes.VcenterVirtualAppName.MetricsInclude != nil {
+ mb.resourceAttributeIncludeFilter["vcenter.virtual_app.name"] = filter.CreateFilter(mbc.ResourceAttributes.VcenterVirtualAppName.MetricsInclude)
+ }
+ if mbc.ResourceAttributes.VcenterVirtualAppName.MetricsExclude != nil {
+ mb.resourceAttributeExcludeFilter["vcenter.virtual_app.name"] = filter.CreateFilter(mbc.ResourceAttributes.VcenterVirtualAppName.MetricsExclude)
+ }
if mbc.ResourceAttributes.VcenterVMID.MetricsInclude != nil {
mb.resourceAttributeIncludeFilter["vcenter.vm.id"] = filter.CreateFilter(mbc.ResourceAttributes.VcenterVMID.MetricsInclude)
}
diff --git a/receiver/vcenterreceiver/internal/metadata/generated_metrics_test.go b/receiver/vcenterreceiver/internal/metadata/generated_metrics_test.go
index a29c84af79b1..a7d264ad9dc1 100644
--- a/receiver/vcenterreceiver/internal/metadata/generated_metrics_test.go
+++ b/receiver/vcenterreceiver/internal/metadata/generated_metrics_test.go
@@ -66,6 +66,14 @@ func TestMetricsBuilder(t *testing.T) {
assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `vcenter.datacenter.name`: this attribute will be enabled by default starting in release v0.101.0", observedLogs.All()[expectedWarnings].Message)
expectedWarnings++
}
+ if test.resAttrsSet == testDataSetDefault {
+ assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `vcenter.virtual_app.inventory_path`: this attribute will be enabled by default starting in release v0.101.0", observedLogs.All()[expectedWarnings].Message)
+ expectedWarnings++
+ }
+ if test.resAttrsSet == testDataSetDefault {
+ assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `vcenter.virtual_app.name`: this attribute will be enabled by default starting in release v0.101.0", observedLogs.All()[expectedWarnings].Message)
+ expectedWarnings++
+ }
assert.Equal(t, expectedWarnings, observedLogs.Len())
@@ -234,6 +242,8 @@ func TestMetricsBuilder(t *testing.T) {
rb.SetVcenterHostName("vcenter.host.name-val")
rb.SetVcenterResourcePoolInventoryPath("vcenter.resource_pool.inventory_path-val")
rb.SetVcenterResourcePoolName("vcenter.resource_pool.name-val")
+ rb.SetVcenterVirtualAppInventoryPath("vcenter.virtual_app.inventory_path-val")
+ rb.SetVcenterVirtualAppName("vcenter.virtual_app.name-val")
rb.SetVcenterVMID("vcenter.vm.id-val")
rb.SetVcenterVMName("vcenter.vm.name-val")
res := rb.Emit()
diff --git a/receiver/vcenterreceiver/internal/metadata/generated_resource.go b/receiver/vcenterreceiver/internal/metadata/generated_resource.go
index abb087dc71ae..2319b184b00c 100644
--- a/receiver/vcenterreceiver/internal/metadata/generated_resource.go
+++ b/receiver/vcenterreceiver/internal/metadata/generated_resource.go
@@ -63,6 +63,20 @@ func (rb *ResourceBuilder) SetVcenterResourcePoolName(val string) {
}
}
+// SetVcenterVirtualAppInventoryPath sets provided value as "vcenter.virtual_app.inventory_path" attribute.
+func (rb *ResourceBuilder) SetVcenterVirtualAppInventoryPath(val string) {
+ if rb.config.VcenterVirtualAppInventoryPath.Enabled {
+ rb.res.Attributes().PutStr("vcenter.virtual_app.inventory_path", val)
+ }
+}
+
+// SetVcenterVirtualAppName sets provided value as "vcenter.virtual_app.name" attribute.
+func (rb *ResourceBuilder) SetVcenterVirtualAppName(val string) {
+ if rb.config.VcenterVirtualAppName.Enabled {
+ rb.res.Attributes().PutStr("vcenter.virtual_app.name", val)
+ }
+}
+
// SetVcenterVMID sets provided value as "vcenter.vm.id" attribute.
func (rb *ResourceBuilder) SetVcenterVMID(val string) {
if rb.config.VcenterVMID.Enabled {
diff --git a/receiver/vcenterreceiver/internal/metadata/generated_resource_test.go b/receiver/vcenterreceiver/internal/metadata/generated_resource_test.go
index bd6121433168..4216d7d2f453 100644
--- a/receiver/vcenterreceiver/internal/metadata/generated_resource_test.go
+++ b/receiver/vcenterreceiver/internal/metadata/generated_resource_test.go
@@ -19,6 +19,8 @@ func TestResourceBuilder(t *testing.T) {
rb.SetVcenterHostName("vcenter.host.name-val")
rb.SetVcenterResourcePoolInventoryPath("vcenter.resource_pool.inventory_path-val")
rb.SetVcenterResourcePoolName("vcenter.resource_pool.name-val")
+ rb.SetVcenterVirtualAppInventoryPath("vcenter.virtual_app.inventory_path-val")
+ rb.SetVcenterVirtualAppName("vcenter.virtual_app.name-val")
rb.SetVcenterVMID("vcenter.vm.id-val")
rb.SetVcenterVMName("vcenter.vm.name-val")
@@ -29,7 +31,7 @@ func TestResourceBuilder(t *testing.T) {
case "default":
assert.Equal(t, 7, res.Attributes().Len())
case "all_set":
- assert.Equal(t, 8, res.Attributes().Len())
+ assert.Equal(t, 10, res.Attributes().Len())
case "none_set":
assert.Equal(t, 0, res.Attributes().Len())
return
@@ -67,6 +69,16 @@ func TestResourceBuilder(t *testing.T) {
if ok {
assert.EqualValues(t, "vcenter.resource_pool.name-val", val.Str())
}
+ val, ok = res.Attributes().Get("vcenter.virtual_app.inventory_path")
+ assert.Equal(t, test == "all_set", ok)
+ if ok {
+ assert.EqualValues(t, "vcenter.virtual_app.inventory_path-val", val.Str())
+ }
+ val, ok = res.Attributes().Get("vcenter.virtual_app.name")
+ assert.Equal(t, test == "all_set", ok)
+ if ok {
+ assert.EqualValues(t, "vcenter.virtual_app.name-val", val.Str())
+ }
val, ok = res.Attributes().Get("vcenter.vm.id")
assert.True(t, ok)
if ok {
diff --git a/receiver/vcenterreceiver/internal/metadata/testdata/config.yaml b/receiver/vcenterreceiver/internal/metadata/testdata/config.yaml
index ae941ef2060a..d212701831d8 100644
--- a/receiver/vcenterreceiver/internal/metadata/testdata/config.yaml
+++ b/receiver/vcenterreceiver/internal/metadata/testdata/config.yaml
@@ -92,6 +92,10 @@ all_set:
enabled: true
vcenter.resource_pool.name:
enabled: true
+ vcenter.virtual_app.inventory_path:
+ enabled: true
+ vcenter.virtual_app.name:
+ enabled: true
vcenter.vm.id:
enabled: true
vcenter.vm.name:
@@ -189,6 +193,10 @@ none_set:
enabled: false
vcenter.resource_pool.name:
enabled: false
+ vcenter.virtual_app.inventory_path:
+ enabled: false
+ vcenter.virtual_app.name:
+ enabled: false
vcenter.vm.id:
enabled: false
vcenter.vm.name:
@@ -219,6 +227,14 @@ filter_set_include:
enabled: true
metrics_include:
- regexp: ".*"
+ vcenter.virtual_app.inventory_path:
+ enabled: true
+ metrics_include:
+ - regexp: ".*"
+ vcenter.virtual_app.name:
+ enabled: true
+ metrics_include:
+ - regexp: ".*"
vcenter.vm.id:
enabled: true
metrics_include:
@@ -253,6 +269,14 @@ filter_set_exclude:
enabled: true
metrics_exclude:
- strict: "vcenter.resource_pool.name-val"
+ vcenter.virtual_app.inventory_path:
+ enabled: true
+ metrics_exclude:
+ - strict: "vcenter.virtual_app.inventory_path-val"
+ vcenter.virtual_app.name:
+ enabled: true
+ metrics_exclude:
+ - strict: "vcenter.virtual_app.name-val"
vcenter.vm.id:
enabled: true
metrics_exclude:
diff --git a/receiver/vcenterreceiver/internal/mockserver/client_mock.go b/receiver/vcenterreceiver/internal/mockserver/client_mock.go
index 449877eea164..a15f63dbc2fe 100644
--- a/receiver/vcenterreceiver/internal/mockserver/client_mock.go
+++ b/receiver/vcenterreceiver/internal/mockserver/client_mock.go
@@ -114,6 +114,13 @@ func routeRetreiveProperties(t *testing.T, body map[string]any) ([]byte, error)
switch {
case content == "group-d1" && contentType == "Folder":
+ for _, i := range propSetArray {
+ m, ok := i.(map[string]any)
+ require.True(t, ok)
+ if m["pathSet"] == "parentVApp" && m["type"] == "VirtualMachine" {
+ return loadResponse("datacenter-list.xml")
+ }
+ }
return loadResponse("datacenter.xml")
case content == "datacenter-3" && contentType == "Datacenter":
@@ -199,6 +206,9 @@ func routeRetreiveProperties(t *testing.T, body map[string]any) ([]byte, error)
return loadResponse("virtual-app-children.xml")
}
}
+ if _, ok := propSet["pathSet"].([]any); ok {
+ return loadResponse("virtual-app-properties.xml")
+ }
if ps, ok := propSet["pathSet"].(string); ok {
if ps == "owner" {
return loadResponse("virtual-app-owner.xml")
diff --git a/receiver/vcenterreceiver/internal/mockserver/responses/virtual-app-properties.xml b/receiver/vcenterreceiver/internal/mockserver/responses/virtual-app-properties.xml
new file mode 100644
index 000000000000..dc60a5088bab
--- /dev/null
+++ b/receiver/vcenterreceiver/internal/mockserver/responses/virtual-app-properties.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+ resgroup-v10
+
+ name
+ v-app-1
+
+
+ vm
+
+ vm-6004
+
+
+
+
+
+
diff --git a/receiver/vcenterreceiver/internal/mockserver/responses/virtual-app.xml b/receiver/vcenterreceiver/internal/mockserver/responses/virtual-app.xml
new file mode 100644
index 000000000000..1f854623d778
--- /dev/null
+++ b/receiver/vcenterreceiver/internal/mockserver/responses/virtual-app.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+ resgroup-v10
+
+ name
+ v-app-1
+
+
+
+
+
diff --git a/receiver/vcenterreceiver/metadata.yaml b/receiver/vcenterreceiver/metadata.yaml
index 595640adb1cd..0642659d31c1 100644
--- a/receiver/vcenterreceiver/metadata.yaml
+++ b/receiver/vcenterreceiver/metadata.yaml
@@ -33,6 +33,18 @@ resource_attributes:
description: The inventory path of the resource pool.
enabled: true
type: string
+ vcenter.virtual_app.name:
+ description: The name of the vApp.
+ enabled: false
+ type: string
+ warnings:
+ if_enabled_not_set: "this attribute will be enabled by default starting in release v0.101.0"
+ vcenter.virtual_app.inventory_path:
+ description: The inventory path of the vApp.
+ enabled: false
+ type: string
+ warnings:
+ if_enabled_not_set: "this attribute will be enabled by default starting in release v0.101.0"
vcenter.datastore.name:
description: The name of the vCenter datastore.
enabled: true
diff --git a/receiver/vcenterreceiver/resources.go b/receiver/vcenterreceiver/resources.go
index b212c741e1ed..aa5a24bbbaae 100644
--- a/receiver/vcenterreceiver/resources.go
+++ b/receiver/vcenterreceiver/resources.go
@@ -16,6 +16,7 @@ func (v *vcenterMetricScraper) createVMResourceBuilder(
hs mo.HostSystem,
compute *object.ComputeResource,
rp *object.ResourcePool,
+ vApp *object.VirtualApp,
) *metadata.ResourceBuilder {
rb := v.mb.NewResourceBuilder()
rb.SetVcenterDatacenterName(dcName)
@@ -29,5 +30,9 @@ func (v *vcenterMetricScraper) createVMResourceBuilder(
rb.SetVcenterResourcePoolName(rp.Name())
rb.SetVcenterResourcePoolInventoryPath(rp.InventoryPath)
}
+ if vApp != nil && vApp.Name() != "" {
+ rb.SetVcenterVirtualAppName(vApp.Name())
+ rb.SetVcenterVirtualAppInventoryPath(vApp.InventoryPath)
+ }
return rb
}
diff --git a/receiver/vcenterreceiver/scraper.go b/receiver/vcenterreceiver/scraper.go
index 17a70822d48c..f498b3e7edae 100644
--- a/receiver/vcenterreceiver/scraper.go
+++ b/receiver/vcenterreceiver/scraper.go
@@ -44,6 +44,7 @@ type vcenterMetricScraper struct {
// map of vm name => compute name
vmToComputeMap map[string]string
vmToResourcePool map[string]*object.ResourcePool
+ vmToVirtualApp map[string]*object.VirtualApp
}
func newVmwareVcenterScraper(
@@ -59,6 +60,7 @@ func newVmwareVcenterScraper(
mb: metadata.NewMetricsBuilder(config.MetricsBuilderConfig, settings),
vmToComputeMap: make(map[string]string),
vmToResourcePool: make(map[string]*object.ResourcePool),
+ vmToVirtualApp: make(map[string]*object.VirtualApp),
}
}
@@ -89,6 +91,7 @@ func (v *vcenterMetricScraper) scrape(ctx context.Context) (pmetric.Metrics, err
// cleanup so any inventory moves are accounted for
v.vmToComputeMap = make(map[string]string)
v.vmToResourcePool = make(map[string]*object.ResourcePool)
+ v.vmToVirtualApp = make(map[string]*object.VirtualApp)
return v.mb.Emit(), err
}
@@ -115,6 +118,7 @@ func (v *vcenterMetricScraper) collectClusters(ctx context.Context, datacenter *
now := pcommon.NewTimestampFromTime(time.Now())
dcName := datacenter.Name()
+ v.collectVirtualApps(ctx, errs)
v.collectResourcePools(ctx, now, dcName, computes, errs)
for _, c := range computes {
v.collectHosts(ctx, now, dcName, c, errs)
@@ -329,6 +333,32 @@ func (v *vcenterMetricScraper) collectResourcePools(
}
}
+func (v *vcenterMetricScraper) collectVirtualApps(
+ ctx context.Context,
+ errs *scrapererror.ScrapeErrors,
+) {
+ vApps, err := v.client.VirtualApps(ctx)
+ if err != nil {
+ errs.AddPartial(1, err)
+ return
+ }
+ for _, vApp := range vApps {
+ var moVApp mo.VirtualApp
+ err = vApp.Properties(ctx, vApp.Reference(), []string{
+ "name",
+ "vm",
+ }, &moVApp)
+ if err != nil {
+ errs.AddPartial(1, err)
+ continue
+ }
+
+ for _, vmRef := range moVApp.Vm {
+ v.vmToVirtualApp[vmRef.Value] = vApp
+ }
+ }
+}
+
func (v *vcenterMetricScraper) collectVMs(
ctx context.Context,
colTime pcommon.Timestamp,
@@ -373,6 +403,9 @@ func (v *vcenterMetricScraper) collectVMs(
poweredOnVMs++
}
+ // vApp may not exist for a VM
+ vApp := v.vmToVirtualApp[vm.Reference().Value]
+
// vms are optional without a resource pool
rpRef := vm.ResourcePool
var rp *object.ResourcePool
@@ -422,7 +455,7 @@ func (v *vcenterMetricScraper) collectVMs(
perfMetrics := vmPerfMetrics.resultsByMoRef[vm.Reference().Value]
v.buildVMMetrics(colTime, vm, hwSum, perfMetrics)
- rb := v.createVMResourceBuilder(dcName, vm, hwSum, compute, rp)
+ rb := v.createVMResourceBuilder(dcName, vm, hwSum, compute, rp, vApp)
v.mb.EmitForResource(metadata.WithResource(rb.Emit()))
}
diff --git a/receiver/vcenterreceiver/scraper_test.go b/receiver/vcenterreceiver/scraper_test.go
index e438c4139a23..7f47ee4784b9 100644
--- a/receiver/vcenterreceiver/scraper_test.go
+++ b/receiver/vcenterreceiver/scraper_test.go
@@ -40,6 +40,8 @@ func TestScrapeConfigsEnabled(t *testing.T) {
optConfigs := metadata.DefaultMetricsBuilderConfig()
optConfigs.ResourceAttributes.VcenterDatacenterName.Enabled = true
+ optConfigs.ResourceAttributes.VcenterVirtualAppName.Enabled = true
+ optConfigs.ResourceAttributes.VcenterVirtualAppInventoryPath.Enabled = true
optConfigs.Metrics.VcenterVMMemoryUtilization.Enabled = true
cfg := &Config{
diff --git a/receiver/vcenterreceiver/testdata/metrics/expected-all-enabled.yaml b/receiver/vcenterreceiver/testdata/metrics/expected-all-enabled.yaml
index 23d3d357fca3..11cf0587c7cc 100644
--- a/receiver/vcenterreceiver/testdata/metrics/expected-all-enabled.yaml
+++ b/receiver/vcenterreceiver/testdata/metrics/expected-all-enabled.yaml
@@ -5651,6 +5651,12 @@ resourceMetrics:
- key: vcenter.host.name
value:
stringValue: esxi-27971.cf5e88ac.australia-southeast1.gve.goog
+ - key: vcenter.virtual_app.name
+ value:
+ stringValue: v-app-1
+ - key: vcenter.virtual_app.inventory_path
+ value:
+ stringValue: /Datacenter/vm/v-app-1
- key: vcenter.vm.id
value:
stringValue: 5000bbe0-993e-5813-c56a-198eaa62fb62