mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
feat!: drop support for legacy parameters (#7663)
This commit is contained in:
@ -34,15 +34,14 @@ import (
|
||||
// build, job, err := b.Build(...)
|
||||
type Builder struct {
|
||||
// settings that control the kind of build you get
|
||||
workspace database.Workspace
|
||||
trans database.WorkspaceTransition
|
||||
version versionTarget
|
||||
state stateTarget
|
||||
logLevel string
|
||||
legacyParameterValues []codersdk.CreateParameterRequest
|
||||
richParameterValues []codersdk.WorkspaceBuildParameter
|
||||
initiator uuid.UUID
|
||||
reason database.BuildReason
|
||||
workspace database.Workspace
|
||||
trans database.WorkspaceTransition
|
||||
version versionTarget
|
||||
state stateTarget
|
||||
logLevel string
|
||||
richParameterValues []codersdk.WorkspaceBuildParameter
|
||||
initiator uuid.UUID
|
||||
reason database.BuildReason
|
||||
|
||||
// used during build, makes function arguments less verbose
|
||||
ctx context.Context
|
||||
@ -56,8 +55,9 @@ type Builder struct {
|
||||
lastBuild *database.WorkspaceBuild
|
||||
lastBuildErr *error
|
||||
lastBuildParameters *[]database.WorkspaceBuildParameter
|
||||
lastParameterValues *[]database.ParameterValue
|
||||
lastBuildJob *database.ProvisionerJob
|
||||
|
||||
verifyNoLegacyParametersOnce bool
|
||||
}
|
||||
|
||||
type Option func(Builder) Builder
|
||||
@ -140,12 +140,6 @@ func (b Builder) Reason(r database.BuildReason) Builder {
|
||||
return b
|
||||
}
|
||||
|
||||
func (b Builder) LegacyParameterValues(p []codersdk.CreateParameterRequest) Builder {
|
||||
// nolint: revive
|
||||
b.legacyParameterValues = p
|
||||
return b
|
||||
}
|
||||
|
||||
func (b Builder) RichParameterValues(p []codersdk.WorkspaceBuildParameter) Builder {
|
||||
// nolint: revive
|
||||
b.richParameterValues = p
|
||||
@ -271,15 +265,6 @@ func (b *Builder) buildTx(authFunc func(action rbac.Action, object rbac.Objecter
|
||||
}
|
||||
}
|
||||
|
||||
legacyParameters, err := b.getLastParameterValues()
|
||||
if err != nil {
|
||||
return nil, nil, BuildError{
|
||||
http.StatusInternalServerError,
|
||||
"failed to fetch previous legacy parameters.",
|
||||
err,
|
||||
}
|
||||
}
|
||||
|
||||
// if we haven't been told specifically who initiated, default to owner
|
||||
if b.initiator == uuid.Nil {
|
||||
b.initiator = b.workspace.OwnerID
|
||||
@ -289,45 +274,6 @@ func (b *Builder) buildTx(authFunc func(action rbac.Action, object rbac.Objecter
|
||||
b.reason = database.BuildReasonInitiator
|
||||
}
|
||||
|
||||
// Write/Update any new params
|
||||
now := database.Now()
|
||||
for _, param := range b.legacyParameterValues {
|
||||
for _, exists := range legacyParameters {
|
||||
// If the param exists, delete the old param before inserting the new one
|
||||
if exists.Name == param.Name {
|
||||
err = b.store.DeleteParameterValueByID(b.ctx, exists.ID)
|
||||
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil, BuildError{
|
||||
http.StatusInternalServerError,
|
||||
fmt.Sprintf("Failed to delete old param %q", exists.Name),
|
||||
err,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the value is empty, we don't want to save it on database so
|
||||
// Terraform can use the default value
|
||||
if param.SourceValue == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = b.store.InsertParameterValue(b.ctx, database.InsertParameterValueParams{
|
||||
ID: uuid.New(),
|
||||
Name: param.Name,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Scope: database.ParameterScopeWorkspace,
|
||||
ScopeID: b.workspace.ID,
|
||||
SourceScheme: database.ParameterSourceScheme(param.SourceScheme),
|
||||
SourceValue: param.SourceValue,
|
||||
DestinationScheme: database.ParameterDestinationScheme(param.DestinationScheme),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, BuildError{http.StatusInternalServerError, "insert parameter value", err}
|
||||
}
|
||||
}
|
||||
|
||||
workspaceBuildID := uuid.New()
|
||||
input, err := json.Marshal(provisionerdserver.WorkspaceProvisionJob{
|
||||
WorkspaceBuildID: workspaceBuildID,
|
||||
@ -346,6 +292,7 @@ func (b *Builder) buildTx(authFunc func(action rbac.Action, object rbac.Objecter
|
||||
}
|
||||
tags := provisionerdserver.MutateTags(b.workspace.OwnerID, templateVersionJob.Tags)
|
||||
|
||||
now := database.Now()
|
||||
provisionerJob, err := b.store.InsertProvisionerJob(b.ctx, database.InsertProvisionerJobParams{
|
||||
ID: uuid.New(),
|
||||
CreatedAt: now,
|
||||
@ -536,13 +483,12 @@ func (b *Builder) getParameters() (names, values []string, err error) {
|
||||
if err != nil {
|
||||
return nil, nil, BuildError{http.StatusInternalServerError, "failed to fetch last build parameters", err}
|
||||
}
|
||||
lastParameterValues, err := b.getLastParameterValues()
|
||||
err = b.verifyNoLegacyParameters()
|
||||
if err != nil {
|
||||
return nil, nil, BuildError{http.StatusInternalServerError, "failed to fetch last parameter values", err}
|
||||
return nil, nil, BuildError{http.StatusBadRequest, "Unable to build workspace with unsupported parameters", err}
|
||||
}
|
||||
resolver := codersdk.ParameterResolver{
|
||||
Rich: db2sdk.WorkspaceBuildParameters(lastBuildParameters),
|
||||
Legacy: db2sdk.Parameters(lastParameterValues),
|
||||
Rich: db2sdk.WorkspaceBuildParameters(lastBuildParameters),
|
||||
}
|
||||
for _, templateVersionParameter := range templateVersionParameters {
|
||||
tvp, err := db2sdk.TemplateVersionParameter(templateVersionParameter)
|
||||
@ -611,19 +557,36 @@ func (b *Builder) getTemplateVersionParameters() ([]database.TemplateVersionPara
|
||||
return tvp, nil
|
||||
}
|
||||
|
||||
func (b *Builder) getLastParameterValues() ([]database.ParameterValue, error) {
|
||||
if b.lastParameterValues != nil {
|
||||
return *b.lastParameterValues, nil
|
||||
// verifyNoLegacyParameters verifies that initiator can't start the workspace build
|
||||
// if it uses legacy parameters (database.ParameterSchemas).
|
||||
func (b *Builder) verifyNoLegacyParameters() error {
|
||||
if b.verifyNoLegacyParametersOnce {
|
||||
return nil
|
||||
}
|
||||
pv, err := b.store.ParameterValues(b.ctx, database.ParameterValuesParams{
|
||||
Scopes: []database.ParameterScope{database.ParameterScopeWorkspace},
|
||||
ScopeIds: []uuid.UUID{b.workspace.ID},
|
||||
})
|
||||
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
|
||||
return nil, xerrors.Errorf("get workspace %w parameter values: %w", b.workspace.ID, err)
|
||||
b.verifyNoLegacyParametersOnce = true
|
||||
|
||||
// Block starting the workspace with legacy parameters.
|
||||
if b.trans != database.WorkspaceTransitionStart {
|
||||
return nil
|
||||
}
|
||||
b.lastParameterValues = &pv
|
||||
return pv, nil
|
||||
|
||||
templateVersionJob, err := b.getTemplateVersionJob()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to fetch template version job: %w", err)
|
||||
}
|
||||
|
||||
parameterSchemas, err := b.store.GetParameterSchemasByJobID(b.ctx, templateVersionJob.ID)
|
||||
if xerrors.Is(err, sql.ErrNoRows) {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get parameter schemas: %w", err)
|
||||
}
|
||||
|
||||
if len(parameterSchemas) > 0 {
|
||||
return xerrors.Errorf("Legacy parameters in use on this version are not supported anymore. Contact your administrator for assistance.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Builder) getLastBuildJob() (*database.ProvisionerJob, error) {
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
@ -24,21 +23,19 @@ import (
|
||||
|
||||
var (
|
||||
// use fixed IDs so logs are easier to read
|
||||
templateID = uuid.MustParse("12341234-0000-0000-0001-000000000000")
|
||||
activeVersionID = uuid.MustParse("12341234-0000-0000-0002-000000000000")
|
||||
inactiveVersionID = uuid.MustParse("12341234-0000-0000-0003-000000000000")
|
||||
activeJobID = uuid.MustParse("12341234-0000-0000-0004-000000000000")
|
||||
inactiveJobID = uuid.MustParse("12341234-0000-0000-0005-000000000000")
|
||||
orgID = uuid.MustParse("12341234-0000-0000-0006-000000000000")
|
||||
workspaceID = uuid.MustParse("12341234-0000-0000-0007-000000000000")
|
||||
userID = uuid.MustParse("12341234-0000-0000-0008-000000000000")
|
||||
activeFileID = uuid.MustParse("12341234-0000-0000-0009-000000000000")
|
||||
inactiveFileID = uuid.MustParse("12341234-0000-0000-000a-000000000000")
|
||||
lastBuildID = uuid.MustParse("12341234-0000-0000-000b-000000000000")
|
||||
lastBuildJobID = uuid.MustParse("12341234-0000-0000-000c-000000000000")
|
||||
otherUserID = uuid.MustParse("12341234-0000-0000-000d-000000000000")
|
||||
notReplacedParamID = uuid.MustParse("12341234-0000-0000-000e-000000000000")
|
||||
replacedParamID = uuid.MustParse("12341234-0000-0000-000f-000000000000")
|
||||
templateID = uuid.MustParse("12341234-0000-0000-0001-000000000000")
|
||||
activeVersionID = uuid.MustParse("12341234-0000-0000-0002-000000000000")
|
||||
inactiveVersionID = uuid.MustParse("12341234-0000-0000-0003-000000000000")
|
||||
activeJobID = uuid.MustParse("12341234-0000-0000-0004-000000000000")
|
||||
inactiveJobID = uuid.MustParse("12341234-0000-0000-0005-000000000000")
|
||||
orgID = uuid.MustParse("12341234-0000-0000-0006-000000000000")
|
||||
workspaceID = uuid.MustParse("12341234-0000-0000-0007-000000000000")
|
||||
userID = uuid.MustParse("12341234-0000-0000-0008-000000000000")
|
||||
activeFileID = uuid.MustParse("12341234-0000-0000-0009-000000000000")
|
||||
inactiveFileID = uuid.MustParse("12341234-0000-0000-000a-000000000000")
|
||||
lastBuildID = uuid.MustParse("12341234-0000-0000-000b-000000000000")
|
||||
lastBuildJobID = uuid.MustParse("12341234-0000-0000-000c-000000000000")
|
||||
otherUserID = uuid.MustParse("12341234-0000-0000-000d-000000000000")
|
||||
)
|
||||
|
||||
func TestBuilder_NoOptions(t *testing.T) {
|
||||
@ -56,7 +53,8 @@ func TestBuilder_NoOptions(t *testing.T) {
|
||||
withTemplate,
|
||||
withInactiveVersion(nil),
|
||||
withLastBuildFound,
|
||||
withLegacyParameters(nil), withRichParameters(nil),
|
||||
withRichParameters(nil),
|
||||
withParameterSchemas(inactiveJobID, nil),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {
|
||||
@ -104,7 +102,8 @@ func TestBuilder_Initiator(t *testing.T) {
|
||||
withTemplate,
|
||||
withInactiveVersion(nil),
|
||||
withLastBuildFound,
|
||||
withLegacyParameters(nil), withRichParameters(nil),
|
||||
withRichParameters(nil),
|
||||
withParameterSchemas(inactiveJobID, nil),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {
|
||||
@ -136,7 +135,8 @@ func TestBuilder_Reason(t *testing.T) {
|
||||
withTemplate,
|
||||
withInactiveVersion(nil),
|
||||
withLastBuildFound,
|
||||
withLegacyParameters(nil), withRichParameters(nil),
|
||||
withRichParameters(nil),
|
||||
withParameterSchemas(inactiveJobID, nil),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {
|
||||
@ -167,7 +167,7 @@ func TestBuilder_ActiveVersion(t *testing.T) {
|
||||
withTemplate,
|
||||
withActiveVersion(nil),
|
||||
withLastBuildNotFound,
|
||||
withLegacyParameters(nil),
|
||||
withParameterSchemas(activeJobID, nil),
|
||||
// previous rich parameters are not queried because there is no previous build.
|
||||
|
||||
// Outputs
|
||||
@ -190,47 +190,6 @@ func TestBuilder_ActiveVersion(t *testing.T) {
|
||||
req.NoError(err)
|
||||
}
|
||||
|
||||
func TestBuilder_LegacyParams(t *testing.T) {
|
||||
t.Parallel()
|
||||
req := require.New(t)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
oldParams := []database.ParameterValue{
|
||||
{Name: "not-replaced", SourceValue: "nr", ID: notReplacedParamID},
|
||||
{Name: "replaced", SourceValue: "r", ID: replacedParamID},
|
||||
}
|
||||
newParams := []codersdk.CreateParameterRequest{
|
||||
{Name: "replaced", SourceValue: "s"},
|
||||
{Name: "new", SourceValue: "n"},
|
||||
}
|
||||
|
||||
mDB := expectDB(t,
|
||||
// Inputs
|
||||
withTemplate,
|
||||
withActiveVersion(nil),
|
||||
withLastBuildFound,
|
||||
withLegacyParameters(oldParams),
|
||||
withRichParameters(nil),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {
|
||||
}),
|
||||
expectBuild(func(bld database.InsertWorkspaceBuildParams) {
|
||||
}),
|
||||
expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) {
|
||||
}),
|
||||
expectReplacedParam(replacedParamID, "replaced", "s"),
|
||||
expectInsertedParam("new", "n"),
|
||||
)
|
||||
|
||||
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
|
||||
uut := wsbuilder.New(ws, database.WorkspaceTransitionStart).ActiveVersion().LegacyParameterValues(newParams)
|
||||
_, _, err := uut.Build(ctx, mDB, nil)
|
||||
req.NoError(err)
|
||||
}
|
||||
|
||||
func TestWorkspaceBuildWithRichParameters(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@ -285,8 +244,8 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
|
||||
withTemplate,
|
||||
withInactiveVersion(richParameters),
|
||||
withLastBuildFound,
|
||||
withLegacyParameters(nil),
|
||||
withRichParameters(initialBuildParameters),
|
||||
withParameterSchemas(inactiveJobID, nil),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
|
||||
@ -326,8 +285,8 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
|
||||
withTemplate,
|
||||
withInactiveVersion(richParameters),
|
||||
withLastBuildFound,
|
||||
withLegacyParameters(nil),
|
||||
withRichParameters(initialBuildParameters),
|
||||
withParameterSchemas(inactiveJobID, nil),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
|
||||
@ -348,6 +307,47 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("StartWorkspaceWithLegacyParameterValues", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
req := require.New(t)
|
||||
asrt := assert.New(t)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
schemas := []database.ParameterSchema{
|
||||
{
|
||||
Name: "not-replaced",
|
||||
DefaultDestinationScheme: database.ParameterDestinationSchemeEnvironmentVariable,
|
||||
},
|
||||
{
|
||||
Name: "replaced",
|
||||
DefaultDestinationScheme: database.ParameterDestinationSchemeEnvironmentVariable,
|
||||
},
|
||||
}
|
||||
|
||||
mDB := expectDB(t,
|
||||
// Inputs
|
||||
withTemplate,
|
||||
withInactiveVersion(richParameters),
|
||||
withLastBuildFound,
|
||||
withRichParameters(nil),
|
||||
withParameterSchemas(inactiveJobID, schemas),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
|
||||
expectBuild(func(bld database.InsertWorkspaceBuildParams) {}),
|
||||
)
|
||||
|
||||
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
|
||||
uut := wsbuilder.New(ws, database.WorkspaceTransitionStart)
|
||||
_, _, err := uut.Build(ctx, mDB, nil)
|
||||
bldErr := wsbuilder.BuildError{}
|
||||
req.ErrorAs(err, &bldErr)
|
||||
asrt.Equal(http.StatusBadRequest, bldErr.Status)
|
||||
})
|
||||
|
||||
t.Run("DoNotModifyImmutables", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@ -366,8 +366,8 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
|
||||
withTemplate,
|
||||
withInactiveVersion(richParameters),
|
||||
withLastBuildFound,
|
||||
withLegacyParameters(nil),
|
||||
withRichParameters(initialBuildParameters),
|
||||
withParameterSchemas(inactiveJobID, nil),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
|
||||
@ -418,8 +418,8 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
|
||||
withTemplate,
|
||||
withActiveVersion(version2params),
|
||||
withLastBuildFound,
|
||||
withLegacyParameters(nil),
|
||||
withRichParameters(initialBuildParameters),
|
||||
withParameterSchemas(activeJobID, nil),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
|
||||
@ -476,8 +476,8 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
|
||||
withTemplate,
|
||||
withActiveVersion(version2params),
|
||||
withLastBuildFound,
|
||||
withLegacyParameters(nil),
|
||||
withRichParameters(initialBuildParameters),
|
||||
withParameterSchemas(activeJobID, nil),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
|
||||
@ -532,8 +532,8 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
|
||||
withTemplate,
|
||||
withActiveVersion(version2params),
|
||||
withLastBuildFound,
|
||||
withLegacyParameters(nil),
|
||||
withRichParameters(initialBuildParameters),
|
||||
withParameterSchemas(activeJobID, nil),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
|
||||
@ -710,17 +710,14 @@ func withLastBuildNotFound(mTx *dbmock.MockStore) {
|
||||
Return(database.WorkspaceBuild{}, sql.ErrNoRows)
|
||||
}
|
||||
|
||||
func withLegacyParameters(params []database.ParameterValue) func(mTx *dbmock.MockStore) {
|
||||
func withParameterSchemas(jobID uuid.UUID, schemas []database.ParameterSchema) func(mTx *dbmock.MockStore) {
|
||||
return func(mTx *dbmock.MockStore) {
|
||||
c := mTx.EXPECT().ParameterValues(
|
||||
c := mTx.EXPECT().GetParameterSchemasByJobID(
|
||||
gomock.Any(),
|
||||
database.ParameterValuesParams{
|
||||
Scopes: []database.ParameterScope{database.ParameterScopeWorkspace},
|
||||
ScopeIds: []uuid.UUID{workspaceID},
|
||||
}).
|
||||
jobID).
|
||||
Times(1)
|
||||
if len(params) > 0 {
|
||||
c.Return(params, nil)
|
||||
if len(schemas) > 0 {
|
||||
c.Return(schemas, nil)
|
||||
} else {
|
||||
c.Return(nil, sql.ErrNoRows)
|
||||
}
|
||||
@ -797,43 +794,3 @@ func expectBuildParameters(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
type insertParameterMatcher struct {
|
||||
name string
|
||||
value string
|
||||
}
|
||||
|
||||
func (m insertParameterMatcher) Matches(x interface{}) bool {
|
||||
p, ok := x.(database.InsertParameterValueParams)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if p.Name != m.name {
|
||||
return false
|
||||
}
|
||||
return p.SourceValue == m.value
|
||||
}
|
||||
|
||||
func (m insertParameterMatcher) String() string {
|
||||
return fmt.Sprintf("ParameterValue %s=%s", m.name, m.value)
|
||||
}
|
||||
|
||||
func expectReplacedParam(oldID uuid.UUID, name, newValue string) func(store *dbmock.MockStore) {
|
||||
return func(mTx *dbmock.MockStore) {
|
||||
del := mTx.EXPECT().DeleteParameterValueByID(gomock.Any(), oldID).
|
||||
Times(1).
|
||||
Return(nil)
|
||||
mTx.EXPECT().InsertParameterValue(gomock.Any(), insertParameterMatcher{name, newValue}).
|
||||
Times(1).
|
||||
After(del).
|
||||
Return(database.ParameterValue{}, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func expectInsertedParam(name, newValue string) func(store *dbmock.MockStore) {
|
||||
return func(mTx *dbmock.MockStore) {
|
||||
mTx.EXPECT().InsertParameterValue(gomock.Any(), insertParameterMatcher{name, newValue}).
|
||||
Times(1).
|
||||
Return(database.ParameterValue{}, nil)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user