Skip to content

Commit 6aa90bc

Browse files
committed
Merge branch 'main' into jon/glue
2 parents 87828a2 + 343f8ec commit 6aa90bc

File tree

127 files changed

+1968
-1192
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+1968
-1192
lines changed

agent/agent.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,11 +1134,19 @@ func (a *agent) trackGoroutine(fn func()) error {
11341134
}
11351135

11361136
func (a *agent) createTailnet(ctx context.Context, agentID uuid.UUID, derpMap *tailcfg.DERPMap, derpForceWebSockets, disableDirectConnections bool) (_ *tailnet.Conn, err error) {
1137+
// Inject `CODER_AGENT_HEADER` into the DERP header.
1138+
var header http.Header
1139+
if client, ok := a.client.(*agentsdk.Client); ok {
1140+
if headerTransport, ok := client.SDK.HTTPClient.Transport.(*codersdk.HeaderTransport); ok {
1141+
header = headerTransport.Header
1142+
}
1143+
}
11371144
network, err := tailnet.NewConn(&tailnet.Options{
11381145
ID: agentID,
11391146
Addresses: a.wireguardAddresses(agentID),
11401147
DERPMap: derpMap,
11411148
DERPForceWebSockets: derpForceWebSockets,
1149+
DERPHeader: &header,
11421150
Logger: a.logger.Named("net.tailnet"),
11431151
ListenPort: a.tailnetListenPort,
11441152
BlockEndpoints: disableDirectConnections,

cli/agent_test.go

Lines changed: 76 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"fmt"
66
"net/http"
7-
"net/http/httptest"
87
"os"
98
"path/filepath"
109
"runtime"
@@ -18,6 +17,7 @@ import (
1817

1918
"github.com/coder/coder/v2/agent"
2019
"github.com/coder/coder/v2/cli/clitest"
20+
"github.com/coder/coder/v2/coderd"
2121
"github.com/coder/coder/v2/coderd/coderdtest"
2222
"github.com/coder/coder/v2/coderd/database"
2323
"github.com/coder/coder/v2/coderd/database/dbfake"
@@ -35,7 +35,7 @@ func TestWorkspaceAgent(t *testing.T) {
3535

3636
client, db := coderdtest.NewWithDatabase(t, nil)
3737
user := coderdtest.CreateFirstUser(t, client)
38-
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
38+
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
3939
OrganizationID: user.OrganizationID,
4040
OwnerID: user.UserID,
4141
}).
@@ -71,7 +71,7 @@ func TestWorkspaceAgent(t *testing.T) {
7171
AzureCertificates: certificates,
7272
})
7373
user := coderdtest.CreateFirstUser(t, client)
74-
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
74+
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
7575
OrganizationID: user.OrganizationID,
7676
OwnerID: user.UserID,
7777
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
@@ -110,7 +110,7 @@ func TestWorkspaceAgent(t *testing.T) {
110110
AWSCertificates: certificates,
111111
})
112112
user := coderdtest.CreateFirstUser(t, client)
113-
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
113+
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
114114
OrganizationID: user.OrganizationID,
115115
OwnerID: user.UserID,
116116
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
@@ -151,7 +151,7 @@ func TestWorkspaceAgent(t *testing.T) {
151151
})
152152
owner := coderdtest.CreateFirstUser(t, client)
153153
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
154-
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
154+
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
155155
OrganizationID: owner.OrganizationID,
156156
OwnerID: memberUser.ID,
157157
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
@@ -205,7 +205,7 @@ func TestWorkspaceAgent(t *testing.T) {
205205

206206
client, db := coderdtest.NewWithDatabase(t, nil)
207207
user := coderdtest.CreateFirstUser(t, client)
208-
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
208+
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
209209
OrganizationID: user.OrganizationID,
210210
OwnerID: user.UserID,
211211
}).WithAgent().Do()
@@ -232,42 +232,92 @@ func TestWorkspaceAgent(t *testing.T) {
232232
require.Equal(t, codersdk.AgentSubsystemEnvbox, resources[0].Agents[0].Subsystems[0])
233233
require.Equal(t, codersdk.AgentSubsystemExectrace, resources[0].Agents[0].Subsystems[1])
234234
})
235-
t.Run("Header", func(t *testing.T) {
235+
t.Run("Headers&DERPHeaders", func(t *testing.T) {
236236
t.Parallel()
237237

238-
var url string
239-
var called int64
240-
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
241-
assert.Equal(t, "wow", r.Header.Get("X-Testing"))
242-
assert.Equal(t, "Ethan was Here!", r.Header.Get("Cool-Header"))
243-
assert.Equal(t, "very-wow-"+url, r.Header.Get("X-Process-Testing"))
244-
assert.Equal(t, "more-wow", r.Header.Get("X-Process-Testing2"))
245-
atomic.AddInt64(&called, 1)
246-
w.WriteHeader(http.StatusGone)
238+
// Create a coderd API instance the hard way since we need to change the
239+
// handler to inject our custom /derp handler.
240+
dv := coderdtest.DeploymentValues(t)
241+
dv.DERP.Config.BlockDirect = true
242+
setHandler, cancelFunc, serverURL, newOptions := coderdtest.NewOptions(t, &coderdtest.Options{
243+
DeploymentValues: dv,
244+
})
245+
246+
// We set the handler after server creation for the access URL.
247+
coderAPI := coderd.New(newOptions)
248+
setHandler(coderAPI.RootHandler)
249+
provisionerCloser := coderdtest.NewProvisionerDaemon(t, coderAPI)
250+
t.Cleanup(func() {
251+
_ = provisionerCloser.Close()
252+
})
253+
client := codersdk.New(serverURL)
254+
t.Cleanup(func() {
255+
cancelFunc()
256+
_ = provisionerCloser.Close()
257+
_ = coderAPI.Close()
258+
client.HTTPClient.CloseIdleConnections()
259+
})
260+
261+
var (
262+
admin = coderdtest.CreateFirstUser(t, client)
263+
member, memberUser = coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
264+
called int64
265+
derpCalled int64
266+
)
267+
268+
setHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
269+
// Ignore client requests
270+
if r.Header.Get("X-Testing") == "agent" {
271+
assert.Equal(t, "Ethan was Here!", r.Header.Get("Cool-Header"))
272+
assert.Equal(t, "very-wow-"+client.URL.String(), r.Header.Get("X-Process-Testing"))
273+
assert.Equal(t, "more-wow", r.Header.Get("X-Process-Testing2"))
274+
if strings.HasPrefix(r.URL.Path, "/derp") {
275+
atomic.AddInt64(&derpCalled, 1)
276+
} else {
277+
atomic.AddInt64(&called, 1)
278+
}
279+
}
280+
coderAPI.RootHandler.ServeHTTP(w, r)
247281
}))
248-
defer srv.Close()
249-
url = srv.URL
282+
r := dbfake.WorkspaceBuild(t, coderAPI.Database, database.WorkspaceTable{
283+
OrganizationID: memberUser.OrganizationIDs[0],
284+
OwnerID: memberUser.ID,
285+
}).WithAgent().Do()
286+
250287
coderURLEnv := "$CODER_URL"
251288
if runtime.GOOS == "windows" {
252289
coderURLEnv = "%CODER_URL%"
253290
}
254291

255292
logDir := t.TempDir()
256-
inv, _ := clitest.New(t,
293+
agentInv, _ := clitest.New(t,
257294
"agent",
258295
"--auth", "token",
259-
"--agent-token", "fake-token",
260-
"--agent-url", srv.URL,
296+
"--agent-token", r.AgentToken,
297+
"--agent-url", client.URL.String(),
261298
"--log-dir", logDir,
262-
"--agent-header", "X-Testing=wow",
299+
"--agent-header", "X-Testing=agent",
263300
"--agent-header", "Cool-Header=Ethan was Here!",
264301
"--agent-header-command", "printf X-Process-Testing=very-wow-"+coderURLEnv+"'\\r\\n'X-Process-Testing2=more-wow",
265302
)
303+
clitest.Start(t, agentInv)
304+
coderdtest.NewWorkspaceAgentWaiter(t, client, r.Workspace.ID).
305+
MatchResources(matchAgentWithVersion).Wait()
306+
307+
ctx := testutil.Context(t, testutil.WaitLong)
308+
clientInv, root := clitest.New(t,
309+
"-v",
310+
"--no-feature-warning",
311+
"--no-version-warning",
312+
"ping", r.Workspace.Name,
313+
"-n", "1",
314+
)
315+
clitest.SetupConfig(t, member, root)
316+
err := clientInv.WithContext(ctx).Run()
317+
require.NoError(t, err)
266318

267-
clitest.Start(t, inv)
268-
require.Eventually(t, func() bool {
269-
return atomic.LoadInt64(&called) > 0
270-
}, testutil.WaitShort, testutil.IntervalFast)
319+
require.Greater(t, atomic.LoadInt64(&called), int64(0), "expected coderd to be reached with custom headers")
320+
require.Greater(t, atomic.LoadInt64(&derpCalled), int64(0), "expected /derp to be called with custom headers")
271321
})
272322
}
273323

