Skip to content

Commit

Permalink
Consume APMConfig from input units in agent mode (#3277)
Browse files Browse the repository at this point in the history
* Consume APMConfig from input units in agent mode

Consume and prefer APMConfig from the expected input component while
operating in agent mode over config in inputs[0].server.instrumentation.

---------

Co-authored-by: Julia Bardi <90178898+juliaElastic@users.noreply.github.com>
  • Loading branch information
michel-laterman and juliaElastic authored Feb 14, 2024
1 parent 726a74f commit d16a665
Show file tree
Hide file tree
Showing 3 changed files with 388 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Kind can be one of:
# - breaking-change: a change to previously-documented behavior
# - deprecation: functionality that is being removed in a later release
# - bug-fix: fixes a problem in a previous version
# - enhancement: extends functionality but does not break or fix existing behavior
# - feature: new functionality
# - known-issue: problems that we are aware of in a given version
# - security: impacts on the security of a product or a user’s deployment.
# - upgrade: important information for someone upgrading from a prior version
# - other: does not fit into any of the other categories
kind: enhancement

# Change summary; a 80ish characters long description of the change.
summary: Prefer elastic-agent-client APMConfig in agent mode

# Long description; in case the summary is not enough to describe the change
# this field accommodate a description without length limits.
# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment.
description: |
While running in agent-mode fleet-server will use the APMConfig
settings of expected input if it's set over the settings in
inputs[0].server.instrumentation; this should make it easier for
managing agents to inject APM config data.
# Affected component; a word indicating the component this changeset affects.
component:

# PR URL; optional; the PR number that added the changeset.
# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added.
# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number.
# Please provide it if you are adding a fragment for a different PR.
pr: 3277

# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of).
# If not present is automatically filled by the tooling with the issue linked to the PR number.
issue: 2868
51 changes: 48 additions & 3 deletions internal/pkg/server/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/rs/zerolog"

"github.com/elastic/elastic-agent-client/v7/pkg/client"
"github.com/elastic/elastic-agent-client/v7/pkg/proto"
"github.com/elastic/go-ucfg"
"gopkg.in/yaml.v3"
)
Expand Down Expand Up @@ -285,7 +286,7 @@ func (a *Agent) start(ctx context.Context) error {
return a.reconfigure(ctx)
}

cfg, err := a.configFromUnits()
cfg, err := a.configFromUnits(ctx)
if err != nil {
return err
}
Expand Down Expand Up @@ -331,7 +332,7 @@ func (a *Agent) reconfigure(ctx context.Context) error {
return a.start(ctx)
}

cfg, err := a.configFromUnits()
cfg, err := a.configFromUnits(ctx)
if err != nil {
return err
}
Expand Down Expand Up @@ -373,7 +374,7 @@ func (a *Agent) stop() {

// configFromUnits takes both inputUnit and outputUnit and creates a single configuration just like fleet server was
// being started from a configuration file.
func (a *Agent) configFromUnits() (*config.Config, error) {
func (a *Agent) configFromUnits(ctx context.Context) (*config.Config, error) {
agentID := ""
agentVersion := ""
agentInfo := a.agent.AgentInfo()
Expand Down Expand Up @@ -420,10 +421,54 @@ func (a *Agent) configFromUnits() (*config.Config, error) {
return nil, err
}

if expAPMCFG := expInput.APMConfig; expAPMCFG != nil {
instrumentationCfg, err := apmConfigToInstrumentation(expAPMCFG)
if err != nil {
zerolog.Ctx(ctx).Warn().Err(err).Msg("Unable to parse expected APM config as instrumentation config")
} else {
obj := map[string]interface{}{
"inputs": []interface{}{map[string]interface{}{
"server": map[string]interface{}{
"instrumentation": instrumentationCfg,
},
},
}}
err = cfgData.Merge(obj, config.DefaultOptions...)
if err != nil {
zerolog.Ctx(ctx).Warn().Err(err).Msg("Failed to merge APM config into cfgData")
}
}

}

cliCfg := ucfg.MustNewFrom(a.cliCfg, config.DefaultOptions...)
err = cliCfg.Merge(cfgData, config.DefaultOptions...)
if err != nil {
return nil, err
}
return config.FromConfig(cliCfg)
}

// apmConfigToInstrumentation transforms the passed APMConfig into the Instrumentation config that is used by fleet-server.
func apmConfigToInstrumentation(src *proto.APMConfig) (config.Instrumentation, error) {
if apmest := src.GetElastic(); apmest != nil {
apmTLS := apmest.GetTls()
iTLS := config.InstrumentationTLS{
SkipVerify: apmTLS.GetSkipVerify(),
ServerCertificate: apmTLS.GetServerCert(),
ServerCA: apmTLS.GetServerCa(),
}

cfg := config.Instrumentation{
Enabled: true,
TLS: iTLS,
Environment: apmest.GetEnvironment(),
APIKey: apmest.GetApiKey(),
SecretToken: apmest.GetSecretToken(),
Hosts: apmest.GetHosts(),
GlobalLabels: apmest.GetGlobalLabels(),
}
return cfg, nil
}
return config.Instrumentation{}, fmt.Errorf("unable to transform APMConfig to instrumentation")
}
Loading

0 comments on commit d16a665

Please sign in to comment.