Skip to content

Commit 89b1887

Browse files
committed
fix: Convert all jobs to use a common resource and agent type
This enables a consistent API for project import and provisioned resources.
1 parent 108f1b5 commit 89b1887

17 files changed

+629
-628
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"ntqry",
5151
"oneof",
5252
"parameterscopeid",
53+
"pqtype",
5354
"promptui",
5455
"protobuf",
5556
"provisionerd",

cli/projects.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func projects() *cobra.Command {
4040
return cmd
4141
}
4242

43-
func displayProjectImportInfo(cmd *cobra.Command, parameterSchemas []coderd.ParameterSchema, parameterValues []coderd.ComputedParameterValue, resources []coderd.ProjectImportJobResource) error {
43+
func displayProjectImportInfo(cmd *cobra.Command, parameterSchemas []coderd.ParameterSchema, parameterValues []coderd.ComputedParameterValue, resources []coderd.ProvisionerJobResource) error {
4444
schemaByID := map[string]coderd.ParameterSchema{}
4545
for _, schema := range parameterSchemas {
4646
schemaByID[schema.ID.String()] = schema

coderd/projectimport.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ type ParameterSchema database.ParameterSchema
2121
// ComputedParameterValue represents a computed parameter value.
2222
type ComputedParameterValue parameter.ComputedValue
2323

24-
// ProjectImportJobResource is a resource created by a project import job.
25-
type ProjectImportJobResource database.ProjectImportJobResource
26-
2724
// CreateProjectImportJobRequest provides options to create a project import job.
2825
type CreateProjectImportJobRequest struct {
2926
StorageMethod database.ProvisionerStorageMethod `json:"storage_method" validate:"oneof=file,required"`
@@ -167,7 +164,7 @@ func (api *api) projectImportJobResourcesByID(rw http.ResponseWriter, r *http.Re
167164
})
168165
return
169166
}
170-
resources, err := api.Database.GetProjectImportJobResourcesByJobID(r.Context(), job.ID)
167+
resources, err := api.Database.GetProvisionerJobResourcesByJobID(r.Context(), job.ID)
171168
if errors.Is(err, sql.ErrNoRows) {
172169
err = nil
173170
}
@@ -178,7 +175,7 @@ func (api *api) projectImportJobResourcesByID(rw http.ResponseWriter, r *http.Re
178175
return
179176
}
180177
if resources == nil {
181-
resources = []database.ProjectImportJobResource{}
178+
resources = []database.ProvisionerJobResource{}
182179
}
183180
render.Status(r, http.StatusOK)
184181
render.JSON(rw, r, resources)

coderd/provisionerdaemons.go

Lines changed: 60 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/google/uuid"
1616
"github.com/hashicorp/yamux"
1717
"github.com/moby/moby/pkg/namesgenerator"
18+
"github.com/tabbed/pqtype"
1819
"golang.org/x/xerrors"
1920
"nhooyr.io/websocket"
2021
"storj.io/drpc/drpcmux"
@@ -453,14 +454,8 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr
453454
slog.F("resource_name", resource.Name),
454455
slog.F("resource_type", resource.Type),
455456
slog.F("transition", transition))
456-
_, err = server.Database.InsertProjectImportJobResource(ctx, database.InsertProjectImportJobResourceParams{
457-
ID: uuid.New(),
458-
CreatedAt: database.Now(),
459-
JobID: jobID,
460-
Transition: transition,
461-
Type: resource.Type,
462-
Name: resource.Name,
463-
})
457+
458+
err = insertProvisionerJobResource(ctx, server.Database, jobID, transition, resource)
464459
if err != nil {
465460
return nil, xerrors.Errorf("insert resource: %w", err)
466461
}
@@ -516,26 +511,9 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr
516511
}
517512
// This could be a bulk insert to improve performance.
518513
for _, protoResource := range jobType.WorkspaceProvision.Resources {
519-
var instanceID sql.NullString
520-
if protoResource.Agent != nil && protoResource.Agent.GetGoogleInstanceIdentity() != nil {
521-
instanceID = sql.NullString{
522-
String: protoResource.Agent.GetGoogleInstanceIdentity().InstanceId,
523-
Valid: true,
524-
}
525-
}
526-
_, err = db.InsertWorkspaceResource(ctx, database.InsertWorkspaceResourceParams{
527-
ID: uuid.New(),
528-
CreatedAt: database.Now(),
529-
WorkspaceHistoryID: input.WorkspaceHistoryID,
530-
Type: protoResource.Type,
531-
Name: protoResource.Name,
532-
InstanceID: instanceID,
533-
// TODO: Generate this at the variable validation phase.
534-
// Set the value in `default_source`, and disallow overwrite.
535-
WorkspaceAgentToken: uuid.NewString(),
536-
})
514+
err = insertProvisionerJobResource(ctx, db, job.ID, workspaceHistory.Transition, protoResource)
537515
if err != nil {
538-
return xerrors.Errorf("insert workspace resource %q: %w", protoResource.Name, err)
516+
return xerrors.Errorf("insert provisioner job: %w", err)
539517
}
540518
}
541519
return nil
@@ -551,6 +529,61 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr
551529
return &proto.Empty{}, nil
552530
}
553531

