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 invalid log level sent to endpoint #25854

Merged
merged 6 commits into from
May 28, 2021
Merged
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions x-pack/elastic-agent/CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
- Add error log entry when listener creation fails {issue}23483[23482]
- Handle case where policy doesn't contain Fleet connection information {pull}25707[25707]
- Fix fleet-server.yml spec to not overwrite existing keys {pull}25741[25741]
- Agent sends wrong log level to Endpoint {issue}25583[25583]

==== New features

Expand Down
3 changes: 2 additions & 1 deletion x-pack/elastic-agent/pkg/agent/application/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ func createApplication(

func mergeFleetConfig(rawConfig *config.Config) (storage.Store, *configuration.Configuration, error) {
path := paths.AgentConfigFile()
store := storage.NewDiskStore(path)
diskStore := storage.NewDiskStore(path)
store := storage.NewWindowsSyncOnSaveStore(diskStore, path)
reader, err := store.Load()
if err != nil {
return store, nil, errors.New(err, "could not initialize config store",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ func withGateway(agentInfo agentInfo, settings *fleetGatewaySettings, fn withGat
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

stateStore, err := store.NewStateStore(log, storage.NewDiskStore(paths.AgentStateStoreFile()))
diskStore := storage.NewDiskStore(paths.AgentStateStoreFile())
syncStore := storage.NewWindowsSyncOnSaveStore(diskStore, paths.AgentStateStoreFile())
stateStore, err := store.NewStateStore(log, syncStore)
require.NoError(t, err)

gateway, err := newFleetGatewayWithScheduler(
Expand Down Expand Up @@ -253,7 +255,10 @@ func TestFleetGateway(t *testing.T) {
defer cancel()

log, _ := logger.New("tst", false)
stateStore, err := store.NewStateStore(log, storage.NewDiskStore(paths.AgentStateStoreFile()))

diskStore := storage.NewDiskStore(paths.AgentStateStoreFile())
syncStore := storage.NewWindowsSyncOnSaveStore(diskStore, paths.AgentStateStoreFile())
stateStore, err := store.NewStateStore(log, syncStore)
require.NoError(t, err)

gateway, err := newFleetGatewayWithScheduler(
Expand Down Expand Up @@ -344,7 +349,9 @@ func TestFleetGateway(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
log, _ := logger.New("tst", false)

stateStore, err := store.NewStateStore(log, storage.NewDiskStore(paths.AgentStateStoreFile()))
diskStore := storage.NewDiskStore(paths.AgentStateStoreFile())
syncStore := storage.NewWindowsSyncOnSaveStore(diskStore, paths.AgentStateStoreFile())
stateStore, err := store.NewStateStore(log, syncStore)
require.NoError(t, err)

gateway, err := newFleetGatewayWithScheduler(
Expand Down
12 changes: 7 additions & 5 deletions x-pack/elastic-agent/pkg/agent/application/info/agent_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ func updateLogLevel(level string) error {
}

agentConfigFile := paths.AgentConfigFile()
s := storage.NewDiskStore(agentConfigFile)
diskStore := storage.NewDiskStore(agentConfigFile)
syncStore := storage.NewWindowsSyncOnSaveStore(diskStore, agentConfigFile)

ai.LogLevel = level
return updateAgentInfo(s, ai)
return updateAgentInfo(syncStore, ai)
}

func generateAgentID() (string, error) {
Expand Down Expand Up @@ -191,9 +192,10 @@ func loadAgentInfo(forceUpdate bool, logLevel string, createAgentID bool) (*pers
defer idLock.Unlock()

agentConfigFile := paths.AgentConfigFile()
s := storage.NewDiskStore(agentConfigFile)
diskStore := storage.NewDiskStore(agentConfigFile)
syncStore := storage.NewWindowsSyncOnSaveStore(diskStore, agentConfigFile)

agentinfo, err := getInfoFromStore(s, logLevel)
agentinfo, err := getInfoFromStore(syncStore, logLevel)
if err != nil {
return nil, err
}
Expand All @@ -202,7 +204,7 @@ func loadAgentInfo(forceUpdate bool, logLevel string, createAgentID bool) (*pers
return agentinfo, nil
}

if err := updateID(agentinfo, s); err != nil {
if err := updateID(agentinfo, syncStore); err != nil {
return nil, err
}

Expand Down
13 changes: 11 additions & 2 deletions x-pack/elastic-agent/pkg/agent/application/info/agent_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package info

import (
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/logger"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/release"
)

Expand Down Expand Up @@ -41,8 +42,16 @@ func NewAgentInfo(createAgentID bool) (*AgentInfo, error) {
return NewAgentInfoWithLog(defaultLogLevel, createAgentID)
}

// LogLevel updates log level of agent.
func (i *AgentInfo) LogLevel(level string) error {
// LogLevel retrieves a log level.
func (i *AgentInfo) LogLevel() string {
if i.logLevel == "" {
return logger.DefaultLogLevel.String()
}
return i.logLevel
}

// SetLogLevel updates log level of agent.
func (i *AgentInfo) SetLogLevel(level string) error {
if err := updateLogLevel(level); err != nil {
return err
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func (i *AgentInfo) ECSMetadata() (*ECSMeta, error) {
// only upgradeable if running from Agent installer and running under the
// control of the system supervisor (or built specifically with upgrading enabled)
Upgradeable: release.Upgradeable() || (RunningInstalled() && RunningUnderSupervisor()),
LogLevel: i.logLevel,
LogLevel: i.LogLevel(),
},
},
Host: &HostECSMeta{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (h *Settings) Handle(ctx context.Context, a fleetapi.Action, acker store.Fl
return fmt.Errorf("invalid log level, expected debug|info|warning|error and received '%s'", action.LogLevel)
}

if err := h.agentInfo.LogLevel(action.LogLevel); err != nil {
if err := h.agentInfo.SetLogLevel(action.LogLevel); err != nil {
return errors.New("failed to update log level", err)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@ import (
// InjectFleet injects fleet metadata into a configuration.
func InjectFleet(cfg *config.Config, hostInfo types.HostInfo, agentInfo *info.AgentInfo) func(*logger.Logger, *transpiler.AST) error {
return func(logger *logger.Logger, rootAst *transpiler.AST) error {
ecsMeta, err := agentInfo.ECSMetadata()
if err != nil {
return err
}
logLevel := ecsMeta.Elastic.Agent.LogLevel

config, err := cfg.ToMapStr()
if err != nil {
return err
Expand All @@ -46,7 +40,7 @@ func InjectFleet(cfg *config.Config, hostInfo types.HostInfo, agentInfo *info.Ag

// ensure that the agent.logging.level is present
if _, found := transpiler.Lookup(ast, "agent.logging.level"); !found {
transpiler.Insert(ast, transpiler.NewKey("level", transpiler.NewStrVal(logLevel)), "agent.logging")
transpiler.Insert(ast, transpiler.NewKey("level", transpiler.NewStrVal(agentInfo.LogLevel())), "agent.logging")
}

// fleet.host to Agent can be the host to connect to Fleet Server, but to Applications it should
Expand Down
4 changes: 3 additions & 1 deletion x-pack/elastic-agent/pkg/agent/cmd/enroll_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,13 @@ func newEnrollCmd(
storage.NewDiskStore(paths.AgentConfigFile()),
)

syncStore := storage.NewWindowsSyncOnSaveStore(store, paths.AgentStateStoreFile())

return newEnrollCmdWithStore(
log,
options,
configPath,
store,
syncStore,
)
}

Expand Down
5 changes: 3 additions & 2 deletions x-pack/elastic-agent/pkg/agent/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,9 @@ func getOverwrites(rawConfig *config.Config) error {
return nil
}
path := paths.AgentConfigFile()
diskStore := storage.NewDiskStore(path)
store := storage.NewWindowsSyncOnSaveStore(diskStore, path)

store := storage.NewDiskStore(path)
reader, err := store.Load()
if err != nil && errors.Is(err, os.ErrNotExist) {
// no fleet file ignore
Expand Down Expand Up @@ -262,7 +263,7 @@ func defaultLogLevel(cfg *configuration.Configuration) string {
return ""
}

defaultLogLevel := logger.DefaultLoggingConfig().Level.String()
defaultLogLevel := logger.DefaultLogLevel.String()
if configuredLevel := cfg.Settings.LoggingConfig.Level.String(); configuredLevel != "" && configuredLevel != defaultLogLevel {
// predefined log level
return configuredLevel
Expand Down
96 changes: 96 additions & 0 deletions x-pack/elastic-agent/pkg/agent/storage/disk_store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// 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 storage

import (
"fmt"
"io"
"os"

"github.com/hectane/go-acl"

"github.com/elastic/beats/v7/libbeat/common/file"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/errors"
)

// NewDiskStore creates an unencrypted disk store.
func NewDiskStore(target string) *DiskStore {
return &DiskStore{target: target}
}

// Exists check if the store file exists on the disk
func (d *DiskStore) Exists() (bool, error) {
_, err := os.Stat(d.target)
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
return true, nil
}

// Delete deletes the store file on the disk
func (d *DiskStore) Delete() error {
return os.Remove(d.target)
}

// Save accepts a persistedConfig and saved it to a target file, to do so we will
// make a temporary files if the write is successful we are replacing the target file with the
// original content.
func (d *DiskStore) Save(in io.Reader) error {
tmpFile := d.target + ".tmp"

fd, err := os.OpenFile(tmpFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, perms)
Copy link

Choose a reason for hiding this comment

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

You might want to open your file with O_DIRECT.

if err != nil {
return errors.New(err,
fmt.Sprintf("could not save to %s", tmpFile),
errors.TypeFilesystem,
errors.M(errors.MetaKeyPath, tmpFile))
}

// Always clean up the temporary file and ignore errors.
defer os.Remove(tmpFile)

if _, err := io.Copy(fd, in); err != nil {
return errors.New(err, "could not save content on disk",
errors.TypeFilesystem,
errors.M(errors.MetaKeyPath, tmpFile))
}

if err := fd.Close(); err != nil {
urso marked this conversation as resolved.
Show resolved Hide resolved
return errors.New(err, "could not close temporary file",
errors.TypeFilesystem,
errors.M(errors.MetaKeyPath, tmpFile))
}

if err := file.SafeFileRotate(d.target, tmpFile); err != nil {
return errors.New(err,
fmt.Sprintf("could not replace target file %s", d.target),
errors.TypeFilesystem,
errors.M(errors.MetaKeyPath, d.target))
}

if err := acl.Chmod(d.target, perms); err != nil {
return errors.New(err,
fmt.Sprintf("could not set permissions target file %s", d.target),
errors.TypeFilesystem,
errors.M(errors.MetaKeyPath, d.target))
}

return nil
}

// Load return a io.ReadCloser for the target file.
func (d *DiskStore) Load() (io.ReadCloser, error) {
fd, err := os.OpenFile(d.target, os.O_RDONLY|os.O_CREATE, perms)
if err != nil {
return nil, errors.New(err,
fmt.Sprintf("could not open %s", d.target),
errors.TypeFilesystem,
errors.M(errors.MetaKeyPath, d.target))
}
return fd, nil
}
24 changes: 24 additions & 0 deletions x-pack/elastic-agent/pkg/agent/storage/handler_store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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 storage

import "io"

type handlerFunc func(io.Reader) error

// HandlerStore take a function handler and wrap it into the store interface.
type HandlerStore struct {
fn handlerFunc
}

// NewHandlerStore takes a function and wrap it into an handlerStore.
func NewHandlerStore(fn handlerFunc) *HandlerStore {
return &HandlerStore{fn: fn}
}

// Save calls the handler.
func (h *HandlerStore) Save(in io.Reader) error {
return h.fn(in)
}
15 changes: 15 additions & 0 deletions x-pack/elastic-agent/pkg/agent/storage/null_store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// 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 storage

import "io"

// NullStore this is only use to split the work into multiples PRs.
type NullStore struct{}

// Save takes the fleetConfig and persist it, will return an errors on failure.
func (m *NullStore) Save(_ io.Reader) error {
return nil
}
Loading