cli/clistat/container.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
const (
1313
procMounts = "/proc/mounts"
1414
procOneCgroup = "/proc/1/cgroup"
15+
sysCgroupType = "/sys/fs/cgroup/cgroup.type"
1516
kubernetesDefaultServiceAccountToken = "/var/run/secrets/kubernetes.io/serviceaccount/token" //nolint:gosec
1617
)
1718

@@ -65,6 +66,17 @@ func IsContainerized(fs afero.Fs) (ok bool, err error) {
6566
}
6667
}
6768

69+
// Adapted from https://github.com/systemd/systemd/blob/88bbf187a9b2ebe0732caa1e886616ae5f8186da/src/basic/virt.c#L603-L605
70+
// The file `/sys/fs/cgroup/cgroup.type` does not exist on the root cgroup.
71+
// If this file exists we can be sure we're in a container.
72+
cgTypeExists, err := afero.Exists(fs, sysCgroupType)
73+
if err != nil {
74+
return false, xerrors.Errorf("check file exists %s: %w", sysCgroupType, err)
75+
}
76+
if cgTypeExists {
77+
return true, nil
78+
}
79+
6880
// If we get here, we are _probably_ not running in a container.
6981
return false, nil
7082
}

cli/clistat/stat_internal_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,12 @@ func TestIsContainerized(t *testing.T) {
309309
Expected: true,
310310
Error: "",
311311
},
312+
{
313+
Name: "Docker (Cgroupns=private)",
314+
FS: fsContainerCgroupV2PrivateCgroupns,
315+
Expected: true,
316+
Error: "",
317+
},
312318
} {
313319
tt := tt
314320
t.Run(tt.Name, func(t *testing.T) {
@@ -374,6 +380,12 @@ proc /proc/sys proc ro,nosuid,nodev,noexec,relatime 0 0`,
374380
cgroupV2MemoryUsageBytes: "536870912",
375381
cgroupV2MemoryStat: "inactive_file 268435456",
376382
}
383+
fsContainerCgroupV2PrivateCgroupns = map[string]string{
384+
procOneCgroup: "0::/",
385+
procMounts: `overlay / overlay rw,relatime,lowerdir=/some/path:/some/path,upperdir=/some/path:/some/path,workdir=/some/path:/some/path 0 0
386+
proc /proc/sys proc ro,nosuid,nodev,noexec,relatime 0 0`,
387+
sysCgroupType: "domain",
388+
}
377389
fsContainerCgroupV1 = map[string]string{
378390
procOneCgroup: "0::/docker/aa86ac98959eeedeae0ecb6e0c9ddd8ae8b97a9d0fdccccf7ea7a474f4e0bb1f",
379391
procMounts: `overlay / overlay rw,relatime,lowerdir=/some/path:/some/path,upperdir=/some/path:/some/path,workdir=/some/path:/some/path 0 0

cli/configssh_test.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"os"
1111
"os/exec"
1212
"path/filepath"
13+
"runtime"
1314
"strconv"
1415
"strings"
1516
"sync"
@@ -63,6 +64,10 @@ func sshConfigFileRead(t *testing.T, name string) string {
6364
func TestConfigSSH(t *testing.T) {
6465
t.Parallel()
6566

67+
if runtime.GOOS == "windows" {
68+
t.Skip("See coder/internal#117")
69+
}
70+
6671
const hostname = "test-coder."
6772
const expectedKey = "ConnectionAttempts"
6873
const removeKey = "ConnectTimeout"
@@ -78,7 +83,7 @@ func TestConfigSSH(t *testing.T) {
7883
})
7984
owner := coderdtest.CreateFirstUser(t, client)
8085
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
81-
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
86+
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
8287
OrganizationID: owner.OrganizationID,
8388
OwnerID: memberUser.ID,
8489
}).WithAgent().Do()
@@ -642,7 +647,7 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) {
642647
client, db := coderdtest.NewWithDatabase(t, nil)
643648
user := coderdtest.CreateFirstUser(t, client)
644649
if tt.hasAgent {
645-
_ = dbfake.WorkspaceBuild(t, db, database.Workspace{
650+
_ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
646651
OrganizationID: user.OrganizationID,
647652
OwnerID: user.UserID,
648653
}).WithAgent().Do()
@@ -762,7 +767,7 @@ func TestConfigSSH_Hostnames(t *testing.T) {
762767
owner := coderdtest.CreateFirstUser(t, client)
763768
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
764769

765-
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
770+
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
766771
OrganizationID: owner.OrganizationID,
767772
OwnerID: memberUser.ID,
768773
}).Resource(resources...).Do()

cli/favorite_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func TestFavoriteUnfavorite(t *testing.T) {
1919
client, db = coderdtest.NewWithDatabase(t, nil)
2020
owner = coderdtest.CreateFirstUser(t, client)
2121
memberClient, member = coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
22-
ws = dbfake.WorkspaceBuild(t, db, database.Workspace{OwnerID: member.ID, OrganizationID: owner.OrganizationID}).Do()
22+
ws = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{OwnerID: member.ID, OrganizationID: owner.OrganizationID}).Do()
2323
)
2424

2525
inv, root := clitest.New(t, "favorite", ws.Workspace.Name)

cli/gitssh_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func prepareTestGitSSH(ctx context.Context, t *testing.T) (*agentsdk.Client, str
4848
require.NoError(t, err)
4949

5050
// setup template
51-
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
51+
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
5252
OrganizationID: user.OrganizationID,
5353
OwnerID: user.UserID,
5454
}).WithAgent().Do()