532+
func insertProvisionerJobResource(ctx context.Context, db database.Store, jobID uuid.UUID, transition database.WorkspaceTransition, protoResource *sdkproto.Resource) error {
533+
resource, err := db.InsertProvisionerJobResource(ctx, database.InsertProvisionerJobResourceParams{
534+
ID: uuid.New(),
535+
CreatedAt: database.Now(),
536+
JobID: jobID,
537+
Transition: transition,
538+
Type: protoResource.Type,
539+
Name: protoResource.Name,
540+
AgentID: uuid.NullUUID{
541+
UUID: uuid.New(),
542+
Valid: protoResource.Agent != nil,
543+
},
544+
})
545+
if err != nil {
546+
return xerrors.Errorf("insert provisioner job resource %q: %w", protoResource.Name, err)
547+
}
548+
if resource.AgentID.Valid {
549+
var instanceID sql.NullString
550+
if protoResource.Agent.GetGoogleInstanceIdentity() != nil {
551+
instanceID = sql.NullString{
552+
String: protoResource.Agent.GetGoogleInstanceIdentity().InstanceId,
553+
Valid: true,
554+
}
555+
}
556+
var env pqtype.NullRawMessage
557+
if protoResource.Agent.Env != nil {
558+
data, err := json.Marshal(protoResource.Agent.Env)
559+
if err != nil {
560+
return xerrors.Errorf("marshal env: %w", err)
561+
}
562+
env = pqtype.NullRawMessage{
563+
RawMessage: data,
564+
Valid: true,
565+
}
566+
}
567+
568+
_, err := db.InsertProvisionerJobAgent(ctx, database.InsertProvisionerJobAgentParams{
569+
ID: resource.AgentID.UUID,
570+
CreatedAt: database.Now(),
571+
ResourceID: resource.ID,
572+
AuthToken: uuid.New(),
573+
AuthInstanceID: instanceID,
574+
EnvironmentVariables: env,
575+
StartupScript: sql.NullString{
576+
String: protoResource.Agent.StartupScript,
577+
Valid: protoResource.Agent.StartupScript != "",
578+
},
579+
})
580+
if err != nil {
581+
return xerrors.Errorf("insert agent: %w", err)
582+
}
583+
}
584+
return nil
585+
}
586+
554587
func convertValidationTypeSystem(typeSystem sdkproto.ParameterSchema_TypeSystem) (database.ParameterTypeSystem, error) {
555588
switch typeSystem {
556589
case sdkproto.ParameterSchema_None:

coderd/provisionerjobs.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,32 @@ type ProvisionerJob struct {
5050

5151
// ProvisionerJobLog represents a single log from a provisioner job.
5252
type ProvisionerJobLog struct {
53-
ID uuid.UUID
53+
ID uuid.UUID `json:"id"`
5454
CreatedAt time.Time `json:"created_at"`
5555
Source database.LogSource `json:"log_source"`
5656
Level database.LogLevel `json:"log_level"`
5757
Output string `json:"output"`
5858
}
5959

60+
type ProvisionerJobResource struct {
61+
ID uuid.UUID `json:"id"`
62+
CreatedAt time.Time `json:"created_at"`
63+
JobID uuid.UUID `json:"job_id"`
64+
Transition database.WorkspaceTransition `json:"workspace_transition"`
65+
Type string `json:"type"`
66+
Name string `json:"name"`
67+
}
68+
69+
type ProvisionerJobAgent struct {
70+
ID uuid.UUID `json:"id"`
71+
CreatedAt time.Time `json:"created_at"`
72+
UpdatedAt time.Time `json:"updated_at"`
73+
ResourceID uuid.UUID `json:"resource_id"`
74+
InstanceID string `json:"instance_id,omitempty"`
75+
EnvironmentVariables map[string]string `json:"environment_variables"`
76+
StartupScript string `json:"startup_script,omitempty"`
77+
}
78+
6079
func (*api) provisionerJobByID(rw http.ResponseWriter, r *http.Request) {
6180
job := httpmw.ProvisionerJobParam(r)
6281
render.Status(r, http.StatusOK)

coderd/workspaceagent.go

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ package coderd
22

33
import (
44
"database/sql"
5+
"encoding/json"
56
"errors"
67
"fmt"
78
"net/http"
89

910
"github.com/go-chi/render"
1011

12+
"github.com/coder/coder/database"
1113
"github.com/coder/coder/httpapi"
1214

1315
"github.com/mitchellh/mapstructure"
@@ -54,14 +56,48 @@ func (api *api) postAuthenticateWorkspaceAgentUsingGoogleInstanceIdentity(rw htt
5456
})
5557
return
5658
}
57-
resource, err := api.Database.GetWorkspaceResourceByInstanceID(r.Context(), claims.Google.ComputeEngine.InstanceID)
59+
agent, err := api.Database.GetProvisionerJobAgentByInstanceID(r.Context(), claims.Google.ComputeEngine.InstanceID)
5860
if errors.Is(err, sql.ErrNoRows) {
5961
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
6062
Message: fmt.Sprintf("instance with id %q not found", claims.Google.ComputeEngine.InstanceID),
6163
})
6264
return
6365
}
64-
resourceHistory, err := api.Database.GetWorkspaceHistoryByID(r.Context(), resource.WorkspaceHistoryID)
66+
if err != nil {
67+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
68+
Message: fmt.Sprintf("get provisioner job agent: %s", err),
69+
})
70+
return
71+
}
72+
resource, err := api.Database.GetProvisionerJobResourceByID(r.Context(), agent.ResourceID)
73+
if err != nil {
74+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
75+
Message: fmt.Sprintf("get provisioner job resource: %s", err),
76+
})
77+
return
78+
}
79+
job, err := api.Database.GetProvisionerJobByID(r.Context(), resource.JobID)
80+
if err != nil {
81+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
82+
Message: fmt.Sprintf("get provisioner job: %s", err),
83+
})
84+
return
85+
}
86+
if job.Type != database.ProvisionerJobTypeWorkspaceProvision {
87+
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
88+
Message: fmt.Sprintf("%q jobs cannot be authenticated", job.Type),
89+
})
90+
return
91+
}
92+
var jobData workspaceProvisionJob
93+
err = json.Unmarshal(job.Input, &jobData)
94+
if err != nil {
95+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
96+
Message: fmt.Sprintf("extract job data: %s", err),
97+
})
98+
return
99+
}
100+
resourceHistory, err := api.Database.GetWorkspaceHistoryByID(r.Context(), jobData.WorkspaceHistoryID)
65101
if err != nil {
66102
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
67103
Message: fmt.Sprintf("get workspace history: %s", err),
@@ -86,6 +122,6 @@ func (api *api) postAuthenticateWorkspaceAgentUsingGoogleInstanceIdentity(rw htt
86122
}
87123
render.Status(r, http.StatusOK)
88124
render.JSON(rw, r, WorkspaceAgentAuthenticateResponse{
89-
SessionToken: resource.WorkspaceAgentToken,
125+
SessionToken: agent.AuthToken.String(),
90126
})
91127
}

codersdk/projectimport.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func (c *Client) ProjectImportJobParameters(ctx context.Context, organization st
8181
}
8282

8383
// ProjectImportJobResources returns resources for a project import job.
84-
func (c *Client) ProjectImportJobResources(ctx context.Context, organization string, job uuid.UUID) ([]coderd.ProjectImportJobResource, error) {
84+
func (c *Client) ProjectImportJobResources(ctx context.Context, organization string, job uuid.UUID) ([]coderd.ProvisionerJobResource, error) {
8585
res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/projectimport/%s/%s/resources", organization, job), nil)
8686
if err != nil {
8787
return nil, err
@@ -90,6 +90,6 @@ func (c *Client) ProjectImportJobResources(ctx context.Context, organization str
9090
if res.StatusCode != http.StatusOK {
9191
return nil, readBodyAsError(res)
9292
}
93-
var resources []coderd.ProjectImportJobResource
93+
var resources []coderd.ProvisionerJobResource
9494
return resources, json.NewDecoder(res.Body).Decode(&resources)
9595
}

0 commit comments

Comments
 (0)