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:
Kyle Carberry
2022-03-07 11:40:54 -06:00
committed by GitHub
parent 330686f60a
commit bf0ae8f573
115 changed files with 5853 additions and 4657 deletions

View File

@ -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{