diff --git a/x-pack/elastic-agent/CHANGELOG.asciidoc b/x-pack/elastic-agent/CHANGELOG.asciidoc index 2b67153634fb..16e9fd671ce5 100644 --- a/x-pack/elastic-agent/CHANGELOG.asciidoc +++ b/x-pack/elastic-agent/CHANGELOG.asciidoc @@ -34,15 +34,15 @@ - Fixed Monitoring filebeat and metricbeat not connecting to Agent over GRPC {pull}23843[23843] - Fixed make status readable in the log. {pull}23849[23849] - Windows agent doesn't uninstall with a lowercase `c:` drive in the path {pull}23998[23998] -- Fix reloading of log level for services {pull}[24055]24055 -- Fix: Successfully installed and enrolled agent running standalone{pull}[24128]24128 -- Make installer atomic on windows {pull}[24253]24253 -- Remove installed services on agent uninstall {pull}[24151]24151 -- Fix failing installation on windows 7 {pull}[24387]24387 -- Fix capabilities resolution in inspect command {pull}[24346]24346 -- Fix windows installer during enroll {pull}[24343]24343 -- Logging to file disabled on enroll {issue}[24173]24173 -- Prevent uninstall failures on empty config {pull}[24838]24838 +- Fix reloading of log level for services {pull}24055[24055] +- Fix: Successfully installed and enrolled agent running standalone{pull}24128[24128] +- Make installer atomic on windows {pull}24253[24253] +- Remove installed services on agent uninstall {pull}24151[24151] +- Fix failing installation on windows 7 {pull}24387[24387] +- Fix capabilities resolution in inspect command {pull}24346[24346] +- Fix windows installer during enroll {pull}24343[24343] +- Logging to file disabled on enroll {issue}24173[24173] +- Prevent uninstall failures on empty config {pull}24838[24838] ==== New features @@ -63,6 +63,7 @@ - Add `event.dataset` to all events {pull}20076[20076] - Send datastreams fields {pull}20416[20416] - Agent supports capabilities definition {pull}23848[23848] +- Restart process on output change {pull}24907[24907] [[release-notes-7.8.0]] === Elastic Agent version 7.8.0 diff --git a/x-pack/elastic-agent/pkg/agent/program/spec.go b/x-pack/elastic-agent/pkg/agent/program/spec.go index 98e539d20077..79a08071202d 100644 --- a/x-pack/elastic-agent/pkg/agent/program/spec.go +++ b/x-pack/elastic-agent/pkg/agent/program/spec.go @@ -27,20 +27,21 @@ var ErrMissingWhen = errors.New("program must define a 'When' expression") // NOTE: Current spec are build at compile time, we want to revisit that to allow other program // to register their spec in a secure way. type Spec struct { - Name string `yaml:"name"` - ServicePort int `yaml:"service,omitempty"` - Cmd string `yaml:"cmd"` - Args []string `yaml:"args"` - Artifact string `yaml:"artifact"` - ActionInputTypes []string `yaml:"action_input_types,omitempty"` - LogPaths map[string]string `yaml:"log_paths,omitempty"` - MetricEndpoints map[string]string `yaml:"metric_endpoints,omitempty"` - Rules *transpiler.RuleList `yaml:"rules"` - CheckInstallSteps *transpiler.StepList `yaml:"check_install"` - PostInstallSteps *transpiler.StepList `yaml:"post_install"` - PreUninstallSteps *transpiler.StepList `yaml:"pre_uninstall"` - When string `yaml:"when"` - Constraints string `yaml:"constraints"` + Name string `yaml:"name"` + ServicePort int `yaml:"service,omitempty"` + Cmd string `yaml:"cmd"` + Args []string `yaml:"args"` + Artifact string `yaml:"artifact"` + ActionInputTypes []string `yaml:"action_input_types,omitempty"` + LogPaths map[string]string `yaml:"log_paths,omitempty"` + MetricEndpoints map[string]string `yaml:"metric_endpoints,omitempty"` + Rules *transpiler.RuleList `yaml:"rules"` + CheckInstallSteps *transpiler.StepList `yaml:"check_install"` + PostInstallSteps *transpiler.StepList `yaml:"post_install"` + PreUninstallSteps *transpiler.StepList `yaml:"pre_uninstall"` + When string `yaml:"when"` + Constraints string `yaml:"constraints"` + RestartOnOutputChange bool `yaml:"restart_on_output_change,omitempty"` } // ReadSpecs reads all the specs that match the provided globbing path. diff --git a/x-pack/elastic-agent/pkg/agent/program/supported.go b/x-pack/elastic-agent/pkg/agent/program/supported.go index 9909f9eafe33..fb8f482fa1cf 100644 --- a/x-pack/elastic-agent/pkg/agent/program/supported.go +++ b/x-pack/elastic-agent/pkg/agent/program/supported.go @@ -25,7 +25,7 @@ func init() { // spec/metricbeat.yml // spec/osquerybeat.yml // spec/packetbeat.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/core/plugin/common.go b/x-pack/elastic-agent/pkg/core/plugin/common.go new file mode 100644 index 000000000000..7bb25c7e94d0 --- /dev/null +++ b/x-pack/elastic-agent/pkg/core/plugin/common.go @@ -0,0 +1,79 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package plugin + +import ( + "gopkg.in/yaml.v2" + + "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/config" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/logger" +) + +type configFetcher interface { + Config() string +} + +// IsRestartNeeded returns true if +// - spec is configured to support restart on change +// - output changes in between configs +func IsRestartNeeded(log *logger.Logger, spec program.Spec, cfgFetch configFetcher, newCfg map[string]interface{}) bool { + // compare outputs + curCfgStr := cfgFetch.Config() + if curCfgStr == "" { + // no config currently applied + return false + } + + currentOutput, err := getOutputConfigFromString(curCfgStr) + if err != nil { + log.Errorf("failed to retrieve output config from current state: %v", err) + return false + } + + newOutput, err := getOutputConfigFromMap(newCfg) + if err != nil { + log.Errorf("failed to retrieve output config from new state: %v", err) + return false + } + + // restart needed only if specified and output changed + return spec.RestartOnOutputChange && currentOutput != newOutput +} + +func getOutputConfigFromString(cfgString string) (string, error) { + cfg, err := config.NewConfigFrom(cfgString) + if err != nil { + return "", err + } + + cfgMap, err := cfg.ToMapStr() + if err != nil { + return "", err + } + + return getOutputConfigFromMap(cfgMap) +} + +func getOutputConfigFromMap(cfgMap map[string]interface{}) (string, error) { + outputCfgIface, found := cfgMap["output"] + if !found { + // output not found not an error + return "", nil + } + + outputCfg, ok := outputCfgIface.(map[string]interface{}) + if !ok { + return "", errors.New("not a map") + } + + cfgStr, err := yaml.Marshal(outputCfg) + if err != nil { + return "", errors.New(err, errors.TypeApplication) + } + + return string(cfgStr), nil +} diff --git a/x-pack/elastic-agent/pkg/core/plugin/common_test.go b/x-pack/elastic-agent/pkg/core/plugin/common_test.go new file mode 100644 index 000000000000..70b673e09ad2 --- /dev/null +++ b/x-pack/elastic-agent/pkg/core/plugin/common_test.go @@ -0,0 +1,95 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package plugin + +import ( + "testing" + + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v2" + + "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/core/logger" +) + +func TestRestartNeeded(t *testing.T) { + tt := []struct { + Name string + OldOutput map[string]interface{} + NewOutput map[string]interface{} + ShouldRestart bool + + ExpectedRestart bool + }{ + { + "same empty output", + map[string]interface{}{}, + map[string]interface{}{}, + true, + false, + }, + { + "same not empty output", + map[string]interface{}{"output": map[string]interface{}{"username": "user", "password": "123456"}}, + map[string]interface{}{"output": map[string]interface{}{"username": "user", "password": "123456"}}, + true, + false, + }, + { + "different empty output", + map[string]interface{}{}, + map[string]interface{}{"output": map[string]interface{}{"username": "user", "password": "123456"}}, + true, + false, + }, + { + "different not empty output", + map[string]interface{}{"output": map[string]interface{}{"username": "user", "password": "123456"}}, + map[string]interface{}{"output": map[string]interface{}{"username": "user", "password": "s3cur3_Pa55;"}}, + true, + true, + }, + { + "different not empty output no restart required", + map[string]interface{}{"output": map[string]interface{}{"username": "user", "password": "123456"}}, + map[string]interface{}{"output": map[string]interface{}{"username": "user", "password": "s3cur3_Pa55;"}}, + false, + false, + }, + } + + for _, tc := range tt { + t.Run(tc.Name, func(t *testing.T) { + cf, err := newTestConfigFetcher(tc.OldOutput) + require.NoError(t, err) + s := testProgramSpec(tc.ShouldRestart) + l, _ := logger.New("tst", false) + + IsRestartNeeded(l, s, cf, tc.NewOutput) + }) + } +} + +func newTestConfigFetcher(cfg map[string]interface{}) (*testConfigFetcher, error) { + cfgStr, err := yaml.Marshal(cfg) + if err != nil { + return nil, errors.New(err, errors.TypeApplication) + } + + return &testConfigFetcher{cfg: string(cfgStr)}, nil +} + +type testConfigFetcher struct { + cfg string +} + +func (f testConfigFetcher) Config() string { return f.cfg } + +func testProgramSpec(restartOnOutput bool) program.Spec { + return program.Spec{ + RestartOnOutputChange: restartOnOutput, + } +} diff --git a/x-pack/elastic-agent/pkg/core/plugin/process/configure.go b/x-pack/elastic-agent/pkg/core/plugin/process/configure.go index a3f96458b6c9..0563d0f7cce8 100644 --- a/x-pack/elastic-agent/pkg/core/plugin/process/configure.go +++ b/x-pack/elastic-agent/pkg/core/plugin/process/configure.go @@ -10,11 +10,12 @@ import ( "gopkg.in/yaml.v2" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/errors" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/plugin" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/state" ) // Configure configures the application with the passed configuration. -func (a *Application) Configure(_ context.Context, config map[string]interface{}) (err error) { +func (a *Application) Configure(ctx context.Context, config map[string]interface{}) (err error) { defer func() { if err != nil { // inject App metadata @@ -37,10 +38,22 @@ func (a *Application) Configure(_ context.Context, config map[string]interface{} if err != nil { return errors.New(err, errors.TypeApplication) } + + isRestartNeeded := plugin.IsRestartNeeded(a.logger, a.Spec(), a.srvState, config) + err = a.srvState.UpdateConfig(string(cfgStr)) if err != nil { return errors.New(err, errors.TypeApplication) } - return nil + if isRestartNeeded { + a.logger.Infof("initiating restart of '%s' due to config change", a.Name()) + a.appLock.Unlock() + a.Stop() + err = a.Start(ctx, a.desc, config) + // lock back so it wont panic on deferred unlock + a.appLock.Lock() + } + + return err } diff --git a/x-pack/elastic-agent/pkg/core/plugin/service/app.go b/x-pack/elastic-agent/pkg/core/plugin/service/app.go index 3cb14dc46c61..83fa39954829 100644 --- a/x-pack/elastic-agent/pkg/core/plugin/service/app.go +++ b/x-pack/elastic-agent/pkg/core/plugin/service/app.go @@ -24,6 +24,7 @@ import ( "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/app" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/logger" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/monitoring" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/plugin" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/process" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/server" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/state" @@ -145,7 +146,7 @@ func (a *Application) SetState(s state.Status, msg string, payload map[string]in } // Start starts the application with a specified config. -func (a *Application) Start(ctx context.Context, t app.Taggable, cfg map[string]interface{}) (err error) { +func (a *Application) Start(ctx context.Context, _ app.Taggable, cfg map[string]interface{}) (err error) { defer func() { if err != nil { // inject App metadata @@ -203,7 +204,7 @@ func (a *Application) Start(ctx context.Context, t app.Taggable, cfg map[string] } // Configure configures the application with the passed configuration. -func (a *Application) Configure(_ context.Context, config map[string]interface{}) (err error) { +func (a *Application) Configure(ctx context.Context, config map[string]interface{}) (err error) { defer func() { if err != nil { // inject App metadata @@ -223,11 +224,24 @@ func (a *Application) Configure(_ context.Context, config map[string]interface{} if err != nil { return errors.New(err, errors.TypeApplication) } + + isRestartNeeded := plugin.IsRestartNeeded(a.logger, a.Spec(), a.srvState, config) + err = a.srvState.UpdateConfig(string(cfgStr)) if err != nil { return errors.New(err, errors.TypeApplication) } - return nil + + if isRestartNeeded { + a.logger.Infof("initiating restart of '%s' due to config change", a.Name()) + a.appLock.Unlock() + a.Stop() + err = a.Start(ctx, a.desc, config) + // lock back so it wont panic on deferred unlock + a.appLock.Lock() + } + + return err } // Stop stops the current application. diff --git a/x-pack/elastic-agent/spec/filebeat.yml b/x-pack/elastic-agent/spec/filebeat.yml index c156d60aaa7f..77f18ebe3ff2 100644 --- a/x-pack/elastic-agent/spec/filebeat.yml +++ b/x-pack/elastic-agent/spec/filebeat.yml @@ -2,6 +2,7 @@ name: Filebeat cmd: filebeat args: ["-E", "setup.ilm.enabled=false", "-E", "setup.template.enabled=false", "-E", "management.mode=x-pack-fleet", "-E", "management.enabled=true", "-E", "logging.level=debug"] artifact: beats/filebeat +restart_on_output_change: true rules: - fix_stream: {} - inject_index: diff --git a/x-pack/elastic-agent/spec/heartbeat.yml b/x-pack/elastic-agent/spec/heartbeat.yml index 399fd7d08851..b4f5b14e5a87 100644 --- a/x-pack/elastic-agent/spec/heartbeat.yml +++ b/x-pack/elastic-agent/spec/heartbeat.yml @@ -2,6 +2,7 @@ name: Heartbeat cmd: heartbeat args: ["-E", "setup.ilm.enabled=false", "-E", "setup.template.enabled=false", "-E", "management.mode=x-pack-fleet", "-E", "management.enabled=true", "-E", "logging.level=debug"] artifact: beats/heartbeat +restart_on_output_change: true rules: - fix_stream: {} - filter_values_with_regexp: diff --git a/x-pack/elastic-agent/spec/metricbeat.yml b/x-pack/elastic-agent/spec/metricbeat.yml index a5015a974a57..b06575014d77 100644 --- a/x-pack/elastic-agent/spec/metricbeat.yml +++ b/x-pack/elastic-agent/spec/metricbeat.yml @@ -2,6 +2,7 @@ name: Metricbeat cmd: metricbeat args: ["-E", "setup.ilm.enabled=false", "-E", "setup.template.enabled=false", "-E", "management.mode=x-pack-fleet", "-E", "management.enabled=true", "-E", "logging.level=debug"] artifact: beats/metricbeat +restart_on_output_change: true post_install: - move_file: path: "modules.d/system.yml" diff --git a/x-pack/elastic-agent/spec/osquerybeat.yml b/x-pack/elastic-agent/spec/osquerybeat.yml index f92574128a2b..c4d218b2cc6e 100644 --- a/x-pack/elastic-agent/spec/osquerybeat.yml +++ b/x-pack/elastic-agent/spec/osquerybeat.yml @@ -1,6 +1,7 @@ name: Osquerybeat cmd: osquerybeat args: ["-E", "setup.ilm.enabled=false", "-E", "setup.template.enabled=false", "-E", "management.mode=x-pack-fleet", "-E", "management.enabled=true", "-E", "logging.level=debug"] +restart_on_output_change: true artifact: beats/osquerybeat action_input_types: - osquery @@ -26,4 +27,4 @@ rules: - output when: length(${inputs}) > 0 and hasKey(${output}, 'elasticsearch') -constraints: ${runtime.arch} != 'arm64' \ No newline at end of file +constraints: ${runtime.arch} != 'arm64' diff --git a/x-pack/elastic-agent/spec/packetbeat.yml b/x-pack/elastic-agent/spec/packetbeat.yml index 6dffecbda6df..bf05f901c48f 100644 --- a/x-pack/elastic-agent/spec/packetbeat.yml +++ b/x-pack/elastic-agent/spec/packetbeat.yml @@ -2,6 +2,7 @@ name: Packetbeat cmd: packetbeat args: ['-E', 'setup.ilm.enabled=false', '-E', 'setup.template.enabled=false', '-E', 'management.mode=x-pack-fleet', '-E', 'management.enabled=true', '-E', 'logging.level=debug'] artifact: beats/packetbeat +restart_on_output_change: true rules: - filter_values: selector: inputs