mirror of
https://github.com/coder/coder.git
synced 2025-07-13 21:36:50 +00:00
Merge branch 'jjs/presets-api' into jjs/presets
This commit is contained in:
2
Makefile
2
Makefile
@ -809,7 +809,7 @@ provisioner/terraform/testdata/version:
|
||||
.PHONY: provisioner/terraform/testdata/version
|
||||
|
||||
test:
|
||||
$(GIT_FLAGS) gotestsum --format standard-quiet -- -v -short -count=1 ./...
|
||||
$(GIT_FLAGS) gotestsum --format standard-quiet -- -v -short -count=1 ./... $(if $(RUN),-run $(RUN))
|
||||
.PHONY: test
|
||||
|
||||
test-cli:
|
||||
|
@ -140,3 +140,10 @@ type Lister interface {
|
||||
// This should include running and stopped containers.
|
||||
List(ctx context.Context) (codersdk.WorkspaceAgentListContainersResponse, error)
|
||||
}
|
||||
|
||||
// NoopLister is a Lister interface that never returns any containers.
|
||||
type NoopLister struct{}
|
||||
|
||||
func (NoopLister) List(_ context.Context) (codersdk.WorkspaceAgentListContainersResponse, error) {
|
||||
return codersdk.WorkspaceAgentListContainersResponse{}, nil
|
||||
}
|
||||
|
19
cli/agent.go
19
cli/agent.go
@ -25,6 +25,7 @@ import (
|
||||
"cdr.dev/slog/sloggers/slogjson"
|
||||
"cdr.dev/slog/sloggers/slogstackdriver"
|
||||
"github.com/coder/coder/v2/agent"
|
||||
"github.com/coder/coder/v2/agent/agentcontainers"
|
||||
"github.com/coder/coder/v2/agent/agentexec"
|
||||
"github.com/coder/coder/v2/agent/agentssh"
|
||||
"github.com/coder/coder/v2/agent/reaper"
|
||||
@ -52,6 +53,7 @@ func (r *RootCmd) workspaceAgent() *serpent.Command {
|
||||
blockFileTransfer bool
|
||||
agentHeaderCommand string
|
||||
agentHeader []string
|
||||
devcontainersEnabled bool
|
||||
)
|
||||
cmd := &serpent.Command{
|
||||
Use: "agent",
|
||||
@ -314,6 +316,15 @@ func (r *RootCmd) workspaceAgent() *serpent.Command {
|
||||
return xerrors.Errorf("create agent execer: %w", err)
|
||||
}
|
||||
|
||||
var containerLister agentcontainers.Lister
|
||||
if !devcontainersEnabled {
|
||||
logger.Info(ctx, "agent devcontainer detection not enabled")
|
||||
containerLister = &agentcontainers.NoopLister{}
|
||||
} else {
|
||||
logger.Info(ctx, "agent devcontainer detection enabled")
|
||||
containerLister = agentcontainers.NewDocker(execer)
|
||||
}
|
||||
|
||||
agnt := agent.New(agent.Options{
|
||||
Client: client,
|
||||
Logger: logger,
|
||||
@ -339,6 +350,7 @@ func (r *RootCmd) workspaceAgent() *serpent.Command {
|
||||
PrometheusRegistry: prometheusRegistry,
|
||||
BlockFileTransfer: blockFileTransfer,
|
||||
Execer: execer,
|
||||
ContainerLister: containerLister,
|
||||
})
|
||||
|
||||
promHandler := agent.PrometheusMetricsHandler(prometheusRegistry, logger)
|
||||
@ -461,6 +473,13 @@ func (r *RootCmd) workspaceAgent() *serpent.Command {
|
||||
Description: fmt.Sprintf("Block file transfer using known applications: %s.", strings.Join(agentssh.BlockedFileTransferCommands, ",")),
|
||||
Value: serpent.BoolOf(&blockFileTransfer),
|
||||
},
|
||||
{
|
||||
Flag: "devcontainers-enable",
|
||||
Default: "false",
|
||||
Env: "CODER_AGENT_DEVCONTAINERS_ENABLE",
|
||||
Description: "Allow the agent to automatically detect running devcontainers.",
|
||||
Value: serpent.BoolOf(&devcontainersEnabled),
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
|
3
cli/testdata/coder_agent_--help.golden
vendored
3
cli/testdata/coder_agent_--help.golden
vendored
@ -33,6 +33,9 @@ OPTIONS:
|
||||
--debug-address string, $CODER_AGENT_DEBUG_ADDRESS (default: 127.0.0.1:2113)
|
||||
The bind address to serve a debug HTTP server.
|
||||
|
||||
--devcontainers-enable bool, $CODER_AGENT_DEVCONTAINERS_ENABLE (default: false)
|
||||
Allow the agent to automatically detect running devcontainers.
|
||||
|
||||
--log-dir string, $CODER_AGENT_LOG_DIR (default: /tmp)
|
||||
Specify the location for the agent log files.
|
||||
|
||||
|
@ -11,7 +11,7 @@ OPTIONS:
|
||||
-O, --org string, $CODER_ORGANIZATION
|
||||
Select which organization (uuid or name) to use.
|
||||
|
||||
-c, --column [id|organization id|created at|last seen at|name|version|api version|tags|key name|status|current job id|current job status|previous job id|previous job status|organization] (default: name,organization,status,key name,created at,last seen at,version,tags)
|
||||
-c, --column [id|organization id|created at|last seen at|name|version|api version|tags|key name|status|current job id|current job status|current job template name|current job template icon|current job template display name|previous job id|previous job status|previous job template name|previous job template icon|previous job template display name|organization] (default: name,organization,status,key name,created at,last seen at,version,tags)
|
||||
Columns to display in table output.
|
||||
|
||||
-o, --output table|json (default: table)
|
||||
|
@ -20,7 +20,10 @@
|
||||
"current_job": null,
|
||||
"previous_job": {
|
||||
"id": "======[workspace build job ID]======",
|
||||
"status": "succeeded"
|
||||
"status": "succeeded",
|
||||
"template_name": "",
|
||||
"template_icon": "",
|
||||
"template_display_name": ""
|
||||
},
|
||||
"organization_name": "Coder"
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
coder v0.0.0-devel
|
||||
|
||||
USAGE:
|
||||
coder tokens remove <name>
|
||||
coder tokens remove <name|id|token>
|
||||
|
||||
Delete a token
|
||||
|
||||
|
@ -3,6 +3,7 @@ package cli
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
@ -223,7 +224,7 @@ func (r *RootCmd) listTokens() *serpent.Command {
|
||||
func (r *RootCmd) removeToken() *serpent.Command {
|
||||
client := new(codersdk.Client)
|
||||
cmd := &serpent.Command{
|
||||
Use: "remove <name>",
|
||||
Use: "remove <name|id|token>",
|
||||
Aliases: []string{"delete"},
|
||||
Short: "Delete a token",
|
||||
Middleware: serpent.Chain(
|
||||
@ -233,7 +234,12 @@ func (r *RootCmd) removeToken() *serpent.Command {
|
||||
Handler: func(inv *serpent.Invocation) error {
|
||||
token, err := client.APIKeyByName(inv.Context(), codersdk.Me, inv.Args[0])
|
||||
if err != nil {
|
||||
return xerrors.Errorf("fetch api key by name %s: %w", inv.Args[0], err)
|
||||
// If it's a token, we need to extract the ID
|
||||
maybeID := strings.Split(inv.Args[0], "-")[0]
|
||||
token, err = client.APIKeyByID(inv.Context(), codersdk.Me, maybeID)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("fetch api key by name or id: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = client.DeleteAPIKey(inv.Context(), codersdk.Me, token.ID)
|
||||
|
@ -93,7 +93,7 @@ func TestTokens(t *testing.T) {
|
||||
require.Contains(t, res, secondTokenID)
|
||||
|
||||
// Test creating a token for third user from second user's (non-admin) session
|
||||
inv, root = clitest.New(t, "tokens", "create", "--name", "token-two", "--user", thirdUser.ID.String())
|
||||
inv, root = clitest.New(t, "tokens", "create", "--name", "failed-token", "--user", thirdUser.ID.String())
|
||||
clitest.SetupConfig(t, secondUserClient, root)
|
||||
buf = new(bytes.Buffer)
|
||||
inv.Stdout = buf
|
||||
@ -113,6 +113,7 @@ func TestTokens(t *testing.T) {
|
||||
require.Len(t, tokens, 1)
|
||||
require.Equal(t, id, tokens[0].ID)
|
||||
|
||||
// Delete by name
|
||||
inv, root = clitest.New(t, "tokens", "rm", "token-one")
|
||||
clitest.SetupConfig(t, client, root)
|
||||
buf = new(bytes.Buffer)
|
||||
@ -122,4 +123,37 @@ func TestTokens(t *testing.T) {
|
||||
res = buf.String()
|
||||
require.NotEmpty(t, res)
|
||||
require.Contains(t, res, "deleted")
|
||||
|
||||
// Delete by ID
|
||||
inv, root = clitest.New(t, "tokens", "rm", secondTokenID)
|
||||
clitest.SetupConfig(t, client, root)
|
||||
buf = new(bytes.Buffer)
|
||||
inv.Stdout = buf
|
||||
err = inv.WithContext(ctx).Run()
|
||||
require.NoError(t, err)
|
||||
res = buf.String()
|
||||
require.NotEmpty(t, res)
|
||||
require.Contains(t, res, "deleted")
|
||||
|
||||
// Create third token
|
||||
inv, root = clitest.New(t, "tokens", "create", "--name", "token-three")
|
||||
clitest.SetupConfig(t, client, root)
|
||||
buf = new(bytes.Buffer)
|
||||
inv.Stdout = buf
|
||||
err = inv.WithContext(ctx).Run()
|
||||
require.NoError(t, err)
|
||||
res = buf.String()
|
||||
require.NotEmpty(t, res)
|
||||
fourthToken := res
|
||||
|
||||
// Delete by token
|
||||
inv, root = clitest.New(t, "tokens", "rm", fourthToken)
|
||||
clitest.SetupConfig(t, client, root)
|
||||
buf = new(bytes.Buffer)
|
||||
inv.Stdout = buf
|
||||
err = inv.WithContext(ctx).Run()
|
||||
require.NoError(t, err)
|
||||
res = buf.String()
|
||||
require.NotEmpty(t, res)
|
||||
require.Contains(t, res, "deleted")
|
||||
}
|
||||
|
56
coderd/apidoc/docs.go
generated
56
coderd/apidoc/docs.go
generated
@ -5643,44 +5643,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/templateversions/{templateversion}/presets/parameters": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Templates"
|
||||
],
|
||||
"summary": "Get template version preset parameters",
|
||||
"operationId": "get-template-version-preset-parameters",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Template version ID",
|
||||
"name": "templateversion",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/codersdk.PresetParameter"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/templateversions/{templateversion}/resources": {
|
||||
"get": {
|
||||
"security": [
|
||||
@ -13051,6 +13013,12 @@ const docTemplate = `{
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"parameters": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/codersdk.PresetParameter"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -13060,9 +13028,6 @@ const docTemplate = `{
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"presetID": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
}
|
||||
@ -13207,6 +13172,15 @@ const docTemplate = `{
|
||||
"$ref": "#/definitions/codersdk.ProvisionerJobStatus"
|
||||
}
|
||||
]
|
||||
},
|
||||
"template_display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"template_icon": {
|
||||
"type": "string"
|
||||
},
|
||||
"template_name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
52
coderd/apidoc/swagger.json
generated
52
coderd/apidoc/swagger.json
generated
@ -4985,40 +4985,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/templateversions/{templateversion}/presets/parameters": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["Templates"],
|
||||
"summary": "Get template version preset parameters",
|
||||
"operationId": "get-template-version-preset-parameters",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Template version ID",
|
||||
"name": "templateversion",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/codersdk.PresetParameter"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/templateversions/{templateversion}/resources": {
|
||||
"get": {
|
||||
"security": [
|
||||
@ -11776,6 +11742,12 @@
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"parameters": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/codersdk.PresetParameter"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -11785,9 +11757,6 @@
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"presetID": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
}
|
||||
@ -11928,6 +11897,15 @@
|
||||
"$ref": "#/definitions/codersdk.ProvisionerJobStatus"
|
||||
}
|
||||
]
|
||||
},
|
||||
"template_display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"template_icon": {
|
||||
"type": "string"
|
||||
},
|
||||
"template_name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -788,6 +788,7 @@ func New(options *Options) *API {
|
||||
httpmw.AttachRequestID,
|
||||
httpmw.ExtractRealIP(api.RealIPConfig),
|
||||
httpmw.Logger(api.Logger),
|
||||
singleSlashMW,
|
||||
rolestore.CustomRoleMW,
|
||||
prometheusMW,
|
||||
// Build-Version is helpful for debugging.
|
||||
@ -1057,10 +1058,7 @@ func New(options *Options) *API {
|
||||
r.Get("/rich-parameters", api.templateVersionRichParameters)
|
||||
r.Get("/external-auth", api.templateVersionExternalAuth)
|
||||
r.Get("/variables", api.templateVersionVariables)
|
||||
r.Route("/presets", func(r chi.Router) {
|
||||
r.Get("/", api.templateVersionPresets)
|
||||
r.Get("/parameters", api.templateVersionPresetParameters)
|
||||
})
|
||||
r.Get("/presets", api.templateVersionPresets)
|
||||
r.Get("/resources", api.templateVersionResources)
|
||||
r.Get("/logs", api.templateVersionLogs)
|
||||
r.Route("/dry-run", func(r chi.Router) {
|
||||
@ -1735,3 +1733,31 @@ func ReadExperiments(log slog.Logger, raw []string) codersdk.Experiments {
|
||||
}
|
||||
return exps
|
||||
}
|
||||
|
||||
var multipleSlashesRe = regexp.MustCompile(`/+`)
|
||||
|
||||
func singleSlashMW(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
var path string
|
||||
rctx := chi.RouteContext(r.Context())
|
||||
if rctx != nil && rctx.RoutePath != "" {
|
||||
path = rctx.RoutePath
|
||||
} else {
|
||||
path = r.URL.Path
|
||||
}
|
||||
|
||||
// Normalize multiple slashes to a single slash
|
||||
newPath := multipleSlashesRe.ReplaceAllString(path, "/")
|
||||
|
||||
// Apply the cleaned path
|
||||
// The approach is consistent with: https://github.com/go-chi/chi/blob/e846b8304c769c4f1a51c9de06bebfaa4576bd88/middleware/strip.go#L24-L28
|
||||
if rctx != nil {
|
||||
rctx.RoutePath = newPath
|
||||
} else {
|
||||
r.URL.Path = newPath
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
|
69
coderd/coderd_internal_test.go
Normal file
69
coderd/coderd_internal_test.go
Normal file
@ -0,0 +1,69 @@
|
||||
package coderd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStripSlashesMW(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
inputPath string
|
||||
wantPath string
|
||||
}{
|
||||
{"No changes", "/api/v1/buildinfo", "/api/v1/buildinfo"},
|
||||
{"Double slashes", "/api//v2//buildinfo", "/api/v2/buildinfo"},
|
||||
{"Triple slashes", "/api///v2///buildinfo", "/api/v2/buildinfo"},
|
||||
{"Leading slashes", "///api/v2/buildinfo", "/api/v2/buildinfo"},
|
||||
{"Root path", "/", "/"},
|
||||
{"Double slashes root", "//", "/"},
|
||||
{"Only slashes", "/////", "/"},
|
||||
}
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
|
||||
t.Run("chi/"+tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
req := httptest.NewRequest("GET", tt.inputPath, nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
// given
|
||||
rctx := chi.NewRouteContext()
|
||||
rctx.RoutePath = tt.inputPath
|
||||
req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx))
|
||||
|
||||
// when
|
||||
singleSlashMW(handler).ServeHTTP(rec, req)
|
||||
updatedCtx := chi.RouteContext(req.Context())
|
||||
|
||||
// then
|
||||
assert.Equal(t, tt.inputPath, req.URL.Path)
|
||||
assert.Equal(t, tt.wantPath, updatedCtx.RoutePath)
|
||||
})
|
||||
|
||||
t.Run("stdlib/"+tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
req := httptest.NewRequest("GET", tt.inputPath, nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
// when
|
||||
singleSlashMW(handler).ServeHTTP(rec, req)
|
||||
|
||||
// then
|
||||
assert.Equal(t, tt.wantPath, req.URL.Path)
|
||||
assert.Nil(t, chi.RouteContext(req.Context()))
|
||||
})
|
||||
}
|
||||
}
|
@ -886,7 +886,6 @@ func (s *MethodTestSuite) TestOrganization() {
|
||||
JobID: job.ID,
|
||||
})
|
||||
insertPresetParams := database.InsertPresetParams{
|
||||
ID: uuid.New(),
|
||||
TemplateVersionID: workspaceBuild.TemplateVersionID,
|
||||
Name: "test",
|
||||
}
|
||||
@ -3817,13 +3816,11 @@ func (s *MethodTestSuite) TestSystemFunctions() {
|
||||
CreatedBy: user.ID,
|
||||
})
|
||||
preset, err := db.InsertPreset(ctx, database.InsertPresetParams{
|
||||
ID: uuid.New(),
|
||||
TemplateVersionID: templateVersion.ID,
|
||||
Name: "test",
|
||||
})
|
||||
require.NoError(s.T(), err)
|
||||
_, err = db.InsertPresetParameters(ctx, database.InsertPresetParametersParams{
|
||||
ID: uuid.New(),
|
||||
TemplateVersionPresetID: preset.ID,
|
||||
Names: []string{"test"},
|
||||
Values: []string{"test"},
|
||||
|
@ -8149,6 +8149,7 @@ func (q *FakeQuerier) InsertPreset(_ context.Context, arg database.InsertPresetP
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
//nolint:gosimple // arg needs to keep its type for interface reasons and that type is not appropriate for preset below.
|
||||
preset := database.TemplateVersionPreset{
|
||||
ID: uuid.New(),
|
||||
TemplateVersionID: arg.TemplateVersionID,
|
||||
|
4
coderd/database/dump.sql
generated
4
coderd/database/dump.sql
generated
@ -1266,14 +1266,14 @@ COMMENT ON COLUMN template_version_parameters.display_order IS 'Specifies the or
|
||||
COMMENT ON COLUMN template_version_parameters.ephemeral IS 'The value of an ephemeral parameter will not be preserved between consecutive workspace builds.';
|
||||
|
||||
CREATE TABLE template_version_preset_parameters (
|
||||
id uuid NOT NULL,
|
||||
id uuid DEFAULT gen_random_uuid() NOT NULL,
|
||||
template_version_preset_id uuid NOT NULL,
|
||||
name text NOT NULL,
|
||||
value text NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE template_version_presets (
|
||||
id uuid NOT NULL,
|
||||
id uuid DEFAULT gen_random_uuid() NOT NULL,
|
||||
template_version_id uuid NOT NULL,
|
||||
name text NOT NULL,
|
||||
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
|
@ -0,0 +1,5 @@
|
||||
ALTER TABLE template_version_presets
|
||||
ALTER COLUMN id DROP DEFAULT;
|
||||
|
||||
ALTER TABLE template_version_preset_parameters
|
||||
ALTER COLUMN id DROP DEFAULT;
|
@ -0,0 +1,5 @@
|
||||
ALTER TABLE template_version_presets
|
||||
ALTER COLUMN id SET DEFAULT gen_random_uuid();
|
||||
|
||||
ALTER TABLE template_version_preset_parameters
|
||||
ALTER COLUMN id SET DEFAULT gen_random_uuid();
|
@ -5494,25 +5494,19 @@ func (q *sqlQuerier) GetPresetsByTemplateVersionID(ctx context.Context, template
|
||||
|
||||
const insertPreset = `-- name: InsertPreset :one
|
||||
INSERT INTO
|
||||
template_version_presets (id, template_version_id, name, created_at)
|
||||
template_version_presets (template_version_id, name, created_at)
|
||||
VALUES
|
||||
($1, $2, $3, $4) RETURNING id, template_version_id, name, created_at
|
||||
($1, $2, $3) RETURNING id, template_version_id, name, created_at
|
||||
`
|
||||
|
||||
type InsertPresetParams struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
TemplateVersionID uuid.UUID `db:"template_version_id" json:"template_version_id"`
|
||||
Name string `db:"name" json:"name"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) InsertPreset(ctx context.Context, arg InsertPresetParams) (TemplateVersionPreset, error) {
|
||||
row := q.db.QueryRowContext(ctx, insertPreset,
|
||||
arg.ID,
|
||||
arg.TemplateVersionID,
|
||||
arg.Name,
|
||||
arg.CreatedAt,
|
||||
)
|
||||
row := q.db.QueryRowContext(ctx, insertPreset, arg.TemplateVersionID, arg.Name, arg.CreatedAt)
|
||||
var i TemplateVersionPreset
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
@ -5525,29 +5519,22 @@ func (q *sqlQuerier) InsertPreset(ctx context.Context, arg InsertPresetParams) (
|
||||
|
||||
const insertPresetParameters = `-- name: InsertPresetParameters :many
|
||||
INSERT INTO
|
||||
template_version_preset_parameters (id, template_version_preset_id, name, value)
|
||||
template_version_preset_parameters (template_version_preset_id, name, value)
|
||||
SELECT
|
||||
$1,
|
||||
$2,
|
||||
unnest($3 :: TEXT[]),
|
||||
unnest($4 :: TEXT[])
|
||||
unnest($2 :: TEXT[]),
|
||||
unnest($3 :: TEXT[])
|
||||
RETURNING id, template_version_preset_id, name, value
|
||||
`
|
||||
|
||||
type InsertPresetParametersParams struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
TemplateVersionPresetID uuid.UUID `db:"template_version_preset_id" json:"template_version_preset_id"`
|
||||
Names []string `db:"names" json:"names"`
|
||||
Values []string `db:"values" json:"values"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) InsertPresetParameters(ctx context.Context, arg InsertPresetParametersParams) ([]TemplateVersionPresetParameter, error) {
|
||||
rows, err := q.db.QueryContext(ctx, insertPresetParameters,
|
||||
arg.ID,
|
||||
arg.TemplateVersionPresetID,
|
||||
pq.Array(arg.Names),
|
||||
pq.Array(arg.Values),
|
||||
)
|
||||
rows, err := q.db.QueryContext(ctx, insertPresetParameters, arg.TemplateVersionPresetID, pq.Array(arg.Names), pq.Array(arg.Values))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -5755,7 +5742,10 @@ SELECT
|
||||
current_job.id AS current_job_id,
|
||||
current_job.job_status AS current_job_status,
|
||||
previous_job.id AS previous_job_id,
|
||||
previous_job.job_status AS previous_job_status
|
||||
previous_job.job_status AS previous_job_status,
|
||||
COALESCE(tmpl.name, ''::text) AS current_job_template_name,
|
||||
COALESCE(tmpl.display_name, ''::text) AS current_job_template_display_name,
|
||||
COALESCE(tmpl.icon, ''::text) AS current_job_template_icon
|
||||
FROM
|
||||
provisioner_daemons pd
|
||||
JOIN
|
||||
@ -5780,6 +5770,10 @@ LEFT JOIN
|
||||
LIMIT 1
|
||||
)
|
||||
)
|
||||
LEFT JOIN
|
||||
template_versions version ON version.id = (current_job.input->>'template_version_id')::uuid
|
||||
LEFT JOIN
|
||||
templates tmpl ON tmpl.id = version.template_id
|
||||
WHERE
|
||||
pd.organization_id = $2::uuid
|
||||
AND (COALESCE(array_length($3::uuid[], 1), 0) = 0 OR pd.id = ANY($3::uuid[]))
|
||||
@ -5803,6 +5797,9 @@ type GetProvisionerDaemonsWithStatusByOrganizationRow struct {
|
||||
CurrentJobStatus NullProvisionerJobStatus `db:"current_job_status" json:"current_job_status"`
|
||||
PreviousJobID uuid.NullUUID `db:"previous_job_id" json:"previous_job_id"`
|
||||
PreviousJobStatus NullProvisionerJobStatus `db:"previous_job_status" json:"previous_job_status"`
|
||||
CurrentJobTemplateName string `db:"current_job_template_name" json:"current_job_template_name"`
|
||||
CurrentJobTemplateDisplayName string `db:"current_job_template_display_name" json:"current_job_template_display_name"`
|
||||
CurrentJobTemplateIcon string `db:"current_job_template_icon" json:"current_job_template_icon"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) GetProvisionerDaemonsWithStatusByOrganization(ctx context.Context, arg GetProvisionerDaemonsWithStatusByOrganizationParams) ([]GetProvisionerDaemonsWithStatusByOrganizationRow, error) {
|
||||
@ -5837,6 +5834,9 @@ func (q *sqlQuerier) GetProvisionerDaemonsWithStatusByOrganization(ctx context.C
|
||||
&i.CurrentJobStatus,
|
||||
&i.PreviousJobID,
|
||||
&i.PreviousJobStatus,
|
||||
&i.CurrentJobTemplateName,
|
||||
&i.CurrentJobTemplateDisplayName,
|
||||
&i.CurrentJobTemplateIcon,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1,14 +1,13 @@
|
||||
-- name: InsertPreset :one
|
||||
INSERT INTO
|
||||
template_version_presets (id, template_version_id, name, created_at)
|
||||
template_version_presets (template_version_id, name, created_at)
|
||||
VALUES
|
||||
(@id, @template_version_id, @name, @created_at) RETURNING *;
|
||||
(@template_version_id, @name, @created_at) RETURNING *;
|
||||
|
||||
-- name: InsertPresetParameters :many
|
||||
INSERT INTO
|
||||
template_version_preset_parameters (id, template_version_preset_id, name, value)
|
||||
template_version_preset_parameters (template_version_preset_id, name, value)
|
||||
SELECT
|
||||
@id,
|
||||
@template_version_preset_id,
|
||||
unnest(@names :: TEXT[]),
|
||||
unnest(@values :: TEXT[])
|
||||
|
@ -44,7 +44,10 @@ SELECT
|
||||
current_job.id AS current_job_id,
|
||||
current_job.job_status AS current_job_status,
|
||||
previous_job.id AS previous_job_id,
|
||||
previous_job.job_status AS previous_job_status
|
||||
previous_job.job_status AS previous_job_status,
|
||||
COALESCE(tmpl.name, ''::text) AS current_job_template_name,
|
||||
COALESCE(tmpl.display_name, ''::text) AS current_job_template_display_name,
|
||||
COALESCE(tmpl.icon, ''::text) AS current_job_template_icon
|
||||
FROM
|
||||
provisioner_daemons pd
|
||||
JOIN
|
||||
@ -69,6 +72,10 @@ LEFT JOIN
|
||||
LIMIT 1
|
||||
)
|
||||
)
|
||||
LEFT JOIN
|
||||
template_versions version ON version.id = (current_job.input->>'template_version_id')::uuid
|
||||
LEFT JOIN
|
||||
templates tmpl ON tmpl.id = version.template_id
|
||||
WHERE
|
||||
pd.organization_id = @organization_id::uuid
|
||||
AND (COALESCE(array_length(@ids::uuid[], 1), 0) = 0 OR pd.id = ANY(@ids::uuid[]))
|
||||
|
@ -29,32 +29,6 @@ func (api *API) templateVersionPresets(rw http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
var res []codersdk.Preset
|
||||
for _, preset := range presets {
|
||||
res = append(res, codersdk.Preset{
|
||||
ID: preset.ID,
|
||||
Name: preset.Name,
|
||||
})
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, res)
|
||||
}
|
||||
|
||||
// @Summary Get template version preset parameters
|
||||
// @ID get-template-version-preset-parameters
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param templateversion path string true "Template version ID" format(uuid)
|
||||
// @Success 200 {array} codersdk.PresetParameter
|
||||
// @Router /templateversions/{templateversion}/presets/parameters [get]
|
||||
func (api *API) templateVersionPresetParameters(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
templateVersion := httpmw.TemplateVersionParam(r)
|
||||
|
||||
// TODO (sasswart): Test case: what if a user tries to read presets or preset parameters from a different org?
|
||||
// TODO (sasswart): Do a prelim auth check here.
|
||||
|
||||
presetParams, err := api.Database.GetPresetParametersByTemplateVersionID(ctx, templateVersion.ID)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
@ -64,14 +38,20 @@ func (api *API) templateVersionPresetParameters(rw http.ResponseWriter, r *http.
|
||||
return
|
||||
}
|
||||
|
||||
var res []codersdk.PresetParameter
|
||||
var res []codersdk.Preset
|
||||
for _, preset := range presets {
|
||||
sdkPreset := codersdk.Preset{
|
||||
ID: preset.ID,
|
||||
Name: preset.Name,
|
||||
}
|
||||
for _, presetParam := range presetParams {
|
||||
res = append(res, codersdk.PresetParameter{
|
||||
PresetID: presetParam.TemplateVersionPresetID,
|
||||
sdkPreset.Parameters = append(sdkPreset.Parameters, codersdk.PresetParameter{
|
||||
Name: presetParam.Name,
|
||||
Value: presetParam.Value,
|
||||
})
|
||||
}
|
||||
res = append(res, sdkPreset)
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, res)
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package coderd_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -11,12 +10,29 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/database/dbauthz"
|
||||
"github.com/coder/coder/v2/coderd/httpmw"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/testutil"
|
||||
)
|
||||
|
||||
func TestTemplateVersionPresets(t *testing.T) {
|
||||
// TODO (sasswart): Test case: what if a user tries to read presets or preset parameters from a different org?
|
||||
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
givenPreset := codersdk.Preset{
|
||||
Name: "My Preset",
|
||||
Parameters: []codersdk.PresetParameter{
|
||||
{
|
||||
Name: "preset_param1",
|
||||
Value: "A1B2C3",
|
||||
},
|
||||
{
|
||||
Name: "preset_param2",
|
||||
Value: "D4E5F6",
|
||||
},
|
||||
},
|
||||
}
|
||||
ctx := testutil.Context(t, testutil.WaitShort)
|
||||
|
||||
client, db := coderdtest.NewWithDatabase(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
@ -25,15 +41,22 @@ func TestTemplateVersionPresets(t *testing.T) {
|
||||
// nolint:gocritic // This is a test
|
||||
provisionerCtx := dbauthz.AsProvisionerd(ctx)
|
||||
|
||||
preset, err := db.InsertPreset(provisionerCtx, database.InsertPresetParams{
|
||||
Name: "My Preset",
|
||||
dbPreset, err := db.InsertPreset(provisionerCtx, database.InsertPresetParams{
|
||||
Name: givenPreset.Name,
|
||||
TemplateVersionID: version.ID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
var presetParameterNames []string
|
||||
var presetParameterValues []string
|
||||
for _, presetParameter := range givenPreset.Parameters {
|
||||
presetParameterNames = append(presetParameterNames, presetParameter.Name)
|
||||
presetParameterValues = append(presetParameterValues, presetParameter.Value)
|
||||
}
|
||||
_, err = db.InsertPresetParameters(provisionerCtx, database.InsertPresetParametersParams{
|
||||
TemplateVersionPresetID: preset.ID,
|
||||
Names: []string{"preset_param1", "preset_param2"},
|
||||
Values: []string{"A1B2C3", "D4E5F6"},
|
||||
TemplateVersionPresetID: dbPreset.ID,
|
||||
Names: presetParameterNames,
|
||||
Values: presetParameterValues,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -41,16 +64,13 @@ func TestTemplateVersionPresets(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
userCtx := dbauthz.As(ctx, userSubject)
|
||||
|
||||
presets, err := client.TemplateVersionPresets(userCtx, version.ID)
|
||||
gotPresets, err := client.TemplateVersionPresets(userCtx, version.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(presets))
|
||||
require.Equal(t, "My Preset", presets[0].Name)
|
||||
|
||||
presetParams, err := client.TemplateVersionPresetParameters(userCtx, version.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(presetParams))
|
||||
require.Equal(t, "preset_param1", presetParams[0].Name)
|
||||
require.Equal(t, "A1B2C3", presetParams[0].Value)
|
||||
require.Equal(t, "preset_param2", presetParams[1].Name)
|
||||
require.Equal(t, "D4E5F6", presetParams[1].Value)
|
||||
require.Equal(t, 1, len(gotPresets))
|
||||
require.Equal(t, givenPreset.Name, gotPresets[0].Name)
|
||||
|
||||
for _, presetParameter := range givenPreset.Parameters {
|
||||
require.Contains(t, gotPresets[0].Parameters, presetParameter)
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,9 @@ func (api *API) provisionerDaemons(rw http.ResponseWriter, r *http.Request) {
|
||||
currentJob = &codersdk.ProvisionerDaemonJob{
|
||||
ID: dbDaemon.CurrentJobID.UUID,
|
||||
Status: codersdk.ProvisionerJobStatus(dbDaemon.CurrentJobStatus.ProvisionerJobStatus),
|
||||
TemplateName: dbDaemon.CurrentJobTemplateName,
|
||||
TemplateIcon: dbDaemon.CurrentJobTemplateIcon,
|
||||
TemplateDisplayName: dbDaemon.CurrentJobTemplateDisplayName,
|
||||
}
|
||||
}
|
||||
if dbDaemon.PreviousJobID.Valid {
|
||||
|
@ -1830,7 +1830,6 @@ func InsertWorkspacePresetsAndParameters(ctx context.Context, logger slog.Logger
|
||||
func InsertWorkspacePresetAndParameters(ctx context.Context, db database.Store, templateVersionID uuid.UUID, protoPreset *sdkproto.Preset, t time.Time) error {
|
||||
err := db.InTx(func(tx database.Store) error {
|
||||
dbPreset, err := tx.InsertPreset(ctx, database.InsertPresetParams{
|
||||
ID: uuid.New(),
|
||||
TemplateVersionID: templateVersionID,
|
||||
Name: protoPreset.Name,
|
||||
CreatedAt: t,
|
||||
@ -1846,7 +1845,6 @@ func InsertWorkspacePresetAndParameters(ctx context.Context, db database.Store,
|
||||
presetParameterValues = append(presetParameterValues, parameter.Value)
|
||||
}
|
||||
_, err = tx.InsertPresetParameters(ctx, database.InsertPresetParametersParams{
|
||||
ID: uuid.New(),
|
||||
TemplateVersionPresetID: dbPreset.ID,
|
||||
Names: presetParameterNames,
|
||||
Values: presetParameterValues,
|
||||
|
@ -13,10 +13,10 @@ import (
|
||||
type Preset struct {
|
||||
ID uuid.UUID
|
||||
Name string
|
||||
Parameters []PresetParameter
|
||||
}
|
||||
|
||||
type PresetParameter struct {
|
||||
PresetID uuid.UUID
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
@ -34,17 +34,3 @@ func (c *Client) TemplateVersionPresets(ctx context.Context, templateVersionID u
|
||||
var presets []Preset
|
||||
return presets, json.NewDecoder(res.Body).Decode(&presets)
|
||||
}
|
||||
|
||||
// TemplateVersionPresetParameters returns the parameters associated with the given presets.
|
||||
func (c *Client) TemplateVersionPresetParameters(ctx context.Context, templateVersionID uuid.UUID) ([]PresetParameter, error) {
|
||||
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/templateversions/%s/presets/parameters", templateVersionID), nil)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("do request: %w", err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, ReadBodyAsError(res)
|
||||
}
|
||||
var parameters []PresetParameter
|
||||
return parameters, json.NewDecoder(res.Body).Decode(¶meters)
|
||||
}
|
||||
|
@ -71,6 +71,9 @@ type ProvisionerDaemon struct {
|
||||
type ProvisionerDaemonJob struct {
|
||||
ID uuid.UUID `json:"id" format:"uuid" table:"id"`
|
||||
Status ProvisionerJobStatus `json:"status" enums:"pending,running,succeeded,canceling,canceled,failed" table:"status"`
|
||||
TemplateName string `json:"template_name" table:"template name"`
|
||||
TemplateIcon string `json:"template_icon" table:"template icon"`
|
||||
TemplateDisplayName string `json:"template_display_name" table:"template display name"`
|
||||
}
|
||||
|
||||
// MatchedProvisioners represents the number of provisioner daemons
|
||||
|
10
docs/reference/api/debug.md
generated
10
docs/reference/api/debug.md
generated
@ -309,7 +309,10 @@ curl -X GET http://coder-server:8080/api/v2/debug/health \
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"current_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"key_id": "1e779c8a-6786-4c89-b7c3-a6666f5fd6b5",
|
||||
@ -319,7 +322,10 @@ curl -X GET http://coder-server:8080/api/v2/debug/health \
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"previous_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"provisioners": [
|
||||
"string"
|
||||
|
15
docs/reference/api/enterprise.md
generated
15
docs/reference/api/enterprise.md
generated
@ -1629,7 +1629,10 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisi
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"current_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"key_id": "1e779c8a-6786-4c89-b7c3-a6666f5fd6b5",
|
||||
@ -1639,7 +1642,10 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisi
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"previous_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"provisioners": [
|
||||
"string"
|
||||
@ -1677,7 +1683,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisi
|
||||
Status Code **200**
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|----------------------|--------------------------------------------------------------------------------|----------|--------------|------------------|
|
||||
|-----------------------------|--------------------------------------------------------------------------------|----------|--------------|------------------|
|
||||
| `[array item]` | array | false | | |
|
||||
| `» daemons` | array | false | | |
|
||||
| `»» api_version` | string | false | | |
|
||||
@ -1685,6 +1691,9 @@ Status Code **200**
|
||||
| `»» current_job` | [codersdk.ProvisionerDaemonJob](schemas.md#codersdkprovisionerdaemonjob) | false | | |
|
||||
| `»»» id` | string(uuid) | false | | |
|
||||
| `»»» status` | [codersdk.ProvisionerJobStatus](schemas.md#codersdkprovisionerjobstatus) | false | | |
|
||||
| `»»» template_display_name` | string | false | | |
|
||||
| `»»» template_icon` | string | false | | |
|
||||
| `»»» template_name` | string | false | | |
|
||||
| `»» id` | string(uuid) | false | | |
|
||||
| `»» key_id` | string(uuid) | false | | |
|
||||
| `»» key_name` | string | false | | Optional fields. |
|
||||
|
15
docs/reference/api/provisioning.md
generated
15
docs/reference/api/provisioning.md
generated
@ -31,7 +31,10 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisi
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"current_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"key_id": "1e779c8a-6786-4c89-b7c3-a6666f5fd6b5",
|
||||
@ -41,7 +44,10 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisi
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"previous_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"provisioners": [
|
||||
"string"
|
||||
@ -67,13 +73,16 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisi
|
||||
Status Code **200**
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|---------------------|--------------------------------------------------------------------------------|----------|--------------|------------------|
|
||||
|----------------------------|--------------------------------------------------------------------------------|----------|--------------|------------------|
|
||||
| `[array item]` | array | false | | |
|
||||
| `» api_version` | string | false | | |
|
||||
| `» created_at` | string(date-time) | false | | |
|
||||
| `» current_job` | [codersdk.ProvisionerDaemonJob](schemas.md#codersdkprovisionerdaemonjob) | false | | |
|
||||
| `»» id` | string(uuid) | false | | |
|
||||
| `»» status` | [codersdk.ProvisionerJobStatus](schemas.md#codersdkprovisionerjobstatus) | false | | |
|
||||
| `»» template_display_name` | string | false | | |
|
||||
| `»» template_icon` | string | false | | |
|
||||
| `»» template_name` | string | false | | |
|
||||
| `» id` | string(uuid) | false | | |
|
||||
| `» key_id` | string(uuid) | false | | |
|
||||
| `» key_name` | string | false | | Optional fields. |
|
||||
|
75
docs/reference/api/schemas.md
generated
75
docs/reference/api/schemas.md
generated
@ -4432,23 +4432,29 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith
|
||||
```json
|
||||
{
|
||||
"id": "string",
|
||||
"name": "string"
|
||||
"name": "string",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "string",
|
||||
"value": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|--------|--------|----------|--------------|-------------|
|
||||
|--------------|---------------------------------------------------------------|----------|--------------|-------------|
|
||||
| `id` | string | false | | |
|
||||
| `name` | string | false | | |
|
||||
| `parameters` | array of [codersdk.PresetParameter](#codersdkpresetparameter) | false | | |
|
||||
|
||||
## codersdk.PresetParameter
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "string",
|
||||
"presetID": "string",
|
||||
"value": "string"
|
||||
}
|
||||
```
|
||||
@ -4456,9 +4462,8 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|------------|--------|----------|--------------|-------------|
|
||||
|---------|--------|----------|--------------|-------------|
|
||||
| `name` | string | false | | |
|
||||
| `presetID` | string | false | | |
|
||||
| `value` | string | false | | |
|
||||
|
||||
## codersdk.PrometheusConfig
|
||||
@ -4522,7 +4527,10 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"current_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"key_id": "1e779c8a-6786-4c89-b7c3-a6666f5fd6b5",
|
||||
@ -4532,7 +4540,10 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"previous_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"provisioners": [
|
||||
"string"
|
||||
@ -4579,16 +4590,22 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith
|
||||
```json
|
||||
{
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
}
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|----------|----------------------------------------------------------------|----------|--------------|-------------|
|
||||
|-------------------------|----------------------------------------------------------------|----------|--------------|-------------|
|
||||
| `id` | string | false | | |
|
||||
| `status` | [codersdk.ProvisionerJobStatus](#codersdkprovisionerjobstatus) | false | | |
|
||||
| `template_display_name` | string | false | | |
|
||||
| `template_icon` | string | false | | |
|
||||
| `template_name` | string | false | | |
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
@ -4844,7 +4861,10 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"current_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"key_id": "1e779c8a-6786-4c89-b7c3-a6666f5fd6b5",
|
||||
@ -4854,7 +4874,10 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"previous_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"provisioners": [
|
||||
"string"
|
||||
@ -9862,7 +9885,10 @@ Zero means unspecified. There might be a limit, but the client need not try to r
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"current_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"key_id": "1e779c8a-6786-4c89-b7c3-a6666f5fd6b5",
|
||||
@ -9872,7 +9898,10 @@ Zero means unspecified. There might be a limit, but the client need not try to r
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"previous_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"provisioners": [
|
||||
"string"
|
||||
@ -9998,7 +10027,10 @@ Zero means unspecified. There might be a limit, but the client need not try to r
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"current_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"key_id": "1e779c8a-6786-4c89-b7c3-a6666f5fd6b5",
|
||||
@ -10008,7 +10040,10 @@ Zero means unspecified. There might be a limit, but the client need not try to r
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"previous_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"provisioners": [
|
||||
"string"
|
||||
@ -10065,7 +10100,10 @@ Zero means unspecified. There might be a limit, but the client need not try to r
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"current_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"key_id": "1e779c8a-6786-4c89-b7c3-a6666f5fd6b5",
|
||||
@ -10075,7 +10113,10 @@ Zero means unspecified. There might be a limit, but the client need not try to r
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"previous_job": {
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"status": "pending"
|
||||
"status": "pending",
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_name": "string"
|
||||
},
|
||||
"provisioners": [
|
||||
"string"
|
||||
|
63
docs/reference/api/templates.md
generated
63
docs/reference/api/templates.md
generated
@ -2699,7 +2699,13 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/p
|
||||
[
|
||||
{
|
||||
"id": "string",
|
||||
"name": "string"
|
||||
"name": "string",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "string",
|
||||
"value": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
@ -2719,58 +2725,9 @@ Status Code **200**
|
||||
| `[array item]` | array | false | | |
|
||||
| `» id` | string | false | | |
|
||||
| `» name` | string | false | | |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Get template version preset parameters
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/presets/parameters \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /templateversions/{templateversion}/presets/parameters`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
|-------------------|------|--------------|----------|---------------------|
|
||||
| `templateversion` | path | string(uuid) | true | Template version ID |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "string",
|
||||
"presetID": "string",
|
||||
"value": "string"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
|--------|---------------------------------------------------------|-------------|-------------------------------------------------------------------------|
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | array of [codersdk.PresetParameter](schemas.md#codersdkpresetparameter) |
|
||||
|
||||
<h3 id="get-template-version-preset-parameters-responseschema">Response Schema</h3>
|
||||
|
||||
Status Code **200**
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|----------------|--------|----------|--------------|-------------|
|
||||
| `[array item]` | array | false | | |
|
||||
| `» name` | string | false | | |
|
||||
| `» presetID` | string | false | | |
|
||||
| `» value` | string | false | | |
|
||||
| `» parameters` | array | false | | |
|
||||
| `»» name` | string | false | | |
|
||||
| `»» value` | string | false | | |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
|
4
docs/reference/cli/provisioner_list.md
generated
4
docs/reference/cli/provisioner_list.md
generated
@ -27,8 +27,8 @@ Select which organization (uuid or name) to use.
|
||||
### -c, --column
|
||||
|
||||
| | |
|
||||
|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Type | <code>[id\|organization id\|created at\|last seen at\|name\|version\|api version\|tags\|key name\|status\|current job id\|current job status\|previous job id\|previous job status\|organization]</code> |
|
||||
|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Type | <code>[id\|organization id\|created at\|last seen at\|name\|version\|api version\|tags\|key name\|status\|current job id\|current job status\|current job template name\|current job template icon\|current job template display name\|previous job id\|previous job status\|previous job template name\|previous job template icon\|previous job template display name\|organization]</code> |
|
||||
| Default | <code>name,organization,status,key name,created at,last seen at,version,tags</code> |
|
||||
|
||||
Columns to display in table output.
|
||||
|
2
docs/reference/cli/tokens_remove.md
generated
2
docs/reference/cli/tokens_remove.md
generated
@ -11,5 +11,5 @@ Aliases:
|
||||
## Usage
|
||||
|
||||
```console
|
||||
coder tokens remove <name>
|
||||
coder tokens remove <name|id|token>
|
||||
```
|
||||
|
@ -374,6 +374,7 @@ resource "docker_container" "workspace" {
|
||||
"CODER_PROC_PRIO_MGMT=1",
|
||||
"CODER_PROC_OOM_SCORE=10",
|
||||
"CODER_PROC_NICE_SCORE=1",
|
||||
"CODER_AGENT_DEVCONTAINERS_ENABLE=1",
|
||||
]
|
||||
host {
|
||||
host = "host.docker.internal"
|
||||
|
@ -11,7 +11,7 @@ OPTIONS:
|
||||
-O, --org string, $CODER_ORGANIZATION
|
||||
Select which organization (uuid or name) to use.
|
||||
|
||||
-c, --column [id|organization id|created at|last seen at|name|version|api version|tags|key name|status|current job id|current job status|previous job id|previous job status|organization] (default: name,organization,status,key name,created at,last seen at,version,tags)
|
||||
-c, --column [id|organization id|created at|last seen at|name|version|api version|tags|key name|status|current job id|current job status|current job template name|current job template icon|current job template display name|previous job id|previous job status|previous job template name|previous job template icon|previous job template display name|organization] (default: name,organization,status,key name,created at,last seen at,version,tags)
|
||||
Columns to display in table output.
|
||||
|
||||
-o, --output table|json (default: table)
|
||||
|
@ -764,7 +764,7 @@ export const createServer = async (
|
||||
async function waitForPort(
|
||||
port: number,
|
||||
host = "0.0.0.0",
|
||||
timeout = 30000,
|
||||
timeout = 60_000,
|
||||
): Promise<void> {
|
||||
const start = Date.now();
|
||||
while (Date.now() - start < timeout) {
|
||||
|
5
site/src/api/typesGenerated.ts
generated
5
site/src/api/typesGenerated.ts
generated
@ -1554,11 +1554,11 @@ export interface PprofConfig {
|
||||
export interface Preset {
|
||||
readonly ID: string;
|
||||
readonly Name: string;
|
||||
readonly Parameters: readonly PresetParameter[];
|
||||
}
|
||||
|
||||
// From codersdk/presets.go
|
||||
export interface PresetParameter {
|
||||
readonly PresetID: string;
|
||||
readonly Name: string;
|
||||
readonly Value: string;
|
||||
}
|
||||
@ -1604,6 +1604,9 @@ export interface ProvisionerDaemon {
|
||||
export interface ProvisionerDaemonJob {
|
||||
readonly id: string;
|
||||
readonly status: ProvisionerJobStatus;
|
||||
readonly template_name: string;
|
||||
readonly template_icon: string;
|
||||
readonly template_display_name: string;
|
||||
}
|
||||
|
||||
// From codersdk/client.go
|
||||
|
@ -52,6 +52,12 @@ export default defineConfig({
|
||||
"csrf_token=JXm9hOUdZctWt0ZZGAy9xiS/gxMKYOThdxjjMnMUyn4=; Path=/; HttpOnly; SameSite=Lax",
|
||||
},
|
||||
proxy: {
|
||||
"//": {
|
||||
changeOrigin: true,
|
||||
target: process.env.CODER_HOST || "http://localhost:3000",
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
rewrite: (path) => path.replace(/\/+/g, "/"),
|
||||
},
|
||||
"/api": {
|
||||
ws: true,
|
||||
changeOrigin: true,
|
||||
@ -84,6 +90,7 @@ export default defineConfig({
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
},
|
||||
},
|
||||
allowedHosts: true,
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
|
Reference in New Issue
Block a user