Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf752a7e

Browse files
committed
feat: add WorkspaceUpdates rpc
1 parent54cbfaf commitf752a7e

20 files changed

+1476
-232
lines changed

‎coderd/apidoc/docs.go

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

‎coderd/apidoc/swagger.json

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

‎coderd/coderd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,7 @@ func New(options *Options) *API {
10101010
r.Route("/roles",func(r chi.Router) {
10111011
r.Get("/",api.AssignableSiteRoles)
10121012
})
1013+
r.Get("/me/tailnet",api.tailnet)
10131014
r.Route("/{user}",func(r chi.Router) {
10141015
r.Use(httpmw.ExtractUserParam(options.Database))
10151016
r.Post("/convert-login",api.postConvertLoginType)

‎coderd/workspaceagents.go

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -855,26 +855,10 @@ func (api *API) workspaceAgentClientCoordinate(rw http.ResponseWriter, r *http.R
855855
return
856856
}
857857

858-
// Accept a resume_token query parameter to use the same peer ID.
859-
var (
860-
peerID=uuid.New()
861-
resumeToken=r.URL.Query().Get("resume_token")
862-
)
863-
ifresumeToken!="" {
864-
varerrerror
865-
peerID,err=api.Options.CoordinatorResumeTokenProvider.VerifyResumeToken(resumeToken)
866-
iferr!=nil {
867-
httpapi.Write(ctx,rw,http.StatusUnauthorized, codersdk.Response{
868-
Message:workspacesdk.CoordinateAPIInvalidResumeToken,
869-
Detail:err.Error(),
870-
Validations: []codersdk.ValidationError{
871-
{Field:"resume_token",Detail:workspacesdk.CoordinateAPIInvalidResumeToken},
872-
},
873-
})
874-
return
875-
}
876-
api.Logger.Debug(ctx,"accepted coordinate resume token for peer",
877-
slog.F("peer_id",peerID.String()))
858+
peerID,err:=api.handleResumeToken(ctx,rw,r)
859+
iferr!=nil {
860+
// handleResumeToken has already written the response.
861+
return
878862
}
879863

880864
api.WebsocketWaitMutex.Lock()
@@ -904,6 +888,28 @@ func (api *API) workspaceAgentClientCoordinate(rw http.ResponseWriter, r *http.R
904888
}
905889
}
906890

891+
// handleResumeToken accepts a resume_token query parameter to use the same peer ID
892+
func (api*API)handleResumeToken(ctx context.Context,rw http.ResponseWriter,r*http.Request) (peerID uuid.UUID,errerror) {
893+
peerID=uuid.New()
894+
resumeToken:=r.URL.Query().Get("resume_token")
895+
ifresumeToken!="" {
896+
peerID,err=api.Options.CoordinatorResumeTokenProvider.VerifyResumeToken(resumeToken)
897+
iferr!=nil {
898+
httpapi.Write(ctx,rw,http.StatusUnauthorized, codersdk.Response{
899+
Message:workspacesdk.CoordinateAPIInvalidResumeToken,
900+
Detail:err.Error(),
901+
Validations: []codersdk.ValidationError{
902+
{Field:"resume_token",Detail:workspacesdk.CoordinateAPIInvalidResumeToken},
903+
},
904+
})
905+
returnpeerID,err
906+
}
907+
api.Logger.Debug(ctx,"accepted coordinate resume token for peer",
908+
slog.F("peer_id",peerID.String()))
909+
}
910+
returnpeerID,err
911+
}
912+
907913
// @Summary Post workspace agent log source
908914
// @ID post-workspace-agent-log-source
909915
// @Security CoderSessionToken

‎coderd/workspacebuilds.go

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -958,7 +958,7 @@ func (api *API) convertWorkspaceBuild(
958958
MaxDeadline:codersdk.NewNullTime(build.MaxDeadline,!build.MaxDeadline.IsZero()),
959959
Reason:codersdk.BuildReason(build.Reason),
960960
Resources:apiResources,
961-
Status:convertWorkspaceStatus(apiJob.Status,transition),
961+
Status:codersdk.ConvertWorkspaceStatus(apiJob.Status,transition),
962962
DailyCost:build.DailyCost,
963963
},nil
964964
}
@@ -987,37 +987,3 @@ func convertWorkspaceResource(resource database.WorkspaceResource, agents []code
987987
DailyCost:resource.DailyCost,
988988
}
989989
}
990-
991-
funcconvertWorkspaceStatus(jobStatus codersdk.ProvisionerJobStatus,transition codersdk.WorkspaceTransition) codersdk.WorkspaceStatus {
992-
switchjobStatus {
993-
casecodersdk.ProvisionerJobPending:
994-
returncodersdk.WorkspaceStatusPending
995-
casecodersdk.ProvisionerJobRunning:
996-
switchtransition {
997-
casecodersdk.WorkspaceTransitionStart:
998-
returncodersdk.WorkspaceStatusStarting
999-
casecodersdk.WorkspaceTransitionStop:
1000-
returncodersdk.WorkspaceStatusStopping
1001-
casecodersdk.WorkspaceTransitionDelete:
1002-
returncodersdk.WorkspaceStatusDeleting
1003-
}
1004-
casecodersdk.ProvisionerJobSucceeded:
1005-
switchtransition {
1006-
casecodersdk.WorkspaceTransitionStart:
1007-
returncodersdk.WorkspaceStatusRunning
1008-
casecodersdk.WorkspaceTransitionStop:
1009-
returncodersdk.WorkspaceStatusStopped
1010-
casecodersdk.WorkspaceTransitionDelete:
1011-
returncodersdk.WorkspaceStatusDeleted
1012-
}
1013-
casecodersdk.ProvisionerJobCanceling:
1014-
returncodersdk.WorkspaceStatusCanceling
1015-
casecodersdk.ProvisionerJobCanceled:
1016-
returncodersdk.WorkspaceStatusCanceled
1017-
casecodersdk.ProvisionerJobFailed:
1018-
returncodersdk.WorkspaceStatusFailed
1019-
}
1020-
1021-
// return error status since we should never get here
1022-
returncodersdk.WorkspaceStatusFailed
1023-
}

‎coderd/workspaces.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"encoding/json"
77
"errors"
88
"fmt"
9+
"io"
910
"net/http"
1011
"slices"
1112
"strconv"
@@ -15,6 +16,7 @@ import (
1516
"github.com/go-chi/chi/v5"
1617
"github.com/google/uuid"
1718
"golang.org/x/xerrors"
19+
"nhooyr.io/websocket"
1820

1921
"cdr.dev/slog"
2022
"github.com/coder/coder/v2/agent/proto"
@@ -36,6 +38,7 @@ import (
3638
"github.com/coder/coder/v2/coderd/wsbuilder"
3739
"github.com/coder/coder/v2/codersdk"
3840
"github.com/coder/coder/v2/codersdk/agentsdk"
41+
"github.com/coder/coder/v2/tailnet"
3942
)
4043

4144
var (
@@ -2089,6 +2092,11 @@ func (api *API) publishWorkspaceUpdate(ctx context.Context, ownerID uuid.UUID, e
20892092
api.Logger.Warn(ctx,"failed to publish workspace update",
20902093
slog.F("workspace_id",event.WorkspaceID),slog.Error(err))
20912094
}
2095+
err=api.Pubsub.Publish(codersdk.AllWorkspacesNotifyChannel, []byte(workspaceID.String()))
2096+
iferr!=nil {
2097+
api.Logger.Warn(ctx,"failed to publish all workspaces update",
2098+
slog.F("workspace_id",workspaceID),slog.Error(err))
2099+
}
20922100
}
20932101

20942102
func (api*API)publishWorkspaceAgentLogsUpdate(ctx context.Context,workspaceAgentID uuid.UUID,m agentsdk.LogsNotifyMessage) {
@@ -2101,3 +2109,72 @@ func (api *API) publishWorkspaceAgentLogsUpdate(ctx context.Context, workspaceAg
21012109
api.Logger.Warn(ctx,"failed to publish workspace agent logs update",slog.F("workspace_agent_id",workspaceAgentID),slog.Error(err))
21022110
}
21032111
}
2112+
2113+
// @Summary Coordinate multiple workspace agents
2114+
// @ID coordinate-multiple-workspace-agents
2115+
// @Security CoderSessionToken
2116+
// @Tags Workspaces
2117+
// @Success 101
2118+
// @Router /users/me/tailnet [get]
2119+
func (api*API)tailnet(rw http.ResponseWriter,r*http.Request) {
2120+
ctx:=r.Context()
2121+
owner:=httpmw.UserParam(r)
2122+
ownerRoles:=httpmw.UserAuthorization(r)
2123+
2124+
// Check if the actor is allowed to access any workspace owned by the user.
2125+
if!api.Authorize(r,policy.ActionSSH,rbac.ResourceWorkspace.WithOwner(owner.ID.String())) {
2126+
httpapi.ResourceNotFound(rw)
2127+
return
2128+
}
2129+
2130+
version:="1.0"
2131+
qv:=r.URL.Query().Get("version")
2132+
ifqv!="" {
2133+
version=qv
2134+
}
2135+
iferr:=proto.CurrentVersion.Validate(version);err!=nil {
2136+
httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{
2137+
Message:"Unknown or unsupported API version",
2138+
Validations: []codersdk.ValidationError{
2139+
{Field:"version",Detail:err.Error()},
2140+
},
2141+
})
2142+
return
2143+
}
2144+
2145+
peerID,err:=api.handleResumeToken(ctx,rw,r)
2146+
iferr!=nil {
2147+
// handleResumeToken has already written the response.
2148+
return
2149+
}
2150+
2151+
api.WebsocketWaitMutex.Lock()
2152+
api.WebsocketWaitGroup.Add(1)
2153+
api.WebsocketWaitMutex.Unlock()
2154+
deferapi.WebsocketWaitGroup.Done()
2155+
2156+
conn,err:=websocket.Accept(rw,r,nil)
2157+
iferr!=nil {
2158+
httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{
2159+
Message:"Failed to accept websocket.",
2160+
Detail:err.Error(),
2161+
})
2162+
return
2163+
}
2164+
ctx,wsNetConn:=codersdk.WebsocketNetConn(ctx,conn,websocket.MessageBinary)
2165+
deferwsNetConn.Close()
2166+
deferconn.Close(websocket.StatusNormalClosure,"")
2167+
2168+
gohttpapi.Heartbeat(ctx,conn)
2169+
err=api.TailnetClientService.ServeUserClient(ctx,version,wsNetConn, tailnet.ServeUserClientOptions{
2170+
PeerID:peerID,
2171+
UserID:owner.ID,
2172+
Subject:&ownerRoles,
2173+
Authz:api.Authorizer,
2174+
Database:api.Database,
2175+
})
2176+
iferr!=nil&&!xerrors.Is(err,io.EOF)&&!xerrors.Is(err,context.Canceled) {
2177+
_=conn.Close(websocket.StatusInternalError,err.Error())
2178+
return
2179+
}
2180+
}

