mirror of https://github.com/coder/coder.git
feat: accept immutable parameters when used first time (#7000)
* Backend fixes * CLI: adjust update flow
This commit is contained in:
parent
e84061e2be
commit
083fc89f93
|
@ -6,6 +6,7 @@ import (
|
|||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
|
@ -213,6 +214,7 @@ type prepWorkspaceBuildArgs struct {
|
|||
NewWorkspaceName string
|
||||
|
||||
UpdateWorkspace bool
|
||||
WorkspaceID uuid.UUID
|
||||
}
|
||||
|
||||
type buildParameters struct {
|
||||
|
@ -340,8 +342,17 @@ PromptRichParamLoop:
|
|||
}
|
||||
|
||||
if args.UpdateWorkspace && !templateVersionParameter.Mutable {
|
||||
_, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Warn.Render(fmt.Sprintf(`Parameter %q is not mutable, so can't be customized after workspace creation.`, templateVersionParameter.Name)))
|
||||
continue
|
||||
// Check if the immutable parameter was used in the previous build. If so, then it isn't a fresh one
|
||||
// and the user should be warned.
|
||||
exists, err := workspaceBuildParameterExists(ctx, client, args.WorkspaceID, templateVersionParameter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
_, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Warn.Render(fmt.Sprintf(`Parameter %q is not mutable, so can't be customized after workspace creation.`, templateVersionParameter.Name)))
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
parameterValue, err := getWorkspaceBuildParameterValueFromMapOrInput(inv, parameterMapFromFile, templateVersionParameter)
|
||||
|
@ -414,3 +425,17 @@ PromptRichParamLoop:
|
|||
richParameters: richParameters,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func workspaceBuildParameterExists(ctx context.Context, client *codersdk.Client, workspaceID uuid.UUID, templateVersionParameter codersdk.TemplateVersionParameter) (bool, error) {
|
||||
lastBuildParameters, err := client.WorkspaceBuildParameters(ctx, workspaceID)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("can't fetch last workspace build parameters: %w", err)
|
||||
}
|
||||
|
||||
for _, p := range lastBuildParameters {
|
||||
if p.Name == templateVersionParameter.Name {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
|
|
@ -59,7 +59,9 @@ func (r *RootCmd) update() *clibase.Cmd {
|
|||
ExistingRichParams: existingRichParams,
|
||||
RichParameterFile: richParameterFile,
|
||||
NewWorkspaceName: workspace.Name,
|
||||
UpdateWorkspace: true,
|
||||
|
||||
UpdateWorkspace: true,
|
||||
WorkspaceID: workspace.LatestBuild.ID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil
|
||||
|
|
|
@ -530,10 +530,12 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
|
|||
// Check if parameter value is in request
|
||||
if buildParameter, found := findWorkspaceBuildParameter(createBuild.RichParameterValues, templateVersionParameter.Name); found {
|
||||
if !templateVersionParameter.Mutable {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: fmt.Sprintf("Parameter %q is not mutable, so it can't be updated after creating a workspace.", templateVersionParameter.Name),
|
||||
})
|
||||
return
|
||||
if _, found := findWorkspaceBuildParameter(apiLastBuildParameters, templateVersionParameter.Name); found {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: fmt.Sprintf("Parameter %q is not mutable, so it can't be updated after creating a workspace.", templateVersionParameter.Name),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
parameters = append(parameters, *buildParameter)
|
||||
continue
|
||||
|
|
|
@ -781,6 +781,190 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
|
|||
})
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("NewImmutableRequiredParameterAdded", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, echoResponses)
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) {
|
||||
cwr.RichParameterValues = initialBuildParameters
|
||||
})
|
||||
|
||||
workspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
|
||||
require.Equal(t, codersdk.WorkspaceStatusRunning, workspaceBuild.Status)
|
||||
|
||||
// Push new template revision
|
||||
const newImmutableParameterName = "new_immutable_parameter"
|
||||
const newImmutableParameterDescription = "This is also an immutable parameter"
|
||||
version2 := coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
ProvisionPlan: []*proto.Provision_Response{
|
||||
{
|
||||
Type: &proto.Provision_Response_Complete{
|
||||
Complete: &proto.Provision_Complete{
|
||||
Parameters: []*proto.RichParameter{
|
||||
{Name: firstParameterName, Description: firstParameterDescription, Mutable: true},
|
||||
{Name: secondParameterName, Description: secondParameterDescription, Mutable: true},
|
||||
{Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false},
|
||||
{Name: newImmutableParameterName, Description: newImmutableParameterDescription, Mutable: false, Required: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ProvisionApply: []*proto.Provision_Response{{
|
||||
Type: &proto.Provision_Response_Complete{
|
||||
Complete: &proto.Provision_Complete{},
|
||||
},
|
||||
}},
|
||||
}, template.ID)
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version2.ID)
|
||||
err := client.UpdateActiveTemplateVersion(context.Background(), template.ID, codersdk.UpdateActiveTemplateVersion{
|
||||
ID: version2.ID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update build parameters
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
|
||||
nextBuildParameters := []codersdk.WorkspaceBuildParameter{
|
||||
{Name: newImmutableParameterName, Value: "good"},
|
||||
}
|
||||
_, err = client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
|
||||
TemplateVersionID: version2.ID,
|
||||
Transition: codersdk.WorkspaceTransitionStart,
|
||||
RichParameterValues: nextBuildParameters,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("NewImmutableOptionalParameterAdded", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, echoResponses)
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) {
|
||||
cwr.RichParameterValues = initialBuildParameters
|
||||
})
|
||||
|
||||
workspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
|
||||
require.Equal(t, codersdk.WorkspaceStatusRunning, workspaceBuild.Status)
|
||||
|
||||
// Push new template revision
|
||||
const newImmutableParameterName = "new_immutable_parameter"
|
||||
const newImmutableParameterDescription = "This is also an immutable parameter"
|
||||
version2 := coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
ProvisionPlan: []*proto.Provision_Response{
|
||||
{
|
||||
Type: &proto.Provision_Response_Complete{
|
||||
Complete: &proto.Provision_Complete{
|
||||
Parameters: []*proto.RichParameter{
|
||||
{Name: firstParameterName, Description: firstParameterDescription, Mutable: true},
|
||||
{Name: secondParameterName, Description: secondParameterDescription, Mutable: true},
|
||||
{Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false},
|
||||
{Name: newImmutableParameterName, Description: newImmutableParameterDescription, Mutable: false, DefaultValue: "12345"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ProvisionApply: []*proto.Provision_Response{{
|
||||
Type: &proto.Provision_Response_Complete{
|
||||
Complete: &proto.Provision_Complete{},
|
||||
},
|
||||
}},
|
||||
}, template.ID)
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version2.ID)
|
||||
err := client.UpdateActiveTemplateVersion(context.Background(), template.ID, codersdk.UpdateActiveTemplateVersion{
|
||||
ID: version2.ID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update build parameters
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
|
||||
nextBuildParameters := []codersdk.WorkspaceBuildParameter{
|
||||
{Name: newImmutableParameterName, Value: "good"},
|
||||
}
|
||||
_, err = client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
|
||||
TemplateVersionID: version2.ID,
|
||||
Transition: codersdk.WorkspaceTransitionStart,
|
||||
RichParameterValues: nextBuildParameters,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("NewImmutableOptionalParameterUsesDefault", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, echoResponses)
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) {
|
||||
cwr.RichParameterValues = initialBuildParameters
|
||||
})
|
||||
|
||||
workspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
|
||||
require.Equal(t, codersdk.WorkspaceStatusRunning, workspaceBuild.Status)
|
||||
|
||||
// Push new template revision
|
||||
const newImmutableParameterName = "new_immutable_parameter"
|
||||
const newImmutableParameterDescription = "This is also an immutable parameter"
|
||||
version2 := coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
ProvisionPlan: []*proto.Provision_Response{
|
||||
{
|
||||
Type: &proto.Provision_Response_Complete{
|
||||
Complete: &proto.Provision_Complete{
|
||||
Parameters: []*proto.RichParameter{
|
||||
{Name: firstParameterName, Description: firstParameterDescription, Mutable: true},
|
||||
{Name: secondParameterName, Description: secondParameterDescription, Mutable: true},
|
||||
{Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false},
|
||||
{Name: newImmutableParameterName, Description: newImmutableParameterDescription, Mutable: false, DefaultValue: "12345"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ProvisionApply: []*proto.Provision_Response{{
|
||||
Type: &proto.Provision_Response_Complete{
|
||||
Complete: &proto.Provision_Complete{},
|
||||
},
|
||||
}},
|
||||
}, template.ID)
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version2.ID)
|
||||
err := client.UpdateActiveTemplateVersion(context.Background(), template.ID, codersdk.UpdateActiveTemplateVersion{
|
||||
ID: version2.ID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update build parameters
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
|
||||
var nextBuildParameters []codersdk.WorkspaceBuildParameter
|
||||
_, err = client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
|
||||
TemplateVersionID: version2.ID,
|
||||
Transition: codersdk.WorkspaceTransitionStart,
|
||||
RichParameterValues: nextBuildParameters,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestWorkspaceBuildValidateRichParameters(t *testing.T) {
|
||||
|
|
Loading…
Reference in New Issue