Skip to content

Commit 66fa2a1

Browse files
authored
docs: API workspace agents and builds (#5538)
1 parent e6b17b6 commit 66fa2a1

25 files changed

+4341
-261
lines changed

coderd/apidoc/docs.go

Lines changed: 1037 additions & 18 deletions
Large diffs are not rendered by default.

coderd/apidoc/swagger.json

Lines changed: 936 additions & 25 deletions
Large diffs are not rendered by default.

coderd/gitsshkey.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,14 @@ func (api *API) gitSSHKey(rw http.ResponseWriter, r *http.Request) {
100100
})
101101
}
102102

103+
// @Summary Get workspace agent Git SSH key
104+
// @ID get-workspace-agent-git-ssh-key
105+
// @Security CoderSessionToken
106+
// @Accept json
107+
// @Produce json
108+
// @Tags Agents
109+
// @Success 200 {object} codersdk.AgentGitSSHKey
110+
// @Router /workspaceagents/me/gitsshkey [get]
103111
func (api *API) agentGitSSHKey(rw http.ResponseWriter, r *http.Request) {
104112
ctx := r.Context()
105113
agent := httpmw.WorkspaceAgent(r)

coderd/workspaceagents.go

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ func (api *API) workspaceAgent(rw http.ResponseWriter, r *http.Request) {
6363
httpapi.Write(ctx, rw, http.StatusOK, apiAgent)
6464
}
6565

66+
// @Summary Get authorized workspace agent metadata
67+
// @ID get-authorized-workspace-agent-metadata
68+
// @Security CoderSessionToken
69+
// @Accept json
70+
// @Produce json
71+
// @Tags Agents
72+
// @Success 200 {object} codersdk.WorkspaceAgentMetadata
73+
// @Router /workspaceagents/me/metadata [get]
6674
func (api *API) workspaceAgentMetadata(rw http.ResponseWriter, r *http.Request) {
6775
ctx := r.Context()
6876
workspaceAgent := httpmw.WorkspaceAgent(r)
@@ -138,6 +146,15 @@ func (api *API) workspaceAgentMetadata(rw http.ResponseWriter, r *http.Request)
138146
})
139147
}
140148

149+
// @Summary Submit workspace agent version
150+
// @ID submit-workspace-workspace-agent-version
151+
// @Security CoderSessionToken
152+
// @Produce application/json
153+
// @Tags Agents
154+
// @Param request body codersdk.PostWorkspaceAgentVersionRequest true "Version request"
155+
// @Success 200
156+
// @Router /workspaceagents/me/version [post]
157+
// @x-apidocgen {"skip": true}
141158
func (api *API) postWorkspaceAgentVersion(rw http.ResponseWriter, r *http.Request) {
142159
ctx := r.Context()
143160
workspaceAgent := httpmw.WorkspaceAgent(r)
@@ -438,6 +455,15 @@ func (api *API) workspaceAgentConnection(rw http.ResponseWriter, r *http.Request
438455
})
439456
}
440457

458+
// @Summary Coordinate workspace agent via Tailnet
459+
// @Description It accepts a WebSocket connection to an agent that listens to
460+
// @Description incoming connections and publishes node updates.
461+
// @ID get-workspace-agent-git-ssh-key-via-tailnet
462+
// @Security CoderSessionToken
463+
// @Produce json
464+
// @Tags Agents
465+
// @Success 101
466+
// @Router /workspaceagents/me/coordinate [get]
441467
func (api *API) workspaceAgentCoordinate(rw http.ResponseWriter, r *http.Request) {
442468
ctx := r.Context()
443469

@@ -757,6 +783,14 @@ func convertWorkspaceAgent(derpMap *tailcfg.DERPMap, coordinator tailnet.Coordin
757783
return workspaceAgent, nil
758784
}
759785

786+
// @Summary Submit workspace agent stats
787+
// @ID submit-workspace-workspace-agent-stats
788+
// @Security CoderSessionToken
789+
// @Produce application/json
790+
// @Tags Agents
791+
// @Param request body codersdk.AgentStats true "Stats request"
792+
// @Success 200 {object} codersdk.AgentStatsResponse
793+
// @Router /workspaceagents/me/report-stats [post]
760794
func (api *API) workspaceAgentReportStats(rw http.ResponseWriter, r *http.Request) {
761795
ctx := r.Context()
762796

@@ -826,6 +860,14 @@ func (api *API) workspaceAgentReportStats(rw http.ResponseWriter, r *http.Reques
826860
})
827861
}
828862