‎codersdk/provisionerdaemons.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,3 +402,37 @@ func (c *Client) DeleteProvisionerKey(ctx context.Context, organizationID uuid.U
402402
}
403403
returnnil
404404
}
405+
406+
funcConvertWorkspaceStatus(jobStatusProvisionerJobStatus,transitionWorkspaceTransition)WorkspaceStatus {
407+
switchjobStatus {
408+
caseProvisionerJobPending:
409+
returnWorkspaceStatusPending
410+
caseProvisionerJobRunning:
411+
switchtransition {
412+
caseWorkspaceTransitionStart:
413+
returnWorkspaceStatusStarting
414+
caseWorkspaceTransitionStop:
415+
returnWorkspaceStatusStopping
416+
caseWorkspaceTransitionDelete:
417+
returnWorkspaceStatusDeleting
418+
}
419+
caseProvisionerJobSucceeded:
420+
switchtransition {
421+
caseWorkspaceTransitionStart:
422+
returnWorkspaceStatusRunning
423+
caseWorkspaceTransitionStop:
424+
returnWorkspaceStatusStopped
425+
caseWorkspaceTransitionDelete:
426+
returnWorkspaceStatusDeleted
427+
}
428+
caseProvisionerJobCanceling:
429+
returnWorkspaceStatusCanceling
430+
caseProvisionerJobCanceled:
431+
returnWorkspaceStatusCanceled
432+
caseProvisionerJobFailed:
433+
returnWorkspaceStatusFailed
434+
}
435+
436+
// return error status since we should never get here
437+
returnWorkspaceStatusFailed
438+
}

