feat: add port-sharing backend (#11939)

This commit is contained in:
Garrett Delfosse
2024-02-13 09:31:20 -05:00
committed by GitHub
parent c939416702
commit 3ab3a62bef
48 changed files with 1947 additions and 59 deletions
+7 -2
View File
@@ -52,6 +52,7 @@ const (
FeatureWorkspaceBatchActions FeatureName = "workspace_batch_actions"
FeatureAccessControl FeatureName = "access_control"
FeatureOAuth2Provider FeatureName = "oauth2_provider"
FeatureControlSharedPorts FeatureName = "control_shared_ports"
)
// FeatureNames must be kept in-sync with the Feature enum above.
@@ -72,6 +73,7 @@ var FeatureNames = []FeatureName{
FeatureWorkspaceBatchActions,
FeatureAccessControl,
FeatureOAuth2Provider,
FeatureControlSharedPorts,
}
// Humanize returns the feature name in a human-readable format.
@@ -2115,14 +2117,17 @@ type Experiment string
const (
// Add new experiments here!
ExperimentExample Experiment = "example" // This isn't used for anything.
ExperimentExample Experiment = "example" // This isn't used for anything.
ExperimentSharedPorts Experiment = "shared-ports"
)
// ExperimentsAll should include all experiments that are safe for
// users to opt-in to via --experimental='*'.
// Experiments that are not ready for consumption by all users should
// not be included here and will be essentially hidden.
var ExperimentsAll = Experiments{}
var ExperimentsAll = Experiments{
ExperimentSharedPorts,
}
// Experiments is a list of experiments.
// Multiple experiments may be enabled at the same time.
+4 -2
View File
@@ -61,7 +61,8 @@ type Template struct {
// RequireActiveVersion mandates that workspaces are built with the active
// template version.
RequireActiveVersion bool `json:"require_active_version"`
RequireActiveVersion bool `json:"require_active_version"`
MaxPortShareLevel WorkspaceAgentPortShareLevel `json:"max_port_share_level"`
}
// WeekdaysToBitmap converts a list of weekdays to a bitmap in accordance with
@@ -251,7 +252,8 @@ type UpdateTemplateMeta struct {
// If this is set to true, the template will not be available to all users,
// and must be explicitly granted to users or groups in the permissions settings
// of the template.
DisableEveryoneGroupAccess bool `json:"disable_everyone_group_access"`
DisableEveryoneGroupAccess bool `json:"disable_everyone_group_access"`
MaxPortShareLevel *WorkspaceAgentPortShareLevel `json:"max_port_share_level"`
}
type TemplateExample struct {
+89
View File
@@ -0,0 +1,89 @@
package codersdk
import (
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/google/uuid"
)
const (
WorkspaceAgentPortShareLevelOwner WorkspaceAgentPortShareLevel = "owner"
WorkspaceAgentPortShareLevelAuthenticated WorkspaceAgentPortShareLevel = "authenticated"
WorkspaceAgentPortShareLevelPublic WorkspaceAgentPortShareLevel = "public"
)
type (
WorkspaceAgentPortShareLevel string
UpsertWorkspaceAgentPortShareRequest struct {
AgentName string `json:"agent_name"`
Port int32 `json:"port"`
ShareLevel WorkspaceAgentPortShareLevel `json:"share_level"`
}
WorkspaceAgentPortShares struct {
Shares []WorkspaceAgentPortShare `json:"shares"`
}
WorkspaceAgentPortShare struct {
WorkspaceID uuid.UUID `json:"workspace_id" format:"uuid"`
AgentName string `json:"agent_name"`
Port int32 `json:"port"`
ShareLevel WorkspaceAgentPortShareLevel `json:"share_level"`
}
DeleteWorkspaceAgentPortShareRequest struct {
AgentName string `json:"agent_name"`
Port int32 `json:"port"`
}
)
func (l WorkspaceAgentPortShareLevel) ValidMaxLevel() bool {
return l == WorkspaceAgentPortShareLevelOwner ||
l == WorkspaceAgentPortShareLevelAuthenticated ||
l == WorkspaceAgentPortShareLevelPublic
}
func (l WorkspaceAgentPortShareLevel) ValidPortShareLevel() bool {
return l == WorkspaceAgentPortShareLevelAuthenticated ||
l == WorkspaceAgentPortShareLevelPublic
}
func (c *Client) GetWorkspaceAgentPortShares(ctx context.Context, workspaceID uuid.UUID) (WorkspaceAgentPortShares, error) {
var shares WorkspaceAgentPortShares
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/port-share", workspaceID), nil)
if err != nil {
return shares, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return shares, ReadBodyAsError(res)
}
return shares, json.NewDecoder(res.Body).Decode(&shares)
}
func (c *Client) UpsertWorkspaceAgentPortShare(ctx context.Context, workspaceID uuid.UUID, req UpsertWorkspaceAgentPortShareRequest) (WorkspaceAgentPortShare, error) {
var share WorkspaceAgentPortShare
res, err := c.Request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/workspaces/%s/port-share", workspaceID), req)
if err != nil {
return share, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return share, ReadBodyAsError(res)
}
return share, json.NewDecoder(res.Body).Decode(&share)
}
func (c *Client) DeleteWorkspaceAgentPortShare(ctx context.Context, workspaceID uuid.UUID, req DeleteWorkspaceAgentPortShareRequest) error {
res, err := c.Request(ctx, http.MethodDelete, fmt.Sprintf("/api/v2/workspaces/%s/port-share", workspaceID), req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return ReadBodyAsError(res)
}
return nil
}