- Notifications
You must be signed in to change notification settings - Fork928
feat: run a terraform plan before creating workspaces with the given template parameters#1732
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
3e9ecc3
cf033aa
bafe1c1
cfe34af
0d03a39
4078fd1
8d04749
4b06c72
2fee23a
6b95e54
0b6d083
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
package cliui | ||
import ( | ||
"bytes" | ||
"context" | ||
"fmt" | ||
"io" | ||
@@ -35,6 +36,9 @@ type ProvisionerJobOptions struct { | ||
FetchInterval time.Duration | ||
// Verbose determines whether debug and trace logs will be shown. | ||
Verbose bool | ||
// Silent determines whether log output will be shown unless there is an | ||
// error. | ||
Silent bool | ||
} | ||
// ProvisionerJob renders a provisioner job with interactive cancellation. | ||
@@ -133,12 +137,30 @@ func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOp | ||
return xerrors.Errorf("logs: %w", err) | ||
} | ||
var ( | ||
// logOutput is where log output is written | ||
logOutput = writer | ||
// logBuffer is where logs are buffered if opts.Silent is true | ||
logBuffer = &bytes.Buffer{} | ||
) | ||
if opts.Silent { | ||
logOutput = logBuffer | ||
} | ||
flushLogBuffer := func() { | ||
if opts.Silent { | ||
_, _ = io.Copy(writer, logBuffer) | ||
} | ||
} | ||
ticker := time.NewTicker(opts.FetchInterval) | ||
defer ticker.Stop() | ||
deansheather marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
for { | ||
select { | ||
case err = <-errChan: | ||
flushLogBuffer() | ||
return err | ||
case <-ctx.Done(): | ||
flushLogBuffer() | ||
return ctx.Err() | ||
case <-ticker.C: | ||
updateJob() | ||
@@ -160,8 +182,10 @@ func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOp | ||
} | ||
err = xerrors.New(job.Error) | ||
jobMutex.Unlock() | ||
flushLogBuffer() | ||
return err | ||
} | ||
output := "" | ||
switch log.Level { | ||
case codersdk.LogLevelTrace, codersdk.LogLevelDebug: | ||
@@ -176,14 +200,17 @@ func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOp | ||
case codersdk.LogLevelInfo: | ||
output = log.Output | ||
} | ||
jobMutex.Lock() | ||
if log.Stage != currentStage && log.Stage != "" { | ||
updateStage(log.Stage, log.CreatedAt) | ||
jobMutex.Unlock() | ||
continue | ||
} | ||
_, _ = fmt.Fprintf(logOutput, "%s %s\n", Styles.Placeholder.Render(" "), output) | ||
if !opts.Silent { | ||
didLogBetweenStage = true | ||
} | ||
jobMutex.Unlock() | ||
} | ||
} | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -170,10 +170,40 @@ func create() *cobra.Command { | ||
} | ||
_, _ = fmt.Fprintln(cmd.OutOrStdout()) | ||
// Run a dry-run with the given parameters to check correctness | ||
after := time.Now() | ||
dryRun, err := client.CreateTemplateVersionDryRun(cmd.Context(), templateVersion.ID, codersdk.CreateTemplateVersionDryRunRequest{ | ||
WorkspaceName: workspaceName, | ||
ParameterValues: parameters, | ||
}) | ||
if err != nil { | ||
return xerrors.Errorf("begin workspace dry-run: %w", err) | ||
} | ||
_, _ = fmt.Fprintln(cmd.OutOrStdout(), "Planning workspace...") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. I kept the language "Planning workspace" because I couldn't come up with something that made sense with the word "dry-run".... "Dry-running workspace" "Running workspace dry-run" etc. | ||
err = cliui.ProvisionerJob(cmd.Context(), cmd.OutOrStdout(), cliui.ProvisionerJobOptions{ | ||
Fetch: func() (codersdk.ProvisionerJob, error) { | ||
return client.TemplateVersionDryRun(cmd.Context(), templateVersion.ID, dryRun.ID) | ||
}, | ||
Cancel: func() error { | ||
return client.CancelTemplateVersionDryRun(cmd.Context(), templateVersion.ID, dryRun.ID) | ||
}, | ||
Logs: func() (<-chan codersdk.ProvisionerJobLog, error) { | ||
return client.TemplateVersionDryRunLogsAfter(cmd.Context(), templateVersion.ID, dryRun.ID, after) | ||
}, | ||
// Don't show log output for the dry-run unless there's an error. | ||
Silent: true, | ||
}) | ||
if err != nil { | ||
// TODO (Dean): reprompt for parameter values if we deem it to | ||
// be a validation error | ||
Comment on lines +197 to +198 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. TODO: open an issue There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. | ||
return xerrors.Errorf("dry-run workspace: %w", err) | ||
} | ||
resources, err := client.TemplateVersionDryRunResources(cmd.Context(), templateVersion.ID, dryRun.ID) | ||
if err != nil { | ||
return xerrors.Errorf("get workspace dry-run resources: %w", err) | ||
} | ||
err = cliui.WorkspaceResources(cmd.OutOrStdout(), resources, cliui.WorkspaceResourcesOptions{ | ||
WorkspaceName: workspaceName, | ||
// Since agent's haven't connected yet, hiding this makes more sense. | ||
@@ -192,7 +222,6 @@ func create() *cobra.Command { | ||
return err | ||
} | ||
workspace, err := client.CreateWorkspace(cmd.Context(), organization.ID, codersdk.CreateWorkspaceRequest{ | ||
TemplateID: template.ID, | ||
Name: workspaceName, | ||
@@ -204,7 +233,7 @@ func create() *cobra.Command { | ||
return err | ||
} | ||
err = cliui.WorkspaceBuild(cmd.Context(), cmd.OutOrStdout(), client, workspace.LatestBuild.ID,after) | ||
if err != nil { | ||
return err | ||
} | ||
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
-- It's not possible to drop enum values from enum types, so the UP has "IF NOT | ||
-- EXISTS". | ||
-- Delete all jobs that use the new enum value. | ||
DELETE FROM | ||
provisioner_jobs | ||
WHERE | ||
type = 'template_version_dry_run' | ||
; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
ALTER TYPE provisioner_job_type | ||
ADD VALUE IF NOT EXISTS 'template_version_dry_run'; |
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.