‎codersdk/workspacesdk/connector_internal_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,11 @@ func (f *fakeDRPCClient) RefreshResumeToken(_ context.Context, _ *proto.RefreshR
571571
},nil
572572
}
573573

574+
// WorkspaceUpdates implements proto.DRPCTailnetClient.
575+
func (*fakeDRPCClient)WorkspaceUpdates(context.Context,*proto.WorkspaceUpdatesRequest) (proto.DRPCTailnet_WorkspaceUpdatesClient,error) {
576+
panic("unimplemented")
577+
}
578+
574579
typefakeDRPCConnstruct{}
575580

576581
var_ drpc.Conn=&fakeDRPCConn{}

‎docs/reference/api/workspaces.md

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

‎enterprise/tailnet/connio.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ var errDisconnect = xerrors.New("graceful disconnect")
133133

134134
func (c*connIO)handleRequest(req*proto.CoordinateRequest)error {
135135
c.logger.Debug(c.peerCtx,"got request")
136-
err:=c.auth.Authorize(req)
136+
err:=c.auth.Authorize(c.coordCtx,req)
137137
iferr!=nil {
138138
c.logger.Warn(c.peerCtx,"unauthorized request",slog.Error(err))
139139
returnxerrors.Errorf("authorize request: %w",err)

‎tailnet/convert.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"tailscale.com/tailcfg"
1010
"tailscale.com/types/key"
1111

12+
"github.com/coder/coder/v2/codersdk"
1213
"github.com/coder/coder/v2/tailnet/proto"
1314
)
1415

@@ -270,3 +271,30 @@ func DERPNodeFromProto(node *proto.DERPMap_Region_Node) *tailcfg.DERPNode {
270271
CanPort80:node.CanPort_80,
271272
}
272273
}
274+
275+
funcWorkspaceStatusToProto(status codersdk.WorkspaceStatus) proto.Workspace_Status {
276+
switchstatus {
277+
casecodersdk.WorkspaceStatusCanceled:
278+
returnproto.Workspace_CANCELED
279+
casecodersdk.WorkspaceStatusCanceling:
280+
returnproto.Workspace_CANCELING
281+
casecodersdk.WorkspaceStatusDeleted:
282+
returnproto.Workspace_DELETED
283+
casecodersdk.WorkspaceStatusDeleting:
284+
returnproto.Workspace_DELETING
285+
casecodersdk.WorkspaceStatusFailed:
286+
returnproto.Workspace_FAILED
287+
casecodersdk.WorkspaceStatusPending:
288+
returnproto.Workspace_PENDING
289+
casecodersdk.WorkspaceStatusRunning:
290+
returnproto.Workspace_RUNNING
291+
casecodersdk.WorkspaceStatusStarting:
292+
returnproto.Workspace_STARTING
293+
casecodersdk.WorkspaceStatusStopped:
294+
returnproto.Workspace_STOPPED
295+
casecodersdk.WorkspaceStatusStopping:
296+
returnproto.Workspace_STOPPING
297+
default:
298+
returnproto.Workspace_UNKNOWN
299+
}
300+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp