mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: use tailnet v2 API for coordination (#11638)
This one is huge, and I'm sorry. The problem is that once I change `tailnet.Conn` to start doing v2 behavior, I kind of have to change it everywhere, including in CoderSDK (CLI), the agent, wsproxy, and ServerTailnet. There is still a bit more cleanup to do, and I need to add code so that when we lose connection to the Coordinator, we mark all peers as LOST, but that will be in a separate PR since this is big enough!
This commit is contained in:
@@ -14,12 +14,15 @@ import (
|
||||
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hashicorp/yamux"
|
||||
"golang.org/x/xerrors"
|
||||
"nhooyr.io/websocket"
|
||||
"storj.io/drpc"
|
||||
"tailscale.com/tailcfg"
|
||||
|
||||
"cdr.dev/slog"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
drpcsdk "github.com/coder/coder/v2/codersdk/drpc"
|
||||
"github.com/coder/retry"
|
||||
)
|
||||
|
||||
@@ -280,8 +283,8 @@ func (c *Client) DERPMapUpdates(ctx context.Context) (<-chan DERPMapUpdate, io.C
|
||||
|
||||
// Listen connects to the workspace agent coordinate WebSocket
|
||||
// that handles connection negotiation.
|
||||
func (c *Client) Listen(ctx context.Context) (net.Conn, error) {
|
||||
coordinateURL, err := c.SDK.URL.Parse("/api/v2/workspaceagents/me/coordinate")
|
||||
func (c *Client) Listen(ctx context.Context) (drpc.Conn, error) {
|
||||
coordinateURL, err := c.SDK.URL.Parse("/api/v2/workspaceagents/me/rpc")
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse url: %w", err)
|
||||
}
|
||||
@@ -312,14 +315,21 @@ func (c *Client) Listen(ctx context.Context) (net.Conn, error) {
|
||||
ctx, wsNetConn := websocketNetConn(ctx, conn, websocket.MessageBinary)
|
||||
pingClosed := pingWebSocket(ctx, c.SDK.Logger(), conn, "coordinate")
|
||||
|
||||
return &closeNetConn{
|
||||
netConn := &closeNetConn{
|
||||
Conn: wsNetConn,
|
||||
closeFunc: func() {
|
||||
cancelFunc()
|
||||
_ = conn.Close(websocket.StatusGoingAway, "Listen closed")
|
||||
<-pingClosed
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
config := yamux.DefaultConfig()
|
||||
config.LogOutput = io.Discard
|
||||
session, err := yamux.Client(netConn, config)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("multiplex client: %w", err)
|
||||
}
|
||||
return drpcsdk.MultiplexedConn(session), nil
|
||||
}
|
||||
|
||||
type PostAppHealthsRequest struct {
|
||||
|
||||
@@ -313,6 +313,9 @@ func (c *Client) DialWorkspaceAgent(dialCtx context.Context, agentID uuid.UUID,
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse url: %w", err)
|
||||
}
|
||||
q := coordinateURL.Query()
|
||||
q.Add("version", tailnet.CurrentVersion.String())
|
||||
coordinateURL.RawQuery = q.Encode()
|
||||
closedCoordinator := make(chan struct{})
|
||||
// Must only ever be used once, send error OR close to avoid
|
||||
// reassignment race. Buffered so we don't hang in goroutine.
|
||||
@@ -344,12 +347,22 @@ func (c *Client) DialWorkspaceAgent(dialCtx context.Context, agentID uuid.UUID,
|
||||
options.Logger.Debug(ctx, "failed to dial", slog.Error(err))
|
||||
continue
|
||||
}
|
||||
sendNode, errChan := tailnet.ServeCoordinator(websocket.NetConn(ctx, ws, websocket.MessageBinary), func(nodes []*tailnet.Node) error {
|
||||
return conn.UpdateNodes(nodes, false)
|
||||
})
|
||||
conn.SetNodeCallback(sendNode)
|
||||
client, err := tailnet.NewDRPCClient(websocket.NetConn(ctx, ws, websocket.MessageBinary))
|
||||
if err != nil {
|
||||
options.Logger.Debug(ctx, "failed to create DRPCClient", slog.Error(err))
|
||||
_ = ws.Close(websocket.StatusInternalError, "")
|
||||
continue
|
||||
}
|
||||
coordinate, err := client.Coordinate(ctx)
|
||||
if err != nil {
|
||||
options.Logger.Debug(ctx, "failed to reach the Coordinate endpoint", slog.Error(err))
|
||||
_ = ws.Close(websocket.StatusInternalError, "")
|
||||
continue
|
||||
}
|
||||
|
||||
coordination := tailnet.NewRemoteCoordination(options.Logger, coordinate, conn, agentID)
|
||||
options.Logger.Debug(ctx, "serving coordinator")
|
||||
err = <-errChan
|
||||
err = <-coordination.Error()
|
||||
if errors.Is(err, context.Canceled) {
|
||||
_ = ws.Close(websocket.StatusGoingAway, "")
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user