mirror of
https://github.com/coder/coder.git
synced 2025-07-08 11:39:50 +00:00
* feat: convertGroups() no longer requires organization info Removing role information from some users in the api. This info is excessive and not required. It is costly to always include
223 lines
7.1 KiB
Go
223 lines
7.1 KiB
Go
package codersdk
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type ProxyHealthStatus string
|
|
|
|
const (
|
|
// ProxyHealthy means the proxy access url is reachable and returns a healthy
|
|
// status code.
|
|
ProxyHealthy ProxyHealthStatus = "ok"
|
|
// ProxyUnreachable means the proxy access url is not responding.
|
|
ProxyUnreachable ProxyHealthStatus = "unreachable"
|
|
// ProxyUnhealthy means the proxy access url is responding, but there is some
|
|
// problem with the proxy. This problem may or may not be preventing functionality.
|
|
ProxyUnhealthy ProxyHealthStatus = "unhealthy"
|
|
// ProxyUnregistered means the proxy has not registered a url yet. This means
|
|
// the proxy was created with the cli, but has not yet been started.
|
|
ProxyUnregistered ProxyHealthStatus = "unregistered"
|
|
)
|
|
|
|
type WorkspaceProxyStatus struct {
|
|
Status ProxyHealthStatus `json:"status" table:"status,default_sort"`
|
|
// Report provides more information about the health of the workspace proxy.
|
|
Report ProxyHealthReport `json:"report,omitempty" table:"report"`
|
|
CheckedAt time.Time `json:"checked_at" table:"checked_at" format:"date-time"`
|
|
}
|
|
|
|
// ProxyHealthReport is a report of the health of the workspace proxy.
|
|
// A healthy report will have no errors. Warnings are not fatal.
|
|
type ProxyHealthReport struct {
|
|
// Errors are problems that prevent the workspace proxy from being healthy
|
|
Errors []string `json:"errors"`
|
|
// Warnings do not prevent the workspace proxy from being healthy, but
|
|
// should be addressed.
|
|
Warnings []string `json:"warnings"`
|
|
}
|
|
|
|
type WorkspaceProxy struct {
|
|
// Extends Region with extra information
|
|
Region `table:"region,recursive_inline"`
|
|
DerpEnabled bool `json:"derp_enabled" table:"derp_enabled"`
|
|
DerpOnly bool `json:"derp_only" table:"derp_only"`
|
|
|
|
// Status is the latest status check of the proxy. This will be empty for deleted
|
|
// proxies. This value can be used to determine if a workspace proxy is healthy
|
|
// and ready to use.
|
|
Status WorkspaceProxyStatus `json:"status,omitempty" table:"proxy,recursive"`
|
|
|
|
CreatedAt time.Time `json:"created_at" format:"date-time" table:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at" format:"date-time" table:"updated_at"`
|
|
Deleted bool `json:"deleted" table:"deleted"`
|
|
Version string `json:"version" table:"version"`
|
|
}
|
|
|
|
type CreateWorkspaceProxyRequest struct {
|
|
Name string `json:"name" validate:"required"`
|
|
DisplayName string `json:"display_name"`
|
|
Icon string `json:"icon"`
|
|
}
|
|
|
|
type UpdateWorkspaceProxyResponse struct {
|
|
Proxy WorkspaceProxy `json:"proxy" table:"p,recursive_inline"`
|
|
ProxyToken string `json:"proxy_token" table:"proxy token"`
|
|
}
|
|
|
|
func (c *Client) CreateWorkspaceProxy(ctx context.Context, req CreateWorkspaceProxyRequest) (UpdateWorkspaceProxyResponse, error) {
|
|
res, err := c.Request(ctx, http.MethodPost,
|
|
"/api/v2/workspaceproxies",
|
|
req,
|
|
)
|
|
if err != nil {
|
|
return UpdateWorkspaceProxyResponse{}, xerrors.Errorf("make request: %w", err)
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
if res.StatusCode != http.StatusCreated {
|
|
return UpdateWorkspaceProxyResponse{}, ReadBodyAsError(res)
|
|
}
|
|
var resp UpdateWorkspaceProxyResponse
|
|
return resp, json.NewDecoder(res.Body).Decode(&resp)
|
|
}
|
|
|
|
func (c *Client) WorkspaceProxies(ctx context.Context) (RegionsResponse[WorkspaceProxy], error) {
|
|
res, err := c.Request(ctx, http.MethodGet,
|
|
"/api/v2/workspaceproxies",
|
|
nil,
|
|
)
|
|
if err != nil {
|
|
return RegionsResponse[WorkspaceProxy]{}, xerrors.Errorf("make request: %w", err)
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
if res.StatusCode != http.StatusOK {
|
|
return RegionsResponse[WorkspaceProxy]{}, ReadBodyAsError(res)
|
|
}
|
|
|
|
var proxies RegionsResponse[WorkspaceProxy]
|
|
return proxies, json.NewDecoder(res.Body).Decode(&proxies)
|
|
}
|
|
|
|
type PatchWorkspaceProxy struct {
|
|
ID uuid.UUID `json:"id" format:"uuid" validate:"required"`
|
|
Name string `json:"name" validate:"required"`
|
|
DisplayName string `json:"display_name" validate:"required"`
|
|
Icon string `json:"icon" validate:"required"`
|
|
RegenerateToken bool `json:"regenerate_token"`
|
|
}
|
|
|
|
func (c *Client) PatchWorkspaceProxy(ctx context.Context, req PatchWorkspaceProxy) (UpdateWorkspaceProxyResponse, error) {
|
|
res, err := c.Request(ctx, http.MethodPatch,
|
|
fmt.Sprintf("/api/v2/workspaceproxies/%s", req.ID.String()),
|
|
req,
|
|
)
|
|
if err != nil {
|
|
return UpdateWorkspaceProxyResponse{}, xerrors.Errorf("make request: %w", err)
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
if res.StatusCode != http.StatusOK {
|
|
return UpdateWorkspaceProxyResponse{}, ReadBodyAsError(res)
|
|
}
|
|
var resp UpdateWorkspaceProxyResponse
|
|
return resp, json.NewDecoder(res.Body).Decode(&resp)
|
|
}
|
|
|
|
func (c *Client) DeleteWorkspaceProxyByName(ctx context.Context, name string) error {
|
|
res, err := c.Request(ctx, http.MethodDelete,
|
|
fmt.Sprintf("/api/v2/workspaceproxies/%s", name),
|
|
nil,
|
|
)
|
|
if err != nil {
|
|
return xerrors.Errorf("make request: %w", err)
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
if res.StatusCode != http.StatusOK {
|
|
return ReadBodyAsError(res)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) DeleteWorkspaceProxyByID(ctx context.Context, id uuid.UUID) error {
|
|
return c.DeleteWorkspaceProxyByName(ctx, id.String())
|
|
}
|
|
|
|
func (c *Client) WorkspaceProxyByName(ctx context.Context, name string) (WorkspaceProxy, error) {
|
|
res, err := c.Request(ctx, http.MethodGet,
|
|
fmt.Sprintf("/api/v2/workspaceproxies/%s", name),
|
|
nil,
|
|
)
|
|
if err != nil {
|
|
return WorkspaceProxy{}, xerrors.Errorf("make request: %w", err)
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
if res.StatusCode != http.StatusOK {
|
|
return WorkspaceProxy{}, ReadBodyAsError(res)
|
|
}
|
|
|
|
var resp WorkspaceProxy
|
|
return resp, json.NewDecoder(res.Body).Decode(&resp)
|
|
}
|
|
|
|
func (c *Client) WorkspaceProxyByID(ctx context.Context, id uuid.UUID) (WorkspaceProxy, error) {
|
|
return c.WorkspaceProxyByName(ctx, id.String())
|
|
}
|
|
|
|
type RegionTypes interface {
|
|
Region | WorkspaceProxy
|
|
}
|
|
|
|
type RegionsResponse[R RegionTypes] struct {
|
|
Regions []R `json:"regions"`
|
|
}
|
|
|
|
type Region struct {
|
|
ID uuid.UUID `json:"id" format:"uuid" table:"id"`
|
|
Name string `json:"name" table:"name,default_sort"`
|
|
DisplayName string `json:"display_name" table:"display_name"`
|
|
IconURL string `json:"icon_url" table:"icon_url"`
|
|
Healthy bool `json:"healthy" table:"healthy"`
|
|
|
|
// PathAppURL is the URL to the base path for path apps. Optional
|
|
// unless wildcard_hostname is set.
|
|
// E.g. https://us.example.com
|
|
PathAppURL string `json:"path_app_url" table:"url"`
|
|
|
|
// WildcardHostname is the wildcard hostname for subdomain apps.
|
|
// E.g. *.us.example.com
|
|
// E.g. *--suffix.au.example.com
|
|
// Optional. Does not need to be on the same domain as PathAppURL.
|
|
WildcardHostname string `json:"wildcard_hostname" table:"wildcard_hostname"`
|
|
}
|
|
|
|
func (c *Client) Regions(ctx context.Context) ([]Region, error) {
|
|
res, err := c.Request(ctx, http.MethodGet,
|
|
"/api/v2/regions",
|
|
nil,
|
|
)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("make request: %w", err)
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
if res.StatusCode != http.StatusOK {
|
|
return nil, ReadBodyAsError(res)
|
|
}
|
|
|
|
var regions RegionsResponse[Region]
|
|
return regions.Regions, json.NewDecoder(res.Body).Decode(®ions)
|
|
}
|