diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 4e26d96efdbd6..d95cf43748b69 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -9220,6 +9220,14 @@ const docTemplate = `{ "description": "Icon is a relative path or external URL that specifies\nan icon to be displayed in the dashboard.", "type": "string" }, + "max_port_share_level": { + "description": "MaxPortShareLevel allows optionally specifying the maximum port share level\nfor workspaces created from the template.", + "allOf": [ + { + "$ref": "#/definitions/codersdk.WorkspaceAgentPortShareLevel" + } + ] + }, "name": { "description": "Name is the name of the template.", "type": "string" diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 5f2ed6e5aa9e7..6aa6232b6ced2 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -8209,6 +8209,14 @@ "description": "Icon is a relative path or external URL that specifies\nan icon to be displayed in the dashboard.", "type": "string" }, + "max_port_share_level": { + "description": "MaxPortShareLevel allows optionally specifying the maximum port share level\nfor workspaces created from the template.", + "allOf": [ + { + "$ref": "#/definitions/codersdk.WorkspaceAgentPortShareLevel" + } + ] + }, "name": { "description": "Name is the name of the template.", "type": "string" diff --git a/coderd/templates.go b/coderd/templates.go index ade849ba99c9c..dc32841b72aad 100644 --- a/coderd/templates.go +++ b/coderd/templates.go @@ -163,6 +163,7 @@ func (api *API) notifyTemplateDeleted(ctx context.Context, template database.Tem func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Request) { var ( ctx = r.Context() + portSharer = *api.PortSharer.Load() createTemplate codersdk.CreateTemplateRequest organization = httpmw.OrganizationParam(r) apiKey = httpmw.APIKey(r) @@ -309,6 +310,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque validErrs []codersdk.ValidationError autostopRequirementDaysOfWeekParsed uint8 autostartRequirementDaysOfWeekParsed uint8 + maxPortShareLevel = database.AppSharingLevelOwner // default ) if defaultTTL < 0 { validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be a positive integer."}) @@ -329,6 +331,14 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque validErrs = append(validErrs, codersdk.ValidationError{Field: "autostart_requirement.days_of_week", Detail: err.Error()}) } } + if createTemplate.MaxPortShareLevel != nil { + err = portSharer.ValidateTemplateMaxLevel(*createTemplate.MaxPortShareLevel) + if err != nil { + validErrs = append(validErrs, codersdk.ValidationError{Field: "max_port_share_level", Detail: err.Error()}) + } else { + maxPortShareLevel = database.AppSharingLevel(*createTemplate.MaxPortShareLevel) + } + } if autostopRequirementWeeks < 0 { validErrs = append(validErrs, codersdk.ValidationError{Field: "autostop_requirement.weeks", Detail: "Must be a positive integer."}) @@ -386,7 +396,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque DisplayName: createTemplate.DisplayName, Icon: createTemplate.Icon, AllowUserCancelWorkspaceJobs: allowUserCancelWorkspaceJobs, - MaxPortSharingLevel: database.AppSharingLevelOwner, + MaxPortSharingLevel: maxPortShareLevel, }) if err != nil { return xerrors.Errorf("insert template: %s", err) diff --git a/coderd/templates_test.go b/coderd/templates_test.go index 5efd127681bbd..ca8d9c4cf88f2 100644 --- a/coderd/templates_test.go +++ b/coderd/templates_test.go @@ -401,6 +401,44 @@ func TestPostTemplateByOrganization(t *testing.T) { require.EqualValues(t, 1, got.AutostopRequirement.Weeks) }) }) + + t.Run("MaxPortShareLevel", func(t *testing.T) { + t.Parallel() + + t.Run("OK", func(t *testing.T) { + client := coderdtest.New(t, nil) + user := coderdtest.CreateFirstUser(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + got, err := client.CreateTemplate(ctx, user.OrganizationID, codersdk.CreateTemplateRequest{ + Name: "testing", + VersionID: version.ID, + }) + require.NoError(t, err) + require.Equal(t, codersdk.WorkspaceAgentPortShareLevelPublic, got.MaxPortShareLevel) + }) + + t.Run("EnterpriseLevelError", func(t *testing.T) { + client := coderdtest.New(t, nil) + user := coderdtest.CreateFirstUser(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + _, err := client.CreateTemplate(ctx, user.OrganizationID, codersdk.CreateTemplateRequest{ + Name: "testing", + VersionID: version.ID, + MaxPortShareLevel: ptr.Ref(codersdk.WorkspaceAgentPortShareLevelPublic), + }) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusBadRequest, apiErr.StatusCode()) + }) + }) } func TestTemplatesByOrganization(t *testing.T) { diff --git a/codersdk/organizations.go b/codersdk/organizations.go index a1dc562055f82..77e24a2be3e10 100644 --- a/codersdk/organizations.go +++ b/codersdk/organizations.go @@ -184,6 +184,10 @@ type CreateTemplateRequest struct { // RequireActiveVersion mandates that workspaces are built with the active // template version. RequireActiveVersion bool `json:"require_active_version"` + + // MaxPortShareLevel allows optionally specifying the maximum port share level + // for workspaces created from the template. + MaxPortShareLevel *WorkspaceAgentPortShareLevel `json:"max_port_share_level"` } // CreateWorkspaceRequest provides options for creating a new workspace. diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index 27d65ad5ecd6f..9f9188ced1761 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -1107,6 +1107,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in "dormant_ttl_ms": 0, "failure_ttl_ms": 0, "icon": "string", + "max_port_share_level": "owner", "name": "string", "require_active_version": true, "template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1" @@ -1131,6 +1132,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `dormant_ttl_ms` | integer | false | | Dormant ttl ms allows optionally specifying the max lifetime before Coder locks inactive workspaces created from this template. | | `failure_ttl_ms` | integer | false | | Failure ttl ms allows optionally specifying the max lifetime before Coder stops all resources for failed workspaces created from this template. | | `icon` | string | false | | Icon is a relative path or external URL that specifies an icon to be displayed in the dashboard. | +| `max_port_share_level` | [codersdk.WorkspaceAgentPortShareLevel](#codersdkworkspaceagentportsharelevel) | false | | Max port share level allows optionally specifying the maximum port share level for workspaces created from the template. | | `name` | string | true | | Name is the name of the template. | | `require_active_version` | boolean | false | | Require active version mandates that workspaces are built with the active template version. | | `template_version_id` | string | true | | Template version ID is an in-progress or completed job to use as an initial version of the template. | diff --git a/docs/reference/api/templates.md b/docs/reference/api/templates.md index da7b61d8a2fa9..ef90c243a5961 100644 --- a/docs/reference/api/templates.md +++ b/docs/reference/api/templates.md @@ -175,6 +175,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa "dormant_ttl_ms": 0, "failure_ttl_ms": 0, "icon": "string", + "max_port_share_level": "owner", "name": "string", "require_active_version": true, "template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1" diff --git a/enterprise/coderd/templates_test.go b/enterprise/coderd/templates_test.go index 5bb41cf534e68..782132f5d3ba2 100644 --- a/enterprise/coderd/templates_test.go +++ b/enterprise/coderd/templates_test.go @@ -132,7 +132,10 @@ func TestTemplates(t *testing.T) { }, }}, }) - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { + ctr.MaxPortShareLevel = ptr.Ref(codersdk.WorkspaceAgentPortShareLevelPublic) + }) + require.Equal(t, template.MaxPortShareLevel, codersdk.WorkspaceAgentPortShareLevelPublic) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) ws := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 0f99c2fd2ef4e..1186f26ad90c8 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -261,6 +261,7 @@ export interface CreateTemplateRequest { readonly delete_ttl_ms?: number; readonly disable_everyone_group_access: boolean; readonly require_active_version: boolean; + readonly max_port_share_level?: WorkspaceAgentPortShareLevel; } // From codersdk/templateversions.go pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy