Skip to content

Commit 11983ab

Browse files
committed
Merge remote-tracking branch 'origin/main' into authzquerier_layer
2 parents 161842d + ac4adab commit 11983ab

36 files changed

+344
-90
lines changed

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
<div align="center">
2-
<img src="./docs/images/logo.png" style="width: 128px">
2+
<a href="https://coder.com#gh-light-mode-only">
3+
<img src="./docs/images/logo-black.png" style="width: 128px">
4+
</a>
5+
<a href="https://coder.com#gh-dark-mode-only">
6+
<img src="./docs/images/logo-white.png" style="width: 128px">
7+
</a>
38

49
<h1>
510
Self-Hosted Remote Development Environments
611
</h1>
712

8-
<img src="./docs/images/banner.png" style="width: 650px">
13+
<a href="https://coder.com#gh-light-mode-only">
14+
<img src="./docs/images/banner-black.png" style="width: 650px">
15+
</a>
16+
<a href="https://coder.com#gh-dark-mode-only">
17+
<img src="./docs/images/banner-white.png" style="width: 650px">
18+
</a>
919

1020
<br>
1121
<br>

agent/agent.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ const (
6060

6161
type Options struct {
6262
Filesystem afero.Fs
63+
LogDir string
6364
TempDir string
6465
ExchangeToken func(ctx context.Context) (string, error)
6566
Client Client
@@ -87,6 +88,12 @@ func New(options Options) io.Closer {
8788
if options.TempDir == "" {
8889
options.TempDir = os.TempDir()
8990
}
91+
if options.LogDir == "" {
92+
if options.TempDir != os.TempDir() {
93+
options.Logger.Debug(context.Background(), "log dir not set, using temp dir", slog.F("temp_dir", options.TempDir))
94+
}
95+
options.LogDir = options.TempDir
96+
}
9097
if options.ExchangeToken == nil {
9198
options.ExchangeToken = func(ctx context.Context) (string, error) {
9299
return "", nil
@@ -102,6 +109,7 @@ func New(options Options) io.Closer {
102109
client: options.Client,
103110
exchangeToken: options.ExchangeToken,
104111
filesystem: options.Filesystem,
112+
logDir: options.LogDir,
105113
tempDir: options.TempDir,
106114
lifecycleUpdate: make(chan struct{}, 1),
107115
}
@@ -114,6 +122,7 @@ type agent struct {
114122
client Client
115123
exchangeToken func(ctx context.Context) (string, error)
116124
filesystem afero.Fs
125+
logDir string
117126
tempDir string
118127

119128
reconnectingPTYs sync.Map
@@ -582,7 +591,7 @@ func (a *agent) runStartupScript(ctx context.Context, script string) error {
582591
}
583592

584593
a.logger.Info(ctx, "running startup script", slog.F("script", script))
585-
writer, err := a.filesystem.OpenFile(filepath.Join(a.tempDir, "coder-startup-script.log"), os.O_CREATE|os.O_RDWR, 0o600)
594+
writer, err := a.filesystem.OpenFile(filepath.Join(a.logDir, "coder-startup-script.log"), os.O_CREATE|os.O_RDWR, 0o600)
586595
if err != nil {
587596
return xerrors.Errorf("open startup script log file: %w", err)
588597
}

cli/agent.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
func workspaceAgent() *cobra.Command {
3030
var (
3131
auth string
32+
logDir string
3233
pprofAddress string
3334
noReap bool
3435
)
@@ -55,7 +56,7 @@ func workspaceAgent() *cobra.Command {
5556
// of zombie processes.
5657
if reaper.IsInitProcess() && !noReap && isLinux {
5758
logWriter := &lumberjack.Logger{
58-
Filename: filepath.Join(os.TempDir(), "coder-agent-init.log"),
59+
Filename: filepath.Join(logDir, "coder-agent-init.log"),
5960
MaxSize: 5, // MB
6061
}
6162
defer logWriter.Close()
@@ -91,7 +92,7 @@ func workspaceAgent() *cobra.Command {
9192
go dumpHandler(ctx)
9293

9394
logWriter := &lumberjack.Logger{
94-
Filename: filepath.Join(os.TempDir(), "coder-agent.log"),
95+
Filename: filepath.Join(logDir, "coder-agent.log"),
9596
MaxSize: 5, // MB
9697
}
9798
defer logWriter.Close()
@@ -178,6 +179,7 @@ func workspaceAgent() *cobra.Command {
178179
closer := agent.New(agent.Options{
179180
Client: client,
180181
Logger: logger,
182+
LogDir: logDir,
181183
ExchangeToken: func(ctx context.Context) (string, error) {
182184
if exchangeToken == nil {
183185
return client.SDK.SessionToken(), nil
@@ -199,8 +201,9 @@ func workspaceAgent() *cobra.Command {
199201
}
200202

201203
cliflag.StringVarP(cmd.Flags(), &auth, "auth", "", "CODER_AGENT_AUTH", "token", "Specify the authentication type to use for the agent")
202-
cliflag.BoolVarP(cmd.Flags(), &noReap, "no-reap", "", "", false, "Do not start a process reaper.")
204+
cliflag.StringVarP(cmd.Flags(), &logDir, "log-dir", "", "CODER_AGENT_LOG_DIR", os.TempDir(), "Specify the location for the agent log files")
203205
cliflag.StringVarP(cmd.Flags(), &pprofAddress, "pprof-address", "", "CODER_AGENT_PPROF_ADDRESS", "127.0.0.1:6060", "The address to serve pprof.")
206+
cliflag.BoolVarP(cmd.Flags(), &noReap, "no-reap", "", "", false, "Do not start a process reaper.")
204207
return cmd
205208
}
206209

cli/agent_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package cli_test
22

33
import (
44
"context"
5+
"os"
6+
"path/filepath"
57
"runtime"
68
"strings"
79
"testing"
@@ -14,10 +16,70 @@ import (
1416
"github.com/coder/coder/coderd/coderdtest"
1517
"github.com/coder/coder/provisioner/echo"
1618
"github.com/coder/coder/provisionersdk/proto"
19+
"github.com/coder/coder/testutil"
1720
)
1821

1922
func TestWorkspaceAgent(t *testing.T) {
2023
t.Parallel()
24+
25+
t.Run("LogDirectory", func(t *testing.T) {
26+
t.Parallel()
27+
28+
authToken := uuid.NewString()
29+
client := coderdtest.New(t, &coderdtest.Options{
30+
IncludeProvisionerDaemon: true,
31+
})
32+
user := coderdtest.CreateFirstUser(t, client)
33+
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
34+
Parse: echo.ParseComplete,
35+
ProvisionApply: []*proto.Provision_Response{{
36+
Type: &proto.Provision_Response_Complete{
37+
Complete: &proto.Provision_Complete{
38+
Resources: []*proto.Resource{{
39+
Name: "somename",
40+
Type: "someinstance",
41+
Agents: []*proto.Agent{{
42+
Id: uuid.NewString(),
43+
Name: "someagent",
44+
Auth: &proto.Agent_Token{
45+
Token: authToken,
46+
},
47+
}},
48+
}},
49+
},
50+
},
51+
}},
52+
})
53+
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
54+
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
55+
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
56+
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
57+
58+
logDir := t.TempDir()
59+
cmd, _ := clitest.New(t,
60+
"agent",
61+
"--auth", "token",
62+
"--agent-token", authToken,
63+
"--agent-url", client.URL.String(),
64+
"--log-dir", logDir,
65+
)
66+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium)
67+
defer cancel()
68+
errC := make(chan error, 1)
69+
go func() {
70+
errC <- cmd.ExecuteContext(ctx)
71+
}()
72+
coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID)
73+
74+
cancel()
75+
err := <-errC
76+
require.NoError(t, err)
77+
78+
info, err := os.Stat(filepath.Join(logDir, "coder-agent.log"))
79+
require.NoError(t, err)
80+
require.Greater(t, info.Size(), int64(0))
81+
})
82+
2183
t.Run("Azure", func(t *testing.T) {
2284
t.Parallel()
2385
instanceID := "instanceidentifier"

cli/root_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ func TestCommandHelp(t *testing.T) {
5353
"CODER_CACHE_DIRECTORY": "/tmp/coder-cli-test-cache",
5454
},
5555
},
56+
{
57+
name: "coder agent --help",
58+
cmd: []string{"agent", "--help"},
59+
env: map[string]string{
60+
"CODER_AGENT_LOG_DIR": "/tmp",
61+
},
62+
},
5663
}
5764

5865
root := cli.Root(cli.AGPL())
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
Usage:
2+
coder agent [flags]
3+
4+
Flags:
5+
--auth string Specify the authentication type to use for the agent.
6+
Consumes $CODER_AGENT_AUTH (default "token")
7+
-h, --help help for agent
8+
--log-dir string Specify the location for the agent log files.
9+
Consumes $CODER_AGENT_LOG_DIR (default "/tmp")
10+
--no-reap Do not start a process reaper.
11+
--pprof-address string The address to serve pprof.
12+
Consumes $CODER_AGENT_PPROF_ADDRESS (default "127.0.0.1:6060")
13+
14+
Global Flags:
15+
--global-config coder Path to the global coder config directory.
16+
Consumes $CODER_CONFIG_DIR (default "/tmp/coder-cli-test-config")
17+
--header stringArray HTTP headers added to all requests. Provide as "Key=Value".
18+
Consumes $CODER_HEADER
19+
--no-feature-warning Suppress warnings about unlicensed features.
20+
Consumes $CODER_NO_FEATURE_WARNING
21+
--no-version-warning Suppress warning when client and server versions do not match.
22+
Consumes $CODER_NO_VERSION_WARNING
23+
--token string Specify an authentication token. For security reasons setting
24+
CODER_SESSION_TOKEN is preferred.
25+
Consumes $CODER_SESSION_TOKEN
26+
--url string URL to a deployment.
27+
Consumes $CODER_URL
28+
-v, --verbose Enable verbose output.
29+
Consumes $CODER_VERBOSE

coderd/apidoc/docs.go

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/audit.go

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"golang.org/x/xerrors"
1818

1919
"cdr.dev/slog"
20+
"github.com/coder/coder/coderd/audit"
2021
"github.com/coder/coder/coderd/database"
2122
"github.com/coder/coder/coderd/httpapi"
2223
"github.com/coder/coder/coderd/httpmw"
@@ -147,6 +148,9 @@ func (api *API) generateFakeAuditLog(rw http.ResponseWriter, r *http.Request) {
147148
if params.Time.IsZero() {
148149
params.Time = time.Now()
149150
}
151+
if len(params.AdditionalFields) == 0 {
152+
params.AdditionalFields = json.RawMessage("{}")
153+
}
150154

151155
_, err = api.Database.InsertAuditLog(ctx, database.InsertAuditLogParams{
152156
ID: uuid.New(),
@@ -160,7 +164,7 @@ func (api *API) generateFakeAuditLog(rw http.ResponseWriter, r *http.Request) {
160164
Action: database.AuditAction(params.Action),
161165
Diff: diff,
162166
StatusCode: http.StatusOK,
163-
AdditionalFields: []byte("{}"),
167+
AdditionalFields: params.AdditionalFields,
164168
})
165169
if err != nil {
166170
httpapi.InternalServerError(rw, err)
@@ -180,12 +184,6 @@ func (api *API) convertAuditLogs(ctx context.Context, dblogs []database.GetAudit
180184
return alogs
181185
}
182186

183-
type AdditionalFields struct {
184-
WorkspaceName string `json:"workspace_name"`
185-
BuildNumber string `json:"build_number"`
186-
BuildReason database.BuildReason `json:"build_reason"`
187-
}
188-
189187
func (api *API) convertAuditLog(ctx context.Context, dblog database.GetAuditLogsOffsetRow) codersdk.AuditLog {
190188
ip, _ := netip.AddrFromSlice(dblog.Ip.IPNet.IP)
191189

@@ -213,16 +211,18 @@ func (api *API) convertAuditLog(ctx context.Context, dblog database.GetAuditLogs
213211

214212
var (
215213
additionalFieldsBytes = []byte(dblog.AdditionalFields)
216-
additionalFields AdditionalFields
214+
additionalFields audit.AdditionalFields
217215
err = json.Unmarshal(additionalFieldsBytes, &additionalFields)
218216
)
219217
if err != nil {
220218
api.Logger.Error(ctx, "unmarshal additional fields", slog.Error(err))
221-
resourceInfo := map[string]string{
222-
"workspaceName": "unknown",
223-
"buildNumber": "unknown",
224-
"buildReason": "unknown",
219+
resourceInfo := audit.AdditionalFields{
220+
WorkspaceName: "unknown",
221+
BuildNumber: "unknown",
222+
BuildReason: "unknown",
223+
WorkspaceOwner: "unknown",
225224
}
225+
226226
dblog.AdditionalFields, err = json.Marshal(resourceInfo)
227227
api.Logger.Error(ctx, "marshal additional fields", slog.Error(err))
228228
}
@@ -259,7 +259,7 @@ func (api *API) convertAuditLog(ctx context.Context, dblog database.GetAuditLogs
259259
}
260260
}
261261

262-
func auditLogDescription(alog database.GetAuditLogsOffsetRow, additionalFields AdditionalFields) string {
262+
func auditLogDescription(alog database.GetAuditLogsOffsetRow, additionalFields audit.AdditionalFields) string {
263263
str := fmt.Sprintf("{user} %s",
264264
codersdk.AuditAction(alog.Action).Friendly(),
265265
)
@@ -344,14 +344,16 @@ func (api *API) auditLogIsResourceDeleted(ctx context.Context, alog database.Get
344344
}
345345
}
346346

347-
func (api *API) auditLogResourceLink(ctx context.Context, alog database.GetAuditLogsOffsetRow, additionalFields AdditionalFields) string {
347+
func (api *API) auditLogResourceLink(ctx context.Context, alog database.GetAuditLogsOffsetRow, additionalFields audit.AdditionalFields) string {
348348
switch alog.ResourceType {
349349
case database.ResourceTypeTemplate:
350350
return fmt.Sprintf("/templates/%s",
351351
alog.ResourceTarget)
352+
352353
case database.ResourceTypeUser:
353354
return fmt.Sprintf("/users?filter=%s",
354355
alog.ResourceTarget)
356+
355357
case database.ResourceTypeWorkspace:
356358
workspace, getWorkspaceErr := api.Database.GetWorkspaceByID(ctx, alog.ResourceID)
357359
if getWorkspaceErr != nil {
@@ -363,6 +365,7 @@ func (api *API) auditLogResourceLink(ctx context.Context, alog database.GetAudit
363365
}
364366
return fmt.Sprintf("/@%s/%s",
365367
workspaceOwner.Username, alog.ResourceTarget)
368+
366369
case database.ResourceTypeWorkspaceBuild:
367370
if len(additionalFields.WorkspaceName) == 0 || len(additionalFields.BuildNumber) == 0 {
368371
return ""
@@ -381,6 +384,7 @@ func (api *API) auditLogResourceLink(ctx context.Context, alog database.GetAudit
381384
}
382385
return fmt.Sprintf("/@%s/%s/builds/%s",
383386
workspaceOwner.Username, additionalFields.WorkspaceName, additionalFields.BuildNumber)
387+
384388
default:
385389
return ""
386390
}

coderd/audit/audit.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ type Auditor interface {
1212
diff(old, new any) Map
1313
}
1414

15+
type AdditionalFields struct {
16+
WorkspaceName string `json:"workspace_name"`
17+
BuildNumber string `json:"build_number"`
18+
BuildReason database.BuildReason `json:"build_reason"`
19+
WorkspaceOwner string `json:"workspace_owner"`
20+
}
21+
1522
func NewNop() Auditor {
1623
return nop{}
1724
}

0 commit comments

Comments
 (0)