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

Commit5adbc9d

Browse files
committed
feat(coderd): implement task to app linking
This change adds workspace build/agent/app linking to tasks and wires itinto `wsbuilder` and `provisionerdserver`.Closescoder/internal#948Closes#20212Closes#19773
1 parent8b065ed commit5adbc9d

File tree

4 files changed

+213
-2
lines changed

4 files changed

+213
-2
lines changed

‎coderd/provisionerdserver/provisionerdserver.go‎

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,14 +1964,26 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
19641964
}
19651965

19661966
appIDs:=make([]string,0)
1967+
agentIDByAppID:=make(map[string]uuid.UUID)
19671968
agentTimeouts:=make(map[time.Duration]bool)// A set of agent timeouts.
19681969
// This could be a bulk insert to improve performance.
19691970
for_,protoResource:=rangejobType.WorkspaceBuild.Resources {
1970-
for_,protoAgent:=rangeprotoResource.Agents {
1971+
for_,protoAgent:=rangeprotoResource.GetAgents() {
1972+
ifprotoAgent==nil {
1973+
continue
1974+
}
1975+
// Always set the agent ID. Previously this ID was generated
1976+
// in InsertWorkspaceResource, but it's required for linking
1977+
// the agent to a task. As per previous behavior, this is OK
1978+
// because we always overwrite the given protoAgent.Id.
1979+
agentID:=uuid.New()
1980+
protoAgent.Id=makeStaticID(agentID)
1981+
19711982
dur:=time.Duration(protoAgent.GetConnectionTimeoutSeconds())*time.Second
19721983
agentTimeouts[dur]=true
19731984
for_,app:=rangeprotoAgent.GetApps() {
19741985
appIDs=append(appIDs,app.GetId())
1986+
agentIDByAppID[app.GetId()]=agentID
19751987
}
19761988
}
19771989

@@ -1987,6 +1999,7 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
19871999
}
19882000

19892001
vartaskAppID uuid.NullUUID
2002+
vartaskAgentID uuid.NullUUID
19902003
varhasAITaskbool
19912004
varwarnUnknownTaskAppIDbool
19922005
iftasks:=jobType.WorkspaceBuild.GetAiTasks();len(tasks)>0 {
@@ -2014,6 +2027,9 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
20142027
}
20152028

20162029
taskAppID= uuid.NullUUID{UUID:id,Valid:true}
2030+
2031+
agentID,ok:=agentIDByAppID[sidebarTaskID]
2032+
taskAgentID= uuid.NullUUID{UUID:agentID,Valid:ok}
20172033
}
20182034

20192035
// This is a hacky workaround for the issue with tasks 'disappearing' on stop:
@@ -2108,6 +2124,27 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
21082124
}
21092125
}
21102126

