From a45e4ccec4b029293e1d4238fb4c35f9abc8c727 Mon Sep 17 00:00:00 2001 From: Blake Rouse Date: Wed, 21 Apr 2021 14:43:30 -0400 Subject: [PATCH] [Elastic Agent] Fix status and inspect command to work inside running container (#25204) * Fix status and inspect command to work inside running container. * Add changelog. (cherry picked from commit b88ad8d5244ae30dfd9c03a51329f16a1cfe6321) --- x-pack/elastic-agent/CHANGELOG.next.asciidoc | 1 + .../elastic-agent/pkg/agent/cmd/container.go | 67 +++++++++++++++++-- x-pack/elastic-agent/pkg/agent/cmd/inspect.go | 5 ++ x-pack/elastic-agent/pkg/agent/cmd/status.go | 5 ++ 4 files changed, 72 insertions(+), 6 deletions(-) diff --git a/x-pack/elastic-agent/CHANGELOG.next.asciidoc b/x-pack/elastic-agent/CHANGELOG.next.asciidoc index 73028e9fac4d..619964f2cfb6 100644 --- a/x-pack/elastic-agent/CHANGELOG.next.asciidoc +++ b/x-pack/elastic-agent/CHANGELOG.next.asciidoc @@ -53,6 +53,7 @@ - Set --inscure in container when FLEET_SERVER_ENABLE and FLEET_INSECURE set {pull}25137[25137] - Restart process on output change {pull}24907[24907] - Fixed: limit for retries to Kibana configurable {issue}25063[25063] +- Fix issue with status and inspect inside of container {pull}25204[25204] ==== New features diff --git a/x-pack/elastic-agent/pkg/agent/cmd/container.go b/x-pack/elastic-agent/pkg/agent/cmd/container.go index 7872172a2741..bb06db41a3a7 100644 --- a/x-pack/elastic-agent/pkg/agent/cmd/container.go +++ b/x-pack/elastic-agent/pkg/agent/cmd/container.go @@ -25,6 +25,7 @@ import ( "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/configuration" "github.com/spf13/cobra" + "gopkg.in/yaml.v2" "github.com/elastic/beats/v7/libbeat/common/transport/tlscommon" "github.com/elastic/beats/v7/libbeat/kibana" @@ -164,7 +165,7 @@ func logContainerCmd(streams *cli.IOStreams, cmd *cobra.Command) error { func containerCmd(streams *cli.IOStreams, cmd *cobra.Command) error { // set paths early so all action below use the defined paths - if err := setPaths(); err != nil { + if err := setPaths("", "", "", true); err != nil { return err } @@ -635,13 +636,13 @@ func logToStderr(cfg *configuration.Configuration) { } } -func setPaths() error { - statePath := envWithDefault(defaultStateDirectory, "STATE_PATH") +func setPaths(statePath, configPath, logsPath string, writePaths bool) error { + statePath = envWithDefault(statePath, "STATE_PATH") if statePath == "" { - return errors.New("STATE_PATH cannot be set to an empty string") + statePath = defaultStateDirectory } topPath := filepath.Join(statePath, "data") - configPath := envWithDefault("", "CONFIG_PATH") + configPath = envWithDefault(configPath, "CONFIG_PATH") if configPath == "" { configPath = statePath } @@ -662,21 +663,75 @@ func setPaths() error { if err := syncDir(srcDownloads, destDownloads); err != nil { return fmt.Errorf("syncing download directory to STATE_PATH(%s) failed: %s", statePath, err) } + originalTop := paths.Top() paths.SetTop(topPath) paths.SetConfig(configPath) // when custom top path is provided the home directory is not versioned paths.SetVersionHome(false) // set LOGS_PATH is given - if logsPath := envWithDefault("", "LOGS_PATH"); logsPath != "" { + logsPath = envWithDefault(logsPath, "LOGS_PATH") + if logsPath != "" { paths.SetLogs(logsPath) // ensure that the logs directory exists if err := os.MkdirAll(filepath.Join(logsPath), 0755); err != nil { return fmt.Errorf("preparing LOGS_PATH(%s) failed: %s", logsPath, err) } } + // persist the paths so other commands in the container will use the correct paths + if writePaths { + if err := writeContainerPaths(originalTop, statePath, configPath, logsPath); err != nil { + return err + } + } + return nil +} + +type containerPaths struct { + StatePath string `config:"state_path" yaml:"state_path"` + ConfigPath string `config:"state_path" yaml:"config_path,omitempty"` + LogsPath string `config:"state_path" yaml:"logs_path,omitempty"` +} + +func writeContainerPaths(original, statePath, configPath, logsPath string) error { + pathFile := filepath.Join(original, "container-paths.yml") + fp, err := os.Create(pathFile) + if err != nil { + return fmt.Errorf("failed creating %s: %s", pathFile, err) + } + b, err := yaml.Marshal(containerPaths{ + StatePath: statePath, + ConfigPath: configPath, + LogsPath: logsPath, + }) + if err != nil { + return fmt.Errorf("failed to marshal for %s: %s", pathFile, err) + } + _, err = fp.Write(b) + if err != nil { + return fmt.Errorf("failed to write %s: %s", pathFile, err) + } return nil } +func tryContainerLoadPaths() error { + pathFile := filepath.Join(paths.Top(), "container-paths.yml") + _, err := os.Stat(pathFile) + if os.IsNotExist(err) { + // no container-paths.yml file exists, so nothing to do + return nil + } + cfg, err := config.LoadFile(pathFile) + if err != nil { + return fmt.Errorf("failed to load %s: %s", pathFile, err) + } + var paths containerPaths + err = cfg.Unpack(&paths) + if err != nil { + return fmt.Errorf("failed to unpack %s: %s", pathFile, err) + } + return setPaths(paths.StatePath, paths.ConfigPath, paths.LogsPath, false) +} + func syncDir(src string, dest string) error { return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { if err != nil { diff --git a/x-pack/elastic-agent/pkg/agent/cmd/inspect.go b/x-pack/elastic-agent/pkg/agent/cmd/inspect.go index 294a8bda284f..16b589bf9d15 100644 --- a/x-pack/elastic-agent/pkg/agent/cmd/inspect.go +++ b/x-pack/elastic-agent/pkg/agent/cmd/inspect.go @@ -84,6 +84,11 @@ func newInspectOutputCommandWithArgs(_ []string, streams *cli.IOStreams) *cobra. } func inspectConfig(cfgPath string) error { + err := tryContainerLoadPaths() + if err != nil { + return err + } + fullCfg, err := operations.LoadFullAgentConfig(cfgPath, true) if err != nil { return err diff --git a/x-pack/elastic-agent/pkg/agent/cmd/status.go b/x-pack/elastic-agent/pkg/agent/cmd/status.go index d076c91ee418..f04da2762e59 100644 --- a/x-pack/elastic-agent/pkg/agent/cmd/status.go +++ b/x-pack/elastic-agent/pkg/agent/cmd/status.go @@ -48,6 +48,11 @@ func newStatusCommand(_ []string, streams *cli.IOStreams) *cobra.Command { } func statusCmd(streams *cli.IOStreams, cmd *cobra.Command, args []string) error { + err := tryContainerLoadPaths() + if err != nil { + return err + } + output, _ := cmd.Flags().GetString("output") outputFunc, ok := outputs[output] if !ok {