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

Commitddc493e

Browse files
committed
feat: add WorkspaceUpdates rpc
1 parent22985f7 commitddc493e

18 files changed

+1422
-232
lines changed

‎coderd/coderd.go

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

‎coderd/workspaceagents.go

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

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

871855
api.WebsocketWaitMutex.Lock()
@@ -895,6 +879,28 @@ func (api *API) workspaceAgentClientCoordinate(rw http.ResponseWriter, r *http.R
895879
}
896880
}
897881

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

‎coderd/workspacebuilds.go

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,7 @@ func (api *API) convertWorkspaceBuild(
947947
MaxDeadline:codersdk.NewNullTime(build.MaxDeadline,!build.MaxDeadline.IsZero()),
948948
Reason:codersdk.BuildReason(build.Reason),
949949
Resources:apiResources,
950-
Status:convertWorkspaceStatus(apiJob.Status,transition),
950+
Status:codersdk.ConvertWorkspaceStatus(apiJob.Status,transition),
951951
DailyCost:build.DailyCost,
952952
},nil
953953
}
@@ -976,37 +976,3 @@ func convertWorkspaceResource(resource database.WorkspaceResource, agents []code
976976
DailyCost:resource.DailyCost,
977977
}
978978
}
979-
980-
funcconvertWorkspaceStatus(jobStatus codersdk.ProvisionerJobStatus,transition codersdk.WorkspaceTransition) codersdk.WorkspaceStatus {
981-
switchjobStatus {
982-
casecodersdk.ProvisionerJobPending:
983-
returncodersdk.WorkspaceStatusPending
984-
casecodersdk.ProvisionerJobRunning:
985-
switchtransition {
986-
casecodersdk.WorkspaceTransitionStart:
987-
returncodersdk.WorkspaceStatusStarting
988-
casecodersdk.WorkspaceTransitionStop:
989-
returncodersdk.WorkspaceStatusStopping
990-
casecodersdk.WorkspaceTransitionDelete:
991-
returncodersdk.WorkspaceStatusDeleting
992-
}
993-
casecodersdk.ProvisionerJobSucceeded:
994-
switchtransition {
995-
casecodersdk.WorkspaceTransitionStart:
996-
returncodersdk.WorkspaceStatusRunning
997-
casecodersdk.WorkspaceTransitionStop:
998-
returncodersdk.WorkspaceStatusStopped
999-
casecodersdk.WorkspaceTransitionDelete:
1000-
returncodersdk.WorkspaceStatusDeleted
1001-
}
1002-
casecodersdk.ProvisionerJobCanceling:
1003-
returncodersdk.WorkspaceStatusCanceling
1004-
casecodersdk.ProvisionerJobCanceled:
1005-
returncodersdk.WorkspaceStatusCanceled
1006-
casecodersdk.ProvisionerJobFailed:
1007-
returncodersdk.WorkspaceStatusFailed
1008-
}
1009-
1010-
// return error status since we should never get here
1011-
returncodersdk.WorkspaceStatusFailed
1012-
}

‎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 (
@@ -2068,6 +2071,11 @@ func (api *API) publishWorkspaceUpdate(ctx context.Context, workspaceID uuid.UUI
20682071
api.Logger.Warn(ctx,"failed to publish workspace update",
20692072
slog.F("workspace_id",workspaceID),slog.Error(err))
20702073
}
2074+
err=api.Pubsub.Publish(codersdk.AllWorkspacesNotifyChannel, []byte(workspaceID.String()))
2075+
iferr!=nil {
2076+
api.Logger.Warn(ctx,"failed to publish all workspaces update",
2077+
slog.F("workspace_id",workspaceID),slog.Error(err))
2078+
}
20712079
}
20722080

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

‎codersdk/provisionerdaemons.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,3 +387,37 @@ func (c *Client) DeleteProvisionerKey(ctx context.Context, organizationID uuid.U
387387
}
388388
returnnil
389389
}
390+
391+
funcConvertWorkspaceStatus(jobStatusProvisionerJobStatus,transitionWorkspaceTransition)WorkspaceStatus {
392+
switchjobStatus {
393+
caseProvisionerJobPending:
394+
returnWorkspaceStatusPending
395+
caseProvisionerJobRunning:
396+
switchtransition {
397+
caseWorkspaceTransitionStart:
398+
returnWorkspaceStatusStarting
399+
caseWorkspaceTransitionStop:
400+
returnWorkspaceStatusStopping
401+
caseWorkspaceTransitionDelete:
402+
returnWorkspaceStatusDeleting
403+
}
404+
caseProvisionerJobSucceeded:
405+
switchtransition {
406+
caseWorkspaceTransitionStart:
407+
returnWorkspaceStatusRunning
408+
caseWorkspaceTransitionStop:
409+
returnWorkspaceStatusStopped
410+
caseWorkspaceTransitionDelete:
411+
returnWorkspaceStatusDeleted
412+
}
413+
caseProvisionerJobCanceling:
414+
returnWorkspaceStatusCanceling
415+
caseProvisionerJobCanceled:
416+
returnWorkspaceStatusCanceled
417+
caseProvisionerJobFailed:
418+
returnWorkspaceStatusFailed
419+
}
420+
421+
// return error status since we should never get here
422+
returnWorkspaceStatusFailed
423+
}

‎codersdk/workspaces.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,3 +661,5 @@ func (c *Client) WorkspaceTimings(ctx context.Context, id uuid.UUID) (WorkspaceT
661661
funcWorkspaceNotifyChannel(id uuid.UUID)string {
662662
returnfmt.Sprintf("workspace:%s",id)
663663
}
664+
665+
constAllWorkspacesNotifyChannel="all-workspaces"

‎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{}

‎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+
}

‎tailnet/coordinator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ func (c *core) handleRequest(p *peer, req *proto.CoordinateRequest) error {
577577
returnErrAlreadyRemoved
578578
}
579579

580-
iferr:=pr.auth.Authorize(req);err!=nil {
580+
iferr:=pr.auth.Authorize(context.Background(),req);err!=nil {
581581
returnxerrors.Errorf("authorize request: %w",err)
582582
}
583583

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp