Skip to content

Commit

Permalink
Target Allocator Module for Prometheus Receiver (#240)
Browse files Browse the repository at this point in the history
* Split target allocator into an internal package (open-telemetry#33223)

Fixes
open-telemetry#33146

* basic working copy

* Added k8 test back

---------

Co-authored-by: David Ashpole <[email protected]>
  • Loading branch information
okankoAMZ and dashpole authored Oct 14, 2024
1 parent 9ae2897 commit a6dbc1d
Show file tree
Hide file tree
Showing 15 changed files with 1,003 additions and 357 deletions.
27 changes: 27 additions & 0 deletions .chloggen/refactor-target-allocator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: breaking

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: prometheusreceiver

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Move the TargetAllocator configuration struct to an internal directory

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [33146]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: [api]
66 changes: 3 additions & 63 deletions receiver/prometheusreceiver/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,17 @@ package prometheusreceiver // import "github.com/open-telemetry/opentelemetry-co
import (
"errors"
"fmt"
"net/url"
"os"
"sort"
"strings"
"time"

commonconfig "github.com/prometheus/common/config"
promconfig "github.com/prometheus/prometheus/config"
promHTTP "github.com/prometheus/prometheus/discovery/http"
"github.com/prometheus/prometheus/discovery/kubernetes"
"go.opentelemetry.io/collector/config/confighttp"
"go.opentelemetry.io/collector/confmap"
"gopkg.in/yaml.v2"

"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver/targetallocator"
)

// Config defines configuration for Prometheus receiver.
Expand All @@ -37,7 +35,7 @@ type Config struct {
// ReportExtraScrapeMetrics - enables reporting of additional metrics for Prometheus client like scrape_body_size_bytes
ReportExtraScrapeMetrics bool `mapstructure:"report_extra_scrape_metrics"`

TargetAllocator *TargetAllocator `mapstructure:"target_allocator"`
TargetAllocator *targetallocator.Config `mapstructure:"target_allocator"`
}

// Validate checks the receiver configuration is valid.
Expand All @@ -48,27 +46,6 @@ func (cfg *Config) Validate() error {
return nil
}

type TargetAllocator struct {
confighttp.ClientConfig `mapstructure:",squash"`
Interval time.Duration `mapstructure:"interval"`
CollectorID string `mapstructure:"collector_id"`
HTTPSDConfig *PromHTTPSDConfig `mapstructure:"http_sd_config"`
HTTPScrapeConfig *PromHTTPClientConfig `mapstructure:"http_scrape_config"`
}

func (cfg *TargetAllocator) Validate() error {
// ensure valid endpoint
if _, err := url.ParseRequestURI(cfg.Endpoint); err != nil {
return fmt.Errorf("TargetAllocator endpoint is not valid: %s", cfg.Endpoint)
}
// ensure valid collectorID without variables
if cfg.CollectorID == "" || strings.Contains(cfg.CollectorID, "${") {
return fmt.Errorf("CollectorID is not a valid ID")
}

return nil
}

// PromConfig is a redeclaration of promconfig.Config because we need custom unmarshaling
// as prometheus "config" uses `yaml` tags.
type PromConfig promconfig.Config
Expand Down Expand Up @@ -126,43 +103,6 @@ func (cfg *PromConfig) Validate() error {
return nil
}

// PromHTTPSDConfig is a redeclaration of promHTTP.SDConfig because we need custom unmarshaling
// as prometheus "config" uses `yaml` tags.
type PromHTTPSDConfig promHTTP.SDConfig

var _ confmap.Unmarshaler = (*PromHTTPSDConfig)(nil)

func (cfg *PromHTTPSDConfig) Unmarshal(componentParser *confmap.Conf) error {
cfgMap := componentParser.ToStringMap()
if len(cfgMap) == 0 {
return nil
}
cfgMap["url"] = "http://placeholder" // we have to set it as else marshaling will fail
return unmarshalYAML(cfgMap, (*promHTTP.SDConfig)(cfg))
}

type PromHTTPClientConfig commonconfig.HTTPClientConfig

var _ confmap.Unmarshaler = (*PromHTTPClientConfig)(nil)

func (cfg *PromHTTPClientConfig) Unmarshal(componentParser *confmap.Conf) error {
cfgMap := componentParser.ToStringMap()
if len(cfgMap) == 0 {
return nil
}
return unmarshalYAML(cfgMap, (*commonconfig.HTTPClientConfig)(cfg))
}

func (cfg *PromHTTPClientConfig) Validate() error {
httpCfg := (*commonconfig.HTTPClientConfig)(cfg)
if err := validateHTTPClientConfig(httpCfg); err != nil {
return err
}
// Prometheus UnmarshalYaml implementation by default calls Validate,
// but it is safer to do it here as well.
return httpCfg.Validate()
}

func unmarshalYAML(in map[string]any, out any) error {
yamlOut, err := yaml.Marshal(in)
if err != nil {
Expand Down
62 changes: 31 additions & 31 deletions receiver/prometheusreceiver/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package prometheusreceiver

import (
"context"
"os"
"path/filepath"
"strings"
"testing"
Expand All @@ -23,6 +24,20 @@ import (
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver/internal/metadata"
)

func setup() {
err := os.Setenv("POD_NAME", "collector-1")
if err != nil {

os.Exit(1)
}
}
func teardown() {
err := os.Unsetenv("POD_NAME")
if err != nil {
os.Exit(1)
}
}

func TestLoadConfig(t *testing.T) {
cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml"))
require.NoError(t, err)
Expand Down Expand Up @@ -104,6 +119,22 @@ func TestLoadTargetAllocatorConfig(t *testing.T) {
assert.Equal(t, 1, len(r2.PrometheusConfig.ScrapeConfigs))
assert.Equal(t, "demo", r2.PrometheusConfig.ScrapeConfigs[0].JobName)
assert.Equal(t, promModel.Duration(5*time.Second), r2.PrometheusConfig.ScrapeConfigs[0].ScrapeInterval)

sub, err = cm.Sub(component.NewIDWithName(metadata.Type, "k8Setup").String())
require.NoError(t, err)

os.Setenv("POD_NAME", "collector-1")
cfg = factory.CreateDefaultConfig()
require.NoError(t, sub.Unmarshal(cfg))
require.NoError(t, component.ValidateConfig(cfg))

r3 := cfg.(*Config)
assert.Equal(t, "https://target-allocator-service:80", r3.TargetAllocator.Endpoint)
assert.Equal(t, 30*time.Second, r3.TargetAllocator.Interval)
assert.Equal(t, "collector-1", r3.TargetAllocator.CollectorID)
assert.Equal(t, promModel.Duration(15*time.Second), r3.PrometheusConfig.GlobalConfig.ScrapeInterval)
assert.Equal(t, promModel.Duration(10*time.Second), r3.PrometheusConfig.GlobalConfig.ScrapeTimeout)

}

func TestLoadConfigFailsOnUnknownSection(t *testing.T) {
Expand Down Expand Up @@ -341,34 +372,3 @@ func TestFileSDConfigWithoutSDFile(t *testing.T) {

require.NoError(t, component.ValidateConfig(cfg))
}

func TestPromHTTPClientConfigValidateAuthorization(t *testing.T) {
cfg := PromHTTPClientConfig{}
require.NoError(t, component.ValidateConfig(cfg))
cfg.Authorization = &promConfig.Authorization{}
require.NoError(t, component.ValidateConfig(cfg))
cfg.Authorization.CredentialsFile = "none"
require.Error(t, component.ValidateConfig(cfg))
cfg.Authorization.CredentialsFile = filepath.Join("testdata", "dummy-tls-cert-file")
require.NoError(t, component.ValidateConfig(cfg))
}

func TestPromHTTPClientConfigValidateTLSConfig(t *testing.T) {
cfg := PromHTTPClientConfig{}
require.NoError(t, component.ValidateConfig(cfg))
cfg.TLSConfig.CertFile = "none"
require.Error(t, component.ValidateConfig(cfg))
cfg.TLSConfig.CertFile = filepath.Join("testdata", "dummy-tls-cert-file")
cfg.TLSConfig.KeyFile = "none"
require.Error(t, component.ValidateConfig(cfg))
cfg.TLSConfig.KeyFile = filepath.Join("testdata", "dummy-tls-key-file")
require.NoError(t, component.ValidateConfig(cfg))
}

func TestPromHTTPClientConfigValidateMain(t *testing.T) {
cfg := PromHTTPClientConfig{}
require.NoError(t, component.ValidateConfig(cfg))
cfg.BearerToken = "foo"
cfg.BearerTokenFile = filepath.Join("testdata", "dummy-tls-key-file")
require.Error(t, component.ValidateConfig(cfg))
}
4 changes: 2 additions & 2 deletions receiver/prometheusreceiver/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ require (
github.com/stretchr/testify v1.9.0
go.opentelemetry.io/collector/component v0.103.0
go.opentelemetry.io/collector/config/confighttp v0.103.0
go.opentelemetry.io/collector/config/configopaque v1.10.0
go.opentelemetry.io/collector/config/configtls v0.103.0
go.opentelemetry.io/collector/confmap v0.103.0
go.opentelemetry.io/collector/confmap/provider/fileprovider v0.103.0
go.opentelemetry.io/collector/consumer v0.103.0
Expand Down Expand Up @@ -164,10 +166,8 @@ require (
go.opentelemetry.io/collector v0.103.0 // indirect
go.opentelemetry.io/collector/config/configauth v0.103.0 // indirect
go.opentelemetry.io/collector/config/configcompression v1.10.0 // indirect
go.opentelemetry.io/collector/config/configopaque v1.10.0 // indirect
go.opentelemetry.io/collector/config/configretry v0.103.0 // indirect
go.opentelemetry.io/collector/config/configtelemetry v0.103.0 // indirect
go.opentelemetry.io/collector/config/configtls v0.103.0 // indirect
go.opentelemetry.io/collector/config/internal v0.103.0 // indirect
go.opentelemetry.io/collector/confmap/converter/expandconverter v0.103.0 // indirect
go.opentelemetry.io/collector/confmap/provider/envprovider v0.103.0 // indirect
Expand Down
Loading

0 comments on commit a6dbc1d

Please sign in to comment.