diff --git a/receiver/vcenterreceiver/config.go b/receiver/vcenterreceiver/config.go index 1319744dcc36a..3dd4f5233aa53 100644 --- a/receiver/vcenterreceiver/config.go +++ b/receiver/vcenterreceiver/config.go @@ -25,6 +25,13 @@ type Config struct { Endpoint string `mapstructure:"endpoint"` Username string `mapstructure:"username"` Password configopaque.String `mapstructure:"password"` + // Scrapers defines which scraper groups are enabled. + // If not specified, all scraper groups are enabled by default for backward compatibility. + Scrapers map[ScraperGroup]ScraperConfig `mapstructure:"scrapers,omitempty"` +} + +type ScraperConfig struct { + Enabled bool `mapstructure:"enabled,omitempty"` } // Validate checks to see if the supplied config will work for the receiver @@ -56,6 +63,19 @@ func (c *Config) Validate() error { err = multierr.Append(err, fmt.Errorf("error loading tls configuration: %w", tlsErr)) } + // Validate scraper group names + if c.Scrapers != nil { + validGroups := make(map[ScraperGroup]bool) + for _, group := range AllScraperGroups() { + validGroups[group] = true + } + for group := range c.Scrapers { + if !validGroups[group] { + err = multierr.Append(err, fmt.Errorf("invalid scraper group: %q. Valid groups are: %v", group, AllScraperGroups())) + } + } + } + return err } diff --git a/receiver/vcenterreceiver/config_test.go b/receiver/vcenterreceiver/config_test.go index 155ca0d78b8aa..bce700139e5f0 100644 --- a/receiver/vcenterreceiver/config_test.go +++ b/receiver/vcenterreceiver/config_test.go @@ -111,3 +111,217 @@ func TestLoadConfig(t *testing.T) { t.Errorf("Config mismatch (-expected +actual):\n%s", diff) } } + +func TestScraperGroupsConfig(t *testing.T) { + tests := []struct { + name string + cfg *Config + expectError bool + errorMsg string + }{ + { + name: "valid scraper group", + cfg: &Config{ + Endpoint: "https://vcsa.some-host", + Username: "user", + Password: "pass", + ControllerConfig: scraperhelper.NewDefaultControllerConfig(), + Scrapers: map[ScraperGroup]ScraperConfig{ + ScraperGroupVSAN: {Enabled: true}, + }, + }, + expectError: false, + }, + { + name: "invalid scraper group", + cfg: &Config{ + Endpoint: "https://vcsa.some-host", + Username: "user", + Password: "pass", + ControllerConfig: scraperhelper.NewDefaultControllerConfig(), + Scrapers: map[ScraperGroup]ScraperConfig{ + ScraperGroup("invalid"): {Enabled: true}, + }, + }, + expectError: true, + errorMsg: "invalid scraper group", + }, + { + name: "multiple scraper groups", + cfg: &Config{ + Endpoint: "https://vcsa.some-host", + Username: "user", + Password: "pass", + ControllerConfig: scraperhelper.NewDefaultControllerConfig(), + Scrapers: map[ScraperGroup]ScraperConfig{ + ScraperGroupVSAN: {Enabled: true}, + ScraperGroupCluster: {Enabled: false}, + ScraperGroupHost: {Enabled: true}, + ScraperGroupVM: {Enabled: true}, + ScraperGroupDatastore: {Enabled: false}, + }, + }, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.cfg.Validate() + if tt.expectError { + require.Error(t, err) + if tt.errorMsg != "" { + require.ErrorContains(t, err, tt.errorMsg) + } + } else { + require.NoError(t, err) + } + }) + } +} + +func TestIsScraperGroupEnabled(t *testing.T) { + tests := []struct { + name string + cfg *Config + group ScraperGroup + expectedResult bool + }{ + { + name: "scraper groups not configured - defaults to enabled", + cfg: &Config{ + Scrapers: nil, + }, + group: ScraperGroupVSAN, + expectedResult: true, + }, + { + name: "scraper group not specified - defaults to enabled", + cfg: &Config{ + Scrapers: map[ScraperGroup]ScraperConfig{ + ScraperGroupCluster: {Enabled: false}, + }, + }, + group: ScraperGroupVSAN, + expectedResult: true, + }, + { + name: "scraper group explicitly enabled", + cfg: &Config{ + Scrapers: map[ScraperGroup]ScraperConfig{ + ScraperGroupVSAN: {Enabled: true}, + }, + }, + group: ScraperGroupVSAN, + expectedResult: true, + }, + { + name: "scraper group explicitly disabled", + cfg: &Config{ + Scrapers: map[ScraperGroup]ScraperConfig{ + ScraperGroupVSAN: {Enabled: false}, + }, + }, + group: ScraperGroupVSAN, + expectedResult: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := isScraperGroupEnabled(tt.cfg, tt.group) + require.Equal(t, tt.expectedResult, result) + }) + } +} + +func TestHasEnabledVSANMetrics(t *testing.T) { + tests := []struct { + name string + cfg *Config + expectedResult bool + }{ + { + name: "scraper groups not configured - uses backward compatibility", + cfg: &Config{ + Scrapers: nil, + MetricsBuilderConfig: metadata.MetricsBuilderConfig{ + Metrics: metadata.MetricsConfig{ + VcenterClusterVsanOperations: metadata.MetricConfig{Enabled: true}, + }, + }, + }, + expectedResult: true, + }, + { + name: "scraper groups configured - vsan enabled", + cfg: &Config{ + Scrapers: map[ScraperGroup]ScraperConfig{ + ScraperGroupVSAN: {Enabled: true}, + }, + MetricsBuilderConfig: metadata.MetricsBuilderConfig{ + Metrics: metadata.MetricsConfig{ + // Even if individual metrics are disabled, scraper group takes precedence + VcenterClusterVsanOperations: metadata.MetricConfig{Enabled: false}, + }, + }, + }, + expectedResult: true, + }, + { + name: "scraper groups configured - vsan disabled", + cfg: &Config{ + Scrapers: map[ScraperGroup]ScraperConfig{ + ScraperGroupVSAN: {Enabled: false}, + }, + MetricsBuilderConfig: metadata.MetricsBuilderConfig{ + Metrics: metadata.MetricsConfig{ + // Even if individual metrics are enabled, scraper group takes precedence + VcenterClusterVsanOperations: metadata.MetricConfig{Enabled: true}, + }, + }, + }, + expectedResult: false, + }, + { + name: "scraper groups configured - vsan not specified, defaults to enabled", + cfg: &Config{ + Scrapers: map[ScraperGroup]ScraperConfig{ + ScraperGroupCluster: {Enabled: false}, + }, + MetricsBuilderConfig: metadata.MetricsBuilderConfig{ + Metrics: metadata.MetricsConfig{ + VcenterClusterVsanOperations: metadata.MetricConfig{Enabled: false}, + }, + }, + }, + expectedResult: true, // Defaults to enabled when not specified + }, + { + name: "backward compatibility - no vsan metrics enabled", + cfg: &Config{ + Scrapers: nil, + MetricsBuilderConfig: metadata.MetricsBuilderConfig{ + Metrics: metadata.MetricsConfig{ + // All vSAN metrics disabled + VcenterClusterVsanOperations: metadata.MetricConfig{Enabled: false}, + VcenterClusterVsanThroughput: metadata.MetricConfig{Enabled: false}, + VcenterHostVsanOperations: metadata.MetricConfig{Enabled: false}, + VcenterVMVsanOperations: metadata.MetricConfig{Enabled: false}, + }, + }, + }, + expectedResult: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + scraper := &vcenterMetricScraper{ + config: tt.cfg, + } + result := scraper.hasEnabledVSANMetrics() + require.Equal(t, tt.expectedResult, result) + }) + } +} diff --git a/receiver/vcenterreceiver/scraper.go b/receiver/vcenterreceiver/scraper.go index 562304871b7da..59ccb224e8d66 100644 --- a/receiver/vcenterreceiver/scraper.go +++ b/receiver/vcenterreceiver/scraper.go @@ -89,6 +89,11 @@ func newVcenterScrapeData() *vcenterScrapeData { } func (v *vcenterMetricScraper) hasEnabledVSANMetrics() bool { + if v.config.Scrapers != nil { + return isScraperGroupEnabled(v.config, ScraperGroupVSAN) + } + + // TODO: keep this or? metrics := v.config.Metrics // Check cluster vSAN metrics diff --git a/receiver/vcenterreceiver/scraper_groups.go b/receiver/vcenterreceiver/scraper_groups.go new file mode 100644 index 0000000000000..fab65b2ad41e1 --- /dev/null +++ b/receiver/vcenterreceiver/scraper_groups.go @@ -0,0 +1,43 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package vcenterreceiver + +type ScraperGroup string + +const ( + ScraperGroupCluster ScraperGroup = "cluster" + ScraperGroupHost ScraperGroup = "host" + ScraperGroupVM ScraperGroup = "vm" + ScraperGroupDatastore ScraperGroup = "datastore" + ScraperGroupResourcePool ScraperGroup = "resourcepool" + ScraperGroupDatacenter ScraperGroup = "datacenter" + ScraperGroupVSAN ScraperGroup = "vsan" +) + +// AllScraperGroups returns all available scraper groups +func AllScraperGroups() []ScraperGroup { + return []ScraperGroup{ + ScraperGroupCluster, + ScraperGroupHost, + ScraperGroupVM, + ScraperGroupDatastore, + ScraperGroupResourcePool, + ScraperGroupDatacenter, + ScraperGroupVSAN, + } +} + +// isScraperGroupEnabled checks if a scraper group is enabled in the config. +// If the scraper group is not specified in the config, it defaults to enabled +// for backward compatibility. +func isScraperGroupEnabled(cfg *Config, group ScraperGroup) bool { + if cfg.Scrapers == nil { + return true + } + scraperCfg, exists := cfg.Scrapers[group] + if !exists { + return true + } + return scraperCfg.Enabled +}