diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 258279b6cb5fa..051674d0661c3 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -875,6 +875,536 @@ const docTemplate = `{ } } }, + "/workspaceagents/aws-instance-identity": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Agents" + ], + "summary": "Authenticate agent on AWS instance", + "operationId": "authenticate-agent-on-aws-instance", + "parameters": [ + { + "description": "Instance identity token", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.AWSInstanceIdentityToken" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceAgentAuthenticateResponse" + } + } + } + } + }, + "/workspaceagents/azure-instance-identity": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Agents" + ], + "summary": "Authenticate agent on Azure instance", + "operationId": "authenticate-agent-on-azure-instance", + "parameters": [ + { + "description": "Instance identity token", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.AzureInstanceIdentityToken" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceAgentAuthenticateResponse" + } + } + } + } + }, + "/workspaceagents/google-instance-identity": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Agents" + ], + "summary": "Authenticate agent on Google Cloud instance", + "operationId": "authenticate-agent-on-google-cloud-instance", + "parameters": [ + { + "description": "Instance identity token", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.GoogleInstanceIdentityToken" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceAgentAuthenticateResponse" + } + } + } + } + }, + "/workspaceagents/me/app-health": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Agents" + ], + "summary": "Submit workspace application health", + "operationId": "submit-workspace-workspace-agent-health", + "parameters": [ + { + "description": "Application health request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.PostWorkspaceAppHealthsRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspaceagents/me/coordinate": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "description": "It accepts a WebSocket connection to an agent that listens to\nincoming connections and publishes node updates.", + "produces": [ + "application/json" + ], + "tags": [ + "Agents" + ], + "summary": "Coordinate workspace agent via Tailnet", + "operationId": "get-workspace-agent-git-ssh-key-via-tailnet", + "responses": { + "101": { + "description": "Switching Protocols" + } + } + } + }, + "/workspaceagents/me/gitauth": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Agents" + ], + "summary": "Get workspace agent Git auth", + "operationId": "get-workspace-agent-git-auth", + "parameters": [ + { + "type": "string", + "format": "uri", + "description": "Git URL", + "name": "url", + "in": "query", + "required": true + }, + { + "type": "boolean", + "description": "Wait for a new token to be issued", + "name": "listen", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceAgentGitAuthResponse" + } + } + } + } + }, + "/workspaceagents/me/gitsshkey": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Agents" + ], + "summary": "Get workspace agent Git SSH key", + "operationId": "get-workspace-agent-git-ssh-key", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.AgentGitSSHKey" + } + } + } + } + }, + "/workspaceagents/me/metadata": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Agents" + ], + "summary": "Get authorized workspace agent metadata", + "operationId": "get-authorized-workspace-agent-metadata", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceAgentMetadata" + } + } + } + } + }, + "/workspaceagents/me/report-stats": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Agents" + ], + "summary": "Submit workspace agent stats", + "operationId": "submit-workspace-workspace-agent-stats", + "parameters": [ + { + "description": "Stats request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.AgentStats" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.AgentStatsResponse" + } + } + } + } + }, + "/workspaceagents/me/version": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Agents" + ], + "summary": "Submit workspace agent version", + "operationId": "submit-workspace-workspace-agent-version", + "parameters": [ + { + "description": "Version request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.PostWorkspaceAgentVersionRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-apidocgen": { + "skip": true + } + } + }, + "/workspacebuilds/{workspacebuild}": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Builds" + ], + "summary": "Get workspace build", + "operationId": "get-workspace-build", + "parameters": [ + { + "type": "string", + "description": "Workspace build ID", + "name": "workspacebuild", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceBuild" + } + } + } + } + }, + "/workspacebuilds/{workspacebuild}/cancel": { + "patch": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Builds" + ], + "summary": "Cancel workspace build", + "operationId": "cancel-workspace-build", + "parameters": [ + { + "type": "string", + "description": "Workspace build ID", + "name": "workspacebuild", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.Response" + } + } + } + } + }, + "/workspacebuilds/{workspacebuild}/logs": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Builds" + ], + "summary": "Get workspace build logs", + "operationId": "get-workspace-build-logs", + "parameters": [ + { + "type": "string", + "description": "Workspace build ID", + "name": "workspacebuild", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Before Unix timestamp", + "name": "before", + "in": "query" + }, + { + "type": "integer", + "description": "After Unix timestamp", + "name": "after", + "in": "query" + }, + { + "type": "boolean", + "description": "Follow log stream", + "name": "follow", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.ProvisionerJobLog" + } + } + } + } + } + }, + "/workspacebuilds/{workspacebuild}/resources": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Builds" + ], + "summary": "Get workspace resources for workspace build", + "operationId": "get-workspace-resources-for-workspace-build", + "parameters": [ + { + "type": "string", + "description": "Workspace build ID", + "name": "workspacebuild", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.WorkspaceResource" + } + } + } + } + } + }, + "/workspacebuilds/{workspacebuild}/state": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Builds" + ], + "summary": "Get provisioner state for workspace build", + "operationId": "get-provisioner-state-for-workspace-build", + "parameters": [ + { + "type": "string", + "description": "Workspace build ID", + "name": "workspacebuild", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceBuild" + } + } + } + } + }, "/workspaces": { "get": { "security": [ @@ -990,6 +1520,112 @@ const docTemplate = `{ } } }, + "/workspaces/{id}/builds": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Builds" + ], + "summary": "Get workspace builds by workspace ID", + "operationId": "get-workspace-builds-by-workspace-id", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Workspace ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "format": "uuid", + "description": "After ID", + "name": "after_id", + "in": "query" + }, + { + "type": "integer", + "description": "Page limit", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "description": "Page offset", + "name": "offset", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "description": "Since timestamp", + "name": "since", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.WorkspaceBuild" + } + } + } + } + }, + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Builds" + ], + "summary": "Create workspace build", + "operationId": "create-workspace-build", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Workspace ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Create workspace build request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.CreateWorkspaceBuildRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceBuild" + } + } + } + } + }, "/workspaces/{workspace}": { "patch": { "security": [ @@ -1215,6 +1851,73 @@ const docTemplate = `{ } } }, + "codersdk.AWSInstanceIdentityToken": { + "type": "object", + "required": [ + "document", + "signature" + ], + "properties": { + "document": { + "type": "string" + }, + "signature": { + "type": "string" + } + } + }, + "codersdk.AgentGitSSHKey": { + "type": "object", + "properties": { + "private_key": { + "type": "string" + }, + "public_key": { + "type": "string" + } + } + }, + "codersdk.AgentStats": { + "type": "object", + "properties": { + "conns_by_proto": { + "description": "ConnsByProto is a count of connections by protocol.", + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "num_comms": { + "description": "NumConns is the number of connections received by an agent.", + "type": "integer" + }, + "rx_bytes": { + "description": "RxBytes is the number of received bytes.", + "type": "integer" + }, + "rx_packets": { + "description": "RxPackets is the number of received packets.", + "type": "integer" + }, + "tx_bytes": { + "description": "TxBytes is the number of transmitted bytes.", + "type": "integer" + }, + "tx_packets": { + "description": "TxPackets is the number of transmitted bytes.", + "type": "integer" + } + } + }, + "codersdk.AgentStatsResponse": { + "type": "object", + "properties": { + "report_interval": { + "description": "ReportInterval is the duration after which the agent should send stats\nagain.", + "type": "integer" + } + } + }, "codersdk.AuditDiff": { "type": "object", "additionalProperties": { @@ -1367,6 +2070,21 @@ const docTemplate = `{ "type": "boolean" } }, + "codersdk.AzureInstanceIdentityToken": { + "type": "object", + "required": [ + "encoding", + "signature" + ], + "properties": { + "encoding": { + "type": "string" + }, + "signature": { + "type": "string" + } + } + }, "codersdk.BuildInfoResponse": { "type": "object", "properties": { @@ -1495,6 +2213,46 @@ const docTemplate = `{ } } }, + "codersdk.CreateWorkspaceBuildRequest": { + "type": "object", + "required": [ + "transition" + ], + "properties": { + "dry_run": { + "type": "boolean" + }, + "orphan": { + "description": "Orphan may be set for the Destroy transition.", + "type": "boolean" + }, + "parameter_values": { + "description": "ParameterValues are optional. It will write params to the 'workspace' scope.\nThis will overwrite any existing parameters with the same name.\nThis will not delete old params not included in this list.", + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.CreateParameterRequest" + } + }, + "state": { + "type": "array", + "items": { + "type": "integer" + } + }, + "template_version_id": { + "type": "string" + }, + "transition": { + "type": "string", + "enum": [ + "create", + "start", + "stop", + "delete" + ] + } + } + }, "codersdk.DERP": { "type": "object", "properties": { @@ -1898,6 +2656,17 @@ const docTemplate = `{ } } }, + "codersdk.GoogleInstanceIdentityToken": { + "type": "object", + "required": [ + "json_web_token" + ], + "properties": { + "json_web_token": { + "type": "string" + } + } + }, "codersdk.Healthcheck": { "type": "object", "properties": { @@ -2026,6 +2795,27 @@ const docTemplate = `{ } } }, + "codersdk.PostWorkspaceAgentVersionRequest": { + "description": "x-apidocgen:skip", + "type": "object", + "properties": { + "version": { + "type": "string" + } + } + }, + "codersdk.PostWorkspaceAppHealthsRequest": { + "type": "object", + "properties": { + "healths": { + "description": "Healths is a map of the workspace app name and the health of the app.", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, "codersdk.PprofConfig": { "type": "object", "properties": { @@ -2069,28 +2859,42 @@ const docTemplate = `{ "type": "object", "properties": { "canceled_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "completed_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "created_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "error": { "type": "string" }, "file_id": { - "type": "string" + "type": "string", + "format": "uuid" }, "id": { - "type": "string" + "type": "string", + "format": "uuid" }, "started_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "status": { - "type": "string" + "type": "string", + "enum": [ + "pending", + "running", + "succeeded", + "canceling", + "canceled", + "failed" + ] }, "tags": { "type": "object", @@ -2099,6 +2903,38 @@ const docTemplate = `{ } }, "worker_id": { + "type": "string", + "format": "uuid" + } + } + }, + "codersdk.ProvisionerJobLog": { + "type": "object", + "properties": { + "created_at": { + "type": "string", + "format": "date-time" + }, + "id": { + "type": "integer" + }, + "log_level": { + "type": "string", + "enum": [ + "trace", + "debug", + "info", + "warn", + "error" + ] + }, + "log_source": { + "type": "string" + }, + "output": { + "type": "string" + }, + "stage": { "type": "string" } } @@ -2481,13 +3317,15 @@ const docTemplate = `{ "type": "integer" }, "created_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "directory": { "type": "string" }, "disconnected_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "environment_variables": { "type": "object", @@ -2496,16 +3334,19 @@ const docTemplate = `{ } }, "first_connected_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "id": { - "type": "string" + "type": "string", + "format": "uuid" }, "instance_id": { "type": "string" }, "last_connected_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "latency": { "description": "DERPLatency is mapped by region name (e.g. \"New York City\", \"Seattle\").", @@ -2521,25 +3362,91 @@ const docTemplate = `{ "type": "string" }, "resource_id": { - "type": "string" + "type": "string", + "format": "uuid" }, "startup_script": { "type": "string" }, "status": { - "type": "string" + "type": "string", + "enum": [ + "connecting", + "connected", + "disconnected", + "timeout" + ] }, "troubleshooting_url": { "type": "string" }, "updated_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "version": { "type": "string" } } }, + "codersdk.WorkspaceAgentAuthenticateResponse": { + "type": "object", + "properties": { + "session_token": { + "type": "string" + } + } + }, + "codersdk.WorkspaceAgentGitAuthResponse": { + "type": "object", + "properties": { + "password": { + "type": "string" + }, + "url": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "codersdk.WorkspaceAgentMetadata": { + "type": "object", + "properties": { + "apps": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.WorkspaceApp" + } + }, + "derpmap": { + "$ref": "#/definitions/tailcfg.DERPMap" + }, + "directory": { + "type": "string" + }, + "environment_variables": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "git_auth_configs": { + "description": "GitAuthConfigs stores the number of Git configurations\nthe Coder deployment has. If this number is \u003e0, we\nset up special configuration in the workspace.", + "type": "integer" + }, + "motd_file": { + "type": "string" + }, + "startup_script": { + "type": "string" + }, + "vscode_port_proxy_uri": { + "type": "string" + } + } + }, "codersdk.WorkspaceApp": { "type": "object", "properties": { @@ -2566,10 +3473,16 @@ const docTemplate = `{ "type": "string" }, "id": { - "type": "string" + "type": "string", + "format": "uuid" }, "sharing_level": { - "type": "string" + "type": "string", + "enum": [ + "owner", + "authenticated", + "public" + ] }, "slug": { "description": "Slug is a unique identifier within the agent.", @@ -2617,7 +3530,12 @@ const docTemplate = `{ "$ref": "#/definitions/codersdk.ProvisionerJob" }, "reason": { - "type": "string" + "type": "string", + "enum": [ + "initiator", + "autostart", + "autostop" + ] }, "resources": { "type": "array", @@ -2757,6 +3675,107 @@ const docTemplate = `{ }, "netip.Addr": { "type": "object" + }, + "tailcfg.DERPMap": { + "type": "object", + "properties": { + "omitDefaultRegions": { + "description": "OmitDefaultRegions specifies to not use Tailscale's DERP servers, and only use those\nspecified in this DERPMap. If there are none set outside of the defaults, this is a noop.", + "type": "boolean" + }, + "regions": { + "description": "Regions is the set of geographic regions running DERP node(s).\n\nIt's keyed by the DERPRegion.RegionID.\n\nThe numbers are not necessarily contiguous.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/tailcfg.DERPRegion" + } + } + } + }, + "tailcfg.DERPNode": { + "type": "object", + "properties": { + "certName": { + "description": "CertName optionally specifies the expected TLS cert common\nname. If empty, HostName is used. If CertName is non-empty,\nHostName is only used for the TCP dial (if IPv4/IPv6 are\nnot present) + TLS ClientHello.", + "type": "string" + }, + "derpport": { + "description": "DERPPort optionally provides an alternate TLS port number\nfor the DERP HTTPS server.\n\nIf zero, 443 is used.", + "type": "integer" + }, + "forceHTTP": { + "description": "ForceHTTP is used by unit tests to force HTTP.\nIt should not be set by users.", + "type": "boolean" + }, + "hostName": { + "description": "HostName is the DERP node's hostname.\n\nIt is required but need not be unique; multiple nodes may\nhave the same HostName but vary in configuration otherwise.", + "type": "string" + }, + "insecureForTests": { + "description": "InsecureForTests is used by unit tests to disable TLS verification.\nIt should not be set by users.", + "type": "boolean" + }, + "ipv4": { + "description": "IPv4 optionally forces an IPv4 address to use, instead of using DNS.\nIf empty, A record(s) from DNS lookups of HostName are used.\nIf the string is not an IPv4 address, IPv4 is not used; the\nconventional string to disable IPv4 (and not use DNS) is\n\"none\".", + "type": "string" + }, + "ipv6": { + "description": "IPv6 optionally forces an IPv6 address to use, instead of using DNS.\nIf empty, AAAA record(s) from DNS lookups of HostName are used.\nIf the string is not an IPv6 address, IPv6 is not used; the\nconventional string to disable IPv6 (and not use DNS) is\n\"none\".", + "type": "string" + }, + "name": { + "description": "Name is a unique node name (across all regions).\nIt is not a host name.\nIt's typically of the form \"1b\", \"2a\", \"3b\", etc. (region\nID + suffix within that region)", + "type": "string" + }, + "regionID": { + "description": "RegionID is the RegionID of the DERPRegion that this node\nis running in.", + "type": "integer" + }, + "stunonly": { + "description": "STUNOnly marks a node as only a STUN server and not a DERP\nserver.", + "type": "boolean" + }, + "stunport": { + "description": "Port optionally specifies a STUN port to use.\nZero means 3478.\nTo disable STUN on this node, use -1.", + "type": "integer" + }, + "stuntestIP": { + "description": "STUNTestIP is used in tests to override the STUN server's IP.\nIf empty, it's assumed to be the same as the DERP server.", + "type": "string" + } + } + }, + "tailcfg.DERPRegion": { + "type": "object", + "properties": { + "avoid": { + "description": "Avoid is whether the client should avoid picking this as its home\nregion. The region should only be used if a peer is there.\nClients already using this region as their home should migrate\naway to a new region without Avoid set.", + "type": "boolean" + }, + "embeddedRelay": { + "description": "EmbeddedRelay is true when the region is bundled with the Coder\ncontrol plane.", + "type": "boolean" + }, + "nodes": { + "description": "Nodes are the DERP nodes running in this region, in\npriority order for the current client. Client TLS\nconnections should ideally only go to the first entry\n(falling back to the second if necessary). STUN packets\nshould go to the first 1 or 2.\n\nIf nodes within a region route packets amongst themselves,\nbut not to other regions. That said, each user/domain\nshould get a the same preferred node order, so if all nodes\nfor a user/network pick the first one (as they should, when\nthings are healthy), the inter-cluster routing is minimal\nto zero.", + "type": "array", + "items": { + "$ref": "#/definitions/tailcfg.DERPNode" + } + }, + "regionCode": { + "description": "RegionCode is a short name for the region. It's usually a popular\ncity or airport code in the region: \"nyc\", \"sf\", \"sin\",\n\"fra\", etc.", + "type": "string" + }, + "regionID": { + "description": "RegionID is a unique integer for a geographic region.\n\nIt corresponds to the legacy derpN.tailscale.com hostnames\nused by older clients. (Older clients will continue to resolve\nderpN.tailscale.com when contacting peers, rather than use\nthe server-provided DERPMap)\n\nRegionIDs must be non-zero, positive, and guaranteed to fit\nin a JavaScript number.\n\nRegionIDs in range 900-999 are reserved for end users to run their\nown DERP nodes.", + "type": "integer" + }, + "regionName": { + "description": "RegionName is a long English name for the region: \"New York City\",\n\"San Francisco\", \"Singapore\", \"Frankfurt\", etc.", + "type": "string" + } + } } }, "securityDefinitions": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 22cc73a97c388..71193925a37d3 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -757,6 +757,470 @@ } } }, + "/workspaceagents/aws-instance-identity": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Agents"], + "summary": "Authenticate agent on AWS instance", + "operationId": "authenticate-agent-on-aws-instance", + "parameters": [ + { + "description": "Instance identity token", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.AWSInstanceIdentityToken" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceAgentAuthenticateResponse" + } + } + } + } + }, + "/workspaceagents/azure-instance-identity": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Agents"], + "summary": "Authenticate agent on Azure instance", + "operationId": "authenticate-agent-on-azure-instance", + "parameters": [ + { + "description": "Instance identity token", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.AzureInstanceIdentityToken" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceAgentAuthenticateResponse" + } + } + } + } + }, + "/workspaceagents/google-instance-identity": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Agents"], + "summary": "Authenticate agent on Google Cloud instance", + "operationId": "authenticate-agent-on-google-cloud-instance", + "parameters": [ + { + "description": "Instance identity token", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.GoogleInstanceIdentityToken" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceAgentAuthenticateResponse" + } + } + } + } + }, + "/workspaceagents/me/app-health": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Agents"], + "summary": "Submit workspace application health", + "operationId": "submit-workspace-workspace-agent-health", + "parameters": [ + { + "description": "Application health request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.PostWorkspaceAppHealthsRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspaceagents/me/coordinate": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "description": "It accepts a WebSocket connection to an agent that listens to\nincoming connections and publishes node updates.", + "produces": ["application/json"], + "tags": ["Agents"], + "summary": "Coordinate workspace agent via Tailnet", + "operationId": "get-workspace-agent-git-ssh-key-via-tailnet", + "responses": { + "101": { + "description": "Switching Protocols" + } + } + } + }, + "/workspaceagents/me/gitauth": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["Agents"], + "summary": "Get workspace agent Git auth", + "operationId": "get-workspace-agent-git-auth", + "parameters": [ + { + "type": "string", + "format": "uri", + "description": "Git URL", + "name": "url", + "in": "query", + "required": true + }, + { + "type": "boolean", + "description": "Wait for a new token to be issued", + "name": "listen", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceAgentGitAuthResponse" + } + } + } + } + }, + "/workspaceagents/me/gitsshkey": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["Agents"], + "summary": "Get workspace agent Git SSH key", + "operationId": "get-workspace-agent-git-ssh-key", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.AgentGitSSHKey" + } + } + } + } + }, + "/workspaceagents/me/metadata": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["Agents"], + "summary": "Get authorized workspace agent metadata", + "operationId": "get-authorized-workspace-agent-metadata", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceAgentMetadata" + } + } + } + } + }, + "/workspaceagents/me/report-stats": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Agents"], + "summary": "Submit workspace agent stats", + "operationId": "submit-workspace-workspace-agent-stats", + "parameters": [ + { + "description": "Stats request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.AgentStats" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.AgentStatsResponse" + } + } + } + } + }, + "/workspaceagents/me/version": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Agents"], + "summary": "Submit workspace agent version", + "operationId": "submit-workspace-workspace-agent-version", + "parameters": [ + { + "description": "Version request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.PostWorkspaceAgentVersionRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-apidocgen": { + "skip": true + } + } + }, + "/workspacebuilds/{workspacebuild}": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Builds"], + "summary": "Get workspace build", + "operationId": "get-workspace-build", + "parameters": [ + { + "type": "string", + "description": "Workspace build ID", + "name": "workspacebuild", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceBuild" + } + } + } + } + }, + "/workspacebuilds/{workspacebuild}/cancel": { + "patch": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Builds"], + "summary": "Cancel workspace build", + "operationId": "cancel-workspace-build", + "parameters": [ + { + "type": "string", + "description": "Workspace build ID", + "name": "workspacebuild", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.Response" + } + } + } + } + }, + "/workspacebuilds/{workspacebuild}/logs": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Builds"], + "summary": "Get workspace build logs", + "operationId": "get-workspace-build-logs", + "parameters": [ + { + "type": "string", + "description": "Workspace build ID", + "name": "workspacebuild", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Before Unix timestamp", + "name": "before", + "in": "query" + }, + { + "type": "integer", + "description": "After Unix timestamp", + "name": "after", + "in": "query" + }, + { + "type": "boolean", + "description": "Follow log stream", + "name": "follow", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.ProvisionerJobLog" + } + } + } + } + } + }, + "/workspacebuilds/{workspacebuild}/resources": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Builds"], + "summary": "Get workspace resources for workspace build", + "operationId": "get-workspace-resources-for-workspace-build", + "parameters": [ + { + "type": "string", + "description": "Workspace build ID", + "name": "workspacebuild", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.WorkspaceResource" + } + } + } + } + } + }, + "/workspacebuilds/{workspacebuild}/state": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Builds"], + "summary": "Get provisioner state for workspace build", + "operationId": "get-provisioner-state-for-workspace-build", + "parameters": [ + { + "type": "string", + "description": "Workspace build ID", + "name": "workspacebuild", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceBuild" + } + } + } + } + }, "/workspaces": { "get": { "security": [ @@ -859,6 +1323,104 @@ } } }, + "/workspaces/{id}/builds": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Builds"], + "summary": "Get workspace builds by workspace ID", + "operationId": "get-workspace-builds-by-workspace-id", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Workspace ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "format": "uuid", + "description": "After ID", + "name": "after_id", + "in": "query" + }, + { + "type": "integer", + "description": "Page limit", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "description": "Page offset", + "name": "offset", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "description": "Since timestamp", + "name": "since", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.WorkspaceBuild" + } + } + } + } + }, + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Builds"], + "summary": "Create workspace build", + "operationId": "create-workspace-build", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Workspace ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Create workspace build request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.CreateWorkspaceBuildRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.WorkspaceBuild" + } + } + } + } + }, "/workspaces/{workspace}": { "patch": { "security": [ @@ -1044,15 +1606,79 @@ } } } - } - }, - "definitions": { - "coderd.cspViolation": { + } + }, + "definitions": { + "coderd.cspViolation": { + "type": "object", + "properties": { + "csp-report": { + "type": "object", + "additionalProperties": true + } + } + }, + "codersdk.AWSInstanceIdentityToken": { + "type": "object", + "required": ["document", "signature"], + "properties": { + "document": { + "type": "string" + }, + "signature": { + "type": "string" + } + } + }, + "codersdk.AgentGitSSHKey": { + "type": "object", + "properties": { + "private_key": { + "type": "string" + }, + "public_key": { + "type": "string" + } + } + }, + "codersdk.AgentStats": { + "type": "object", + "properties": { + "conns_by_proto": { + "description": "ConnsByProto is a count of connections by protocol.", + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "num_comms": { + "description": "NumConns is the number of connections received by an agent.", + "type": "integer" + }, + "rx_bytes": { + "description": "RxBytes is the number of received bytes.", + "type": "integer" + }, + "rx_packets": { + "description": "RxPackets is the number of received packets.", + "type": "integer" + }, + "tx_bytes": { + "description": "TxBytes is the number of transmitted bytes.", + "type": "integer" + }, + "tx_packets": { + "description": "TxPackets is the number of transmitted bytes.", + "type": "integer" + } + } + }, + "codersdk.AgentStatsResponse": { "type": "object", "properties": { - "csp-report": { - "type": "object", - "additionalProperties": true + "report_interval": { + "description": "ReportInterval is the duration after which the agent should send stats\nagain.", + "type": "integer" } } }, @@ -1203,6 +1829,18 @@ "type": "boolean" } }, + "codersdk.AzureInstanceIdentityToken": { + "type": "object", + "required": ["encoding", "signature"], + "properties": { + "encoding": { + "type": "string" + }, + "signature": { + "type": "string" + } + } + }, "codersdk.BuildInfoResponse": { "type": "object", "properties": { @@ -1315,6 +1953,39 @@ } } }, + "codersdk.CreateWorkspaceBuildRequest": { + "type": "object", + "required": ["transition"], + "properties": { + "dry_run": { + "type": "boolean" + }, + "orphan": { + "description": "Orphan may be set for the Destroy transition.", + "type": "boolean" + }, + "parameter_values": { + "description": "ParameterValues are optional. It will write params to the 'workspace' scope.\nThis will overwrite any existing parameters with the same name.\nThis will not delete old params not included in this list.", + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.CreateParameterRequest" + } + }, + "state": { + "type": "array", + "items": { + "type": "integer" + } + }, + "template_version_id": { + "type": "string" + }, + "transition": { + "type": "string", + "enum": ["create", "start", "stop", "delete"] + } + } + }, "codersdk.DERP": { "type": "object", "properties": { @@ -1718,6 +2389,15 @@ } } }, + "codersdk.GoogleInstanceIdentityToken": { + "type": "object", + "required": ["json_web_token"], + "properties": { + "json_web_token": { + "type": "string" + } + } + }, "codersdk.Healthcheck": { "type": "object", "properties": { @@ -1835,6 +2515,27 @@ } } }, + "codersdk.PostWorkspaceAgentVersionRequest": { + "description": "x-apidocgen:skip", + "type": "object", + "properties": { + "version": { + "type": "string" + } + } + }, + "codersdk.PostWorkspaceAppHealthsRequest": { + "type": "object", + "properties": { + "healths": { + "description": "Healths is a map of the workspace app name and the health of the app.", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, "codersdk.PprofConfig": { "type": "object", "properties": { @@ -1878,28 +2579,42 @@ "type": "object", "properties": { "canceled_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "completed_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "created_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "error": { "type": "string" }, "file_id": { - "type": "string" + "type": "string", + "format": "uuid" }, "id": { - "type": "string" + "type": "string", + "format": "uuid" }, "started_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "status": { - "type": "string" + "type": "string", + "enum": [ + "pending", + "running", + "succeeded", + "canceling", + "canceled", + "failed" + ] }, "tags": { "type": "object", @@ -1908,6 +2623,32 @@ } }, "worker_id": { + "type": "string", + "format": "uuid" + } + } + }, + "codersdk.ProvisionerJobLog": { + "type": "object", + "properties": { + "created_at": { + "type": "string", + "format": "date-time" + }, + "id": { + "type": "integer" + }, + "log_level": { + "type": "string", + "enum": ["trace", "debug", "info", "warn", "error"] + }, + "log_source": { + "type": "string" + }, + "output": { + "type": "string" + }, + "stage": { "type": "string" } } @@ -2280,13 +3021,15 @@ "type": "integer" }, "created_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "directory": { "type": "string" }, "disconnected_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "environment_variables": { "type": "object", @@ -2295,16 +3038,19 @@ } }, "first_connected_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "id": { - "type": "string" + "type": "string", + "format": "uuid" }, "instance_id": { "type": "string" }, "last_connected_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "latency": { "description": "DERPLatency is mapped by region name (e.g. \"New York City\", \"Seattle\").", @@ -2320,25 +3066,86 @@ "type": "string" }, "resource_id": { - "type": "string" + "type": "string", + "format": "uuid" }, "startup_script": { "type": "string" }, "status": { - "type": "string" + "type": "string", + "enum": ["connecting", "connected", "disconnected", "timeout"] }, "troubleshooting_url": { "type": "string" }, "updated_at": { - "type": "string" + "type": "string", + "format": "date-time" }, "version": { "type": "string" } } }, + "codersdk.WorkspaceAgentAuthenticateResponse": { + "type": "object", + "properties": { + "session_token": { + "type": "string" + } + } + }, + "codersdk.WorkspaceAgentGitAuthResponse": { + "type": "object", + "properties": { + "password": { + "type": "string" + }, + "url": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "codersdk.WorkspaceAgentMetadata": { + "type": "object", + "properties": { + "apps": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.WorkspaceApp" + } + }, + "derpmap": { + "$ref": "#/definitions/tailcfg.DERPMap" + }, + "directory": { + "type": "string" + }, + "environment_variables": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "git_auth_configs": { + "description": "GitAuthConfigs stores the number of Git configurations\nthe Coder deployment has. If this number is \u003e0, we\nset up special configuration in the workspace.", + "type": "integer" + }, + "motd_file": { + "type": "string" + }, + "startup_script": { + "type": "string" + }, + "vscode_port_proxy_uri": { + "type": "string" + } + } + }, "codersdk.WorkspaceApp": { "type": "object", "properties": { @@ -2365,10 +3172,12 @@ "type": "string" }, "id": { - "type": "string" + "type": "string", + "format": "uuid" }, "sharing_level": { - "type": "string" + "type": "string", + "enum": ["owner", "authenticated", "public"] }, "slug": { "description": "Slug is a unique identifier within the agent.", @@ -2416,7 +3225,8 @@ "$ref": "#/definitions/codersdk.ProvisionerJob" }, "reason": { - "type": "string" + "type": "string", + "enum": ["initiator", "autostart", "autostop"] }, "resources": { "type": "array", @@ -2548,6 +3358,107 @@ }, "netip.Addr": { "type": "object" + }, + "tailcfg.DERPMap": { + "type": "object", + "properties": { + "omitDefaultRegions": { + "description": "OmitDefaultRegions specifies to not use Tailscale's DERP servers, and only use those\nspecified in this DERPMap. If there are none set outside of the defaults, this is a noop.", + "type": "boolean" + }, + "regions": { + "description": "Regions is the set of geographic regions running DERP node(s).\n\nIt's keyed by the DERPRegion.RegionID.\n\nThe numbers are not necessarily contiguous.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/tailcfg.DERPRegion" + } + } + } + }, + "tailcfg.DERPNode": { + "type": "object", + "properties": { + "certName": { + "description": "CertName optionally specifies the expected TLS cert common\nname. If empty, HostName is used. If CertName is non-empty,\nHostName is only used for the TCP dial (if IPv4/IPv6 are\nnot present) + TLS ClientHello.", + "type": "string" + }, + "derpport": { + "description": "DERPPort optionally provides an alternate TLS port number\nfor the DERP HTTPS server.\n\nIf zero, 443 is used.", + "type": "integer" + }, + "forceHTTP": { + "description": "ForceHTTP is used by unit tests to force HTTP.\nIt should not be set by users.", + "type": "boolean" + }, + "hostName": { + "description": "HostName is the DERP node's hostname.\n\nIt is required but need not be unique; multiple nodes may\nhave the same HostName but vary in configuration otherwise.", + "type": "string" + }, + "insecureForTests": { + "description": "InsecureForTests is used by unit tests to disable TLS verification.\nIt should not be set by users.", + "type": "boolean" + }, + "ipv4": { + "description": "IPv4 optionally forces an IPv4 address to use, instead of using DNS.\nIf empty, A record(s) from DNS lookups of HostName are used.\nIf the string is not an IPv4 address, IPv4 is not used; the\nconventional string to disable IPv4 (and not use DNS) is\n\"none\".", + "type": "string" + }, + "ipv6": { + "description": "IPv6 optionally forces an IPv6 address to use, instead of using DNS.\nIf empty, AAAA record(s) from DNS lookups of HostName are used.\nIf the string is not an IPv6 address, IPv6 is not used; the\nconventional string to disable IPv6 (and not use DNS) is\n\"none\".", + "type": "string" + }, + "name": { + "description": "Name is a unique node name (across all regions).\nIt is not a host name.\nIt's typically of the form \"1b\", \"2a\", \"3b\", etc. (region\nID + suffix within that region)", + "type": "string" + }, + "regionID": { + "description": "RegionID is the RegionID of the DERPRegion that this node\nis running in.", + "type": "integer" + }, + "stunonly": { + "description": "STUNOnly marks a node as only a STUN server and not a DERP\nserver.", + "type": "boolean" + }, + "stunport": { + "description": "Port optionally specifies a STUN port to use.\nZero means 3478.\nTo disable STUN on this node, use -1.", + "type": "integer" + }, + "stuntestIP": { + "description": "STUNTestIP is used in tests to override the STUN server's IP.\nIf empty, it's assumed to be the same as the DERP server.", + "type": "string" + } + } + }, + "tailcfg.DERPRegion": { + "type": "object", + "properties": { + "avoid": { + "description": "Avoid is whether the client should avoid picking this as its home\nregion. The region should only be used if a peer is there.\nClients already using this region as their home should migrate\naway to a new region without Avoid set.", + "type": "boolean" + }, + "embeddedRelay": { + "description": "EmbeddedRelay is true when the region is bundled with the Coder\ncontrol plane.", + "type": "boolean" + }, + "nodes": { + "description": "Nodes are the DERP nodes running in this region, in\npriority order for the current client. Client TLS\nconnections should ideally only go to the first entry\n(falling back to the second if necessary). STUN packets\nshould go to the first 1 or 2.\n\nIf nodes within a region route packets amongst themselves,\nbut not to other regions. That said, each user/domain\nshould get a the same preferred node order, so if all nodes\nfor a user/network pick the first one (as they should, when\nthings are healthy), the inter-cluster routing is minimal\nto zero.", + "type": "array", + "items": { + "$ref": "#/definitions/tailcfg.DERPNode" + } + }, + "regionCode": { + "description": "RegionCode is a short name for the region. It's usually a popular\ncity or airport code in the region: \"nyc\", \"sf\", \"sin\",\n\"fra\", etc.", + "type": "string" + }, + "regionID": { + "description": "RegionID is a unique integer for a geographic region.\n\nIt corresponds to the legacy derpN.tailscale.com hostnames\nused by older clients. (Older clients will continue to resolve\nderpN.tailscale.com when contacting peers, rather than use\nthe server-provided DERPMap)\n\nRegionIDs must be non-zero, positive, and guaranteed to fit\nin a JavaScript number.\n\nRegionIDs in range 900-999 are reserved for end users to run their\nown DERP nodes.", + "type": "integer" + }, + "regionName": { + "description": "RegionName is a long English name for the region: \"New York City\",\n\"San Francisco\", \"Singapore\", \"Frankfurt\", etc.", + "type": "string" + } + } } }, "securityDefinitions": { diff --git a/coderd/gitsshkey.go b/coderd/gitsshkey.go index 357f5b2e44dab..a0f15da2e9e0c 100644 --- a/coderd/gitsshkey.go +++ b/coderd/gitsshkey.go @@ -100,6 +100,14 @@ 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 +// @Router /workspaceagents/me/gitsshkey [get] func (api *API) agentGitSSHKey(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() agent := httpmw.WorkspaceAgent(r) diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index 5f03e6ad8b43c..1464f3282f0cf 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -63,6 +63,14 @@ func (api *API) workspaceAgent(rw http.ResponseWriter, r *http.Request) { httpapi.Write(ctx, rw, http.StatusOK, apiAgent) } +// @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 +// @Router /workspaceagents/me/metadata [get] func (api *API) workspaceAgentMetadata(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() workspaceAgent := httpmw.WorkspaceAgent(r) @@ -138,6 +146,15 @@ func (api *API) workspaceAgentMetadata(rw http.ResponseWriter, r *http.Request) }) } +// @Summary Submit workspace agent version +// @ID submit-workspace-workspace-agent-version +// @Security CoderSessionToken +// @Produce application/json +// @Tags Agents +// @Param request body codersdk.PostWorkspaceAgentVersionRequest true "Version request" +// @Success 200 +// @Router /workspaceagents/me/version [post] +// @x-apidocgen {"skip": true} func (api *API) postWorkspaceAgentVersion(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() workspaceAgent := httpmw.WorkspaceAgent(r) @@ -438,6 +455,15 @@ 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 +// @Security CoderSessionToken +// @Produce json +// @Tags Agents +// @Success 101 +// @Router /workspaceagents/me/coordinate [get] func (api *API) workspaceAgentCoordinate(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -757,6 +783,14 @@ func convertWorkspaceAgent(derpMap *tailcfg.DERPMap, coordinator tailnet.Coordin return workspaceAgent, nil } +// @Summary Submit workspace agent stats +// @ID submit-workspace-workspace-agent-stats +// @Security CoderSessionToken +// @Produce application/json +// @Tags Agents +// @Param request body codersdk.AgentStats true "Stats request" +// @Success 200 {object} codersdk.AgentStatsResponse +// @Router /workspaceagents/me/report-stats [post] func (api *API) workspaceAgentReportStats(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -826,6 +860,14 @@ func (api *API) workspaceAgentReportStats(rw http.ResponseWriter, r *http.Reques }) } +// @Summary Submit workspace application health +// @ID submit-workspace-workspace-agent-health +// @Security CoderSessionToken +// @Produce application/json +// @Tags Agents +// @Param request body codersdk.PostWorkspaceAppHealthsRequest true "Application health request" +// @Success 200 +// @Router /workspaceagents/me/app-health [post] func (api *API) postWorkspaceAppHealth(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() workspaceAgent := httpmw.WorkspaceAgent(r) @@ -941,8 +983,19 @@ func (api *API) postWorkspaceAppHealth(rw http.ResponseWriter, r *http.Request) httpapi.Write(ctx, rw, http.StatusOK, nil) } -// postWorkspaceAgentsGitAuth returns a username and password for use +// workspaceAgentsGitAuth returns a username and password for use // with GIT_ASKPASS. +// +// @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) +// @Param listen query bool false "Wait for a new token to be issued" +// @Success 200 {object} codersdk.WorkspaceAgentGitAuthResponse +// @Router /workspaceagents/me/gitauth [get] func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() gitURL := r.URL.Query().Get("url") diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index a006c932c752b..4f057786ddfe1 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -23,6 +23,14 @@ import ( "github.com/coder/coder/codersdk" ) +// @Summary Get workspace build +// @ID get-workspace-build +// @Security CoderSessionToken +// @Produce json +// @Tags Builds +// @Param workspacebuild path string true "Workspace build ID" +// @Success 200 {object} codersdk.WorkspaceBuild +// @Router /workspacebuilds/{workspacebuild} [get] func (api *API) workspaceBuild(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() workspaceBuild := httpmw.WorkspaceBuildParam(r) @@ -64,6 +72,18 @@ func (api *API) workspaceBuild(rw http.ResponseWriter, r *http.Request) { httpapi.Write(ctx, rw, http.StatusOK, apiBuild) } +// @Summary Get workspace builds by workspace ID +// @ID get-workspace-builds-by-workspace-id +// @Security CoderSessionToken +// @Produce json +// @Tags Builds +// @Param id 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] func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() workspace := httpmw.WorkspaceParam(r) @@ -254,6 +274,19 @@ func (api *API) workspaceBuildByBuildNumber(rw http.ResponseWriter, r *http.Requ httpapi.Write(ctx, rw, http.StatusOK, apiBuild) } +// Azure supports instance identity verification: +// https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=linux#tabgroup_14 +// +// @Summary Create workspace build +// @ID create-workspace-build +// @Security CoderSessionToken +// @Accepts json +// @Produce json +// @Tags Builds +// @Param id 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] func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() apiKey := httpmw.APIKey(r) @@ -535,6 +568,14 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { httpapi.Write(ctx, rw, http.StatusCreated, apiBuild) } +// @Summary Cancel workspace build +// @ID cancel-workspace-build +// @Security CoderSessionToken +// @Produce json +// @Tags Builds +// @Param workspacebuild path string true "Workspace build ID" +// @Success 200 {object} codersdk.Response +// @Router /workspacebuilds/{workspacebuild}/cancel [patch] func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() workspaceBuild := httpmw.WorkspaceBuildParam(r) @@ -630,6 +671,14 @@ func (api *API) verifyUserCanCancelWorkspaceBuilds(ctx context.Context, userID u return slices.Contains(user.RBACRoles, rbac.RoleOwner()), nil // only user with "owner" role can cancel workspace builds } +// @Summary Get workspace resources for workspace build +// @ID get-workspace-resources-for-workspace-build +// @Security CoderSessionToken +// @Produce json +// @Tags Builds +// @Param workspacebuild path string true "Workspace build ID" +// @Success 200 {array} codersdk.WorkspaceResource +// @Router /workspacebuilds/{workspacebuild}/resources [get] func (api *API) workspaceBuildResources(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() workspaceBuild := httpmw.WorkspaceBuildParam(r) @@ -657,6 +706,17 @@ func (api *API) workspaceBuildResources(rw http.ResponseWriter, r *http.Request) api.provisionerJobResources(rw, r, job) } +// @Summary Get workspace build logs +// @ID get-workspace-build-logs +// @Security CoderSessionToken +// @Produce json +// @Tags Builds +// @Param workspacebuild path string true "Workspace build ID" +// @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 /workspacebuilds/{workspacebuild}/logs [get] func (api *API) workspaceBuildLogs(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() workspaceBuild := httpmw.WorkspaceBuildParam(r) @@ -684,6 +744,14 @@ func (api *API) workspaceBuildLogs(rw http.ResponseWriter, r *http.Request) { api.provisionerJobLogs(rw, r, job) } +// @Summary Get provisioner state for workspace build +// @ID get-provisioner-state-for-workspace-build +// @Security CoderSessionToken +// @Produce json +// @Tags Builds +// @Param workspacebuild path string true "Workspace build ID" +// @Success 200 {object} codersdk.WorkspaceBuild +// @Router /workspacebuilds/{workspacebuild}/state [get] func (api *API) workspaceBuildState(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() workspaceBuild := httpmw.WorkspaceBuildParam(r) diff --git a/coderd/workspaceresourceauth.go b/coderd/workspaceresourceauth.go index 84923fd33db00..8da31d1cdd96a 100644 --- a/coderd/workspaceresourceauth.go +++ b/coderd/workspaceresourceauth.go @@ -19,6 +19,15 @@ import ( // Azure supports instance identity verification: // https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=linux#tabgroup_14 +// +// @Summary Authenticate agent on Azure instance +// @ID authenticate-agent-on-azure-instance +// @Security CoderSessionToken +// @Produce json +// @Tags Agents +// @Param request body codersdk.AzureInstanceIdentityToken true "Instance identity token" +// @Success 200 {object} codersdk.WorkspaceAgentAuthenticateResponse +// @Router /workspaceagents/azure-instance-identity [post] func (api *API) postWorkspaceAuthAzureInstanceIdentity(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() var req codersdk.AzureInstanceIdentityToken @@ -36,6 +45,15 @@ func (api *API) postWorkspaceAuthAzureInstanceIdentity(rw http.ResponseWriter, r api.handleAuthInstanceID(rw, r, instanceID) } +// @Summary Authenticate agent on AWS instance +// @ID authenticate-agent-on-aws-instance +// @Security CoderSessionToken +// @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. @@ -56,6 +74,15 @@ func (api *API) postWorkspaceAuthAWSInstanceIdentity(rw http.ResponseWriter, r * api.handleAuthInstanceID(rw, r, identity.InstanceID) } +// @Summary Authenticate agent on Google Cloud instance +// @ID authenticate-agent-on-google-cloud-instance +// @Security CoderSessionToken +// @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. diff --git a/codersdk/provisionerdaemons.go b/codersdk/provisionerdaemons.go index 18a771f41809b..da0d2b67d0910 100644 --- a/codersdk/provisionerdaemons.go +++ b/codersdk/provisionerdaemons.go @@ -66,24 +66,26 @@ const ( ProvisionerJobFailed ProvisionerJobStatus = "failed" ) +// ProvisionerJob describes the job executed by the provisioning daemon. type ProvisionerJob struct { - ID uuid.UUID `json:"id"` - CreatedAt time.Time `json:"created_at"` - StartedAt *time.Time `json:"started_at,omitempty"` - CompletedAt *time.Time `json:"completed_at,omitempty"` - CanceledAt *time.Time `json:"canceled_at,omitempty"` + ID uuid.UUID `json:"id" format:"uuid"` + CreatedAt time.Time `json:"created_at" format:"date-time"` + StartedAt *time.Time `json:"started_at,omitempty" format:"date-time"` + CompletedAt *time.Time `json:"completed_at,omitempty" format:"date-time"` + CanceledAt *time.Time `json:"canceled_at,omitempty" format:"date-time"` Error string `json:"error,omitempty"` - Status ProvisionerJobStatus `json:"status"` - WorkerID *uuid.UUID `json:"worker_id,omitempty"` - FileID uuid.UUID `json:"file_id"` + Status ProvisionerJobStatus `json:"status" enums:"pending,running,succeeded,canceling,canceled,failed"` + WorkerID *uuid.UUID `json:"worker_id,omitempty" format:"uuid"` + FileID uuid.UUID `json:"file_id" format:"uuid"` Tags map[string]string `json:"tags"` } +// ProvisionerJobLog represents the provisioner log entry annotated with source and level. type ProvisionerJobLog struct { ID int64 `json:"id"` - CreatedAt time.Time `json:"created_at"` + CreatedAt time.Time `json:"created_at" format:"date-time"` Source LogSource `json:"log_source"` - Level LogLevel `json:"log_level"` + Level LogLevel `json:"log_level" enums:"trace,debug,info,warn,error"` Stage string `json:"stage"` Output string `json:"output"` } diff --git a/codersdk/workspaceagents.go b/codersdk/workspaceagents.go index 258b108737b9c..bb8ce62406f12 100644 --- a/codersdk/workspaceagents.go +++ b/codersdk/workspaceagents.go @@ -35,15 +35,15 @@ const ( ) type WorkspaceAgent struct { - ID uuid.UUID `json:"id"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - FirstConnectedAt *time.Time `json:"first_connected_at,omitempty"` - LastConnectedAt *time.Time `json:"last_connected_at,omitempty"` - DisconnectedAt *time.Time `json:"disconnected_at,omitempty"` - Status WorkspaceAgentStatus `json:"status"` + ID uuid.UUID `json:"id" format:"uuid"` + CreatedAt time.Time `json:"created_at" format:"date-time"` + UpdatedAt time.Time `json:"updated_at" format:"date-time"` + FirstConnectedAt *time.Time `json:"first_connected_at,omitempty" format:"date-time"` + LastConnectedAt *time.Time `json:"last_connected_at,omitempty" format:"date-time"` + DisconnectedAt *time.Time `json:"disconnected_at,omitempty" format:"date-time"` + Status WorkspaceAgentStatus `json:"status" enums:"connecting,connected,disconnected,timeout"` Name string `json:"name"` - ResourceID uuid.UUID `json:"resource_id"` + ResourceID uuid.UUID `json:"resource_id" format:"uuid"` InstanceID string `json:"instance_id,omitempty"` Architecture string `json:"architecture"` EnvironmentVariables map[string]string `json:"environment_variables"` @@ -115,6 +115,7 @@ type WorkspaceAgentConnectionInfo struct { } // @typescript-ignore PostWorkspaceAgentVersionRequest +// @Description x-apidocgen:skip type PostWorkspaceAgentVersionRequest struct { Version string `json:"version"` } diff --git a/codersdk/workspaceapps.go b/codersdk/workspaceapps.go index 8f6003b5fae48..a8bcb31b792d7 100644 --- a/codersdk/workspaceapps.go +++ b/codersdk/workspaceapps.go @@ -22,7 +22,7 @@ const ( ) type WorkspaceApp struct { - ID uuid.UUID `json:"id"` + ID uuid.UUID `json:"id" format:"uuid"` // URL is the address being proxied to inside the workspace. // If external is specified, this will be opened on the client. URL string `json:"url"` @@ -42,7 +42,7 @@ type WorkspaceApp struct { // and there is no app wildcard configured on the server, the app will not // be accessible in the UI. Subdomain bool `json:"subdomain"` - SharingLevel WorkspaceAppSharingLevel `json:"sharing_level"` + SharingLevel WorkspaceAppSharingLevel `json:"sharing_level" enums:"owner,authenticated,public"` // Healthcheck specifies the configuration for checking app health. Healthcheck Healthcheck `json:"healthcheck"` Health WorkspaceAppHealth `json:"health"` diff --git a/codersdk/workspacebuilds.go b/codersdk/workspacebuilds.go index 743c3b778ae36..95f7c9ba07b58 100644 --- a/codersdk/workspacebuilds.go +++ b/codersdk/workspacebuilds.go @@ -65,13 +65,15 @@ type WorkspaceBuild struct { InitiatorID uuid.UUID `json:"initiator_id" format:"uuid"` InitiatorUsername string `json:"initiator_name"` Job ProvisionerJob `json:"job"` - Reason BuildReason `db:"reason" json:"reason"` + Reason BuildReason `db:"reason" json:"reason" enums:"initiator,autostart,autostop"` Resources []WorkspaceResource `json:"resources"` Deadline NullTime `json:"deadline,omitempty" format:"date-time"` Status WorkspaceStatus `json:"status" enums:"pending,starting,running,stopping,stopped,failed,canceling,canceled,deleting,deleted"` DailyCost int32 `json:"daily_cost"` } +// WorkspaceResource describes resources used to create a workspace, for instance: +// containers, images, volumes. type WorkspaceResource struct { ID uuid.UUID `json:"id" format:"uuid"` CreatedAt time.Time `json:"created_at" format:"date-time"` @@ -86,6 +88,7 @@ type WorkspaceResource struct { DailyCost int32 `json:"daily_cost"` } +// WorkspaceResourceMetadata annotates the workspace resource with custom key-value pairs. type WorkspaceResourceMetadata struct { Key string `json:"key"` Value string `json:"value"` diff --git a/docs/api/agents.md b/docs/api/agents.md new file mode 100644 index 0000000000000..4a02ff56dc637 --- /dev/null +++ b/docs/api/agents.md @@ -0,0 +1,439 @@ +# Agents + +> This page is incomplete, stay tuned. + +## Authenticate agent on AWS instance + +### Code samples + +```shell +# Example request using curl +curl -X POST http://coder-server:8080/api/v2/workspaceagents/aws-instance-identity \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`POST /workspaceagents/aws-instance-identity` + +> Body parameter + +```json +{ + "document": "string", + "signature": "string" +} +``` + +### Parameters + +| Name | In | Type | Required | Description | +| ------ | ---- | -------------------------------------------------------------------------------- | -------- | ----------------------- | +| `body` | body | [codersdk.AWSInstanceIdentityToken](schemas.md#codersdkawsinstanceidentitytoken) | true | Instance identity token | + +### Example responses + +> 200 Response + +```json +{ + "session_token": "string" +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------- | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.WorkspaceAgentAuthenticateResponse](schemas.md#codersdkworkspaceagentauthenticateresponse) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + +## Authenticate agent on Azure instance + +### Code samples + +```shell +# Example request using curl +curl -X POST http://coder-server:8080/api/v2/workspaceagents/azure-instance-identity \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`POST /workspaceagents/azure-instance-identity` + +> Body parameter + +```json +{ + "encoding": "string", + "signature": "string" +} +``` + +### Parameters + +| Name | In | Type | Required | Description | +| ------ | ---- | ------------------------------------------------------------------------------------ | -------- | ----------------------- | +| `body` | body | [codersdk.AzureInstanceIdentityToken](schemas.md#codersdkazureinstanceidentitytoken) | true | Instance identity token | + +### Example responses + +> 200 Response + +```json +{ + "session_token": "string" +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------- | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.WorkspaceAgentAuthenticateResponse](schemas.md#codersdkworkspaceagentauthenticateresponse) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + +## Authenticate agent on Google Cloud instance + +### Code samples + +```shell +# Example request using curl +curl -X POST http://coder-server:8080/api/v2/workspaceagents/google-instance-identity \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`POST /workspaceagents/google-instance-identity` + +> Body parameter + +```json +{ + "json_web_token": "string" +} +``` + +### Parameters + +| Name | In | Type | Required | Description | +| ------ | ---- | -------------------------------------------------------------------------------------- | -------- | ----------------------- | +| `body` | body | [codersdk.GoogleInstanceIdentityToken](schemas.md#codersdkgoogleinstanceidentitytoken) | true | Instance identity token | + +### Example responses + +> 200 Response + +```json +{ + "session_token": "string" +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------- | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.WorkspaceAgentAuthenticateResponse](schemas.md#codersdkworkspaceagentauthenticateresponse) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + +## Submit workspace application health + +### Code samples + +```shell +# Example request using curl +curl -X POST http://coder-server:8080/api/v2/workspaceagents/me/app-health \ + -H 'Content-Type: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`POST /workspaceagents/me/app-health` + +> Body parameter + +```json +{ + "healths": { + "property1": "string", + "property2": "string" + } +} +``` + +### Parameters + +| Name | In | Type | Required | Description | +| ------ | ---- | -------------------------------------------------------------------------------------------- | -------- | -------------------------- | +| `body` | body | [codersdk.PostWorkspaceAppHealthsRequest](schemas.md#codersdkpostworkspaceapphealthsrequest) | true | Application health request | + +### 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). + +## Coordinate workspace agent via Tailnet + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/workspaceagents/me/coordinate \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /workspaceagents/me/coordinate` + +It accepts a WebSocket connection to an agent that listens to +incoming connections and publishes node updates. + +### 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 workspace agent Git auth + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/workspaceagents/me/gitauth?url=http%3A%2F%2Fexample.com \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /workspaceagents/me/gitauth` + +### Parameters + +| Name | In | Type | Required | Description | +| -------- | ----- | ----------- | -------- | --------------------------------- | +| `url` | query | string(uri) | true | Git URL | +| `listen` | query | boolean | false | Wait for a new token to be issued | + +### Example responses + +> 200 Response + +```json +{ + "password": "string", + "url": "string", + "username": "string" +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------ | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.WorkspaceAgentGitAuthResponse](schemas.md#codersdkworkspaceagentgitauthresponse) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + +## Get workspace agent Git SSH key + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/workspaceagents/me/gitsshkey \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /workspaceagents/me/gitsshkey` + +### Example responses + +> 200 Response + +```json +{ + "private_key": "string", + "public_key": "string" +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------------------ | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.AgentGitSSHKey](schemas.md#codersdkagentgitsshkey) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + +## Get authorized workspace agent metadata + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/workspaceagents/me/metadata \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /workspaceagents/me/metadata` + +### Example responses + +> 200 Response + +```json +{ + "apps": [ + { + "command": "string", + "display_name": "string", + "external": true, + "health": "string", + "healthcheck": { + "interval": 0, + "threshold": 0, + "url": "string" + }, + "icon": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "sharing_level": "owner", + "slug": "string", + "subdomain": true, + "url": "string" + } + ], + "derpmap": { + "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" + } + } + }, + "directory": "string", + "environment_variables": { + "property1": "string", + "property2": "string" + }, + "git_auth_configs": 0, + "motd_file": "string", + "startup_script": "string", + "vscode_port_proxy_uri": "string" +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------- | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.WorkspaceAgentMetadata](schemas.md#codersdkworkspaceagentmetadata) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + +## Submit workspace agent stats + +### Code samples + +```shell +# Example request using curl +curl -X POST http://coder-server:8080/api/v2/workspaceagents/me/report-stats \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`POST /workspaceagents/me/report-stats` + +> Body parameter + +```json +{ + "conns_by_proto": { + "property1": 0, + "property2": 0 + }, + "num_comms": 0, + "rx_bytes": 0, + "rx_packets": 0, + "tx_bytes": 0, + "tx_packets": 0 +} +``` + +### Parameters + +| Name | In | Type | Required | Description | +| ------ | ---- | ---------------------------------------------------- | -------- | ------------- | +| `body` | body | [codersdk.AgentStats](schemas.md#codersdkagentstats) | true | Stats request | + +### Example responses + +> 200 Response + +```json +{ + "report_interval": 0 +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------------------------- | +| 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). diff --git a/docs/api/applications.md b/docs/api/applications.md index eeb6f42c2c21d..9da19cabf9791 100644 --- a/docs/api/applications.md +++ b/docs/api/applications.md @@ -26,7 +26,7 @@ curl -X GET http://coder-server:8080/api/v2/applications/auth-redirect \ | ------ | ----------------------------------------------------------------------- | ------------------ | ------ | | 307 | [Temporary Redirect](https://tools.ietf.org/html/rfc7231#section-6.4.7) | Temporary Redirect | | -To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**. +To perform this operation, you must be authenticated. [Learn more](authentication.md). ## Get applications host @@ -57,4 +57,4 @@ curl -X GET http://coder-server:8080/api/v2/applications/host \ | ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------------------------- | | 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.GetAppHostResponse](schemas.md#codersdkgetapphostresponse) | -To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**. +To perform this operation, you must be authenticated. [Learn more](authentication.md). diff --git a/docs/api/audit.md b/docs/api/audit.md index 8b3946c715665..8c85b97f68618 100644 --- a/docs/api/audit.md +++ b/docs/api/audit.md @@ -88,7 +88,7 @@ curl -X GET http://coder-server:8080/api/v2/audit?q=string \ | ------ | ------------------------------------------------------- | ----------- | ---------------------------------------------------------------- | | 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.AuditLogResponse](schemas.md#codersdkauditlogresponse) | -To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**. +To perform this operation, you must be authenticated. [Learn more](authentication.md). ## Generate fake audit log @@ -126,4 +126,4 @@ curl -X POST http://coder-server:8080/api/v2/audit/testgenerate \ | ------ | --------------------------------------------------------------- | ----------- | ------ | | 204 | [No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5) | No Content | | -To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**. +To perform this operation, you must be authenticated. [Learn more](authentication.md). diff --git a/docs/api/authorization.md b/docs/api/authorization.md index e6c2e9e155a72..884b3fa3c5c41 100644 --- a/docs/api/authorization.md +++ b/docs/api/authorization.md @@ -66,4 +66,4 @@ curl -X POST http://coder-server:8080/api/v2/authcheck \ | ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------------------------------- | | 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.AuthorizationResponse](schemas.md#codersdkauthorizationresponse) | -To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**. +To perform this operation, you must be authenticated. [Learn more](authentication.md). diff --git a/docs/api/builds.md b/docs/api/builds.md new file mode 100644 index 0000000000000..053819796c123 --- /dev/null +++ b/docs/api/builds.md @@ -0,0 +1,1025 @@ +# Builds + +> This page is incomplete, stay tuned. + +## Get workspace build + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild} \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /workspacebuilds/{workspacebuild}` + +### Parameters + +| Name | In | Type | Required | Description | +| ---------------- | ---- | ------ | -------- | ------------------ | +| `workspacebuild` | path | string | true | Workspace build ID | + +### Example responses + +> 200 Response + +```json +{ + "build_number": 0, + "created_at": "2019-08-24T14:15:22Z", + "daily_cost": 0, + "deadline": "2019-08-24T14:15:22Z", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3", + "initiator_name": "string", + "job": { + "canceled_at": "2019-08-24T14:15:22Z", + "completed_at": "2019-08-24T14:15:22Z", + "created_at": "2019-08-24T14:15:22Z", + "error": "string", + "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "started_at": "2019-08-24T14:15:22Z", + "status": "pending", + "tags": { + "property1": "string", + "property2": "string" + }, + "worker_id": "ae5fa6f7-c55b-40c1-b40a-b36ac467652b" + }, + "reason": "initiator", + "resources": [ + { + "agents": [ + { + "apps": [ + { + "command": "string", + "display_name": "string", + "external": true, + "health": "string", + "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" + } + ], + "created_at": "2019-08-24T14:15:22Z", + "daily_cost": 0, + "hide": true, + "icon": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "job_id": "453bd7d7-5355-4d6d-a38e-d9e7eb218c3f", + "metadata": [ + { + "key": "string", + "sensitive": true, + "value": "string" + } + ], + "name": "string", + "type": "string", + "workspace_transition": "start" + } + ], + "status": "pending", + "template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1", + "template_version_name": "string", + "transition": "start", + "updated_at": "2019-08-24T14:15:22Z", + "workspace_id": "0967198e-ec7b-4c6b-b4d3-f71244cadbe9", + "workspace_name": "string", + "workspace_owner_id": "e7078695-5279-4c86-8774-3ac2367a2fc7", + "workspace_owner_name": "string" +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------------------ | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.WorkspaceBuild](schemas.md#codersdkworkspacebuild) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + +## Cancel workspace build + +### Code samples + +```shell +# Example request using curl +curl -X PATCH http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/cancel \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`PATCH /workspacebuilds/{workspacebuild}/cancel` + +### Parameters + +| Name | In | Type | Required | Description | +| ---------------- | ---- | ------ | -------- | ------------------ | +| `workspacebuild` | path | string | true | Workspace build ID | + +### Example responses + +> 200 Response + +```json +{ + "detail": "string", + "message": "string", + "validations": [ + { + "detail": "string", + "field": "string" + } + ] +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------ | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Response](schemas.md#codersdkresponse) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + +## Get workspace build logs + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/logs \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /workspacebuilds/{workspacebuild}/logs` + +### Parameters + +| Name | In | Type | Required | Description | +| ---------------- | ----- | ------- | -------- | --------------------- | +| `workspacebuild` | path | string | true | Workspace build ID | +| `before` | query | integer | false | Before Unix timestamp | +| `after` | query | integer | false | After Unix timestamp | +| `follow` | query | boolean | false | Follow log stream | + +### Example responses + +> 200 Response + +```json +[ + { + "created_at": "2019-08-24T14:15:22Z", + "id": 0, + "log_level": "trace", + "log_source": "string", + "output": "string", + "stage": "string" + } +] +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | --------------------------------------------------------------------------- | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | array of [codersdk.ProvisionerJobLog](schemas.md#codersdkprovisionerjoblog) | + +