feat!: extract provisioner tags from coder_workspace_tags data source#15578
Conversation
…when creating a template version
…space-tags-plumbing
…space-tags-plumbing
| // Tag order precedence: | ||
| // 1) User-specified tags in the request | ||
| // 2) Tags parsed from coder_workspace_tags data source in template file | ||
| // 2 may clobber 1. | ||
| tags := provisionersdk.MutateTags(apiKey.UserID, req.ProvisionerTags, parsedTags) |
There was a problem hiding this comment.
TBD: Which is the desired order here? 1 -> 2, 2-> 1, or 1 XOR 2?
There was a problem hiding this comment.
Wouldn't it be a potential security issue if a user could override the template tags? The user could then swap to a provisioner they shouldn't be able to access. Just a thought.
There was a problem hiding this comment.
As long as a user can't modify owner or scope, I think being able to override tags is a feature. It's how I would get a workspace to be provisioned using a provisioner in my specific region if the template defaults to a US region provisioner for example. And MutateTags protects the owner and scope tags afaik.
Although the template may well have a tag sourced from a variable for this.
|
Bit of an essay 🙈: There's some duplication ( Yesterday, I was in favour of the CLI and frontend checks for provisioners instead of warnings, because:
Currently, it looks to me like it would actually be better to use your more robust endpoint-side check and send a warning, instead of doing the same check in three places. That would eliminate duplication not only in your CLI command but also in my frontend alerts. Another key aspect of this is the configurable health check interval that I can't currently access from the frontend. This might be more accessible in the API than in the other places. |
| // Tag order precedence: | ||
| // 1) User-specified tags in the request | ||
| // 2) Tags parsed from coder_workspace_tags data source in template file | ||
| // 2 may clobber 1. | ||
| tags := provisionersdk.MutateTags(apiKey.UserID, req.ProvisionerTags, parsedTags) |
There was a problem hiding this comment.
Wouldn't it be a potential security issue if a user could override the template tags? The user could then swap to a provisioner they shouldn't be able to access. Just a thought.
| } | ||
| }`, | ||
| }, | ||
| wantTags: map[string]string{"owner": "", "scope": "organization"}, |
There was a problem hiding this comment.
Should this be an error? Silently replacing seems like a recipe for confusion.
There was a problem hiding this comment.
I was debating that, but you've sold me. 👍
There was a problem hiding this comment.
I might make this a follow-up, as the existing behaviour of provisionersdk.MutateTags is to overwrite provisionersdk.TagOwner
At this point, the user still needs to be a template admin. a) don't want to use Right now there's no field in |
|
|
||
| Warnings []TemplateVersionWarning `json:"warnings,omitempty" enums:"DEPRECATED_PARAMETERS"` | ||
| Warnings []TemplateVersionWarning `json:"warnings,omitempty" enums:"DEPRECATED_PARAMETERS"` | ||
| MatchedProvisioners MatchedProvisioners `json:"matched_provisioners,omitempty"` |
There was a problem hiding this comment.
review: I considered adding as a field on the ProvisionerJob but it did not seem 100% correct.
However, as it does not make sense to return this from e.g. getting a previous template version, it may make sense instead to make this nullable (e.g. *MatchedProvisioners). Thoughts?
There was a problem hiding this comment.
From what I could see last week, the only way to see tags for a workspace build is to get that workspace's template version. Therefore, I think we need this even for previous template versions.
There was a problem hiding this comment.
Looked at where else we use this payload. You're right, it isn't necessary elsewhere. That means we could make it nullable. Whether that would be better for API clients, I'm not sure. Would be happy if you made it nullable. Would be happy if you left it as is.
There was a problem hiding this comment.
I'll keep it as-is for now so you can build on top of it. It should be a fairly simple refactor to make it a nullable field later.
| return codersdk.MatchedProvisioners{}, xerrors.Errorf("provisioner daemons by organization: %w", err) | ||
| } | ||
|
|
||
| threePollsAgo := time.Now().Add(-3 * pollInterval) |
There was a problem hiding this comment.
review: this is duplicated from / in line with coderd/healthcheck:
if opts.StaleInterval == 0 {
opts.StaleInterval = provisionerdserver.DefaultHeartbeatInterval * 3
}
There was a problem hiding this comment.
Do we need the above as a code comment or perhaps a test that checks that they remain in sync?
There was a problem hiding this comment.
I'm not sure of the value of adding a test for this, but we can possibly refactor where it's defined in a follow-up so that it's consistent. For now, I'll add a comment 👍
There was a problem hiding this comment.
On the surface it kinda makes sense to use the same logic (3*poll), but at the same time I feel multiplying by 3 is pretty extreme, I'm more in favor of a fixed time like poll+30s or something like that. In this instance poll+30s would surface the issue in half the time. If poll is ever raised, to say 2min, the multiplication would go from 1.5min to 3.5min longer to surface the issue, etc.
SasSwart
left a comment
There was a problem hiding this comment.
Looks good. There are some comments left, but none of them block merge IMO. I'm going to be actively consuming this shortly, so I'll get to nits in a subsequent PR if we're happy to do that.
mafredri
left a comment
There was a problem hiding this comment.
Minor nits, and not sold on the three-polls duration (I feel that's longer than what was discussed previously), but otherwise LGTM. 👍🏻
| return codersdk.MatchedProvisioners{}, xerrors.Errorf("provisioner daemons by organization: %w", err) | ||
| } | ||
|
|
||
| threePollsAgo := time.Now().Add(-3 * pollInterval) |
There was a problem hiding this comment.
On the surface it kinda makes sense to use the same logic (3*poll), but at the same time I feel multiplying by 3 is pretty extreme, I'm more in favor of a fixed time like poll+30s or something like that. In this instance poll+30s would surface the issue in half the time. If poll is ever raised, to say 2min, the multiplication would go from 1.5min to 3.5min longer to surface the issue, etc.
| // MostRecentlySeen is the most recently seen time of the set of matched | ||
| // provisioners. If no provisioners matched, this field will be null. | ||
| MostRecentlySeen NullTime `json:"most_recently_seen,omitempty" format:"date-time"` | ||
| } |
That's fair; I'd rather have it be consistent though. I'll open a follow-up PR to adjust this. |
Co-authored-by: Mathias Fredriksson <mafredri@gmail.com>
Relates to #15087 and #15427
coder_workspace_tagson template version creation usingprovisioner/terraform/tfparseadded in feat(provisioner/terraform/tfparse): implement WorkspaceTagDefaultsFromFile #15236codersdk.MatchedProvisionersstruct to theTemplateVersionresponse containing details of how many provisioners were around at the time of the insert.NOTE: As this effectively blocks template creation if
coder_workspace_tagsis malformed or references anything other than a Terraform variable orcoder_parameter, I am marking this as a breaking change.Testing notes:
coderdtestin favour of just creating the template version and asserting that a provisioner job was created with the expected tags.Checklist:
Manual testing performed:
./develop.sh -- --provisioner-daemons=0with a separate./scripts/coder-dev.sh --key=foobarwhere foobar.keys ={"foo": "bar"}coder template pushand observed the job get picked uptemplate_version_workspace_tags:Ran
coder createand observed the job getting picked up correctly.Failure case:
coder templates push <template>with no workspace tags available:Remaining work:
/api/v2/organizations/:org/templateversionsreturns an error. This will need to be addressed in a follow-up PR.