diff --git a/workspaces/backend/api/helpers.go b/workspaces/backend/api/helpers.go index ed14d3f8..0076a060 100644 --- a/workspaces/backend/api/helpers.go +++ b/workspaces/backend/api/helpers.go @@ -28,6 +28,7 @@ import ( // NOTE: error responses use the ErrorEnvelope type type Envelope[D any] struct { // TODO: make all declarations of Envelope use pointers for D + Data D `json:"data"` } diff --git a/workspaces/backend/api/namespaces_handler.go b/workspaces/backend/api/namespaces_handler.go index fb62d7d7..9405c2e0 100644 --- a/workspaces/backend/api/namespaces_handler.go +++ b/workspaces/backend/api/namespaces_handler.go @@ -28,6 +28,17 @@ import ( type NamespaceListEnvelope Envelope[[]models.Namespace] +// GetNamespacesHandler returns a list of all namespaces. +// +// @Summary Returns a list of all namespaces +// @Description Provides a list of all namespaces that the user has access to +// @Tags namespaces +// @Produce application/json +// @Success 200 {object} NamespaceListEnvelope "Successful namespaces response" +// @Failure 401 {object} ErrorEnvelope "Unauthorized" +// @Failure 403 {object} ErrorEnvelope "Forbidden" +// @Failure 500 {object} ErrorEnvelope "Internal server error" +// @Router /namespaces [get] func (a *App) GetNamespacesHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { // =========================== AUTH =========================== diff --git a/workspaces/backend/api/workspacekinds_handler.go b/workspaces/backend/api/workspacekinds_handler.go index 14b97995..b19fc327 100644 --- a/workspaces/backend/api/workspacekinds_handler.go +++ b/workspaces/backend/api/workspacekinds_handler.go @@ -35,6 +35,22 @@ type WorkspaceKindListEnvelope Envelope[[]models.WorkspaceKind] type WorkspaceKindEnvelope Envelope[models.WorkspaceKind] +// GetWorkspaceKindHandler retrieves a specific workspace kind by name. +// +// @Summary Get workspace kind +// @Description Returns details of a specific workspace kind identified by its name. Workspace kinds define the available types of workspaces that can be created. +// @Tags workspacekinds +// @Accept json +// @Produce json +// @Param name path string true "Name of the workspace kind" example(jupyterlab) +// @Success 200 {object} WorkspaceKindEnvelope "Successful operation. Returns the requested workspace kind details." +// @Failure 400 {object} ErrorEnvelope "Bad Request. Invalid workspace kind name format." +// @Failure 401 {object} ErrorEnvelope "Unauthorized. Authentication is required." +// @Failure 403 {object} ErrorEnvelope "Forbidden. User does not have permission to access the workspace kind." +// @Failure 404 {object} ErrorEnvelope "Not Found. Workspace kind does not exist." +// @Failure 500 {object} ErrorEnvelope "Internal server error. An unexpected error occurred on the server." +// @Router /workspacekinds/{name} [get] +// @Security ApiKeyAuth func (a *App) GetWorkspaceKindHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { name := ps.ByName(ResourceNamePathParam) @@ -74,6 +90,19 @@ func (a *App) GetWorkspaceKindHandler(w http.ResponseWriter, r *http.Request, ps a.dataResponse(w, r, responseEnvelope) } +// GetWorkspaceKindsHandler returns a list of all available workspace kinds. +// +// @Summary List workspace kinds +// @Description Returns a list of all available workspace kinds. Workspace kinds define the different types of workspaces that can be created in the system. +// @Tags workspacekinds +// @Accept json +// @Produce json +// @Success 200 {object} WorkspaceKindListEnvelope "Successful operation. Returns a list of all available workspace kinds." +// @Failure 401 {object} ErrorEnvelope "Unauthorized. Authentication is required." +// @Failure 403 {object} ErrorEnvelope "Forbidden. User does not have permission to list workspace kinds." +// @Failure 500 {object} ErrorEnvelope "Internal server error. An unexpected error occurred on the server." +// @Router /workspacekinds [get] +// @Security ApiKeyAuth func (a *App) GetWorkspaceKindsHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { // =========================== AUTH =========================== authPolicies := []*auth.ResourcePolicy{ diff --git a/workspaces/backend/api/workspaces_handler.go b/workspaces/backend/api/workspaces_handler.go index 889ba009..a64c04c7 100644 --- a/workspaces/backend/api/workspaces_handler.go +++ b/workspaces/backend/api/workspaces_handler.go @@ -39,6 +39,23 @@ type WorkspaceListEnvelope Envelope[[]models.Workspace] type WorkspaceEnvelope Envelope[models.Workspace] +// GetWorkspaceHandler retrieves a specific workspace by namespace and name. +// +// @Summary Get workspace +// @Description Returns details of a specific workspace identified by namespace and workspace name. +// @Tags workspaces +// @Accept json +// @Produce json +// @Param namespace path string true "Namespace of the workspace" example(kubeflow-user-example-com) +// @Param workspace_name path string true "Name of the workspace" example(my-workspace) +// @Success 200 {object} WorkspaceEnvelope "Successful operation. Returns the requested workspace details." +// @Failure 400 {object} ErrorEnvelope "Bad Request. Invalid namespace or workspace name format." +// @Failure 401 {object} ErrorEnvelope "Unauthorized. Authentication is required." +// @Failure 403 {object} ErrorEnvelope "Forbidden. User does not have permission to access the workspace." +// @Failure 404 {object} ErrorEnvelope "Not Found. Workspace does not exist." +// @Failure 500 {object} ErrorEnvelope "Internal server error. An unexpected error occurred on the server." +// @Router /workspaces/{namespace}/{workspace_name} [get] +// @Security ApiKeyAuth func (a *App) GetWorkspaceHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { namespace := ps.ByName(NamespacePathParam) workspaceName := ps.ByName(ResourceNamePathParam) @@ -83,6 +100,24 @@ func (a *App) GetWorkspaceHandler(w http.ResponseWriter, r *http.Request, ps htt a.dataResponse(w, r, responseEnvelope) } +// GetWorkspacesHandler returns a list of workspaces. +// +// @Summary List workspaces +// @Description Returns a list of workspaces. The endpoint supports two modes: +// @Description 1. List all workspaces across all namespaces (when no namespace is provided) +// @Description 2. List workspaces in a specific namespace (when namespace is provided) +// @Tags workspaces +// @Accept json +// @Produce json +// @Param namespace path string false "Namespace to filter workspaces. If not provided, returns all workspaces across all namespaces." example(kubeflow-user-example-com) +// @Success 200 {object} WorkspaceListEnvelope "Successful operation. Returns a list of workspaces." +// @Failure 400 {object} ErrorEnvelope "Bad Request. Invalid namespace format." +// @Failure 401 {object} ErrorEnvelope "Unauthorized. Authentication is required." +// @Failure 403 {object} ErrorEnvelope "Forbidden. User does not have permission to list workspaces." +// @Failure 500 {object} ErrorEnvelope "Internal server error. An unexpected error occurred on the server." +// @Router /workspaces [get] +// @Router /workspaces/{namespace} [get] +// @Security ApiKeyAuth func (a *App) GetWorkspacesHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { namespace := ps.ByName(NamespacePathParam) @@ -129,6 +164,23 @@ func (a *App) GetWorkspacesHandler(w http.ResponseWriter, r *http.Request, ps ht a.dataResponse(w, r, responseEnvelope) } +// CreateWorkspaceHandler creates a new workspace in the specified namespace. +// +// @Summary Create workspace +// @Description Creates a new workspace in the specified namespace. +// @Tags workspaces +// @Accept json +// @Produce json +// @Param namespace path string true "Namespace for the workspace" example(kubeflow-user-example-com) +// @Param body body WorkspaceCreateEnvelope true "Workspace creation configuration" +// @Success 201 {object} WorkspaceEnvelope "Workspace created successfully" +// @Failure 400 {object} ErrorEnvelope "Bad Request. Invalid request body or namespace format." +// @Failure 401 {object} ErrorEnvelope "Unauthorized. Authentication is required." +// @Failure 403 {object} ErrorEnvelope "Forbidden. User does not have permission to create workspace." +// @Failure 409 {object} ErrorEnvelope "Conflict. Workspace with the same name already exists." +// @Failure 500 {object} ErrorEnvelope "Internal server error. An unexpected error occurred on the server." +// @Router /workspaces/{namespace} [post] +// @Security ApiKeyAuth func (a *App) CreateWorkspaceHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { namespace := ps.ByName(NamespacePathParam) @@ -207,6 +259,23 @@ func (a *App) CreateWorkspaceHandler(w http.ResponseWriter, r *http.Request, ps a.createdResponse(w, r, responseEnvelope, location) } +// DeleteWorkspaceHandler deletes a specific workspace by namespace and name. +// +// @Summary Delete workspace +// @Description Deletes a specific workspace identified by namespace and workspace name. +// @Tags workspaces +// @Accept json +// @Produce json +// @Param namespace path string true "Namespace of the workspace" example(kubeflow-user-example-com) +// @Param workspace_name path string true "Name of the workspace" example(my-workspace) +// @Success 204 {object} nil "Workspace deleted successfully" +// @Failure 400 {object} ErrorEnvelope "Bad Request. Invalid namespace or workspace name format." +// @Failure 401 {object} ErrorEnvelope "Unauthorized. Authentication is required." +// @Failure 403 {object} ErrorEnvelope "Forbidden. User does not have permission to delete the workspace." +// @Failure 404 {object} ErrorEnvelope "Not Found. Workspace does not exist." +// @Failure 500 {object} ErrorEnvelope "Internal server error. An unexpected error occurred on the server." +// @Router /workspaces/{namespace}/{workspace_name} [delete] +// @Security ApiKeyAuth func (a *App) DeleteWorkspaceHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { namespace := ps.ByName(NamespacePathParam) workspaceName := ps.ByName(ResourceNamePathParam) diff --git a/workspaces/backend/openapi/docs.go b/workspaces/backend/openapi/docs.go index c16957b2..245a64fb 100644 --- a/workspaces/backend/openapi/docs.go +++ b/workspaces/backend/openapi/docs.go @@ -44,112 +44,1298 @@ const docTemplate = `{ } } } + }, + "/namespaces": { + "get": { + "description": "Provides a list of all namespaces that the user has access to", + "produces": [ + "application/json" + ], + "tags": [ + "namespaces" + ], + "summary": "Returns a list of all namespaces", + "responses": { + "200": { + "description": "Successful namespaces response", + "schema": { + "$ref": "#/definitions/api.NamespaceListEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + } + }, + "/workspacekinds": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Returns a list of all available workspace kinds. Workspace kinds define the different types of workspaces that can be created in the system.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspacekinds" + ], + "summary": "List workspace kinds", + "responses": { + "200": { + "description": "Successful operation. Returns a list of all available workspace kinds.", + "schema": { + "$ref": "#/definitions/api.WorkspaceKindListEnvelope" + } + }, + "401": { + "description": "Unauthorized. Authentication is required.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden. User does not have permission to list workspace kinds.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error. An unexpected error occurred on the server.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + } + }, + "/workspacekinds/{name}": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Returns details of a specific workspace kind identified by its name. Workspace kinds define the available types of workspaces that can be created.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspacekinds" + ], + "summary": "Get workspace kind", + "parameters": [ + { + "type": "string", + "example": "jupyterlab", + "description": "Name of the workspace kind", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Successful operation. Returns the requested workspace kind details.", + "schema": { + "$ref": "#/definitions/api.WorkspaceKindEnvelope" + } + }, + "400": { + "description": "Bad Request. Invalid workspace kind name format.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized. Authentication is required.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden. User does not have permission to access the workspace kind.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found. Workspace kind does not exist.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error. An unexpected error occurred on the server.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + } + }, + "/workspaces": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Returns a list of workspaces. The endpoint supports two modes:\n1. List all workspaces across all namespaces (when no namespace is provided)\n2. List workspaces in a specific namespace (when namespace is provided)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "List workspaces", + "responses": { + "200": { + "description": "Successful operation. Returns a list of workspaces.", + "schema": { + "$ref": "#/definitions/api.WorkspaceListEnvelope" + } + }, + "400": { + "description": "Bad Request. Invalid namespace format.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized. Authentication is required.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden. User does not have permission to list workspaces.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error. An unexpected error occurred on the server.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + } + }, + "/workspaces/{namespace}": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Returns a list of workspaces. The endpoint supports two modes:\n1. List all workspaces across all namespaces (when no namespace is provided)\n2. List workspaces in a specific namespace (when namespace is provided)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "List workspaces", + "parameters": [ + { + "type": "string", + "example": "kubeflow-user-example-com", + "description": "Namespace to filter workspaces. If not provided, returns all workspaces across all namespaces.", + "name": "namespace", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Successful operation. Returns a list of workspaces.", + "schema": { + "$ref": "#/definitions/api.WorkspaceListEnvelope" + } + }, + "400": { + "description": "Bad Request. Invalid namespace format.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized. Authentication is required.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden. User does not have permission to list workspaces.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error. An unexpected error occurred on the server.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + }, + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Creates a new workspace in the specified namespace.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "Create workspace", + "parameters": [ + { + "type": "string", + "example": "kubeflow-user-example-com", + "description": "Namespace for the workspace", + "name": "namespace", + "in": "path", + "required": true + }, + { + "description": "Workspace creation configuration", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.WorkspaceCreateEnvelope" + } + } + ], + "responses": { + "201": { + "description": "Workspace created successfully", + "schema": { + "$ref": "#/definitions/api.WorkspaceEnvelope" + } + }, + "400": { + "description": "Bad Request. Invalid request body or namespace format.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized. Authentication is required.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden. User does not have permission to create workspace.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict. Workspace with the same name already exists.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error. An unexpected error occurred on the server.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + } + }, + "/workspaces/{namespace}/{workspace_name}": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Returns details of a specific workspace identified by namespace and workspace name.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "Get workspace", + "parameters": [ + { + "type": "string", + "example": "kubeflow-user-example-com", + "description": "Namespace of the workspace", + "name": "namespace", + "in": "path", + "required": true + }, + { + "type": "string", + "example": "my-workspace", + "description": "Name of the workspace", + "name": "workspace_name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Successful operation. Returns the requested workspace details.", + "schema": { + "$ref": "#/definitions/api.WorkspaceEnvelope" + } + }, + "400": { + "description": "Bad Request. Invalid namespace or workspace name format.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized. Authentication is required.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden. User does not have permission to access the workspace.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found. Workspace does not exist.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error. An unexpected error occurred on the server.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + }, + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Deletes a specific workspace identified by namespace and workspace name.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "Delete workspace", + "parameters": [ + { + "type": "string", + "example": "kubeflow-user-example-com", + "description": "Namespace of the workspace", + "name": "namespace", + "in": "path", + "required": true + }, + { + "type": "string", + "example": "my-workspace", + "description": "Name of the workspace", + "name": "workspace_name", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Workspace deleted successfully" + }, + "400": { + "description": "Bad Request. Invalid namespace or workspace name format.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized. Authentication is required.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden. User does not have permission to delete the workspace.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found. Workspace does not exist.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error. An unexpected error occurred on the server.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + } } }, "definitions": { "api.ErrorCause": { "type": "object", "properties": { - "validation_errors": { + "validation_errors": { + "type": "array", + "items": { + "$ref": "#/definitions/api.ValidationError" + } + } + } + }, + "api.ErrorEnvelope": { + "type": "object", + "properties": { + "error": { + "$ref": "#/definitions/api.HTTPError" + } + } + }, + "api.HTTPError": { + "type": "object", + "properties": { + "cause": { + "$ref": "#/definitions/api.ErrorCause" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + } + } + }, + "api.NamespaceListEnvelope": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/namespaces.Namespace" + } + } + } + }, + "api.ValidationError": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "message": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/field.ErrorType" + } + } + }, + "api.WorkspaceCreateEnvelope": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/workspaces.WorkspaceCreate" + } + } + }, + "api.WorkspaceEnvelope": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/workspaces.Workspace" + } + } + }, + "api.WorkspaceKindEnvelope": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/workspacekinds.WorkspaceKind" + } + } + }, + "api.WorkspaceKindListEnvelope": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/workspacekinds.WorkspaceKind" + } + } + } + }, + "api.WorkspaceListEnvelope": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/workspaces.Workspace" + } + } + } + }, + "field.ErrorType": { + "type": "string", + "enum": [ + "FieldValueNotFound", + "FieldValueRequired", + "FieldValueDuplicate", + "FieldValueInvalid", + "FieldValueNotSupported", + "FieldValueForbidden", + "FieldValueTooLong", + "FieldValueTooMany", + "InternalError", + "FieldValueTypeInvalid" + ], + "x-enum-varnames": [ + "ErrorTypeNotFound", + "ErrorTypeRequired", + "ErrorTypeDuplicate", + "ErrorTypeInvalid", + "ErrorTypeNotSupported", + "ErrorTypeForbidden", + "ErrorTypeTooLong", + "ErrorTypeTooMany", + "ErrorTypeInternal", + "ErrorTypeTypeInvalid" + ] + }, + "health_check.HealthCheck": { + "type": "object", + "properties": { + "status": { + "$ref": "#/definitions/health_check.ServiceStatus" + }, + "systemInfo": { + "$ref": "#/definitions/health_check.SystemInfo" + } + } + }, + "health_check.ServiceStatus": { + "type": "string", + "enum": [ + "Healthy", + "Unhealthy" + ], + "x-enum-varnames": [ + "ServiceStatusHealthy", + "ServiceStatusUnhealthy" + ] + }, + "health_check.SystemInfo": { + "type": "object", + "properties": { + "version": { + "type": "string" + } + } + }, + "namespaces.Namespace": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, + "workspacekinds.ImageConfig": { + "type": "object", + "properties": { + "default": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "$ref": "#/definitions/workspacekinds.ImageConfigValue" + } + } + } + }, + "workspacekinds.ImageConfigValue": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/definitions/workspacekinds.OptionLabel" + } + }, + "redirect": { + "$ref": "#/definitions/workspacekinds.OptionRedirect" + } + } + }, + "workspacekinds.ImageRef": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + } + }, + "workspacekinds.OptionLabel": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "workspacekinds.OptionRedirect": { + "type": "object", + "properties": { + "message": { + "$ref": "#/definitions/workspacekinds.RedirectMessage" + }, + "to": { + "type": "string" + } + } + }, + "workspacekinds.PodConfig": { + "type": "object", + "properties": { + "default": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "$ref": "#/definitions/workspacekinds.PodConfigValue" + } + } + } + }, + "workspacekinds.PodConfigValue": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/definitions/workspacekinds.OptionLabel" + } + }, + "redirect": { + "$ref": "#/definitions/workspacekinds.OptionRedirect" + } + } + }, + "workspacekinds.PodMetadata": { + "type": "object", + "properties": { + "annotations": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "workspacekinds.PodTemplate": { + "type": "object", + "properties": { + "options": { + "$ref": "#/definitions/workspacekinds.PodTemplateOptions" + }, + "podMetadata": { + "$ref": "#/definitions/workspacekinds.PodMetadata" + }, + "volumeMounts": { + "$ref": "#/definitions/workspacekinds.PodVolumeMounts" + } + } + }, + "workspacekinds.PodTemplateOptions": { + "type": "object", + "properties": { + "imageConfig": { + "$ref": "#/definitions/workspacekinds.ImageConfig" + }, + "podConfig": { + "$ref": "#/definitions/workspacekinds.PodConfig" + } + } + }, + "workspacekinds.PodVolumeMounts": { + "type": "object", + "properties": { + "home": { + "type": "string" + } + } + }, + "workspacekinds.RedirectMessage": { + "type": "object", + "properties": { + "level": { + "$ref": "#/definitions/workspacekinds.RedirectMessageLevel" + }, + "text": { + "type": "string" + } + } + }, + "workspacekinds.RedirectMessageLevel": { + "type": "string", + "enum": [ + "Info", + "Warning", + "Danger" + ], + "x-enum-varnames": [ + "RedirectMessageLevelInfo", + "RedirectMessageLevelWarning", + "RedirectMessageLevelDanger" + ] + }, + "workspacekinds.WorkspaceKind": { + "type": "object", + "properties": { + "deprecated": { + "type": "boolean" + }, + "deprecationMessage": { + "type": "string" + }, + "description": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "icon": { + "$ref": "#/definitions/workspacekinds.ImageRef" + }, + "logo": { + "$ref": "#/definitions/workspacekinds.ImageRef" + }, + "name": { + "type": "string" + }, + "podTemplate": { + "$ref": "#/definitions/workspacekinds.PodTemplate" + } + } + }, + "workspaces.Activity": { + "type": "object", + "properties": { + "lastActivity": { + "description": "Unix Epoch time", + "type": "integer" + }, + "lastProbe": { + "$ref": "#/definitions/workspaces.LastProbeInfo" + }, + "lastUpdate": { + "description": "Unix Epoch time", + "type": "integer" + } + } + }, + "workspaces.HttpService": { + "type": "object", + "properties": { + "displayName": { + "type": "string" + }, + "httpPath": { + "type": "string" + } + } + }, + "workspaces.ImageConfig": { + "type": "object", + "properties": { + "current": { + "$ref": "#/definitions/workspaces.OptionInfo" + }, + "desired": { + "$ref": "#/definitions/workspaces.OptionInfo" + }, + "redirectChain": { "type": "array", "items": { - "$ref": "#/definitions/api.ValidationError" + "$ref": "#/definitions/workspaces.RedirectStep" } } } }, - "api.ErrorEnvelope": { + "workspaces.ImageRef": { "type": "object", "properties": { - "error": { - "$ref": "#/definitions/api.HTTPError" + "url": { + "type": "string" } } }, - "api.HTTPError": { + "workspaces.LastProbeInfo": { "type": "object", "properties": { - "cause": { - "$ref": "#/definitions/api.ErrorCause" + "endTimeMs": { + "description": "Unix Epoch time in milliseconds", + "type": "integer" }, - "code": { + "message": { "type": "string" }, - "message": { + "result": { + "$ref": "#/definitions/workspaces.ProbeResult" + }, + "startTimeMs": { + "description": "Unix Epoch time in milliseconds", + "type": "integer" + } + } + }, + "workspaces.OptionInfo": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "displayName": { "type": "string" + }, + "id": { + "type": "string" + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/definitions/workspaces.OptionLabel" + } } } }, - "api.ValidationError": { + "workspaces.OptionLabel": { "type": "object", "properties": { - "field": { + "key": { "type": "string" }, - "message": { + "value": { "type": "string" + } + } + }, + "workspaces.PodConfig": { + "type": "object", + "properties": { + "current": { + "$ref": "#/definitions/workspaces.OptionInfo" }, - "type": { - "$ref": "#/definitions/field.ErrorType" + "desired": { + "$ref": "#/definitions/workspaces.OptionInfo" + }, + "redirectChain": { + "type": "array", + "items": { + "$ref": "#/definitions/workspaces.RedirectStep" + } } } }, - "field.ErrorType": { + "workspaces.PodMetadata": { + "type": "object", + "properties": { + "annotations": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "workspaces.PodMetadataMutate": { + "type": "object", + "properties": { + "annotations": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "workspaces.PodTemplate": { + "type": "object", + "properties": { + "options": { + "$ref": "#/definitions/workspaces.PodTemplateOptions" + }, + "podMetadata": { + "$ref": "#/definitions/workspaces.PodMetadata" + }, + "volumes": { + "$ref": "#/definitions/workspaces.PodVolumes" + } + } + }, + "workspaces.PodTemplateMutate": { + "type": "object", + "properties": { + "options": { + "$ref": "#/definitions/workspaces.PodTemplateOptionsMutate" + }, + "podMetadata": { + "$ref": "#/definitions/workspaces.PodMetadataMutate" + }, + "volumes": { + "$ref": "#/definitions/workspaces.PodVolumesMutate" + } + } + }, + "workspaces.PodTemplateOptions": { + "type": "object", + "properties": { + "imageConfig": { + "$ref": "#/definitions/workspaces.ImageConfig" + }, + "podConfig": { + "$ref": "#/definitions/workspaces.PodConfig" + } + } + }, + "workspaces.PodTemplateOptionsMutate": { + "type": "object", + "properties": { + "imageConfig": { + "type": "string" + }, + "podConfig": { + "type": "string" + } + } + }, + "workspaces.PodVolumeInfo": { + "type": "object", + "properties": { + "mountPath": { + "type": "string" + }, + "pvcName": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + } + } + }, + "workspaces.PodVolumeMount": { + "type": "object", + "properties": { + "mountPath": { + "type": "string" + }, + "pvcName": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + } + } + }, + "workspaces.PodVolumes": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/workspaces.PodVolumeInfo" + } + }, + "home": { + "$ref": "#/definitions/workspaces.PodVolumeInfo" + } + } + }, + "workspaces.PodVolumesMutate": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/workspaces.PodVolumeMount" + } + }, + "home": { + "type": "string" + } + } + }, + "workspaces.ProbeResult": { "type": "string", "enum": [ - "FieldValueNotFound", - "FieldValueRequired", - "FieldValueDuplicate", - "FieldValueInvalid", - "FieldValueNotSupported", - "FieldValueForbidden", - "FieldValueTooLong", - "FieldValueTooMany", - "InternalError", - "FieldValueTypeInvalid" + "Success", + "Failure", + "Timeout" ], "x-enum-varnames": [ - "ErrorTypeNotFound", - "ErrorTypeRequired", - "ErrorTypeDuplicate", - "ErrorTypeInvalid", - "ErrorTypeNotSupported", - "ErrorTypeForbidden", - "ErrorTypeTooLong", - "ErrorTypeTooMany", - "ErrorTypeInternal", - "ErrorTypeTypeInvalid" + "ProbeResultSuccess", + "ProbeResultFailure", + "ProbeResultTimeout" ] }, - "health_check.HealthCheck": { + "workspaces.RedirectMessage": { "type": "object", "properties": { - "status": { - "$ref": "#/definitions/health_check.ServiceStatus" + "level": { + "$ref": "#/definitions/workspaces.RedirectMessageLevel" }, - "systemInfo": { - "$ref": "#/definitions/health_check.SystemInfo" + "text": { + "type": "string" } } }, - "health_check.ServiceStatus": { + "workspaces.RedirectMessageLevel": { "type": "string", "enum": [ - "Healthy", - "Unhealthy" + "Info", + "Warning", + "Danger" ], "x-enum-varnames": [ - "ServiceStatusHealthy", - "ServiceStatusUnhealthy" + "RedirectMessageLevelInfo", + "RedirectMessageLevelWarning", + "RedirectMessageLevelDanger" ] }, - "health_check.SystemInfo": { + "workspaces.RedirectStep": { "type": "object", "properties": { - "version": { + "message": { + "$ref": "#/definitions/workspaces.RedirectMessage" + }, + "sourceId": { + "type": "string" + }, + "targetId": { + "type": "string" + } + } + }, + "workspaces.Service": { + "type": "object", + "properties": { + "httpService": { + "$ref": "#/definitions/workspaces.HttpService" + } + } + }, + "workspaces.Workspace": { + "type": "object", + "properties": { + "activity": { + "$ref": "#/definitions/workspaces.Activity" + }, + "deferUpdates": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "paused": { + "type": "boolean" + }, + "pausedTime": { + "type": "integer" + }, + "pendingRestart": { + "type": "boolean" + }, + "podTemplate": { + "$ref": "#/definitions/workspaces.PodTemplate" + }, + "services": { + "type": "array", + "items": { + "$ref": "#/definitions/workspaces.Service" + } + }, + "state": { + "$ref": "#/definitions/workspaces.WorkspaceState" + }, + "stateMessage": { + "type": "string" + }, + "workspaceKind": { + "$ref": "#/definitions/workspaces.WorkspaceKindInfo" + } + } + }, + "workspaces.WorkspaceCreate": { + "type": "object", + "properties": { + "deferUpdates": { + "type": "boolean" + }, + "kind": { + "type": "string" + }, + "name": { + "type": "string" + }, + "paused": { + "type": "boolean" + }, + "podTemplate": { + "$ref": "#/definitions/workspaces.PodTemplateMutate" + } + } + }, + "workspaces.WorkspaceKindInfo": { + "type": "object", + "properties": { + "icon": { + "$ref": "#/definitions/workspaces.ImageRef" + }, + "logo": { + "$ref": "#/definitions/workspaces.ImageRef" + }, + "missing": { + "type": "boolean" + }, + "name": { "type": "string" } } + }, + "workspaces.WorkspaceState": { + "type": "string", + "enum": [ + "Running", + "Terminating", + "Paused", + "Pending", + "Error", + "Unknown" + ], + "x-enum-varnames": [ + "WorkspaceStateRunning", + "WorkspaceStateTerminating", + "WorkspaceStatePaused", + "WorkspaceStatePending", + "WorkspaceStateError", + "WorkspaceStateUnknown" + ] } } }` diff --git a/workspaces/backend/openapi/swagger.json b/workspaces/backend/openapi/swagger.json index 50644d14..fc438928 100644 --- a/workspaces/backend/openapi/swagger.json +++ b/workspaces/backend/openapi/swagger.json @@ -42,112 +42,1298 @@ } } } + }, + "/namespaces": { + "get": { + "description": "Provides a list of all namespaces that the user has access to", + "produces": [ + "application/json" + ], + "tags": [ + "namespaces" + ], + "summary": "Returns a list of all namespaces", + "responses": { + "200": { + "description": "Successful namespaces response", + "schema": { + "$ref": "#/definitions/api.NamespaceListEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + } + }, + "/workspacekinds": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Returns a list of all available workspace kinds. Workspace kinds define the different types of workspaces that can be created in the system.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspacekinds" + ], + "summary": "List workspace kinds", + "responses": { + "200": { + "description": "Successful operation. Returns a list of all available workspace kinds.", + "schema": { + "$ref": "#/definitions/api.WorkspaceKindListEnvelope" + } + }, + "401": { + "description": "Unauthorized. Authentication is required.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden. User does not have permission to list workspace kinds.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error. An unexpected error occurred on the server.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + } + }, + "/workspacekinds/{name}": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Returns details of a specific workspace kind identified by its name. Workspace kinds define the available types of workspaces that can be created.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspacekinds" + ], + "summary": "Get workspace kind", + "parameters": [ + { + "type": "string", + "example": "jupyterlab", + "description": "Name of the workspace kind", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Successful operation. Returns the requested workspace kind details.", + "schema": { + "$ref": "#/definitions/api.WorkspaceKindEnvelope" + } + }, + "400": { + "description": "Bad Request. Invalid workspace kind name format.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized. Authentication is required.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden. User does not have permission to access the workspace kind.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found. Workspace kind does not exist.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error. An unexpected error occurred on the server.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + } + }, + "/workspaces": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Returns a list of workspaces. The endpoint supports two modes:\n1. List all workspaces across all namespaces (when no namespace is provided)\n2. List workspaces in a specific namespace (when namespace is provided)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "List workspaces", + "responses": { + "200": { + "description": "Successful operation. Returns a list of workspaces.", + "schema": { + "$ref": "#/definitions/api.WorkspaceListEnvelope" + } + }, + "400": { + "description": "Bad Request. Invalid namespace format.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized. Authentication is required.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden. User does not have permission to list workspaces.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error. An unexpected error occurred on the server.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + } + }, + "/workspaces/{namespace}": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Returns a list of workspaces. The endpoint supports two modes:\n1. List all workspaces across all namespaces (when no namespace is provided)\n2. List workspaces in a specific namespace (when namespace is provided)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "List workspaces", + "parameters": [ + { + "type": "string", + "example": "kubeflow-user-example-com", + "description": "Namespace to filter workspaces. If not provided, returns all workspaces across all namespaces.", + "name": "namespace", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Successful operation. Returns a list of workspaces.", + "schema": { + "$ref": "#/definitions/api.WorkspaceListEnvelope" + } + }, + "400": { + "description": "Bad Request. Invalid namespace format.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized. Authentication is required.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden. User does not have permission to list workspaces.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error. An unexpected error occurred on the server.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + }, + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Creates a new workspace in the specified namespace.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "Create workspace", + "parameters": [ + { + "type": "string", + "example": "kubeflow-user-example-com", + "description": "Namespace for the workspace", + "name": "namespace", + "in": "path", + "required": true + }, + { + "description": "Workspace creation configuration", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.WorkspaceCreateEnvelope" + } + } + ], + "responses": { + "201": { + "description": "Workspace created successfully", + "schema": { + "$ref": "#/definitions/api.WorkspaceEnvelope" + } + }, + "400": { + "description": "Bad Request. Invalid request body or namespace format.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized. Authentication is required.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden. User does not have permission to create workspace.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict. Workspace with the same name already exists.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error. An unexpected error occurred on the server.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + } + }, + "/workspaces/{namespace}/{workspace_name}": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Returns details of a specific workspace identified by namespace and workspace name.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "Get workspace", + "parameters": [ + { + "type": "string", + "example": "kubeflow-user-example-com", + "description": "Namespace of the workspace", + "name": "namespace", + "in": "path", + "required": true + }, + { + "type": "string", + "example": "my-workspace", + "description": "Name of the workspace", + "name": "workspace_name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Successful operation. Returns the requested workspace details.", + "schema": { + "$ref": "#/definitions/api.WorkspaceEnvelope" + } + }, + "400": { + "description": "Bad Request. Invalid namespace or workspace name format.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized. Authentication is required.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden. User does not have permission to access the workspace.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found. Workspace does not exist.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error. An unexpected error occurred on the server.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + }, + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Deletes a specific workspace identified by namespace and workspace name.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "Delete workspace", + "parameters": [ + { + "type": "string", + "example": "kubeflow-user-example-com", + "description": "Namespace of the workspace", + "name": "namespace", + "in": "path", + "required": true + }, + { + "type": "string", + "example": "my-workspace", + "description": "Name of the workspace", + "name": "workspace_name", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Workspace deleted successfully" + }, + "400": { + "description": "Bad Request. Invalid namespace or workspace name format.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized. Authentication is required.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden. User does not have permission to delete the workspace.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found. Workspace does not exist.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + }, + "500": { + "description": "Internal server error. An unexpected error occurred on the server.", + "schema": { + "$ref": "#/definitions/api.ErrorEnvelope" + } + } + } + } } }, "definitions": { "api.ErrorCause": { "type": "object", "properties": { - "validation_errors": { + "validation_errors": { + "type": "array", + "items": { + "$ref": "#/definitions/api.ValidationError" + } + } + } + }, + "api.ErrorEnvelope": { + "type": "object", + "properties": { + "error": { + "$ref": "#/definitions/api.HTTPError" + } + } + }, + "api.HTTPError": { + "type": "object", + "properties": { + "cause": { + "$ref": "#/definitions/api.ErrorCause" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + } + } + }, + "api.NamespaceListEnvelope": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/namespaces.Namespace" + } + } + } + }, + "api.ValidationError": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "message": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/field.ErrorType" + } + } + }, + "api.WorkspaceCreateEnvelope": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/workspaces.WorkspaceCreate" + } + } + }, + "api.WorkspaceEnvelope": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/workspaces.Workspace" + } + } + }, + "api.WorkspaceKindEnvelope": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/workspacekinds.WorkspaceKind" + } + } + }, + "api.WorkspaceKindListEnvelope": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/workspacekinds.WorkspaceKind" + } + } + } + }, + "api.WorkspaceListEnvelope": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/workspaces.Workspace" + } + } + } + }, + "field.ErrorType": { + "type": "string", + "enum": [ + "FieldValueNotFound", + "FieldValueRequired", + "FieldValueDuplicate", + "FieldValueInvalid", + "FieldValueNotSupported", + "FieldValueForbidden", + "FieldValueTooLong", + "FieldValueTooMany", + "InternalError", + "FieldValueTypeInvalid" + ], + "x-enum-varnames": [ + "ErrorTypeNotFound", + "ErrorTypeRequired", + "ErrorTypeDuplicate", + "ErrorTypeInvalid", + "ErrorTypeNotSupported", + "ErrorTypeForbidden", + "ErrorTypeTooLong", + "ErrorTypeTooMany", + "ErrorTypeInternal", + "ErrorTypeTypeInvalid" + ] + }, + "health_check.HealthCheck": { + "type": "object", + "properties": { + "status": { + "$ref": "#/definitions/health_check.ServiceStatus" + }, + "systemInfo": { + "$ref": "#/definitions/health_check.SystemInfo" + } + } + }, + "health_check.ServiceStatus": { + "type": "string", + "enum": [ + "Healthy", + "Unhealthy" + ], + "x-enum-varnames": [ + "ServiceStatusHealthy", + "ServiceStatusUnhealthy" + ] + }, + "health_check.SystemInfo": { + "type": "object", + "properties": { + "version": { + "type": "string" + } + } + }, + "namespaces.Namespace": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, + "workspacekinds.ImageConfig": { + "type": "object", + "properties": { + "default": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "$ref": "#/definitions/workspacekinds.ImageConfigValue" + } + } + } + }, + "workspacekinds.ImageConfigValue": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/definitions/workspacekinds.OptionLabel" + } + }, + "redirect": { + "$ref": "#/definitions/workspacekinds.OptionRedirect" + } + } + }, + "workspacekinds.ImageRef": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + } + }, + "workspacekinds.OptionLabel": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "workspacekinds.OptionRedirect": { + "type": "object", + "properties": { + "message": { + "$ref": "#/definitions/workspacekinds.RedirectMessage" + }, + "to": { + "type": "string" + } + } + }, + "workspacekinds.PodConfig": { + "type": "object", + "properties": { + "default": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "$ref": "#/definitions/workspacekinds.PodConfigValue" + } + } + } + }, + "workspacekinds.PodConfigValue": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/definitions/workspacekinds.OptionLabel" + } + }, + "redirect": { + "$ref": "#/definitions/workspacekinds.OptionRedirect" + } + } + }, + "workspacekinds.PodMetadata": { + "type": "object", + "properties": { + "annotations": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "workspacekinds.PodTemplate": { + "type": "object", + "properties": { + "options": { + "$ref": "#/definitions/workspacekinds.PodTemplateOptions" + }, + "podMetadata": { + "$ref": "#/definitions/workspacekinds.PodMetadata" + }, + "volumeMounts": { + "$ref": "#/definitions/workspacekinds.PodVolumeMounts" + } + } + }, + "workspacekinds.PodTemplateOptions": { + "type": "object", + "properties": { + "imageConfig": { + "$ref": "#/definitions/workspacekinds.ImageConfig" + }, + "podConfig": { + "$ref": "#/definitions/workspacekinds.PodConfig" + } + } + }, + "workspacekinds.PodVolumeMounts": { + "type": "object", + "properties": { + "home": { + "type": "string" + } + } + }, + "workspacekinds.RedirectMessage": { + "type": "object", + "properties": { + "level": { + "$ref": "#/definitions/workspacekinds.RedirectMessageLevel" + }, + "text": { + "type": "string" + } + } + }, + "workspacekinds.RedirectMessageLevel": { + "type": "string", + "enum": [ + "Info", + "Warning", + "Danger" + ], + "x-enum-varnames": [ + "RedirectMessageLevelInfo", + "RedirectMessageLevelWarning", + "RedirectMessageLevelDanger" + ] + }, + "workspacekinds.WorkspaceKind": { + "type": "object", + "properties": { + "deprecated": { + "type": "boolean" + }, + "deprecationMessage": { + "type": "string" + }, + "description": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "icon": { + "$ref": "#/definitions/workspacekinds.ImageRef" + }, + "logo": { + "$ref": "#/definitions/workspacekinds.ImageRef" + }, + "name": { + "type": "string" + }, + "podTemplate": { + "$ref": "#/definitions/workspacekinds.PodTemplate" + } + } + }, + "workspaces.Activity": { + "type": "object", + "properties": { + "lastActivity": { + "description": "Unix Epoch time", + "type": "integer" + }, + "lastProbe": { + "$ref": "#/definitions/workspaces.LastProbeInfo" + }, + "lastUpdate": { + "description": "Unix Epoch time", + "type": "integer" + } + } + }, + "workspaces.HttpService": { + "type": "object", + "properties": { + "displayName": { + "type": "string" + }, + "httpPath": { + "type": "string" + } + } + }, + "workspaces.ImageConfig": { + "type": "object", + "properties": { + "current": { + "$ref": "#/definitions/workspaces.OptionInfo" + }, + "desired": { + "$ref": "#/definitions/workspaces.OptionInfo" + }, + "redirectChain": { "type": "array", "items": { - "$ref": "#/definitions/api.ValidationError" + "$ref": "#/definitions/workspaces.RedirectStep" } } } }, - "api.ErrorEnvelope": { + "workspaces.ImageRef": { "type": "object", "properties": { - "error": { - "$ref": "#/definitions/api.HTTPError" + "url": { + "type": "string" } } }, - "api.HTTPError": { + "workspaces.LastProbeInfo": { "type": "object", "properties": { - "cause": { - "$ref": "#/definitions/api.ErrorCause" + "endTimeMs": { + "description": "Unix Epoch time in milliseconds", + "type": "integer" }, - "code": { + "message": { "type": "string" }, - "message": { + "result": { + "$ref": "#/definitions/workspaces.ProbeResult" + }, + "startTimeMs": { + "description": "Unix Epoch time in milliseconds", + "type": "integer" + } + } + }, + "workspaces.OptionInfo": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "displayName": { "type": "string" + }, + "id": { + "type": "string" + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/definitions/workspaces.OptionLabel" + } } } }, - "api.ValidationError": { + "workspaces.OptionLabel": { "type": "object", "properties": { - "field": { + "key": { "type": "string" }, - "message": { + "value": { "type": "string" + } + } + }, + "workspaces.PodConfig": { + "type": "object", + "properties": { + "current": { + "$ref": "#/definitions/workspaces.OptionInfo" }, - "type": { - "$ref": "#/definitions/field.ErrorType" + "desired": { + "$ref": "#/definitions/workspaces.OptionInfo" + }, + "redirectChain": { + "type": "array", + "items": { + "$ref": "#/definitions/workspaces.RedirectStep" + } } } }, - "field.ErrorType": { + "workspaces.PodMetadata": { + "type": "object", + "properties": { + "annotations": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "workspaces.PodMetadataMutate": { + "type": "object", + "properties": { + "annotations": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "workspaces.PodTemplate": { + "type": "object", + "properties": { + "options": { + "$ref": "#/definitions/workspaces.PodTemplateOptions" + }, + "podMetadata": { + "$ref": "#/definitions/workspaces.PodMetadata" + }, + "volumes": { + "$ref": "#/definitions/workspaces.PodVolumes" + } + } + }, + "workspaces.PodTemplateMutate": { + "type": "object", + "properties": { + "options": { + "$ref": "#/definitions/workspaces.PodTemplateOptionsMutate" + }, + "podMetadata": { + "$ref": "#/definitions/workspaces.PodMetadataMutate" + }, + "volumes": { + "$ref": "#/definitions/workspaces.PodVolumesMutate" + } + } + }, + "workspaces.PodTemplateOptions": { + "type": "object", + "properties": { + "imageConfig": { + "$ref": "#/definitions/workspaces.ImageConfig" + }, + "podConfig": { + "$ref": "#/definitions/workspaces.PodConfig" + } + } + }, + "workspaces.PodTemplateOptionsMutate": { + "type": "object", + "properties": { + "imageConfig": { + "type": "string" + }, + "podConfig": { + "type": "string" + } + } + }, + "workspaces.PodVolumeInfo": { + "type": "object", + "properties": { + "mountPath": { + "type": "string" + }, + "pvcName": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + } + } + }, + "workspaces.PodVolumeMount": { + "type": "object", + "properties": { + "mountPath": { + "type": "string" + }, + "pvcName": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + } + } + }, + "workspaces.PodVolumes": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/workspaces.PodVolumeInfo" + } + }, + "home": { + "$ref": "#/definitions/workspaces.PodVolumeInfo" + } + } + }, + "workspaces.PodVolumesMutate": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/workspaces.PodVolumeMount" + } + }, + "home": { + "type": "string" + } + } + }, + "workspaces.ProbeResult": { "type": "string", "enum": [ - "FieldValueNotFound", - "FieldValueRequired", - "FieldValueDuplicate", - "FieldValueInvalid", - "FieldValueNotSupported", - "FieldValueForbidden", - "FieldValueTooLong", - "FieldValueTooMany", - "InternalError", - "FieldValueTypeInvalid" + "Success", + "Failure", + "Timeout" ], "x-enum-varnames": [ - "ErrorTypeNotFound", - "ErrorTypeRequired", - "ErrorTypeDuplicate", - "ErrorTypeInvalid", - "ErrorTypeNotSupported", - "ErrorTypeForbidden", - "ErrorTypeTooLong", - "ErrorTypeTooMany", - "ErrorTypeInternal", - "ErrorTypeTypeInvalid" + "ProbeResultSuccess", + "ProbeResultFailure", + "ProbeResultTimeout" ] }, - "health_check.HealthCheck": { + "workspaces.RedirectMessage": { "type": "object", "properties": { - "status": { - "$ref": "#/definitions/health_check.ServiceStatus" + "level": { + "$ref": "#/definitions/workspaces.RedirectMessageLevel" }, - "systemInfo": { - "$ref": "#/definitions/health_check.SystemInfo" + "text": { + "type": "string" } } }, - "health_check.ServiceStatus": { + "workspaces.RedirectMessageLevel": { "type": "string", "enum": [ - "Healthy", - "Unhealthy" + "Info", + "Warning", + "Danger" ], "x-enum-varnames": [ - "ServiceStatusHealthy", - "ServiceStatusUnhealthy" + "RedirectMessageLevelInfo", + "RedirectMessageLevelWarning", + "RedirectMessageLevelDanger" ] }, - "health_check.SystemInfo": { + "workspaces.RedirectStep": { "type": "object", "properties": { - "version": { + "message": { + "$ref": "#/definitions/workspaces.RedirectMessage" + }, + "sourceId": { + "type": "string" + }, + "targetId": { + "type": "string" + } + } + }, + "workspaces.Service": { + "type": "object", + "properties": { + "httpService": { + "$ref": "#/definitions/workspaces.HttpService" + } + } + }, + "workspaces.Workspace": { + "type": "object", + "properties": { + "activity": { + "$ref": "#/definitions/workspaces.Activity" + }, + "deferUpdates": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "paused": { + "type": "boolean" + }, + "pausedTime": { + "type": "integer" + }, + "pendingRestart": { + "type": "boolean" + }, + "podTemplate": { + "$ref": "#/definitions/workspaces.PodTemplate" + }, + "services": { + "type": "array", + "items": { + "$ref": "#/definitions/workspaces.Service" + } + }, + "state": { + "$ref": "#/definitions/workspaces.WorkspaceState" + }, + "stateMessage": { + "type": "string" + }, + "workspaceKind": { + "$ref": "#/definitions/workspaces.WorkspaceKindInfo" + } + } + }, + "workspaces.WorkspaceCreate": { + "type": "object", + "properties": { + "deferUpdates": { + "type": "boolean" + }, + "kind": { + "type": "string" + }, + "name": { + "type": "string" + }, + "paused": { + "type": "boolean" + }, + "podTemplate": { + "$ref": "#/definitions/workspaces.PodTemplateMutate" + } + } + }, + "workspaces.WorkspaceKindInfo": { + "type": "object", + "properties": { + "icon": { + "$ref": "#/definitions/workspaces.ImageRef" + }, + "logo": { + "$ref": "#/definitions/workspaces.ImageRef" + }, + "missing": { + "type": "boolean" + }, + "name": { "type": "string" } } + }, + "workspaces.WorkspaceState": { + "type": "string", + "enum": [ + "Running", + "Terminating", + "Paused", + "Pending", + "Error", + "Unknown" + ], + "x-enum-varnames": [ + "WorkspaceStateRunning", + "WorkspaceStateTerminating", + "WorkspaceStatePaused", + "WorkspaceStatePending", + "WorkspaceStateError", + "WorkspaceStateUnknown" + ] } } } \ No newline at end of file diff --git a/workspaces/backend/openapi/swagger.yaml b/workspaces/backend/openapi/swagger.yaml index 89027d92..27cf9bcc 100644 --- a/workspaces/backend/openapi/swagger.yaml +++ b/workspaces/backend/openapi/swagger.yaml @@ -21,6 +21,13 @@ definitions: message: type: string type: object + api.NamespaceListEnvelope: + properties: + data: + items: + $ref: '#/definitions/namespaces.Namespace' + type: array + type: object api.ValidationError: properties: field: @@ -30,6 +37,35 @@ definitions: type: $ref: '#/definitions/field.ErrorType' type: object + api.WorkspaceCreateEnvelope: + properties: + data: + $ref: '#/definitions/workspaces.WorkspaceCreate' + type: object + api.WorkspaceEnvelope: + properties: + data: + $ref: '#/definitions/workspaces.Workspace' + type: object + api.WorkspaceKindEnvelope: + properties: + data: + $ref: '#/definitions/workspacekinds.WorkspaceKind' + type: object + api.WorkspaceKindListEnvelope: + properties: + data: + items: + $ref: '#/definitions/workspacekinds.WorkspaceKind' + type: array + type: object + api.WorkspaceListEnvelope: + properties: + data: + items: + $ref: '#/definitions/workspaces.Workspace' + type: array + type: object field.ErrorType: enum: - FieldValueNotFound @@ -74,6 +110,430 @@ definitions: version: type: string type: object + namespaces.Namespace: + properties: + name: + type: string + type: object + workspacekinds.ImageConfig: + properties: + default: + type: string + values: + items: + $ref: '#/definitions/workspacekinds.ImageConfigValue' + type: array + type: object + workspacekinds.ImageConfigValue: + properties: + description: + type: string + displayName: + type: string + hidden: + type: boolean + id: + type: string + labels: + items: + $ref: '#/definitions/workspacekinds.OptionLabel' + type: array + redirect: + $ref: '#/definitions/workspacekinds.OptionRedirect' + type: object + workspacekinds.ImageRef: + properties: + url: + type: string + type: object + workspacekinds.OptionLabel: + properties: + key: + type: string + value: + type: string + type: object + workspacekinds.OptionRedirect: + properties: + message: + $ref: '#/definitions/workspacekinds.RedirectMessage' + to: + type: string + type: object + workspacekinds.PodConfig: + properties: + default: + type: string + values: + items: + $ref: '#/definitions/workspacekinds.PodConfigValue' + type: array + type: object + workspacekinds.PodConfigValue: + properties: + description: + type: string + displayName: + type: string + hidden: + type: boolean + id: + type: string + labels: + items: + $ref: '#/definitions/workspacekinds.OptionLabel' + type: array + redirect: + $ref: '#/definitions/workspacekinds.OptionRedirect' + type: object + workspacekinds.PodMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + workspacekinds.PodTemplate: + properties: + options: + $ref: '#/definitions/workspacekinds.PodTemplateOptions' + podMetadata: + $ref: '#/definitions/workspacekinds.PodMetadata' + volumeMounts: + $ref: '#/definitions/workspacekinds.PodVolumeMounts' + type: object + workspacekinds.PodTemplateOptions: + properties: + imageConfig: + $ref: '#/definitions/workspacekinds.ImageConfig' + podConfig: + $ref: '#/definitions/workspacekinds.PodConfig' + type: object + workspacekinds.PodVolumeMounts: + properties: + home: + type: string + type: object + workspacekinds.RedirectMessage: + properties: + level: + $ref: '#/definitions/workspacekinds.RedirectMessageLevel' + text: + type: string + type: object + workspacekinds.RedirectMessageLevel: + enum: + - Info + - Warning + - Danger + type: string + x-enum-varnames: + - RedirectMessageLevelInfo + - RedirectMessageLevelWarning + - RedirectMessageLevelDanger + workspacekinds.WorkspaceKind: + properties: + deprecated: + type: boolean + deprecationMessage: + type: string + description: + type: string + displayName: + type: string + hidden: + type: boolean + icon: + $ref: '#/definitions/workspacekinds.ImageRef' + logo: + $ref: '#/definitions/workspacekinds.ImageRef' + name: + type: string + podTemplate: + $ref: '#/definitions/workspacekinds.PodTemplate' + type: object + workspaces.Activity: + properties: + lastActivity: + description: Unix Epoch time + type: integer + lastProbe: + $ref: '#/definitions/workspaces.LastProbeInfo' + lastUpdate: + description: Unix Epoch time + type: integer + type: object + workspaces.HttpService: + properties: + displayName: + type: string + httpPath: + type: string + type: object + workspaces.ImageConfig: + properties: + current: + $ref: '#/definitions/workspaces.OptionInfo' + desired: + $ref: '#/definitions/workspaces.OptionInfo' + redirectChain: + items: + $ref: '#/definitions/workspaces.RedirectStep' + type: array + type: object + workspaces.ImageRef: + properties: + url: + type: string + type: object + workspaces.LastProbeInfo: + properties: + endTimeMs: + description: Unix Epoch time in milliseconds + type: integer + message: + type: string + result: + $ref: '#/definitions/workspaces.ProbeResult' + startTimeMs: + description: Unix Epoch time in milliseconds + type: integer + type: object + workspaces.OptionInfo: + properties: + description: + type: string + displayName: + type: string + id: + type: string + labels: + items: + $ref: '#/definitions/workspaces.OptionLabel' + type: array + type: object + workspaces.OptionLabel: + properties: + key: + type: string + value: + type: string + type: object + workspaces.PodConfig: + properties: + current: + $ref: '#/definitions/workspaces.OptionInfo' + desired: + $ref: '#/definitions/workspaces.OptionInfo' + redirectChain: + items: + $ref: '#/definitions/workspaces.RedirectStep' + type: array + type: object + workspaces.PodMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + workspaces.PodMetadataMutate: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + workspaces.PodTemplate: + properties: + options: + $ref: '#/definitions/workspaces.PodTemplateOptions' + podMetadata: + $ref: '#/definitions/workspaces.PodMetadata' + volumes: + $ref: '#/definitions/workspaces.PodVolumes' + type: object + workspaces.PodTemplateMutate: + properties: + options: + $ref: '#/definitions/workspaces.PodTemplateOptionsMutate' + podMetadata: + $ref: '#/definitions/workspaces.PodMetadataMutate' + volumes: + $ref: '#/definitions/workspaces.PodVolumesMutate' + type: object + workspaces.PodTemplateOptions: + properties: + imageConfig: + $ref: '#/definitions/workspaces.ImageConfig' + podConfig: + $ref: '#/definitions/workspaces.PodConfig' + type: object + workspaces.PodTemplateOptionsMutate: + properties: + imageConfig: + type: string + podConfig: + type: string + type: object + workspaces.PodVolumeInfo: + properties: + mountPath: + type: string + pvcName: + type: string + readOnly: + type: boolean + type: object + workspaces.PodVolumeMount: + properties: + mountPath: + type: string + pvcName: + type: string + readOnly: + type: boolean + type: object + workspaces.PodVolumes: + properties: + data: + items: + $ref: '#/definitions/workspaces.PodVolumeInfo' + type: array + home: + $ref: '#/definitions/workspaces.PodVolumeInfo' + type: object + workspaces.PodVolumesMutate: + properties: + data: + items: + $ref: '#/definitions/workspaces.PodVolumeMount' + type: array + home: + type: string + type: object + workspaces.ProbeResult: + enum: + - Success + - Failure + - Timeout + type: string + x-enum-varnames: + - ProbeResultSuccess + - ProbeResultFailure + - ProbeResultTimeout + workspaces.RedirectMessage: + properties: + level: + $ref: '#/definitions/workspaces.RedirectMessageLevel' + text: + type: string + type: object + workspaces.RedirectMessageLevel: + enum: + - Info + - Warning + - Danger + type: string + x-enum-varnames: + - RedirectMessageLevelInfo + - RedirectMessageLevelWarning + - RedirectMessageLevelDanger + workspaces.RedirectStep: + properties: + message: + $ref: '#/definitions/workspaces.RedirectMessage' + sourceId: + type: string + targetId: + type: string + type: object + workspaces.Service: + properties: + httpService: + $ref: '#/definitions/workspaces.HttpService' + type: object + workspaces.Workspace: + properties: + activity: + $ref: '#/definitions/workspaces.Activity' + deferUpdates: + type: boolean + name: + type: string + namespace: + type: string + paused: + type: boolean + pausedTime: + type: integer + pendingRestart: + type: boolean + podTemplate: + $ref: '#/definitions/workspaces.PodTemplate' + services: + items: + $ref: '#/definitions/workspaces.Service' + type: array + state: + $ref: '#/definitions/workspaces.WorkspaceState' + stateMessage: + type: string + workspaceKind: + $ref: '#/definitions/workspaces.WorkspaceKindInfo' + type: object + workspaces.WorkspaceCreate: + properties: + deferUpdates: + type: boolean + kind: + type: string + name: + type: string + paused: + type: boolean + podTemplate: + $ref: '#/definitions/workspaces.PodTemplateMutate' + type: object + workspaces.WorkspaceKindInfo: + properties: + icon: + $ref: '#/definitions/workspaces.ImageRef' + logo: + $ref: '#/definitions/workspaces.ImageRef' + missing: + type: boolean + name: + type: string + type: object + workspaces.WorkspaceState: + enum: + - Running + - Terminating + - Paused + - Pending + - Error + - Unknown + type: string + x-enum-varnames: + - WorkspaceStateRunning + - WorkspaceStateTerminating + - WorkspaceStatePaused + - WorkspaceStatePending + - WorkspaceStateError + - WorkspaceStateUnknown host: localhost:4000 info: contact: {} @@ -103,6 +563,345 @@ paths: summary: Returns the health status of the application tags: - healthcheck + /namespaces: + get: + description: Provides a list of all namespaces that the user has access to + produces: + - application/json + responses: + "200": + description: Successful namespaces response + schema: + $ref: '#/definitions/api.NamespaceListEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "500": + description: Internal server error + schema: + $ref: '#/definitions/api.ErrorEnvelope' + summary: Returns a list of all namespaces + tags: + - namespaces + /workspacekinds: + get: + consumes: + - application/json + description: Returns a list of all available workspace kinds. Workspace kinds + define the different types of workspaces that can be created in the system. + produces: + - application/json + responses: + "200": + description: Successful operation. Returns a list of all available workspace + kinds. + schema: + $ref: '#/definitions/api.WorkspaceKindListEnvelope' + "401": + description: Unauthorized. Authentication is required. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "403": + description: Forbidden. User does not have permission to list workspace + kinds. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "500": + description: Internal server error. An unexpected error occurred on the + server. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + security: + - ApiKeyAuth: [] + summary: List workspace kinds + tags: + - workspacekinds + /workspacekinds/{name}: + get: + consumes: + - application/json + description: Returns details of a specific workspace kind identified by its + name. Workspace kinds define the available types of workspaces that can be + created. + parameters: + - description: Name of the workspace kind + example: jupyterlab + in: path + name: name + required: true + type: string + produces: + - application/json + responses: + "200": + description: Successful operation. Returns the requested workspace kind + details. + schema: + $ref: '#/definitions/api.WorkspaceKindEnvelope' + "400": + description: Bad Request. Invalid workspace kind name format. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "401": + description: Unauthorized. Authentication is required. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "403": + description: Forbidden. User does not have permission to access the workspace + kind. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "404": + description: Not Found. Workspace kind does not exist. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "500": + description: Internal server error. An unexpected error occurred on the + server. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + security: + - ApiKeyAuth: [] + summary: Get workspace kind + tags: + - workspacekinds + /workspaces: + get: + consumes: + - application/json + description: |- + Returns a list of workspaces. The endpoint supports two modes: + 1. List all workspaces across all namespaces (when no namespace is provided) + 2. List workspaces in a specific namespace (when namespace is provided) + produces: + - application/json + responses: + "200": + description: Successful operation. Returns a list of workspaces. + schema: + $ref: '#/definitions/api.WorkspaceListEnvelope' + "400": + description: Bad Request. Invalid namespace format. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "401": + description: Unauthorized. Authentication is required. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "403": + description: Forbidden. User does not have permission to list workspaces. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "500": + description: Internal server error. An unexpected error occurred on the + server. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + security: + - ApiKeyAuth: [] + summary: List workspaces + tags: + - workspaces + /workspaces/{namespace}: + get: + consumes: + - application/json + description: |- + Returns a list of workspaces. The endpoint supports two modes: + 1. List all workspaces across all namespaces (when no namespace is provided) + 2. List workspaces in a specific namespace (when namespace is provided) + parameters: + - description: Namespace to filter workspaces. If not provided, returns all + workspaces across all namespaces. + example: kubeflow-user-example-com + in: path + name: namespace + type: string + produces: + - application/json + responses: + "200": + description: Successful operation. Returns a list of workspaces. + schema: + $ref: '#/definitions/api.WorkspaceListEnvelope' + "400": + description: Bad Request. Invalid namespace format. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "401": + description: Unauthorized. Authentication is required. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "403": + description: Forbidden. User does not have permission to list workspaces. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "500": + description: Internal server error. An unexpected error occurred on the + server. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + security: + - ApiKeyAuth: [] + summary: List workspaces + tags: + - workspaces + post: + consumes: + - application/json + description: Creates a new workspace in the specified namespace. + parameters: + - description: Namespace for the workspace + example: kubeflow-user-example-com + in: path + name: namespace + required: true + type: string + - description: Workspace creation configuration + in: body + name: body + required: true + schema: + $ref: '#/definitions/api.WorkspaceCreateEnvelope' + produces: + - application/json + responses: + "201": + description: Workspace created successfully + schema: + $ref: '#/definitions/api.WorkspaceEnvelope' + "400": + description: Bad Request. Invalid request body or namespace format. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "401": + description: Unauthorized. Authentication is required. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "403": + description: Forbidden. User does not have permission to create workspace. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "409": + description: Conflict. Workspace with the same name already exists. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "500": + description: Internal server error. An unexpected error occurred on the + server. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + security: + - ApiKeyAuth: [] + summary: Create workspace + tags: + - workspaces + /workspaces/{namespace}/{workspace_name}: + delete: + consumes: + - application/json + description: Deletes a specific workspace identified by namespace and workspace + name. + parameters: + - description: Namespace of the workspace + example: kubeflow-user-example-com + in: path + name: namespace + required: true + type: string + - description: Name of the workspace + example: my-workspace + in: path + name: workspace_name + required: true + type: string + produces: + - application/json + responses: + "204": + description: Workspace deleted successfully + "400": + description: Bad Request. Invalid namespace or workspace name format. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "401": + description: Unauthorized. Authentication is required. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "403": + description: Forbidden. User does not have permission to delete the workspace. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "404": + description: Not Found. Workspace does not exist. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "500": + description: Internal server error. An unexpected error occurred on the + server. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + security: + - ApiKeyAuth: [] + summary: Delete workspace + tags: + - workspaces + get: + consumes: + - application/json + description: Returns details of a specific workspace identified by namespace + and workspace name. + parameters: + - description: Namespace of the workspace + example: kubeflow-user-example-com + in: path + name: namespace + required: true + type: string + - description: Name of the workspace + example: my-workspace + in: path + name: workspace_name + required: true + type: string + produces: + - application/json + responses: + "200": + description: Successful operation. Returns the requested workspace details. + schema: + $ref: '#/definitions/api.WorkspaceEnvelope' + "400": + description: Bad Request. Invalid namespace or workspace name format. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "401": + description: Unauthorized. Authentication is required. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "403": + description: Forbidden. User does not have permission to access the workspace. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "404": + description: Not Found. Workspace does not exist. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + "500": + description: Internal server error. An unexpected error occurred on the + server. + schema: + $ref: '#/definitions/api.ErrorEnvelope' + security: + - ApiKeyAuth: [] + summary: Get workspace + tags: + - workspaces schemes: - http - https