Skip to content

Commit 211e59b

Browse files
authored
feat: add tailnet v2 API support to coordinate endpoint (#11228)
closes #10532 Adds v2 support to the /coordinate endpoint via a query parameter. v1 already has test cases, and we haven't implemented v2 at the client yet, so the only new test case is an unsupported version.
1 parent a41cbb0 commit 211e59b

File tree

4 files changed

+55
-2
lines changed

4 files changed

+55
-2
lines changed

coderd/coderd.go

+6
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,11 @@ func New(options *Options) *API {
473473
Cache: wsconncache.New(api._dialWorkspaceAgentTailnet, 0),
474474
}
475475
}
476+
api.TailnetClientService, err = tailnet.NewClientService(
477+
api.Logger.Named("tailnetclient"), &api.TailnetCoordinator)
478+
if err != nil {
479+
api.Logger.Fatal(api.ctx, "failed to initialize tailnet client service", slog.Error(err))
480+
}
476481

477482
workspaceAppsLogger := options.Logger.Named("workspaceapps")
478483
if options.WorkspaceAppsStatsCollectorOptions.Logger == nil {
@@ -1061,6 +1066,7 @@ type API struct {
10611066
Auditor atomic.Pointer[audit.Auditor]
10621067
WorkspaceClientCoordinateOverride atomic.Pointer[func(rw http.ResponseWriter) bool]
10631068
TailnetCoordinator atomic.Pointer[tailnet.Coordinator]
1069+
TailnetClientService *tailnet.ClientService
10641070
QuotaCommitter atomic.Pointer[proto.QuotaCommitter]
10651071
// WorkspaceProxyHostsFn returns the hosts of healthy workspace proxies
10661072
// for header reasons.

coderd/workspaceagents.go

+17-2
Original file line numberDiff line numberDiff line change
@@ -1387,6 +1387,21 @@ func (api *API) workspaceAgentClientCoordinate(rw http.ResponseWriter, r *http.R
13871387
}
13881388
}
13891389

1390+
version := "1.0"
1391+
qv := r.URL.Query().Get("version")
1392+
if qv != "" {
1393+
version = qv
1394+
}
1395+
if err := tailnet.ValidateVersion(version); err != nil {
1396+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
1397+
Message: "Unknown or unsupported API version",
1398+
Validations: []codersdk.ValidationError{
1399+
{Field: "version", Detail: err.Error()},
1400+
},
1401+
})
1402+
return
1403+
}
1404+
13901405
api.WebsocketWaitMutex.Lock()
13911406
api.WebsocketWaitGroup.Add(1)
13921407
api.WebsocketWaitMutex.Unlock()
@@ -1407,8 +1422,8 @@ func (api *API) workspaceAgentClientCoordinate(rw http.ResponseWriter, r *http.R
14071422
go httpapi.Heartbeat(ctx, conn)
14081423

14091424
defer conn.Close(websocket.StatusNormalClosure, "")
1410-
err = (*api.TailnetCoordinator.Load()).ServeClient(wsNetConn, uuid.New(), workspaceAgent.ID)
1411-
if err != nil {
1425+
err = api.TailnetClientService.ServeClient(ctx, version, wsNetConn, uuid.New(), workspaceAgent.ID)
1426+
if err != nil && !xerrors.Is(err, io.EOF) && !xerrors.Is(err, context.Canceled) {
14121427
_ = conn.Close(websocket.StatusInternalError, err.Error())
14131428
return
14141429
}

coderd/workspaceagents_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,38 @@ func TestWorkspaceAgentTailnet(t *testing.T) {
444444
require.Equal(t, "test", strings.TrimSpace(string(output)))
445445
}
446446

447+
func TestWorkspaceAgentClientCoordinate_BadVersion(t *testing.T) {
448+
t.Parallel()
449+
client, db := coderdtest.NewWithDatabase(t, nil)
450+
user := coderdtest.CreateFirstUser(t, client)
451+
452+
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
453+
OrganizationID: user.OrganizationID,
454+
OwnerID: user.UserID,
455+
}).WithAgent().Do()
456+
457+
ctx := testutil.Context(t, testutil.WaitShort)
458+
agentToken, err := uuid.Parse(r.AgentToken)
459+
require.NoError(t, err)
460+
//nolint: gocritic // testing
461+
ao, err := db.GetWorkspaceAgentAndOwnerByAuthToken(dbauthz.AsSystemRestricted(ctx), agentToken)
462+
require.NoError(t, err)
463+
464+
//nolint: bodyclose // closed by ReadBodyAsError
465+
resp, err := client.Request(ctx, http.MethodGet,
466+
fmt.Sprintf("api/v2/workspaceagents/%s/coordinate", ao.WorkspaceAgent.ID),
467+
nil,
468+
codersdk.WithQueryParam("version", "99.99"))
469+
require.NoError(t, err)
470+
require.Equal(t, http.StatusBadRequest, resp.StatusCode)
471+
err = codersdk.ReadBodyAsError(resp)
472+
var sdkErr *codersdk.Error
473+
require.ErrorAs(t, err, &sdkErr)
474+
require.Equal(t, "Unknown or unsupported API version", sdkErr.Message)
475+
require.Len(t, sdkErr.Validations, 1)
476+
require.Equal(t, "version", sdkErr.Validations[0].Field)
477+
}
478+
447479
func TestWorkspaceAgentTailnetDirectDisabled(t *testing.T) {
448480
t.Parallel()
449481

-1 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)