mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
Adds `POST /api/v2/templatebuilder/compose/template`, a synchronous endpoint that composes a template from a base and modules, validates it via a provisioner import job, and creates the template in a single request. The handler composes terraform files, bundles them as a tar, inserts the file with hash-based dedup, creates a template version with an import job, waits up to 2 minutes for the job to complete, classifies errors for known failure modes (network-unreachable registry, DNS failures), then creates the template on success. Canceled and failed jobs return appropriate error responses. Also adds `hclwrite.Format` to composed terraform output for canonical HCL formatting. Closes https://linear.app/codercom/issue/DEVEX-279 <details> <summary>Implementation notes</summary> - SDK types and client method in `codersdk/templatebuilder.go` with validation tags matching the standard template creation path (`template_display_name`, `lt=128`) - `ClassifyProvisionerError` in `coderd/templatebuilder/errors.go` detects DNS, connection refused, i/o timeout, and TLS handshake failures and returns actionable messages - `waitForProvisionerJob` polls with a ramp-up interval schedule (100ms, 200ms, 500ms, then 1s steady) and accepts an `onUpdate` callback for future SSE streaming - Audit logging for both template and template version creation - TOCTOU name uniqueness: early check for fast feedback, DB unique constraint catch for the race window (returns 409, not 500) - Swagger annotations for all error responses (400, 404, 409, 504) </details> > 🤖 Generated by Coder Agents
33 lines
1005 B
Go
33 lines
1005 B
Go
package templatebuilder
|
|
|
|
import "strings"
|
|
|
|
// networkErrorPatterns are substrings found in provisioner job output when
|
|
// the Terraform registry or provider endpoints are unreachable.
|
|
var networkErrorPatterns = []string{
|
|
"no such host",
|
|
"connection refused",
|
|
"i/o timeout",
|
|
"dial tcp: lookup",
|
|
"network is unreachable",
|
|
"no route to host",
|
|
"TLS handshake timeout",
|
|
}
|
|
|
|
// ClassifyProvisionerError inspects a provisioner job error and its log
|
|
// lines, returning a user-friendly message for known failure modes.
|
|
// If the error is not recognized, the raw jobError is returned unchanged.
|
|
func ClassifyProvisionerError(jobError string, logs []string) string {
|
|
combined := jobError + "\n" + strings.Join(logs, "\n")
|
|
|
|
for _, pattern := range networkErrorPatterns {
|
|
if strings.Contains(combined, pattern) {
|
|
return "The Terraform registry is unreachable from your provisioner. " +
|
|
"Check network configuration and ensure registry.terraform.io " +
|
|
"is accessible."
|
|
}
|
|
}
|
|
|
|
return jobError
|
|
}
|