mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
refactor: workspace builds (#7541)
* refactor workspace builds Signed-off-by: Spike Curtis <spike@coder.com> * make gen Signed-off-by: Spike Curtis <spike@coder.com> * Remove ParameterResolver from typescript Signed-off-by: Spike Curtis <spike@coder.com> * rename conversion -> database/db2sdk Signed-off-by: Spike Curtis <spike@coder.com> * tests for db2sdk Signed-off-by: Spike Curtis <spike@coder.com> * Tests for ParameterResolver Signed-off-by: Spike Curtis <spike@coder.com> * wsbuilder tests Signed-off-by: Spike Curtis <spike@coder.com> * Move parameter validation tests to richparameters_test.go Signed-off-by: Spike Curtis <spike@coder.com> * Fix CI generation; rename mock->dbmock Signed-off-by: Spike Curtis <spike@coder.com> * Fix test imports Signed-off-by: Spike Curtis <spike@coder.com> --------- Signed-off-by: Spike Curtis <spike@coder.com>
This commit is contained in:
+24
-156
@@ -13,7 +13,6 @@ import (
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/google/uuid"
|
||||
"github.com/tabbed/pqtype"
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -22,13 +21,12 @@ import (
|
||||
"github.com/coder/coder/coderd/database"
|
||||
"github.com/coder/coder/coderd/httpapi"
|
||||
"github.com/coder/coder/coderd/httpmw"
|
||||
"github.com/coder/coder/coderd/provisionerdserver"
|
||||
"github.com/coder/coder/coderd/rbac"
|
||||
"github.com/coder/coder/coderd/schedule"
|
||||
"github.com/coder/coder/coderd/searchquery"
|
||||
"github.com/coder/coder/coderd/telemetry"
|
||||
"github.com/coder/coder/coderd/tracing"
|
||||
"github.com/coder/coder/coderd/util/ptr"
|
||||
"github.com/coder/coder/coderd/wsbuilder"
|
||||
"github.com/coder/coder/codersdk"
|
||||
)
|
||||
|
||||
@@ -399,77 +397,12 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
|
||||
return
|
||||
}
|
||||
|
||||
templateVersion, err := api.Database.GetTemplateVersionByID(ctx, template.ActiveVersionID)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching template version.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
dbTemplateVersionParameters, err := api.Database.GetTemplateVersionParameters(ctx, templateVersion.ID)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching template version parameters.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
templateVersionParameters, err := convertTemplateVersionParameters(dbTemplateVersionParameters)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error converting template version parameters.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err = codersdk.ValidateNewWorkspaceParameters(templateVersionParameters, createWorkspace.RichParameterValues)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Error validating workspace build parameters.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
templateVersionJob, err := api.Database.GetProvisionerJobByID(ctx, templateVersion.JobID)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching template version job.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
templateVersionJobStatus := convertProvisionerJob(templateVersionJob).Status
|
||||
switch templateVersionJobStatus {
|
||||
case codersdk.ProvisionerJobPending, codersdk.ProvisionerJobRunning:
|
||||
httpapi.Write(ctx, rw, http.StatusNotAcceptable, codersdk.Response{
|
||||
Message: fmt.Sprintf("The provided template version is %s. Wait for it to complete importing!", templateVersionJobStatus),
|
||||
})
|
||||
return
|
||||
case codersdk.ProvisionerJobFailed:
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: fmt.Sprintf("The provided template version %q has failed to import. You cannot create workspaces using it!", templateVersion.Name),
|
||||
})
|
||||
return
|
||||
case codersdk.ProvisionerJobCanceled:
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "The provided template version was canceled during import. You cannot create workspaces using it!",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
tags := provisionerdserver.MutateTags(user.ID, templateVersionJob.Tags)
|
||||
var (
|
||||
provisionerJob database.ProvisionerJob
|
||||
workspaceBuild database.WorkspaceBuild
|
||||
provisionerJob *database.ProvisionerJob
|
||||
workspaceBuild *database.WorkspaceBuild
|
||||
)
|
||||
err = api.Database.InTx(func(db database.Store) error {
|
||||
now := database.Now()
|
||||
workspaceBuildID := uuid.New()
|
||||
// Workspaces are created without any versions.
|
||||
workspace, err = db.InsertWorkspace(ctx, database.InsertWorkspaceParams{
|
||||
ID: uuid.New(),
|
||||
@@ -488,92 +421,27 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
|
||||
if err != nil {
|
||||
return xerrors.Errorf("insert workspace: %w", err)
|
||||
}
|
||||
for _, parameterValue := range createWorkspace.ParameterValues {
|
||||
// If the value is empty, we don't want to save it on database so
|
||||
// Terraform can use the default value
|
||||
if parameterValue.SourceValue == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = db.InsertParameterValue(ctx, database.InsertParameterValueParams{
|
||||
ID: uuid.New(),
|
||||
Name: parameterValue.Name,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Scope: database.ParameterScopeWorkspace,
|
||||
ScopeID: workspace.ID,
|
||||
SourceScheme: database.ParameterSourceScheme(parameterValue.SourceScheme),
|
||||
SourceValue: parameterValue.SourceValue,
|
||||
DestinationScheme: database.ParameterDestinationScheme(parameterValue.DestinationScheme),
|
||||
builder := wsbuilder.New(workspace, database.WorkspaceTransitionStart).
|
||||
Reason(database.BuildReasonInitiator).
|
||||
Initiator(apiKey.UserID).
|
||||
ActiveVersion().
|
||||
LegacyParameterValues(createWorkspace.ParameterValues).
|
||||
RichParameterValues(createWorkspace.RichParameterValues)
|
||||
workspaceBuild, provisionerJob, err = builder.Build(
|
||||
ctx, db, func(action rbac.Action, object rbac.Objecter) bool {
|
||||
return api.Authorize(r, action, object)
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("insert parameter value: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
input, err := json.Marshal(provisionerdserver.WorkspaceProvisionJob{
|
||||
WorkspaceBuildID: workspaceBuildID,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("marshal provision job: %w", err)
|
||||
}
|
||||
traceMetadataRaw, err := json.Marshal(tracing.MetadataFromContext(ctx))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("marshal metadata: %w", err)
|
||||
}
|
||||
provisionerJob, err = db.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{
|
||||
ID: uuid.New(),
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
InitiatorID: apiKey.UserID,
|
||||
OrganizationID: template.OrganizationID,
|
||||
Provisioner: template.Provisioner,
|
||||
Type: database.ProvisionerJobTypeWorkspaceBuild,
|
||||
StorageMethod: templateVersionJob.StorageMethod,
|
||||
FileID: templateVersionJob.FileID,
|
||||
Input: input,
|
||||
Tags: tags,
|
||||
TraceMetadata: pqtype.NullRawMessage{
|
||||
Valid: true,
|
||||
RawMessage: traceMetadataRaw,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("insert provisioner job: %w", err)
|
||||
}
|
||||
workspaceBuild, err = db.InsertWorkspaceBuild(ctx, database.InsertWorkspaceBuildParams{
|
||||
ID: workspaceBuildID,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
WorkspaceID: workspace.ID,
|
||||
TemplateVersionID: templateVersion.ID,
|
||||
InitiatorID: apiKey.UserID,
|
||||
Transition: database.WorkspaceTransitionStart,
|
||||
JobID: provisionerJob.ID,
|
||||
BuildNumber: 1, // First build!
|
||||
Deadline: time.Time{}, // provisionerd will set this upon success
|
||||
Reason: database.BuildReasonInitiator,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("insert workspace build: %w", err)
|
||||
}
|
||||
|
||||
names := make([]string, 0, len(createWorkspace.RichParameterValues))
|
||||
values := make([]string, 0, len(createWorkspace.RichParameterValues))
|
||||
for _, param := range createWorkspace.RichParameterValues {
|
||||
names = append(names, param.Name)
|
||||
values = append(values, param.Value)
|
||||
}
|
||||
err = db.InsertWorkspaceBuildParameters(ctx, database.InsertWorkspaceBuildParametersParams{
|
||||
WorkspaceBuildID: workspaceBuildID,
|
||||
Name: names,
|
||||
Value: values,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("insert workspace build parameters: %w", err)
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}, nil)
|
||||
var bldErr wsbuilder.BuildError
|
||||
if xerrors.As(err, &bldErr) {
|
||||
httpapi.Write(ctx, rw, bldErr.Status, codersdk.Response{
|
||||
Message: bldErr.Message,
|
||||
Detail: bldErr.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error creating workspace.",
|
||||
@@ -594,14 +462,14 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
|
||||
|
||||
api.Telemetry.Report(&telemetry.Snapshot{
|
||||
Workspaces: []telemetry.Workspace{telemetry.ConvertWorkspace(workspace)},
|
||||
WorkspaceBuilds: []telemetry.WorkspaceBuild{telemetry.ConvertWorkspaceBuild(workspaceBuild)},
|
||||
WorkspaceBuilds: []telemetry.WorkspaceBuild{telemetry.ConvertWorkspaceBuild(*workspaceBuild)},
|
||||
})
|
||||
|
||||
users := []database.User{user, initiator}
|
||||
apiBuild, err := api.convertWorkspaceBuild(
|
||||
workspaceBuild,
|
||||
*workspaceBuild,
|
||||
workspace,
|
||||
provisionerJob,
|
||||
*provisionerJob,
|
||||
users,
|
||||
[]database.WorkspaceResource{},
|
||||
[]database.WorkspaceResourceMetadatum{},
|
||||
|
||||
Reference in New Issue
Block a user