diff --git a/confmap/internal/e2e/testdata/indirect-slice-env-var-main.yaml b/confmap/internal/e2e/testdata/indirect-slice-env-var-main.yaml new file mode 100644 index 00000000000..8ba70ed338d --- /dev/null +++ b/confmap/internal/e2e/testdata/indirect-slice-env-var-main.yaml @@ -0,0 +1,13 @@ +receivers: + nop: + otlp: + protocols: + grpc: + +exporters: + nop: + otlp: + endpoint: localhost:4317 + +service: + pipelines: ${file:${env:BASE_FOLDER}/indirect-slice-env-var-pipelines.yaml} diff --git a/confmap/internal/e2e/testdata/indirect-slice-env-var-pipelines.yaml b/confmap/internal/e2e/testdata/indirect-slice-env-var-pipelines.yaml new file mode 100644 index 00000000000..04f4f23124f --- /dev/null +++ b/confmap/internal/e2e/testdata/indirect-slice-env-var-pipelines.yaml @@ -0,0 +1,3 @@ +logs: + receivers: ${env:OTEL_LOGS_RECEIVER} + exporters: ${env:OTEL_LOGS_EXPORTER} diff --git a/confmap/internal/e2e/types_test.go b/confmap/internal/e2e/types_test.go index be099ee9bb2..88dbe5a7162 100644 --- a/confmap/internal/e2e/types_test.go +++ b/confmap/internal/e2e/types_test.go @@ -634,3 +634,54 @@ logging: cfgStr.Field, ) } + +func TestIndirectSliceEnvVar(t *testing.T) { + previousValue := globalgates.StrictlyTypedInputGate.IsEnabled() + err := featuregate.GlobalRegistry().Set(globalgates.StrictlyTypedInputID, true) + require.NoError(t, err) + defer func() { + seterr := featuregate.GlobalRegistry().Set(globalgates.StrictlyTypedInputID, previousValue) + require.NoError(t, seterr) + }() + + // This replicates the situation in https://github.com/open-telemetry/opentelemetry-collector/issues/10799 + // where a configuration file is loaded that contains a reference to a slice of strings in an environment variable. + t.Setenv("BASE_FOLDER", "testdata") + t.Setenv("OTEL_LOGS_RECEIVER", "[nop, otlp]") + t.Setenv("OTEL_LOGS_EXPORTER", "[otlp, nop]") + resolver := NewResolver(t, "indirect-slice-env-var-main.yaml") + conf, err := resolver.Resolve(context.Background()) + require.NoError(t, err) + + type CollectorConf struct { + Exporters struct { + OTLP struct { + Endpoint string `mapstructure:"endpoint"` + } `mapstructure:"otlp"` + Nop struct{} `mapstructure:"nop"` + } `mapstructure:"exporters"` + Receivers struct { + OTLP struct { + Protocols struct { + GRPC struct{} `mapstructure:"grpc"` + } `mapstructure:"protocols"` + } `mapstructure:"otlp"` + Nop struct{} `mapstructure:"nop"` + } `mapstructure:"receivers"` + Service struct { + Pipelines struct { + Logs struct { + Exporters []string `mapstructure:"exporters"` + Receivers []string `mapstructure:"receivers"` + } `mapstructure:"logs"` + } `mapstructure:"pipelines"` + } `mapstructure:"service"` + } + + var collectorConf CollectorConf + err = conf.Unmarshal(&collectorConf) + require.NoError(t, err) + assert.Equal(t, collectorConf.Exporters.OTLP.Endpoint, "localhost:4317") + assert.Equal(t, collectorConf.Service.Pipelines.Logs.Receivers, []string{"nop", "otlp"}) + assert.Equal(t, collectorConf.Service.Pipelines.Logs.Exporters, []string{"otlp", "nop"}) +}