Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Elastic Agent] Fix status and inspect command to work inside running container #25204

Merged
merged 2 commits into from
Apr 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions x-pack/elastic-agent/CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
- Respect host configuration for exposed processes endpoint {pull}25114[25114]
- Set --inscure in container when FLEET_SERVER_ENABLE and FLEET_INSECURE set {pull}25137[25137]
- Fixed: limit for retries to Kibana configurable {issue}25063[25063]
- Fix issue with status and inspect inside of container {pull}25204[25204]

==== New features

- Prepare packaging for endpoint and asc files {pull}20186[20186]
Expand Down
67 changes: 61 additions & 6 deletions x-pack/elastic-agent/pkg/agent/cmd/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
}
Expand All @@ -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")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a new file for this or could we use an existing "state" file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is only specific to running in container mode. Being that Elastic Agent ships with pre-built binaries and the state will normally be mounted from a volume we need to do a lot to ensure that the containers paths are correct.

The code will not know the path of state.yml because that is based on the STATE_PATH adjusting that location. So we use a unique file to just do this one thing, for the status and inspect commands. All other commands should either not be used in the container or are used as children of the container command itself.

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 {
Expand Down
5 changes: 5 additions & 0 deletions x-pack/elastic-agent/pkg/agent/cmd/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions x-pack/elastic-agent/pkg/agent/cmd/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down