diff --git a/internal/agentcfg/fetch.go b/internal/agentcfg/fetch.go index f4792d16e96..a803184fdb0 100644 --- a/internal/agentcfg/fetch.go +++ b/internal/agentcfg/fetch.go @@ -17,38 +17,46 @@ package agentcfg -import ( - "context" - - "github.com/elastic/apm-server/internal/beater/config" -) - -// TransactionSamplingRateKey is the agent configuration key for the -// sampling rate. This is used by the Jaeger handler to adapt our agent -// configuration to the Jaeger remote sampler protocol. -const TransactionSamplingRateKey = "transaction_sample_rate" +import "context" // Fetcher defines a common interface to retrieving agent config. type Fetcher interface { Fetch(context.Context, Query) (Result, error) } -// DirectFetcher is an agent config fetcher which serves requests out of a -// statically defined set of agent configuration. These configurations are -// typically provided via Fleet. -type DirectFetcher struct { - cfgs []AgentConfig +// AgentConfig holds an agent configuration definition. +type AgentConfig struct { + // ServiceName holds the service name to which this agent configuration + // applies. This is optional. + ServiceName string + + // ServiceEnvironment holds the service environment to which this agent + // configuration applies. This is optional. + ServiceEnvironment string + + // AgentName holds the agent name to which this agent configuration + // applies. This is optional, and is used for filtering configuration + // settings for unauthenticated agents. + AgentName string + + // Etag holds a unique ID for the configuration, which agents + // will send along with their queries. The server uses this to + // determine whether agent configuration has been applied. + Etag string + + // Config holds configuration settings that should be sent to + // agents matching the above constraints. + Config map[string]string } -// NewDirectFetcher returns a new DirectFetcher that serves agent configuration -// requests using cfgs. -func NewDirectFetcher(cfgs []AgentConfig) *DirectFetcher { - return &DirectFetcher{cfgs} +func NewEmptyFetcher() Fetcher { + return &emptyFetcher{} } -// Fetch finds a matching AgentConfig in cfgs based on the received Query. -func (f *DirectFetcher) Fetch(_ context.Context, query Query) (Result, error) { - return matchAgentConfig(query, f.cfgs), nil +type emptyFetcher struct{} + +func (*emptyFetcher) Fetch(context.Context, Query) (Result, error) { + return zeroResult(), nil } // matchAgentConfig finds a matching AgentConfig based on the received Query. @@ -97,42 +105,3 @@ func matchAgentConfig(query Query, cfgs []AgentConfig) Result { } return result } - -// AgentConfig holds an agent configuration definition. -type AgentConfig struct { - // ServiceName holds the service name to which this agent configuration - // applies. This is optional. - ServiceName string - - // ServiceEnvironment holds the service environment to which this agent - // configuration applies. This is optional. - ServiceEnvironment string - - // AgentName holds the agent name to which this agent configuration - // applies. This is optional, and is used for filtering configuration - // settings for unauthenticated agents. - AgentName string - - // Etag holds a unique ID for the configuration, which agents - // will send along with their queries. The server uses this to - // determine whether agent configuration has been applied. - Etag string - - // Config holds configuration settings that should be sent to - // agents matching the above constraints. - Config map[string]string -} - -func ConvertAgentConfigs(fleetAgentConfigs []config.FleetAgentConfig) []AgentConfig { - agentConfigurations := make([]AgentConfig, len(fleetAgentConfigs)) - for i, in := range fleetAgentConfigs { - agentConfigurations[i] = AgentConfig{ - ServiceName: in.Service.Name, - ServiceEnvironment: in.Service.Environment, - AgentName: in.AgentName, - Etag: in.Etag, - Config: in.Config, - } - } - return agentConfigurations -} diff --git a/internal/agentcfg/fetch_test.go b/internal/agentcfg/fetch_test.go index 6c124572fc8..83e311f981f 100644 --- a/internal/agentcfg/fetch_test.go +++ b/internal/agentcfg/fetch_test.go @@ -18,12 +18,10 @@ package agentcfg import ( - "context" "testing" "time" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) var ( @@ -38,214 +36,3 @@ func TestCustomJSON(t *testing.T) { actual, _ := newResult([]byte(input), nil) assert.Equal(t, expected, actual) } - -func TestDirectConfigurationPrecedence(t *testing.T) { - for _, tc := range []struct { - query Query - agentConfigs []AgentConfig - expectedSettings map[string]string - }{ - { - query: Query{ - Service: Service{ - Name: "service1", - Environment: "production", - }, - }, - agentConfigs: []AgentConfig{ - { - ServiceEnvironment: "production", - Config: map[string]string{"key1": "val2", "key2": "val2"}, - Etag: "def456", - }, - { - ServiceName: "service1", - Config: map[string]string{"key3": "val3"}, - Etag: "abc123", - }, - { - ServiceName: "service1", - ServiceEnvironment: "production", - Config: map[string]string{"key1": "val1"}, - Etag: "abc123", - }, - }, - expectedSettings: map[string]string{ - "key1": "val1", - }, - }, - { - query: Query{ - Service: Service{ - Name: "service1", - Environment: "production", - }, - }, - agentConfigs: []AgentConfig{ - { - ServiceEnvironment: "production", - Config: map[string]string{"key3": "val3"}, - Etag: "def456", - }, - { - ServiceName: "service1", - Config: map[string]string{"key1": "val1", "key2": "val2"}, - Etag: "abc123", - }, - }, - expectedSettings: map[string]string{ - "key1": "val1", - "key2": "val2", - }, - }, - { - query: Query{ - InsecureAgents: []string{"Jaeger"}, - Service: Service{ - Name: "service1", - Environment: "production", - }, - }, - agentConfigs: []AgentConfig{ - { - ServiceEnvironment: "production", - Config: map[string]string{"key3": "val3"}, - Etag: "def456", - }, - { - ServiceName: "service1", - Config: map[string]string{"key1": "val1", "key2": "val2"}, - Etag: "abc123", - }, - }, - expectedSettings: map[string]string{ - "key1": "val1", - "key2": "val2", - }, - }, - { - query: Query{ - InsecureAgents: []string{"Jaeger"}, - Service: Service{ - Name: "service1", - Environment: "production", - }, - }, - agentConfigs: []AgentConfig{ - { - ServiceEnvironment: "production", - Config: map[string]string{"key3": "val3"}, - Etag: "def456", - }, - { - ServiceName: "service1", - AgentName: "Jaeger/Python", - Config: map[string]string{"key1": "val1", "key2": "val2", "transaction_sample_rate": "0.1"}, - Etag: "abc123", - }, - }, - expectedSettings: map[string]string{ - "key1": "val1", - "key2": "val2", - "transaction_sample_rate": "0.1", - }, - }, - { - query: Query{ - Service: Service{ - Name: "service1", - Environment: "production", - }, - }, - agentConfigs: []AgentConfig{ - { - ServiceName: "service2", - Config: map[string]string{"key1": "val1", "key2": "val2"}, - Etag: "abc123", - }, - { - ServiceEnvironment: "production", - Config: map[string]string{"key3": "val3"}, - Etag: "def456", - }, - }, - expectedSettings: map[string]string{ - "key3": "val3", - }, - }, - { - query: Query{ - Service: Service{ - Name: "service1", - Environment: "production", - }, - }, - agentConfigs: []AgentConfig{ - { - ServiceName: "not-found", - Config: map[string]string{"key1": "val1"}, - Etag: "abc123", - }, - }, - expectedSettings: map[string]string{}, - }, - { - query: Query{ - Service: Service{ - Name: "service2", - Environment: "production", - }, - }, - agentConfigs: []AgentConfig{ - { - ServiceName: "service1", - Config: map[string]string{"key1": "val1", "key2": "val2"}, - Etag: "abc123", - }, - { - ServiceName: "service2", - Config: map[string]string{"key1": "val4", "key2": "val5"}, - Etag: "abc123", - }, - }, - expectedSettings: map[string]string{ - "key1": "val4", - "key2": "val5", - }, - }, - { - query: Query{ - Service: Service{ - Name: "service2", - Environment: "staging", - }, - }, - agentConfigs: []AgentConfig{ - { - ServiceName: "service1", - Config: map[string]string{"key1": "val1", "key2": "val2"}, - Etag: "abc123", - }, - { - ServiceEnvironment: "production", - Config: map[string]string{"key1": "val4", "key2": "val5"}, - Etag: "abc123", - }, - { - Config: map[string]string{"key3": "val5", "key4": "val6"}, - Etag: "abc123", - }, - }, - expectedSettings: map[string]string{ - "key3": "val5", - "key4": "val6", - }, - }, - } { - f := NewDirectFetcher(tc.agentConfigs) - result, err := f.Fetch(context.Background(), tc.query) - require.NoError(t, err) - - assert.Equal(t, Settings(tc.expectedSettings), result.Source.Settings) - } -} diff --git a/internal/beater/api/config/agent/handler_test.go b/internal/beater/api/config/agent/handler_test.go index 8450bfebb64..c95417d73e3 100644 --- a/internal/beater/api/config/agent/handler_test.go +++ b/internal/beater/api/config/agent/handler_test.go @@ -231,23 +231,6 @@ func TestAgentConfigHandlerAuthorizedForService(t *testing.T) { assert.False(t, called) } -func TestConfigAgentHandler_DirectConfiguration(t *testing.T) { - fetcher := agentcfg.NewDirectFetcher([]agentcfg.AgentConfig{{ - ServiceName: "service1", - Config: map[string]string{"key1": "val1"}, - Etag: "abc123", - }}) - h := NewHandler(fetcher, time.Nanosecond, "", nil) - - w := sendRequest(h, httptest.NewRequest(http.MethodPost, "/config", jsonReader(map[string]interface{}{ - "service": map[string]interface{}{ - "name": "service1", - }, - }))) - assert.Equal(t, http.StatusOK, w.Code, w.Body.String()) - assert.JSONEq(t, `{"key1":"val1"}`, w.Body.String()) -} - func TestAgentConfigHandler_PostOk(t *testing.T) { f := newSanitizingKibanaFetcher(t, func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, `{"_id": "1", "_source": {"settings": {"sampling_rate": 0.5}}}`) diff --git a/internal/beater/api/mux_test.go b/internal/beater/api/mux_test.go index ce0ca1d8f90..4f1996912c7 100644 --- a/internal/beater/api/mux_test.go +++ b/internal/beater/api/mux_test.go @@ -163,7 +163,7 @@ func (m muxBuilder) build(cfg *config.Config) (http.Handler, error) { cfg, nopBatchProcessor, authenticator, - agentcfg.NewDirectFetcher(nil), + agentcfg.NewEmptyFetcher(), ratelimitStore, m.SourcemapFetcher, func() bool { return true }, diff --git a/internal/beater/config/agentconfig.go b/internal/beater/config/agentconfig.go index 55f22ed2c1d..dad7f59cd06 100644 --- a/internal/beater/config/agentconfig.go +++ b/internal/beater/config/agentconfig.go @@ -18,9 +18,6 @@ package config import ( - "crypto/md5" - "encoding/json" - "fmt" "strings" "time" @@ -106,30 +103,6 @@ func defaultAgentConfig() AgentConfig { } } -// FleetAgentConfig defines configuration for agents. -type FleetAgentConfig struct { - Service Service `config:"service"` - AgentName string `config:"agent.name"` - Etag string `config:"etag"` - Config map[string]string -} - -func (s *FleetAgentConfig) setup() error { - if s.Config == nil { - // Config may be passed to APM Server as `null` when no attributes - // are defined in an APM Agent central configuration entry. - s.Config = make(map[string]string) - } - if s.Etag == "" { - m, err := json.Marshal(s) - if err != nil { - return fmt.Errorf("error generating etag for %s: %v", s.Service, err) - } - s.Etag = fmt.Sprintf("%x", md5.Sum(m)) - } - return nil -} - // Service defines a unique way of identifying a running agent. type Service struct { Name string `config:"name"` diff --git a/internal/beater/config/agentconfig_test.go b/internal/beater/config/agentconfig_test.go index 94d66701bb6..23b004f6b36 100644 --- a/internal/beater/config/agentconfig_test.go +++ b/internal/beater/config/agentconfig_test.go @@ -47,18 +47,3 @@ func TestAgentConfig(t *testing.T) { assert.Equal(t, time.Second*123, cfg.AgentConfig.Cache.Expiration) }) } - -func TestAgentConfigs(t *testing.T) { - cfg, err := NewConfig(config.MustNewConfigFrom(`{"agent_config":[{"service.environment":"production","config":{"transaction_sample_rate":0.5}}]}`), nil) - require.NoError(t, err) - assert.NotNil(t, cfg) - assert.Len(t, cfg.FleetAgentConfigs, 1) - assert.NotEmpty(t, cfg.FleetAgentConfigs[0].Etag) - - // The "config" attribute may come through as `null` when no config attributes are defined. - cfg, err = NewConfig(config.MustNewConfigFrom(`{"agent_config":[{"service.environment":"production","config":null}]}`), nil) - require.NoError(t, err) - assert.NotNil(t, cfg) - assert.Len(t, cfg.FleetAgentConfigs, 1) - assert.NotEmpty(t, cfg.FleetAgentConfigs[0].Etag) -} diff --git a/internal/beater/config/config.go b/internal/beater/config/config.go index 55782c6f3c7..23c411450c5 100644 --- a/internal/beater/config/config.go +++ b/internal/beater/config/config.go @@ -65,8 +65,6 @@ type Config struct { DefaultServiceEnvironment string `config:"default_service_environment"` JavaAttacherConfig JavaAttacherConfig `config:"java_attacher"` - FleetAgentConfigs []FleetAgentConfig `config:"agent_config"` - // WaitReadyInterval holds the interval for checks when waiting for // the integration package to be installed, and for checking the // Elasticsearch license level. @@ -89,12 +87,6 @@ func NewConfig(ucfg *config.C, outputESCfg *config.C) (*Config, error) { return nil, errors.Wrap(err, "Error processing configuration") } - for i := range c.FleetAgentConfigs { - if err := c.FleetAgentConfigs[i].setup(); err != nil { - return nil, err - } - } - if err := c.AgentConfig.setup(logger, outputESCfg); err != nil { return nil, err } diff --git a/internal/beater/otlp/http_test.go b/internal/beater/otlp/http_test.go index 93702049759..a626d2570ac 100644 --- a/internal/beater/otlp/http_test.go +++ b/internal/beater/otlp/http_test.go @@ -190,7 +190,7 @@ func newHTTPServer(t *testing.T, batchProcessor modelpb.BatchProcessor) string { cfg, batchProcessor, auth, - agentcfg.NewDirectFetcher(nil), + agentcfg.NewEmptyFetcher(), ratelimitStore, nil, func() bool { return true }, diff --git a/internal/beater/server.go b/internal/beater/server.go index 1da7bcf2ece..01124f9204a 100644 --- a/internal/beater/server.go +++ b/internal/beater/server.go @@ -241,17 +241,13 @@ func newAgentConfigFetcher( ) (agentcfg.Fetcher, func(context.Context) error, error) { // Always use ElasticsearchFetcher, and as a fallback, use: // 1. no fallback if Elasticsearch is explicitly configured - // 2. fleet agent config - // 3. kibana fetcher if (2) is not available - // 4. no fallback if both (2) and (3) are not available + // 2. kibana fetcher + // 3. no fallback if (2) is not available var fallbackFetcher agentcfg.Fetcher switch { case cfg.AgentConfig.ESOverrideConfigured: // Disable fallback because agent config Elasticsearch is explicitly configured. - case cfg.FleetAgentConfigs != nil: - agentConfigurations := agentcfg.ConvertAgentConfigs(cfg.FleetAgentConfigs) - fallbackFetcher = agentcfg.NewDirectFetcher(agentConfigurations) case kibanaClient != nil: var err error fallbackFetcher, err = agentcfg.NewKibanaFetcher(kibanaClient, cfg.AgentConfig.Cache.Expiration) diff --git a/internal/beater/tracing.go b/internal/beater/tracing.go index fdc5cc25211..ec974bc0385 100644 --- a/internal/beater/tracing.go +++ b/internal/beater/tracing.go @@ -41,12 +41,11 @@ func newTracerServer(cfg *config.Config, listener net.Listener, logger *logp.Log if err != nil { return nil, err } - agentConfigFetcher := agentcfg.SanitizingFetcher{Fetcher: agentcfg.NewDirectFetcher(agentcfg.ConvertAgentConfigs(cfg.FleetAgentConfigs))} mux, err := api.NewMux( cfg, batchProcessor, authenticator, - agentConfigFetcher, + agentcfg.NewEmptyFetcher(), ratelimitStore, nil, // no sourcemap store func() bool { return true }, // ready for publishing