mirror of
https://github.com/coder/coder.git
synced 2025-07-15 22:20:27 +00:00
fix: fix for prebuilds claiming and deletion (#17624)
PR contains: - fix for claiming & deleting prebuilds with immutable params - unit test for claiming scenario - unit test for deletion scenario The parameter resolver was failing when deleting/claiming prebuilds because a value for a previously-used parameter was provided to the resolver, but since the value was unchanged (it's coming from the preset) it failed in the resolver. The resolver was missing a check to see if the old value != new value; if the values match then there's no mutation of an immutable parameter. --------- Signed-off-by: Danny Kopping <dannykopping@gmail.com>
This commit is contained in:
committed by
GitHub
parent
c7fc7b91ec
commit
98e5611e16
@ -164,7 +164,7 @@ type ParameterResolver struct {
|
|||||||
// resolves the correct value. It returns the value of the parameter, if valid, and an error if invalid.
|
// resolves the correct value. It returns the value of the parameter, if valid, and an error if invalid.
|
||||||
func (r *ParameterResolver) ValidateResolve(p TemplateVersionParameter, v *WorkspaceBuildParameter) (value string, err error) {
|
func (r *ParameterResolver) ValidateResolve(p TemplateVersionParameter, v *WorkspaceBuildParameter) (value string, err error) {
|
||||||
prevV := r.findLastValue(p)
|
prevV := r.findLastValue(p)
|
||||||
if !p.Mutable && v != nil && prevV != nil {
|
if !p.Mutable && v != nil && prevV != nil && v.Value != prevV.Value {
|
||||||
return "", xerrors.Errorf("Parameter %q is not mutable, so it can't be updated after creating a workspace.", p.Name)
|
return "", xerrors.Errorf("Parameter %q is not mutable, so it can't be updated after creating a workspace.", p.Name)
|
||||||
}
|
}
|
||||||
if p.Required && v == nil && prevV == nil {
|
if p.Required && v == nil && prevV == nil {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package codersdk_test
|
package codersdk_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -121,20 +122,60 @@ func TestParameterResolver_ValidateResolve_NewOverridesOld(t *testing.T) {
|
|||||||
func TestParameterResolver_ValidateResolve_Immutable(t *testing.T) {
|
func TestParameterResolver_ValidateResolve_Immutable(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
uut := codersdk.ParameterResolver{
|
uut := codersdk.ParameterResolver{
|
||||||
Rich: []codersdk.WorkspaceBuildParameter{{Name: "n", Value: "5"}},
|
Rich: []codersdk.WorkspaceBuildParameter{{Name: "n", Value: "old"}},
|
||||||
}
|
}
|
||||||
p := codersdk.TemplateVersionParameter{
|
p := codersdk.TemplateVersionParameter{
|
||||||
Name: "n",
|
Name: "n",
|
||||||
Type: "number",
|
Type: "string",
|
||||||
Required: true,
|
Required: true,
|
||||||
Mutable: false,
|
Mutable: false,
|
||||||
}
|
}
|
||||||
v, err := uut.ValidateResolve(p, &codersdk.WorkspaceBuildParameter{
|
|
||||||
Name: "n",
|
cases := []struct {
|
||||||
Value: "6",
|
name string
|
||||||
})
|
newValue string
|
||||||
require.Error(t, err)
|
expectedErr string
|
||||||
require.Equal(t, "", v)
|
}{
|
||||||
|
{
|
||||||
|
name: "mutation",
|
||||||
|
newValue: "new", // "new" != "old"
|
||||||
|
expectedErr: fmt.Sprintf("Parameter %q is not mutable", p.Name),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Values are case-sensitive.
|
||||||
|
name: "case change",
|
||||||
|
newValue: "Old", // "Old" != "old"
|
||||||
|
expectedErr: fmt.Sprintf("Parameter %q is not mutable", p.Name),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "default",
|
||||||
|
newValue: "", // "" != "old"
|
||||||
|
expectedErr: fmt.Sprintf("Parameter %q is not mutable", p.Name),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no change",
|
||||||
|
newValue: "old", // "old" == "old"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
v, err := uut.ValidateResolve(p, &codersdk.WorkspaceBuildParameter{
|
||||||
|
Name: "n",
|
||||||
|
Value: tc.newValue,
|
||||||
|
})
|
||||||
|
|
||||||
|
if tc.expectedErr == "" {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, tc.newValue, v)
|
||||||
|
} else {
|
||||||
|
require.ErrorContains(t, err, tc.expectedErr)
|
||||||
|
require.Equal(t, "", v)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRichParameterValidation(t *testing.T) {
|
func TestRichParameterValidation(t *testing.T) {
|
||||||
|
@ -329,9 +329,8 @@ func TestClaimPrebuild(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
stopBuild, err := userClient.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
|
stopBuild, err := userClient.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
|
||||||
TemplateVersionID: version.ID,
|
TemplateVersionID: version.ID,
|
||||||
Transition: codersdk.WorkspaceTransitionStop,
|
Transition: codersdk.WorkspaceTransitionStop,
|
||||||
RichParameterValues: wp,
|
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
coderdtest.AwaitWorkspaceBuildJobCompleted(t, userClient, stopBuild.ID)
|
coderdtest.AwaitWorkspaceBuildJobCompleted(t, userClient, stopBuild.ID)
|
||||||
@ -369,6 +368,17 @@ func templateWithAgentAndPresetsWithPrebuilds(desiredInstances int32) *echo.Resp
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// Make sure immutable params don't break claiming logic
|
||||||
|
Parameters: []*proto.RichParameter{
|
||||||
|
{
|
||||||
|
Name: "k1",
|
||||||
|
Description: "immutable param",
|
||||||
|
Type: "string",
|
||||||
|
DefaultValue: "",
|
||||||
|
Required: false,
|
||||||
|
Mutable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
Presets: []*proto.Preset{
|
Presets: []*proto.Preset{
|
||||||
{
|
{
|
||||||
Name: "preset-a",
|
Name: "preset-a",
|
||||||
|
@ -901,6 +901,16 @@ func setupTestDBTemplateVersion(
|
|||||||
ID: templateID,
|
ID: templateID,
|
||||||
ActiveVersionID: templateVersion.ID,
|
ActiveVersionID: templateVersion.ID,
|
||||||
}))
|
}))
|
||||||
|
// Make sure immutable params don't break prebuilt workspace deletion logic
|
||||||
|
dbgen.TemplateVersionParameter(t, db, database.TemplateVersionParameter{
|
||||||
|
TemplateVersionID: templateVersion.ID,
|
||||||
|
Name: "test",
|
||||||
|
Description: "required & immutable param",
|
||||||
|
Type: "string",
|
||||||
|
DefaultValue: "",
|
||||||
|
Required: true,
|
||||||
|
Mutable: false,
|
||||||
|
})
|
||||||
return templateVersion.ID
|
return templateVersion.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -999,7 +1009,7 @@ func setupTestDBWorkspace(
|
|||||||
OrganizationID: orgID,
|
OrganizationID: orgID,
|
||||||
Error: buildError,
|
Error: buildError,
|
||||||
})
|
})
|
||||||
dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{
|
workspaceBuild := dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{
|
||||||
WorkspaceID: workspace.ID,
|
WorkspaceID: workspace.ID,
|
||||||
InitiatorID: initiatorID,
|
InitiatorID: initiatorID,
|
||||||
TemplateVersionID: templateVersionID,
|
TemplateVersionID: templateVersionID,
|
||||||
@ -1008,6 +1018,13 @@ func setupTestDBWorkspace(
|
|||||||
Transition: transition,
|
Transition: transition,
|
||||||
CreatedAt: clock.Now(),
|
CreatedAt: clock.Now(),
|
||||||
})
|
})
|
||||||
|
dbgen.WorkspaceBuildParameters(t, db, []database.WorkspaceBuildParameter{
|
||||||
|
{
|
||||||
|
WorkspaceBuildID: workspaceBuild.ID,
|
||||||
|
Name: "test",
|
||||||
|
Value: "test",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
return workspace
|
return workspace
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user