-
Notifications
You must be signed in to change notification settings - Fork 888
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't tested this out myself, but it looks solid to me.
coderd/templateversions.go
Outdated
// We use the workspace RBAC check since we don't want to allow plans if the | ||
// user can't create workspaces. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically correct - the best kind of correct.
-- 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 | ||
provisioner_job_type = 'template_version_plan' | ||
; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ALTER TYPE provisioner_job_type | ||
ADD VALUE IF NOT EXISTS 'template_version_plan'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// TODO (Dean): reprompt for parameter values if we deem it to | ||
// be a validation error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The 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 comment
The reason will be displayed to describe this comment to others. Learn more.
} | ||
transition, err := convertWorkspaceTransition(workspaceBuild.Transition) | ||
if err != nil { | ||
return nil, failJob(fmt.Sprint("convert workspace transition: %w", err)) | ||
return nil, failJob(fmt.Sprintf("convert workspace transition: %s", err)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No wrapping? I guess this gets protobuffed in the end, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't wrap with Sprintf, and these just get condensed to strings sadly :(
coderd/templateversions.go
Outdated
var req codersdk.CreateTemplateVersionPlanRequest | ||
if !httpapi.Read(rw, r, &req) { | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a user, I could spam this ~1000 times and take down a Coder deployment for the day. The same could be said for workspaces, but we have issues tracking quotas for those.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK so I'll just add details to those issues that whatever fix we do needs to apply to this endpoint too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you link the issue? I can't seem to find it after searching "rate limit" and "quota"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh my bad for being slow here.
Can we limit the parallelization here? This is a remarkably easy attack vector that we don't seem to have a solid plan to fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems out of scope for this PR because we have the same issue with regular workspace builds and template imports which also needs to be fixed. It'd make sense to come up with a good solution that covers all of these job types
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case, what's the mechanism we use to block multiple workspace builds so we can implement here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiple builds cannot occur for the same workspace in parallel because they are stateful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have any protection across multiple builds across multiple workspaces on the same user?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, but it's less of a problem because that'd be extremely easy to detect malice via our current API. An admin could list workspaces to easily detect who's the malicious actor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair, but I still think that a global solution should be applied to all jobs simultaneously. You said earlier there was a ticket about this, could you link it so I can add context to it? I will try to tackle it before community MVP
coderd/provisionerdaemons.go
Outdated
var input templateVersionPlanJob | ||
err = json.Unmarshal(job.Input, &input) | ||
if err != nil { | ||
return nil, failJob(fmt.Sprintf("unmarshal job input %q: %s", job.Input, err)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It scares me to add another job with such similar scope to the others, but I understand why.
It'd be helpful if you explained why we couldn't use the workspace_build
job to do similarly. I believe it'd just require not being attached to a literal workspace build, which seems like a reasonable change anyways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to have a separate job for this because the job endpoints have different schemas and different endpoints to access the job details, not a unified /jobs
endpoint. You've said in the past that you'd like to split these different job types apart more in the future (so they don't share DB tables for metadata etc.), so merging these two jobs together would be counterintuitive to that goal
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The inputs are slightly different, but the outputs are the same, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Effectively, yes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably worth opening a ticket considering merging those job types, or at least stating what the impl would look like to merge them. I'm always nervous about adding more job types.
return err | ||
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 comment
The 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.
…template parameters (#1732)
Adds a new provisioner job type
template_version_plan
which is for running a plan against a template version with custom parameters, but without having to make a workspace first. This will be used incoder create
so we can verify that the workspace creation will start successfully and not fail quickly due to bad parameter values (leaving an inconsolable workspace state).Subtasks
template_version_plan
provisioner job type to databasePOST /templateversions/:template_version_id/plan
endpoint and codersdk methodsTemplateVersionPlan
template_version_plan
provisioner jobs =>TemplateVersionPlan
protobuf jobsTemplateVersionPlan
jobscoder create
before creating the workspacecoder create
planFuture:
Screenshots
Successful validation:

Unsuccessful validation/plan:

Fixes #831