diff --git a/config/config.go b/config/config.go index d93cba25487..b69a29e3ee2 100644 --- a/config/config.go +++ b/config/config.go @@ -26,7 +26,6 @@ import ( "github.com/spf13/cast" "github.com/spf13/viper" - "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configmodels" @@ -42,15 +41,6 @@ const ( errInvalidTypeAndNameKey errUnknownType errDuplicateName - errMissingPipelines - errPipelineMustHaveReceiver - errPipelineMustHaveExporter - errExtensionNotExists - errPipelineReceiverNotExists - errPipelineProcessorNotExists - errPipelineExporterNotExists - errMissingReceivers - errMissingExporters errUnmarshalTopLevelStructureError ) @@ -478,171 +468,6 @@ func loadPipelines(pipelinesConfig map[string]pipelineSettings) (configmodels.Pi return pipelines, nil } -// ValidateConfig validates config. -func ValidateConfig(cfg *configmodels.Config, _ *zap.Logger) error { - // This function performs basic validation of configuration. There may be more subtle - // invalid cases that we currently don't check for but which we may want to add in - // the future (e.g. disallowing receiving and exporting on the same endpoint). - - if err := validateReceivers(cfg); err != nil { - return err - } - - if err := validateExporters(cfg); err != nil { - return err - } - - if err := validateService(cfg); err != nil { - return err - } - - return nil -} - -func validateService(cfg *configmodels.Config) error { - if err := validatePipelines(cfg); err != nil { - return err - } - - return validateServiceExtensions(cfg) -} - -func validateServiceExtensions(cfg *configmodels.Config) error { - if len(cfg.Service.Extensions) == 0 { - return nil - } - - // Validate extensions. - for _, ref := range cfg.Service.Extensions { - // Check that the name referenced in the Service extensions exists in the top-level extensions - if cfg.Extensions[ref] == nil { - return &configError{ - code: errExtensionNotExists, - msg: fmt.Sprintf("Service references extension %q which does not exist", ref), - } - } - } - - return nil -} - -func validatePipelines(cfg *configmodels.Config) error { - // Must have at least one pipeline. - if len(cfg.Service.Pipelines) == 0 { - return &configError{code: errMissingPipelines, msg: "must have at least one pipeline"} - } - - // Validate pipelines. - for _, pipeline := range cfg.Service.Pipelines { - if err := validatePipeline(cfg, pipeline); err != nil { - return err - } - } - return nil -} - -func validatePipeline(cfg *configmodels.Config, pipeline *configmodels.Pipeline) error { - if err := validatePipelineReceivers(cfg, pipeline); err != nil { - return err - } - - if err := validatePipelineExporters(cfg, pipeline); err != nil { - return err - } - - if err := validatePipelineProcessors(cfg, pipeline); err != nil { - return err - } - - return nil -} - -func validatePipelineReceivers(cfg *configmodels.Config, pipeline *configmodels.Pipeline) error { - if len(pipeline.Receivers) == 0 { - return &configError{ - code: errPipelineMustHaveReceiver, - msg: fmt.Sprintf("pipeline %q must have at least one receiver", pipeline.Name), - } - } - - // Validate pipeline receiver name references. - for _, ref := range pipeline.Receivers { - // Check that the name referenced in the pipeline's receivers exists in the top-level receivers - if cfg.Receivers[ref] == nil { - return &configError{ - code: errPipelineReceiverNotExists, - msg: fmt.Sprintf("pipeline %q references receiver %q which does not exist", pipeline.Name, ref), - } - } - } - - return nil -} - -func validatePipelineExporters(cfg *configmodels.Config, pipeline *configmodels.Pipeline) error { - if len(pipeline.Exporters) == 0 { - return &configError{ - code: errPipelineMustHaveExporter, - msg: fmt.Sprintf("pipeline %q must have at least one exporter", pipeline.Name), - } - } - - // Validate pipeline exporter name references. - for _, ref := range pipeline.Exporters { - // Check that the name referenced in the pipeline's Exporters exists in the top-level Exporters - if cfg.Exporters[ref] == nil { - return &configError{ - code: errPipelineExporterNotExists, - msg: fmt.Sprintf("pipeline %q references exporter %q which does not exist", pipeline.Name, ref), - } - } - } - - return nil -} - -func validatePipelineProcessors(cfg *configmodels.Config, pipeline *configmodels.Pipeline) error { - if len(pipeline.Processors) == 0 { - return nil - } - - // Validate pipeline processor name references - for _, ref := range pipeline.Processors { - // Check that the name referenced in the pipeline's processors exists in the top-level processors. - if cfg.Processors[ref] == nil { - return &configError{ - code: errPipelineProcessorNotExists, - msg: fmt.Sprintf("pipeline %q references processor %s which does not exist", pipeline.Name, ref), - } - } - } - - return nil -} - -func validateReceivers(cfg *configmodels.Config) error { - // Currently there is no default receiver enabled. The configuration must specify at least one enabled receiver to - // be valid. - if len(cfg.Receivers) == 0 { - return &configError{ - code: errMissingReceivers, - msg: "no enabled receivers specified in config", - } - } - return nil -} - -func validateExporters(cfg *configmodels.Config) error { - // There must be at least one enabled exporter to be considered a valid configuration. - if len(cfg.Exporters) == 0 { - return &configError{ - code: errMissingExporters, - msg: "no enabled exporters specified in config", - } - } - return nil -} - // expandEnvConfig creates a new viper config with expanded values for all the values (simple, list or map value). // It does not expand the keys. func expandEnvConfig(v *viper.Viper) { diff --git a/config/config_test.go b/config/config_test.go index e85be8e7554..7f6b5dad293 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -21,7 +21,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" @@ -414,47 +413,40 @@ func TestDecodeConfig_Invalid(t *testing.T) { expected configErrorCode // expected error (if nil any error is acceptable) expectedMessage string // string that the error must contain }{ - {name: "empty-config"}, - {name: "missing-all-sections"}, - {name: "missing-exporters", expected: errMissingExporters}, - {name: "missing-receivers", expected: errMissingReceivers}, - {name: "missing-processors"}, - {name: "invalid-extension-name", expected: errExtensionNotExists}, - {name: "invalid-receiver-name"}, - {name: "invalid-receiver-reference", expected: errPipelineReceiverNotExists}, - {name: "missing-extension-type", expected: errInvalidTypeAndNameKey}, - {name: "missing-receiver-type", expected: errInvalidTypeAndNameKey}, - {name: "missing-exporter-name-after-slash", expected: errInvalidTypeAndNameKey}, - {name: "missing-processor-type", expected: errInvalidTypeAndNameKey}, - {name: "missing-pipelines", expected: errMissingPipelines}, - {name: "pipeline-must-have-exporter-logs", expected: errPipelineMustHaveExporter}, - {name: "pipeline-must-have-exporter-metrics", expected: errPipelineMustHaveExporter}, - {name: "pipeline-must-have-exporter-traces", expected: errPipelineMustHaveExporter}, - {name: "pipeline-must-have-receiver-logs", expected: errPipelineMustHaveReceiver}, - {name: "pipeline-must-have-receiver-metrics", expected: errPipelineMustHaveReceiver}, - {name: "pipeline-must-have-receiver-traces", expected: errPipelineMustHaveReceiver}, - {name: "pipeline-exporter-not-exists", expected: errPipelineExporterNotExists}, - {name: "pipeline-processor-not-exists", expected: errPipelineProcessorNotExists}, + {name: "invalid-extension-type", expected: errInvalidTypeAndNameKey}, + {name: "invalid-receiver-type", expected: errInvalidTypeAndNameKey}, + {name: "invalid-exporter-type", expected: errInvalidTypeAndNameKey}, + {name: "invalid-processor-type", expected: errInvalidTypeAndNameKey}, + {name: "invalid-pipeline-type", expected: errInvalidTypeAndNameKey}, + + {name: "invalid-extension-name-after-slash", expected: errInvalidTypeAndNameKey}, + {name: "invalid-receiver-name-after-slash", expected: errInvalidTypeAndNameKey}, + {name: "invalid-exporter-name-after-slash", expected: errInvalidTypeAndNameKey}, + {name: "invalid-processor-name-after-slash", expected: errInvalidTypeAndNameKey}, + {name: "invalid-pipeline-name-after-slash", expected: errInvalidTypeAndNameKey}, + {name: "unknown-extension-type", expected: errUnknownType, expectedMessage: "extensions"}, {name: "unknown-receiver-type", expected: errUnknownType, expectedMessage: "receivers"}, {name: "unknown-exporter-type", expected: errUnknownType, expectedMessage: "exporters"}, {name: "unknown-processor-type", expected: errUnknownType, expectedMessage: "processors"}, - {name: "invalid-service-extensions-value", expected: errUnmarshalTopLevelStructureError, expectedMessage: "service"}, - {name: "invalid-sequence-value", expected: errUnmarshalTopLevelStructureError, expectedMessage: "pipelines"}, - {name: "invalid-pipeline-type", expected: errUnknownType, expectedMessage: "pipelines"}, - {name: "invalid-pipeline-type-and-name", expected: errInvalidTypeAndNameKey}, + {name: "unknown-pipeline-type", expected: errUnknownType, expectedMessage: "pipelines"}, + {name: "duplicate-extension", expected: errDuplicateName, expectedMessage: "extensions"}, {name: "duplicate-receiver", expected: errDuplicateName, expectedMessage: "receivers"}, {name: "duplicate-exporter", expected: errDuplicateName, expectedMessage: "exporters"}, {name: "duplicate-processor", expected: errDuplicateName, expectedMessage: "processors"}, {name: "duplicate-pipeline", expected: errDuplicateName, expectedMessage: "pipelines"}, + {name: "invalid-top-level-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "top level"}, {name: "invalid-extension-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "extensions"}, - {name: "invalid-service-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "service"}, {name: "invalid-receiver-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "receivers"}, {name: "invalid-processor-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "processors"}, {name: "invalid-exporter-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "exporters"}, + {name: "invalid-service-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "service"}, + {name: "invalid-service-extensions-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "service"}, {name: "invalid-pipeline-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "pipelines"}, + {name: "invalid-sequence-value", expected: errUnmarshalTopLevelStructureError, expectedMessage: "pipelines"}, + {name: "invalid-extension-sub-config", expected: errUnmarshalTopLevelStructureError}, {name: "invalid-exporter-sub-config", expected: errUnmarshalTopLevelStructureError}, {name: "invalid-processor-sub-config", expected: errUnmarshalTopLevelStructureError}, @@ -468,9 +460,8 @@ func TestDecodeConfig_Invalid(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { _, err := loadConfigFile(t, path.Join(".", "testdata", test.name+".yaml"), factories) - if err == nil { - t.Error("expected error but succeeded") - } else if test.expected != 0 { + require.Error(t, err) + if test.expected != 0 { cfgErr, ok := err.(*configError) if !ok { t.Errorf("expected config error code %v but got a different error '%v'", test.expected, err) @@ -486,25 +477,19 @@ func TestDecodeConfig_Invalid(t *testing.T) { } } -func TestLoadEmptyConfig(t *testing.T) { +func TestLoadEmpty(t *testing.T) { factories, err := componenttest.ExampleComponents() assert.NoError(t, err) - // Open the file for reading. - file, err := os.Open(path.Join(".", "testdata", "empty-config.yaml")) - require.NoError(t, err) - - defer func() { - require.NoError(t, file.Close()) - }() + _, err = loadConfigFile(t, path.Join(".", "testdata", "empty-config.yaml"), factories) + assert.NoError(t, err) +} - // Read yaml config from file - v := NewViper() - v.SetConfigType("yaml") - require.NoError(t, v.ReadConfig(file)) +func TestLoadEmptyAllSections(t *testing.T) { + factories, err := componenttest.ExampleComponents() + assert.NoError(t, err) - // Load the config from viper using the given factories. - _, err = Load(v, factories) + _, err = loadConfigFile(t, path.Join(".", "testdata", "empty-all-sections.yaml"), factories) assert.NoError(t, err) } @@ -515,11 +500,7 @@ func loadConfigFile(t *testing.T, fileName string, factories component.Factories require.NoErrorf(t, v.ReadInConfig(), "unable to read the file %v", fileName) // Load the config from viper using the given factories. - cfg, err := Load(v, factories) - if err != nil { - return nil, err - } - return cfg, ValidateConfig(cfg, zap.NewNop()) + return Load(v, factories) } type nestedConfig struct { diff --git a/config/configmodels/config.go b/config/configmodels/config.go index a01e677e398..04e676c5be8 100644 --- a/config/configmodels/config.go +++ b/config/configmodels/config.go @@ -29,6 +29,17 @@ // the corresponding common settings struct (the easiest approach is to embed the common struct). package configmodels +import ( + "errors" + "fmt" +) + +var ( + errMissingExporters = errors.New("no enabled exporters specified in config") + errMissingReceivers = errors.New("no enabled receivers specified in config") + errMissingServicePipelines = errors.New("service must have at least one pipeline") +) + // Config defines the configuration for the various elements of collector or agent. type Config struct { Receivers @@ -38,6 +49,91 @@ type Config struct { Service } +// Validate returns an error if the config is invalid. +// +// This function performs basic validation of configuration. There may be more subtle +// invalid cases that we currently don't check for but which we may want to add in +// the future (e.g. disallowing receiving and exporting on the same endpoint). +func (cfg *Config) Validate() error { + // Currently there is no default receiver enabled. + // The configuration must specify at least one receiver to be valid. + if len(cfg.Receivers) == 0 { + return errMissingReceivers + } + + // Currently there is no default exporter enabled. + // The configuration must specify at least one exporter to be valid. + if len(cfg.Exporters) == 0 { + return errMissingExporters + } + + // Check that all enabled extensions in the service are configured + if err := cfg.validateServiceExtensions(); err != nil { + return err + } + + // Check that all pipelines have at least one receiver and one exporter, and they reference + // only configured components. + return cfg.validateServicePipelines() +} + +func (cfg *Config) validateServiceExtensions() error { + // Validate extensions. + for _, ref := range cfg.Service.Extensions { + // Check that the name referenced in the Service extensions exists in the top-level extensions + if cfg.Extensions[ref] == nil { + return fmt.Errorf("service references extension %q which does not exist", ref) + } + } + + return nil +} + +func (cfg *Config) validateServicePipelines() error { + // Must have at least one pipeline. + if len(cfg.Service.Pipelines) == 0 { + return errMissingServicePipelines + } + + // Validate pipelines. + for _, pipeline := range cfg.Service.Pipelines { + // Validate pipeline has at least one receiver. + if len(pipeline.Receivers) == 0 { + return fmt.Errorf("pipeline %q must have at least one receiver", pipeline.Name) + } + + // Validate pipeline receiver name references. + for _, ref := range pipeline.Receivers { + // Check that the name referenced in the pipeline's receivers exists in the top-level receivers + if cfg.Receivers[ref] == nil { + return fmt.Errorf("pipeline %q references receiver %q which does not exist", pipeline.Name, ref) + } + } + + // Validate pipeline processor name references + for _, ref := range pipeline.Processors { + // Check that the name referenced in the pipeline's processors exists in the top-level processors. + if cfg.Processors[ref] == nil { + return fmt.Errorf("pipeline %q references processor %q which does not exist", pipeline.Name, ref) + } + } + + // Validate pipeline has at least one exporter + if len(pipeline.Exporters) == 0 { + return fmt.Errorf("pipeline %q must have at least one exporter", pipeline.Name) + } + + // Validate pipeline exporter name references. + for _, ref := range pipeline.Exporters { + // Check that the name referenced in the pipeline's Exporters exists in the top-level Exporters + if cfg.Exporters[ref] == nil { + return fmt.Errorf("pipeline %q references exporter %q which does not exist", pipeline.Name, ref) + } + } + } + return nil +} + // Service defines the configurable components of the service. type Service struct { // Extensions is the ordered list of extensions configured for the service. diff --git a/config/configmodels/config_test.go b/config/configmodels/config_test.go new file mode 100644 index 00000000000..8dc2e848589 --- /dev/null +++ b/config/configmodels/config_test.go @@ -0,0 +1,158 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package configmodels + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestConfigValidate(t *testing.T) { + var testCases = []struct { + name string // test case name (also file name containing config yaml) + cfgFn func() *Config + expected error + }{ + { + name: "valid", + cfgFn: generateConfig, + expected: nil, + }, + { + name: "missing-exporters", + cfgFn: func() *Config { + cfg := generateConfig() + cfg.Exporters = nil + return cfg + }, + expected: errMissingExporters, + }, + { + name: "missing-receivers", + cfgFn: func() *Config { + cfg := generateConfig() + cfg.Receivers = nil + return cfg + }, + expected: errMissingReceivers, + }, + { + name: "invalid-extension-reference", + cfgFn: func() *Config { + cfg := generateConfig() + cfg.Service.Extensions = append(cfg.Service.Extensions, "nop/2") + return cfg + }, + expected: errors.New(`service references extension "nop/2" which does not exist`), + }, + { + name: "invalid-receiver-reference", + cfgFn: func() *Config { + cfg := generateConfig() + pipe := cfg.Service.Pipelines["traces"] + pipe.Receivers = append(pipe.Receivers, "nop/2") + return cfg + }, + expected: errors.New(`pipeline "traces" references receiver "nop/2" which does not exist`), + }, + { + name: "invalid-processor-reference", + cfgFn: func() *Config { + cfg := generateConfig() + pipe := cfg.Service.Pipelines["traces"] + pipe.Processors = append(pipe.Processors, "nop/2") + return cfg + }, + expected: errors.New(`pipeline "traces" references processor "nop/2" which does not exist`), + }, + { + name: "invalid-exporter-reference", + cfgFn: func() *Config { + cfg := generateConfig() + pipe := cfg.Service.Pipelines["traces"] + pipe.Exporters = append(pipe.Exporters, "nop/2") + return cfg + }, + expected: errors.New(`pipeline "traces" references exporter "nop/2" which does not exist`), + }, + { + name: "missing-pipeline-receivers", + cfgFn: func() *Config { + cfg := generateConfig() + pipe := cfg.Service.Pipelines["traces"] + pipe.Receivers = nil + return cfg + }, + expected: errors.New(`pipeline "traces" must have at least one receiver`), + }, + { + name: "missing-pipeline-exporters", + cfgFn: func() *Config { + cfg := generateConfig() + pipe := cfg.Service.Pipelines["traces"] + pipe.Exporters = nil + return cfg + }, + expected: errors.New(`pipeline "traces" must have at least one exporter`), + }, + { + name: "missing-pipelines", + cfgFn: func() *Config { + cfg := generateConfig() + cfg.Service.Pipelines = nil + return cfg + }, + expected: errMissingServicePipelines, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + cfg := test.cfgFn() + assert.Equal(t, test.expected, cfg.Validate()) + }) + } +} + +func generateConfig() *Config { + return &Config{ + Receivers: map[string]Receiver{ + "nop": &ReceiverSettings{TypeVal: "nop"}, + }, + Exporters: map[string]Exporter{ + "nop": &ExporterSettings{TypeVal: "nop"}, + }, + Processors: map[string]Processor{ + "nop": &ProcessorSettings{TypeVal: "nop"}, + }, + Extensions: map[string]Extension{ + "nop": &ExtensionSettings{TypeVal: "nop"}, + }, + Service: Service{ + Extensions: []string{"nop"}, + Pipelines: map[string]*Pipeline{ + "traces": { + Name: "traces", + InputType: TracesDataType, + Receivers: []string{"nop"}, + Processors: []string{"nop"}, + Exporters: []string{"nop"}, + }, + }, + }, + } +} diff --git a/config/configtest/configtest.go b/config/configtest/configtest.go index 3d75e3e5d35..7f397265a52 100644 --- a/config/configtest/configtest.go +++ b/config/configtest/configtest.go @@ -19,7 +19,6 @@ import ( "github.com/spf13/viper" "github.com/stretchr/testify/require" - "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config" @@ -47,5 +46,5 @@ func LoadConfigFile(t *testing.T, fileName string, factories component.Factories if err != nil { return nil, err } - return cfg, config.ValidateConfig(cfg, zap.NewNop()) + return cfg, cfg.Validate() } diff --git a/config/testdata/missing-all-sections.yaml b/config/testdata/empty-all-sections.yaml similarity index 100% rename from config/testdata/missing-all-sections.yaml rename to config/testdata/empty-all-sections.yaml diff --git a/config/testdata/missing-exporter-name-after-slash.yaml b/config/testdata/invalid-exporter-name-after-slash.yaml similarity index 89% rename from config/testdata/missing-exporter-name-after-slash.yaml rename to config/testdata/invalid-exporter-name-after-slash.yaml index 6166c9950e0..b6a03029a3e 100644 --- a/config/testdata/missing-exporter-name-after-slash.yaml +++ b/config/testdata/invalid-exporter-name-after-slash.yaml @@ -1,6 +1,7 @@ receivers: examplereceiver: exporters: + exampleexporter: exampleexporter/: processors: exampleprocessor: diff --git a/config/testdata/missing-processor-type.yaml b/config/testdata/invalid-exporter-type.yaml similarity index 85% rename from config/testdata/missing-processor-type.yaml rename to config/testdata/invalid-exporter-type.yaml index d7e0036dd4e..9f497c228e6 100644 --- a/config/testdata/missing-processor-type.yaml +++ b/config/testdata/invalid-exporter-type.yaml @@ -2,8 +2,9 @@ receivers: examplereceiver: exporters: exampleexporter: + /custom: processors: - /exampleprocessor: + exampleprocessor: service: pipelines: traces: diff --git a/config/testdata/invalid-extension-name-after-slash.yaml b/config/testdata/invalid-extension-name-after-slash.yaml new file mode 100644 index 00000000000..7361f28073b --- /dev/null +++ b/config/testdata/invalid-extension-name-after-slash.yaml @@ -0,0 +1,14 @@ +extensions: + exampleextension/: +receivers: + examplereceiver: +exporters: + exampleexporter: +processors: + exampleprocessor: +service: + pipelines: + traces: + receivers: [examplereceiver] + processors: [exampleprocessor] + exporters: [exampleexporter] \ No newline at end of file diff --git a/config/testdata/invalid-extension-name.yaml b/config/testdata/invalid-extension-name.yaml deleted file mode 100644 index 8ed98292506..00000000000 --- a/config/testdata/invalid-extension-name.yaml +++ /dev/null @@ -1,15 +0,0 @@ -extensions: - exampleextension: -receivers: - examplereceiver: -processors: - exampleprocessor: -exporters: - exampleexporter: -service: - extensions: [exampleextension, nosuchextension, and, another, three] - pipelines: - traces: - receivers: [examplereceiver] - processors: [exampleprocessor] - exporters: [exampleexporter] diff --git a/config/testdata/pipeline-must-have-exporter-metrics.yaml b/config/testdata/invalid-extension-type.yaml similarity index 72% rename from config/testdata/pipeline-must-have-exporter-metrics.yaml rename to config/testdata/invalid-extension-type.yaml index a23eaa47d77..95bca7040e6 100644 --- a/config/testdata/pipeline-must-have-exporter-metrics.yaml +++ b/config/testdata/invalid-extension-type.yaml @@ -1,12 +1,14 @@ +extensions: + /custom: receivers: examplereceiver: exporters: exampleexporter: - extra: "not present in the service pipeline" processors: exampleprocessor: service: pipelines: - metrics: + traces: receivers: [examplereceiver] processors: [exampleprocessor] + exporters: [exampleexporter] \ No newline at end of file diff --git a/config/testdata/invalid-pipeline-type-and-name.yaml b/config/testdata/invalid-pipeline-name-after-slash.yaml similarity index 94% rename from config/testdata/invalid-pipeline-type-and-name.yaml rename to config/testdata/invalid-pipeline-name-after-slash.yaml index 889dd6b1b51..1f4718a2d94 100644 --- a/config/testdata/invalid-pipeline-type-and-name.yaml +++ b/config/testdata/invalid-pipeline-name-after-slash.yaml @@ -7,7 +7,7 @@ exporters: service: pipelines: - /metrics: + metrics/: receivers: [examplereceiver] processors: [exampleprocessor] exporters: [exampleexporter] diff --git a/config/testdata/invalid-pipeline-type.yaml b/config/testdata/invalid-pipeline-type.yaml index 7c88405a947..889dd6b1b51 100644 --- a/config/testdata/invalid-pipeline-type.yaml +++ b/config/testdata/invalid-pipeline-type.yaml @@ -7,7 +7,7 @@ exporters: service: pipelines: - wrongdatatype: + /metrics: receivers: [examplereceiver] processors: [exampleprocessor] exporters: [exampleexporter] diff --git a/config/testdata/invalid-processor-name-after-slash.yaml b/config/testdata/invalid-processor-name-after-slash.yaml new file mode 100644 index 00000000000..7b0fe077c32 --- /dev/null +++ b/config/testdata/invalid-processor-name-after-slash.yaml @@ -0,0 +1,13 @@ +receivers: + examplereceiver: +exporters: + exampleexporter: +processors: + exampleprocessor: + exampleprocessor/: +service: + pipelines: + traces: + receivers: [examplereceiver] + processors: [exampleprocessor] + exporters: [exampleexporter] diff --git a/config/testdata/invalid-receiver-name.yaml b/config/testdata/invalid-processor-type.yaml similarity index 81% rename from config/testdata/invalid-receiver-name.yaml rename to config/testdata/invalid-processor-type.yaml index 7e9eaa19afd..69d87aac4bb 100644 --- a/config/testdata/invalid-receiver-name.yaml +++ b/config/testdata/invalid-processor-type.yaml @@ -4,9 +4,10 @@ exporters: exampleexporter: processors: exampleprocessor: + /custom: service: pipelines: traces: - receivers: [nosuchreceiver] - exporters: [exampleexporter] + receivers: [examplereceiver] processors: [exampleprocessor] + exporters: [exampleexporter] diff --git a/config/testdata/pipeline-must-have-exporter-traces.yaml b/config/testdata/invalid-receiver-name-after-slash.yaml similarity index 78% rename from config/testdata/pipeline-must-have-exporter-traces.yaml rename to config/testdata/invalid-receiver-name-after-slash.yaml index ab85902340a..e2d74fd5e03 100644 --- a/config/testdata/pipeline-must-have-exporter-traces.yaml +++ b/config/testdata/invalid-receiver-name-after-slash.yaml @@ -1,8 +1,8 @@ receivers: examplereceiver: + examplereceiver/: exporters: exampleexporter: - extra: "not present in the service pipeline" processors: exampleprocessor: service: @@ -10,3 +10,4 @@ service: traces: receivers: [examplereceiver] processors: [exampleprocessor] + exporters: [exampleexporter] diff --git a/config/testdata/invalid-receiver-reference.yaml b/config/testdata/invalid-receiver-reference.yaml deleted file mode 100644 index 720b5d90d72..00000000000 --- a/config/testdata/invalid-receiver-reference.yaml +++ /dev/null @@ -1,10 +0,0 @@ -receivers: - examplereceiver: -exporters: - exampleexporter: -processors: - exampleprocessor: -service: - pipelines: - traces: - receivers: [invalidreceivername] diff --git a/config/testdata/pipeline-must-have-receiver-traces.yaml b/config/testdata/invalid-receiver-type.yaml similarity index 80% rename from config/testdata/pipeline-must-have-receiver-traces.yaml rename to config/testdata/invalid-receiver-type.yaml index 718f736398b..29ffaffac33 100644 --- a/config/testdata/pipeline-must-have-receiver-traces.yaml +++ b/config/testdata/invalid-receiver-type.yaml @@ -1,6 +1,6 @@ receivers: examplereceiver: - extra: "not present in the service pipeline" + /custom: exporters: exampleexporter: processors: @@ -8,5 +8,6 @@ processors: service: pipelines: traces: + receivers: [examplereceiver] processors: [exampleprocessor] exporters: [exampleexporter] diff --git a/config/testdata/invalid-service-extensions-value.yaml b/config/testdata/invalid-service-extensions-section.yaml similarity index 100% rename from config/testdata/invalid-service-extensions-value.yaml rename to config/testdata/invalid-service-extensions-section.yaml diff --git a/config/testdata/missing-exporters.yaml b/config/testdata/missing-exporters.yaml deleted file mode 100644 index a6d077a6bbe..00000000000 --- a/config/testdata/missing-exporters.yaml +++ /dev/null @@ -1,9 +0,0 @@ -receivers: - examplereceiver: -exporters: -processors: - exampleprocessor: -service: - pipelines: - traces: - receivers: [invalidreceivername] diff --git a/config/testdata/missing-extension-type.yaml b/config/testdata/missing-extension-type.yaml deleted file mode 100644 index 14eca199345..00000000000 --- a/config/testdata/missing-extension-type.yaml +++ /dev/null @@ -1,2 +0,0 @@ -extensions: - /exampleextension: diff --git a/config/testdata/missing-pipelines.yaml b/config/testdata/missing-pipelines.yaml deleted file mode 100644 index 38eb03535ed..00000000000 --- a/config/testdata/missing-pipelines.yaml +++ /dev/null @@ -1,8 +0,0 @@ -receivers: - examplereceiver: -exporters: - exampleexporter: -processors: - exampleprocessor: -service: - pipelines: diff --git a/config/testdata/missing-processors.yaml b/config/testdata/missing-processors.yaml deleted file mode 100644 index f1321d5883f..00000000000 --- a/config/testdata/missing-processors.yaml +++ /dev/null @@ -1,9 +0,0 @@ -receivers: - examplereceiver: -exporters: - exampleexporter: -processors: -service: - pipelines: - traces: - receivers: [invalidreceivername] diff --git a/config/testdata/missing-receiver-type.yaml b/config/testdata/missing-receiver-type.yaml deleted file mode 100644 index b05c26a28f7..00000000000 --- a/config/testdata/missing-receiver-type.yaml +++ /dev/null @@ -1,10 +0,0 @@ -receivers: - /myreceiver: -exporters: - exampleexporter: -processors: - exampleprocessor: -service: - pipelines: - traces: - receivers: [somereceiver] diff --git a/config/testdata/missing-receivers.yaml b/config/testdata/missing-receivers.yaml deleted file mode 100644 index 7a79d41a661..00000000000 --- a/config/testdata/missing-receivers.yaml +++ /dev/null @@ -1,8 +0,0 @@ -receivers: -exporters: - exampleexporter: -processors: - exampleprocessor: -service: - pipelines: - traces: diff --git a/config/testdata/pipeline-exporter-not-exists.yaml b/config/testdata/pipeline-exporter-not-exists.yaml deleted file mode 100644 index 4fd8383769c..00000000000 --- a/config/testdata/pipeline-exporter-not-exists.yaml +++ /dev/null @@ -1,11 +0,0 @@ -receivers: - examplereceiver: -exporters: - exampleexporter: -processors: - exampleprocessor: -service: - pipelines: - metrics: - receivers: [examplereceiver] - exporters: [nosuchexporter] diff --git a/config/testdata/pipeline-must-have-receiver-logs.yaml b/config/testdata/pipeline-must-have-receiver-logs.yaml deleted file mode 100644 index 0432954d938..00000000000 --- a/config/testdata/pipeline-must-have-receiver-logs.yaml +++ /dev/null @@ -1,12 +0,0 @@ -receivers: - examplereceiver: - extra: "not present in the service pipeline" -exporters: - exampleexporter: -processors: - exampleprocessor: -service: - pipelines: - logs: - processors: [exampleprocessor] - exporters: [exampleexporter] diff --git a/config/testdata/pipeline-must-have-receiver-metrics.yaml b/config/testdata/pipeline-must-have-receiver-metrics.yaml deleted file mode 100644 index 3d3000b1792..00000000000 --- a/config/testdata/pipeline-must-have-receiver-metrics.yaml +++ /dev/null @@ -1,12 +0,0 @@ -receivers: - examplereceiver: - extra: "not present in the service pipeline" -exporters: - exampleexporter: -processors: - exampleprocessor: -service: - pipelines: - metrics: - processors: [exampleprocessor] - exporters: [exampleexporter] diff --git a/config/testdata/pipeline-processor-not-exists.yaml b/config/testdata/pipeline-processor-not-exists.yaml deleted file mode 100644 index cb18a9db337..00000000000 --- a/config/testdata/pipeline-processor-not-exists.yaml +++ /dev/null @@ -1,15 +0,0 @@ -receivers: - examplereceiver: -exporters: - exampleexporter: -processors: - exampleprocessor: -service: - pipelines: - traces: - receivers: - - examplereceiver - processors: - - nosuchprocessor - exporters: - - exampleexporter diff --git a/config/testdata/pipeline-must-have-exporter-logs.yaml b/config/testdata/unknown-pipeline-type.yaml similarity index 75% rename from config/testdata/pipeline-must-have-exporter-logs.yaml rename to config/testdata/unknown-pipeline-type.yaml index 0ba7bfb98ab..7c88405a947 100644 --- a/config/testdata/pipeline-must-have-exporter-logs.yaml +++ b/config/testdata/unknown-pipeline-type.yaml @@ -1,12 +1,13 @@ receivers: examplereceiver: -exporters: - exampleexporter: - extra: "not present in the service pipeline" processors: exampleprocessor: +exporters: + exampleexporter: + service: pipelines: - logs: + wrongdatatype: receivers: [examplereceiver] processors: [exampleprocessor] + exporters: [exampleexporter] diff --git a/service/service.go b/service/service.go index cbe221e0152..8da5544ea7f 100644 --- a/service/service.go +++ b/service/service.go @@ -294,7 +294,7 @@ func (app *Application) setupConfigurationComponents(ctx context.Context, factor if err != nil { return fmt.Errorf("cannot load configuration: %w", err) } - err = config.ValidateConfig(cfg, app.logger) + err = cfg.Validate() if err != nil { return fmt.Errorf("cannot load configuration: %w", err) } diff --git a/service/service_test.go b/service/service_test.go index 003fc51b766..4c0958170b6 100644 --- a/service/service_test.go +++ b/service/service_test.go @@ -548,7 +548,7 @@ func TestSetFlag(t *testing.T) { cfg, err := FileLoaderConfigFactory(app.v, app.rootCmd, factories) require.NoError(t, err) assert.NotNil(t, cfg) - err = config.ValidateConfig(cfg, zap.NewNop()) + err = cfg.Validate() require.NoError(t, err) var processors []string @@ -578,7 +578,7 @@ func TestSetFlag(t *testing.T) { cfg, err := FileLoaderConfigFactory(app.v, app.rootCmd, factories) require.NoError(t, err) require.NotNil(t, cfg) - err = config.ValidateConfig(cfg, zap.NewNop()) + err = cfg.Validate() require.NoError(t, err) assert.Equal(t, 2, len(cfg.Processors)) @@ -643,7 +643,7 @@ service: v.ReadConfig(strings.NewReader(configStr)) cfg, err := config.Load(v, factories) assert.NoError(t, err) - err = config.ValidateConfig(cfg, zap.NewNop()) + err = cfg.Validate() assert.NoError(t, err) return cfg } diff --git a/testbed/testbed/otelcol_runner.go b/testbed/testbed/otelcol_runner.go index 489fff4bc4e..cd8c7795988 100644 --- a/testbed/testbed/otelcol_runner.go +++ b/testbed/testbed/otelcol_runner.go @@ -89,7 +89,7 @@ func (ipp *InProcessCollector) PrepareConfig(configStr string) (configCleanup fu if err != nil { return configCleanup, err } - err = config.ValidateConfig(cfg, zap.NewNop()) + err = cfg.Validate() if err != nil { return configCleanup, err }