mirror of https://github.com/coder/coder.git
feat: Validate swagger definitions (#5694)
* docs: audit, deploymentconfig, files, parameters * Swagger comments in workspacebuilds.go * structs in workspacebuilds.go * workspaceagents: instance identity * workspaceagents.go in progress * workspaceagents.go in progress * Agents * workspacebuilds.go * /workspaces * templates.go, templateversions.go * templateversion.go in progress * cancel * templateversions * wip * Merge * x-apidocgen * NullTime hack not needed anymore * Fix: x-apidocgen * Members * Fixes * Fix * WIP * WIP * Users * Logout * User profile * Status suspend activate * User roles * User tokens * Keys * SSH key * All * Typo * Fix * Entitlements * Groups * SCIM * Fix * Fix * Clean templates * Sort API pages * Fix: HashedSecret * WIP * WIP * WIP * Fix: cover workspaceagents * Assert: consistent ID and summary * Assert: success or failure defined * Fix: parallel * Refactor * Support enterprise * Go comment goes to top * Security * assertPathParametersDefined * assertUniqueRoutes * assertRequestBody * More fixes * Fix: exceptions * Fix field format * Address PR comments * Refactor
This commit is contained in:
parent
dcab87358e
commit
deebfcbd53
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -29,6 +29,7 @@ import (
|
|||
// @Summary Create token API key
|
||||
// @ID create-token-api-key
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Users
|
||||
// @Param user path string true "User ID, name, or me"
|
||||
|
@ -209,9 +210,8 @@ func (api *API) tokens(rw http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// @Summary Delete API key
|
||||
// @ID delete-user-tokens
|
||||
// @ID delete-api-key
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Users
|
||||
// @Param user path string true "User ID, name, or me"
|
||||
// @Param keyid path string true "Key ID" format(uuid)
|
||||
|
|
|
@ -89,7 +89,7 @@ func (api *API) auditLogs(rw http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// @Summary Generate fake audit log
|
||||
// @ID generate-fake-audit-logs
|
||||
// @ID generate-fake-audit-log
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Tags Audit
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package coderdtest_test
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
)
|
||||
|
||||
func TestEndpointsDocumented(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
swaggerComments, err := coderdtest.ParseSwaggerComments("..")
|
||||
require.NoError(t, err, "can't parse swagger comments")
|
||||
|
||||
_, _, api := coderdtest.NewWithAPI(t, nil)
|
||||
coderdtest.VerifySwaggerDefinitions(t, api.APIHandler, swaggerComments)
|
||||
}
|
||||
|
||||
func TestSDKFieldsFormatted(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fileSet := token.NewFileSet()
|
||||
nodes, err := parser.ParseDir(fileSet, "../../codersdk", nil, parser.ParseComments)
|
||||
require.NoError(t, err, "parser.ParseDir failed")
|
||||
|
||||
for _, node := range nodes {
|
||||
ast.Inspect(node, func(n ast.Node) bool {
|
||||
typeSpec, ok := n.(*ast.TypeSpec)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
structureName := typeSpec.Name
|
||||
|
||||
structType, ok := typeSpec.Type.(*ast.StructType)
|
||||
if !ok {
|
||||
return true // not a structure
|
||||
}
|
||||
|
||||
for _, field := range structType.Fields.List {
|
||||
selectorExpr, ok := field.Type.(*ast.SelectorExpr)
|
||||
if !ok {
|
||||
continue // rather a basic, or primitive
|
||||
}
|
||||
|
||||
if field.Tag == nil || !strings.Contains(field.Tag.Value, `json:"`) {
|
||||
continue // not a JSON property
|
||||
}
|
||||
|
||||
switch selectorExpr.Sel.Name {
|
||||
case "UUID":
|
||||
assert.Contains(t, field.Tag.Value, `format:"uuid"`, `Swagger formatting requires to annotate the field with - format:"uuid". Location: %s/%s`, structureName, field.Names)
|
||||
case "Time":
|
||||
assert.Contains(t, field.Tag.Value, `format:"date-time"`, `Swagger formatting requires to annotate the field with - format:"date-time". Location: %s/%s`, structureName, field.Names)
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,318 @@
|
|||
package coderdtest
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type SwaggerComment struct {
|
||||
summary string
|
||||
id string
|
||||
security string
|
||||
tags string
|
||||
accept string
|
||||
produce string
|
||||
|
||||
method string
|
||||
router string
|
||||
|
||||
successes []response
|
||||
failures []response
|
||||
|
||||
parameters []parameter
|
||||
|
||||
raw []*ast.Comment
|
||||
}
|
||||
|
||||
type parameter struct {
|
||||
name string
|
||||
kind string
|
||||
}
|
||||
|
||||
type response struct {
|
||||
status string
|
||||
kind string // {object} or {array}
|
||||
model string
|
||||
}
|
||||
|
||||
func ParseSwaggerComments(dirs ...string) ([]SwaggerComment, error) {
|
||||
fileSet := token.NewFileSet()
|
||||
|
||||
var swaggerComments []SwaggerComment
|
||||
for _, dir := range dirs {
|
||||
nodes, err := parser.ParseDir(fileSet, dir, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf(`parser.ParseDir failed for "%s": %w`, dir, err)
|
||||
}
|
||||
|
||||
for _, node := range nodes {
|
||||
ast.Inspect(node, func(n ast.Node) bool {
|
||||
commentGroup, ok := n.(*ast.CommentGroup)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
|
||||
var isSwaggerComment bool
|
||||
for _, line := range commentGroup.List {
|
||||
text := strings.TrimSpace(line.Text)
|
||||
if strings.HasPrefix(text, "//") && strings.Contains(text, "@Router") {
|
||||
isSwaggerComment = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if isSwaggerComment {
|
||||
swaggerComments = append(swaggerComments, parseSwaggerComment(commentGroup))
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
return swaggerComments, nil
|
||||
}
|
||||
|
||||
func parseSwaggerComment(commentGroup *ast.CommentGroup) SwaggerComment {
|
||||
c := SwaggerComment{
|
||||
raw: commentGroup.List,
|
||||
parameters: []parameter{},
|
||||
successes: []response{},
|
||||
failures: []response{},
|
||||
}
|
||||
for _, line := range commentGroup.List {
|
||||
// @<annotationName> [args...]
|
||||
splitN := strings.SplitN(strings.TrimSpace(line.Text), " ", 3)
|
||||
if len(splitN) < 2 {
|
||||
continue // comment prefix without any content
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(splitN[1], "@") {
|
||||
continue // not a swagger annotation
|
||||
}
|
||||
|
||||
annotationName := splitN[1]
|
||||
annotationArgs := splitN[2]
|
||||
args := strings.Split(splitN[2], " ")
|
||||
|
||||
switch annotationName {
|
||||
case "@Router":
|
||||
c.router = args[0]
|
||||
c.method = args[1][1 : len(args[1])-1]
|
||||
case "@Success", "@Failure":
|
||||
var r response
|
||||
if len(args) > 0 {
|
||||
r.status = args[0]
|
||||
}
|
||||
if len(args) > 1 {
|
||||
r.kind = args[1]
|
||||
}
|
||||
if len(args) > 2 {
|
||||
r.model = args[2]
|
||||
}
|
||||
|
||||
if annotationName == "@Success" {
|
||||
c.successes = append(c.successes, r)
|
||||
} else if annotationName == "@Failure" {
|
||||
c.failures = append(c.failures, r)
|
||||
}
|
||||
case "@Param":
|
||||
p := parameter{
|
||||
name: args[0],
|
||||
kind: args[1],
|
||||
}
|
||||
c.parameters = append(c.parameters, p)
|
||||
case "@Summary":
|
||||
c.summary = annotationArgs
|
||||
case "@ID":
|
||||
c.id = annotationArgs
|
||||
case "@Tags":
|
||||
c.tags = annotationArgs
|
||||
case "@Security":
|
||||
c.security = annotationArgs
|
||||
case "@Accept":
|
||||
c.accept = annotationArgs
|
||||
case "@Produce":
|
||||
c.produce = annotationArgs
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func VerifySwaggerDefinitions(t *testing.T, router chi.Router, swaggerComments []SwaggerComment) {
|
||||
assertUniqueRoutes(t, swaggerComments)
|
||||
|
||||
err := chi.Walk(router, func(method, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error {
|
||||
method = strings.ToLower(method)
|
||||
if route != "/" && strings.HasSuffix(route, "/") {
|
||||
route = route[:len(route)-1]
|
||||
}
|
||||
|
||||
t.Run(method+" "+route, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
c := findSwaggerCommentByMethodAndRoute(swaggerComments, method, route)
|
||||
assert.NotNil(t, c, "Missing @Router annotation")
|
||||
if c == nil {
|
||||
return // do not fail next assertion for this route
|
||||
}
|
||||
|
||||
assertConsistencyBetweenRouteIDAndSummary(t, *c)
|
||||
assertSuccessOrFailureDefined(t, *c)
|
||||
assertRequiredAnnotations(t, *c)
|
||||
assertGoCommentFirst(t, *c)
|
||||
assertPathParametersDefined(t, *c)
|
||||
assertSecurityDefined(t, *c)
|
||||
assertAccept(t, *c)
|
||||
assertProduce(t, *c)
|
||||
})
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err, "chi.Walk should not fail")
|
||||
}
|
||||
|
||||
func assertUniqueRoutes(t *testing.T, comments []SwaggerComment) {
|
||||
m := map[string]struct{}{}
|
||||
|
||||
for _, c := range comments {
|
||||
key := c.method + " " + c.router
|
||||
_, alreadyDefined := m[key]
|
||||
assert.False(t, alreadyDefined, "defined route must be unique (method: %s, route: %s)", c.method, c.router)
|
||||
if !alreadyDefined {
|
||||
m[key] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func findSwaggerCommentByMethodAndRoute(comments []SwaggerComment, method, route string) *SwaggerComment {
|
||||
for _, c := range comments {
|
||||
if c.method == method && c.router == route {
|
||||
return &c
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var nonAlphanumericRegex = regexp.MustCompile(`[^a-zA-Z0-9-]+`)
|
||||
|
||||
func assertConsistencyBetweenRouteIDAndSummary(t *testing.T, comment SwaggerComment) {
|
||||
exp := strings.ToLower(comment.summary)
|
||||
exp = strings.ReplaceAll(exp, " ", "-")
|
||||
exp = nonAlphanumericRegex.ReplaceAllString(exp, "")
|
||||
|
||||
assert.Equal(t, exp, comment.id, "Router ID must match summary")
|
||||
}
|
||||
|
||||
func assertSuccessOrFailureDefined(t *testing.T, comment SwaggerComment) {
|
||||
assert.True(t, len(comment.successes) > 0 || len(comment.failures) > 0, "At least one @Success or @Failure annotation must be defined")
|
||||
}
|
||||
|
||||
func assertRequiredAnnotations(t *testing.T, comment SwaggerComment) {
|
||||
assert.NotEmpty(t, comment.id, "@ID must be defined")
|
||||
assert.NotEmpty(t, comment.summary, "@Summary must be defined")
|
||||
assert.NotEmpty(t, comment.tags, "@Tags must be defined")
|
||||
}
|
||||
|
||||
func assertGoCommentFirst(t *testing.T, comment SwaggerComment) {
|
||||
var inSwaggerBlock bool
|
||||
|
||||
for _, line := range comment.raw {
|
||||
text := strings.TrimSpace(line.Text)
|
||||
|
||||
if inSwaggerBlock {
|
||||
if !strings.HasPrefix(text, "// @") {
|
||||
assert.Fail(t, "Go function comment must be placed before swagger comments")
|
||||
return
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(text, "// @Summary") {
|
||||
inSwaggerBlock = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var urlParameterRegexp = regexp.MustCompile(`{[^{}]*}`)
|
||||
|
||||
func assertPathParametersDefined(t *testing.T, comment SwaggerComment) {
|
||||
matches := urlParameterRegexp.FindAllString(comment.router, -1)
|
||||
if matches == nil {
|
||||
return // router does not require any parameters
|
||||
}
|
||||
|
||||
for _, m := range matches {
|
||||
var matched bool
|
||||
for _, p := range comment.parameters {
|
||||
if p.kind == "path" && "{"+p.name+"}" == m {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !matched {
|
||||
assert.Failf(t, "Missing @Param annotation", "Path parameter: %s", m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func assertSecurityDefined(t *testing.T, comment SwaggerComment) {
|
||||
if comment.router == "/updatecheck" ||
|
||||
comment.router == "/buildinfo" ||
|
||||
comment.router == "/" {
|
||||
return // endpoints do not require authorization
|
||||
}
|
||||
assert.Equal(t, "CoderSessionToken", comment.security, "@Security must be equal CoderSessionToken")
|
||||
}
|
||||
|
||||
func assertAccept(t *testing.T, comment SwaggerComment) {
|
||||
var hasRequestBody bool
|
||||
for _, c := range comment.parameters {
|
||||
if c.name == "request" && c.kind == "body" ||
|
||||
c.name == "file" && c.kind == "formData" {
|
||||
hasRequestBody = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var hasAccept bool
|
||||
if comment.accept != "" {
|
||||
hasAccept = true
|
||||
}
|
||||
|
||||
if comment.method == "get" {
|
||||
assert.Empty(t, comment.accept, "GET route does not require the @Accept annotation")
|
||||
assert.False(t, hasRequestBody, "GET route does not require the request body")
|
||||
} else {
|
||||
assert.False(t, hasRequestBody && !hasAccept, "Route with the request body requires the @Accept annotation")
|
||||
assert.False(t, !hasRequestBody && hasAccept, "Route with @Accept annotation requires the request body or file formData parameter")
|
||||
}
|
||||
}
|
||||
|
||||
func assertProduce(t *testing.T, comment SwaggerComment) {
|
||||
var hasResponseModel bool
|
||||
for _, r := range comment.successes {
|
||||
if r.model != "" {
|
||||
hasResponseModel = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if hasResponseModel {
|
||||
assert.True(t, comment.produce != "", "Route must have @Produce annotation as it responds with a model structure")
|
||||
} else {
|
||||
if (comment.router == "/workspaceagents/me/app-health" && comment.method == "post") ||
|
||||
(comment.router == "/workspaceagents/me/version" && comment.method == "post") ||
|
||||
(comment.router == "/licenses/{id}" && comment.method == "delete") {
|
||||
return // Exception: HTTP 200 is returned without response entity
|
||||
}
|
||||
|
||||
assert.True(t, comment.produce == "", "Response model is undefined, so we can't predict the content type", comment)
|
||||
}
|
||||
}
|
|
@ -20,7 +20,6 @@ type cspViolation struct {
|
|||
// @ID report-csp-violations
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce text/plain
|
||||
// @Tags General
|
||||
// @Param request body cspViolation true "Violation report"
|
||||
// @Success 200
|
||||
|
|
|
@ -25,7 +25,7 @@ const (
|
|||
|
||||
// @Summary Upload file
|
||||
// @Description Swagger notice: Swagger 2.0 doesn't support file upload with a `content-type` different than `application/x-www-form-urlencoded`.
|
||||
// @ID update-file
|
||||
// @ID upload-file
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Accept application/x-tar
|
||||
|
|
|
@ -119,7 +119,6 @@ func (api *API) gitSSHKey(rw http.ResponseWriter, r *http.Request) {
|
|||
// @Summary Get workspace agent Git SSH key
|
||||
// @ID get-workspace-agent-git-ssh-key
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Agents
|
||||
// @Success 200 {object} codersdk.AgentGitSSHKey
|
||||
|
|
|
@ -40,6 +40,7 @@ func (api *API) organization(rw http.ResponseWriter, r *http.Request) {
|
|||
// @Summary Create organization
|
||||
// @ID create-organization
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Organizations
|
||||
// @Param request body codersdk.CreateOrganizationRequest true "Create organization request"
|
||||
|
|
|
@ -23,15 +23,16 @@ import (
|
|||
"github.com/coder/coder/examples"
|
||||
)
|
||||
|
||||
// Returns a single template.
|
||||
//
|
||||
// @Summary Get template metadata by ID
|
||||
// @ID get-template-metadata-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param id path string true "Template ID" format(uuid)
|
||||
// @Param template path string true "Template ID" format(uuid)
|
||||
// @Success 200 {object} codersdk.Template
|
||||
// @Router /templates/{id} [get]
|
||||
// Returns a single template.
|
||||
// @Router /templates/{template} [get]
|
||||
func (api *API) template(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
template := httpmw.TemplateParam(r)
|
||||
|
@ -75,9 +76,9 @@ func (api *API) template(rw http.ResponseWriter, r *http.Request) {
|
|||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param id path string true "Template ID" format(uuid)
|
||||
// @Param template path string true "Template ID" format(uuid)
|
||||
// @Success 200 {object} codersdk.Response
|
||||
// @Router /templates/{id} [delete]
|
||||
// @Router /templates/{template} [delete]
|
||||
func (api *API) deleteTemplate(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
@ -131,6 +132,9 @@ func (api *API) deleteTemplate(rw http.ResponseWriter, r *http.Request) {
|
|||
})
|
||||
}
|
||||
|
||||
// Create a new template in an organization.
|
||||
// Returns a single template.
|
||||
//
|
||||
// @Summary Create template by organization
|
||||
// @ID create-template-by-organization
|
||||
// @Security CoderSessionToken
|
||||
|
@ -141,8 +145,6 @@ func (api *API) deleteTemplate(rw http.ResponseWriter, r *http.Request) {
|
|||
// @Param organization path string true "Organization ID"
|
||||
// @Success 200 {object} codersdk.Template
|
||||
// @Router /organizations/{organization}/templates [post]
|
||||
// Returns a single template.
|
||||
// Create a new template in an organization.
|
||||
func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
@ -461,13 +463,13 @@ func (api *API) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Re
|
|||
}
|
||||
|
||||
// @Summary Update template metadata by ID
|
||||
// @ID update-template-metadata
|
||||
// @ID update-template-metadata-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param id path string true "Template ID" format(uuid)
|
||||
// @Param template path string true "Template ID" format(uuid)
|
||||
// @Success 200 {object} codersdk.Template
|
||||
// @Router /templates/{id} [patch]
|
||||
// @Router /templates/{template} [patch]
|
||||
func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
@ -593,9 +595,9 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
|||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param id path string true "Template ID" format(uuid)
|
||||
// @Param template path string true "Template ID" format(uuid)
|
||||
// @Success 200 {object} codersdk.TemplateDAUsResponse
|
||||
// @Router /templates/{id}/daus [get]
|
||||
// @Router /templates/{template}/daus [get]
|
||||
func (api *API) templateDAUs(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
template := httpmw.TemplateParam(r)
|
||||
|
|
|
@ -353,13 +353,12 @@ func (api *API) postTemplateVersionDryRun(rw http.ResponseWriter, r *http.Reques
|
|||
// @Summary Get template version dry-run by job ID
|
||||
// @ID get-template-version-dry-run-by-job-id
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param templateversion path string true "Template version ID" format(uuid)
|
||||
// @Param jobid path string true "Job ID" format(uuid)
|
||||
// @Param jobID path string true "Job ID" format(uuid)
|
||||
// @Success 200 {object} codersdk.ProvisionerJob
|
||||
// @Router /templateversions/{templateversion}/dry-run/{jobid} [get]
|
||||
// @Router /templateversions/{templateversion}/dry-run/{jobID} [get]
|
||||
func (api *API) templateVersionDryRun(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
job, ok := api.fetchTemplateVersionDryRunJob(rw, r)
|
||||
|
@ -376,9 +375,9 @@ func (api *API) templateVersionDryRun(rw http.ResponseWriter, r *http.Request) {
|
|||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param templateversion path string true "Template version ID" format(uuid)
|
||||
// @Param jobid path string true "Job ID" format(uuid)
|
||||
// @Param jobID path string true "Job ID" format(uuid)
|
||||
// @Success 200 {array} codersdk.WorkspaceResource
|
||||
// @Router /templateversions/{templateversion}/dry-run/{jobid}/resources [get]
|
||||
// @Router /templateversions/{templateversion}/dry-run/{jobID}/resources [get]
|
||||
func (api *API) templateVersionDryRunResources(rw http.ResponseWriter, r *http.Request) {
|
||||
job, ok := api.fetchTemplateVersionDryRunJob(rw, r)
|
||||
if !ok {
|
||||
|
@ -394,12 +393,12 @@ func (api *API) templateVersionDryRunResources(rw http.ResponseWriter, r *http.R
|
|||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param templateversion path string true "Template version ID" format(uuid)
|
||||
// @Param jobid path string true "Job ID" format(uuid)
|
||||
// @Param jobID path string true "Job ID" format(uuid)
|
||||
// @Param before query int false "Before Unix timestamp"
|
||||
// @Param after query int false "After Unix timestamp"
|
||||
// @Param follow query bool false "Follow log stream"
|
||||
// @Success 200 {array} codersdk.ProvisionerJobLog
|
||||
// @Router /templateversions/{templateversion}/dry-run/{jobid}/logs [get]
|
||||
// @Router /templateversions/{templateversion}/dry-run/{jobID}/logs [get]
|
||||
func (api *API) templateVersionDryRunLogs(rw http.ResponseWriter, r *http.Request) {
|
||||
job, ok := api.fetchTemplateVersionDryRunJob(rw, r)
|
||||
if !ok {
|
||||
|
@ -414,9 +413,10 @@ func (api *API) templateVersionDryRunLogs(rw http.ResponseWriter, r *http.Reques
|
|||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param jobID path string true "Job ID" format(uuid)
|
||||
// @Param templateversion path string true "Template version ID" format(uuid)
|
||||
// @Success 200 {object} codersdk.Response
|
||||
// @Router /templateversions/{templateversion}/dry-run/{jobid}/cancel [patch]
|
||||
// @Router /templateversions/{templateversion}/dry-run/{jobID}/cancel [patch]
|
||||
func (api *API) patchTemplateVersionDryRunCancel(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
templateVersion := httpmw.TemplateVersionParam(r)
|
||||
|
@ -536,16 +536,16 @@ func (api *API) fetchTemplateVersionDryRunJob(rw http.ResponseWriter, r *http.Re
|
|||
}
|
||||
|
||||
// @Summary List template versions by template ID
|
||||
// @ID list-template-versions-by-template-ID
|
||||
// @ID list-template-versions-by-template-id
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param id path string true "Template ID" format(uuid)
|
||||
// @Param template path string true "Template ID" format(uuid)
|
||||
// @Param after_id query string false "After ID" format(uuid)
|
||||
// @Param limit query int false "Page limit"
|
||||
// @Param offset query int false "Page offset"
|
||||
// @Success 200 {array} codersdk.TemplateVersion
|
||||
// @Router /templates/{id}/versions [get]
|
||||
// @Router /templates/{template}/versions [get]
|
||||
func (api *API) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
template := httpmw.TemplateParam(r)
|
||||
|
@ -648,10 +648,10 @@ func (api *API) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Reque
|
|||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param id path string true "Template ID" format(uuid)
|
||||
// @Param template path string true "Template ID" format(uuid)
|
||||
// @Param templateversionname path string true "Template version name"
|
||||
// @Success 200 {array} codersdk.TemplateVersion
|
||||
// @Router /templates/{id}/versions/{templateversionname} [get]
|
||||
// @Router /templates/{template}/versions/{templateversionname} [get]
|
||||
func (api *API) templateVersionByName(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
template := httpmw.TemplateParam(r)
|
||||
|
@ -828,15 +828,15 @@ func (api *API) previousTemplateVersionByOrganizationAndName(rw http.ResponseWri
|
|||
}
|
||||
|
||||
// @Summary Update active template version by template ID
|
||||
// @ID update-active-template-version-by-template-ID
|
||||
// @ID update-active-template-version-by-template-id
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param request body codersdk.UpdateActiveTemplateVersion true "Modified template version"
|
||||
// @Param id path string true "Template ID" format(uuid)
|
||||
// @Param template path string true "Template ID" format(uuid)
|
||||
// @Success 200 {object} codersdk.Response
|
||||
// @Router /templates/{id}/versions [patch]
|
||||
// @Router /templates/{template}/versions [patch]
|
||||
func (api *API) patchActiveTemplateVersion(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
@ -911,6 +911,8 @@ func (api *API) patchActiveTemplateVersion(rw http.ResponseWriter, r *http.Reque
|
|||
})
|
||||
}
|
||||
|
||||
// postTemplateVersionsByOrganization creates a new version of a template. An import job is queued to parse the storage method provided.
|
||||
//
|
||||
// @Summary Create template version by organization
|
||||
// @ID create-template-version-by-organization
|
||||
// @Security CoderSessionToken
|
||||
|
@ -921,8 +923,6 @@ func (api *API) patchActiveTemplateVersion(rw http.ResponseWriter, r *http.Reque
|
|||
// @Param request body codersdk.CreateTemplateVersionDryRunRequest true "Create template version request"
|
||||
// @Success 201 {object} codersdk.TemplateVersion
|
||||
// @Router /organizations/{organization}/templateversions [post]
|
||||
//
|
||||
// postTemplateVersionsByOrganization creates a new version of a template. An import job is queued to parse the storage method provided.
|
||||
func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
@ -1207,6 +1207,12 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht
|
|||
httpapi.Write(ctx, rw, http.StatusCreated, convertTemplateVersion(templateVersion, convertProvisionerJob(provisionerJob), user))
|
||||
}
|
||||
|
||||
// templateVersionResources returns the workspace agent resources associated
|
||||
// with a template version. A template can specify more than one resource to be
|
||||
// provisioned, each resource can have an agent that dials back to coderd. The
|
||||
// agents returned are informative of the template version, and do not return
|
||||
// agents associated with any particular workspace.
|
||||
//
|
||||
// @Summary Get resources by template version
|
||||
// @ID get-resources-by-template-version
|
||||
// @Security CoderSessionToken
|
||||
|
@ -1215,12 +1221,6 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht
|
|||
// @Param templateversion path string true "Template version ID" format(uuid)
|
||||
// @Success 200 {array} codersdk.WorkspaceResource
|
||||
// @Router /templateversions/{templateversion}/resources [get]
|
||||
//
|
||||
// templateVersionResources returns the workspace agent resources associated
|
||||
// with a template version. A template can specify more than one resource to be
|
||||
// provisioned, each resource can have an agent that dials back to coderd. The
|
||||
// agents returned are informative of the template version, and do not return
|
||||
// agents associated with any particular workspace.
|
||||
func (api *API) templateVersionResources(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
@ -1244,6 +1244,11 @@ func (api *API) templateVersionResources(rw http.ResponseWriter, r *http.Request
|
|||
api.provisionerJobResources(rw, r, job)
|
||||
}
|
||||
|
||||
// templateVersionLogs returns the logs returned by the provisioner for the given
|
||||
// template version. These logs are only associated with the template version,
|
||||
// and not any build logs for a workspace.
|
||||
// Eg: Logs returned from 'terraform plan' when uploading a new terraform file.
|
||||
//
|
||||
// @Summary Get logs by template version
|
||||
// @ID get-logs-by-template-version
|
||||
// @Security CoderSessionToken
|
||||
|
@ -1255,11 +1260,6 @@ func (api *API) templateVersionResources(rw http.ResponseWriter, r *http.Request
|
|||
// @Param follow query bool false "Follow log stream"
|
||||
// @Success 200 {array} codersdk.ProvisionerJobLog
|
||||
// @Router /templateversions/{templateversion}/logs [get]
|
||||
//
|
||||
// templateVersionLogs returns the logs returned by the provisioner for the given
|
||||
// template version. These logs are only associated with the template version,
|
||||
// and not any build logs for a workspace.
|
||||
// Eg: Logs returned from 'terraform plan' when uploading a new terraform file.
|
||||
func (api *API) templateVersionLogs(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
|
|
@ -59,9 +59,8 @@ func (api *API) userAuthMethods(rw http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// @Summary OAuth 2.0 GitHub Callback
|
||||
// @ID oauth2-github-callback
|
||||
// @ID oauth-20-github-callback
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Users
|
||||
// @Success 307
|
||||
// @Router /users/oauth2/github/callback [get]
|
||||
|
@ -218,9 +217,8 @@ type OIDCConfig struct {
|
|||
}
|
||||
|
||||
// @Summary OpenID Connect Callback
|
||||
// @ID oidc-callback
|
||||
// @ID openid-connect-callback
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Users
|
||||
// @Success 307
|
||||
// @Router /users/oidc/callback [get]
|
||||
|
|
|
@ -435,6 +435,7 @@ func (api *API) userByName(rw http.ResponseWriter, r *http.Request) {
|
|||
// @Summary Update user profile
|
||||
// @ID update-user-profile
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Users
|
||||
// @Param user path string true "User ID, name, or me"
|
||||
|
@ -617,7 +618,7 @@ func (api *API) putUserStatus(status database.UserStatus) func(rw http.ResponseW
|
|||
// @Summary Update user password
|
||||
// @ID update-user-password
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Accept json
|
||||
// @Tags Users
|
||||
// @Param user path string true "User ID, name, or me"
|
||||
// @Param request body codersdk.UpdateUserPasswordRequest true "Update password request"
|
||||
|
@ -908,7 +909,7 @@ func (api *API) updateSiteUserRoles(ctx context.Context, args database.UpdateUse
|
|||
// Returns organizations the parameterized user has access to.
|
||||
//
|
||||
// @Summary Get organizations by user
|
||||
// @ID get-organizations-by-users
|
||||
// @ID get-organizations-by-user
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Users
|
||||
|
@ -990,6 +991,7 @@ func (api *API) organizationByUserAndName(rw http.ResponseWriter, r *http.Reques
|
|||
// @Summary Log in user
|
||||
// @ID log-in-user
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Authorization
|
||||
// @Param request body codersdk.LoginWithPasswordRequest true "Login request"
|
||||
|
|
|
@ -35,6 +35,14 @@ import (
|
|||
"github.com/coder/coder/tailnet"
|
||||
)
|
||||
|
||||
// @Summary Get workspace agent by ID
|
||||
// @ID get-workspace-agent-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Agents
|
||||
// @Param workspaceagent path string true "Workspace agent ID" format(uuid)
|
||||
// @Success 200 {object} codersdk.WorkspaceAgent
|
||||
// @Router /workspaceagents/{workspaceagent} [get]
|
||||
func (api *API) workspaceAgent(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
workspaceAgent := httpmw.WorkspaceAgentParam(r)
|
||||
|
@ -66,7 +74,6 @@ func (api *API) workspaceAgent(rw http.ResponseWriter, r *http.Request) {
|
|||
// @Summary Get authorized workspace agent metadata
|
||||
// @ID get-authorized-workspace-agent-metadata
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Agents
|
||||
// @Success 200 {object} codersdk.WorkspaceAgentMetadata
|
||||
|
@ -147,9 +154,10 @@ func (api *API) workspaceAgentMetadata(rw http.ResponseWriter, r *http.Request)
|
|||
}
|
||||
|
||||
// @Summary Submit workspace agent version
|
||||
// @ID submit-workspace-workspace-agent-version
|
||||
// @ID submit-workspace-agent-version
|
||||
// @Security CoderSessionToken
|
||||
// @Produce application/json
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Agents
|
||||
// @Param request body codersdk.PostWorkspaceAgentVersionRequest true "Version request"
|
||||
// @Success 200
|
||||
|
@ -198,6 +206,14 @@ func (api *API) postWorkspaceAgentVersion(rw http.ResponseWriter, r *http.Reques
|
|||
|
||||
// workspaceAgentPTY spawns a PTY and pipes it over a WebSocket.
|
||||
// This is used for the web terminal.
|
||||
//
|
||||
// @Summary Open PTY to workspace agent
|
||||
// @ID open-pty-to-workspace-agent
|
||||
// @Security CoderSessionToken
|
||||
// @Tags Agents
|
||||
// @Param workspaceagent path string true "Workspace agent ID" format(uuid)
|
||||
// @Success 101
|
||||
// @Router /workspaceagents/{workspaceagent}/pty [get]
|
||||
func (api *API) workspaceAgentPTY(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
|
@ -276,6 +292,14 @@ func (api *API) workspaceAgentPTY(rw http.ResponseWriter, r *http.Request) {
|
|||
agent.Bicopy(ctx, wsNetConn, ptNetConn)
|
||||
}
|
||||
|
||||
// @Summary Get listening ports for workspace agent
|
||||
// @ID get-listening-ports-for-workspace-agent
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Agents
|
||||
// @Param workspaceagent path string true "Workspace agent ID" format(uuid)
|
||||
// @Success 200 {object} codersdk.ListeningPortsResponse
|
||||
// @Router /workspaceagents/{workspaceagent}/listening-ports [get]
|
||||
func (api *API) workspaceAgentListeningPorts(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
workspace := httpmw.WorkspaceParam(r)
|
||||
|
@ -443,6 +467,14 @@ func (api *API) dialWorkspaceAgentTailnet(r *http.Request, agentID uuid.UUID) (*
|
|||
}, nil
|
||||
}
|
||||
|
||||
// @Summary Get connection info for workspace agent
|
||||
// @ID get-connection-info-for-workspace-agent
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Agents
|
||||
// @Param workspaceagent path string true "Workspace agent ID" format(uuid)
|
||||
// @Success 200 {object} codersdk.WorkspaceAgentConnectionInfo
|
||||
// @Router /workspaceagents/{workspaceagent}/connection [get]
|
||||
func (api *API) workspaceAgentConnection(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
workspace := httpmw.WorkspaceParam(r)
|
||||
|
@ -458,9 +490,8 @@ func (api *API) workspaceAgentConnection(rw http.ResponseWriter, r *http.Request
|
|||
// @Summary Coordinate workspace agent via Tailnet
|
||||
// @Description It accepts a WebSocket connection to an agent that listens to
|
||||
// @Description incoming connections and publishes node updates.
|
||||
// @ID get-workspace-agent-git-ssh-key-via-tailnet
|
||||
// @ID coordinate-workspace-agent-via-tailnet
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Agents
|
||||
// @Success 101
|
||||
// @Router /workspaceagents/me/coordinate [get]
|
||||
|
@ -622,6 +653,14 @@ func (api *API) workspaceAgentCoordinate(rw http.ResponseWriter, r *http.Request
|
|||
// workspaceAgentClientCoordinate accepts a WebSocket that reads node network updates.
|
||||
// After accept a PubSub starts listening for new connection node updates
|
||||
// which are written to the WebSocket.
|
||||
//
|
||||
// @Summary Coordinate workspace agent
|
||||
// @ID coordinate-workspace-agent
|
||||
// @Security CoderSessionToken
|
||||
// @Tags Agents
|
||||
// @Param workspaceagent path string true "Workspace agent ID" format(uuid)
|
||||
// @Success 101
|
||||
// @Router /workspaceagents/{workspaceagent}/coordinate [get]
|
||||
func (api *API) workspaceAgentClientCoordinate(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
|
@ -784,8 +823,9 @@ func convertWorkspaceAgent(derpMap *tailcfg.DERPMap, coordinator tailnet.Coordin
|
|||
}
|
||||
|
||||
// @Summary Submit workspace agent stats
|
||||
// @ID submit-workspace-workspace-agent-stats
|
||||
// @ID submit-workspace-agent-stats
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce application/json
|
||||
// @Tags Agents
|
||||
// @Param request body codersdk.AgentStats true "Stats request"
|
||||
|
@ -860,9 +900,10 @@ func (api *API) workspaceAgentReportStats(rw http.ResponseWriter, r *http.Reques
|
|||
})
|
||||
}
|
||||
|
||||
// @Summary Submit workspace application health
|
||||
// @ID submit-workspace-workspace-agent-health
|
||||
// @Summary Submit workspace agent application health
|
||||
// @ID submit-workspace-agent-application-health
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce application/json
|
||||
// @Tags Agents
|
||||
// @Param request body codersdk.PostWorkspaceAppHealthsRequest true "Application health request"
|
||||
|
@ -989,7 +1030,6 @@ func (api *API) postWorkspaceAppHealth(rw http.ResponseWriter, r *http.Request)
|
|||
// @Summary Get workspace agent Git auth
|
||||
// @ID get-workspace-agent-git-auth
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Agents
|
||||
// @Param url query string true "Git URL" format(uri)
|
||||
|
|
|
@ -66,7 +66,7 @@ var nonCanonicalHeaders = map[string]string{
|
|||
}
|
||||
|
||||
// @Summary Get applications host
|
||||
// @ID get-app-host
|
||||
// @ID get-applications-host
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Applications
|
||||
|
@ -614,6 +614,13 @@ func (api *API) setWorkspaceAppCookie(rw http.ResponseWriter, r *http.Request, t
|
|||
return true
|
||||
}
|
||||
|
||||
// workspaceApplicationAuth is an endpoint on the main router that handles
|
||||
// redirects from the subdomain handler.
|
||||
//
|
||||
// This endpoint is under /api so we don't return the friendly error page here.
|
||||
// Any errors on this endpoint should be errors that are unlikely to happen
|
||||
// in production unless the user messes with the URL.
|
||||
//
|
||||
// @Summary Redirect to URI with encrypted API key
|
||||
// @ID redirect-to-uri-with-encrypted-api-key
|
||||
// @Security CoderSessionToken
|
||||
|
@ -621,13 +628,6 @@ func (api *API) setWorkspaceAppCookie(rw http.ResponseWriter, r *http.Request, t
|
|||
// @Param redirect_uri query string false "Redirect destination"
|
||||
// @Success 307
|
||||
// @Router /applications/auth-redirect [get]
|
||||
//
|
||||
// workspaceApplicationAuth is an endpoint on the main router that handles
|
||||
// redirects from the subdomain handler.
|
||||
//
|
||||
// This endpoint is under /api so we don't return the friendly error page here.
|
||||
// Any errors on this endpoint should be errors that are unlikely to happen
|
||||
// in production unless the user messes with the URL.
|
||||
func (api *API) workspaceApplicationAuth(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
if api.AppHostname == "" {
|
||||
|
|
|
@ -77,13 +77,13 @@ func (api *API) workspaceBuild(rw http.ResponseWriter, r *http.Request) {
|
|||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Builds
|
||||
// @Param id path string true "Workspace ID" format(uuid)
|
||||
// @Param workspace path string true "Workspace ID" format(uuid)
|
||||
// @Param after_id query string false "After ID" format(uuid)
|
||||
// @Param limit query int false "Page limit"
|
||||
// @Param offset query int false "Page offset"
|
||||
// @Param since query string false "Since timestamp" format(date-time)
|
||||
// @Success 200 {array} codersdk.WorkspaceBuild
|
||||
// @Router /workspaces/{id}/builds [get]
|
||||
// @Router /workspaces/{workspace}/builds [get]
|
||||
func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
workspace := httpmw.WorkspaceParam(r)
|
||||
|
@ -290,13 +290,13 @@ func (api *API) workspaceBuildByBuildNumber(rw http.ResponseWriter, r *http.Requ
|
|||
// @Summary Create workspace build
|
||||
// @ID create-workspace-build
|
||||
// @Security CoderSessionToken
|
||||
// @Accepts json
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Builds
|
||||
// @Param id path string true "Workspace ID" format(uuid)
|
||||
// @Param workspace path string true "Workspace ID" format(uuid)
|
||||
// @Param request body codersdk.CreateWorkspaceBuildRequest true "Create workspace build request"
|
||||
// @Success 200 {object} codersdk.WorkspaceBuild
|
||||
// @Router /workspaces/{id}/builds [post]
|
||||
// @Router /workspaces/{workspace}/builds [post]
|
||||
func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
apiKey := httpmw.APIKey(r)
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
// @Summary Authenticate agent on Azure instance
|
||||
// @ID authenticate-agent-on-azure-instance
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Agents
|
||||
// @Param request body codersdk.AzureInstanceIdentityToken true "Instance identity token"
|
||||
|
@ -45,18 +46,19 @@ func (api *API) postWorkspaceAuthAzureInstanceIdentity(rw http.ResponseWriter, r
|
|||
api.handleAuthInstanceID(rw, r, instanceID)
|
||||
}
|
||||
|
||||
// AWS supports instance identity verification:
|
||||
// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html
|
||||
// Using this, we can exchange a signed instance payload for an agent token.
|
||||
//
|
||||
// @Summary Authenticate agent on AWS instance
|
||||
// @ID authenticate-agent-on-aws-instance
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Agents
|
||||
// @Param request body codersdk.AWSInstanceIdentityToken true "Instance identity token"
|
||||
// @Success 200 {object} codersdk.WorkspaceAgentAuthenticateResponse
|
||||
// @Router /workspaceagents/aws-instance-identity [post]
|
||||
//
|
||||
// AWS supports instance identity verification:
|
||||
// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html
|
||||
// Using this, we can exchange a signed instance payload for an agent token.
|
||||
func (api *API) postWorkspaceAuthAWSInstanceIdentity(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
var req codersdk.AWSInstanceIdentityToken
|
||||
|
@ -74,18 +76,19 @@ func (api *API) postWorkspaceAuthAWSInstanceIdentity(rw http.ResponseWriter, r *
|
|||
api.handleAuthInstanceID(rw, r, identity.InstanceID)
|
||||
}
|
||||
|
||||
// Google Compute Engine supports instance identity verification:
|
||||
// https://cloud.google.com/compute/docs/instances/verifying-instance-identity
|
||||
// Using this, we can exchange a signed instance payload for an agent token.
|
||||
//
|
||||
// @Summary Authenticate agent on Google Cloud instance
|
||||
// @ID authenticate-agent-on-google-cloud-instance
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Agents
|
||||
// @Param request body codersdk.GoogleInstanceIdentityToken true "Instance identity token"
|
||||
// @Success 200 {object} codersdk.WorkspaceAgentAuthenticateResponse
|
||||
// @Router /workspaceagents/google-instance-identity [post]
|
||||
//
|
||||
// Google Compute Engine supports instance identity verification:
|
||||
// https://cloud.google.com/compute/docs/instances/verifying-instance-identity
|
||||
// Using this, we can exchange a signed instance payload for an agent token.
|
||||
func (api *API) postWorkspaceAuthGoogleInstanceIdentity(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
var req codersdk.GoogleInstanceIdentityToken
|
||||
|
|
|
@ -48,10 +48,10 @@ var (
|
|||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Workspaces
|
||||
// @Param id path string true "Workspace ID" format(uuid)
|
||||
// @Param workspace path string true "Workspace ID" format(uuid)
|
||||
// @Param include_deleted query bool false "Return data instead of HTTP 404 if the workspace is deleted"
|
||||
// @Success 200 {object} codersdk.Workspace
|
||||
// @Router /workspaces/{id} [get]
|
||||
// @Router /workspaces/{workspace} [get]
|
||||
func (api *API) workspace(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
workspace := httpmw.WorkspaceParam(r)
|
||||
|
@ -101,8 +101,11 @@ func (api *API) workspace(rw http.ResponseWriter, r *http.Request) {
|
|||
))
|
||||
}
|
||||
|
||||
// workspaces returns all workspaces a user can read.
|
||||
// Optional filters with query params
|
||||
//
|
||||
// @Summary List workspaces
|
||||
// @ID get-workspaces
|
||||
// @ID list-workspaces
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Workspaces
|
||||
|
@ -113,9 +116,6 @@ func (api *API) workspace(rw http.ResponseWriter, r *http.Request) {
|
|||
// @Param has_agent query string false "Filter by agent status" Enums(connected,connecting,disconnected,timeout)
|
||||
// @Success 200 {object} codersdk.WorkspacesResponse
|
||||
// @Router /workspaces [get]
|
||||
//
|
||||
// workspaces returns all workspaces a user can read.
|
||||
// Optional filters with query params
|
||||
func (api *API) workspaces(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
apiKey := httpmw.APIKey(r)
|
||||
|
@ -266,6 +266,8 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request)
|
|||
))
|
||||
}
|
||||
|
||||
// Create a new workspace for the currently authenticated user.
|
||||
//
|
||||
// @Summary Create user workspace by organization
|
||||
// @ID create-user-workspace-by-organization
|
||||
// @Security CoderSessionToken
|
||||
|
@ -275,8 +277,6 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request)
|
|||
// @Param user path string true "Username, UUID, or me"
|
||||
// @Success 200 {object} codersdk.Workspace
|
||||
// @Router /organizations/{organization}/members/{user}/workspaces [post]
|
||||
//
|
||||
// Create a new workspace for the currently authenticated user.
|
||||
func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
@ -558,7 +558,6 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
|
|||
// @ID update-workspace-metadata-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Workspaces
|
||||
// @Param workspace path string true "Workspace ID" format(uuid)
|
||||
// @Param request body codersdk.UpdateWorkspaceRequest true "Metadata update request"
|
||||
|
@ -648,7 +647,6 @@ func (api *API) patchWorkspace(rw http.ResponseWriter, r *http.Request) {
|
|||
// @ID update-workspace-autostart-schedule-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Workspaces
|
||||
// @Param workspace path string true "Workspace ID" format(uuid)
|
||||
// @Param request body codersdk.UpdateWorkspaceAutostartRequest true "Schedule update request"
|
||||
|
@ -711,7 +709,6 @@ func (api *API) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) {
|
|||
// @ID update-workspace-ttl-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Workspaces
|
||||
// @Param workspace path string true "Workspace ID" format(uuid)
|
||||
// @Param request body codersdk.UpdateWorkspaceTTLRequest true "Workspace TTL update request"
|
||||
|
@ -875,7 +872,7 @@ func (api *API) putExtendWorkspace(rw http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// @Summary Watch workspace by ID
|
||||
// @ID watch-workspace-id
|
||||
// @ID watch-workspace-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Produce text/event-stream
|
||||
// @Tags Workspaces
|
||||
|
|
|
@ -88,14 +88,14 @@ type AuditDiffField struct {
|
|||
}
|
||||
|
||||
type AuditLog struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
RequestID uuid.UUID `json:"request_id"`
|
||||
Time time.Time `json:"time"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
ID uuid.UUID `json:"id" format:"uuid"`
|
||||
RequestID uuid.UUID `json:"request_id" format:"uuid"`
|
||||
Time time.Time `json:"time" format:"date-time"`
|
||||
OrganizationID uuid.UUID `json:"organization_id" format:"uuid"`
|
||||
IP netip.Addr `json:"ip"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
ResourceType ResourceType `json:"resource_type"`
|
||||
ResourceID uuid.UUID `json:"resource_id"`
|
||||
ResourceID uuid.UUID `json:"resource_id" format:"uuid"`
|
||||
// ResourceTarget is the name of the resource.
|
||||
ResourceTarget string `json:"resource_target"`
|
||||
ResourceIcon string `json:"resource_icon"`
|
||||
|
@ -123,8 +123,8 @@ type AuditLogResponse struct {
|
|||
type CreateTestAuditLogRequest struct {
|
||||
Action AuditAction `json:"action,omitempty" enums:"create,write,delete,start,stop"`
|
||||
ResourceType ResourceType `json:"resource_type,omitempty" enums:"organization,template,template_version,user,workspace,workspace_build,git_ssh_key,api_key,group"`
|
||||
ResourceID uuid.UUID `json:"resource_id,omitempty"`
|
||||
Time time.Time `json:"time,omitempty"`
|
||||
ResourceID uuid.UUID `json:"resource_id,omitempty" format:"uuid"`
|
||||
Time time.Time `json:"time,omitempty" format:"date-time"`
|
||||
}
|
||||
|
||||
// AuditLogs retrieves audit logs from the given page.
|
||||
|
|
|
@ -67,7 +67,7 @@ type CreateTemplateRequest struct {
|
|||
// This is required on creation to enable a user-flow of validating a
|
||||
// template works. There is no reason the data-model cannot support empty
|
||||
// templates, but it doesn't make sense for users.
|
||||
VersionID uuid.UUID `json:"template_version_id" validate:"required"`
|
||||
VersionID uuid.UUID `json:"template_version_id" validate:"required" format:"uuid"`
|
||||
ParameterValues []CreateParameterRequest `json:"parameter_values,omitempty"`
|
||||
|
||||
// DefaultTTLMillis allows optionally specifying the default TTL
|
||||
|
@ -81,7 +81,7 @@ type CreateTemplateRequest struct {
|
|||
|
||||
// CreateWorkspaceRequest provides options for creating a new workspace.
|
||||
type CreateWorkspaceRequest struct {
|
||||
TemplateID uuid.UUID `json:"template_id" validate:"required"`
|
||||
TemplateID uuid.UUID `json:"template_id" validate:"required" format:"uuid"`
|
||||
Name string `json:"name" validate:"workspace_name,required"`
|
||||
AutostartSchedule *string `json:"autostart_schedule"`
|
||||
TTLMillis *int64 `json:"ttl_ms,omitempty"`
|
||||
|
|
|
@ -14,7 +14,7 @@ type Pagination struct {
|
|||
// Offset for better performance. To use it as an alternative,
|
||||
// set AfterID to the last UUID returned by the previous
|
||||
// request.
|
||||
AfterID uuid.UUID `json:"after_id,omitempty"`
|
||||
AfterID uuid.UUID `json:"after_id,omitempty" format:"uuid"`
|
||||
// Limit sets the maximum number of users to be returned
|
||||
// in a single page. If the limit is <= 0, there is no limit
|
||||
// and all users are returned.
|
||||
|
|
|
@ -176,7 +176,7 @@ func (c *Client) UpdateActiveTemplateVersion(ctx context.Context, template uuid.
|
|||
// TemplateVersionsByTemplateRequest defines the request parameters for
|
||||
// TemplateVersionsByTemplate.
|
||||
type TemplateVersionsByTemplateRequest struct {
|
||||
TemplateID uuid.UUID `json:"template_id" validate:"required"`
|
||||
TemplateID uuid.UUID `json:"template_id" validate:"required" format:"uuid"`
|
||||
Pagination
|
||||
}
|
||||
|
||||
|
@ -210,7 +210,7 @@ func (c *Client) TemplateVersionByName(ctx context.Context, template uuid.UUID,
|
|||
}
|
||||
|
||||
type DAUEntry struct {
|
||||
Date time.Time `json:"date"`
|
||||
Date time.Time `json:"date" format:"date-time"`
|
||||
Amount int `json:"amount"`
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ type WorkspacesResponse struct {
|
|||
|
||||
// CreateWorkspaceBuildRequest provides options to update the latest workspace build.
|
||||
type CreateWorkspaceBuildRequest struct {
|
||||
TemplateVersionID uuid.UUID `json:"template_version_id,omitempty"`
|
||||
TemplateVersionID uuid.UUID `json:"template_version_id,omitempty" format:"uuid"`
|
||||
Transition WorkspaceTransition `json:"transition" validate:"oneof=create start stop delete,required"`
|
||||
DryRun bool `json:"dry_run,omitempty"`
|
||||
ProvisionerState []byte `json:"state,omitempty"`
|
||||
|
@ -245,7 +245,7 @@ func (c *Client) UpdateWorkspaceTTL(ctx context.Context, id uuid.UUID, req Updat
|
|||
// PutExtendWorkspaceRequest is a request to extend the deadline of
|
||||
// the active workspace build.
|
||||
type PutExtendWorkspaceRequest struct {
|
||||
Deadline time.Time `json:"deadline" validate:"required"`
|
||||
Deadline time.Time `json:"deadline" validate:"required" format:"date-time"`
|
||||
}
|
||||
|
||||
// PutExtendWorkspace updates the deadline for resources of the latest workspace build.
|
||||
|
|
|
@ -142,7 +142,7 @@ curl -X POST http://coder-server:8080/api/v2/workspaceagents/google-instance-ide
|
|||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Submit workspace application health
|
||||
## Submit workspace agent application health
|
||||
|
||||
### Code samples
|
||||
|
||||
|
@ -437,3 +437,271 @@ curl -X POST http://coder-server:8080/api/v2/workspaceagents/me/report-stats \
|
|||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.AgentStatsResponse](schemas.md#codersdkagentstatsresponse) |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Get workspace agent by ID
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/workspaceagents/{workspaceagent} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /workspaceagents/{workspaceagent}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---------------- | ---- | ------------ | -------- | ------------------ |
|
||||
| `workspaceagent` | path | string(uuid) | true | Workspace agent ID |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"apps": [
|
||||
{
|
||||
"command": "string",
|
||||
"display_name": "string",
|
||||
"external": true,
|
||||
"health": "disabled",
|
||||
"healthcheck": {
|
||||
"interval": 0,
|
||||
"threshold": 0,
|
||||
"url": "string"
|
||||
},
|
||||
"icon": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"sharing_level": "owner",
|
||||
"slug": "string",
|
||||
"subdomain": true,
|
||||
"url": "string"
|
||||
}
|
||||
],
|
||||
"architecture": "string",
|
||||
"connection_timeout_seconds": 0,
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"directory": "string",
|
||||
"disconnected_at": "2019-08-24T14:15:22Z",
|
||||
"environment_variables": {
|
||||
"property1": "string",
|
||||
"property2": "string"
|
||||
},
|
||||
"first_connected_at": "2019-08-24T14:15:22Z",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"instance_id": "string",
|
||||
"last_connected_at": "2019-08-24T14:15:22Z",
|
||||
"latency": {
|
||||
"property1": {
|
||||
"latency_ms": 0,
|
||||
"preferred": true
|
||||
},
|
||||
"property2": {
|
||||
"latency_ms": 0,
|
||||
"preferred": true
|
||||
}
|
||||
},
|
||||
"name": "string",
|
||||
"operating_system": "string",
|
||||
"resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
|
||||
"startup_script": "string",
|
||||
"status": "connecting",
|
||||
"troubleshooting_url": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"version": "string"
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------------------ |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.WorkspaceAgent](schemas.md#codersdkworkspaceagent) |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Get connection info for workspace agent
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/workspaceagents/{workspaceagent}/connection \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /workspaceagents/{workspaceagent}/connection`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---------------- | ---- | ------------ | -------- | ------------------ |
|
||||
| `workspaceagent` | path | string(uuid) | true | Workspace agent ID |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"derp_map": {
|
||||
"omitDefaultRegions": true,
|
||||
"regions": {
|
||||
"property1": {
|
||||
"avoid": true,
|
||||
"embeddedRelay": true,
|
||||
"nodes": [
|
||||
{
|
||||
"certName": "string",
|
||||
"derpport": 0,
|
||||
"forceHTTP": true,
|
||||
"hostName": "string",
|
||||
"insecureForTests": true,
|
||||
"ipv4": "string",
|
||||
"ipv6": "string",
|
||||
"name": "string",
|
||||
"regionID": 0,
|
||||
"stunonly": true,
|
||||
"stunport": 0,
|
||||
"stuntestIP": "string"
|
||||
}
|
||||
],
|
||||
"regionCode": "string",
|
||||
"regionID": 0,
|
||||
"regionName": "string"
|
||||
},
|
||||
"property2": {
|
||||
"avoid": true,
|
||||
"embeddedRelay": true,
|
||||
"nodes": [
|
||||
{
|
||||
"certName": "string",
|
||||
"derpport": 0,
|
||||
"forceHTTP": true,
|
||||
"hostName": "string",
|
||||
"insecureForTests": true,
|
||||
"ipv4": "string",
|
||||
"ipv6": "string",
|
||||
"name": "string",
|
||||
"regionID": 0,
|
||||
"stunonly": true,
|
||||
"stunport": 0,
|
||||
"stuntestIP": "string"
|
||||
}
|
||||
],
|
||||
"regionCode": "string",
|
||||
"regionID": 0,
|
||||
"regionName": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------- |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.WorkspaceAgentConnectionInfo](schemas.md#codersdkworkspaceagentconnectioninfo) |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Coordinate workspace agent
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/workspaceagents/{workspaceagent}/coordinate \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /workspaceagents/{workspaceagent}/coordinate`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---------------- | ---- | ------------ | -------- | ------------------ |
|
||||
| `workspaceagent` | path | string(uuid) | true | Workspace agent 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 listening ports for workspace agent
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/workspaceagents/{workspaceagent}/listening-ports \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /workspaceagents/{workspaceagent}/listening-ports`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---------------- | ---- | ------------ | -------- | ------------------ |
|
||||
| `workspaceagent` | path | string(uuid) | true | Workspace agent ID |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"ports": [
|
||||
{
|
||||
"network": "tcp",
|
||||
"port": 0,
|
||||
"process_name": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------- |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.ListeningPortsResponse](schemas.md#codersdklisteningportsresponse) |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Open PTY to workspace agent
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/workspaceagents/{workspaceagent}/pty \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /workspaceagents/{workspaceagent}/pty`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---------------- | ---- | ------------ | -------- | ------------------ |
|
||||
| `workspaceagent` | path | string(uuid) | true | Workspace agent 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).
|
||||
|
|
|
@ -47,18 +47,18 @@ curl -X GET http://coder-server:8080/api/v2/audit?q=string \
|
|||
"secret": true
|
||||
}
|
||||
},
|
||||
"id": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"ip": "string",
|
||||
"is_deleted": true,
|
||||
"organization_id": "string",
|
||||
"request_id": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"request_id": "266ea41d-adf5-480b-af50-15b940c2b846",
|
||||
"resource_icon": "string",
|
||||
"resource_id": "string",
|
||||
"resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
|
||||
"resource_link": "string",
|
||||
"resource_target": "string",
|
||||
"resource_type": "organization",
|
||||
"status_code": 0,
|
||||
"time": "string",
|
||||
"time": "2019-08-24T14:15:22Z",
|
||||
"user": {
|
||||
"avatar_url": "http://example.com",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
|
@ -108,9 +108,9 @@ curl -X POST http://coder-server:8080/api/v2/audit/testgenerate \
|
|||
```json
|
||||
{
|
||||
"action": "create",
|
||||
"resource_id": "string",
|
||||
"resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
|
||||
"resource_type": "organization",
|
||||
"time": "string"
|
||||
"time": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -740,22 +740,22 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
|
|||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/workspaces/{id}/builds \
|
||||
curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace}/builds \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /workspaces/{id}/builds`
|
||||
`GET /workspaces/{workspace}/builds`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---------- | ----- | ----------------- | -------- | --------------- |
|
||||
| `id` | path | string(uuid) | true | Workspace ID |
|
||||
| `after_id` | query | string(uuid) | false | After ID |
|
||||
| `limit` | query | integer | false | Page limit |
|
||||
| `offset` | query | integer | false | Page offset |
|
||||
| `since` | query | string(date-time) | false | Since timestamp |
|
||||
| Name | In | Type | Required | Description |
|
||||
| ----------- | ----- | ----------------- | -------- | --------------- |
|
||||
| `workspace` | path | string(uuid) | true | Workspace ID |
|
||||
| `after_id` | query | string(uuid) | false | After ID |
|
||||
| `limit` | query | integer | false | Page limit |
|
||||
| `offset` | query | integer | false | Page offset |
|
||||
| `since` | query | string(date-time) | false | Since timestamp |
|
||||
|
||||
### Example responses
|
||||
|
||||
|
@ -1019,13 +1019,13 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
|
|||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X POST http://coder-server:8080/api/v2/workspaces/{id}/builds \
|
||||
curl -X POST http://coder-server:8080/api/v2/workspaces/{workspace}/builds \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`POST /workspaces/{id}/builds`
|
||||
`POST /workspaces/{workspace}/builds`
|
||||
|
||||
> Body parameter
|
||||
|
||||
|
@ -1043,17 +1043,17 @@ curl -X POST http://coder-server:8080/api/v2/workspaces/{id}/builds \
|
|||
}
|
||||
],
|
||||
"state": [0],
|
||||
"template_version_id": "string",
|
||||
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
|
||||
"transition": "create"
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ------ | ---- | -------------------------------------------------------------------------------------- | -------- | ------------------------------ |
|
||||
| `id` | path | string(uuid) | true | Workspace ID |
|
||||
| `body` | body | [codersdk.CreateWorkspaceBuildRequest](schemas.md#codersdkcreateworkspacebuildrequest) | true | Create workspace build request |
|
||||
| Name | In | Type | Required | Description |
|
||||
| ----------- | ---- | -------------------------------------------------------------------------------------- | -------- | ------------------------------ |
|
||||
| `workspace` | path | string(uuid) | true | Workspace ID |
|
||||
| `body` | body | [codersdk.CreateWorkspaceBuildRequest](schemas.md#codersdkcreateworkspacebuildrequest) | true | Create workspace build request |
|
||||
|
||||
### Example responses
|
||||
|
||||
|
|
|
@ -242,18 +242,18 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
|
|||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/groups/{groupName} \
|
||||
curl -X GET http://coder-server:8080/api/v2/groups/{group} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /groups/{groupName}`
|
||||
`GET /groups/{group}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ----------- | ---- | ------ | -------- | ----------- |
|
||||
| `groupName` | path | string | true | Group name |
|
||||
| Name | In | Type | Required | Description |
|
||||
| ------- | ---- | ------ | -------- | ----------- |
|
||||
| `group` | path | string | true | Group name |
|
||||
|
||||
### Example responses
|
||||
|
||||
|
@ -295,29 +295,121 @@ curl -X GET http://coder-server:8080/api/v2/groups/{groupName} \
|
|||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Delete license
|
||||
## Delete group by name
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X DELETE http://coder-server:8080/api/v2/license/{id} \
|
||||
curl -X DELETE http://coder-server:8080/api/v2/groups/{group} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`DELETE /license/{id}`
|
||||
`DELETE /groups/{group}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---- | ---- | -------------- | -------- | ----------- |
|
||||
| `id` | path | string(number) | true | License ID |
|
||||
| Name | In | Type | Required | Description |
|
||||
| ------- | ---- | ------ | -------- | ----------- |
|
||||
| `group` | path | string | true | Group name |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"avatar_url": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"members": [
|
||||
{
|
||||
"avatar_url": "http://example.com",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"email": "user@example.com",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"last_seen_at": "2019-08-24T14:15:22Z",
|
||||
"organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"],
|
||||
"roles": [
|
||||
{
|
||||
"display_name": "string",
|
||||
"name": "string"
|
||||
}
|
||||
],
|
||||
"status": "active",
|
||||
"username": "string"
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"quota_allowance": 0
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ------ |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | |
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------ |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Group](schemas.md#codersdkgroup) |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Update group by name
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X PATCH http://coder-server:8080/api/v2/groups/{group} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`PATCH /groups/{group}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ------- | ---- | ------ | -------- | ----------- |
|
||||
| `group` | path | string | true | Group name |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"avatar_url": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"members": [
|
||||
{
|
||||
"avatar_url": "http://example.com",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"email": "user@example.com",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"last_seen_at": "2019-08-24T14:15:22Z",
|
||||
"organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"],
|
||||
"roles": [
|
||||
{
|
||||
"display_name": "string",
|
||||
"name": "string"
|
||||
}
|
||||
],
|
||||
"status": "active",
|
||||
"username": "string"
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"quota_allowance": 0
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------ |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Group](schemas.md#codersdkgroup) |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
|
@ -369,6 +461,32 @@ Status Code **200**
|
|||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Delete license
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X DELETE http://coder-server:8080/api/v2/licenses/{id} \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`DELETE /licenses/{id}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---- | ---- | -------------- | -------- | ----------- |
|
||||
| `id` | path | string(number) | true | License ID |
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ------ |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Get groups by organization
|
||||
|
||||
### Code samples
|
||||
|
@ -462,6 +580,66 @@ Status Code **200**
|
|||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Get group by organization and group name
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/groups/{groupName} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /organizations/{organization}/groups/{groupName}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| -------------- | ---- | ------------ | -------- | --------------- |
|
||||
| `organization` | path | string(uuid) | true | Organization ID |
|
||||
| `groupName` | path | string | true | Group name |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"avatar_url": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"members": [
|
||||
{
|
||||
"avatar_url": "http://example.com",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"email": "user@example.com",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"last_seen_at": "2019-08-24T14:15:22Z",
|
||||
"organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"],
|
||||
"roles": [
|
||||
{
|
||||
"display_name": "string",
|
||||
"name": "string"
|
||||
}
|
||||
],
|
||||
"status": "active",
|
||||
"username": "string"
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"quota_allowance": 0
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------ |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Group](schemas.md#codersdkgroup) |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Get provisioner daemons
|
||||
|
||||
### Code samples
|
||||
|
@ -609,6 +787,26 @@ Status Code **200**
|
|||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## SCIM 2.0: Get users
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/scim/v2/Users \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /scim/v2/Users`
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ------ |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## SCIM 2.0: Create new user
|
||||
|
||||
### Code samples
|
||||
|
|
|
@ -323,18 +323,18 @@
|
|||
"secret": true
|
||||
}
|
||||
},
|
||||
"id": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"ip": "string",
|
||||
"is_deleted": true,
|
||||
"organization_id": "string",
|
||||
"request_id": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"request_id": "266ea41d-adf5-480b-af50-15b940c2b846",
|
||||
"resource_icon": "string",
|
||||
"resource_id": "string",
|
||||
"resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
|
||||
"resource_link": "string",
|
||||
"resource_target": "string",
|
||||
"resource_type": "organization",
|
||||
"status_code": 0,
|
||||
"time": "string",
|
||||
"time": "2019-08-24T14:15:22Z",
|
||||
"user": {
|
||||
"avatar_url": "http://example.com",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
|
@ -399,18 +399,18 @@
|
|||
"secret": true
|
||||
}
|
||||
},
|
||||
"id": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"ip": "string",
|
||||
"is_deleted": true,
|
||||
"organization_id": "string",
|
||||
"request_id": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"request_id": "266ea41d-adf5-480b-af50-15b940c2b846",
|
||||
"resource_icon": "string",
|
||||
"resource_id": "string",
|
||||
"resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
|
||||
"resource_link": "string",
|
||||
"resource_target": "string",
|
||||
"resource_type": "organization",
|
||||
"status_code": 0,
|
||||
"time": "string",
|
||||
"time": "2019-08-24T14:15:22Z",
|
||||
"user": {
|
||||
"avatar_url": "http://example.com",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
|
@ -731,7 +731,7 @@ CreateParameterRequest is a structure used to create a new parameter value for a
|
|||
"source_value": "string"
|
||||
}
|
||||
],
|
||||
"template_version_id": "string"
|
||||
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -778,9 +778,9 @@ CreateParameterRequest is a structure used to create a new parameter value for a
|
|||
```json
|
||||
{
|
||||
"action": "create",
|
||||
"resource_id": "string",
|
||||
"resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
|
||||
"resource_type": "organization",
|
||||
"time": "string"
|
||||
"time": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -871,7 +871,7 @@ CreateParameterRequest is a structure used to create a new parameter value for a
|
|||
}
|
||||
],
|
||||
"state": [0],
|
||||
"template_version_id": "string",
|
||||
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
|
||||
"transition": "create"
|
||||
}
|
||||
```
|
||||
|
@ -901,7 +901,7 @@ CreateParameterRequest is a structure used to create a new parameter value for a
|
|||
```json
|
||||
{
|
||||
"amount": 0,
|
||||
"date": "string"
|
||||
"date": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -2561,6 +2561,58 @@ CreateParameterRequest is a structure used to create a new parameter value for a
|
|||
| `uploaded_at` | string | false | | |
|
||||
| `uuid` | string | false | | |
|
||||
|
||||
## codersdk.ListeningPort
|
||||
|
||||
```json
|
||||
{
|
||||
"network": "tcp",
|
||||
"port": 0,
|
||||
"process_name": "string"
|
||||
}
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| -------------- | -------------------------------------------------------------- | -------- | ------------ | ------------------------ |
|
||||
| `network` | [codersdk.ListeningPortNetwork](#codersdklisteningportnetwork) | false | | only "tcp" at the moment |
|
||||
| `port` | integer | false | | |
|
||||
| `process_name` | string | false | | may be empty |
|
||||
|
||||
## codersdk.ListeningPortNetwork
|
||||
|
||||
```json
|
||||
"tcp"
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
| Value |
|
||||
| ----- |
|
||||
| `tcp` |
|
||||
|
||||
## codersdk.ListeningPortsResponse
|
||||
|
||||
```json
|
||||
{
|
||||
"ports": [
|
||||
{
|
||||
"network": "tcp",
|
||||
"port": 0,
|
||||
"process_name": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ------- | --------------------------------------------------------- | -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `ports` | array of [codersdk.ListeningPort](#codersdklisteningport) | false | | If there are no ports in the list, nothing should be displayed in the UI. There must not be a "no ports available" message or anything similar, as there will always be no ports displayed on platforms where our port detection logic is unsupported. |
|
||||
|
||||
## codersdk.LogLevel
|
||||
|
||||
```json
|
||||
|
@ -3463,7 +3515,7 @@ Parameter represents a set value for the scope.
|
|||
|
||||
```json
|
||||
{
|
||||
"deadline": "string"
|
||||
"deadline": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -3907,7 +3959,7 @@ Parameter represents a set value for the scope.
|
|||
"entries": [
|
||||
{
|
||||
"amount": 0,
|
||||
"date": "string"
|
||||
"date": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -4617,6 +4669,70 @@ Parameter represents a set value for the scope.
|
|||
| --------------- | ------ | -------- | ------------ | ----------- |
|
||||
| `session_token` | string | false | | |
|
||||
|
||||
## codersdk.WorkspaceAgentConnectionInfo
|
||||
|
||||
```json
|
||||
{
|
||||
"derp_map": {
|
||||
"omitDefaultRegions": true,
|
||||
"regions": {
|
||||
"property1": {
|
||||
"avoid": true,
|
||||
"embeddedRelay": true,
|
||||
"nodes": [
|
||||
{
|
||||
"certName": "string",
|
||||
"derpport": 0,
|
||||
"forceHTTP": true,
|
||||
"hostName": "string",
|
||||
"insecureForTests": true,
|
||||
"ipv4": "string",
|
||||
"ipv6": "string",
|
||||
"name": "string",
|
||||
"regionID": 0,
|
||||
"stunonly": true,
|
||||
"stunport": 0,
|
||||
"stuntestIP": "string"
|
||||
}
|
||||
],
|
||||
"regionCode": "string",
|
||||
"regionID": 0,
|
||||
"regionName": "string"
|
||||
},
|
||||
"property2": {
|
||||
"avoid": true,
|
||||
"embeddedRelay": true,
|
||||
"nodes": [
|
||||
{
|
||||
"certName": "string",
|
||||
"derpport": 0,
|
||||
"forceHTTP": true,
|
||||
"hostName": "string",
|
||||
"insecureForTests": true,
|
||||
"ipv4": "string",
|
||||
"ipv6": "string",
|
||||
"name": "string",
|
||||
"regionID": 0,
|
||||
"stunonly": true,
|
||||
"stunport": 0,
|
||||
"stuntestIP": "string"
|
||||
}
|
||||
],
|
||||
"regionCode": "string",
|
||||
"regionID": 0,
|
||||
"regionName": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ---------- | ---------------------------------- | -------- | ------------ | ----------- |
|
||||
| `derp_map` | [tailcfg.DERPMap](#tailcfgderpmap) | false | | |
|
||||
|
||||
## codersdk.WorkspaceAgentGitAuthResponse
|
||||
|
||||
```json
|
||||
|
|
|
@ -204,7 +204,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
|
|||
"source_value": "string"
|
||||
}
|
||||
],
|
||||
"template_version_id": "string"
|
||||
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -630,18 +630,18 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
|
|||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/templates/{id} \
|
||||
curl -X GET http://coder-server:8080/api/v2/templates/{template} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /templates/{id}`
|
||||
`GET /templates/{template}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---- | ---- | ------------ | -------- | ----------- |
|
||||
| `id` | path | string(uuid) | true | Template ID |
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---------- | ---- | ------------ | -------- | ----------- |
|
||||
| `template` | path | string(uuid) | true | Template ID |
|
||||
|
||||
### Example responses
|
||||
|
||||
|
@ -692,18 +692,18 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
|
|||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X DELETE http://coder-server:8080/api/v2/templates/{id} \
|
||||
curl -X DELETE http://coder-server:8080/api/v2/templates/{template} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`DELETE /templates/{id}`
|
||||
`DELETE /templates/{template}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---- | ---- | ------------ | -------- | ----------- |
|
||||
| `id` | path | string(uuid) | true | Template ID |
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---------- | ---- | ------------ | -------- | ----------- |
|
||||
| `template` | path | string(uuid) | true | Template ID |
|
||||
|
||||
### Example responses
|
||||
|
||||
|
@ -736,18 +736,18 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
|
|||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X PATCH http://coder-server:8080/api/v2/templates/{id} \
|
||||
curl -X PATCH http://coder-server:8080/api/v2/templates/{template} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`PATCH /templates/{id}`
|
||||
`PATCH /templates/{template}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---- | ---- | ------------ | -------- | ----------- |
|
||||
| `id` | path | string(uuid) | true | Template ID |
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---------- | ---- | ------------ | -------- | ----------- |
|
||||
| `template` | path | string(uuid) | true | Template ID |
|
||||
|
||||
### Example responses
|
||||
|
||||
|
@ -798,18 +798,18 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
|
|||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/templates/{id}/daus \
|
||||
curl -X GET http://coder-server:8080/api/v2/templates/{template}/daus \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /templates/{id}/daus`
|
||||
`GET /templates/{template}/daus`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---- | ---- | ------------ | -------- | ----------- |
|
||||
| `id` | path | string(uuid) | true | Template ID |
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---------- | ---- | ------------ | -------- | ----------- |
|
||||
| `template` | path | string(uuid) | true | Template ID |
|
||||
|
||||
### Example responses
|
||||
|
||||
|
@ -820,7 +820,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{id}/daus \
|
|||
"entries": [
|
||||
{
|
||||
"amount": 0,
|
||||
"date": "string"
|
||||
"date": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -840,18 +840,18 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
|
|||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/templates/{id}/versions \
|
||||
curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /templates/{id}/versions`
|
||||
`GET /templates/{template}/versions`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---------- | ----- | ------------ | -------- | ----------- |
|
||||
| `id` | path | string(uuid) | true | Template ID |
|
||||
| `template` | path | string(uuid) | true | Template ID |
|
||||
| `after_id` | query | string(uuid) | false | After ID |
|
||||
| `limit` | query | integer | false | Page limit |
|
||||
| `offset` | query | integer | false | Page offset |
|
||||
|
@ -971,13 +971,13 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
|
|||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X PATCH http://coder-server:8080/api/v2/templates/{id}/versions \
|
||||
curl -X PATCH http://coder-server:8080/api/v2/templates/{template}/versions \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`PATCH /templates/{id}/versions`
|
||||
`PATCH /templates/{template}/versions`
|
||||
|
||||
> Body parameter
|
||||
|
||||
|
@ -989,10 +989,10 @@ curl -X PATCH http://coder-server:8080/api/v2/templates/{id}/versions \
|
|||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ------ | ---- | -------------------------------------------------------------------------------------- | -------- | ------------------------- |
|
||||
| `id` | path | string(uuid) | true | Template ID |
|
||||
| `body` | body | [codersdk.UpdateActiveTemplateVersion](schemas.md#codersdkupdateactivetemplateversion) | true | Modified template version |
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---------- | ---- | -------------------------------------------------------------------------------------- | -------- | ------------------------- |
|
||||
| `template` | path | string(uuid) | true | Template ID |
|
||||
| `body` | body | [codersdk.UpdateActiveTemplateVersion](schemas.md#codersdkupdateactivetemplateversion) | true | Modified template version |
|
||||
|
||||
### Example responses
|
||||
|
||||
|
@ -1025,18 +1025,18 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
|
|||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/templates/{id}/versions/{templateversionname} \
|
||||
curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions/{templateversionname} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /templates/{id}/versions/{templateversionname}`
|
||||
`GET /templates/{template}/versions/{templateversionname}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| --------------------- | ---- | ------------ | -------- | --------------------- |
|
||||
| `id` | path | string(uuid) | true | Template ID |
|
||||
| `template` | path | string(uuid) | true | Template ID |
|
||||
| `templateversionname` | path | string | true | Template version name |
|
||||
|
||||
### Example responses
|
||||
|
@ -1340,19 +1340,19 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
|
|||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/dry-run/{jobid} \
|
||||
curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/dry-run/{jobID} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /templateversions/{templateversion}/dry-run/{jobid}`
|
||||
`GET /templateversions/{templateversion}/dry-run/{jobID}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ----------------- | ---- | ------------ | -------- | ------------------- |
|
||||
| `templateversion` | path | string(uuid) | true | Template version ID |
|
||||
| `jobid` | path | string(uuid) | true | Job ID |
|
||||
| `jobID` | path | string(uuid) | true | Job ID |
|
||||
|
||||
### Example responses
|
||||
|
||||
|
@ -1390,17 +1390,18 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
|
|||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X PATCH http://coder-server:8080/api/v2/templateversions/{templateversion}/dry-run/{jobid}/cancel \
|
||||
curl -X PATCH http://coder-server:8080/api/v2/templateversions/{templateversion}/dry-run/{jobID}/cancel \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`PATCH /templateversions/{templateversion}/dry-run/{jobid}/cancel`
|
||||
`PATCH /templateversions/{templateversion}/dry-run/{jobID}/cancel`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ----------------- | ---- | ------------ | -------- | ------------------- |
|
||||
| `jobID` | path | string(uuid) | true | Job ID |
|
||||
| `templateversion` | path | string(uuid) | true | Template version ID |
|
||||
|
||||
### Example responses
|
||||
|
@ -1434,19 +1435,19 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
|
|||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/dry-run/{jobid}/logs \
|
||||
curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/dry-run/{jobID}/logs \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /templateversions/{templateversion}/dry-run/{jobid}/logs`
|
||||
`GET /templateversions/{templateversion}/dry-run/{jobID}/logs`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ----------------- | ----- | ------------ | -------- | --------------------- |
|
||||
| `templateversion` | path | string(uuid) | true | Template version ID |
|
||||
| `jobid` | path | string(uuid) | true | Job ID |
|
||||
| `jobID` | path | string(uuid) | true | Job ID |
|
||||
| `before` | query | integer | false | Before Unix timestamp |
|
||||
| `after` | query | integer | false | After Unix timestamp |
|
||||
| `follow` | query | boolean | false | Follow log stream |
|
||||
|
@ -1508,19 +1509,19 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
|
|||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/dry-run/{jobid}/resources \
|
||||
curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/dry-run/{jobID}/resources \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /templateversions/{templateversion}/dry-run/{jobid}/resources`
|
||||
`GET /templateversions/{templateversion}/dry-run/{jobID}/resources`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ----------------- | ---- | ------------ | -------- | ------------------- |
|
||||
| `templateversion` | path | string(uuid) | true | Template version ID |
|
||||
| `jobid` | path | string(uuid) | true | Job ID |
|
||||
| `jobID` | path | string(uuid) | true | Job ID |
|
||||
|
||||
### Example responses
|
||||
|
||||
|
|
|
@ -511,18 +511,18 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
|
|||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/workspaces/{id} \
|
||||
curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /workspaces/{id}`
|
||||
`GET /workspaces/{workspace}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ----------------- | ----- | ------------ | -------- | ----------------------------------------------------------- |
|
||||
| `id` | path | string(uuid) | true | Workspace ID |
|
||||
| `workspace` | path | string(uuid) | true | Workspace ID |
|
||||
| `include_deleted` | query | boolean | false | Return data instead of HTTP 404 if the workspace is deleted |
|
||||
|
||||
### Example responses
|
||||
|
@ -755,7 +755,7 @@ curl -X PUT http://coder-server:8080/api/v2/workspaces/{workspace}/extend \
|
|||
|
||||
```json
|
||||
{
|
||||
"deadline": "string"
|
||||
"deadline": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ func validateHexColor(color string) error {
|
|||
// @Summary Update appearance
|
||||
// @ID update-appearance
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Enterprise
|
||||
// @Param request body codersdk.AppearanceConfig true "Update appearance request"
|
||||
|
|
|
@ -87,7 +87,7 @@ func New(ctx context.Context, options *Options) (*API, error) {
|
|||
httpmw.ExtractGroupByNameParam(api.Database),
|
||||
)
|
||||
|
||||
r.Get("/", api.group)
|
||||
r.Get("/", api.groupByOrganization)
|
||||
})
|
||||
})
|
||||
r.Route("/organizations/{organization}/provisionerdaemons", func(r chi.Router) {
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package coderdenttest_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
"github.com/coder/coder/enterprise/coderd/coderdenttest"
|
||||
)
|
||||
|
||||
func TestEnterpriseEndpointsDocumented(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
swaggerComments, err := coderdtest.ParseSwaggerComments("..", "../../../coderd")
|
||||
require.NoError(t, err, "can't parse swagger comments")
|
||||
|
||||
_, _, api := coderdenttest.NewWithAPI(t, nil)
|
||||
coderdtest.VerifySwaggerDefinitions(t, api.AGPL.APIHandler, swaggerComments)
|
||||
}
|
|
@ -80,6 +80,14 @@ func (api *API) postGroupByOrganization(rw http.ResponseWriter, r *http.Request)
|
|||
httpapi.Write(ctx, rw, http.StatusCreated, convertGroup(group, nil))
|
||||
}
|
||||
|
||||
// @Summary Update group by name
|
||||
// @ID update-group-by-name
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Enterprise
|
||||
// @Param group path string true "Group name"
|
||||
// @Success 200 {object} codersdk.Group
|
||||
// @Router /groups/{group} [patch]
|
||||
func (api *API) patchGroup(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
@ -236,6 +244,14 @@ func (api *API) patchGroup(rw http.ResponseWriter, r *http.Request) {
|
|||
httpapi.Write(ctx, rw, http.StatusOK, convertGroup(group, members))
|
||||
}
|
||||
|
||||
// @Summary Delete group by name
|
||||
// @ID delete-group-by-name
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Enterprise
|
||||
// @Param group path string true "Group name"
|
||||
// @Success 200 {object} codersdk.Group
|
||||
// @Router /groups/{group} [delete]
|
||||
func (api *API) deleteGroup(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
@ -274,14 +290,27 @@ func (api *API) deleteGroup(rw http.ResponseWriter, r *http.Request) {
|
|||
})
|
||||
}
|
||||
|
||||
// @Summary Get group by organization and group name
|
||||
// @ID get-group-by-organization-and-group-name
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Enterprise
|
||||
// @Param organization path string true "Organization ID" format(uuid)
|
||||
// @Param groupName path string true "Group name"
|
||||
// @Success 200 {object} codersdk.Group
|
||||
// @Router /organizations/{organization}/groups/{groupName} [get]
|
||||
func (api *API) groupByOrganization(rw http.ResponseWriter, r *http.Request) {
|
||||
api.group(rw, r)
|
||||
}
|
||||
|
||||
// @Summary Get group by name
|
||||
// @ID get-group-by-name
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Enterprise
|
||||
// @Param groupName path string true "Group name"
|
||||
// @Param group path string true "Group name"
|
||||
// @Success 200 {object} codersdk.Group
|
||||
// @Router /groups/{groupName} [get]
|
||||
// @Router /groups/{group} [get]
|
||||
func (api *API) group(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
|
|
@ -52,6 +52,7 @@ var Keys = map[string]ed25519.PublicKey{"2022-08-12": ed25519.PublicKey(key20220
|
|||
// @Summary Add new license
|
||||
// @ID add-new-license
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Organizations
|
||||
// @Param request body codersdk.AddLicenseRequest true "Add license request"
|
||||
|
@ -178,7 +179,7 @@ func (api *API) licenses(rw http.ResponseWriter, r *http.Request) {
|
|||
// @Tags Enterprise
|
||||
// @Param id path string true "License ID" format(number)
|
||||
// @Success 200
|
||||
// @Router /license/{id} [delete]
|
||||
// @Router /licenses/{id} [delete]
|
||||
func (api *API) deleteLicense(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
if !api.AGPL.Authorize(r, rbac.ActionDelete, rbac.ResourceLicense) {
|
||||
|
|
|
@ -94,7 +94,6 @@ func (api *API) provisionerDaemons(rw http.ResponseWriter, r *http.Request) {
|
|||
// @Summary Serve provisioner daemon
|
||||
// @ID serve-provisioner-daemon
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Enterprise
|
||||
// @Param organization path string true "Organization ID" format(uuid)
|
||||
// @Success 101
|
||||
|
|
|
@ -49,7 +49,7 @@ func (api *API) scimVerifyAuthHeader(r *http.Request) bool {
|
|||
// @Produce application/scim+json
|
||||
// @Tags Enterprise
|
||||
// @Success 200
|
||||
// @Router /scim/v2/Users [post]
|
||||
// @Router /scim/v2/Users [get]
|
||||
//
|
||||
//nolint:revive
|
||||
func (api *API) scimGetUsers(rw http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
@ -103,6 +103,7 @@ func (api *API) templateACL(rw http.ResponseWriter, r *http.Request) {
|
|||
// @Summary Update template ACL
|
||||
// @ID update-template-acl
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Enterprise
|
||||
// @Param template path string true "Template ID" format(uuid)
|
||||
|
|
Loading…
Reference in New Issue