mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat: add dynamic parameters websocket endpoint (#17165)
This commit is contained in:
+2
-3
@@ -9,9 +9,8 @@ import (
|
|||||||
"github.com/spf13/afero/tarfs"
|
"github.com/spf13/afero/tarfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// FromTarReader creates a read-only in-memory FS
|
||||||
func FromTarReader(r io.Reader) fs.FS {
|
func FromTarReader(r io.Reader) fs.FS {
|
||||||
tr := tar.NewReader(r)
|
tr := tar.NewReader(r)
|
||||||
tfs := tarfs.New(tr)
|
return afero.NewIOFS(tarfs.New(tr))
|
||||||
rofs := afero.NewReadOnlyFs(tfs)
|
|
||||||
return afero.NewIOFS(rofs)
|
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+30
-67
@@ -5764,6 +5764,35 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/templateversions/{templateversion}/dynamic-parameters": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"CoderSessionToken": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Templates"
|
||||||
|
],
|
||||||
|
"summary": "Open dynamic parameters WebSocket by template version",
|
||||||
|
"operationId": "open-dynamic-parameters-websocket-by-template-version",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"format": "uuid",
|
||||||
|
"description": "Template version ID",
|
||||||
|
"name": "templateversion",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"101": {
|
||||||
|
"description": "Switching Protocols"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/templateversions/{templateversion}/external-auth": {
|
"/templateversions/{templateversion}/external-auth": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -11332,73 +11361,7 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"codersdk.CreateTestAuditLogRequest": {
|
"codersdk.CreateTestAuditLogRequest": {
|
||||||
"type": "object",
|
"type": "object"
|
||||||
"properties": {
|
|
||||||
"action": {
|
|
||||||
"enum": [
|
|
||||||
"create",
|
|
||||||
"write",
|
|
||||||
"delete",
|
|
||||||
"start",
|
|
||||||
"stop"
|
|
||||||
],
|
|
||||||
"allOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/codersdk.AuditAction"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"additional_fields": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"build_reason": {
|
|
||||||
"enum": [
|
|
||||||
"autostart",
|
|
||||||
"autostop",
|
|
||||||
"initiator"
|
|
||||||
],
|
|
||||||
"allOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/codersdk.BuildReason"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"organization_id": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "uuid"
|
|
||||||
},
|
|
||||||
"request_id": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "uuid"
|
|
||||||
},
|
|
||||||
"resource_id": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "uuid"
|
|
||||||
},
|
|
||||||
"resource_type": {
|
|
||||||
"enum": [
|
|
||||||
"template",
|
|
||||||
"template_version",
|
|
||||||
"user",
|
|
||||||
"workspace",
|
|
||||||
"workspace_build",
|
|
||||||
"git_ssh_key",
|
|
||||||
"auditable_group"
|
|
||||||
],
|
|
||||||
"allOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/codersdk.ResourceType"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"time": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "date-time"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"codersdk.CreateTokenRequest": {
|
"codersdk.CreateTokenRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|||||||
Generated
+28
-57
@@ -5097,6 +5097,33 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/templateversions/{templateversion}/dynamic-parameters": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"CoderSessionToken": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": ["Templates"],
|
||||||
|
"summary": "Open dynamic parameters WebSocket by template version",
|
||||||
|
"operationId": "open-dynamic-parameters-websocket-by-template-version",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"format": "uuid",
|
||||||
|
"description": "Template version ID",
|
||||||
|
"name": "templateversion",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"101": {
|
||||||
|
"description": "Switching Protocols"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/templateversions/{templateversion}/external-auth": {
|
"/templateversions/{templateversion}/external-auth": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -10100,63 +10127,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"codersdk.CreateTestAuditLogRequest": {
|
"codersdk.CreateTestAuditLogRequest": {
|
||||||
"type": "object",
|
"type": "object"
|
||||||
"properties": {
|
|
||||||
"action": {
|
|
||||||
"enum": ["create", "write", "delete", "start", "stop"],
|
|
||||||
"allOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/codersdk.AuditAction"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"additional_fields": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"build_reason": {
|
|
||||||
"enum": ["autostart", "autostop", "initiator"],
|
|
||||||
"allOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/codersdk.BuildReason"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"organization_id": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "uuid"
|
|
||||||
},
|
|
||||||
"request_id": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "uuid"
|
|
||||||
},
|
|
||||||
"resource_id": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "uuid"
|
|
||||||
},
|
|
||||||
"resource_type": {
|
|
||||||
"enum": [
|
|
||||||
"template",
|
|
||||||
"template_version",
|
|
||||||
"user",
|
|
||||||
"workspace",
|
|
||||||
"workspace_build",
|
|
||||||
"git_ssh_key",
|
|
||||||
"auditable_group"
|
|
||||||
],
|
|
||||||
"allOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/codersdk.ResourceType"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"time": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "date-time"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"codersdk.CreateTokenRequest": {
|
"codersdk.CreateTokenRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import (
|
|||||||
|
|
||||||
"github.com/coder/coder/v2/coderd/cryptokeys"
|
"github.com/coder/coder/v2/coderd/cryptokeys"
|
||||||
"github.com/coder/coder/v2/coderd/entitlements"
|
"github.com/coder/coder/v2/coderd/entitlements"
|
||||||
|
"github.com/coder/coder/v2/coderd/files"
|
||||||
"github.com/coder/coder/v2/coderd/idpsync"
|
"github.com/coder/coder/v2/coderd/idpsync"
|
||||||
"github.com/coder/coder/v2/coderd/runtimeconfig"
|
"github.com/coder/coder/v2/coderd/runtimeconfig"
|
||||||
"github.com/coder/coder/v2/coderd/webpush"
|
"github.com/coder/coder/v2/coderd/webpush"
|
||||||
@@ -557,6 +558,7 @@ func New(options *Options) *API {
|
|||||||
TemplateScheduleStore: options.TemplateScheduleStore,
|
TemplateScheduleStore: options.TemplateScheduleStore,
|
||||||
UserQuietHoursScheduleStore: options.UserQuietHoursScheduleStore,
|
UserQuietHoursScheduleStore: options.UserQuietHoursScheduleStore,
|
||||||
AccessControlStore: options.AccessControlStore,
|
AccessControlStore: options.AccessControlStore,
|
||||||
|
FileCache: files.NewFromStore(options.Database),
|
||||||
Experiments: experiments,
|
Experiments: experiments,
|
||||||
WebpushDispatcher: options.WebPushDispatcher,
|
WebpushDispatcher: options.WebPushDispatcher,
|
||||||
healthCheckGroup: &singleflight.Group[string, *healthsdk.HealthcheckReport]{},
|
healthCheckGroup: &singleflight.Group[string, *healthsdk.HealthcheckReport]{},
|
||||||
@@ -1096,6 +1098,10 @@ func New(options *Options) *API {
|
|||||||
// The idea is to return an empty [], so that the coder CLI won't get blocked accidentally.
|
// The idea is to return an empty [], so that the coder CLI won't get blocked accidentally.
|
||||||
r.Get("/schema", templateVersionSchemaDeprecated)
|
r.Get("/schema", templateVersionSchemaDeprecated)
|
||||||
r.Get("/parameters", templateVersionParametersDeprecated)
|
r.Get("/parameters", templateVersionParametersDeprecated)
|
||||||
|
r.Group(func(r chi.Router) {
|
||||||
|
r.Use(httpmw.RequireExperiment(api.Experiments, codersdk.ExperimentDynamicParameters))
|
||||||
|
r.Get("/dynamic-parameters", api.templateVersionDynamicParameters)
|
||||||
|
})
|
||||||
r.Get("/rich-parameters", api.templateVersionRichParameters)
|
r.Get("/rich-parameters", api.templateVersionRichParameters)
|
||||||
r.Get("/external-auth", api.templateVersionExternalAuth)
|
r.Get("/external-auth", api.templateVersionExternalAuth)
|
||||||
r.Get("/variables", api.templateVersionVariables)
|
r.Get("/variables", api.templateVersionVariables)
|
||||||
@@ -1545,6 +1551,7 @@ type API struct {
|
|||||||
// passed to dbauthz.
|
// passed to dbauthz.
|
||||||
AccessControlStore *atomic.Pointer[dbauthz.AccessControlStore]
|
AccessControlStore *atomic.Pointer[dbauthz.AccessControlStore]
|
||||||
PortSharer atomic.Pointer[portsharing.PortSharer]
|
PortSharer atomic.Pointer[portsharing.PortSharer]
|
||||||
|
FileCache files.Cache
|
||||||
|
|
||||||
UpdatesProvider tailnet.WorkspaceUpdatesProvider
|
UpdatesProvider tailnet.WorkspaceUpdatesProvider
|
||||||
|
|
||||||
|
|||||||
+137
-4
@@ -35,10 +35,14 @@ import (
|
|||||||
"github.com/coder/coder/v2/coderd/tracing"
|
"github.com/coder/coder/v2/coderd/tracing"
|
||||||
"github.com/coder/coder/v2/coderd/util/ptr"
|
"github.com/coder/coder/v2/coderd/util/ptr"
|
||||||
"github.com/coder/coder/v2/codersdk"
|
"github.com/coder/coder/v2/codersdk"
|
||||||
|
"github.com/coder/coder/v2/codersdk/wsjson"
|
||||||
"github.com/coder/coder/v2/examples"
|
"github.com/coder/coder/v2/examples"
|
||||||
"github.com/coder/coder/v2/provisioner/terraform/tfparse"
|
"github.com/coder/coder/v2/provisioner/terraform/tfparse"
|
||||||
"github.com/coder/coder/v2/provisionersdk"
|
"github.com/coder/coder/v2/provisionersdk"
|
||||||
sdkproto "github.com/coder/coder/v2/provisionersdk/proto"
|
sdkproto "github.com/coder/coder/v2/provisionersdk/proto"
|
||||||
|
"github.com/coder/preview"
|
||||||
|
previewtypes "github.com/coder/preview/types"
|
||||||
|
"github.com/coder/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @Summary Get template version by ID
|
// @Summary Get template version by ID
|
||||||
@@ -266,6 +270,135 @@ func (api *API) patchCancelTemplateVersion(rw http.ResponseWriter, r *http.Reque
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Summary Open dynamic parameters WebSocket by template version
|
||||||
|
// @ID open-dynamic-parameters-websocket-by-template-version
|
||||||
|
// @Security CoderSessionToken
|
||||||
|
// @Tags Templates
|
||||||
|
// @Param templateversion path string true "Template version ID" format(uuid)
|
||||||
|
// @Success 101
|
||||||
|
// @Router /templateversions/{templateversion}/dynamic-parameters [get]
|
||||||
|
func (api *API) templateVersionDynamicParameters(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
templateVersion := httpmw.TemplateVersionParam(r)
|
||||||
|
|
||||||
|
// Check that the job has completed successfully
|
||||||
|
job, err := api.Database.GetProvisionerJobByID(ctx, templateVersion.JobID)
|
||||||
|
if httpapi.Is404Error(err) {
|
||||||
|
httpapi.ResourceNotFound(rw)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||||
|
Message: "Internal error fetching provisioner job.",
|
||||||
|
Detail: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !job.CompletedAt.Valid {
|
||||||
|
httpapi.Write(ctx, rw, http.StatusTooEarly, codersdk.Response{
|
||||||
|
Message: "Template version job has not finished",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Having the Terraform plan available for the evaluation engine is helpful
|
||||||
|
// for populating values from data blocks, but isn't strictly required. If
|
||||||
|
// we don't have a cached plan available, we just use an empty one instead.
|
||||||
|
plan := json.RawMessage("{}")
|
||||||
|
tf, err := api.Database.GetTemplateVersionTerraformValues(ctx, templateVersion.ID)
|
||||||
|
if err == nil {
|
||||||
|
plan = tf.CachedPlan
|
||||||
|
}
|
||||||
|
|
||||||
|
input := preview.Input{
|
||||||
|
PlanJSON: plan,
|
||||||
|
ParameterValues: map[string]string{},
|
||||||
|
// TODO: write a db query that fetches all of the data needed to fill out
|
||||||
|
// this owner value
|
||||||
|
Owner: previewtypes.WorkspaceOwner{
|
||||||
|
Groups: []string{"Everyone"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint:gocritic // We need to fetch the templates files for the Terraform
|
||||||
|
// evaluator, and the user likely does not have permission.
|
||||||
|
fileCtx := dbauthz.AsProvisionerd(ctx)
|
||||||
|
fileID, err := api.Database.GetFileIDByTemplateVersionID(fileCtx, templateVersion.ID)
|
||||||
|
if err != nil {
|
||||||
|
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||||
|
Message: "Internal error finding template version Terraform.",
|
||||||
|
Detail: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fs, err := api.FileCache.Acquire(fileCtx, fileID)
|
||||||
|
defer api.FileCache.Release(fileID)
|
||||||
|
if err != nil {
|
||||||
|
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
|
||||||
|
Message: "Internal error fetching template version Terraform.",
|
||||||
|
Detail: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := websocket.Accept(rw, r, nil)
|
||||||
|
if err != nil {
|
||||||
|
httpapi.Write(ctx, rw, http.StatusUpgradeRequired, codersdk.Response{
|
||||||
|
Message: "Failed to accept WebSocket.",
|
||||||
|
Detail: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
stream := wsjson.NewStream[codersdk.DynamicParametersRequest, codersdk.DynamicParametersResponse](conn, websocket.MessageText, websocket.MessageText, api.Logger)
|
||||||
|
|
||||||
|
// Send an initial form state, computed without any user input.
|
||||||
|
result, diagnostics := preview.Preview(ctx, input, fs)
|
||||||
|
response := codersdk.DynamicParametersResponse{
|
||||||
|
ID: -1,
|
||||||
|
Diagnostics: previewtypes.Diagnostics(diagnostics),
|
||||||
|
}
|
||||||
|
if result != nil {
|
||||||
|
response.Parameters = result.Parameters
|
||||||
|
}
|
||||||
|
err = stream.Send(response)
|
||||||
|
if err != nil {
|
||||||
|
stream.Drop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// As the user types into the form, reprocess the state using their input,
|
||||||
|
// and respond with updates.
|
||||||
|
updates := stream.Chan()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
stream.Close(websocket.StatusGoingAway)
|
||||||
|
return
|
||||||
|
case update, ok := <-updates:
|
||||||
|
if !ok {
|
||||||
|
// The connection has been closed, so there is no one to write to
|
||||||
|
return
|
||||||
|
}
|
||||||
|
input.ParameterValues = update.Inputs
|
||||||
|
result, diagnostics := preview.Preview(ctx, input, fs)
|
||||||
|
response := codersdk.DynamicParametersResponse{
|
||||||
|
ID: update.ID,
|
||||||
|
Diagnostics: previewtypes.Diagnostics(diagnostics),
|
||||||
|
}
|
||||||
|
if result != nil {
|
||||||
|
response.Parameters = result.Parameters
|
||||||
|
}
|
||||||
|
err = stream.Send(response)
|
||||||
|
if err != nil {
|
||||||
|
stream.Drop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// @Summary Get rich parameters by template version
|
// @Summary Get rich parameters by template version
|
||||||
// @ID get-rich-parameters-by-template-version
|
// @ID get-rich-parameters-by-template-version
|
||||||
// @Security CoderSessionToken
|
// @Security CoderSessionToken
|
||||||
@@ -287,8 +420,8 @@ func (api *API) templateVersionRichParameters(rw http.ResponseWriter, r *http.Re
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !job.CompletedAt.Valid {
|
if !job.CompletedAt.Valid {
|
||||||
httpapi.Write(ctx, rw, http.StatusForbidden, codersdk.Response{
|
httpapi.Write(ctx, rw, http.StatusTooEarly, codersdk.Response{
|
||||||
Message: "Job hasn't completed!",
|
Message: "Template version job has not finished",
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -428,7 +561,7 @@ func (api *API) templateVersionVariables(rw http.ResponseWriter, r *http.Request
|
|||||||
}
|
}
|
||||||
if !job.CompletedAt.Valid {
|
if !job.CompletedAt.Valid {
|
||||||
httpapi.Write(ctx, rw, http.StatusForbidden, codersdk.Response{
|
httpapi.Write(ctx, rw, http.StatusForbidden, codersdk.Response{
|
||||||
Message: "Job hasn't completed!",
|
Message: "Template version job has not finished",
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -483,7 +616,7 @@ func (api *API) postTemplateVersionDryRun(rw http.ResponseWriter, r *http.Reques
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !job.CompletedAt.Valid {
|
if !job.CompletedAt.Valid {
|
||||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
httpapi.Write(ctx, rw, http.StatusTooEarly, codersdk.Response{
|
||||||
Message: "Template version import job hasn't completed!",
|
Message: "Template version import job hasn't completed!",
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -27,6 +28,7 @@ import (
|
|||||||
"github.com/coder/coder/v2/provisionersdk"
|
"github.com/coder/coder/v2/provisionersdk"
|
||||||
"github.com/coder/coder/v2/provisionersdk/proto"
|
"github.com/coder/coder/v2/provisionersdk/proto"
|
||||||
"github.com/coder/coder/v2/testutil"
|
"github.com/coder/coder/v2/testutil"
|
||||||
|
"github.com/coder/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTemplateVersion(t *testing.T) {
|
func TestTemplateVersion(t *testing.T) {
|
||||||
@@ -1207,7 +1209,7 @@ func TestTemplateVersionDryRun(t *testing.T) {
|
|||||||
_, err := client.CreateTemplateVersionDryRun(ctx, version.ID, codersdk.CreateTemplateVersionDryRunRequest{})
|
_, err := client.CreateTemplateVersionDryRun(ctx, version.ID, codersdk.CreateTemplateVersionDryRunRequest{})
|
||||||
var apiErr *codersdk.Error
|
var apiErr *codersdk.Error
|
||||||
require.ErrorAs(t, err, &apiErr)
|
require.ErrorAs(t, err, &apiErr)
|
||||||
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
|
require.Equal(t, http.StatusTooEarly, apiErr.StatusCode())
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Cancel", func(t *testing.T) {
|
t.Run("Cancel", func(t *testing.T) {
|
||||||
@@ -2056,11 +2058,7 @@ func TestTemplateArchiveVersions(t *testing.T) {
|
|||||||
|
|
||||||
// Create some unused versions
|
// Create some unused versions
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
unused := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, &echo.Responses{
|
unused := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil, func(req *codersdk.CreateTemplateVersionRequest) {
|
||||||
Parse: echo.ParseComplete,
|
|
||||||
ProvisionPlan: echo.PlanComplete,
|
|
||||||
ProvisionApply: echo.ApplyComplete,
|
|
||||||
}, func(req *codersdk.CreateTemplateVersionRequest) {
|
|
||||||
req.TemplateID = template.ID
|
req.TemplateID = template.ID
|
||||||
})
|
})
|
||||||
expArchived = append(expArchived, unused.ID)
|
expArchived = append(expArchived, unused.ID)
|
||||||
@@ -2069,11 +2067,7 @@ func TestTemplateArchiveVersions(t *testing.T) {
|
|||||||
|
|
||||||
// Create some used template versions
|
// Create some used template versions
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
used := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, &echo.Responses{
|
used := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil, func(req *codersdk.CreateTemplateVersionRequest) {
|
||||||
Parse: echo.ParseComplete,
|
|
||||||
ProvisionPlan: echo.PlanComplete,
|
|
||||||
ProvisionApply: echo.ApplyComplete,
|
|
||||||
}, func(req *codersdk.CreateTemplateVersionRequest) {
|
|
||||||
req.TemplateID = template.ID
|
req.TemplateID = template.ID
|
||||||
})
|
})
|
||||||
coderdtest.AwaitTemplateVersionJobCompleted(t, client, used.ID)
|
coderdtest.AwaitTemplateVersionJobCompleted(t, client, used.ID)
|
||||||
@@ -2140,3 +2134,73 @@ func TestTemplateArchiveVersions(t *testing.T) {
|
|||||||
require.NoError(t, err, "fetch all versions")
|
require.NoError(t, err, "fetch all versions")
|
||||||
require.Len(t, remaining, totalVersions-len(expArchived)-len(allFailed)+1, "remaining versions")
|
require.Len(t, remaining, totalVersions-len(expArchived)-len(allFailed)+1, "remaining versions")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTemplateVersionDynamicParameters(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cfg := coderdtest.DeploymentValues(t)
|
||||||
|
cfg.Experiments = []string{string(codersdk.ExperimentDynamicParameters)}
|
||||||
|
ownerClient := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, DeploymentValues: cfg})
|
||||||
|
owner := coderdtest.CreateFirstUser(t, ownerClient)
|
||||||
|
templateAdmin, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.RoleTemplateAdmin())
|
||||||
|
|
||||||
|
dynamicParametersTerraformSource, err := os.ReadFile("testdata/dynamicparameters/groups/main.tf")
|
||||||
|
require.NoError(t, err)
|
||||||
|
dynamicParametersTerraformPlan, err := os.ReadFile("testdata/dynamicparameters/groups/plan.json")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
files := echo.WithExtraFiles(map[string][]byte{
|
||||||
|
"main.tf": dynamicParametersTerraformSource,
|
||||||
|
})
|
||||||
|
files.ProvisionPlan = []*proto.Response{{
|
||||||
|
Type: &proto.Response_Plan{
|
||||||
|
Plan: &proto.PlanComplete{
|
||||||
|
Plan: dynamicParametersTerraformPlan,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
version := coderdtest.CreateTemplateVersion(t, templateAdmin, owner.OrganizationID, files)
|
||||||
|
coderdtest.AwaitTemplateVersionJobCompleted(t, templateAdmin, version.ID)
|
||||||
|
_ = coderdtest.CreateTemplate(t, templateAdmin, owner.OrganizationID, version.ID)
|
||||||
|
|
||||||
|
ctx := testutil.Context(t, testutil.WaitShort)
|
||||||
|
stream, err := templateAdmin.TemplateVersionDynamicParameters(ctx, version.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer stream.Close(websocket.StatusGoingAway)
|
||||||
|
|
||||||
|
previews := stream.Chan()
|
||||||
|
|
||||||
|
// Should automatically send a form state with all defaulted/empty values
|
||||||
|
preview := testutil.RequireRecvCtx(ctx, t, previews)
|
||||||
|
require.Empty(t, preview.Diagnostics)
|
||||||
|
require.Equal(t, "group", preview.Parameters[0].Name)
|
||||||
|
require.True(t, preview.Parameters[0].Value.Valid())
|
||||||
|
require.Equal(t, "Everyone", preview.Parameters[0].Value.Value.AsString())
|
||||||
|
|
||||||
|
// Send a new value, and see it reflected
|
||||||
|
err = stream.Send(codersdk.DynamicParametersRequest{
|
||||||
|
ID: 1,
|
||||||
|
Inputs: map[string]string{"group": "Bloob"},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
preview = testutil.RequireRecvCtx(ctx, t, previews)
|
||||||
|
require.Equal(t, 1, preview.ID)
|
||||||
|
require.Empty(t, preview.Diagnostics)
|
||||||
|
require.Equal(t, "group", preview.Parameters[0].Name)
|
||||||
|
require.True(t, preview.Parameters[0].Value.Valid())
|
||||||
|
require.Equal(t, "Bloob", preview.Parameters[0].Value.Value.AsString())
|
||||||
|
|
||||||
|
// Back to default
|
||||||
|
err = stream.Send(codersdk.DynamicParametersRequest{
|
||||||
|
ID: 3,
|
||||||
|
Inputs: map[string]string{},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
preview = testutil.RequireRecvCtx(ctx, t, previews)
|
||||||
|
require.Equal(t, 3, preview.ID)
|
||||||
|
require.Empty(t, preview.Diagnostics)
|
||||||
|
require.Equal(t, "group", preview.Parameters[0].Name)
|
||||||
|
require.True(t, preview.Parameters[0].Value.Valid())
|
||||||
|
require.Equal(t, "Everyone", preview.Parameters[0].Value.Value.AsString())
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
coder = {
|
||||||
|
source = "coder/coder"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "coder_workspace_owner" "me" {}
|
||||||
|
|
||||||
|
output "groups" {
|
||||||
|
value = data.coder_workspace_owner.me.groups
|
||||||
|
}
|
||||||
|
|
||||||
|
data "coder_parameter" "group" {
|
||||||
|
name = "group"
|
||||||
|
default = try(data.coder_workspace_owner.me.groups[0], "")
|
||||||
|
dynamic "option" {
|
||||||
|
for_each = data.coder_workspace_owner.me.groups
|
||||||
|
content {
|
||||||
|
name = option.value
|
||||||
|
value = option.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
{
|
||||||
|
"terraform_version": "1.11.2",
|
||||||
|
"format_version": "1.2",
|
||||||
|
"checks": [],
|
||||||
|
"complete": true,
|
||||||
|
"timestamp": "2025-04-02T01:29:59Z",
|
||||||
|
"variables": {},
|
||||||
|
"prior_state": {
|
||||||
|
"values": {
|
||||||
|
"root_module": {
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"mode": "data",
|
||||||
|
"name": "me",
|
||||||
|
"type": "coder_workspace_owner",
|
||||||
|
"address": "data.coder_workspace_owner.me",
|
||||||
|
"provider_name": "registry.terraform.io/coder/coder",
|
||||||
|
"schema_version": 0,
|
||||||
|
"values": {
|
||||||
|
"id": "25e81ec3-0eb9-4ee3-8b6d-738b8552f7a9",
|
||||||
|
"name": "default",
|
||||||
|
"email": "default@example.com",
|
||||||
|
"groups": [],
|
||||||
|
"full_name": "default",
|
||||||
|
"login_type": null,
|
||||||
|
"rbac_roles": [],
|
||||||
|
"session_token": "",
|
||||||
|
"ssh_public_key": "",
|
||||||
|
"ssh_private_key": "",
|
||||||
|
"oidc_access_token": ""
|
||||||
|
},
|
||||||
|
"sensitive_values": {
|
||||||
|
"groups": [],
|
||||||
|
"rbac_roles": [],
|
||||||
|
"ssh_private_key": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"child_modules": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"format_version": "1.0",
|
||||||
|
"terraform_version": "1.11.2"
|
||||||
|
},
|
||||||
|
"configuration": {
|
||||||
|
"root_module": {
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"mode": "data",
|
||||||
|
"name": "me",
|
||||||
|
"type": "coder_workspace_owner",
|
||||||
|
"address": "data.coder_workspace_owner.me",
|
||||||
|
"schema_version": 0,
|
||||||
|
"provider_config_key": "coder"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"variables": {},
|
||||||
|
"module_calls": {}
|
||||||
|
},
|
||||||
|
"provider_config": {
|
||||||
|
"coder": {
|
||||||
|
"name": "coder",
|
||||||
|
"full_name": "registry.terraform.io/coder/coder"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"planned_values": {
|
||||||
|
"root_module": {
|
||||||
|
"resources": [],
|
||||||
|
"child_modules": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resource_changes": [],
|
||||||
|
"relevant_attributes": [
|
||||||
|
{
|
||||||
|
"resource": "data.coder_workspace_owner.me",
|
||||||
|
"attribute": ["full_name"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": "data.coder_workspace_owner.me",
|
||||||
|
"attribute": ["email"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": "data.coder_workspace_owner.me",
|
||||||
|
"attribute": ["id"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": "data.coder_workspace_owner.me",
|
||||||
|
"attribute": ["name"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/coder/coder/v2/coderd/tracing"
|
"github.com/coder/coder/v2/coderd/tracing"
|
||||||
|
"github.com/coder/websocket"
|
||||||
|
|
||||||
"cdr.dev/slog"
|
"cdr.dev/slog"
|
||||||
)
|
)
|
||||||
@@ -336,6 +337,38 @@ func (c *Client) Request(ctx context.Context, method, path string, body interfac
|
|||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) Dial(ctx context.Context, path string, opts *websocket.DialOptions) (*websocket.Conn, error) {
|
||||||
|
u, err := c.URL.Parse(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenHeader := c.SessionTokenHeader
|
||||||
|
if tokenHeader == "" {
|
||||||
|
tokenHeader = SessionTokenHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts == nil {
|
||||||
|
opts = &websocket.DialOptions{}
|
||||||
|
}
|
||||||
|
if opts.HTTPHeader == nil {
|
||||||
|
opts.HTTPHeader = http.Header{}
|
||||||
|
}
|
||||||
|
if opts.HTTPHeader.Get("tokenHeader") == "" {
|
||||||
|
opts.HTTPHeader.Set(tokenHeader, c.SessionToken())
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, resp, err := websocket.Dial(ctx, u.String(), opts)
|
||||||
|
if resp.Body != nil {
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ExpectJSONMime is a helper function that will assert the content type
|
// ExpectJSONMime is a helper function that will assert the content type
|
||||||
// of the response is application/json.
|
// of the response is application/json.
|
||||||
func ExpectJSONMime(res *http.Response) error {
|
func ExpectJSONMime(res *http.Response) error {
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"github.com/coder/coder/v2/codersdk/wsjson"
|
||||||
|
previewtypes "github.com/coder/preview/types"
|
||||||
|
"github.com/coder/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TemplateVersionWarning string
|
type TemplateVersionWarning string
|
||||||
@@ -123,6 +127,28 @@ func (c *Client) CancelTemplateVersion(ctx context.Context, version uuid.UUID) e
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DynamicParametersRequest struct {
|
||||||
|
// ID identifies the request. The response contains the same
|
||||||
|
// ID so that the client can match it to the request.
|
||||||
|
ID int `json:"id"`
|
||||||
|
Inputs map[string]string `json:"inputs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DynamicParametersResponse struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Diagnostics previewtypes.Diagnostics `json:"diagnostics"`
|
||||||
|
Parameters []previewtypes.Parameter `json:"parameters"`
|
||||||
|
// TODO: Workspace tags
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) TemplateVersionDynamicParameters(ctx context.Context, version uuid.UUID) (*wsjson.Stream[DynamicParametersResponse, DynamicParametersRequest], error) {
|
||||||
|
conn, err := c.Dial(ctx, fmt.Sprintf("/api/v2/templateversions/%s/dynamic-parameters", version), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return wsjson.NewStream[DynamicParametersResponse, DynamicParametersRequest](conn, websocket.MessageText, websocket.MessageText, c.Logger()), nil
|
||||||
|
}
|
||||||
|
|
||||||
// TemplateVersionParameters returns parameters a template version exposes.
|
// TemplateVersionParameters returns parameters a template version exposes.
|
||||||
func (c *Client) TemplateVersionRichParameters(ctx context.Context, version uuid.UUID) ([]TemplateVersionParameter, error) {
|
func (c *Client) TemplateVersionRichParameters(ctx context.Context, version uuid.UUID) ([]TemplateVersionParameter, error) {
|
||||||
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/templateversions/%s/rich-parameters", version), nil)
|
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/templateversions/%s/rich-parameters", version), nil)
|
||||||
|
|||||||
@@ -18,9 +18,12 @@ type Decoder[T any] struct {
|
|||||||
logger slog.Logger
|
logger slog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chan starts the decoder reading from the websocket and returns a channel for reading the
|
// Chan returns a `chan` that you can read incoming messages from. The returned
|
||||||
// resulting values. The chan T is closed if the underlying websocket is closed, or we encounter an
|
// `chan` will be closed when the WebSocket connection is closed. If there is an
|
||||||
// error. We also close the underlying websocket if we encounter an error reading or decoding.
|
// error reading from the WebSocket or decoding a value the WebSocket will be
|
||||||
|
// closed.
|
||||||
|
//
|
||||||
|
// Safety: Chan must only be called once. Successive calls will panic.
|
||||||
func (d *Decoder[T]) Chan() <-chan T {
|
func (d *Decoder[T]) Chan() <-chan T {
|
||||||
if !d.chanCalled.CompareAndSwap(false, true) {
|
if !d.chanCalled.CompareAndSwap(false, true) {
|
||||||
panic("chan called more than once")
|
panic("chan called more than once")
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package wsjson
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cdr.dev/slog"
|
||||||
|
"github.com/coder/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Stream is a two-way messaging interface over a WebSocket connection.
|
||||||
|
type Stream[R any, W any] struct {
|
||||||
|
conn *websocket.Conn
|
||||||
|
r *Decoder[R]
|
||||||
|
w *Encoder[W]
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStream[R any, W any](conn *websocket.Conn, readType, writeType websocket.MessageType, logger slog.Logger) *Stream[R, W] {
|
||||||
|
return &Stream[R, W]{
|
||||||
|
conn: conn,
|
||||||
|
r: NewDecoder[R](conn, readType, logger),
|
||||||
|
// We intentionally don't call `NewEncoder` because it calls `CloseRead`.
|
||||||
|
w: &Encoder[W]{conn: conn, typ: writeType},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chan returns a `chan` that you can read incoming messages from. The returned
|
||||||
|
// `chan` will be closed when the WebSocket connection is closed. If there is an
|
||||||
|
// error reading from the WebSocket or decoding a value the WebSocket will be
|
||||||
|
// closed.
|
||||||
|
//
|
||||||
|
// Safety: Chan must only be called once. Successive calls will panic.
|
||||||
|
func (s *Stream[R, W]) Chan() <-chan R {
|
||||||
|
return s.r.Chan()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream[R, W]) Send(v W) error {
|
||||||
|
return s.w.Encode(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream[R, W]) Close(c websocket.StatusCode) error {
|
||||||
|
return s.conn.Close(c, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream[R, W]) Drop() {
|
||||||
|
_ = s.conn.Close(websocket.StatusInternalError, "dropping connection")
|
||||||
|
}
|
||||||
Generated
+2
-42
@@ -1334,52 +1334,12 @@ This is required on creation to enable a user-flow of validating a template work
|
|||||||
## codersdk.CreateTestAuditLogRequest
|
## codersdk.CreateTestAuditLogRequest
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{}
|
||||||
"action": "create",
|
|
||||||
"additional_fields": [
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"build_reason": "autostart",
|
|
||||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
|
||||||
"request_id": "266ea41d-adf5-480b-af50-15b940c2b846",
|
|
||||||
"resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
|
|
||||||
"resource_type": "template",
|
|
||||||
"time": "2019-08-24T14:15:22Z"
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Properties
|
### Properties
|
||||||
|
|
||||||
| Name | Type | Required | Restrictions | Description |
|
None
|
||||||
|---------------------|------------------------------------------------|----------|--------------|-------------|
|
|
||||||
| `action` | [codersdk.AuditAction](#codersdkauditaction) | false | | |
|
|
||||||
| `additional_fields` | array of integer | false | | |
|
|
||||||
| `build_reason` | [codersdk.BuildReason](#codersdkbuildreason) | false | | |
|
|
||||||
| `organization_id` | string | false | | |
|
|
||||||
| `request_id` | string | false | | |
|
|
||||||
| `resource_id` | string | false | | |
|
|
||||||
| `resource_type` | [codersdk.ResourceType](#codersdkresourcetype) | false | | |
|
|
||||||
| `time` | string | false | | |
|
|
||||||
|
|
||||||
#### Enumerated Values
|
|
||||||
|
|
||||||
| Property | Value |
|
|
||||||
|-----------------|--------------------|
|
|
||||||
| `action` | `create` |
|
|
||||||
| `action` | `write` |
|
|
||||||
| `action` | `delete` |
|
|
||||||
| `action` | `start` |
|
|
||||||
| `action` | `stop` |
|
|
||||||
| `build_reason` | `autostart` |
|
|
||||||
| `build_reason` | `autostop` |
|
|
||||||
| `build_reason` | `initiator` |
|
|
||||||
| `resource_type` | `template` |
|
|
||||||
| `resource_type` | `template_version` |
|
|
||||||
| `resource_type` | `user` |
|
|
||||||
| `resource_type` | `workspace` |
|
|
||||||
| `resource_type` | `workspace_build` |
|
|
||||||
| `resource_type` | `git_ssh_key` |
|
|
||||||
| `resource_type` | `auditable_group` |
|
|
||||||
|
|
||||||
## codersdk.CreateTokenRequest
|
## codersdk.CreateTokenRequest
|
||||||
|
|
||||||
|
|||||||
Generated
+26
@@ -2541,6 +2541,32 @@ Status Code **200**
|
|||||||
|
|
||||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||||
|
|
||||||
|
## Open dynamic parameters WebSocket by template version
|
||||||
|
|
||||||
|
### Code samples
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Example request using curl
|
||||||
|
curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/dynamic-parameters \
|
||||||
|
-H 'Coder-Session-Token: API_KEY'
|
||||||
|
```
|
||||||
|
|
||||||
|
`GET /templateversions/{templateversion}/dynamic-parameters`
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
| Name | In | Type | Required | Description |
|
||||||
|
|-------------------|------|--------------|----------|---------------------|
|
||||||
|
| `templateversion` | path | string(uuid) | true | Template version ID |
|
||||||
|
|
||||||
|
### Responses
|
||||||
|
|
||||||
|
| Status | Meaning | Description | Schema |
|
||||||
|
|--------|--------------------------------------------------------------------------|---------------------|--------|
|
||||||
|
| 101 | [Switching Protocols](https://tools.ietf.org/html/rfc7231#section-6.2.2) | Switching Protocols | |
|
||||||
|
|
||||||
|
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||||
|
|
||||||
## Get external auth by template version
|
## Get external auth by template version
|
||||||
|
|
||||||
### Code samples
|
### Code samples
|
||||||
|
|||||||
@@ -64,6 +64,14 @@ replace github.com/lib/pq => github.com/coder/pq v1.10.5-0.20240813183442-0c420c
|
|||||||
// used in conjunction with agent-exec. See https://github.com/coder/coder/pull/15817
|
// used in conjunction with agent-exec. See https://github.com/coder/coder/pull/15817
|
||||||
replace github.com/charmbracelet/bubbletea => github.com/coder/bubbletea v1.2.2-0.20241212190825-007a1cdb2c41
|
replace github.com/charmbracelet/bubbletea => github.com/coder/bubbletea v1.2.2-0.20241212190825-007a1cdb2c41
|
||||||
|
|
||||||
|
// Trivy has some issues that we're floating patches for, and will hopefully
|
||||||
|
// be upstreamed eventually.
|
||||||
|
replace github.com/aquasecurity/trivy => github.com/emyrk/trivy v0.0.0-20250320190949-47caa1ac2d53
|
||||||
|
|
||||||
|
// afero/tarfs has a bug that breaks our usage. A PR has been submitted upstream.
|
||||||
|
// https://github.com/spf13/afero/pull/487
|
||||||
|
replace github.com/spf13/afero => github.com/aslilac/afero v0.0.0-20250403163713-f06e86036696
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cdr.dev/slog v1.6.2-0.20241112041820-0ec81e6e67bb
|
cdr.dev/slog v1.6.2-0.20241112041820-0ec81e6e67bb
|
||||||
cloud.google.com/go/compute/metadata v0.6.0
|
cloud.google.com/go/compute/metadata v0.6.0
|
||||||
@@ -74,10 +82,10 @@ require (
|
|||||||
github.com/aquasecurity/trivy-iac v0.8.0
|
github.com/aquasecurity/trivy-iac v0.8.0
|
||||||
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2
|
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2
|
||||||
github.com/awalterschulze/gographviz v2.0.3+incompatible
|
github.com/awalterschulze/gographviz v2.0.3+incompatible
|
||||||
github.com/aws/smithy-go v1.22.2
|
github.com/aws/smithy-go v1.22.3
|
||||||
github.com/bgentry/speakeasy v0.2.0
|
github.com/bgentry/speakeasy v0.2.0
|
||||||
github.com/bramvdbogaerde/go-scp v1.5.0
|
github.com/bramvdbogaerde/go-scp v1.5.0
|
||||||
github.com/briandowns/spinner v1.18.1
|
github.com/briandowns/spinner v1.23.0
|
||||||
github.com/cakturk/go-netstat v0.0.0-20200220111822-e5b49efee7a5
|
github.com/cakturk/go-netstat v0.0.0-20200220111822-e5b49efee7a5
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0
|
github.com/cenkalti/backoff/v4 v4.3.0
|
||||||
github.com/cespare/xxhash/v2 v2.3.0
|
github.com/cespare/xxhash/v2 v2.3.0
|
||||||
@@ -94,8 +102,8 @@ require (
|
|||||||
github.com/coder/quartz v0.1.2
|
github.com/coder/quartz v0.1.2
|
||||||
github.com/coder/retry v1.5.1
|
github.com/coder/retry v1.5.1
|
||||||
github.com/coder/serpent v0.10.0
|
github.com/coder/serpent v0.10.0
|
||||||
github.com/coder/terraform-provider-coder/v2 v2.3.1-0.20250407075538-3a2c18dab13e
|
github.com/coder/terraform-provider-coder/v2 v2.4.0-pre0
|
||||||
github.com/coder/websocket v1.8.12
|
github.com/coder/websocket v1.8.13
|
||||||
github.com/coder/wgtunnel v0.1.13-0.20240522110300-ade90dfb2da0
|
github.com/coder/wgtunnel v0.1.13-0.20240522110300-ade90dfb2da0
|
||||||
github.com/coreos/go-oidc/v3 v3.14.1
|
github.com/coreos/go-oidc/v3 v3.14.1
|
||||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
||||||
@@ -137,7 +145,7 @@ require (
|
|||||||
github.com/hashicorp/yamux v0.1.2
|
github.com/hashicorp/yamux v0.1.2
|
||||||
github.com/hinshun/vt10x v0.0.0-20220301184237-5011da428d02
|
github.com/hinshun/vt10x v0.0.0-20220301184237-5011da428d02
|
||||||
github.com/imulab/go-scim/pkg/v2 v2.2.0
|
github.com/imulab/go-scim/pkg/v2 v2.2.0
|
||||||
github.com/jedib0t/go-pretty/v6 v6.6.0
|
github.com/jedib0t/go-pretty/v6 v6.6.7
|
||||||
github.com/jmoiron/sqlx v1.4.0
|
github.com/jmoiron/sqlx v1.4.0
|
||||||
github.com/justinas/nosurf v1.1.1
|
github.com/justinas/nosurf v1.1.1
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||||
@@ -161,7 +169,7 @@ require (
|
|||||||
github.com/prometheus/client_golang v1.21.1
|
github.com/prometheus/client_golang v1.21.1
|
||||||
github.com/prometheus/client_model v0.6.1
|
github.com/prometheus/client_model v0.6.1
|
||||||
github.com/prometheus/common v0.63.0
|
github.com/prometheus/common v0.63.0
|
||||||
github.com/quasilyte/go-ruleguard/dsl v0.3.21
|
github.com/quasilyte/go-ruleguard/dsl v0.3.22
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/shirou/gopsutil/v4 v4.25.2
|
github.com/shirou/gopsutil/v4 v4.25.2
|
||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
|
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
|
||||||
@@ -189,7 +197,7 @@ require (
|
|||||||
go.uber.org/mock v0.5.0
|
go.uber.org/mock v0.5.0
|
||||||
go4.org/netipx v0.0.0-20230728180743-ad4cb58a6516
|
go4.org/netipx v0.0.0-20230728180743-ad4cb58a6516
|
||||||
golang.org/x/crypto v0.37.0
|
golang.org/x/crypto v0.37.0
|
||||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
|
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8
|
||||||
golang.org/x/mod v0.24.0
|
golang.org/x/mod v0.24.0
|
||||||
golang.org/x/net v0.38.0
|
golang.org/x/net v0.38.0
|
||||||
golang.org/x/oauth2 v0.29.0
|
golang.org/x/oauth2 v0.29.0
|
||||||
@@ -216,7 +224,7 @@ require (
|
|||||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||||
cloud.google.com/go/logging v1.12.0 // indirect
|
cloud.google.com/go/logging v1.12.0 // indirect
|
||||||
cloud.google.com/go/longrunning v0.6.2 // indirect
|
cloud.google.com/go/longrunning v0.6.2 // indirect
|
||||||
dario.cat/mergo v1.0.0 // indirect
|
dario.cat/mergo v1.0.1 // indirect
|
||||||
filippo.io/edwards25519 v1.1.0 // indirect
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||||
github.com/DataDog/appsec-internal-go v1.9.0 // indirect
|
github.com/DataDog/appsec-internal-go v1.9.0 // indirect
|
||||||
@@ -237,7 +245,7 @@ require (
|
|||||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||||
github.com/ProtonMail/go-crypto v1.1.3 // indirect
|
github.com/ProtonMail/go-crypto v1.1.5 // indirect
|
||||||
github.com/agext/levenshtein v1.2.3 // indirect
|
github.com/agext/levenshtein v1.2.3 // indirect
|
||||||
github.com/agnivade/levenshtein v1.2.1 // indirect
|
github.com/agnivade/levenshtein v1.2.1 // indirect
|
||||||
github.com/akutz/memconn v0.1.0 // indirect
|
github.com/akutz/memconn v0.1.0 // indirect
|
||||||
@@ -248,37 +256,37 @@ require (
|
|||||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||||
github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c // indirect
|
github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c // indirect
|
||||||
github.com/atotto/clipboard v0.1.4 // indirect
|
github.com/atotto/clipboard v0.1.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2 v1.36.0
|
github.com/aws/aws-sdk-go-v2 v1.36.3
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.29.1
|
github.com/aws/aws-sdk-go-v2/config v1.29.9
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.54 // indirect
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.62 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.24 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.1
|
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.1
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.28 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.28 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.9 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssm v1.52.4 // indirect
|
github.com/aws/aws-sdk-go-v2/service/ssm v1.52.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.11 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.10 // indirect
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.9 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 // indirect
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
github.com/aymerick/douceur v0.2.0 // indirect
|
github.com/aymerick/douceur v0.2.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bep/godartsass/v2 v2.3.2 // indirect
|
github.com/bep/godartsass/v2 v2.3.2 // indirect
|
||||||
github.com/bep/golibsass v1.2.0 // indirect
|
github.com/bep/golibsass v1.2.0 // indirect
|
||||||
github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
|
github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect
|
||||||
github.com/charmbracelet/x/ansi v0.8.0 // indirect
|
github.com/charmbracelet/x/ansi v0.8.0 // indirect
|
||||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||||
github.com/chromedp/sysutil v1.1.0 // indirect
|
github.com/chromedp/sysutil v1.1.0 // indirect
|
||||||
github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575 // indirect
|
github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575 // indirect
|
||||||
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||||
github.com/cloudflare/circl v1.3.7 // indirect
|
github.com/cloudflare/circl v1.6.0 // indirect
|
||||||
github.com/containerd/continuity v0.4.5 // indirect
|
github.com/containerd/continuity v0.4.5 // indirect
|
||||||
github.com/coreos/go-iptables v0.6.0 // indirect
|
github.com/coreos/go-iptables v0.6.0 // indirect
|
||||||
github.com/dlclark/regexp2 v1.11.4 // indirect
|
github.com/dlclark/regexp2 v1.11.4 // indirect
|
||||||
github.com/docker/cli v27.4.1+incompatible // indirect
|
github.com/docker/cli v27.5.0+incompatible // indirect
|
||||||
github.com/docker/docker v27.2.0+incompatible // indirect
|
github.com/docker/docker v27.5.0+incompatible // indirect
|
||||||
github.com/docker/go-connections v0.5.0 // indirect
|
github.com/docker/go-connections v0.5.0 // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd // indirect
|
github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd // indirect
|
||||||
@@ -288,16 +296,16 @@ require (
|
|||||||
github.com/elastic/go-windows v1.0.0 // indirect
|
github.com/elastic/go-windows v1.0.0 // indirect
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
|
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||||
github.com/go-chi/hostrouter v0.2.0 // indirect
|
github.com/go-chi/hostrouter v0.2.0 // indirect
|
||||||
github.com/go-ini/ini v1.67.0 // indirect
|
github.com/go-ini/ini v1.67.0 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.20.2 // indirect
|
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||||
github.com/go-openapi/spec v0.20.6 // indirect
|
github.com/go-openapi/spec v0.21.0 // indirect
|
||||||
github.com/go-openapi/swag v0.22.8 // indirect
|
github.com/go-openapi/swag v0.23.0 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
||||||
@@ -311,12 +319,12 @@ require (
|
|||||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/gohugoio/hashstructure v0.3.0 // indirect
|
github.com/gohugoio/hashstructure v0.3.0 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/google/btree v1.1.2 // indirect
|
github.com/google/btree v1.1.2 // indirect
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/google/nftables v0.2.0 // indirect
|
github.com/google/nftables v0.2.0 // indirect
|
||||||
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect
|
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 // indirect
|
||||||
github.com/google/s2a-go v0.1.9 // indirect
|
github.com/google/s2a-go v0.1.9 // indirect
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||||
@@ -334,7 +342,7 @@ require (
|
|||||||
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
|
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
|
||||||
github.com/hashicorp/go-terraform-address v0.0.0-20240523040243-ccea9d309e0c
|
github.com/hashicorp/go-terraform-address v0.0.0-20240523040243-ccea9d309e0c
|
||||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
|
github.com/hashicorp/hcl v1.0.1-vault-7 // indirect
|
||||||
github.com/hashicorp/hcl/v2 v2.23.0
|
github.com/hashicorp/hcl/v2 v2.23.0
|
||||||
github.com/hashicorp/logutils v1.0.0 // indirect
|
github.com/hashicorp/logutils v1.0.0 // indirect
|
||||||
github.com/hashicorp/terraform-plugin-go v0.26.0 // indirect
|
github.com/hashicorp/terraform-plugin-go v0.26.0 // indirect
|
||||||
@@ -343,7 +351,7 @@ require (
|
|||||||
github.com/hdevalence/ed25519consensus v0.1.0 // indirect
|
github.com/hdevalence/ed25519consensus v0.1.0 // indirect
|
||||||
github.com/illarion/gonotify v1.0.1 // indirect
|
github.com/illarion/gonotify v1.0.1 // indirect
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 // indirect
|
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 // indirect
|
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 // indirect
|
||||||
github.com/jsimonetti/rtnetlink v1.3.5 // indirect
|
github.com/jsimonetti/rtnetlink v1.3.5 // indirect
|
||||||
@@ -353,9 +361,9 @@ require (
|
|||||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c // indirect
|
github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
github.com/mdlayher/genetlink v1.3.2 // indirect
|
github.com/mdlayher/genetlink v1.3.2 // indirect
|
||||||
@@ -391,7 +399,7 @@ require (
|
|||||||
github.com/pion/transport/v3 v3.0.7 // indirect
|
github.com/pion/transport/v3 v3.0.7 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c // indirect
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||||
github.com/prometheus/procfs v0.15.1 // indirect
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
||||||
github.com/riandyrn/otelchi v0.5.1 // indirect
|
github.com/riandyrn/otelchi v0.5.1 // indirect
|
||||||
@@ -399,7 +407,7 @@ require (
|
|||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||||
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
|
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
|
||||||
github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect
|
github.com/secure-systems-lab/go-securesystemslib v0.9.0 // indirect
|
||||||
github.com/shirou/gopsutil/v3 v3.24.4 // indirect
|
github.com/shirou/gopsutil/v3 v3.24.4 // indirect
|
||||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
@@ -420,8 +428,8 @@ require (
|
|||||||
github.com/tidwall/match v1.1.1 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
github.com/tidwall/pretty v1.2.1 // indirect
|
github.com/tidwall/pretty v1.2.1 // indirect
|
||||||
github.com/tinylib/msgp v1.2.1 // indirect
|
github.com/tinylib/msgp v1.2.1 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
github.com/tklauser/go-sysconf v0.3.13 // indirect
|
||||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
github.com/tklauser/numcpus v0.7.0 // indirect
|
||||||
github.com/u-root/uio v0.0.0-20240209044354-b3d14b93376a // indirect
|
github.com/u-root/uio v0.0.0-20240209044354-b3d14b93376a // indirect
|
||||||
github.com/vishvananda/netlink v1.2.1-beta.2 // indirect
|
github.com/vishvananda/netlink v1.2.1-beta.2 // indirect
|
||||||
github.com/vishvananda/netns v0.0.4 // indirect
|
github.com/vishvananda/netns v0.0.4 // indirect
|
||||||
@@ -479,11 +487,40 @@ require (
|
|||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
require github.com/mark3labs/mcp-go v0.17.0
|
require (
|
||||||
|
github.com/coder/preview v0.0.0-20250409162646-62939c63c71a
|
||||||
|
github.com/mark3labs/mcp-go v0.17.0
|
||||||
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
cel.dev/expr v0.19.1 // indirect
|
||||||
|
cloud.google.com/go v0.116.0 // indirect
|
||||||
|
cloud.google.com/go/iam v1.2.2 // indirect
|
||||||
|
cloud.google.com/go/monitoring v1.21.2 // indirect
|
||||||
|
cloud.google.com/go/storage v1.49.0 // indirect
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 // indirect
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 // indirect
|
||||||
|
github.com/aquasecurity/go-version v0.0.1 // indirect
|
||||||
|
github.com/aquasecurity/trivy v0.58.2 // indirect
|
||||||
|
github.com/aws/aws-sdk-go v1.55.6 // indirect
|
||||||
|
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||||
|
github.com/cncf/xds/go v0.0.0-20241223141626-cff3c89139a3 // indirect
|
||||||
|
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
|
||||||
|
github.com/hashicorp/go-getter v1.7.8 // indirect
|
||||||
|
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||||
|
github.com/liamg/memoryfs v1.6.0 // indirect
|
||||||
github.com/moby/sys/user v0.3.0 // indirect
|
github.com/moby/sys/user v0.3.0 // indirect
|
||||||
|
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||||
|
github.com/samber/lo v1.49.1 // indirect
|
||||||
|
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||||
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
|
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
|
||||||
github.com/zeebo/xxh3 v1.0.2 // indirect
|
github.com/zeebo/xxh3 v1.0.2 // indirect
|
||||||
|
go.opencensus.io v0.24.0 // indirect
|
||||||
|
go.opentelemetry.io/contrib/detectors/gcp v1.34.0 // indirect
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
|
||||||
|
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -211,6 +211,8 @@ type Responses struct {
|
|||||||
// transition responses. They are prioritized over the generic responses.
|
// transition responses. They are prioritized over the generic responses.
|
||||||
ProvisionApplyMap map[proto.WorkspaceTransition][]*proto.Response
|
ProvisionApplyMap map[proto.WorkspaceTransition][]*proto.Response
|
||||||
ProvisionPlanMap map[proto.WorkspaceTransition][]*proto.Response
|
ProvisionPlanMap map[proto.WorkspaceTransition][]*proto.Response
|
||||||
|
|
||||||
|
ExtraFiles map[string][]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tar returns a tar archive of responses to provisioner operations.
|
// Tar returns a tar archive of responses to provisioner operations.
|
||||||
@@ -226,8 +228,12 @@ func TarWithOptions(ctx context.Context, logger slog.Logger, responses *Response
|
|||||||
|
|
||||||
if responses == nil {
|
if responses == nil {
|
||||||
responses = &Responses{
|
responses = &Responses{
|
||||||
ParseComplete, ApplyComplete, PlanComplete,
|
Parse: ParseComplete,
|
||||||
nil, nil,
|
ProvisionApply: ApplyComplete,
|
||||||
|
ProvisionPlan: PlanComplete,
|
||||||
|
ProvisionApplyMap: nil,
|
||||||
|
ProvisionPlanMap: nil,
|
||||||
|
ExtraFiles: nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if responses.ProvisionPlan == nil {
|
if responses.ProvisionPlan == nil {
|
||||||
@@ -327,6 +333,25 @@ func TarWithOptions(ctx context.Context, logger slog.Logger, responses *Response
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for name, content := range responses.ExtraFiles {
|
||||||
|
logger.Debug(ctx, "extra file", slog.F("name", name))
|
||||||
|
|
||||||
|
err := writer.WriteHeader(&tar.Header{
|
||||||
|
Name: name,
|
||||||
|
Size: int64(len(content)),
|
||||||
|
Mode: 0o644,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := writer.Write(content)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug(context.Background(), "extra file written", slog.F("name", name), slog.F("bytes_written", n))
|
||||||
|
}
|
||||||
// `writer.Close()` function flushes the writer buffer, and adds extra padding to create a legal tarball.
|
// `writer.Close()` function flushes the writer buffer, and adds extra padding to create a legal tarball.
|
||||||
err := writer.Close()
|
err := writer.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -347,3 +372,12 @@ func WithResources(resources []*proto.Resource) *Responses {
|
|||||||
}}}},
|
}}}},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithExtraFiles(extraFiles map[string][]byte) *Responses {
|
||||||
|
return &Responses{
|
||||||
|
Parse: ParseComplete,
|
||||||
|
ProvisionApply: ApplyComplete,
|
||||||
|
ProvisionPlan: PlanComplete,
|
||||||
|
ExtraFiles: extraFiles,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,8 +32,10 @@ func main() {
|
|||||||
// Serpent has some types referenced in the codersdk.
|
// Serpent has some types referenced in the codersdk.
|
||||||
// We want the referenced types generated.
|
// We want the referenced types generated.
|
||||||
referencePackages := map[string]string{
|
referencePackages := map[string]string{
|
||||||
"github.com/coder/serpent": "Serpent",
|
"github.com/coder/preview": "",
|
||||||
"tailscale.com/derp": "",
|
"github.com/coder/serpent": "Serpent",
|
||||||
|
"github.com/hashicorp/hcl/v2": "Hcl",
|
||||||
|
"tailscale.com/derp": "",
|
||||||
// Conflicting name "DERPRegion"
|
// Conflicting name "DERPRegion"
|
||||||
"tailscale.com/tailcfg": "Tail",
|
"tailscale.com/tailcfg": "Tail",
|
||||||
"tailscale.com/net/netcheck": "Netcheck",
|
"tailscale.com/net/netcheck": "Netcheck",
|
||||||
@@ -88,7 +90,8 @@ func TypeMappings(gen *guts.GoParser) error {
|
|||||||
gen.IncludeCustomDeclaration(map[string]guts.TypeOverride{
|
gen.IncludeCustomDeclaration(map[string]guts.TypeOverride{
|
||||||
"github.com/coder/coder/v2/codersdk.NullTime": config.OverrideNullable(config.OverrideLiteral(bindings.KeywordString)),
|
"github.com/coder/coder/v2/codersdk.NullTime": config.OverrideNullable(config.OverrideLiteral(bindings.KeywordString)),
|
||||||
// opt.Bool can return 'null' if unset
|
// opt.Bool can return 'null' if unset
|
||||||
"tailscale.com/types/opt.Bool": config.OverrideNullable(config.OverrideLiteral(bindings.KeywordBoolean)),
|
"tailscale.com/types/opt.Bool": config.OverrideNullable(config.OverrideLiteral(bindings.KeywordBoolean)),
|
||||||
|
"github.com/hashicorp/hcl/v2.Expression": config.OverrideLiteral(bindings.KeywordUnknown),
|
||||||
})
|
})
|
||||||
|
|
||||||
err := gen.IncludeCustom(map[string]string{
|
err := gen.IncludeCustom(map[string]string{
|
||||||
|
|||||||
Generated
+53
@@ -706,6 +706,21 @@ export const DisplayApps: DisplayApp[] = [
|
|||||||
"web_terminal",
|
"web_terminal",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// From codersdk/templateversions.go
|
||||||
|
export interface DynamicParametersRequest {
|
||||||
|
readonly id: number;
|
||||||
|
readonly inputs: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// From codersdk/templateversions.go
|
||||||
|
export interface DynamicParametersResponse {
|
||||||
|
readonly id: number;
|
||||||
|
// this is likely an enum in an external package "github.com/coder/preview/types.Diagnostics"
|
||||||
|
readonly diagnostics: readonly (HclDiagnostic | null)[];
|
||||||
|
// external type "github.com/coder/preview/types.Parameter", to include this type the package must be explicitly included in the parsing
|
||||||
|
readonly parameters: readonly unknown[];
|
||||||
|
}
|
||||||
|
|
||||||
// From codersdk/externalauth.go
|
// From codersdk/externalauth.go
|
||||||
export type EnhancedExternalAuthProvider =
|
export type EnhancedExternalAuthProvider =
|
||||||
| "azure-devops"
|
| "azure-devops"
|
||||||
@@ -982,6 +997,44 @@ export interface HTTPCookieConfig {
|
|||||||
readonly same_site?: string;
|
readonly same_site?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From hcl/diagnostic.go
|
||||||
|
export interface HclDiagnostic {
|
||||||
|
readonly Severity: HclDiagnosticSeverity;
|
||||||
|
readonly Summary: string;
|
||||||
|
readonly Detail: string;
|
||||||
|
readonly Subject: HclRange | null;
|
||||||
|
readonly Context: HclRange | null;
|
||||||
|
readonly Expression: unknown;
|
||||||
|
readonly EvalContext: HclEvalContext | null;
|
||||||
|
// empty interface{} type, falling back to unknown
|
||||||
|
readonly Extra: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
// From hcl/diagnostic.go
|
||||||
|
export type HclDiagnosticSeverity = number;
|
||||||
|
|
||||||
|
// From hcl/eval_context.go
|
||||||
|
export interface HclEvalContext {
|
||||||
|
// external type "github.com/zclconf/go-cty/cty.Value", to include this type the package must be explicitly included in the parsing
|
||||||
|
readonly Variables: Record<string, unknown>;
|
||||||
|
// external type "github.com/zclconf/go-cty/cty/function.Function", to include this type the package must be explicitly included in the parsing
|
||||||
|
readonly Functions: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// From hcl/pos.go
|
||||||
|
export interface HclPos {
|
||||||
|
readonly Line: number;
|
||||||
|
readonly Column: number;
|
||||||
|
readonly Byte: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// From hcl/pos.go
|
||||||
|
export interface HclRange {
|
||||||
|
readonly Filename: string;
|
||||||
|
readonly Start: HclPos;
|
||||||
|
readonly End: HclPos;
|
||||||
|
}
|
||||||
|
|
||||||
// From health/model.go
|
// From health/model.go
|
||||||
export type HealthCode =
|
export type HealthCode =
|
||||||
| "EACS03"
|
| "EACS03"
|
||||||
|
|||||||
Reference in New Issue
Block a user