feat!: drop support for legacy parameters (#7663)

This commit is contained in:
Marcin Tojek
2023-06-02 11:16:46 +02:00
committed by GitHub
parent 2b63492649
commit a7366a8b76
106 changed files with 1153 additions and 8553 deletions

View File

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

View File

@ -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)
}
}