863+
// @Summary Submit workspace application health
864+
// @ID submit-workspace-workspace-agent-health
865+
// @Security CoderSessionToken
866+
// @Produce application/json
867+
// @Tags Agents
868+
// @Param request body codersdk.PostWorkspaceAppHealthsRequest true "Application health request"
869+
// @Success 200
870+
// @Router /workspaceagents/me/app-health [post]
829871
func (api *API) postWorkspaceAppHealth(rw http.ResponseWriter, r *http.Request) {
830872
ctx := r.Context()
831873
workspaceAgent := httpmw.WorkspaceAgent(r)
@@ -941,8 +983,19 @@ func (api *API) postWorkspaceAppHealth(rw http.ResponseWriter, r *http.Request)
941983
httpapi.Write(ctx, rw, http.StatusOK, nil)
942984
}
943985

944-
// postWorkspaceAgentsGitAuth returns a username and password for use
986+
// workspaceAgentsGitAuth returns a username and password for use
945987
// with GIT_ASKPASS.
988+
//
989+
// @Summary Get workspace agent Git auth
990+
// @ID get-workspace-agent-git-auth
991+
// @Security CoderSessionToken
992+
// @Accept json
993+
// @Produce json
994+
// @Tags Agents
995+
// @Param url query string true "Git URL" format(uri)
996+
// @Param listen query bool false "Wait for a new token to be issued"
997+
// @Success 200 {object} codersdk.WorkspaceAgentGitAuthResponse
998+
// @Router /workspaceagents/me/gitauth [get]
946999
func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request) {
9471000
ctx := r.Context()
9481001
gitURL := r.URL.Query().Get("url")

coderd/workspacebuilds.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ import (
2323
"github.com/coder/coder/codersdk"
2424
)
2525

26+
// @Summary Get workspace build
27+
// @ID get-workspace-build
28+
// @Security CoderSessionToken
29+
// @Produce json
30+
// @Tags Builds
31+
// @Param workspacebuild path string true "Workspace build ID"
32+
// @Success 200 {object} codersdk.WorkspaceBuild
33+
// @Router /workspacebuilds/{workspacebuild} [get]
2634
func (api *API) workspaceBuild(rw http.ResponseWriter, r *http.Request) {
2735
ctx := r.Context()
2836
workspaceBuild := httpmw.WorkspaceBuildParam(r)
@@ -64,6 +72,18 @@ func (api *API) workspaceBuild(rw http.ResponseWriter, r *http.Request) {
6472
httpapi.Write(ctx, rw, http.StatusOK, apiBuild)
6573
}
6674

75+
// @Summary Get workspace builds by workspace ID
76+
// @ID get-workspace-builds-by-workspace-id
77+
// @Security CoderSessionToken
78+
// @Produce json
79+
// @Tags Builds
80+
// @Param id path string true "Workspace ID" format(uuid)
81+
// @Param after_id query string false "After ID" format(uuid)
82+
// @Param limit query int false "Page limit"
83+
// @Param offset query int false "Page offset"
84+
// @Param since query string false "Since timestamp" format(date-time)
85+
// @Success 200 {array} codersdk.WorkspaceBuild
86+
// @Router /workspaces/{id}/builds [get]
6787
func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
6888
ctx := r.Context()
6989
workspace := httpmw.WorkspaceParam(r)
@@ -254,6 +274,19 @@ func (api *API) workspaceBuildByBuildNumber(rw http.ResponseWriter, r *http.Requ
254274
httpapi.Write(ctx, rw, http.StatusOK, apiBuild)
255275
}
256276

277+
// Azure supports instance identity verification:
278+
// https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=linux#tabgroup_14
279+
//
280+
// @Summary Create workspace build
281+
// @ID create-workspace-build
282+
// @Security CoderSessionToken
283+
// @Accepts json
284+
// @Produce json
285+
// @Tags Builds
286+
// @Param id path string true "Workspace ID" format(uuid)
287+
// @Param request body codersdk.CreateWorkspaceBuildRequest true "Create workspace build request"
288+
// @Success 200 {object} codersdk.WorkspaceBuild
289+
// @Router /workspaces/{id}/builds [post]
257290
func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
258291
ctx := r.Context()
259292
apiKey := httpmw.APIKey(r)
@@ -535,6 +568,14 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
535568
httpapi.Write(ctx, rw, http.StatusCreated, apiBuild)
536569
}
537570

571+
// @Summary Cancel workspace build
572+
// @ID cancel-workspace-build
573+
// @Security CoderSessionToken
574+
// @Produce json
575+
// @Tags Builds
576+
// @Param workspacebuild path string true "Workspace build ID"
577+
// @Success 200 {object} codersdk.Response
578+
// @Router /workspacebuilds/{workspacebuild}/cancel [patch]
538579
func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Request) {
539580
ctx := r.Context()
540581
workspaceBuild := httpmw.WorkspaceBuildParam(r)
@@ -630,6 +671,14 @@ func (api *API) verifyUserCanCancelWorkspaceBuilds(ctx context.Context, userID u
630671
return slices.Contains(user.RBACRoles, rbac.RoleOwner()), nil // only user with "owner" role can cancel workspace builds
631672
}
632673

674+
// @Summary Get workspace resources for workspace build
675+
// @ID get-workspace-resources-for-workspace-build
676+
// @Security CoderSessionToken
677+
// @Produce json
678+
// @Tags Builds
679+
// @Param workspacebuild path string true "Workspace build ID"
680+
// @Success 200 {array} codersdk.WorkspaceResource
681+
// @Router /workspacebuilds/{workspacebuild}/resources [get]
633682
func (api *API) workspaceBuildResources(rw http.ResponseWriter, r *http.Request) {
634683
ctx := r.Context()
635684
workspaceBuild := httpmw.WorkspaceBuildParam(r)
@@ -657,6 +706,17 @@ func (api *API) workspaceBuildResources(rw http.ResponseWriter, r *http.Request)
657706
api.provisionerJobResources(rw, r, job)
658707
}
659708

709+
// @Summary Get workspace build logs
710+
// @ID get-workspace-build-logs
711+
// @Security CoderSessionToken
712+
// @Produce json
713+
// @Tags Builds
714+
// @Param workspacebuild path string true "Workspace build ID"
715+
// @Param before query int false "Before Unix timestamp"
716+
// @Param after query int false "After Unix timestamp"
717+
// @Param follow query bool false "Follow log stream"
718+
// @Success 200 {array} codersdk.ProvisionerJobLog
719+
// @Router /workspacebuilds/{workspacebuild}/logs [get]
660720
func (api *API) workspaceBuildLogs(rw http.ResponseWriter, r *http.Request) {
661721
ctx := r.Context()
662722
workspaceBuild := httpmw.WorkspaceBuildParam(r)
@@ -684,6 +744,14 @@ func (api *API) workspaceBuildLogs(rw http.ResponseWriter, r *http.Request) {
684744
api.provisionerJobLogs(rw, r, job)
685745
}
686746

747+
// @Summary Get provisioner state for workspace build
748+
// @ID get-provisioner-state-for-workspace-build
749+
// @Security CoderSessionToken
750+
// @Produce json
751+
// @Tags Builds
752+
// @Param workspacebuild path string true "Workspace build ID"
753+
// @Success 200 {object} codersdk.WorkspaceBuild
754+
// @Router /workspacebuilds/{workspacebuild}/state [get]
687755
func (api *API) workspaceBuildState(rw http.ResponseWriter, r *http.Request) {
688756
ctx := r.Context()
689757
workspaceBuild := httpmw.WorkspaceBuildParam(r)

coderd/workspaceresourceauth.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ import (
1919

2020
// Azure supports instance identity verification:
2121
// https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=linux#tabgroup_14
22+
//
23+
// @Summary Authenticate agent on Azure instance
24+
// @ID authenticate-agent-on-azure-instance
25+
// @Security CoderSessionToken
26+
// @Produce json
27+
// @Tags Agents
28+
// @Param request body codersdk.AzureInstanceIdentityToken true "Instance identity token"
29+
// @Success 200 {object} codersdk.WorkspaceAgentAuthenticateResponse
30+
// @Router /workspaceagents/azure-instance-identity [post]
2231
func (api *API) postWorkspaceAuthAzureInstanceIdentity(rw http.ResponseWriter, r *http.Request) {
2332
ctx := r.Context()
2433
var req codersdk.AzureInstanceIdentityToken
@@ -36,6 +45,15 @@ func (api *API) postWorkspaceAuthAzureInstanceIdentity(rw http.ResponseWriter, r
3645
api.handleAuthInstanceID(rw, r, instanceID)
3746
}
3847

48+
// @Summary Authenticate agent on AWS instance
49+
// @ID authenticate-agent-on-aws-instance
50+
// @Security CoderSessionToken
51+
// @Produce json
52+
// @Tags Agents
53+
// @Param request body codersdk.AWSInstanceIdentityToken true "Instance identity token"
54+
// @Success 200 {object} codersdk.WorkspaceAgentAuthenticateResponse
55+
// @Router /workspaceagents/aws-instance-identity [post]
56+
//
3957
// AWS supports instance identity verification:
4058
// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html
4159
// Using this, we can exchange a signed instance payload for an agent token.
@@ -56,6 +74,15 @@ func (api *API) postWorkspaceAuthAWSInstanceIdentity(rw http.ResponseWriter, r *
5674
api.handleAuthInstanceID(rw, r, identity.InstanceID)
5775
}
5876

77+
// @Summary Authenticate agent on Google Cloud instance
78+
// @ID authenticate-agent-on-google-cloud-instance
79+
// @Security CoderSessionToken
80+
// @Produce json
81+
// @Tags Agents
82+
// @Param request body codersdk.GoogleInstanceIdentityToken true "Instance identity token"
83+
// @Success 200 {object} codersdk.WorkspaceAgentAuthenticateResponse
84+
// @Router /workspaceagents/google-instance-identity [post]
85+
//
5986
// Google Compute Engine supports instance identity verification:
6087
// https://cloud.google.com/compute/docs/instances/verifying-instance-identity
6188
// Using this, we can exchange a signed instance payload for an agent token.

codersdk/provisionerdaemons.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,24 +66,26 @@ const (
6666
ProvisionerJobFailed ProvisionerJobStatus = "failed"
6767
)
6868

69+
// ProvisionerJob describes the job executed by the provisioning daemon.
6970
type ProvisionerJob struct {
70-
ID uuid.UUID `json:"id"`
71-
CreatedAt time.Time `json:"created_at"`
72-
StartedAt *time.Time `json:"started_at,omitempty"`
73-
CompletedAt *time.Time `json:"completed_at,omitempty"`
74-
CanceledAt *time.Time `json:"canceled_at,omitempty"`
71+
ID uuid.UUID `json:"id" format:"uuid"`
72+
CreatedAt time.Time `json:"created_at" format:"date-time"`
73+
StartedAt *time.Time `json:"started_at,omitempty" format:"date-time"`
74+
CompletedAt *time.Time `json:"completed_at,omitempty" format:"date-time"`
75+
CanceledAt *time.Time `json:"canceled_at,omitempty" format:"date-time"`
7576
Error string `json:"error,omitempty"`
76-
Status ProvisionerJobStatus `json:"status"`
77-
WorkerID *uuid.UUID `json:"worker_id,omitempty"`
78-
FileID uuid.UUID `json:"file_id"`
77+
Status ProvisionerJobStatus `json:"status" enums:"pending,running,succeeded,canceling,canceled,failed"`
78+
WorkerID *uuid.UUID `json:"worker_id,omitempty" format:"uuid"`
79+
FileID uuid.UUID `json:"file_id" format:"uuid"`
7980
Tags map[string]string `json:"tags"`
8081
}
8182

83+
// ProvisionerJobLog represents the provisioner log entry annotated with source and level.
8284
type ProvisionerJobLog struct {
8385
ID int64 `json:"id"`
84-
CreatedAt time.Time `json:"created_at"`
86+
CreatedAt time.Time `json:"created_at" format:"date-time"`
8587
Source LogSource `json:"log_source"`
86-
Level LogLevel `json:"log_level"`
88+
Level LogLevel `json:"log_level" enums:"trace,debug,info,warn,error"`
8789
Stage string `json:"stage"`
8890
Output string `json:"output"`
8991
}

codersdk/workspaceagents.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ const (
3535
)
3636

3737
type WorkspaceAgent struct {
38-
ID uuid.UUID `json:"id"`
39-
CreatedAt time.Time `json:"created_at"`
40-
UpdatedAt time.Time `json:"updated_at"`
41-
FirstConnectedAt *time.Time `json:"first_connected_at,omitempty"`
42-
LastConnectedAt *time.Time `json:"last_connected_at,omitempty"`
43-
DisconnectedAt *time.Time `json:"disconnected_at,omitempty"`
44-
Status WorkspaceAgentStatus `json:"status"`
38+
ID uuid.UUID `json:"id" format:"uuid"`
39+
CreatedAt time.Time `json:"created_at" format:"date-time"`
40+
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
41+
FirstConnectedAt *time.Time `json:"first_connected_at,omitempty" format:"date-time"`
42+
LastConnectedAt *time.Time `json:"last_connected_at,omitempty" format:"date-time"`
43+
DisconnectedAt *time.Time `json:"disconnected_at,omitempty" format:"date-time"`
44+
Status WorkspaceAgentStatus `json:"status" enums:"connecting,connected,disconnected,timeout"`
4545
Name string `json:"name"`
46-
ResourceID uuid.UUID `json:"resource_id"`
46+
ResourceID uuid.UUID `json:"resource_id" format:"uuid"`
4747
InstanceID string `json:"instance_id,omitempty"`
4848
Architecture string `json:"architecture"`
4949
EnvironmentVariables map[string]string `json:"environment_variables"`
@@ -115,6 +115,7 @@ type WorkspaceAgentConnectionInfo struct {
115115
}
116116

117117
// @typescript-ignore PostWorkspaceAgentVersionRequest
118+
// @Description x-apidocgen:skip
118119
type PostWorkspaceAgentVersionRequest struct {
119120
Version string `json:"version"`
120121
}

codersdk/workspaceapps.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const (
2222
)
2323

2424
type WorkspaceApp struct {
25-
ID uuid.UUID `json:"id"`
25+
ID uuid.UUID `json:"id" format:"uuid"`
2626
// URL is the address being proxied to inside the workspace.
2727
// If external is specified, this will be opened on the client.
2828
URL string `json:"url"`
@@ -42,7 +42,7 @@ type WorkspaceApp struct {
4242
// and there is no app wildcard configured on the server, the app will not
4343
// be accessible in the UI.
4444
Subdomain bool `json:"subdomain"`
45-
SharingLevel WorkspaceAppSharingLevel `json:"sharing_level"`
45+
SharingLevel WorkspaceAppSharingLevel `json:"sharing_level" enums:"owner,authenticated,public"`
4646
// Healthcheck specifies the configuration for checking app health.
4747
Healthcheck Healthcheck `json:"healthcheck"`
4848
Health WorkspaceAppHealth `json:"health"`

codersdk/workspacebuilds.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,15 @@ type WorkspaceBuild struct {
6565
InitiatorID uuid.UUID `json:"initiator_id" format:"uuid"`
6666
InitiatorUsername string `json:"initiator_name"`
6767
Job ProvisionerJob `json:"job"`
68-
Reason BuildReason `db:"reason" json:"reason"`
68+
Reason BuildReason `db:"reason" json:"reason" enums:"initiator,autostart,autostop"`
6969
Resources []WorkspaceResource `json:"resources"`
7070
Deadline NullTime `json:"deadline,omitempty" format:"date-time"`
7171
Status WorkspaceStatus `json:"status" enums:"pending,starting,running,stopping,stopped,failed,canceling,canceled,deleting,deleted"`
7272
DailyCost int32 `json:"daily_cost"`
7373
}
7474

75+
// WorkspaceResource describes resources used to create a workspace, for instance:
76+
// containers, images, volumes.
7577
type WorkspaceResource struct {
7678
ID uuid.UUID `json:"id" format:"uuid"`
7779
CreatedAt time.Time `json:"created_at" format:"date-time"`
@@ -86,6 +88,7 @@ type WorkspaceResource struct {
8688
DailyCost int32 `json:"daily_cost"`
8789
}
8890

91+
// WorkspaceResourceMetadata annotates the workspace resource with custom key-value pairs.
8992
type WorkspaceResourceMetadata struct {
9093
Key string `json:"key"`
9194
Value string `json:"value"`

0 commit comments

Comments
 (0)