From 117bf325c08c29dba675a08d82facedef7e46110 Mon Sep 17 00:00:00 2001 From: Blake Rouse Date: Tue, 6 Oct 2020 09:02:26 -0400 Subject: [PATCH] [Elastic Agent] Add elastic agent ID and version to events from filebeat and metricbeat. (#21543) * Add elastic agent ID and version to events from filebeat and metricbeat. * Add changelog and fix inputs. (cherry picked from commit f5d13aa2037bb26b8b1f0dcc801b48abb299e8e8) --- x-pack/elastic-agent/CHANGELOG.next.asciidoc | 1 + .../pkg/agent/application/emitter.go | 11 +- .../pkg/agent/application/info/agent_info.go | 12 ++ .../agent/application/inspect_output_cmd.go | 45 ++++--- .../pkg/agent/application/local_mode.go | 1 + .../pkg/agent/application/managed_mode.go | 1 + .../agent/application/managed_mode_test.go | 4 +- .../agent/application/monitoring_decorator.go | 6 +- .../application/monitoring_decorator_test.go | 25 +++- .../pkg/agent/program/program.go | 8 +- .../pkg/agent/program/program_test.go | 16 ++- .../pkg/agent/program/supported.go | 2 +- .../testdata/enabled_output_true-filebeat.yml | 6 + .../testdata/enabled_true-filebeat.yml | 6 + .../testdata/single_config-filebeat.yml | 12 ++ .../testdata/single_config-metricbeat.yml | 19 ++- .../pkg/agent/transpiler/rules.go | 126 ++++++++++++++---- .../pkg/agent/transpiler/rules_test.go | 65 ++++++++- x-pack/elastic-agent/spec/filebeat.yml | 2 + x-pack/elastic-agent/spec/metricbeat.yml | 2 + 20 files changed, 301 insertions(+), 69 deletions(-) diff --git a/x-pack/elastic-agent/CHANGELOG.next.asciidoc b/x-pack/elastic-agent/CHANGELOG.next.asciidoc index 7d6870328c7..639b1dbad17 100644 --- a/x-pack/elastic-agent/CHANGELOG.next.asciidoc +++ b/x-pack/elastic-agent/CHANGELOG.next.asciidoc @@ -29,4 +29,5 @@ - Send `fleet.host.id` to Endpoint Security {pull}21042[21042] - Add `install` and `uninstall` subcommands {pull}21206[21206] - Send updating state {pull}21461[21461] +- Add `elastic.agent.id` and `elastic.agent.version` to published events from filebeat and metricbeat {pull}21543[21543] - Add `upgrade` subcommand to perform upgrade of installed Elastic Agent {pull}21425[21425] diff --git a/x-pack/elastic-agent/pkg/agent/application/emitter.go b/x-pack/elastic-agent/pkg/agent/application/emitter.go index d8a19492e2b..fc103366826 100644 --- a/x-pack/elastic-agent/pkg/agent/application/emitter.go +++ b/x-pack/elastic-agent/pkg/agent/application/emitter.go @@ -10,6 +10,7 @@ import ( "strings" "sync" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/info" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/errors" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/program" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/transpiler" @@ -18,7 +19,7 @@ import ( "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/logger" ) -type decoratorFunc = func(string, *transpiler.AST, []program.Program) ([]program.Program, error) +type decoratorFunc = func(*info.AgentInfo, string, *transpiler.AST, []program.Program) ([]program.Program, error) type filterFunc = func(*logger.Logger, *transpiler.AST) error type reloadable interface { @@ -36,6 +37,7 @@ type programsDispatcher interface { type emitterController struct { logger *logger.Logger + agentInfo *info.AgentInfo controller composable.Controller router programsDispatcher modifiers *configModifiers @@ -112,14 +114,14 @@ func (e *emitterController) update() error { e.logger.Debug("Converting single configuration into specific programs configuration") - programsToRun, err := program.Programs(ast) + programsToRun, err := program.Programs(e.agentInfo, ast) if err != nil { return err } for _, decorator := range e.modifiers.Decorators { for outputType, ptr := range programsToRun { - programsToRun[outputType], err = decorator(outputType, ast, ptr) + programsToRun[outputType], err = decorator(e.agentInfo, outputType, ast, ptr) if err != nil { return err } @@ -135,12 +137,13 @@ func (e *emitterController) update() error { return e.router.Dispatch(ast.HashStr(), programsToRun) } -func emitter(ctx context.Context, log *logger.Logger, controller composable.Controller, router programsDispatcher, modifiers *configModifiers, reloadables ...reloadable) (emitterFunc, error) { +func emitter(ctx context.Context, log *logger.Logger, agentInfo *info.AgentInfo, controller composable.Controller, router programsDispatcher, modifiers *configModifiers, reloadables ...reloadable) (emitterFunc, error) { log.Debugf("Supported programs: %s", strings.Join(program.KnownProgramNames(), ", ")) init, _ := transpiler.NewVars(map[string]interface{}{}) ctrl := &emitterController{ logger: log, + agentInfo: agentInfo, controller: controller, router: router, modifiers: modifiers, diff --git a/x-pack/elastic-agent/pkg/agent/application/info/agent_info.go b/x-pack/elastic-agent/pkg/agent/application/info/agent_info.go index e990b83bd49..b0abbe19e64 100644 --- a/x-pack/elastic-agent/pkg/agent/application/info/agent_info.go +++ b/x-pack/elastic-agent/pkg/agent/application/info/agent_info.go @@ -4,6 +4,8 @@ package info +import "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/release" + // AgentInfo is a collection of information about agent. type AgentInfo struct { agentID string @@ -44,3 +46,13 @@ func ForceNewAgentInfo() (*AgentInfo, error) { func (i *AgentInfo) AgentID() string { return i.agentID } + +// Version returns the version for this Agent. +func (*AgentInfo) Version() string { + return release.Version() +} + +// Snapshot returns if this version is a snapshot. +func (*AgentInfo) Snapshot() bool { + return release.Snapshot() +} diff --git a/x-pack/elastic-agent/pkg/agent/application/inspect_output_cmd.go b/x-pack/elastic-agent/pkg/agent/application/inspect_output_cmd.go index 8f648887d10..bb319ce1569 100644 --- a/x-pack/elastic-agent/pkg/agent/application/inspect_output_cmd.go +++ b/x-pack/elastic-agent/pkg/agent/application/inspect_output_cmd.go @@ -8,11 +8,12 @@ import ( "context" "fmt" - "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/transpiler" - "github.com/elastic/beats/v7/libbeat/logp" + + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/info" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/configuration" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/program" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/transpiler" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/composable" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/config" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/logger" @@ -37,14 +38,19 @@ func NewInspectOutputCmd(configPath, output, program string) (*InspectOutputCmd, // Execute tries to enroll the agent into Fleet. func (c *InspectOutputCmd) Execute() error { + agentInfo, err := info.NewAgentInfo() + if err != nil { + return err + } + if c.output == "" { - return c.inspectOutputs() + return c.inspectOutputs(agentInfo) } - return c.inspectOutput() + return c.inspectOutput(agentInfo) } -func (c *InspectOutputCmd) inspectOutputs() error { +func (c *InspectOutputCmd) inspectOutputs(agentInfo *info.AgentInfo) error { rawConfig, err := loadConfig(c.cfgPath) if err != nil { return err @@ -61,7 +67,7 @@ func (c *InspectOutputCmd) inspectOutputs() error { } if isStandalone(cfg.Fleet) { - return listOutputsFromConfig(l, rawConfig) + return listOutputsFromConfig(l, agentInfo, rawConfig) } fleetConfig, err := loadFleetConfig(rawConfig) @@ -71,11 +77,11 @@ func (c *InspectOutputCmd) inspectOutputs() error { return fmt.Errorf("no fleet config retrieved yet") } - return listOutputsFromMap(l, fleetConfig) + return listOutputsFromMap(l, agentInfo, fleetConfig) } -func listOutputsFromConfig(log *logger.Logger, cfg *config.Config) error { - programsGroup, err := getProgramsFromConfig(log, cfg) +func listOutputsFromConfig(log *logger.Logger, agentInfo *info.AgentInfo, cfg *config.Config) error { + programsGroup, err := getProgramsFromConfig(log, agentInfo, cfg) if err != nil { return err @@ -88,16 +94,16 @@ func listOutputsFromConfig(log *logger.Logger, cfg *config.Config) error { return nil } -func listOutputsFromMap(log *logger.Logger, cfg map[string]interface{}) error { +func listOutputsFromMap(log *logger.Logger, agentInfo *info.AgentInfo, cfg map[string]interface{}) error { c, err := config.NewConfigFrom(cfg) if err != nil { return err } - return listOutputsFromConfig(log, c) + return listOutputsFromConfig(log, agentInfo, c) } -func (c *InspectOutputCmd) inspectOutput() error { +func (c *InspectOutputCmd) inspectOutput(agentInfo *info.AgentInfo) error { rawConfig, err := loadConfig(c.cfgPath) if err != nil { return err @@ -114,7 +120,7 @@ func (c *InspectOutputCmd) inspectOutput() error { } if isStandalone(cfg.Fleet) { - return printOutputFromConfig(l, c.output, c.program, rawConfig) + return printOutputFromConfig(l, agentInfo, c.output, c.program, rawConfig) } fleetConfig, err := loadFleetConfig(rawConfig) @@ -124,11 +130,11 @@ func (c *InspectOutputCmd) inspectOutput() error { return fmt.Errorf("no fleet config retrieved yet") } - return printOutputFromMap(l, c.output, c.program, fleetConfig) + return printOutputFromMap(l, agentInfo, c.output, c.program, fleetConfig) } -func printOutputFromConfig(log *logger.Logger, output, programName string, cfg *config.Config) error { - programsGroup, err := getProgramsFromConfig(log, cfg) +func printOutputFromConfig(log *logger.Logger, agentInfo *info.AgentInfo, output, programName string, cfg *config.Config) error { + programsGroup, err := getProgramsFromConfig(log, agentInfo, cfg) if err != nil { return err @@ -164,16 +170,16 @@ func printOutputFromConfig(log *logger.Logger, output, programName string, cfg * } -func printOutputFromMap(log *logger.Logger, output, programName string, cfg map[string]interface{}) error { +func printOutputFromMap(log *logger.Logger, agentInfo *info.AgentInfo, output, programName string, cfg map[string]interface{}) error { c, err := config.NewConfigFrom(cfg) if err != nil { return err } - return printOutputFromConfig(log, output, programName, c) + return printOutputFromConfig(log, agentInfo, output, programName, c) } -func getProgramsFromConfig(log *logger.Logger, cfg *config.Config) (map[string][]program.Program, error) { +func getProgramsFromConfig(log *logger.Logger, agentInfo *info.AgentInfo, cfg *config.Config) (map[string][]program.Program, error) { monitor := noop.NewMonitor() router := &inmemRouter{} ctx, cancel := context.WithCancel(context.Background()) @@ -186,6 +192,7 @@ func getProgramsFromConfig(log *logger.Logger, cfg *config.Config) (map[string][ emit, err := emitter( ctx, log, + agentInfo, composableWaiter, router, &configModifiers{ diff --git a/x-pack/elastic-agent/pkg/agent/application/local_mode.go b/x-pack/elastic-agent/pkg/agent/application/local_mode.go index f8eed0f5792..b58e260cab6 100644 --- a/x-pack/elastic-agent/pkg/agent/application/local_mode.go +++ b/x-pack/elastic-agent/pkg/agent/application/local_mode.go @@ -115,6 +115,7 @@ func newLocal( emit, err := emitter( localApplication.bgContext, log, + agentInfo, composableCtrl, router, &configModifiers{ diff --git a/x-pack/elastic-agent/pkg/agent/application/managed_mode.go b/x-pack/elastic-agent/pkg/agent/application/managed_mode.go index 66a252203fc..ea39bddd6c0 100644 --- a/x-pack/elastic-agent/pkg/agent/application/managed_mode.go +++ b/x-pack/elastic-agent/pkg/agent/application/managed_mode.go @@ -172,6 +172,7 @@ func newManaged( emit, err := emitter( managedApplication.bgContext, log, + agentInfo, composableCtrl, router, &configModifiers{ diff --git a/x-pack/elastic-agent/pkg/agent/application/managed_mode_test.go b/x-pack/elastic-agent/pkg/agent/application/managed_mode_test.go index 81f2419f936..65cb27547ff 100644 --- a/x-pack/elastic-agent/pkg/agent/application/managed_mode_test.go +++ b/x-pack/elastic-agent/pkg/agent/application/managed_mode_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/info" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/configrequest" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/composable" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/logger" @@ -32,8 +33,9 @@ func TestManagedModeRouting(t *testing.T) { log, _ := logger.New("") router, _ := newRouter(log, streamFn) + agentInfo, _ := info.NewAgentInfo() composableCtrl, _ := composable.New(log, nil) - emit, err := emitter(ctx, log, composableCtrl, router, &configModifiers{Decorators: []decoratorFunc{injectMonitoring}}) + emit, err := emitter(ctx, log, agentInfo, composableCtrl, router, &configModifiers{Decorators: []decoratorFunc{injectMonitoring}}) require.NoError(t, err) actionDispatcher, err := newActionDispatcher(ctx, log, &handlerDefault{log: log}) diff --git a/x-pack/elastic-agent/pkg/agent/application/monitoring_decorator.go b/x-pack/elastic-agent/pkg/agent/application/monitoring_decorator.go index 2b04126381b..3fc49ef17d3 100644 --- a/x-pack/elastic-agent/pkg/agent/application/monitoring_decorator.go +++ b/x-pack/elastic-agent/pkg/agent/application/monitoring_decorator.go @@ -7,6 +7,7 @@ package application import ( "fmt" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/info" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/program" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/transpiler" ) @@ -28,7 +29,7 @@ const ( defaultOutputName = "default" ) -func injectMonitoring(outputGroup string, rootAst *transpiler.AST, programsToRun []program.Program) ([]program.Program, error) { +func injectMonitoring(agentInfo *info.AgentInfo, outputGroup string, rootAst *transpiler.AST, programsToRun []program.Program) ([]program.Program, error) { var err error monitoringProgram := program.Program{ Spec: program.Spec{ @@ -63,7 +64,7 @@ func injectMonitoring(outputGroup string, rootAst *transpiler.AST, programsToRun } ast := rootAst.Clone() - if err := getMonitoringRule(monitoringOutputName).Apply(ast); err != nil { + if err := getMonitoringRule(monitoringOutputName).Apply(agentInfo, ast); err != nil { return programsToRun, err } @@ -93,6 +94,7 @@ func getMonitoringRule(outputName string) *transpiler.RuleList { return transpiler.NewRuleList( transpiler.Copy(monitoringOutputSelector, outputKey), transpiler.Rename(fmt.Sprintf("%s.%s", outputsKey, outputName), elasticsearchKey), + transpiler.InjectAgentInfo(), transpiler.Filter(monitoringKey, programsKey, outputKey), ) } diff --git a/x-pack/elastic-agent/pkg/agent/application/monitoring_decorator_test.go b/x-pack/elastic-agent/pkg/agent/application/monitoring_decorator_test.go index f50bb74d5e8..6a3be4100be 100644 --- a/x-pack/elastic-agent/pkg/agent/application/monitoring_decorator_test.go +++ b/x-pack/elastic-agent/pkg/agent/application/monitoring_decorator_test.go @@ -7,17 +7,22 @@ package application import ( "testing" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/info" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/program" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/transpiler" ) func TestMonitoringInjection(t *testing.T) { + agentInfo, err := info.NewAgentInfo() + if err != nil { + t.Fatal(err) + } ast, err := transpiler.NewAST(inputConfigMap) if err != nil { t.Fatal(err) } - programsToRun, err := program.Programs(ast) + programsToRun, err := program.Programs(agentInfo, ast) if err != nil { t.Fatal(err) } @@ -25,7 +30,7 @@ func TestMonitoringInjection(t *testing.T) { GROUPLOOP: for group, ptr := range programsToRun { programsCount := len(ptr) - newPtr, err := injectMonitoring(group, ast, ptr) + newPtr, err := injectMonitoring(agentInfo, group, ast, ptr) if err != nil { t.Error(err) continue GROUPLOOP @@ -83,12 +88,16 @@ GROUPLOOP: } func TestMonitoringInjectionDefaults(t *testing.T) { + agentInfo, err := info.NewAgentInfo() + if err != nil { + t.Fatal(err) + } ast, err := transpiler.NewAST(inputConfigMapDefaults) if err != nil { t.Fatal(err) } - programsToRun, err := program.Programs(ast) + programsToRun, err := program.Programs(agentInfo, ast) if err != nil { t.Fatal(err) } @@ -96,7 +105,7 @@ func TestMonitoringInjectionDefaults(t *testing.T) { GROUPLOOP: for group, ptr := range programsToRun { programsCount := len(ptr) - newPtr, err := injectMonitoring(group, ast, ptr) + newPtr, err := injectMonitoring(agentInfo, group, ast, ptr) if err != nil { t.Error(err) continue GROUPLOOP @@ -154,12 +163,16 @@ GROUPLOOP: } func TestMonitoringInjectionDisabled(t *testing.T) { + agentInfo, err := info.NewAgentInfo() + if err != nil { + t.Fatal(err) + } ast, err := transpiler.NewAST(inputConfigMapDisabled) if err != nil { t.Fatal(err) } - programsToRun, err := program.Programs(ast) + programsToRun, err := program.Programs(agentInfo, ast) if err != nil { t.Fatal(err) } @@ -167,7 +180,7 @@ func TestMonitoringInjectionDisabled(t *testing.T) { GROUPLOOP: for group, ptr := range programsToRun { programsCount := len(ptr) - newPtr, err := injectMonitoring(group, ast, ptr) + newPtr, err := injectMonitoring(agentInfo, group, ast, ptr) if err != nil { t.Error(err) continue GROUPLOOP diff --git a/x-pack/elastic-agent/pkg/agent/program/program.go b/x-pack/elastic-agent/pkg/agent/program/program.go index 25b56081e68..f3f17d06b9d 100644 --- a/x-pack/elastic-agent/pkg/agent/program/program.go +++ b/x-pack/elastic-agent/pkg/agent/program/program.go @@ -47,7 +47,7 @@ func (p *Program) Configuration() map[string]interface{} { // Programs take a Tree representation of the main configuration and apply all the different // programs rules and generate individual configuration from the rules. -func Programs(singleConfig *transpiler.AST) (map[string][]Program, error) { +func Programs(agentInfo transpiler.AgentInfo, singleConfig *transpiler.AST) (map[string][]Program, error) { grouped, err := groupByOutputs(singleConfig) if err != nil { return nil, errors.New(err, errors.TypeConfig, "fail to extract program configuration") @@ -55,7 +55,7 @@ func Programs(singleConfig *transpiler.AST) (map[string][]Program, error) { groupedPrograms := make(map[string][]Program) for k, config := range grouped { - programs, err := detectPrograms(config) + programs, err := detectPrograms(agentInfo, config) if err != nil { return nil, errors.New(err, errors.TypeConfig, "fail to generate program configuration") } @@ -65,11 +65,11 @@ func Programs(singleConfig *transpiler.AST) (map[string][]Program, error) { return groupedPrograms, nil } -func detectPrograms(singleConfig *transpiler.AST) ([]Program, error) { +func detectPrograms(agentInfo transpiler.AgentInfo, singleConfig *transpiler.AST) ([]Program, error) { programs := make([]Program, 0) for _, spec := range Supported { specificAST := singleConfig.Clone() - err := spec.Rules.Apply(specificAST) + err := spec.Rules.Apply(agentInfo, specificAST) if err != nil { return nil, err } diff --git a/x-pack/elastic-agent/pkg/agent/program/program_test.go b/x-pack/elastic-agent/pkg/agent/program/program_test.go index c15510b6655..8c2cf8c499f 100644 --- a/x-pack/elastic-agent/pkg/agent/program/program_test.go +++ b/x-pack/elastic-agent/pkg/agent/program/program_test.go @@ -437,7 +437,7 @@ func TestConfiguration(t *testing.T) { ast, err := transpiler.NewAST(m) require.NoError(t, err) - programs, err := Programs(ast) + programs, err := Programs(&fakeAgentInfo{}, ast) if test.err { require.Error(t, err) return @@ -478,3 +478,17 @@ func TestConfiguration(t *testing.T) { }) } } + +type fakeAgentInfo struct{} + +func (*fakeAgentInfo) AgentID() string { + return "agent-id" +} + +func (*fakeAgentInfo) Version() string { + return "8.0.0" +} + +func (*fakeAgentInfo) Snapshot() bool { + return false +} diff --git a/x-pack/elastic-agent/pkg/agent/program/supported.go b/x-pack/elastic-agent/pkg/agent/program/supported.go index 3b314bfa3f4..adc13938ae2 100644 --- a/x-pack/elastic-agent/pkg/agent/program/supported.go +++ b/x-pack/elastic-agent/pkg/agent/program/supported.go @@ -21,7 +21,7 @@ func init() { // spec/filebeat.yml // spec/heartbeat.yml // spec/metricbeat.yml - unpacked := packer.MustUnpack("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") + unpacked := packer.MustUnpack("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") SupportedMap = make(map[string]Spec) for f, v := range unpacked { diff --git a/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_output_true-filebeat.yml b/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_output_true-filebeat.yml index 8edc27061b0..38b251d95dc 100644 --- a/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_output_true-filebeat.yml +++ b/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_output_true-filebeat.yml @@ -16,6 +16,12 @@ filebeat: target: "event" fields: dataset: generic + - add_fields: + target: "elastic" + fields: + agent.id: agent-id + agent.version: 8.0.0 + agent.snapshot: false output: elasticsearch: enabled: true diff --git a/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_true-filebeat.yml b/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_true-filebeat.yml index 8bd5d93a3b9..6e768db6aa4 100644 --- a/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_true-filebeat.yml +++ b/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_true-filebeat.yml @@ -17,6 +17,12 @@ filebeat: target: "event" fields: dataset: generic + - add_fields: + target: "elastic" + fields: + agent.id: agent-id + agent.version: 8.0.0 + agent.snapshot: false output: elasticsearch: hosts: diff --git a/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-filebeat.yml b/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-filebeat.yml index b996e13b531..01ee955e4ec 100644 --- a/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-filebeat.yml +++ b/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-filebeat.yml @@ -18,6 +18,12 @@ filebeat: target: "event" fields: dataset: generic + - add_fields: + target: "elastic" + fields: + agent.id: agent-id + agent.version: 8.0.0 + agent.snapshot: false - type: log paths: - /var/log/hello3.log @@ -36,6 +42,12 @@ filebeat: target: "event" fields: dataset: generic + - add_fields: + target: "elastic" + fields: + agent.id: agent-id + agent.version: 8.0.0 + agent.snapshot: false output: elasticsearch: hosts: diff --git a/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-metricbeat.yml b/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-metricbeat.yml index c62882ff6da..d09e80accf1 100644 --- a/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-metricbeat.yml +++ b/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-metricbeat.yml @@ -15,6 +15,12 @@ metricbeat: target: "event" fields: dataset: docker.status + - add_fields: + target: "elastic" + fields: + agent.id: agent-id + agent.version: 8.0.0 + agent.snapshot: false - module: docker metricsets: [info] index: metrics-generic-default @@ -30,6 +36,12 @@ metricbeat: target: "event" fields: dataset: generic + - add_fields: + target: "elastic" + fields: + agent.id: agent-id + agent.version: 8.0.0 + agent.snapshot: false - module: apache metricsets: [info] index: metrics-generic-testing @@ -48,7 +60,12 @@ metricbeat: target: "event" fields: dataset: generic - + - add_fields: + target: "elastic" + fields: + agent.id: agent-id + agent.version: 8.0.0 + agent.snapshot: false output: elasticsearch: hosts: [127.0.0.1:9200, 127.0.0.1:9300] diff --git a/x-pack/elastic-agent/pkg/agent/transpiler/rules.go b/x-pack/elastic-agent/pkg/agent/transpiler/rules.go index 5ad790eb31e..29ff1786d1e 100644 --- a/x-pack/elastic-agent/pkg/agent/transpiler/rules.go +++ b/x-pack/elastic-agent/pkg/agent/transpiler/rules.go @@ -14,6 +14,13 @@ import ( "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/errors" ) +// AgentInfo is an interface to get the agent info. +type AgentInfo interface { + AgentID() string + Version() string + Snapshot() bool +} + // RuleList is a container that allow the same tree to be executed on multiple defined Rule. type RuleList struct { Rules []Rule @@ -21,15 +28,15 @@ type RuleList struct { // Rule defines a rule that can be Applied on the Tree. type Rule interface { - Apply(*AST) error + Apply(AgentInfo, *AST) error } // Apply applies a list of rules over the same tree and use the result of the previous execution // as the input of the next rule, will return early if any error is raise during the execution. -func (r *RuleList) Apply(ast *AST) error { +func (r *RuleList) Apply(agentInfo AgentInfo, ast *AST) error { var err error for _, rule := range r.Rules { - err = rule.Apply(ast) + err = rule.Apply(agentInfo, ast) if err != nil { return err } @@ -73,6 +80,8 @@ func (r *RuleList) MarshalYAML() (interface{}, error) { name = "inject_index" case *InjectStreamProcessorRule: name = "inject_stream_processor" + case *InjectAgentInfoRule: + name = "inject_agent_info" case *MakeArrayRule: name = "make_array" case *RemoveKeyRule: @@ -154,6 +163,8 @@ func (r *RuleList) UnmarshalYAML(unmarshal func(interface{}) error) error { r = &InjectIndexRule{} case "inject_stream_processor": r = &InjectStreamProcessorRule{} + case "inject_agent_info": + r = &InjectAgentInfoRule{} case "make_array": r = &MakeArrayRule{} case "remove_key": @@ -181,7 +192,7 @@ type SelectIntoRule struct { } // Apply applies select into rule. -func (r *SelectIntoRule) Apply(ast *AST) error { +func (r *SelectIntoRule) Apply(_ AgentInfo, ast *AST) error { target := &Dict{} for _, selector := range r.Selectors { @@ -214,7 +225,7 @@ type RemoveKeyRule struct { } // Apply applies remove key rule. -func (r *RemoveKeyRule) Apply(ast *AST) error { +func (r *RemoveKeyRule) Apply(_ AgentInfo, ast *AST) error { sourceMap, ok := ast.root.(*Dict) if !ok { return nil @@ -250,7 +261,7 @@ type MakeArrayRule struct { } // Apply applies make array rule. -func (r *MakeArrayRule) Apply(ast *AST) error { +func (r *MakeArrayRule) Apply(_ AgentInfo, ast *AST) error { sourceNode, found := Lookup(ast, r.Item) if !found { return nil @@ -286,7 +297,7 @@ type CopyToListRule struct { } // Apply copies specified node into every item of the list. -func (r *CopyToListRule) Apply(ast *AST) error { +func (r *CopyToListRule) Apply(_ AgentInfo, ast *AST) error { sourceNode, found := Lookup(ast, r.Item) if !found { // nothing to copy @@ -347,7 +358,7 @@ type CopyAllToListRule struct { } // Apply copies all nodes into every item of the list. -func (r *CopyAllToListRule) Apply(ast *AST) error { +func (r *CopyAllToListRule) Apply(agentInfo AgentInfo, ast *AST) error { // get list of nodes astMap, err := ast.Map() if err != nil { @@ -370,7 +381,7 @@ func (r *CopyAllToListRule) Apply(ast *AST) error { continue } - if err := CopyToList(item, r.To, r.OnConflict).Apply(ast); err != nil { + if err := CopyToList(item, r.To, r.OnConflict).Apply(agentInfo, ast); err != nil { return err } } @@ -393,7 +404,7 @@ type FixStreamRule struct { } // Apply stream fixes. -func (r *FixStreamRule) Apply(ast *AST) error { +func (r *FixStreamRule) Apply(_ AgentInfo, ast *AST) error { const defaultDataset = "generic" const defaultNamespace = "default" @@ -526,7 +537,7 @@ type InjectIndexRule struct { } // Apply injects index into input. -func (r *InjectIndexRule) Apply(ast *AST) error { +func (r *InjectIndexRule) Apply(_ AgentInfo, ast *AST) error { inputsNode, found := Lookup(ast, "inputs") if !found { return nil @@ -583,7 +594,7 @@ type InjectStreamProcessorRule struct { } // Apply injects processor into input. -func (r *InjectStreamProcessorRule) Apply(ast *AST) error { +func (r *InjectStreamProcessorRule) Apply(_ AgentInfo, ast *AST) error { inputsNode, found := Lookup(ast, "inputs") if !found { return nil @@ -665,6 +676,63 @@ func InjectStreamProcessor(onMerge, streamType string) *InjectStreamProcessorRul } } +// InjectAgentInfoRule injects agent information into each rule. +type InjectAgentInfoRule struct{} + +// Apply injects index into input. +func (r *InjectAgentInfoRule) Apply(agentInfo AgentInfo, ast *AST) error { + inputsNode, found := Lookup(ast, "inputs") + if !found { + return nil + } + + inputsList, ok := inputsNode.Value().(*List) + if !ok { + return nil + } + + for _, inputNode := range inputsList.value { + inputMap, ok := inputNode.(*Dict) + if !ok { + continue + } + + // get processors node + processorsNode, found := inputMap.Find("processors") + if !found { + processorsNode = &Key{ + name: "processors", + value: &List{value: make([]Node, 0)}, + } + + inputMap.value = append(inputMap.value, processorsNode) + } + + processorsList, ok := processorsNode.Value().(*List) + if !ok { + return errors.New("InjectAgentInfoRule: processors is not a list") + } + + // elastic.agent + processorMap := &Dict{value: make([]Node, 0)} + processorMap.value = append(processorMap.value, &Key{name: "target", value: &StrVal{value: "elastic"}}) + processorMap.value = append(processorMap.value, &Key{name: "fields", value: &Dict{value: []Node{ + &Key{name: "agent.id", value: &StrVal{value: agentInfo.AgentID()}}, + &Key{name: "agent.version", value: &StrVal{value: agentInfo.Version()}}, + &Key{name: "agent.snapshot", value: &BoolVal{value: agentInfo.Snapshot()}}, + }}}) + addFieldsMap := &Dict{value: []Node{&Key{"add_fields", processorMap}}} + processorsList.value = mergeStrategy("").InjectItem(processorsList.value, addFieldsMap) + } + + return nil +} + +// InjectAgentInfo creates a InjectAgentInfoRule +func InjectAgentInfo() *InjectAgentInfoRule { + return &InjectAgentInfoRule{} +} + // ExtractListItemRule extract items with specified name from a list of maps. // The result is store in a new array. // Example: @@ -679,7 +747,7 @@ type ExtractListItemRule struct { } // Apply extracts items from array. -func (r *ExtractListItemRule) Apply(ast *AST) error { +func (r *ExtractListItemRule) Apply(_ AgentInfo, ast *AST) error { node, found := Lookup(ast, r.Path) if !found { return nil @@ -740,7 +808,7 @@ type RenameRule struct { // Apply renames the last items of a Selector to a new name and keep all the other values and will // return an error on failure. -func (r *RenameRule) Apply(ast *AST) error { +func (r *RenameRule) Apply(_ AgentInfo, ast *AST) error { // Skip rename when node is not found. node, ok := Lookup(ast, r.From) if !ok { @@ -773,7 +841,7 @@ func Copy(from, to Selector) *CopyRule { } // Apply copy a part of a tree into a new destination. -func (r CopyRule) Apply(ast *AST) error { +func (r CopyRule) Apply(_ AgentInfo, ast *AST) error { node, ok := Lookup(ast, r.From) // skip when the `from` node is not found. if !ok { @@ -800,7 +868,7 @@ func Translate(path Selector, mapper map[string]interface{}) *TranslateRule { } // Apply translates matching elements of a translation table for a specific selector. -func (r *TranslateRule) Apply(ast *AST) error { +func (r *TranslateRule) Apply(_ AgentInfo, ast *AST) error { // Skip translate when node is not found. node, ok := Lookup(ast, r.Path) if !ok { @@ -873,7 +941,7 @@ func TranslateWithRegexp(path Selector, re *regexp.Regexp, with string) *Transla } // Apply translates matching elements of a translation table for a specific selector. -func (r *TranslateWithRegexpRule) Apply(ast *AST) error { +func (r *TranslateWithRegexpRule) Apply(_ AgentInfo, ast *AST) error { // Skip translate when node is not found. node, ok := Lookup(ast, r.Path) if !ok { @@ -914,7 +982,7 @@ func Map(path Selector, rules ...Rule) *MapRule { } // Apply maps multiples rules over a subset of the tree. -func (r *MapRule) Apply(ast *AST) error { +func (r *MapRule) Apply(agentInfo AgentInfo, ast *AST) error { node, ok := Lookup(ast, r.Path) // Skip map when node is not found. if !ok { @@ -931,15 +999,15 @@ func (r *MapRule) Apply(ast *AST) error { switch t := n.Value().(type) { case *List: - return mapList(r, t) + return mapList(agentInfo, r, t) case *Dict: - return mapDict(r, t) + return mapDict(agentInfo, r, t) case *Key: switch t := n.Value().(type) { case *List: - return mapList(r, t) + return mapList(agentInfo, r, t) case *Dict: - return mapDict(r, t) + return mapDict(agentInfo, r, t) default: return fmt.Errorf( "cannot iterate over node, invalid type expected 'List' or 'Dict' received '%T'", @@ -954,13 +1022,13 @@ func (r *MapRule) Apply(ast *AST) error { ) } -func mapList(r *MapRule, l *List) error { +func mapList(agentInfo AgentInfo, r *MapRule, l *List) error { values := l.Value().([]Node) for idx, item := range values { newAST := &AST{root: item} for _, rule := range r.Rules { - err := rule.Apply(newAST) + err := rule.Apply(agentInfo, newAST) if err != nil { return err } @@ -970,10 +1038,10 @@ func mapList(r *MapRule, l *List) error { return nil } -func mapDict(r *MapRule, l *Dict) error { +func mapDict(agentInfo AgentInfo, r *MapRule, l *Dict) error { newAST := &AST{root: l} for _, rule := range r.Rules { - err := rule.Apply(newAST) + err := rule.Apply(agentInfo, newAST) if err != nil { return err } @@ -1024,7 +1092,7 @@ func Filter(selectors ...Selector) *FilterRule { } // Apply filters a Tree based on list of selectors. -func (r *FilterRule) Apply(ast *AST) error { +func (r *FilterRule) Apply(_ AgentInfo, ast *AST) error { mergedAST := &AST{root: &Dict{}} var err error for _, selector := range r.Selectors { @@ -1054,7 +1122,7 @@ func FilterValues(selector Selector, key Selector, values ...interface{}) *Filte } // Apply filters a Tree based on list of selectors. -func (r *FilterValuesRule) Apply(ast *AST) error { +func (r *FilterValuesRule) Apply(_ AgentInfo, ast *AST) error { node, ok := Lookup(ast, r.Selector) // Skip map when node is not found. if !ok { @@ -1167,7 +1235,7 @@ func (r *FilterValuesWithRegexpRule) UnmarshalYAML(unmarshal func(interface{}) e } // Apply filters a Tree based on list of selectors. -func (r *FilterValuesWithRegexpRule) Apply(ast *AST) error { +func (r *FilterValuesWithRegexpRule) Apply(_ AgentInfo, ast *AST) error { node, ok := Lookup(ast, r.Selector) // Skip map when node is not found. if !ok { diff --git a/x-pack/elastic-agent/pkg/agent/transpiler/rules_test.go b/x-pack/elastic-agent/pkg/agent/transpiler/rules_test.go index c3207f48cea..d92ba0de985 100644 --- a/x-pack/elastic-agent/pkg/agent/transpiler/rules_test.go +++ b/x-pack/elastic-agent/pkg/agent/transpiler/rules_test.go @@ -165,6 +165,51 @@ inputs: }, }, + "inject agent info": { + givenYAML: ` +inputs: + - name: No processors + type: file + - name: With processors + type: file + processors: + - add_fields: + target: other + fields: + data: more +`, + expectedYAML: ` +inputs: + - name: No processors + type: file + processors: + - add_fields: + target: elastic + fields: + agent.id: agent-id + agent.snapshot: false + agent.version: 8.0.0 + - name: With processors + type: file + processors: + - add_fields: + target: other + fields: + data: more + - add_fields: + target: elastic + fields: + agent.id: agent-id + agent.snapshot: false + agent.version: 8.0.0 +`, + rule: &RuleList{ + Rules: []Rule{ + InjectAgentInfo(), + }, + }, + }, + "extract items from array": { givenYAML: ` streams: @@ -615,7 +660,7 @@ logs: a, err := makeASTFromYAML(test.givenYAML) require.NoError(t, err) - err = test.rule.Apply(a) + err = test.rule.Apply(FakeAgentInfo(), a) require.NoError(t, err) v := &MapVisitor{} @@ -751,3 +796,21 @@ func TestSerialization(t *testing.T) { assert.Equal(t, value, v) }) } + +type fakeAgentInfo struct{} + +func (*fakeAgentInfo) AgentID() string { + return "agent-id" +} + +func (*fakeAgentInfo) Version() string { + return "8.0.0" +} + +func (*fakeAgentInfo) Snapshot() bool { + return false +} + +func FakeAgentInfo() AgentInfo { + return &fakeAgentInfo{} +} diff --git a/x-pack/elastic-agent/spec/filebeat.yml b/x-pack/elastic-agent/spec/filebeat.yml index 1b184b10098..aa09b4f9121 100644 --- a/x-pack/elastic-agent/spec/filebeat.yml +++ b/x-pack/elastic-agent/spec/filebeat.yml @@ -87,6 +87,8 @@ rules: values: - true +- inject_agent_info: {} + - copy: from: inputs to: filebeat diff --git a/x-pack/elastic-agent/spec/metricbeat.yml b/x-pack/elastic-agent/spec/metricbeat.yml index 94b69e9a2f3..a5015a974a5 100644 --- a/x-pack/elastic-agent/spec/metricbeat.yml +++ b/x-pack/elastic-agent/spec/metricbeat.yml @@ -73,6 +73,8 @@ rules: - remove_key: key: use_output +- inject_agent_info: {} + - copy: from: inputs to: metricbeat