Skip to content

fix(coderd/wsbuilder): correctly evaluate dynamic workspace tag values #15897

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

Merged
merged 10 commits into from
Dec 17, 2024

Conversation

johnstcn
Copy link
Member

@johnstcn johnstcn commented Dec 17, 2024

Relates to #15894:

  • Adds coderdenttest.NewExternalProvisionerDaemonTerraform
  • Adds integration-style test coverage for creating a workspace with coder_workspace_tags specified in main.tf
  • Modifies coderd/wsbuilder to fetch template version variables and include them in eval context for evaluating coder_workspace_tags

@johnstcn johnstcn changed the title Cj/fix gh 15894 fix(coderd/wsbuilder): correctly evaluate dynamic workspace tag values Dec 17, 2024
@johnstcn johnstcn marked this pull request as ready for review December 17, 2024 18:07
Copy link

github-actions bot commented Dec 17, 2024


✔️ PR 15897 Updated successfully.
🚀 Access the credentials here.

cc: @johnstcn

Copy link
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks for adding this functionality!

@@ -617,6 +618,22 @@ func (b *Builder) getTemplateVersionParameters() ([]database.TemplateVersionPara
return tvp, nil
}

func (b *Builder) getTemplateVersionVariables() ([]database.TemplateVersionVariable, error) {
if b.templateVersionVariables != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use a mutex/atomic here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the builder is meant to be safe for concurrent use.
Maybe good for a follow-up though, as it could trip someone else up in future.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, we do this pattern everywhere. It's all single threaded

// goroutine and returns a closer to stop it. The echo provisioner is used
// here. This is the default provisioner for tests and should be fine for
// most use cases. If you need to test terraform-specific behaviors, use
// NewExternalProvisionerDaemonTerraform instead.
func NewExternalProvisionerDaemon(t testing.TB, client *codersdk.Client, org uuid.UUID, tags map[string]string) io.Closer {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: NewExternalEchoProvisionerDaemon?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can rename in a follow-up! It would be a big diff :D

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, I think I wrote the original name. I don't think I even considered expected non-echo type in tests 😄

Copy link
Member

@mtojek mtojek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

// goroutine and returns a closer to stop it. The echo provisioner is used
// here. This is the default provisioner for tests and should be fine for
// most use cases. If you need to test terraform-specific behaviors, use
// NewExternalProvisionerDaemonTerraform instead.
func NewExternalProvisionerDaemon(t testing.TB, client *codersdk.Client, org uuid.UUID, tags map[string]string) io.Closer {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, I think I wrote the original name. I don't think I even considered expected non-echo type in tests 😄

Comment on lines +367 to +373
assert.NoError(t, terraform.Serve(ctx, &terraform.ServeOptions{
BinaryPath: terraformPath,
CachePath: t.TempDir(),
ServeOptions: &provisionersdk.ServeOptions{
Listener: provisionerSrv,
WorkDirectory: t.TempDir(),
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this runs real terraform? Does this mean tests can accidentally provision resources?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's the tricky thing if you're not careful. There's no other real way to test this apart from spinning up a Docker container or manual testing, and we really need some kind of integration test here.

Comment on lines +1425 to +1430
// TestWorkspaceTagsTerraform tests that a workspace can be created with tags.
// This is an end-to-end-style test, meaning that we actually run the
// real Terraform provisioner and validate that the workspace is created
// successfully. The workspace itself does not specify any resources, and
// this is fine.
func TestWorkspaceTagsTerraform(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woah, he did it 🤯

This is a super nice test. Slightly concerned with terraform being executed in tests, would be nice if we could lock it down somehow to prevent it allocating any resources.

Copy link
Member Author

@johnstcn johnstcn Dec 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could add a hacky check for the pattern resource "[^"]+" "[^"]+" and fail. That would at least make folks think twice before hacking it further to allow certain resources.

EDIT: Actually I'm not even sure I could do that right now due to how provisionerd works. Needs some more thinking. For now... ruleguard? 🤷

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think ruleguard would be sufficient. I wonder if we can do something to the executable. Run it another userspace with no perms? Configure a HTTP_PROXY that is broken so any external requests fail? I'm not sure 🤷‍♂️

I'm ok if we let this slide for now, since I don't know a good way. Just an unfortunate consequence.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think we may need to think about the best way to prevent misuse of this.

@johnstcn johnstcn merged commit dcf5153 into main Dec 17, 2024
30 checks passed
@johnstcn johnstcn deleted the cj/fix-gh-15894 branch December 17, 2024 21:57
@github-actions github-actions bot locked and limited conversation to collaborators Dec 17, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
4 participants