2127+
iftask,err:=db.GetTaskByWorkspaceID(ctx,workspace.ID);err==nil {
2128+
// Irrespective of whether the agent or sidebar app is present,
2129+
// perform the upsert to ensure a link between the task and
2130+
// workspace build. Linking the task to the build is typically
2131+
// already established by wsbuilder.
2132+
_,err=db.UpsertTaskWorkspaceApp(
2133+
ctx,
2134+
database.UpsertTaskWorkspaceAppParams{
2135+
TaskID:task.ID,
2136+
WorkspaceBuildNumber:workspaceBuild.BuildNumber,
2137+
WorkspaceAgentID:taskAgentID,
2138+
WorkspaceAppID:taskAppID,
2139+
},
2140+
)
2141+
iferr!=nil {
2142+
returnxerrors.Errorf("upsert task workspace app: %w",err)
2143+
}
2144+
}elseif!errors.Is(err,sql.ErrNoRows) {
2145+
returnxerrors.Errorf("get task by workspace id: %w",err)
2146+
}
2147+
21112148
// Regardless of whether there is an AI task or not, update the field to indicate one way or the other since it
21122149
// always defaults to nil. ONLY if has_ai_task=true MUST ai_task_sidebar_app_id be set.
21132150
iferr:=db.UpdateWorkspaceBuildFlagsByID(ctx, database.UpdateWorkspaceBuildFlagsByIDParams{
@@ -2674,7 +2711,15 @@ func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
26742711
apiKeyScope=database.AgentKeyScopeEnumNoUserData
26752712
}
26762713

2677-
agentID:=uuid.New()
2714+
varagentID uuid.UUID
2715+
ifid,ok:=staticID(prAgent.GetId());ok {
2716+
agentID,err=uuid.Parse(id)
2717+
iferr!=nil {
2718+
returnxerrors.Errorf("invalid agent ID format; must be uuid: %w",err)
2719+
}
2720+
}else {
2721+
agentID=uuid.New()
2722+
}
26782723
dbAgent,err:=db.InsertWorkspaceAgent(ctx, database.InsertWorkspaceAgentParams{
26792724
ID:agentID,
26802725
ParentID: uuid.NullUUID{},
@@ -3249,3 +3294,22 @@ func convertDisplayApps(apps *sdkproto.DisplayApps) []database.DisplayApp {
32493294
}
32503295
returndapps
32513296
}
3297+
3298+
conststaticIDPrefix="static:"
3299+
3300+
// makeStaticID encodes the UUID into a magic string that can be identified in
3301+
// InsertWorkspaceResource and used as-is. Typically the provided ID is always
3302+
// replaced for the agent ID but this is not practical when the agent ID needs
3303+
// to be known after-the-fact and we want to avoid additional database lookups.
3304+
funcmakeStaticID(id uuid.UUID)string {
3305+
returnstaticIDPrefix+id.String()
3306+
}
3307+
3308+
// staticID extracts the static ID from a string and returns true if this is a
3309+
// static ID.
3310+
funcstaticID(agentIDstring) (string,bool) {
3311+
if!strings.HasPrefix(agentID,staticIDPrefix) {
3312+
return"",false
3313+
}
3314+
returnstrings.TrimPrefix(agentID,staticIDPrefix),true
3315+
}

‎coderd/provisionerdserver/provisionerdserver_test.go‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2850,6 +2850,8 @@ func TestCompleteJob(t *testing.T) {
28502850
seedFuncfunc(context.Context, testing.TB, database.Store)error// If you need to insert other resources
28512851
transition database.WorkspaceTransition
28522852
input*proto.CompletedJob_WorkspaceBuild
2853+
isTaskbool
2854+
expectTaskStatus database.TaskStatus
28532855
expectHasAiTaskbool
28542856
expectUsageEventbool
28552857
}
@@ -2862,6 +2864,7 @@ func TestCompleteJob(t *testing.T) {
28622864
input:&proto.CompletedJob_WorkspaceBuild{
28632865
// No AiTasks defined.
28642866
},
2867+
isTask:false,
28652868
expectHasAiTask:false,
28662869
expectUsageEvent:false,
28672870
},
@@ -2894,6 +2897,8 @@ func TestCompleteJob(t *testing.T) {
28942897
},
28952898
},
28962899
},
2900+
isTask:true,
2901+
expectTaskStatus:database.TaskStatusInitializing,
28972902
expectHasAiTask:true,
28982903
expectUsageEvent:true,
28992904
},
@@ -2912,6 +2917,8 @@ func TestCompleteJob(t *testing.T) {
29122917
},
29132918
},
29142919
},
2920+
isTask:true,
2921+
expectTaskStatus:database.TaskStatusInitializing,
29152922
expectHasAiTask:false,
29162923
expectUsageEvent:false,
29172924
},
@@ -2944,6 +2951,8 @@ func TestCompleteJob(t *testing.T) {
29442951
},
29452952
},
29462953
},
2954+
isTask:true,
2955+
expectTaskStatus:database.TaskStatusPaused,
29472956
expectHasAiTask:true,
29482957
expectUsageEvent:false,
29492958
},
@@ -2955,6 +2964,8 @@ func TestCompleteJob(t *testing.T) {
29552964
AiTasks: []*sdkproto.AITask{},
29562965
Resources: []*sdkproto.Resource{},
29572966
},
2967+
isTask:true,
2968+
expectTaskStatus:database.TaskStatusPaused,
29582969
expectHasAiTask:true,
29592970
expectUsageEvent:false,
29602971
},
@@ -2992,6 +3003,15 @@ func TestCompleteJob(t *testing.T) {
29923003
OwnerID:user.ID,
29933004
OrganizationID:pd.OrganizationID,
29943005
})
3006+
vartaskTable database.TaskTable
3007+
iftc.isTask {
3008+
taskTable=dbgen.Task(t,db, database.TaskTable{
3009+
OwnerID:user.ID,
3010+
OrganizationID:pd.OrganizationID,
3011+
WorkspaceID: uuid.NullUUID{UUID:workspaceTable.ID,Valid:true},
3012+
TemplateVersionID:version.ID,
3013+
})
3014+
}
29953015

29963016
ctx:=testutil.Context(t,testutil.WaitShort)
29973017
iftc.seedFunc!=nil {
@@ -3060,6 +3080,12 @@ func TestCompleteJob(t *testing.T) {
30603080
require.True(t,build.HasAITask.Valid)// We ALWAYS expect a value to be set, therefore not nil, i.e. valid = true.
30613081
require.Equal(t,tc.expectHasAiTask,build.HasAITask.Bool)
30623082

3083+
iftc.isTask {
3084+
task,err:=db.GetTaskByID(ctx,taskTable.ID)
3085+
require.NoError(t,err)
3086+
require.Equal(t,tc.expectTaskStatus,task.Status)
3087+
}
3088+
30633089
iftc.expectHasAiTask&&build.Transition!=database.WorkspaceTransitionStop {
30643090
require.Equal(t,sidebarAppID,build.AITaskSidebarAppID.UUID.String())
30653091
}

‎coderd/wsbuilder/wsbuilder.go‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"context"
77
"database/sql"
88
"encoding/json"
9+
"errors"
910
"fmt"
1011
"net/http"
1112
"time"
@@ -488,6 +489,21 @@ func (b *Builder) buildTx(authFunc func(action policy.Action, object rbac.Object
488489
returnBuildError{code,"insert workspace build",err}
489490
}
490491

492+
// If this is a task workspace, link it to the latest workspace build.
493+
iftask,err:=store.GetTaskByWorkspaceID(b.ctx,b.workspace.ID);err==nil {
494+
_,err=store.UpsertTaskWorkspaceApp(b.ctx, database.UpsertTaskWorkspaceAppParams{
495+
TaskID:task.ID,
496+
WorkspaceBuildNumber:buildNum,
497+
WorkspaceAgentID: uuid.NullUUID{},// Updated by the provisioner upon job completion.
498+
WorkspaceAppID: uuid.NullUUID{},// Updated by the provisioner upon job completion.
499+
})
500+
iferr!=nil {
501+
returnBuildError{http.StatusInternalServerError,"upsert task workspace app",err}
502+
}
503+
}elseif!errors.Is(err,sql.ErrNoRows) {
504+
returnBuildError{http.StatusInternalServerError,"get task by workspace id",err}
505+
}
506+
491507
err=store.InsertWorkspaceBuildParameters(b.ctx, database.InsertWorkspaceBuildParametersParams{
492508
WorkspaceBuildID:workspaceBuildID,
493509
Name:names,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp