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

VAULT-9900: Log rotation for 'agent' and 'server' commands #18031

Merged
merged 44 commits into from
Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
134d0b0
Initial work to unify log-file for agent/server and add rotation
Nov 11, 2022
82416d7
Updates to rotation code, tried to centralise the log config setup
Nov 14, 2022
71d0e0f
Removed the named part of log files in server cmd
Nov 14, 2022
561cafc
Merge branch 'main' into VAULT-9900-log-file-rotate
Nov 15, 2022
11b2469
logging + tests
Nov 15, 2022
a6ba065
Revert server.go for now, tweaks to agent
Nov 16, 2022
eb9dd87
Move LogFile to ShareConfig in test
Nov 16, 2022
1888b78
drop reassignment for updateConfig
Nov 16, 2022
4a4cf8a
Bit of a clean up, and attempt to add logging to server cmd
Nov 16, 2022
8558aee
combineLogs flag in server, cleaned up unused func
Nov 16, 2022
dd6d0ef
Merge branch 'main' into VAULT-9900-log-file-rotate
Nov 16, 2022
fa08494
Merge branch 'main' into VAULT-9900-log-file-rotate
Nov 17, 2022
c333ebe
We already add the logger once it's setup
Nov 17, 2022
50299f2
Basic test for log_flags
Nov 17, 2022
09e3424
Add the flags (and remove ones in cmd)
Nov 17, 2022
5437e45
Don't redefine some log flags
Nov 17, 2022
f935293
Merge branch 'main' into VAULT-9900-log-file-rotate
Nov 17, 2022
2d3d344
Docs
Nov 18, 2022
bfa65ac
changelog added
Nov 18, 2022
8395310
removed commented out code in logger test
Nov 18, 2022
0fb186b
Match docs for server/agent
Nov 18, 2022
28506f5
styling tweak to docs
Nov 18, 2022
ca956b5
Docs: typo + config options
Nov 18, 2022
7f2796a
docs: re-org of config
Nov 18, 2022
8e79d2f
fix anchors
Nov 18, 2022
a890155
Reload config, update docs, centralise config for server values
Nov 18, 2022
8afd752
typo :(
Nov 18, 2022
1d88e83
Updates from PR feedback - thanks Mike
Nov 19, 2022
5eb5282
Add nil check for recevier
Nov 19, 2022
be410aa
Handle removing file errors better, track bytes written even on errorr
Nov 21, 2022
4690b6e
Check correct error
Nov 21, 2022
e503105
Sanitize log file name and dir on Setup
Nov 21, 2022
1bd0290
Move 'combine-logs' flag to logFlags
Nov 22, 2022
7ac723d
Fix bad multierror append calls
Nov 22, 2022
9aa1c8f
More globbing chars checked for
Nov 22, 2022
895c9bc
Merge branch 'main' into VAULT-9900-log-file-rotate
Nov 24, 2022
21e6a17
maxFiles => maxArchivedFiles
Nov 24, 2022
a9bed51
Named logger restored to test
Nov 24, 2022
5ae834c
Not sure table driven was required for this test
Nov 24, 2022
5bdbc01
Removed env vars for log rotation
Nov 24, 2022
35c2e01
Scrap env var tests, fix pointer snafu, combine logs moved to logFlags
Nov 24, 2022
14c8ccf
Merge branch 'main' into VAULT-9900-log-file-rotate
Nov 24, 2022
537804e
don't need to export log flags outside the command (so far)
Nov 25, 2022
479a504
Merge branch 'main' into VAULT-9900-log-file-rotate
Nov 28, 2022
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
3 changes: 3 additions & 0 deletions changelog/18031.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:feature
logging: Vault agent and server commands support log file and log rotation.
```
103 changes: 46 additions & 57 deletions command/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
systemd "github.com/coreos/go-systemd/daemon"
log "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-secure-stdlib/gatedwriter"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/command/agent/auth"
"github.com/hashicorp/vault/command/agent/auth/alicloud"
Expand Down Expand Up @@ -69,6 +70,7 @@ const (

type AgentCommand struct {
*BaseCommand
logFlags logFlags

ShutdownCh chan struct{}
SighupCh chan struct{}
Expand All @@ -84,13 +86,9 @@ type AgentCommand struct {

startedCh chan (struct{}) // for tests

flagConfigs []string
flagLogLevel string
flagLogFile string
flagExitAfterAuth bool

flagConfigs []string
flagExitAfterAuth bool
flagTestVerifyOnly bool
flagCombineLogs bool
}

func (c *AgentCommand) Synopsis() string {
Expand Down Expand Up @@ -119,6 +117,9 @@ func (c *AgentCommand) Flags() *FlagSets {

f := set.NewFlagSet("Command Options")

// Augment with the log flags
f.addLogFlags(&c.logFlags)

f.StringSliceVar(&StringSliceVar{
Name: "config",
Target: &c.flagConfigs,
Expand All @@ -130,23 +131,6 @@ func (c *AgentCommand) Flags() *FlagSets {
"contain only agent directives.",
})

f.StringVar(&StringVar{
Name: flagNameLogLevel,
Target: &c.flagLogLevel,
Default: "info",
EnvVar: EnvVaultLogLevel,
Completion: complete.PredictSet("trace", "debug", "info", "warn", "error"),
Usage: "Log verbosity level. Supported values (in order of detail) are " +
"\"trace\", \"debug\", \"info\", \"warn\", and \"error\".",
})

f.StringVar(&StringVar{
Name: flagNameLogFile,
Target: &c.flagLogFile,
EnvVar: EnvVaultLogFile,
Usage: "Path to the log file that Vault should use for logging",
})

f.BoolVar(&BoolVar{
Name: flagNameAgentExitAfterAuth,
Target: &c.flagExitAfterAuth,
Expand All @@ -163,15 +147,6 @@ func (c *AgentCommand) Flags() *FlagSets {
// no warranty or backwards-compatibility promise. Do not use these flags
// in production. Do not build automation using these flags. Unless you are
// developing against Vault, you should not need any of these flags.

// TODO: should the below flags be public?
f.BoolVar(&BoolVar{
Name: "combine-logs",
Target: &c.flagCombineLogs,
Default: false,
Hidden: true,
})

f.BoolVar(&BoolVar{
Name: "test-verify-only",
Target: &c.flagTestVerifyOnly,
Expand Down Expand Up @@ -204,7 +179,8 @@ func (c *AgentCommand) Run(args []string) int {
// start logging too early.
c.logGate = gatedwriter.NewWriter(os.Stderr)
c.logWriter = c.logGate
if c.flagCombineLogs {

if c.logFlags.flagCombineLogs {
c.logWriter = os.Stdout
}

Expand Down Expand Up @@ -237,9 +213,9 @@ func (c *AgentCommand) Run(args []string) int {
c.UI.Info("No auto_auth block found in config file, not starting automatic authentication feature")
}

config = c.aggregateConfig(f, config)
c.updateConfig(f, config)

// Build the logger using level, format and path
// Parse all the log related config
logLevel, err := logging.ParseLogLevel(config.LogLevel)
if err != nil {
c.UI.Error(err.Error())
Expand All @@ -252,7 +228,34 @@ func (c *AgentCommand) Run(args []string) int {
return 1
}

logCfg := logging.NewLogConfig("agent", logLevel, logFormat, config.LogFile)
logRotateDuration, err := parseutil.ParseDurationSecond(config.LogRotateDuration)
if err != nil {
c.UI.Error(err.Error())
return 1
}

logRotateBytes, err := parseutil.ParseInt(config.LogRotateBytes)
if err != nil {
c.UI.Error(err.Error())
return 1
}

logRotateMaxFiles, err := parseutil.ParseInt(config.LogRotateMaxFiles)
if err != nil {
c.UI.Error(err.Error())
return 1
}

logCfg := &logging.LogConfig{
Name: "vault-agent",
LogLevel: logLevel,
LogFormat: logFormat,
LogFilePath: config.LogFile,
LogRotateDuration: logRotateDuration,
LogRotateBytes: int(logRotateBytes),
LogRotateMaxFiles: int(logRotateMaxFiles),
}

l, err := logging.Setup(logCfg, c.logWriter)
if err != nil {
c.UI.Error(err.Error())
Expand All @@ -263,7 +266,7 @@ func (c *AgentCommand) Run(args []string) int {

infoKeys := make([]string, 0, 10)
info := make(map[string]string)
info["log level"] = c.flagLogLevel
info["log level"] = config.LogLevel
infoKeys = append(infoKeys, "log level")

infoKeys = append(infoKeys, "version")
Expand Down Expand Up @@ -457,7 +460,7 @@ func (c *AgentCommand) Run(args []string) int {
}

// Output the header that the agent has started
if !c.flagCombineLogs {
if !c.logFlags.flagCombineLogs {
c.UI.Output("==> Vault agent started! Log data will stream in below:\n")
}

Expand Down Expand Up @@ -924,31 +927,19 @@ func (c *AgentCommand) Run(args []string) int {
return 0
}

// aggregateConfig ensures that the config object accurately reflects the desired
// updateConfig ensures that the config object accurately reflects the desired
// settings as configured by the user. It applies the relevant config setting based
// on the precedence (env var overrides file config, cli overrides env var).
// It mutates the config object supplied and returns the updated object.
func (c *AgentCommand) aggregateConfig(f *FlagSets, config *agentConfig.Config) *agentConfig.Config {
// It mutates the config object supplied.
func (c *AgentCommand) updateConfig(f *FlagSets, config *agentConfig.Config) {
f.updateLogConfig(config.SharedConfig)

f.Visit(func(fl *flag.Flag) {
if fl.Name == flagNameAgentExitAfterAuth {
config.ExitAfterAuth = c.flagExitAfterAuth
}
})

c.setStringFlag(f, config.LogFile, &StringVar{
Name: flagNameLogFile,
EnvVar: EnvVaultLogFile,
Target: &c.flagLogFile,
})
config.LogFile = c.flagLogFile

c.setStringFlag(f, config.LogLevel, &StringVar{
Name: flagNameLogLevel,
EnvVar: EnvVaultLogLevel,
Target: &c.flagLogLevel,
})
config.LogLevel = c.flagLogLevel

c.setStringFlag(f, config.Vault.Address, &StringVar{
Name: flagNameAddress,
Target: &c.flagAddress,
Expand Down Expand Up @@ -998,8 +989,6 @@ func (c *AgentCommand) aggregateConfig(f *FlagSets, config *agentConfig.Config)
EnvVar: api.EnvVaultTLSServerName,
})
config.Vault.TLSServerName = c.flagTLSServerName

return config
}

// verifyRequestHeader wraps an http.Handler inside a Handler that checks for
Expand Down
1 change: 0 additions & 1 deletion command/agent/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ type Config struct {
DisableKeepAlivesCaching bool `hcl:"-"`
DisableKeepAlivesTemplating bool `hcl:"-"`
DisableKeepAlivesAutoAuth bool `hcl:"-"`
LogFile string `hcl:"log_file"`
}

const (
Expand Down
2 changes: 1 addition & 1 deletion command/agent/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ func TestLoadConfigFile(t *testing.T) {
expected := &Config{
SharedConfig: &configutil.SharedConfig{
PidFile: "./pidfile",
LogFile: "/var/log/vault/vault-agent.log",
},
AutoAuth: &AutoAuth{
Method: &Method{
Expand Down Expand Up @@ -230,7 +231,6 @@ func TestLoadConfigFile(t *testing.T) {
NumRetries: 12,
},
},
LogFile: "/var/log/vault/vault-agent.log",
}

config.Prune()
Expand Down
53 changes: 3 additions & 50 deletions command/agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2250,7 +2250,7 @@ cache {}
wg.Wait()
}

func TestAgent_LogFile_EnvVarOverridesConfig(t *testing.T) {
func TestAgent_LogFile_CliOverridesConfig(t *testing.T) {
// Create basic config
configFile := populateTempFile(t, "agent-config.hcl", BasicHclConfig)
cfg, err := agentConfig.LoadConfig(configFile.Name())
Expand All @@ -2261,50 +2261,6 @@ func TestAgent_LogFile_EnvVarOverridesConfig(t *testing.T) {
// Sanity check that the config value is the current value
assert.Equal(t, "/foo/bar/juan.log", cfg.LogFile)

// Make sure the env var is configured
oldEnvVarLogFile := os.Getenv(EnvVaultLogFile)
os.Setenv(EnvVaultLogFile, "/squiggle/logs.txt")
if oldEnvVarLogFile == "" {
defer os.Unsetenv(EnvVaultLogFile)
} else {
defer os.Setenv(EnvVaultLogFile, oldEnvVarLogFile)
}

// Initialize the command and parse any flags
cmd := &AgentCommand{BaseCommand: &BaseCommand{}}
f := cmd.Flags()
err = f.Parse([]string{})
if err != nil {
t.Fatal(err)
}

// Update the config based on the inputs.
cfg = cmd.aggregateConfig(f, cfg)

assert.NotEqual(t, "/foo/bar/juan.log", cfg.LogFile)
assert.Equal(t, "/squiggle/logs.txt", cfg.LogFile)
}

func TestAgent_LogFile_CliOverridesEnvVar(t *testing.T) {
// Create basic config
configFile := populateTempFile(t, "agent-config.hcl", BasicHclConfig)
cfg, err := agentConfig.LoadConfig(configFile.Name())
if err != nil {
t.Fatal("Cannot load config to test update/merge", err)
}

// Sanity check that the config value is the current value
assert.Equal(t, "/foo/bar/juan.log", cfg.LogFile)

// Make sure the env var is configured
oldEnvVarLogFile := os.Getenv(EnvVaultLogFile)
os.Setenv(EnvVaultLogFile, "/squiggle/logs.txt")
if oldEnvVarLogFile == "" {
defer os.Unsetenv(EnvVaultLogFile)
} else {
defer os.Setenv(EnvVaultLogFile, oldEnvVarLogFile)
}

// Initialize the command and parse any flags
cmd := &AgentCommand{BaseCommand: &BaseCommand{}}
f := cmd.Flags()
Expand All @@ -2315,17 +2271,14 @@ func TestAgent_LogFile_CliOverridesEnvVar(t *testing.T) {
}

// Update the config based on the inputs.
cfg = cmd.aggregateConfig(f, cfg)
cmd.updateConfig(f, cfg)

assert.NotEqual(t, "/foo/bar/juan.log", cfg.LogFile)
assert.NotEqual(t, "/squiggle/logs.txt", cfg.LogFile)
assert.Equal(t, "/foo/bar/test.log", cfg.LogFile)
}

func TestAgent_LogFile_Config(t *testing.T) {
// Sanity check, remove any env var
os.Unsetenv(EnvVaultLogFile)

configFile := populateTempFile(t, "agent-config.hcl", BasicHclConfig)

cfg, err := agentConfig.LoadConfig(configFile.Name())
Expand All @@ -2344,7 +2297,7 @@ func TestAgent_LogFile_Config(t *testing.T) {
t.Fatal(err)
}

cfg = cmd.aggregateConfig(f, cfg)
cmd.updateConfig(f, cfg)

assert.Equal(t, "/foo/bar/juan.log", cfg.LogFile, "actual config check")
}
Expand Down
14 changes: 12 additions & 2 deletions command/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ const (
EnvVaultLicensePath = "VAULT_LICENSE_PATH"
// EnvVaultDetailed is to output detailed information (e.g., ListResponseWithInfo).
EnvVaultDetailed = `VAULT_DETAILED`
// EnvVaultLogFile is used to specify the path to the log file that Vault should use for logging
EnvVaultLogFile = "VAULT_LOG_FILE"
// EnvVaultLogFormat is used to specify the log format. Supported values are "standard" and "json"
EnvVaultLogFormat = "VAULT_LOG_FORMAT"
// EnvVaultLogLevel is used to specify the log level applied to logging
// Supported log levels: Trace, Debug, Error, Warn, Info
EnvVaultLogLevel = "VAULT_LOG_LEVEL"
Expand Down Expand Up @@ -141,8 +141,18 @@ const (
flagNameUserLockoutDisable = "user-lockout-disable"
// flagNameDisableRedirects is used to prevent the client from honoring a single redirect as a response to a request
flagNameDisableRedirects = "disable-redirects"
// flagNameCombineLogs is used to specify whether log output should be combined and sent to stdout
flagNameCombineLogs = "combine-logs"
// flagNameLogFile is used to specify the path to the log file that Vault should use for logging
flagNameLogFile = "log-file"
// flagNameLogRotateBytes is the flag used to specify the number of bytes a log file should be before it is rotated.
flagNameLogRotateBytes = "log-rotate-bytes"
// flagNameLogRotateDuration is the flag used to specify the duration after which a log file should be rotated.
flagNameLogRotateDuration = "log-rotate-duration"
// flagNameLogRotateMaxFiles is the flag used to specify the maximum number of older/archived log files to keep.
flagNameLogRotateMaxFiles = "log-rotate-max-files"
// flagNameLogFormat is the flag used to specify the log format. Supported values are "standard" and "json"
flagNameLogFormat = "log-format"
// flagNameLogLevel is used to specify the log level applied to logging
// Supported log levels: Trace, Debug, Error, Warn, Info
flagNameLogLevel = "log-level"
Expand Down
Loading