mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
feat: Refactor API routes to use UUIDs instead of friendly names (#401)
* Add client for agent * Cleanup code * Fix linting error * Rename routes to be simpler * Rename workspace history to workspace build * Refactor HTTP middlewares to use UUIDs * Cleanup routes * Compiles! * Fix files and organizations * Fix querying * Fix agent lock * Cleanup database abstraction * Add parameters * Fix linting errors * Fix log race * Lock on close wait * Fix log cleanup * Fix e2e tests * Fix upstream version of opencensus-go * Update coderdtest.go * Fix coverpkg * Fix codecov ignore
This commit is contained in:
@ -12,7 +12,6 @@ import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/render"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hashicorp/yamux"
|
||||
"github.com/moby/moby/pkg/namesgenerator"
|
||||
@ -33,27 +32,8 @@ import (
|
||||
|
||||
type ProvisionerDaemon database.ProvisionerDaemon
|
||||
|
||||
// Lists all registered provisioner daemons.
|
||||
func (api *api) provisionerDaemons(rw http.ResponseWriter, r *http.Request) {
|
||||
daemons, err := api.Database.GetProvisionerDaemons(r.Context())
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
|
||||
Message: fmt.Sprintf("get provisioner daemons: %s", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
if daemons == nil {
|
||||
daemons = []database.ProvisionerDaemon{}
|
||||
}
|
||||
render.Status(r, http.StatusOK)
|
||||
render.JSON(rw, r, daemons)
|
||||
}
|
||||
|
||||
// Serves the provisioner daemon protobuf API over a WebSocket.
|
||||
func (api *api) provisionerDaemonsServe(rw http.ResponseWriter, r *http.Request) {
|
||||
func (api *api) provisionerDaemonsListen(rw http.ResponseWriter, r *http.Request) {
|
||||
api.websocketWaitGroup.Add(1)
|
||||
defer api.websocketWaitGroup.Done()
|
||||
|
||||
@ -113,8 +93,8 @@ func (api *api) provisionerDaemonsServe(rw http.ResponseWriter, r *http.Request)
|
||||
|
||||
// The input for a "workspace_provision" job.
|
||||
type workspaceProvisionJob struct {
|
||||
WorkspaceHistoryID uuid.UUID `json:"workspace_history_id"`
|
||||
DryRun bool `json:"dry_run"`
|
||||
WorkspaceBuildID uuid.UUID `json:"workspace_build_id"`
|
||||
DryRun bool `json:"dry_run"`
|
||||
}
|
||||
|
||||
// Implementation of the provisioner daemon protobuf server.
|
||||
@ -182,32 +162,32 @@ func (server *provisionerdServer) AcquireJob(ctx context.Context, _ *proto.Empty
|
||||
UserName: user.Username,
|
||||
}
|
||||
switch job.Type {
|
||||
case database.ProvisionerJobTypeWorkspaceProvision:
|
||||
case database.ProvisionerJobTypeWorkspaceBuild:
|
||||
var input workspaceProvisionJob
|
||||
err = json.Unmarshal(job.Input, &input)
|
||||
if err != nil {
|
||||
return nil, failJob(fmt.Sprintf("unmarshal job input %q: %s", job.Input, err))
|
||||
}
|
||||
workspaceHistory, err := server.Database.GetWorkspaceHistoryByID(ctx, input.WorkspaceHistoryID)
|
||||
workspaceBuild, err := server.Database.GetWorkspaceBuildByID(ctx, input.WorkspaceBuildID)
|
||||
if err != nil {
|
||||
return nil, failJob(fmt.Sprintf("get workspace history: %s", err))
|
||||
return nil, failJob(fmt.Sprintf("get workspace build: %s", err))
|
||||
}
|
||||
workspace, err := server.Database.GetWorkspaceByID(ctx, workspaceHistory.WorkspaceID)
|
||||
workspace, err := server.Database.GetWorkspaceByID(ctx, workspaceBuild.WorkspaceID)
|
||||
if err != nil {
|
||||
return nil, failJob(fmt.Sprintf("get workspace: %s", err))
|
||||
}
|
||||
projectVersion, err := server.Database.GetProjectVersionByID(ctx, workspaceHistory.ProjectVersionID)
|
||||
projectVersion, err := server.Database.GetProjectVersionByID(ctx, workspaceBuild.ProjectVersionID)
|
||||
if err != nil {
|
||||
return nil, failJob(fmt.Sprintf("get project version: %s", err))
|
||||
}
|
||||
project, err := server.Database.GetProjectByID(ctx, projectVersion.ProjectID)
|
||||
project, err := server.Database.GetProjectByID(ctx, projectVersion.ProjectID.UUID)
|
||||
if err != nil {
|
||||
return nil, failJob(fmt.Sprintf("get project: %s", err))
|
||||
}
|
||||
|
||||
// Compute parameters for the workspace to consume.
|
||||
parameters, err := parameter.Compute(ctx, server.Database, parameter.ComputeScope{
|
||||
ProjectImportJobID: projectVersion.ImportJobID,
|
||||
ProjectImportJobID: projectVersion.JobID,
|
||||
OrganizationID: job.OrganizationID,
|
||||
ProjectID: uuid.NullUUID{
|
||||
UUID: project.ID,
|
||||
@ -231,17 +211,17 @@ func (server *provisionerdServer) AcquireJob(ctx context.Context, _ *proto.Empty
|
||||
}
|
||||
protoParameters = append(protoParameters, converted)
|
||||
}
|
||||
transition, err := convertWorkspaceTransition(workspaceHistory.Transition)
|
||||
transition, err := convertWorkspaceTransition(workspaceBuild.Transition)
|
||||
if err != nil {
|
||||
return nil, failJob(fmt.Sprint("convert workspace transition: %w", err))
|
||||
}
|
||||
|
||||
protoJob.Type = &proto.AcquiredJob_WorkspaceProvision_{
|
||||
WorkspaceProvision: &proto.AcquiredJob_WorkspaceProvision{
|
||||
WorkspaceHistoryId: workspaceHistory.ID.String(),
|
||||
WorkspaceName: workspace.Name,
|
||||
State: workspaceHistory.ProvisionerState,
|
||||
ParameterValues: protoParameters,
|
||||
protoJob.Type = &proto.AcquiredJob_WorkspaceBuild_{
|
||||
WorkspaceBuild: &proto.AcquiredJob_WorkspaceBuild{
|
||||
WorkspaceBuildId: workspaceBuild.ID.String(),
|
||||
WorkspaceName: workspace.Name,
|
||||
State: workspaceBuild.ProvisionerState,
|
||||
ParameterValues: protoParameters,
|
||||
Metadata: &sdkproto.Provision_Metadata{
|
||||
CoderUrl: server.AccessURL.String(),
|
||||
WorkspaceTransition: transition,
|
||||
@ -432,8 +412,8 @@ func (server *provisionerdServer) FailJob(ctx context.Context, failJob *proto.Fa
|
||||
return nil, xerrors.Errorf("update provisioner job: %w", err)
|
||||
}
|
||||
switch jobType := failJob.Type.(type) {
|
||||
case *proto.FailedJob_WorkspaceProvision_:
|
||||
if jobType.WorkspaceProvision.State == nil {
|
||||
case *proto.FailedJob_WorkspaceBuild_:
|
||||
if jobType.WorkspaceBuild.State == nil {
|
||||
break
|
||||
}
|
||||
var input workspaceProvisionJob
|
||||
@ -441,13 +421,13 @@ func (server *provisionerdServer) FailJob(ctx context.Context, failJob *proto.Fa
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("unmarshal workspace provision input: %w", err)
|
||||
}
|
||||
err = server.Database.UpdateWorkspaceHistoryByID(ctx, database.UpdateWorkspaceHistoryByIDParams{
|
||||
err = server.Database.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{
|
||||
ID: jobID,
|
||||
UpdatedAt: database.Now(),
|
||||
ProvisionerState: jobType.WorkspaceProvision.State,
|
||||
ProvisionerState: jobType.WorkspaceBuild.State,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("update workspace history state: %w", err)
|
||||
return nil, xerrors.Errorf("update workspace build state: %w", err)
|
||||
}
|
||||
case *proto.FailedJob_ProjectImport_:
|
||||
}
|
||||
@ -481,7 +461,7 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr
|
||||
slog.F("resource_type", resource.Type),
|
||||
slog.F("transition", transition))
|
||||
|
||||
err = insertProvisionerJobResource(ctx, server.Database, jobID, transition, resource)
|
||||
err = insertWorkspaceResource(ctx, server.Database, jobID, transition, resource)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("insert resource: %w", err)
|
||||
}
|
||||
@ -503,16 +483,16 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("complete job: %w", err)
|
||||
}
|
||||
case *proto.CompletedJob_WorkspaceProvision_:
|
||||
case *proto.CompletedJob_WorkspaceBuild_:
|
||||
var input workspaceProvisionJob
|
||||
err = json.Unmarshal(job.Input, &input)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("unmarshal job data: %w", err)
|
||||
}
|
||||
|
||||
workspaceHistory, err := server.Database.GetWorkspaceHistoryByID(ctx, input.WorkspaceHistoryID)
|
||||
workspaceBuild, err := server.Database.GetWorkspaceBuildByID(ctx, input.WorkspaceBuildID)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get workspace history: %w", err)
|
||||
return nil, xerrors.Errorf("get workspace build: %w", err)
|
||||
}
|
||||
|
||||
err = server.Database.InTx(func(db database.Store) error {
|
||||
@ -527,17 +507,17 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr
|
||||
if err != nil {
|
||||
return xerrors.Errorf("update provisioner job: %w", err)
|
||||
}
|
||||
err = db.UpdateWorkspaceHistoryByID(ctx, database.UpdateWorkspaceHistoryByIDParams{
|
||||
ID: workspaceHistory.ID,
|
||||
err = db.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{
|
||||
ID: workspaceBuild.ID,
|
||||
UpdatedAt: database.Now(),
|
||||
ProvisionerState: jobType.WorkspaceProvision.State,
|
||||
ProvisionerState: jobType.WorkspaceBuild.State,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("update workspace history: %w", err)
|
||||
return xerrors.Errorf("update workspace build: %w", err)
|
||||
}
|
||||
// This could be a bulk insert to improve performance.
|
||||
for _, protoResource := range jobType.WorkspaceProvision.Resources {
|
||||
err = insertProvisionerJobResource(ctx, db, job.ID, workspaceHistory.Transition, protoResource)
|
||||
for _, protoResource := range jobType.WorkspaceBuild.Resources {
|
||||
err = insertWorkspaceResource(ctx, db, job.ID, workspaceBuild.Transition, protoResource)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("insert provisioner job: %w", err)
|
||||
}
|
||||
@ -555,8 +535,8 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr
|
||||
return &proto.Empty{}, nil
|
||||
}
|
||||
|
||||
func insertProvisionerJobResource(ctx context.Context, db database.Store, jobID uuid.UUID, transition database.WorkspaceTransition, protoResource *sdkproto.Resource) error {
|
||||
resource, err := db.InsertProvisionerJobResource(ctx, database.InsertProvisionerJobResourceParams{
|
||||
func insertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.UUID, transition database.WorkspaceTransition, protoResource *sdkproto.Resource) error {
|
||||
resource, err := db.InsertWorkspaceResource(ctx, database.InsertWorkspaceResourceParams{
|
||||
ID: uuid.New(),
|
||||
CreatedAt: database.Now(),
|
||||
JobID: jobID,
|
||||
@ -590,12 +570,19 @@ func insertProvisionerJobResource(ctx context.Context, db database.Store, jobID
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
authToken := uuid.New()
|
||||
if protoResource.Agent.GetToken() != "" {
|
||||
authToken, err = uuid.Parse(protoResource.Agent.GetToken())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("invalid auth token format; must be uuid: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
_, err := db.InsertProvisionerJobAgent(ctx, database.InsertProvisionerJobAgentParams{
|
||||
_, err := db.InsertWorkspaceAgent(ctx, database.InsertWorkspaceAgentParams{
|
||||
ID: resource.AgentID.UUID,
|
||||
CreatedAt: database.Now(),
|
||||
ResourceID: resource.ID,
|
||||
AuthToken: uuid.New(),
|
||||
AuthToken: authToken,
|
||||
AuthInstanceID: instanceID,
|
||||
EnvironmentVariables: env,
|
||||
StartupScript: sql.NullString{
|
||||
|
Reference in New Issue
Block a user