diff --git a/exporter/solarwindsexporter/README.md b/exporter/solarwindsexporter/README.md index 2c9dd36..654b83a 100644 --- a/exporter/solarwindsexporter/README.md +++ b/exporter/solarwindsexporter/README.md @@ -18,6 +18,8 @@ You just need to include the SolarWinds Exporter in your exporter definitions an ```yaml exporters: solarwinds: {} +extensions: + solarwinds: extensions: solarwinds: token: "TOKEN" diff --git a/exporter/solarwindsexporter/config.go b/exporter/solarwindsexporter/config.go index e7de4dd..be26c97 100644 --- a/exporter/solarwindsexporter/config.go +++ b/exporter/solarwindsexporter/config.go @@ -83,6 +83,16 @@ func NewDefaultConfig() component.Config { // Validate checks the configuration for its validity. func (cfg *Config) Validate() error { + if len(cfg.Extension) != 0 { + _, err := cfg.extensionAsComponent() + if err != nil { + return fmt.Errorf( + "invalid configuration: %q is not a correct value for 'extension'", + cfg.Extension, + ) + } + } + return nil } diff --git a/exporter/solarwindsexporter/config_test.go b/exporter/solarwindsexporter/config_test.go index 9c48309..c923dcd 100644 --- a/exporter/solarwindsexporter/config_test.go +++ b/exporter/solarwindsexporter/config_test.go @@ -72,6 +72,23 @@ func TestConfigValidateOK(t *testing.T) { assert.NoError(t, cfg.(*Config).Validate()) } +// TestConfigValidateNOK. +func TestConfigValidateNOK(t *testing.T) { + cfgFile := testutil.LoadConfigTestdata(t, "invalid") + + // Parse configuration. + factory := NewFactory() + cfg := factory.CreateDefaultConfig() + require.NoError(t, cfgFile.Unmarshal(&cfg)) + + // Validation should fail with an error. + assert.ErrorContains( + t, + cfg.(*Config).Validate(), + "invalid configuration", + ) +} + // TestConfigTokenRedacted checks that the configuration // type doesn't leak its secret token unless it is accessed explicitly. func TestConfigTokenRedacted(t *testing.T) { diff --git a/exporter/solarwindsexporter/metadata.yaml b/exporter/solarwindsexporter/metadata.yaml index d6602da..5b420e7 100644 --- a/exporter/solarwindsexporter/metadata.yaml +++ b/exporter/solarwindsexporter/metadata.yaml @@ -7,5 +7,6 @@ status: development: [traces, metrics, logs] tests: + # skipped because the exporter requires solarwindsextension to run skip_lifecycle: true diff --git a/exporter/solarwindsexporter/testdata/invalid.yaml b/exporter/solarwindsexporter/testdata/invalid.yaml new file mode 100644 index 0000000..abb2afa --- /dev/null +++ b/exporter/solarwindsexporter/testdata/invalid.yaml @@ -0,0 +1 @@ +extension: "/" diff --git a/extension/solarwindsextension/README.md b/extension/solarwindsextension/README.md index a61fbc7..9b84188 100644 --- a/extension/solarwindsextension/README.md +++ b/extension/solarwindsextension/README.md @@ -10,15 +10,16 @@ [development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development -SolarWinds Extension is required sidecar for the [Solarwinds Exporter](../../exporter/solarwindsexporter). +The SolarWinds Extension offers capabilities related to the SolarWinds Observability SaaS platform and is required for the [SolarWinds Exporter](../../exporter/solarwindsexporter) to function. It provides these features: -- Hearbeat signal +- Endpoint configuration for the Solarwinds Exporters +- Heartbeat signal - It's a standard metric: `sw.otecol.uptime` - The value is a time from the start of the collector in seconds - - This signal is necessary for SWO to detect the collector when installed and to determine if it's still alive. - - It also contains some additional informations as resource attributes for SWO: + - This signal is necessary for SolarWinds Observability SaaS to detect the collector when installed and to determine if it's still alive. + - It also contains some additional information as resource attributes for SolarWinds Observability SaaS: - Collector name: `sw.collector.name` ## Getting Started @@ -32,9 +33,9 @@ extensions: data_center: "na-01" collector_name: "Collector Display Name" ``` -- `token` (mandatory) - You can generate your token in your SWO (SolarWinds Observability) account under _Settings / API Tokens / Create API Token_. The type is "Ingestion". You can find the complete documentation [here](https://documentation.solarwinds.com/en/success_center/observability/content/settings/api-tokens.htm). +- `token` (mandatory) - You can generate your token in your SolarWinds Observability SaaS account under _Settings / API Tokens / Create API Token_. The type is "Ingestion". You can find the complete documentation [here](https://documentation.solarwinds.com/en/success_center/observability/content/settings/api-tokens.htm). - `data_center` (mandatory) - Data center is the region you picked during the sign-up process. You can easily see in URLs after logging in to SolarWinds Observability SaaS - it's either `na-01`, `na-02` or `eu-01`. Please refer to the [documentation](https://documentation.solarwinds.com/en/success_center/observability/content/system_requirements/endpoints.htm#Find) for details. -- `collector_name` (mandatory) - this is the name under which the collector will be shown in the SWO UI. Doesn't have to be unique. +- `collector_name` (mandatory) - The collector name passed in the heartbeat metric (as `sw.collector.name` resource attribute) to identify the collector. Doesn't have to be unique. ## Development - **Tests** can be executed with `make test`. diff --git a/extension/solarwindsextension/config_test.go b/extension/solarwindsextension/config_test.go index c9bc35a..93da7b1 100644 --- a/extension/solarwindsextension/config_test.go +++ b/extension/solarwindsextension/config_test.go @@ -41,7 +41,7 @@ func TestConfigUnmarshalFull(t *testing.T) { DataCenter: "na-01", EndpointURLOverride: "127.0.0.1:1234", IngestionToken: "TOKEN", - CollectorName: "best-collector-ever", + CollectorName: "test-collector", Insecure: true, }, cfg) } @@ -115,6 +115,23 @@ func TestConfigValidateMissingCollectorName(t *testing.T) { ) } +// TestConfigValidateInsecureInProd tests that 'insecure' +// cannot be enabled for a production endpoint. +func TestConfigValidateInsecureInProd(t *testing.T) { + cfgFile := testutil.LoadConfigTestdata(t, "insecure_in_prod") + + // Parse configuration. + factory := NewFactory() + cfg := factory.CreateDefaultConfig() + require.NoError(t, cfgFile.Unmarshal(&cfg)) + + assert.ErrorContains( + t, + cfg.(*internal.Config).Validate(), + "invalid configuration: 'insecure'", + ) +} + // TestConfigTokenRedacted checks that the configuration // type doesn't leak its secret token unless it is accessed explicitly. func TestConfigTokenRedacted(t *testing.T) { diff --git a/extension/solarwindsextension/go.mod b/extension/solarwindsextension/go.mod index 375d3a4..8602072 100644 --- a/extension/solarwindsextension/go.mod +++ b/extension/solarwindsextension/go.mod @@ -9,7 +9,7 @@ require ( go.opentelemetry.io/collector/config/configgrpc v0.113.0 go.opentelemetry.io/collector/config/configopaque v1.19.0 go.opentelemetry.io/collector/config/configtls v1.19.0 - go.opentelemetry.io/collector/confmap v1.21.0 + go.opentelemetry.io/collector/confmap v1.19.0 go.opentelemetry.io/collector/exporter v0.113.0 go.opentelemetry.io/collector/exporter/otlpexporter v0.113.0 go.opentelemetry.io/collector/extension v0.113.0 diff --git a/extension/solarwindsextension/go.sum b/extension/solarwindsextension/go.sum index 422c53a..2ed1b3e 100644 --- a/extension/solarwindsextension/go.sum +++ b/extension/solarwindsextension/go.sum @@ -82,8 +82,8 @@ go.opentelemetry.io/collector/config/configtls v1.19.0 h1:GQ/cF1hgNqHVBq2oSSrOFX go.opentelemetry.io/collector/config/configtls v1.19.0/go.mod h1:1hyqnYB3JqEUlk1ME/s9HYz4oCRcxQCRxsJitFFT/cA= go.opentelemetry.io/collector/config/internal v0.113.0 h1:9RAzH8v7ItFT1npHpvP0SvUzBHcZDliCGRo9Spp6v7c= go.opentelemetry.io/collector/config/internal v0.113.0/go.mod h1:yC7E4h1Uj0SubxcFImh6OvBHFTjMh99+A5PuyIgDWqc= -go.opentelemetry.io/collector/confmap v1.21.0 h1:1tIcx2/Suwg8VhuPmQw87ba0ludPmumpFCFRZZa6RXA= -go.opentelemetry.io/collector/confmap v1.21.0/go.mod h1:Rrhs+MWoaP6AswZp+ReQ2VO9dfOfcUjdjiSHBsG+nec= +go.opentelemetry.io/collector/confmap v1.19.0 h1:TQ0lZpAKqgsE0EKk+u4JA+uBbPYeFRmWP3GH43w40CY= +go.opentelemetry.io/collector/confmap v1.19.0/go.mod h1:GgNu1ElPGmLn9govqIfjaopvdspw4PJ9KeDtWC4E2Q4= go.opentelemetry.io/collector/consumer v0.113.0 h1:KJSiK5vSIY9dgPxwKfQ3gOgKtQsqc+7IB7mGhUAL5c8= go.opentelemetry.io/collector/consumer v0.113.0/go.mod h1:zHMlXYFaJlZoLCBR6UwWoyXZ/adcO1u2ydqUal3VmYU= go.opentelemetry.io/collector/consumer/consumererror v0.113.0 h1:Hd2N7n9RKbnKRaVrdw6fPBoQko5zZIgCxwVxkL6SAIE= diff --git a/extension/solarwindsextension/internal/config.go b/extension/solarwindsextension/internal/config.go index 843841f..82893aa 100644 --- a/extension/solarwindsextension/internal/config.go +++ b/extension/solarwindsextension/internal/config.go @@ -32,9 +32,9 @@ import ( type Config struct { // DataCenter ID (e.g. na-01). DataCenter string `mapstructure:"data_center"` - // IngestionToken is your secret generated SWO ingestion token. + // IngestionToken is your secret generated SolarWinds Observability SaaS ingestion token. IngestionToken configopaque.String `mapstructure:"token"` - // CollectorName is the name you will see in the SWO UI + // CollectorName name of the collector passed in the heartbeat metric CollectorName string `mapstructure:"collector_name"` // Insecure disables TLS in the exporters. diff --git a/extension/solarwindsextension/testdata/full.yaml b/extension/solarwindsextension/testdata/full.yaml index 5604d15..b7bd8e3 100644 --- a/extension/solarwindsextension/testdata/full.yaml +++ b/extension/solarwindsextension/testdata/full.yaml @@ -1,5 +1,5 @@ token: "TOKEN" data_center: "na-01" -collector_name: "best-collector-ever" +collector_name: "test-collector" endpoint_url_override: "127.0.0.1:1234" insecure: true diff --git a/extension/solarwindsextension/testdata/insecure_in_prod.yaml b/extension/solarwindsextension/testdata/insecure_in_prod.yaml new file mode 100644 index 0000000..0c0d906 --- /dev/null +++ b/extension/solarwindsextension/testdata/insecure_in_prod.yaml @@ -0,0 +1,4 @@ +token: "YOUR-INGESTION-TOKEN" +data_center: "na-02" +collector_name: "collector" +insecure: true diff --git a/pkg/testutil/go.mod b/pkg/testutil/go.mod index b10c5ba..b262557 100644 --- a/pkg/testutil/go.mod +++ b/pkg/testutil/go.mod @@ -1,9 +1,10 @@ module github.com/solarwinds/solarwinds-otel-collector/pkg/testutil go 1.23.4 + require ( github.com/stretchr/testify v1.10.0 - go.opentelemetry.io/collector/confmap v1.21.0 + go.opentelemetry.io/collector/confmap v1.19.0 ) require ( diff --git a/pkg/testutil/go.sum b/pkg/testutil/go.sum index da9779b..a863f67 100644 --- a/pkg/testutil/go.sum +++ b/pkg/testutil/go.sum @@ -22,8 +22,8 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -go.opentelemetry.io/collector/confmap v1.21.0 h1:1tIcx2/Suwg8VhuPmQw87ba0ludPmumpFCFRZZa6RXA= -go.opentelemetry.io/collector/confmap v1.21.0/go.mod h1:Rrhs+MWoaP6AswZp+ReQ2VO9dfOfcUjdjiSHBsG+nec= +go.opentelemetry.io/collector/confmap v1.19.0 h1:TQ0lZpAKqgsE0EKk+u4JA+uBbPYeFRmWP3GH43w40CY= +go.opentelemetry.io/collector/confmap v1.19.0/go.mod h1:GgNu1ElPGmLn9govqIfjaopvdspw4PJ9KeDtWC4E2Q4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=