@@ -3,6 +3,7 @@ package coderd
33import (
44"context"
55"database/sql"
6+ "encoding/json"
67"errors"
78"fmt"
89"net/http"
@@ -22,6 +23,7 @@ import (
2223"github.com/coder/coder/v2/coderd/rbac/policy"
2324"github.com/coder/coder/v2/coderd/searchquery"
2425"github.com/coder/coder/v2/coderd/taskname"
26+ "github.com/coder/coder/v2/coderd/util/rwsink"
2527"github.com/coder/coder/v2/codersdk"
2628)
2729
@@ -186,9 +188,86 @@ func (api *API) tasksCreate(rw http.ResponseWriter, r *http.Request) {
186188WorkspaceOwner :owner .Username ,
187189},
188190})
189-
190191defer 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+ }
192271}
193272
194273// tasksFromWorkspaces converts a slice of API workspaces into tasks, fetching
@@ -213,60 +292,7 @@ func (api *API) tasksFromWorkspaces(ctx context.Context, apiWorkspaces []codersd
213292
214293tasks := make ([]codersdk.Task ,0 ,len (apiWorkspaces ))
215294for _ ,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 ]))
270296}
271297
272298return tasks ,nil