feat(agent): Allow specifying log directory via flag or env (#5915)

This commit is contained in:
Mathias Fredriksson 2023-01-30 18:39:52 +02:00 committed by GitHub
parent fa5b6125a9
commit f4d6afb01d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 114 additions and 4 deletions

View File

@ -60,6 +60,7 @@ const (
type Options struct {
Filesystem afero.Fs
LogDir string
TempDir string
ExchangeToken func(ctx context.Context) (string, error)
Client Client
@ -87,6 +88,12 @@ func New(options Options) io.Closer {
if options.TempDir == "" {
options.TempDir = os.TempDir()
}
if options.LogDir == "" {
if options.TempDir != os.TempDir() {
options.Logger.Debug(context.Background(), "log dir not set, using temp dir", slog.F("temp_dir", options.TempDir))
}
options.LogDir = options.TempDir
}
if options.ExchangeToken == nil {
options.ExchangeToken = func(ctx context.Context) (string, error) {
return "", nil
@ -102,6 +109,7 @@ func New(options Options) io.Closer {
client: options.Client,
exchangeToken: options.ExchangeToken,
filesystem: options.Filesystem,
logDir: options.LogDir,
tempDir: options.TempDir,
lifecycleUpdate: make(chan struct{}, 1),
}
@ -114,6 +122,7 @@ type agent struct {
client Client
exchangeToken func(ctx context.Context) (string, error)
filesystem afero.Fs
logDir string
tempDir string
reconnectingPTYs sync.Map
@ -582,7 +591,7 @@ func (a *agent) runStartupScript(ctx context.Context, script string) error {
}
a.logger.Info(ctx, "running startup script", slog.F("script", script))
writer, err := a.filesystem.OpenFile(filepath.Join(a.tempDir, "coder-startup-script.log"), os.O_CREATE|os.O_RDWR, 0o600)
writer, err := a.filesystem.OpenFile(filepath.Join(a.logDir, "coder-startup-script.log"), os.O_CREATE|os.O_RDWR, 0o600)
if err != nil {
return xerrors.Errorf("open startup script log file: %w", err)
}

View File

@ -29,6 +29,7 @@ import (
func workspaceAgent() *cobra.Command {
var (
auth string
logDir string
pprofAddress string
noReap bool
)
@ -55,7 +56,7 @@ func workspaceAgent() *cobra.Command {
// of zombie processes.
if reaper.IsInitProcess() && !noReap && isLinux {
logWriter := &lumberjack.Logger{
Filename: filepath.Join(os.TempDir(), "coder-agent-init.log"),
Filename: filepath.Join(logDir, "coder-agent-init.log"),
MaxSize: 5, // MB
}
defer logWriter.Close()
@ -91,7 +92,7 @@ func workspaceAgent() *cobra.Command {
go dumpHandler(ctx)
logWriter := &lumberjack.Logger{
Filename: filepath.Join(os.TempDir(), "coder-agent.log"),
Filename: filepath.Join(logDir, "coder-agent.log"),
MaxSize: 5, // MB
}
defer logWriter.Close()
@ -178,6 +179,7 @@ func workspaceAgent() *cobra.Command {
closer := agent.New(agent.Options{
Client: client,
Logger: logger,
LogDir: logDir,
ExchangeToken: func(ctx context.Context) (string, error) {
if exchangeToken == nil {
return client.SDK.SessionToken(), nil
@ -199,8 +201,9 @@ func workspaceAgent() *cobra.Command {
}
cliflag.StringVarP(cmd.Flags(), &auth, "auth", "", "CODER_AGENT_AUTH", "token", "Specify the authentication type to use for the agent")
cliflag.BoolVarP(cmd.Flags(), &noReap, "no-reap", "", "", false, "Do not start a process reaper.")
cliflag.StringVarP(cmd.Flags(), &logDir, "log-dir", "", "CODER_AGENT_LOG_DIR", os.TempDir(), "Specify the location for the agent log files")
cliflag.StringVarP(cmd.Flags(), &pprofAddress, "pprof-address", "", "CODER_AGENT_PPROF_ADDRESS", "127.0.0.1:6060", "The address to serve pprof.")
cliflag.BoolVarP(cmd.Flags(), &noReap, "no-reap", "", "", false, "Do not start a process reaper.")
return cmd
}

View File

@ -2,6 +2,8 @@ package cli_test
import (
"context"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
@ -14,10 +16,70 @@ import (
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/provisioner/echo"
"github.com/coder/coder/provisionersdk/proto"
"github.com/coder/coder/testutil"
)
func TestWorkspaceAgent(t *testing.T) {
t.Parallel()
t.Run("LogDirectory", func(t *testing.T) {
t.Parallel()
authToken := uuid.NewString()
client := coderdtest.New(t, &coderdtest.Options{
IncludeProvisionerDaemon: true,
})
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
ProvisionApply: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Complete{
Complete: &proto.Provision_Complete{
Resources: []*proto.Resource{{
Name: "somename",
Type: "someinstance",
Agents: []*proto.Agent{{
Id: uuid.NewString(),
Name: "someagent",
Auth: &proto.Agent_Token{
Token: authToken,
},
}},
}},
},
},
}},
})
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
logDir := t.TempDir()
cmd, _ := clitest.New(t,
"agent",
"--auth", "token",
"--agent-token", authToken,
"--agent-url", client.URL.String(),
"--log-dir", logDir,
)
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium)
defer cancel()
errC := make(chan error, 1)
go func() {
errC <- cmd.ExecuteContext(ctx)
}()
coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID)
cancel()
err := <-errC
require.NoError(t, err)
info, err := os.Stat(filepath.Join(logDir, "coder-agent.log"))
require.NoError(t, err)
require.Greater(t, info.Size(), int64(0))
})
t.Run("Azure", func(t *testing.T) {
t.Parallel()
instanceID := "instanceidentifier"

View File

@ -53,6 +53,13 @@ func TestCommandHelp(t *testing.T) {
"CODER_CACHE_DIRECTORY": "/tmp/coder-cli-test-cache",
},
},
{
name: "coder agent --help",
cmd: []string{"agent", "--help"},
env: map[string]string{
"CODER_AGENT_LOG_DIR": "/tmp",
},
},
}
root := cli.Root(cli.AGPL())

29
cli/testdata/coder_agent_--help.golden vendored Normal file
View File

@ -0,0 +1,29 @@
Usage:
coder agent [flags]
Flags:
--auth string Specify the authentication type to use for the agent.
Consumes $CODER_AGENT_AUTH (default "token")
-h, --help help for agent
--log-dir string Specify the location for the agent log files.
Consumes $CODER_AGENT_LOG_DIR (default "/tmp")
--no-reap Do not start a process reaper.
--pprof-address string The address to serve pprof.
Consumes $CODER_AGENT_PPROF_ADDRESS (default "127.0.0.1:6060")
Global Flags:
--global-config coder Path to the global coder config directory.
Consumes $CODER_CONFIG_DIR (default "/tmp/coder-cli-test-config")
--header stringArray HTTP headers added to all requests. Provide as "Key=Value".
Consumes $CODER_HEADER
--no-feature-warning Suppress warnings about unlicensed features.
Consumes $CODER_NO_FEATURE_WARNING
--no-version-warning Suppress warning when client and server versions do not match.
Consumes $CODER_NO_VERSION_WARNING
--token string Specify an authentication token. For security reasons setting
CODER_SESSION_TOKEN is preferred.
Consumes $CODER_SESSION_TOKEN
--url string URL to a deployment.
Consumes $CODER_URL
-v, --verbose Enable verbose output.
Consumes $CODER_VERBOSE