From ee7be8bbf1b8b2820d28468cdaaff768a0579b08 Mon Sep 17 00:00:00 2001 From: Roger Coll Date: Wed, 28 Aug 2024 10:54:50 +0200 Subject: [PATCH] chore: remove config Validate call in docker (#34699) **Description:** Configuration validation is done during collector's startup, making it redundant when being called inside component's logic. This PR removes the Validate call done during Dockers's receiver start function. **Link to tracking Issue:** https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/33498 **Testing:** No testing needed to be modified as the `Validate` functionality is already covered. **Documentation:** --------- Co-authored-by: Sean Marciniak <30928402+MovieStoreGuy@users.noreply.github.com> --- extension/observer/dockerobserver/config.go | 32 ++++----------- .../observer/dockerobserver/config_test.go | 21 +++++----- .../observer/dockerobserver/extension.go | 15 ++++--- extension/observer/dockerobserver/factory.go | 9 +++-- internal/docker/config.go | 40 ++++++++++++------- internal/docker/go.mod | 9 ++++- internal/docker/go.sum | 26 +++++++++--- receiver/dockerstatsreceiver/config.go | 30 ++++---------- receiver/dockerstatsreceiver/config_test.go | 33 +++++++++------ receiver/dockerstatsreceiver/factory.go | 10 +++-- receiver/dockerstatsreceiver/receiver.go | 11 ++--- receiver/dockerstatsreceiver/receiver_test.go | 14 ++++--- 12 files changed, 134 insertions(+), 116 deletions(-) diff --git a/extension/observer/dockerobserver/config.go b/extension/observer/dockerobserver/config.go index 585dc4fcb4f1..cf7e1e61ee4c 100644 --- a/extension/observer/dockerobserver/config.go +++ b/extension/observer/dockerobserver/config.go @@ -4,7 +4,6 @@ package dockerobserver // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/dockerobserver" import ( - "errors" "fmt" "time" @@ -15,16 +14,7 @@ import ( // Config defines configuration for docker observer type Config struct { - - // The URL of the docker server. Default is "unix:///var/run/docker.sock" on non-Windows - // and "npipe:////./pipe/docker_engine" on Windows - Endpoint string `mapstructure:"endpoint"` - - // The maximum amount of time to wait for docker API responses. Default is 5s - Timeout time.Duration `mapstructure:"timeout"` - - // A list of filters whose matching images are to be excluded. Supports literals, globs, and regex. - ExcludedImages []string `mapstructure:"excluded_images"` + docker.Config `mapstructure:",squash"` // If true, the "Config.Hostname" field (if present) of the docker // container will be used as the discovered host that is used to configure @@ -47,15 +37,9 @@ type Config struct { // through the docker event listener example: cache_sync_interval: "20m" // Default: "60m" CacheSyncInterval time.Duration `mapstructure:"cache_sync_interval"` - - // Docker client API version. Default is 1.22 - DockerAPIVersion string `mapstructure:"api_version"` } func (config Config) Validate() error { - if config.Endpoint == "" { - return errors.New("endpoint must be specified") - } if err := docker.VersionIsValidAndGTE(config.DockerAPIVersion, minimumRequiredDockerAPIVersion); err != nil { return err } @@ -71,14 +55,12 @@ func (config Config) Validate() error { func (config *Config) Unmarshal(conf *confmap.Conf) error { err := conf.Unmarshal(config) if err != nil { - if floatAPIVersion, ok := conf.Get("api_version").(float64); ok { - return fmt.Errorf( - "%w.\n\nHint: You may want to wrap the 'api_version' value in quotes (api_version: \"%1.2f\")", - err, - floatAPIVersion, - ) - } return err } - return nil + + if len(config.ExcludedImages) == 0 { + config.ExcludedImages = nil + } + + return err } diff --git a/extension/observer/dockerobserver/config_test.go b/extension/observer/dockerobserver/config_test.go index cab7d3342ede..8f5efd273a8e 100644 --- a/extension/observer/dockerobserver/config_test.go +++ b/extension/observer/dockerobserver/config_test.go @@ -15,6 +15,7 @@ import ( "go.opentelemetry.io/collector/confmap/confmaptest" "github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/dockerobserver/internal/metadata" + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/docker" ) var version = "1.40" @@ -34,14 +35,16 @@ func TestLoadConfig(t *testing.T) { { id: component.NewIDWithName(metadata.Type, "all_settings"), expected: &Config{ - Endpoint: "unix:///var/run/docker.sock", + Config: docker.Config{ + Endpoint: "unix:///var/run/docker.sock", + Timeout: 20 * time.Second, + ExcludedImages: []string{"excluded", "image"}, + DockerAPIVersion: version, + }, CacheSyncInterval: 5 * time.Minute, - Timeout: 20 * time.Second, - ExcludedImages: []string{"excluded", "image"}, UseHostnameIfPresent: true, UseHostBindings: true, IgnoreNonHostBindings: true, - DockerAPIVersion: version, }, }, } @@ -59,19 +62,19 @@ func TestLoadConfig(t *testing.T) { } func TestValidateConfig(t *testing.T) { - cfg := &Config{} + cfg := &Config{Config: docker.Config{DockerAPIVersion: "1.24", Timeout: 5 * time.Second}, CacheSyncInterval: 5 * time.Second} assert.Equal(t, "endpoint must be specified", component.ValidateConfig(cfg).Error()) - cfg = &Config{Endpoint: "someEndpoint", DockerAPIVersion: "1.23"} + cfg = &Config{Config: docker.Config{Endpoint: "someEndpoint", DockerAPIVersion: "1.23"}} assert.Equal(t, `"api_version" 1.23 must be at least 1.24`, component.ValidateConfig(cfg).Error()) - cfg = &Config{Endpoint: "someEndpoint", DockerAPIVersion: version} + cfg = &Config{Config: docker.Config{Endpoint: "someEndpoint", DockerAPIVersion: version}} assert.Equal(t, "timeout must be specified", component.ValidateConfig(cfg).Error()) - cfg = &Config{Endpoint: "someEndpoint", DockerAPIVersion: version, Timeout: 5 * time.Minute} + cfg = &Config{Config: docker.Config{Endpoint: "someEndpoint", DockerAPIVersion: version, Timeout: 5 * time.Minute}} assert.Equal(t, "cache_sync_interval must be specified", component.ValidateConfig(cfg).Error()) - cfg = &Config{Endpoint: "someEndpoint", DockerAPIVersion: version, Timeout: 5 * time.Minute, CacheSyncInterval: 5 * time.Minute} + cfg = &Config{Config: docker.Config{Endpoint: "someEndpoint", DockerAPIVersion: version, Timeout: 5 * time.Minute}, CacheSyncInterval: 5 * time.Minute} assert.Nil(t, component.ValidateConfig(cfg)) } diff --git a/extension/observer/dockerobserver/extension.go b/extension/observer/dockerobserver/extension.go index 4d7932f2ddcf..3573c692ceda 100644 --- a/extension/observer/dockerobserver/extension.go +++ b/extension/observer/dockerobserver/extension.go @@ -26,9 +26,11 @@ var ( minimumRequiredDockerAPIVersion = docker.MustNewAPIVersion(defaultDockerAPIVersion) ) -var _ extension.Extension = (*dockerObserver)(nil) -var _ observer.EndpointsLister = (*dockerObserver)(nil) -var _ observer.Observable = (*dockerObserver)(nil) +var ( + _ extension.Extension = (*dockerObserver)(nil) + _ observer.EndpointsLister = (*dockerObserver)(nil) + _ observer.Observable = (*dockerObserver)(nil) +) type dockerObserver struct { *observer.EndpointsWatcher @@ -60,11 +62,9 @@ func (d *dockerObserver) Start(ctx context.Context, _ component.Host) error { d.ctx = dCtx // Create new Docker client - dConfig, err := docker.NewConfig(d.config.Endpoint, d.config.Timeout, d.config.ExcludedImages, d.config.DockerAPIVersion) - if err != nil { - return err - } + dConfig := docker.NewConfig(d.config.Endpoint, d.config.Timeout, d.config.ExcludedImages, d.config.DockerAPIVersion) + var err error d.dClient, err = docker.NewDockerClient(dConfig, d.logger) if err != nil { return fmt.Errorf("could not create docker client: %w", err) @@ -119,7 +119,6 @@ func (d *dockerObserver) ListEndpoints() []observer.Endpoint { // containerEndpoints generates a list of observer.Endpoint given a Docker ContainerJSON. // This function will only generate endpoints if a container is in the Running state and not Paused. func (d *dockerObserver) containerEndpoints(c *dtypes.ContainerJSON) []observer.Endpoint { - if !c.State.Running || c.State.Running && c.State.Paused { return nil } diff --git a/extension/observer/dockerobserver/factory.go b/extension/observer/dockerobserver/factory.go index 23a023ddd635..20939da92018 100644 --- a/extension/observer/dockerobserver/factory.go +++ b/extension/observer/dockerobserver/factory.go @@ -12,6 +12,7 @@ import ( "go.opentelemetry.io/collector/extension" "github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/dockerobserver/internal/metadata" + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/docker" ) // NewFactory should be called to create a factory with default values. @@ -26,10 +27,12 @@ func NewFactory() extension.Factory { func createDefaultConfig() component.Config { return &Config{ - Endpoint: client.DefaultDockerHost, - Timeout: 5 * time.Second, + Config: docker.Config{ + Endpoint: client.DefaultDockerHost, + Timeout: 5 * time.Second, + DockerAPIVersion: defaultDockerAPIVersion, + }, CacheSyncInterval: 60 * time.Minute, - DockerAPIVersion: defaultDockerAPIVersion, } } diff --git a/internal/docker/config.go b/internal/docker/config.go index ee78570dec9f..8a775ee3e1cc 100644 --- a/internal/docker/config.go +++ b/internal/docker/config.go @@ -12,6 +12,7 @@ import ( "github.com/docker/docker/api/types/versions" "github.com/docker/docker/client" + "go.opentelemetry.io/collector/confmap" ) type Config struct { @@ -29,16 +30,39 @@ type Config struct { DockerAPIVersion string `mapstructure:"api_version"` } +func (config *Config) Unmarshal(conf *confmap.Conf) error { + // WithIgonreUnused needed because this configuration is embedded inside other configurations + err := conf.Unmarshal(config, confmap.WithIgnoreUnused()) + if err != nil { + if floatAPIVersion, ok := conf.Get("api_version").(float64); ok { + return fmt.Errorf( + "%w.\n\nHint: You may want to wrap the 'api_version' value in quotes (api_version: \"%1.2f\")", + err, + floatAPIVersion, + ) + } + return err + } + return nil +} + +func (config Config) Validate() error { + if config.Endpoint == "" { + return errors.New("endpoint must be specified") + } + return nil +} + // NewConfig creates a new config to be used when creating // a docker client -func NewConfig(endpoint string, timeout time.Duration, excludedImages []string, apiVersion string) (*Config, error) { +func NewConfig(endpoint string, timeout time.Duration, excludedImages []string, apiVersion string) *Config { cfg := &Config{ Endpoint: endpoint, Timeout: timeout, ExcludedImages: excludedImages, DockerAPIVersion: apiVersion, } - return cfg, cfg.validate() + return cfg } // NewDefaultConfig creates a new config with default values @@ -53,18 +77,6 @@ func NewDefaultConfig() *Config { return cfg } -// validate asserts that an endpoint field is set -// on the config struct -func (config Config) validate() error { - if config.Endpoint == "" { - return errors.New("config.Endpoint must be specified") - } - if err := VersionIsValidAndGTE(config.DockerAPIVersion, minimumRequiredDockerAPIVersion); err != nil { - return err - } - return nil -} - type apiVersion struct { major int minor int diff --git a/internal/docker/go.mod b/internal/docker/go.mod index ccc0a7cdd48e..a75978af579b 100644 --- a/internal/docker/go.mod +++ b/internal/docker/go.mod @@ -7,6 +7,7 @@ require ( github.com/docker/docker v26.1.5+incompatible github.com/gobwas/glob v0.2.3 github.com/stretchr/testify v1.9.0 + go.opentelemetry.io/collector/confmap v1.14.1 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.0 ) @@ -20,8 +21,13 @@ require ( github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/kr/pretty v0.2.1 // indirect + github.com/knadh/koanf/maps v0.1.1 // indirect + github.com/knadh/koanf/providers/confmap v0.1.0 // indirect + github.com/knadh/koanf/v2 v2.1.1 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect github.com/morikuni/aec v1.0.0 // indirect @@ -39,7 +45,6 @@ require ( golang.org/x/net v0.23.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/time v0.4.0 // indirect - gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.0.3 // indirect ) diff --git a/internal/docker/go.sum b/internal/docker/go.sum index 7304bbb646a8..7fe5053828d2 100644 --- a/internal/docker/go.sum +++ b/internal/docker/go.sum @@ -24,6 +24,8 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w= +github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -38,12 +40,20 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= +github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= +github.com/knadh/koanf/providers/confmap v0.1.0 h1:gOkxhHkemwG4LezxxN8DMOFopOPghxRVp7JbIvdvqzU= +github.com/knadh/koanf/providers/confmap v0.1.0/go.mod h1:2uLhxQzJnyHKfxG927awZC7+fyHFdQkd697K4MdLnIU= +github.com/knadh/koanf/v2 v2.1.1 h1:/R8eXqasSTsmDCsAyYj+81Wteg8AqrV9CP6gvsTsOmM= +github.com/knadh/koanf/v2 v2.1.1/go.mod h1:4mnTRbZCK+ALuBXHZMjDfG9y714L7TykVnZkXbMU3Es= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= @@ -59,6 +69,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -66,6 +78,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/collector/confmap v1.14.1 h1:GPMa+q5ThiBFQaYKJ7xeomiw9tIokkTA1AiF1zwKJck= +go.opentelemetry.io/collector/confmap v1.14.1/go.mod h1:GrIZ12P/9DPOuTpe2PIS51a0P/ZM6iKtByVee1Uf3+k= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= @@ -133,8 +147,8 @@ google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFL google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= diff --git a/receiver/dockerstatsreceiver/config.go b/receiver/dockerstatsreceiver/config.go index 96085e513a9f..750560dbcf98 100644 --- a/receiver/dockerstatsreceiver/config.go +++ b/receiver/dockerstatsreceiver/config.go @@ -4,9 +4,6 @@ package dockerstatsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/dockerstatsreceiver" import ( - "errors" - "fmt" - "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/receiver/scraperhelper" @@ -18,9 +15,9 @@ import ( var _ component.Config = (*Config)(nil) type Config struct { + docker.Config `mapstructure:",squash"` + scraperhelper.ControllerConfig `mapstructure:",squash"` - // The URL of the docker server. Default is "unix:///var/run/docker.sock" - Endpoint string `mapstructure:"endpoint"` // A mapping of container label names to MetricDescriptor label keys. // The corresponding container label value will become the DataPoint label value @@ -37,20 +34,11 @@ type Config struct { // present. EnvVarsToMetricLabels map[string]string `mapstructure:"env_vars_to_metric_labels"` - // A list of filters whose matching images are to be excluded. Supports literals, globs, and regex. - ExcludedImages []string `mapstructure:"excluded_images"` - - // Docker client API version. Default is 1.22 - DockerAPIVersion string `mapstructure:"api_version"` - // MetricsBuilderConfig config. Enable or disable stats by name. metadata.MetricsBuilderConfig `mapstructure:",squash"` } func (config Config) Validate() error { - if config.Endpoint == "" { - return errors.New("endpoint must be specified") - } if err := docker.VersionIsValidAndGTE(config.DockerAPIVersion, minimumRequiredDockerAPIVersion); err != nil { return err } @@ -60,14 +48,12 @@ func (config Config) Validate() error { func (config *Config) Unmarshal(conf *confmap.Conf) error { err := conf.Unmarshal(config) if err != nil { - if floatAPIVersion, ok := conf.Get("api_version").(float64); ok { - return fmt.Errorf( - "%w.\n\nHint: You may want to wrap the 'api_version' value in quotes (api_version: \"%1.2f\")", - err, - floatAPIVersion, - ) - } return err } - return nil + + if len(config.ExcludedImages) == 0 { + config.ExcludedImages = nil + } + + return err } diff --git a/receiver/dockerstatsreceiver/config_test.go b/receiver/dockerstatsreceiver/config_test.go index 4ce59bfea1b7..c9008dcb61bc 100644 --- a/receiver/dockerstatsreceiver/config_test.go +++ b/receiver/dockerstatsreceiver/config_test.go @@ -17,6 +17,7 @@ import ( "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/receiver/scraperhelper" + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/docker" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/dockerstatsreceiver/internal/metadata" ) @@ -47,13 +48,15 @@ func TestLoadConfig(t *testing.T) { InitialDelay: time.Second, Timeout: 20 * time.Second, }, - - Endpoint: "http://example.com/", - DockerAPIVersion: "1.40", - - ExcludedImages: []string{ - "undesired-container", - "another-*-container", + Config: docker.Config{ + Endpoint: "http://example.com/", + DockerAPIVersion: "1.40", + + Timeout: 20 * time.Second, + ExcludedImages: []string{ + "undesired-container", + "another-*-container", + }, }, ContainerLabelsToMetricLabels: map[string]string{ @@ -95,19 +98,25 @@ func TestLoadConfig(t *testing.T) { } func TestValidateErrors(t *testing.T) { - cfg := &Config{ControllerConfig: scraperhelper.NewDefaultControllerConfig()} + cfg := &Config{ControllerConfig: scraperhelper.NewDefaultControllerConfig(), Config: docker.Config{ + DockerAPIVersion: "1.25", + }} assert.Equal(t, "endpoint must be specified", component.ValidateConfig(cfg).Error()) cfg = &Config{ - DockerAPIVersion: "1.21", - Endpoint: "someEndpoint", + Config: docker.Config{ + DockerAPIVersion: "1.21", + Endpoint: "someEndpoint", + }, ControllerConfig: scraperhelper.ControllerConfig{CollectionInterval: 1 * time.Second}, } assert.Equal(t, `"api_version" 1.21 must be at least 1.25`, component.ValidateConfig(cfg).Error()) cfg = &Config{ - Endpoint: "someEndpoint", - DockerAPIVersion: "1.25", + Config: docker.Config{ + Endpoint: "someEndpoint", + DockerAPIVersion: "1.25", + }, ControllerConfig: scraperhelper.ControllerConfig{}, } assert.Equal(t, `"collection_interval": requires positive value`, component.ValidateConfig(cfg).Error()) diff --git a/receiver/dockerstatsreceiver/factory.go b/receiver/dockerstatsreceiver/factory.go index 45b85b4397d7..1fec135b3e14 100644 --- a/receiver/dockerstatsreceiver/factory.go +++ b/receiver/dockerstatsreceiver/factory.go @@ -12,6 +12,7 @@ import ( "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/scraperhelper" + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/docker" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/dockerstatsreceiver/internal/metadata" ) @@ -27,9 +28,12 @@ func createDefaultConfig() component.Config { scs.CollectionInterval = 10 * time.Second scs.Timeout = 5 * time.Second return &Config{ - ControllerConfig: scs, - Endpoint: "unix:///var/run/docker.sock", - DockerAPIVersion: defaultDockerAPIVersion, + ControllerConfig: scs, + Config: docker.Config{ + Endpoint: "unix:///var/run/docker.sock", + DockerAPIVersion: defaultDockerAPIVersion, + Timeout: scs.Timeout, + }, MetricsBuilderConfig: metadata.DefaultMetricsBuilderConfig(), } } diff --git a/receiver/dockerstatsreceiver/receiver.go b/receiver/dockerstatsreceiver/receiver.go index a667d30e2b81..f7e3fb5ea986 100644 --- a/receiver/dockerstatsreceiver/receiver.go +++ b/receiver/dockerstatsreceiver/receiver.go @@ -52,12 +52,8 @@ func newMetricsReceiver(set receiver.Settings, config *Config) *metricsReceiver } func (r *metricsReceiver) start(ctx context.Context, _ component.Host) error { - dConfig, err := docker.NewConfig(r.config.Endpoint, r.config.Timeout, r.config.ExcludedImages, r.config.DockerAPIVersion) - if err != nil { - return err - } - - r.client, err = docker.NewDockerClient(dConfig, r.settings.Logger) + var err error + r.client, err = docker.NewDockerClient(&r.config.Config, r.settings.Logger) if err != nil { return err } @@ -98,7 +94,8 @@ func (r *metricsReceiver) scrapeV2(ctx context.Context) (pmetric.Metrics, error) results <- resultV2{ stats: statsJSON, container: &c, - err: nil} + err: nil, + } }(container) } diff --git a/receiver/dockerstatsreceiver/receiver_test.go b/receiver/dockerstatsreceiver/receiver_test.go index 7acda97556c2..099267467c5c 100644 --- a/receiver/dockerstatsreceiver/receiver_test.go +++ b/receiver/dockerstatsreceiver/receiver_test.go @@ -24,6 +24,7 @@ import ( "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/receiver/scraperhelper" + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/docker" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/pmetrictest" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/dockerstatsreceiver/internal/metadata" @@ -124,8 +125,10 @@ func TestNewReceiver(t *testing.T) { ControllerConfig: scraperhelper.ControllerConfig{ CollectionInterval: 1 * time.Second, }, - Endpoint: "unix:///run/some.sock", - DockerAPIVersion: defaultDockerAPIVersion, + Config: docker.Config{ + Endpoint: "unix:///run/some.sock", + DockerAPIVersion: defaultDockerAPIVersion, + }, } mr := newMetricsReceiver(receivertest.NewNopSettings(), cfg) assert.NotNil(t, mr) @@ -137,8 +140,10 @@ func TestErrorsInStart(t *testing.T) { ControllerConfig: scraperhelper.ControllerConfig{ CollectionInterval: 1 * time.Second, }, - Endpoint: unreachable, - DockerAPIVersion: defaultDockerAPIVersion, + Config: docker.Config{ + Endpoint: unreachable, + DockerAPIVersion: defaultDockerAPIVersion, + }, } recv := newMetricsReceiver(receivertest.NewNopSettings(), cfg) assert.NotNil(t, recv) @@ -155,7 +160,6 @@ func TestErrorsInStart(t *testing.T) { } func TestScrapeV2(t *testing.T) { - testCases := []struct { desc string expectedMetricsFile string