mirror of
https://github.com/coder/coder.git
synced 2025-07-06 15:41:45 +00:00
* feat: influence parameter defaults through cli flag/env Add a --parameter-default flag / CODER_RICH_PARAMETER_DEFAULT environment variable which overrides default values suggested for parameters. This allows scripts or middleware wrapping the CLI to substitute defaults for parameter values beyond those defined at the template level. For example, Git repository/branch parameters can be given defaults based on the current checkout, or default parameter values can be parsed out of files inside the repo. * Rename defaults arg to defaultOverrides
156 lines
5.3 KiB
Go
156 lines
5.3 KiB
Go
package cli
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/coder/coder/v2/cli/cliui"
|
|
"github.com/coder/coder/v2/codersdk"
|
|
"github.com/coder/serpent"
|
|
)
|
|
|
|
func (r *RootCmd) start() *serpent.Command {
|
|
var parameterFlags workspaceParameterFlags
|
|
|
|
client := new(codersdk.Client)
|
|
cmd := &serpent.Command{
|
|
Annotations: workspaceCommand,
|
|
Use: "start <workspace>",
|
|
Short: "Start a workspace",
|
|
Middleware: serpent.Chain(
|
|
serpent.RequireNArgs(1),
|
|
r.InitClient(client),
|
|
),
|
|
Options: serpent.OptionSet{cliui.SkipPromptOption()},
|
|
Handler: func(inv *serpent.Invocation) error {
|
|
workspace, err := namedWorkspace(inv.Context(), client, inv.Args[0])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var build codersdk.WorkspaceBuild
|
|
switch workspace.LatestBuild.Status {
|
|
case codersdk.WorkspaceStatusRunning:
|
|
_, _ = fmt.Fprintf(
|
|
inv.Stdout, "\nThe %s workspace is already running!\n",
|
|
cliui.Keyword(workspace.Name),
|
|
)
|
|
return nil
|
|
case codersdk.WorkspaceStatusStarting:
|
|
_, _ = fmt.Fprintf(
|
|
inv.Stdout, "\nThe %s workspace is already starting.\n",
|
|
cliui.Keyword(workspace.Name),
|
|
)
|
|
build = workspace.LatestBuild
|
|
default:
|
|
build, err = startWorkspace(inv, client, workspace, parameterFlags, WorkspaceStart)
|
|
// It's possible for a workspace build to fail due to the template requiring starting
|
|
// workspaces with the active version.
|
|
if cerr, ok := codersdk.AsError(err); ok && cerr.StatusCode() == http.StatusForbidden {
|
|
_, _ = fmt.Fprintln(inv.Stdout, "Unable to start the workspace with the template version from the last build. Policy may require you to restart with the current active template version.")
|
|
build, err = startWorkspace(inv, client, workspace, parameterFlags, WorkspaceUpdate)
|
|
if err != nil {
|
|
return xerrors.Errorf("start workspace with active template version: %w", err)
|
|
}
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
err = cliui.WorkspaceBuild(inv.Context(), inv.Stdout, client, build.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, _ = fmt.Fprintf(
|
|
inv.Stdout, "\nThe %s workspace has been started at %s!\n",
|
|
cliui.Keyword(workspace.Name), cliui.Timestamp(time.Now()),
|
|
)
|
|
return nil
|
|
},
|
|
}
|
|
|
|
cmd.Options = append(cmd.Options, parameterFlags.allOptions()...)
|
|
|
|
return cmd
|
|
}
|
|
|
|
func buildWorkspaceStartRequest(inv *serpent.Invocation, client *codersdk.Client, workspace codersdk.Workspace, parameterFlags workspaceParameterFlags, action WorkspaceCLIAction) (codersdk.CreateWorkspaceBuildRequest, error) {
|
|
version := workspace.LatestBuild.TemplateVersionID
|
|
|
|
if workspace.AutomaticUpdates == codersdk.AutomaticUpdatesAlways || action == WorkspaceUpdate {
|
|
version = workspace.TemplateActiveVersionID
|
|
if version != workspace.LatestBuild.TemplateVersionID {
|
|
action = WorkspaceUpdate
|
|
}
|
|
}
|
|
|
|
lastBuildParameters, err := client.WorkspaceBuildParameters(inv.Context(), workspace.LatestBuild.ID)
|
|
if err != nil {
|
|
return codersdk.CreateWorkspaceBuildRequest{}, err
|
|
}
|
|
|
|
buildOptions, err := asWorkspaceBuildParameters(parameterFlags.buildOptions)
|
|
if err != nil {
|
|
return codersdk.CreateWorkspaceBuildRequest{}, xerrors.Errorf("unable to parse build options: %w", err)
|
|
}
|
|
|
|
cliRichParameters, err := asWorkspaceBuildParameters(parameterFlags.richParameters)
|
|
if err != nil {
|
|
return codersdk.CreateWorkspaceBuildRequest{}, xerrors.Errorf("unable to parse rich parameters: %w", err)
|
|
}
|
|
|
|
cliRichParameterDefaults, err := asWorkspaceBuildParameters(parameterFlags.richParameterDefaults)
|
|
if err != nil {
|
|
return codersdk.CreateWorkspaceBuildRequest{}, xerrors.Errorf("unable to parse rich parameter defaults: %w", err)
|
|
}
|
|
|
|
buildParameters, err := prepWorkspaceBuild(inv, client, prepWorkspaceBuildArgs{
|
|
Action: action,
|
|
TemplateVersionID: version,
|
|
NewWorkspaceName: workspace.Name,
|
|
LastBuildParameters: lastBuildParameters,
|
|
|
|
PromptBuildOptions: parameterFlags.promptBuildOptions,
|
|
BuildOptions: buildOptions,
|
|
PromptRichParameters: parameterFlags.promptRichParameters,
|
|
RichParameters: cliRichParameters,
|
|
RichParameterFile: parameterFlags.richParameterFile,
|
|
RichParameterDefaults: cliRichParameterDefaults,
|
|
})
|
|
if err != nil {
|
|
return codersdk.CreateWorkspaceBuildRequest{}, err
|
|
}
|
|
|
|
return codersdk.CreateWorkspaceBuildRequest{
|
|
Transition: codersdk.WorkspaceTransitionStart,
|
|
RichParameterValues: buildParameters,
|
|
TemplateVersionID: version,
|
|
}, nil
|
|
}
|
|
|
|
func startWorkspace(inv *serpent.Invocation, client *codersdk.Client, workspace codersdk.Workspace, parameterFlags workspaceParameterFlags, action WorkspaceCLIAction) (codersdk.WorkspaceBuild, error) {
|
|
if workspace.DormantAt != nil {
|
|
_, _ = fmt.Fprintln(inv.Stdout, "Activating dormant workspace...")
|
|
err := client.UpdateWorkspaceDormancy(inv.Context(), workspace.ID, codersdk.UpdateWorkspaceDormancy{
|
|
Dormant: false,
|
|
})
|
|
if err != nil {
|
|
return codersdk.WorkspaceBuild{}, xerrors.Errorf("activate workspace: %w", err)
|
|
}
|
|
}
|
|
req, err := buildWorkspaceStartRequest(inv, client, workspace, parameterFlags, action)
|
|
if err != nil {
|
|
return codersdk.WorkspaceBuild{}, err
|
|
}
|
|
|
|
build, err := client.CreateWorkspaceBuild(inv.Context(), workspace.ID, req)
|
|
if err != nil {
|
|
return codersdk.WorkspaceBuild{}, xerrors.Errorf("create workspace build: %w", err)
|
|
}
|
|
|
|
return build, nil
|
|
}
|