@@ -3,6 +3,7 @@ package coderd
3
3
import (
4
4
"context"
5
5
"database/sql"
6
+ "encoding/json"
6
7
"errors"
7
8
"fmt"
8
9
"net/http"
@@ -22,6 +23,7 @@ import (
22
23
"github.com/coder/coder/v2/coderd/rbac/policy"
23
24
"github.com/coder/coder/v2/coderd/searchquery"
24
25
"github.com/coder/coder/v2/coderd/taskname"
26
+ "github.com/coder/coder/v2/coderd/util/rwsink"
25
27
"github.com/coder/coder/v2/codersdk"
26
28
)
27
29
@@ -186,9 +188,86 @@ func (api *API) tasksCreate(rw http.ResponseWriter, r *http.Request) {
186
188
WorkspaceOwner :owner .Username ,
187
189
},
188
190
})
189
-
190
191
defer commitAudit ()
191
- createWorkspace (ctx ,aReq ,apiKey .UserID ,api ,owner ,createReq ,rw ,r )
192
+
193
+ rwSink := rwsink .New ()
194
+ createWorkspace (ctx ,aReq ,apiKey .UserID ,api ,owner ,createReq ,rwSink ,r )
195
+
196
+ if rwSink .StatusCode != nil && * rwSink .StatusCode == http .StatusCreated {
197
+ bytes := rwSink .ResetBody ()
198
+
199
+ var ws codersdk.Workspace
200
+ if err := json .Unmarshal (bytes ,& ws );err != nil {
201
+ httpapi .Write (ctx ,rw ,http .StatusInternalServerError , codersdk.Response {
202
+ Message :"Internal error decoding created workspace" ,
203
+ Detail :err .Error (),
204
+ })
205
+ return
206
+ }
207
+
208
+ task := taskFromWorkspace (ws ,req .Prompt )
209
+
210
+ httpapi .Write (ctx ,rwSink ,http .StatusCreated ,task )
211
+ }
212
+
213
+ _ = rwSink .FlushTo (rw )
214
+ }
215
+
216
+ func taskFromWorkspace (ws codersdk.Workspace ,initialPrompt string ) codersdk.Task {
217
+ // TODO(DanielleMaywood):
218
+ // This just picks up the first agent it discovers.
219
+ // This approach _might_ break when a task has multiple agents,
220
+ // depending on which agent was found first.
221
+ //
222
+ // We explicitly do not have support for running tasks
223
+ // inside of a sub agent at the moment, so we can be sure
224
+ // that any sub agents are not the agent we're looking for.
225
+ var taskAgentID uuid.NullUUID
226
+ var taskAgentLifecycle * codersdk.WorkspaceAgentLifecycle
227
+ var taskAgentHealth * codersdk.WorkspaceAgentHealth
228
+ for _ ,resource := range ws .LatestBuild .Resources {
229
+ for _ ,agent := range resource .Agents {
230
+ if agent .ParentID .Valid {
231
+ continue
232
+ }
233
+
234
+ taskAgentID = uuid.NullUUID {Valid :true ,UUID :agent .ID }
235
+ taskAgentLifecycle = & agent .LifecycleState
236
+ taskAgentHealth = & agent .Health
237
+ break
238
+ }
239
+ }
240
+
241
+ var currentState * codersdk.TaskStateEntry
242
+ if ws .LatestAppStatus != nil {
243
+ currentState = & codersdk.TaskStateEntry {
244
+ Timestamp :ws .LatestAppStatus .CreatedAt ,
245
+ State :codersdk .TaskState (ws .LatestAppStatus .State ),
246
+ Message :ws .LatestAppStatus .Message ,
247
+ URI :ws .LatestAppStatus .URI ,
248
+ }
249
+ }
250
+
251
+ return codersdk.Task {
252
+ ID :ws .ID ,
253
+ OrganizationID :ws .OrganizationID ,
254
+ OwnerID :ws .OwnerID ,
255
+ OwnerName :ws .OwnerName ,
256
+ Name :ws .Name ,
257
+ TemplateID :ws .TemplateID ,
258
+ TemplateName :ws .TemplateName ,
259
+ TemplateDisplayName :ws .TemplateDisplayName ,
260
+ TemplateIcon :ws .TemplateIcon ,
261
+ WorkspaceID : uuid.NullUUID {Valid :true ,UUID :ws .ID },
262
+ WorkspaceAgentID :taskAgentID ,
263
+ WorkspaceAgentLifecycle :taskAgentLifecycle ,
264
+ WorkspaceAgentHealth :taskAgentHealth ,
265
+ CreatedAt :ws .CreatedAt ,
266
+ UpdatedAt :ws .UpdatedAt ,
267
+ InitialPrompt :initialPrompt ,
268
+ Status :ws .LatestBuild .Status ,
269
+ CurrentState :currentState ,
270
+ }
192
271
}
193
272
194
273
// tasksFromWorkspaces converts a slice of API workspaces into tasks, fetching
@@ -213,60 +292,7 @@ func (api *API) tasksFromWorkspaces(ctx context.Context, apiWorkspaces []codersd
213
292
214
293
tasks := make ([]codersdk.Task ,0 ,len (apiWorkspaces ))
215
294
for _ ,ws := range apiWorkspaces {
216
- // TODO(DanielleMaywood):
217
- // This just picks up the first agent it discovers.
218
- // This approach _might_ break when a task has multiple agents,
219
- // depending on which agent was found first.
220
- //
221
- // We explicitly do not have support for running tasks
222
- // inside of a sub agent at the moment, so we can be sure
223
- // that any sub agents are not the agent we're looking for.
224
- var taskAgentID uuid.NullUUID
225
- var taskAgentLifecycle * codersdk.WorkspaceAgentLifecycle
226
- var taskAgentHealth * codersdk.WorkspaceAgentHealth
227
- for _ ,resource := range ws .LatestBuild .Resources {
228
- for _ ,agent := range resource .Agents {
229
- if agent .ParentID .Valid {
230
- continue
231
- }
232
-
233
- taskAgentID = uuid.NullUUID {Valid :true ,UUID :agent .ID }
234
- taskAgentLifecycle = & agent .LifecycleState
235
- taskAgentHealth = & agent .Health
236
- break
237
- }
238
- }
239
-
240
- var currentState * codersdk.TaskStateEntry
241
- if ws .LatestAppStatus != nil {
242
- currentState = & codersdk.TaskStateEntry {
243
- Timestamp :ws .LatestAppStatus .CreatedAt ,
244
- State :codersdk .TaskState (ws .LatestAppStatus .State ),
245
- Message :ws .LatestAppStatus .Message ,
246
- URI :ws .LatestAppStatus .URI ,
247
- }
248
- }
249
-
250
- tasks = append (tasks , codersdk.Task {
251
- ID :ws .ID ,
252
- OrganizationID :ws .OrganizationID ,
253
- OwnerID :ws .OwnerID ,
254
- OwnerName :ws .OwnerName ,
255
- Name :ws .Name ,
256
- TemplateID :ws .TemplateID ,
257
- TemplateName :ws .TemplateName ,
258
- TemplateDisplayName :ws .TemplateDisplayName ,
259
- TemplateIcon :ws .TemplateIcon ,
260
- WorkspaceID : uuid.NullUUID {Valid :true ,UUID :ws .ID },
261
- WorkspaceAgentID :taskAgentID ,
262
- WorkspaceAgentLifecycle :taskAgentLifecycle ,
263
- WorkspaceAgentHealth :taskAgentHealth ,
264
- CreatedAt :ws .CreatedAt ,
265
- UpdatedAt :ws .UpdatedAt ,
266
- InitialPrompt :promptsByBuildID [ws .LatestBuild .ID ],
267
- Status :ws .LatestBuild .Status ,
268
- CurrentState :currentState ,
269
- })
295
+ tasks = append (tasks ,taskFromWorkspace (ws ,promptsByBuildID [ws .LatestBuild .ID ]))
270
296
}
271
297
272
298
return tasks ,nil