cli/list_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func TestList(t *testing.T) {
2626
owner := coderdtest.CreateFirstUser(t, client)
2727
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
2828
// setup template
29-
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
29+
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
3030
OrganizationID: owner.OrganizationID,
3131
OwnerID: memberUser.ID,
3232
}).WithAgent().Do()
@@ -54,7 +54,7 @@ func TestList(t *testing.T) {
5454
client, db := coderdtest.NewWithDatabase(t, nil)
5555
owner := coderdtest.CreateFirstUser(t, client)
5656
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
57-
_ = dbfake.WorkspaceBuild(t, db, database.Workspace{
57+
_ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
5858
OrganizationID: owner.OrganizationID,
5959
OwnerID: memberUser.ID,
6060
}).WithAgent().Do()

cli/portforward_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,12 +290,12 @@ func TestPortForward(t *testing.T) {
290290
// runAgent creates a fake workspace and starts an agent locally for that
291291
// workspace. The agent will be cleaned up on test completion.
292292
// nolint:unused
293-
func runAgent(t *testing.T, client *codersdk.Client, owner uuid.UUID, db database.Store) database.Workspace {
293+
func runAgent(t *testing.T, client *codersdk.Client, owner uuid.UUID, db database.Store) database.WorkspaceTable {
294294
user, err := client.User(context.Background(), codersdk.Me)
295295
require.NoError(t, err, "specified user does not exist")
296296
require.Greater(t, len(user.OrganizationIDs), 0, "user has no organizations")
297297
orgID := user.OrganizationIDs[0]
298-
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
298+
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
299299
OrganizationID: orgID,
300300
OwnerID: owner,
301301
}).WithAgent().Do()

cli/root.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,16 @@ func formatCoderSDKError(from string, err *codersdk.Error, opts *formatOpts) str
11161116
//nolint:errorlint
11171117
func traceError(err error) string {
11181118
if uw, ok := err.(interface{ Unwrap() error }); ok {
1119-
a, b := err.Error(), uw.Unwrap().Error()
1119+
var a, b string
1120+
if err != nil {
1121+
a = err.Error()
1122+
}
1123+
if uw != nil {
1124+
uwerr := uw.Unwrap()
1125+
if uwerr != nil {
1126+
b = uwerr.Error()
1127+
}
1128+
}
11201129
c := strings.TrimSuffix(a, b)
11211130
return c
11221131
}

cli/schedule_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,27 +38,27 @@ func setupTestSchedule(t *testing.T, sched *cron.Schedule) (ownerClient, memberC
3838
memberClient, memberUser := coderdtest.CreateAnotherUserMutators(t, ownerClient, owner.OrganizationID, nil, func(r *codersdk.CreateUserRequestWithOrgs) {
3939
r.Username = "testuser2" // ensure deterministic ordering
4040
})
41-
_ = dbfake.WorkspaceBuild(t, db, database.Workspace{
41+
_ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
4242
Name: "a-owner",
4343
OwnerID: owner.UserID,
4444
OrganizationID: owner.OrganizationID,
4545
AutostartSchedule: sql.NullString{String: sched.String(), Valid: true},
4646
Ttl: sql.NullInt64{Int64: 8 * time.Hour.Nanoseconds(), Valid: true},
4747
}).WithAgent().Do()
4848

49-
_ = dbfake.WorkspaceBuild(t, db, database.Workspace{
49+
_ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
5050
Name: "b-owner",
5151
OwnerID: owner.UserID,
5252
OrganizationID: owner.OrganizationID,
5353
AutostartSchedule: sql.NullString{String: sched.String(), Valid: true},
5454
}).WithAgent().Do()
55-
_ = dbfake.WorkspaceBuild(t, db, database.Workspace{
55+
_ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
5656
Name: "c-member",
5757
OwnerID: memberUser.ID,
5858
OrganizationID: owner.OrganizationID,
5959
Ttl: sql.NullInt64{Int64: 8 * time.Hour.Nanoseconds(), Valid: true},
6060
}).WithAgent().Do()
61-
_ = dbfake.WorkspaceBuild(t, db, database.Workspace{
61+
_ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
6262
Name: "d-member",
6363
OwnerID: memberUser.ID,
6464
OrganizationID: owner.OrganizationID,

0 commit comments

Comments
 (0)