From e107dc4001c205d9576c7ec3c56fbade59ec9d35 Mon Sep 17 00:00:00 2001 From: Michal Pristas Date: Mon, 4 May 2020 17:19:30 +0200 Subject: [PATCH] [Agent] Allow CLI paths override (#17781) (#18169) [Agent] Allow CLI paths override (#17781) --- x-pack/elastic-agent/CHANGELOG.asciidoc | 1 + x-pack/elastic-agent/main_test.go | 12 ++++-- .../pkg/agent/application/global_config.go | 41 ++++++++++++++++--- x-pack/elastic-agent/pkg/agent/cmd/common.go | 18 ++++---- x-pack/elastic-agent/pkg/agent/cmd/enroll.go | 10 ++--- x-pack/elastic-agent/pkg/agent/cmd/run.go | 9 ++-- 6 files changed, 64 insertions(+), 27 deletions(-) diff --git a/x-pack/elastic-agent/CHANGELOG.asciidoc b/x-pack/elastic-agent/CHANGELOG.asciidoc index f3f6edbc605e..4440679b7ef2 100644 --- a/x-pack/elastic-agent/CHANGELOG.asciidoc +++ b/x-pack/elastic-agent/CHANGELOG.asciidoc @@ -37,4 +37,5 @@ - Display the stability of the agent at enroll and start. {pull}17336[17336] - Expose stream.* variables in events {pull}17468[17468] - Monitoring configuration reloadable {pull}17855[17855] +- Allow CLI overrides of paths {pull}17781[17781] - Enable Filebeat input: S3, Azureeventhub, cloudfoundry, httpjson, netflow, o365audit. {pull}17909[17909] diff --git a/x-pack/elastic-agent/main_test.go b/x-pack/elastic-agent/main_test.go index cdced7ea6774..79e2a9dc719a 100644 --- a/x-pack/elastic-agent/main_test.go +++ b/x-pack/elastic-agent/main_test.go @@ -8,17 +8,21 @@ import ( "flag" "testing" - // Just using this a place holder. - "github.com/elastic/beats/v7/x-pack/filebeat/cmd" + "github.com/spf13/cobra" ) var systemTest *bool func init() { testing.Init() + + cmd := &cobra.Command{ + Use: "elastic-agent [subcommand]", + } + systemTest = flag.Bool("systemTest", false, "Set to true when running system tests") - cmd.RootCmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("systemTest")) - cmd.RootCmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("test.coverprofile")) + cmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("systemTest")) + cmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("test.coverprofile")) } // Test started when the test binary is started. Only calls main. diff --git a/x-pack/elastic-agent/pkg/agent/application/global_config.go b/x-pack/elastic-agent/pkg/agent/application/global_config.go index 44e9f2772ff2..a08a59b09124 100644 --- a/x-pack/elastic-agent/pkg/agent/application/global_config.go +++ b/x-pack/elastic-agent/pkg/agent/application/global_config.go @@ -8,33 +8,64 @@ import ( "os" "path/filepath" + "github.com/elastic/beats/v7/libbeat/common" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/errors" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/config" ) var ( - homePath string - dataPath string + homePath string + dataPath string + overwrites *common.Config ) func init() { homePath = retrieveExecutablePath() dataPath = retrieveDataPath() + overwrites = common.NewConfig() + common.ConfigOverwriteFlag(nil, overwrites, "path.home", "path.home", "", "Agent root path") + common.ConfigOverwriteFlag(nil, overwrites, "path.data", "path.data", "", "Data path contains Agent managed binaries") +} + +// HomePath returns home path where. +func HomePath() string { + if val, err := overwrites.String("path.home", -1); err == nil { + return val + } + + return homePath +} + +// DataPath returns data path where. +func DataPath() string { + if val, err := overwrites.String("path.data", -1); err == nil { + return val + } + + return dataPath } // InjectAgentConfig injects config to a provided configuration. func InjectAgentConfig(c *config.Config) error { - globalConfig := AgentGlobalConfig() + globalConfig := agentGlobalConfig() if err := c.Merge(globalConfig); err != nil { return errors.New("failed to inject agent global config", err, errors.TypeConfig) } + return injectOverwrites(c) +} + +func injectOverwrites(c *config.Config) error { + if err := c.Merge(overwrites); err != nil { + return errors.New("failed to inject agent overwrites", err, errors.TypeConfig) + } + return nil } -// AgentGlobalConfig gets global config used for resolution of variables inside configuration +// agentGlobalConfig gets global config used for resolution of variables inside configuration // such as ${path.data}. -func AgentGlobalConfig() map[string]interface{} { +func agentGlobalConfig() map[string]interface{} { return map[string]interface{}{ "path": map[string]interface{}{ "data": dataPath, diff --git a/x-pack/elastic-agent/pkg/agent/cmd/common.go b/x-pack/elastic-agent/pkg/agent/cmd/common.go index 0189f8e408d8..956b7324d3c8 100644 --- a/x-pack/elastic-agent/pkg/agent/cmd/common.go +++ b/x-pack/elastic-agent/pkg/agent/cmd/common.go @@ -5,30 +5,30 @@ package cmd import ( + "flag" "fmt" "os" "path/filepath" "github.com/spf13/cobra" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/basecmd" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/cli" ) -var defaultConfig = "elastic-agent.yml" +const defaultConfig = "elastic-agent.yml" type globalFlags struct { - PathConfigFile string PathConfig string - PathData string - PathHome string - PathLogs string + PathConfigFile string FlagStrictPerms bool } +// Config returns path which identifies configuration file. func (f *globalFlags) Config() string { if len(f.PathConfigFile) == 0 { - return filepath.Join(f.PathHome, defaultConfig) + return filepath.Join(application.HomePath(), defaultConfig) } return f.PathConfigFile } @@ -50,11 +50,11 @@ func NewCommandWithArgs(args []string, streams *cli.IOStreams) *cobra.Command { flags := &globalFlags{} + cmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("path.home")) + cmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("path.data")) + cmd.PersistentFlags().StringVarP(&flags.PathConfigFile, "", "c", defaultConfig, fmt.Sprintf(`Configuration file, relative to path.config (default "%s")`, defaultConfig)) - cmd.PersistentFlags().StringVarP(&flags.PathHome, "path.home", "", "", "Home path") cmd.PersistentFlags().StringVarP(&flags.PathConfig, "path.config", "", "${path.home}", "Configuration path") - cmd.PersistentFlags().StringVarP(&flags.PathData, "path.data", "", "${path.home}/data", "Data path") - cmd.PersistentFlags().StringVarP(&flags.PathLogs, "path.logs", "", "${path.home}/logs", "Logs path") cmd.PersistentFlags().BoolVarP(&flags.FlagStrictPerms, "strict.perms", "", true, "Strict permission checking on config files") // Add version. diff --git a/x-pack/elastic-agent/pkg/agent/cmd/enroll.go b/x-pack/elastic-agent/pkg/agent/cmd/enroll.go index a2a7ee48d220..abc5efb3b90a 100644 --- a/x-pack/elastic-agent/pkg/agent/cmd/enroll.go +++ b/x-pack/elastic-agent/pkg/agent/cmd/enroll.go @@ -46,13 +46,13 @@ func newEnrollCommandWithArgs(flags *globalFlags, _ []string, streams *cli.IOStr func enroll(streams *cli.IOStreams, cmd *cobra.Command, flags *globalFlags, args []string) error { warn.PrintNotGA(streams.Out) - - config, err := config.LoadYAML(flags.PathConfigFile) + pathConfigFile := flags.Config() + config, err := config.LoadYAML(pathConfigFile) if err != nil { return errors.New(err, - fmt.Sprintf("could not read configuration file %s", flags.PathConfigFile), + fmt.Sprintf("could not read configuration file %s", pathConfigFile), errors.TypeFilesystem, - errors.M(errors.MetaKeyPath, flags.PathConfigFile)) + errors.M(errors.MetaKeyPath, pathConfigFile)) } force, _ := cmd.Flags().GetBool("force") @@ -95,7 +95,7 @@ func enroll(streams *cli.IOStreams, cmd *cobra.Command, flags *globalFlags, args c, err := application.NewEnrollCmd( logger, &options, - flags.PathConfigFile, + pathConfigFile, ) if err != nil { diff --git a/x-pack/elastic-agent/pkg/agent/cmd/run.go b/x-pack/elastic-agent/pkg/agent/cmd/run.go index f0196ba7875e..db199e2b47d0 100644 --- a/x-pack/elastic-agent/pkg/agent/cmd/run.go +++ b/x-pack/elastic-agent/pkg/agent/cmd/run.go @@ -33,12 +33,13 @@ func newRunCommandWithArgs(flags *globalFlags, _ []string, streams *cli.IOStream } func run(flags *globalFlags, streams *cli.IOStreams) error { - config, err := config.LoadYAML(flags.PathConfigFile) + pathConfigFile := flags.Config() + config, err := config.LoadYAML(pathConfigFile) if err != nil { return errors.New(err, - fmt.Sprintf("could not read configuration file %s", flags.PathConfigFile), + fmt.Sprintf("could not read configuration file %s", pathConfigFile), errors.TypeFilesystem, - errors.M(errors.MetaKeyPath, flags.PathConfigFile)) + errors.M(errors.MetaKeyPath, pathConfigFile)) } logger, err := logger.NewFromConfig(config) @@ -46,7 +47,7 @@ func run(flags *globalFlags, streams *cli.IOStreams) error { return err } - app, err := application.New(logger, flags.PathConfigFile) + app, err := application.New(logger, pathConfigFile) if err != nil { return err }