diff --git a/cli/templatecreate.go b/cli/templatecreate.go
index 51a4c33cfa226..62de354fc4c1c 100644
--- a/cli/templatecreate.go
+++ b/cli/templatecreate.go
@@ -1,6 +1,7 @@
package cli
import (
+ "context"
"errors"
"fmt"
"io"
@@ -46,39 +47,22 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
r.InitClient(client),
),
Handler: func(inv *clibase.Invocation) error {
- isTemplateSchedulingOptionsSet := failureTTL != 0 || dormancyThreshold != 0 || dormancyAutoDeletion != 0 || maxTTL != 0
-
- if isTemplateSchedulingOptionsSet || requireActiveVersion {
- if failureTTL != 0 || dormancyThreshold != 0 || dormancyAutoDeletion != 0 {
- // This call can be removed when workspace_actions is no longer experimental
- experiments, exErr := client.Experiments(inv.Context())
- if exErr != nil {
- return xerrors.Errorf("get experiments: %w", exErr)
- }
-
- if !experiments.Enabled(codersdk.ExperimentWorkspaceActions) {
- return xerrors.Errorf("--failure-ttl, --dormancy-threshold, and --dormancy-auto-deletion are experimental features. Use the workspace_actions CODER_EXPERIMENTS flag to set these configuration values.")
- }
- }
-
- entitlements, err := client.Entitlements(inv.Context())
- if cerr, ok := codersdk.AsError(err); ok && cerr.StatusCode() == http.StatusNotFound {
- return xerrors.Errorf("your deployment appears to be an AGPL deployment, so you cannot set enterprise-only flags")
- } else if err != nil {
- return xerrors.Errorf("get entitlements: %w", err)
- }
-
- if isTemplateSchedulingOptionsSet {
- if !entitlements.Features[codersdk.FeatureAdvancedTemplateScheduling].Enabled {
- return xerrors.Errorf("your license is not entitled to use advanced template scheduling, so you cannot set --failure-ttl, --inactivity-ttl, or --max-ttl")
- }
- }
-
- if requireActiveVersion {
- if !entitlements.Features[codersdk.FeatureAccessControl].Enabled {
- return xerrors.Errorf("your license is not entitled to use enterprise access control, so you cannot set --require-active-version")
- }
- }
+ _, _ = fmt.Fprintln(inv.Stdout, "\n"+pretty.Sprint(cliui.DefaultStyles.Wrap,
+ pretty.Sprint(
+ cliui.DefaultStyles.Warn, "DEPRECATION WARNING: The `coder templates push` command should be used instead. This command will be removed in a future release. ")+"\n"))
+ time.Sleep(1 * time.Second)
+
+ err := checkTemplateCreateEntitlements(inv.Context(), checkTemplateCreateEntitlementsArgs{
+ client: client,
+ requireActiveVersion: requireActiveVersion,
+ defaultTTL: defaultTTL,
+ failureTTL: failureTTL,
+ dormancyThreshold: dormancyThreshold,
+ dormancyAutoDeletion: dormancyAutoDeletion,
+ maxTTL: maxTTL,
+ })
+ if err != nil {
+ return err
}
organization, err := CurrentOrganization(inv, client)
@@ -357,3 +341,52 @@ func ParseProvisionerTags(rawTags []string) (map[string]string, error) {
}
return tags, nil
}
+
+type checkTemplateCreateEntitlementsArgs struct {
+ client *codersdk.Client
+ requireActiveVersion bool
+ defaultTTL time.Duration
+ failureTTL time.Duration
+ dormancyThreshold time.Duration
+ dormancyAutoDeletion time.Duration
+ maxTTL time.Duration
+}
+
+func checkTemplateCreateEntitlements(ctx context.Context, args checkTemplateCreateEntitlementsArgs) error {
+ isTemplateSchedulingOptionsSet := args.failureTTL != 0 || args.dormancyThreshold != 0 || args.dormancyAutoDeletion != 0 || args.maxTTL != 0
+
+ if isTemplateSchedulingOptionsSet || args.requireActiveVersion {
+ if args.failureTTL != 0 || args.dormancyThreshold != 0 || args.dormancyAutoDeletion != 0 {
+ // This call can be removed when workspace_actions is no longer experimental
+ experiments, exErr := args.client.Experiments(ctx)
+ if exErr != nil {
+ return xerrors.Errorf("get experiments: %w", exErr)
+ }
+
+ if !experiments.Enabled(codersdk.ExperimentWorkspaceActions) {
+ return xerrors.Errorf("--failure-ttl, --dormancy-threshold, and --dormancy-auto-deletion are experimental features. Use the workspace_actions CODER_EXPERIMENTS flag to set these configuration values.")
+ }
+ }
+
+ entitlements, err := args.client.Entitlements(ctx)
+ if cerr, ok := codersdk.AsError(err); ok && cerr.StatusCode() == http.StatusNotFound {
+ return xerrors.Errorf("your deployment appears to be an AGPL deployment, so you cannot set enterprise-only flags")
+ } else if err != nil {
+ return xerrors.Errorf("get entitlements: %w", err)
+ }
+
+ if isTemplateSchedulingOptionsSet {
+ if !entitlements.Features[codersdk.FeatureAdvancedTemplateScheduling].Enabled {
+ return xerrors.Errorf("your license is not entitled to use advanced template scheduling, so you cannot set --failure-ttl, --inactivity-ttl, or --max-ttl")
+ }
+ }
+
+ if args.requireActiveVersion {
+ if !entitlements.Features[codersdk.FeatureAccessControl].Enabled {
+ return xerrors.Errorf("your license is not entitled to use enterprise access control, so you cannot set --require-active-version")
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/cli/templateedit.go b/cli/templateedit.go
index 9cbcefc88730f..39f7c34537fb4 100644
--- a/cli/templateedit.go
+++ b/cli/templateedit.go
@@ -1,6 +1,7 @@
package cli
import (
+ "context"
"fmt"
"net/http"
"strings"
@@ -46,49 +47,6 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
),
Short: "Edit the metadata of a template by name.",
Handler: func(inv *clibase.Invocation) error {
- // This clause can be removed when workspace_actions is no longer experimental
- if failureTTL != 0 || dormancyThreshold != 0 || dormancyAutoDeletion != 0 {
- experiments, exErr := client.Experiments(inv.Context())
- if exErr != nil {
- return xerrors.Errorf("get experiments: %w", exErr)
- }
-
- if !experiments.Enabled(codersdk.ExperimentWorkspaceActions) {
- return xerrors.Errorf("--failure-ttl, --dormancy-threshold, and --dormancy-auto-deletion are experimental features. Use the workspace_actions CODER_EXPERIMENTS flag to set these configuration values.")
- }
- }
-
- unsetAutostopRequirementDaysOfWeek := len(autostopRequirementDaysOfWeek) == 1 && autostopRequirementDaysOfWeek[0] == "none"
- requiresScheduling := (len(autostopRequirementDaysOfWeek) > 0 && !unsetAutostopRequirementDaysOfWeek) ||
- autostopRequirementWeeks > 0 ||
- !allowUserAutostart ||
- !allowUserAutostop ||
- maxTTL != 0 ||
- failureTTL != 0 ||
- dormancyThreshold != 0 ||
- dormancyAutoDeletion != 0 ||
- len(autostartRequirementDaysOfWeek) > 0
-
- requiresEntitlement := requiresScheduling || requireActiveVersion
- if requiresEntitlement {
- entitlements, err := client.Entitlements(inv.Context())
- if cerr, ok := codersdk.AsError(err); ok && cerr.StatusCode() == http.StatusNotFound {
- return xerrors.Errorf("your deployment appears to be an AGPL deployment, so you cannot set enterprise-only flags")
- } else if err != nil {
- return xerrors.Errorf("get entitlements: %w", err)
- }
-
- if requiresScheduling && !entitlements.Features[codersdk.FeatureAdvancedTemplateScheduling].Enabled {
- return xerrors.Errorf("your license is not entitled to use advanced template scheduling, so you cannot set --max-ttl, --failure-ttl, --inactivityTTL, --allow-user-autostart=false or --allow-user-autostop=false")
- }
-
- if requireActiveVersion {
- if !entitlements.Features[codersdk.FeatureAccessControl].Enabled {
- return xerrors.Errorf("your license is not entitled to use enterprise access control, so you cannot set --require-active-version")
- }
- }
- }
-
organization, err := CurrentOrganization(inv, client)
if err != nil {
return xerrors.Errorf("get current organization: %w", err)
@@ -98,71 +56,51 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
return xerrors.Errorf("get workspace template: %w", err)
}
- // Copy the default value if the list is empty, or if the user
- // specified the "none" value clear the list.
- if len(autostopRequirementDaysOfWeek) == 0 {
- autostopRequirementDaysOfWeek = template.AutostopRequirement.DaysOfWeek
- }
- if len(autostartRequirementDaysOfWeek) == 1 && autostartRequirementDaysOfWeek[0] == "all" {
- // Set it to every day of the week
- autostartRequirementDaysOfWeek = []string{"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"}
- } else if len(autostartRequirementDaysOfWeek) == 0 {
- autostartRequirementDaysOfWeek = template.AutostartRequirement.DaysOfWeek
- }
- if unsetAutostopRequirementDaysOfWeek {
- autostopRequirementDaysOfWeek = []string{}
- }
- if failureTTL == 0 {
- failureTTL = time.Duration(template.FailureTTLMillis) * time.Millisecond
- }
- if dormancyThreshold == 0 {
- dormancyThreshold = time.Duration(template.TimeTilDormantMillis) * time.Millisecond
- }
- if dormancyAutoDeletion == 0 {
- dormancyAutoDeletion = time.Duration(template.TimeTilDormantAutoDeleteMillis) * time.Millisecond
- }
-
- // Default values
- if !userSetOption(inv, "description") {
- description = template.Description
- }
+ unsetAutostopRequirementDaysOfWeek, err := checkEditTemplateEntitlements(inv.Context(), checkEditTemplateEntitlementsArgs{
+ client: client,
+ inv: inv,
- if !userSetOption(inv, "icon") {
- icon = template.Icon
- }
-
- if !userSetOption(inv, "display-name") {
- displayName = template.DisplayName
+ defaultTTL: defaultTTL,
+ maxTTL: maxTTL,
+ autostopRequirementDaysOfWeek: autostopRequirementDaysOfWeek,
+ autostopRequirementWeeks: autostopRequirementWeeks,
+ autostartRequirementDaysOfWeek: autostartRequirementDaysOfWeek,
+ failureTTL: failureTTL,
+ dormancyThreshold: dormancyThreshold,
+ dormancyAutoDeletion: dormancyAutoDeletion,
+ allowUserCancelWorkspaceJobs: allowUserCancelWorkspaceJobs,
+ allowUserAutostart: allowUserAutostart,
+ allowUserAutostop: allowUserAutostop,
+ requireActiveVersion: requireActiveVersion,
+ })
+ if err != nil {
+ return err
}
- var deprecated *string
- if !userSetOption(inv, "deprecated") {
- deprecated = &deprecationMessage
- }
+ req := updateTemplateMetaRequest(updateTemplateMetaArgs{
+ client: client,
+ inv: inv,
+ template: template,
+ unsetAutostopRequirementDaysOfWeek: unsetAutostopRequirementDaysOfWeek,
- req := codersdk.UpdateTemplateMeta{
- Name: name,
- DisplayName: displayName,
- Description: description,
- Icon: icon,
- DefaultTTLMillis: defaultTTL.Milliseconds(),
- MaxTTLMillis: maxTTL.Milliseconds(),
- AutostopRequirement: &codersdk.TemplateAutostopRequirement{
- DaysOfWeek: autostopRequirementDaysOfWeek,
- Weeks: autostopRequirementWeeks,
- },
- AutostartRequirement: &codersdk.TemplateAutostartRequirement{
- DaysOfWeek: autostartRequirementDaysOfWeek,
- },
- FailureTTLMillis: failureTTL.Milliseconds(),
- TimeTilDormantMillis: dormancyThreshold.Milliseconds(),
- TimeTilDormantAutoDeleteMillis: dormancyAutoDeletion.Milliseconds(),
- AllowUserCancelWorkspaceJobs: allowUserCancelWorkspaceJobs,
- AllowUserAutostart: allowUserAutostart,
- AllowUserAutostop: allowUserAutostop,
- RequireActiveVersion: requireActiveVersion,
- DeprecationMessage: deprecated,
- }
+ name: name,
+ displayName: displayName,
+ description: description,
+ icon: icon,
+ defaultTTL: defaultTTL,
+ maxTTL: maxTTL,
+ autostopRequirementDaysOfWeek: autostopRequirementDaysOfWeek,
+ autostopRequirementWeeks: autostopRequirementWeeks,
+ autostartRequirementDaysOfWeek: autostartRequirementDaysOfWeek,
+ failureTTL: failureTTL,
+ dormancyThreshold: dormancyThreshold,
+ dormancyAutoDeletion: dormancyAutoDeletion,
+ allowUserCancelWorkspaceJobs: allowUserCancelWorkspaceJobs,
+ allowUserAutostart: allowUserAutostart,
+ allowUserAutostop: allowUserAutostop,
+ requireActiveVersion: requireActiveVersion,
+ deprecationMessage: deprecationMessage,
+ })
_, err = client.UpdateTemplateMeta(inv.Context(), template.ID, req)
if err != nil {
@@ -297,3 +235,170 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
return cmd
}
+
+type checkEditTemplateEntitlementsArgs struct {
+ client *codersdk.Client
+ inv *clibase.Invocation
+
+ defaultTTL time.Duration
+ maxTTL time.Duration
+ autostopRequirementDaysOfWeek []string
+ autostopRequirementWeeks int64
+ autostartRequirementDaysOfWeek []string
+ failureTTL time.Duration
+ dormancyThreshold time.Duration
+ dormancyAutoDeletion time.Duration
+ allowUserCancelWorkspaceJobs bool
+ allowUserAutostart bool
+ allowUserAutostop bool
+ requireActiveVersion bool
+}
+
+func checkEditTemplateEntitlements(ctx context.Context, args checkEditTemplateEntitlementsArgs) (bool, error) {
+ // This clause can be removed when workspace_actions is no longer experimental
+ if args.failureTTL != 0 || args.dormancyThreshold != 0 || args.dormancyAutoDeletion != 0 {
+ experiments, exErr := args.client.Experiments(ctx)
+ if exErr != nil {
+ return false, xerrors.Errorf("get experiments: %w", exErr)
+ }
+
+ if !experiments.Enabled(codersdk.ExperimentWorkspaceActions) {
+ return false, xerrors.Errorf("--failure-ttl, --dormancy-threshold, and --dormancy-auto-deletion are experimental features. Use the workspace_actions CODER_EXPERIMENTS flag to set these configuration values.")
+ }
+ }
+
+ unsetAutostopRequirementDaysOfWeek := len(args.autostopRequirementDaysOfWeek) == 1 && args.autostopRequirementDaysOfWeek[0] == "none"
+ requiresScheduling := (len(args.autostopRequirementDaysOfWeek) > 0 && !unsetAutostopRequirementDaysOfWeek) ||
+ args.autostopRequirementWeeks > 0 ||
+ !args.allowUserAutostart ||
+ !args.allowUserAutostop ||
+ args.maxTTL != 0 ||
+ args.failureTTL != 0 ||
+ args.dormancyThreshold != 0 ||
+ args.dormancyAutoDeletion != 0 ||
+ len(args.autostartRequirementDaysOfWeek) > 0
+
+ requiresEntitlement := requiresScheduling || args.requireActiveVersion
+ if requiresEntitlement {
+ entitlements, err := args.client.Entitlements(ctx)
+ if cerr, ok := codersdk.AsError(err); ok && cerr.StatusCode() == http.StatusNotFound {
+ return false, xerrors.Errorf("your deployment appears to be an AGPL deployment, so you cannot set enterprise-only flags")
+ } else if err != nil {
+ return false, xerrors.Errorf("get entitlements: %w", err)
+ }
+
+ if requiresScheduling && !entitlements.Features[codersdk.FeatureAdvancedTemplateScheduling].Enabled {
+ return false, xerrors.Errorf("your license is not entitled to use advanced template scheduling, so you cannot set --max-ttl, --failure-ttl, --inactivityTTL, --allow-user-autostart=false or --allow-user-autostop=false")
+ }
+
+ if args.requireActiveVersion {
+ if !entitlements.Features[codersdk.FeatureAccessControl].Enabled {
+ return false, xerrors.Errorf("your license is not entitled to use enterprise access control, so you cannot set --require-active-version")
+ }
+ }
+ }
+
+ return unsetAutostopRequirementDaysOfWeek, nil
+}
+
+type updateTemplateMetaArgs struct {
+ client *codersdk.Client
+ inv *clibase.Invocation
+ template codersdk.Template
+ unsetAutostopRequirementDaysOfWeek bool
+
+ name string
+ displayName string
+ description string
+ icon string
+ defaultTTL time.Duration
+ maxTTL time.Duration
+ autostopRequirementDaysOfWeek []string
+ autostopRequirementWeeks int64
+ autostartRequirementDaysOfWeek []string
+ failureTTL time.Duration
+ dormancyThreshold time.Duration
+ dormancyAutoDeletion time.Duration
+ allowUserCancelWorkspaceJobs bool
+ allowUserAutostart bool
+ allowUserAutostop bool
+ requireActiveVersion bool
+ deprecationMessage string
+ disableEveryone bool
+}
+
+func updateTemplateMetaRequest(args updateTemplateMetaArgs) codersdk.UpdateTemplateMeta {
+ // Copy the default value if the list is empty, or if the user
+ // specified the "none" value clear the list.
+ if len(args.autostopRequirementDaysOfWeek) == 0 {
+ args.autostopRequirementDaysOfWeek = args.template.AutostopRequirement.DaysOfWeek
+ }
+ if len(args.autostartRequirementDaysOfWeek) == 1 && args.autostartRequirementDaysOfWeek[0] == "all" {
+ // Set it to every day of the week
+ args.autostartRequirementDaysOfWeek = []string{"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"}
+ } else if len(args.autostartRequirementDaysOfWeek) == 0 {
+ args.autostartRequirementDaysOfWeek = args.template.AutostartRequirement.DaysOfWeek
+ }
+ if args.unsetAutostopRequirementDaysOfWeek {
+ args.autostopRequirementDaysOfWeek = []string{}
+ }
+ unsetDefaultTTL, err := time.ParseDuration("24h")
+ if err != nil {
+ panic(err)
+ }
+
+ if args.defaultTTL == unsetDefaultTTL {
+ args.defaultTTL = time.Duration(args.template.DefaultTTLMillis) * time.Millisecond
+ }
+ if args.failureTTL == 0 {
+ args.failureTTL = time.Duration(args.template.FailureTTLMillis) * time.Millisecond
+ }
+ if args.dormancyThreshold == 0 {
+ args.dormancyThreshold = time.Duration(args.template.TimeTilDormantMillis) * time.Millisecond
+ }
+ if args.dormancyAutoDeletion == 0 {
+ args.dormancyAutoDeletion = time.Duration(args.template.TimeTilDormantAutoDeleteMillis) * time.Millisecond
+ }
+
+ // Default values
+ if !userSetOption(args.inv, "description") {
+ args.description = args.template.Description
+ }
+
+ if !userSetOption(args.inv, "icon") {
+ args.icon = args.template.Icon
+ }
+
+ if !userSetOption(args.inv, "display-name") {
+ args.displayName = args.template.DisplayName
+ }
+
+ var deprecated *string
+ if !userSetOption(args.inv, "deprecated") {
+ deprecated = &args.deprecationMessage
+ }
+
+ return codersdk.UpdateTemplateMeta{
+ Name: args.name,
+ DisplayName: args.displayName,
+ Description: args.description,
+ Icon: args.icon,
+ DefaultTTLMillis: args.defaultTTL.Milliseconds(),
+ MaxTTLMillis: args.maxTTL.Milliseconds(),
+ AutostopRequirement: &codersdk.TemplateAutostopRequirement{
+ DaysOfWeek: args.autostopRequirementDaysOfWeek,
+ Weeks: args.autostopRequirementWeeks,
+ },
+ AutostartRequirement: &codersdk.TemplateAutostartRequirement{
+ DaysOfWeek: args.autostartRequirementDaysOfWeek,
+ },
+ FailureTTLMillis: args.failureTTL.Milliseconds(),
+ TimeTilDormantMillis: args.dormancyThreshold.Milliseconds(),
+ TimeTilDormantAutoDeleteMillis: args.dormancyAutoDeletion.Milliseconds(),
+ AllowUserCancelWorkspaceJobs: args.allowUserCancelWorkspaceJobs,
+ AllowUserAutostart: args.allowUserAutostart,
+ AllowUserAutostop: args.allowUserAutostop,
+ RequireActiveVersion: args.requireActiveVersion,
+ DeprecationMessage: deprecated,
+ }
+}
diff --git a/cli/templatepush.go b/cli/templatepush.go
index 4c903ef7ca4d9..0b1d765d0b4f1 100644
--- a/cli/templatepush.go
+++ b/cli/templatepush.go
@@ -2,12 +2,15 @@ package cli
import (
"bufio"
+ "errors"
"fmt"
"io"
+ "net/http"
"os"
"path/filepath"
"strings"
"time"
+ "unicode/utf8"
"github.com/briandowns/spinner"
"golang.org/x/xerrors"
@@ -165,7 +168,24 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
provisionerTags []string
uploadFlags templateUploadFlags
activate bool
- create bool
+
+ displayName string
+ description string
+ icon string
+ requireActiveVersion bool
+ disableEveryone bool
+ defaultTTL time.Duration
+ failureTTL time.Duration
+ dormancyThreshold time.Duration
+ dormancyAutoDeletion time.Duration
+ maxTTL time.Duration
+ autostopRequirementDaysOfWeek []string
+ autostopRequirementWeeks int64
+ autostartRequirementDaysOfWeek []string
+ allowUserAutostart bool
+ allowUserAutostop bool
+ allowUserCancelWorkspaceJobs bool
+ deprecationMessage string
)
client := new(codersdk.Client)
cmd := &clibase.Cmd{
@@ -178,6 +198,39 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
Handler: func(inv *clibase.Invocation) error {
uploadFlags.setWorkdir(workdir)
+ err := checkTemplateCreateEntitlements(inv.Context(), checkTemplateCreateEntitlementsArgs{
+ client: client,
+ requireActiveVersion: requireActiveVersion,
+ defaultTTL: defaultTTL,
+ failureTTL: failureTTL,
+ dormancyThreshold: dormancyThreshold,
+ dormancyAutoDeletion: dormancyAutoDeletion,
+ maxTTL: maxTTL,
+ })
+ if err != nil {
+ return err
+ }
+
+ unsetAutostopRequirementDaysOfWeek, err := checkEditTemplateEntitlements(inv.Context(), checkEditTemplateEntitlementsArgs{
+ client: client,
+ inv: inv,
+ defaultTTL: defaultTTL,
+ maxTTL: maxTTL,
+ autostopRequirementDaysOfWeek: autostopRequirementDaysOfWeek,
+ autostopRequirementWeeks: autostopRequirementWeeks,
+ autostartRequirementDaysOfWeek: autostartRequirementDaysOfWeek,
+ failureTTL: failureTTL,
+ dormancyThreshold: dormancyThreshold,
+ dormancyAutoDeletion: dormancyAutoDeletion,
+ allowUserCancelWorkspaceJobs: allowUserCancelWorkspaceJobs,
+ allowUserAutostart: allowUserAutostart,
+ allowUserAutostop: allowUserAutostop,
+ requireActiveVersion: requireActiveVersion,
+ })
+ if err != nil {
+ return err
+ }
+
organization, err := CurrentOrganization(inv, client)
if err != nil {
return err
@@ -188,10 +241,15 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
return err
}
+ if utf8.RuneCountInString(name) > 31 {
+ return xerrors.Errorf("Template name must be less than 32 characters")
+ }
+
var createTemplate bool
template, err := client.TemplateByName(inv.Context(), organization.ID, name)
if err != nil {
- if !create {
+ var apiError *codersdk.Error
+ if errors.As(err, &apiError) && apiError.StatusCode() != http.StatusNotFound {
return err
}
createTemplate = true
@@ -269,6 +327,46 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
}
_, _ = fmt.Fprintf(inv.Stdout, "Updated version at %s!\n", pretty.Sprint(cliui.DefaultStyles.DateTimeStamp, time.Now().Format(time.Stamp)))
+
+ // refresh template data for edit api call
+ template, err = client.TemplateByName(inv.Context(), organization.ID, name)
+ if err != nil {
+ return err
+ }
+ req := updateTemplateMetaRequest(updateTemplateMetaArgs{
+ client: client,
+ inv: inv,
+ template: template,
+ unsetAutostopRequirementDaysOfWeek: unsetAutostopRequirementDaysOfWeek,
+
+ displayName: displayName,
+ description: description,
+ icon: icon,
+ requireActiveVersion: requireActiveVersion,
+ disableEveryone: disableEveryone,
+ defaultTTL: defaultTTL,
+ failureTTL: failureTTL,
+ dormancyThreshold: dormancyThreshold,
+ dormancyAutoDeletion: dormancyAutoDeletion,
+ maxTTL: maxTTL,
+ autostopRequirementDaysOfWeek: autostopRequirementDaysOfWeek,
+ autostopRequirementWeeks: autostopRequirementWeeks,
+ autostartRequirementDaysOfWeek: autostartRequirementDaysOfWeek,
+ allowUserAutostart: allowUserAutostart,
+ allowUserAutostop: allowUserAutostop,
+ allowUserCancelWorkspaceJobs: allowUserCancelWorkspaceJobs,
+ deprecationMessage: deprecationMessage,
+ })
+
+ _, err = client.UpdateTemplateMeta(inv.Context(), template.ID, req)
+ if err != nil {
+ return xerrors.Errorf("update template metadata: %w", err)
+ }
+ if err != nil {
+ return err
+ }
+ _, _ = fmt.Fprintf(inv.Stdout, "Updated template metadata at %s!\n", pretty.Sprint(cliui.DefaultStyles.DateTimeStamp, time.Now().Format(time.Stamp)))
+
return nil
},
}
@@ -315,6 +413,27 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
Description: "Specify a name for the new template version. It will be automatically generated if not provided.",
Value: clibase.StringOf(&versionName),
},
+ {
+ Flag: "display-name",
+ Description: "Edit the template display name.",
+ Value: clibase.StringOf(&displayName),
+ },
+ {
+ Flag: "description",
+ Description: "Edit the template description.",
+ Value: clibase.StringOf(&description),
+ },
+ {
+ Name: "Deprecated",
+ Flag: "deprecated",
+ Description: "Sets the template as deprecated. Must be a message explaining why the template is deprecated.",
+ Value: clibase.StringOf(&deprecationMessage),
+ },
+ {
+ Flag: "icon",
+ Description: "Edit the template icon path.",
+ Value: clibase.StringOf(&icon),
+ },
{
Flag: "always-prompt",
Description: "Always prompt all parameters. Does not pull parameter values from active template version.",
@@ -327,10 +446,103 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
Value: clibase.BoolOf(&activate),
},
{
- Flag: "create",
- Description: "Create the template if it does not exist.",
+ Flag: "require-active-version",
+ Description: "Requires workspace builds to use the active template version. This setting does not apply to template admins. This is an enterprise-only feature.",
+ Value: clibase.BoolOf(&requireActiveVersion),
Default: "false",
- Value: clibase.BoolOf(&create),
+ },
+ {
+ Flag: "default-ttl",
+ Description: "Specify a default TTL for workspaces created from this template. It is the default time before shutdown - workspaces created from this template default to this value. Maps to \"Default autostop\" in the UI.",
+ Default: "24h",
+ Value: clibase.DurationOf(&defaultTTL),
+ },
+ {
+ Flag: "failure-ttl",
+ Description: "Specify a failure TTL for workspaces created from this template. It is the amount of time after a failed \"start\" build before coder automatically schedules a \"stop\" build to cleanup.This licensed feature's default is 0h (off). Maps to \"Failure cleanup\"in the UI.",
+ Default: "0h",
+ Value: clibase.DurationOf(&failureTTL),
+ },
+ {
+ Flag: "dormancy-threshold",
+ Description: "Specify a duration workspaces may be inactive prior to being moved to the dormant state. This licensed feature's default is 0h (off). Maps to \"Dormancy threshold\" in the UI.",
+ Default: "0h",
+ Value: clibase.DurationOf(&dormancyThreshold),
+ },
+ {
+ Flag: "dormancy-auto-deletion",
+ Description: "Specify a duration workspaces may be in the dormant state prior to being deleted. This licensed feature's default is 0h (off). Maps to \"Dormancy Auto-Deletion\" in the UI.",
+ Default: "0h",
+ Value: clibase.DurationOf(&dormancyAutoDeletion),
+ },
+ {
+ Flag: "max-ttl",
+ Description: "Edit the template maximum time before shutdown - workspaces created from this template must shutdown within the given duration after starting. This is an enterprise-only feature.",
+ Value: clibase.DurationOf(&maxTTL),
+ },
+ {
+ Flag: "private",
+ Description: "Disable the default behavior of granting template access to the 'everyone' group. " +
+ "The template permissions must be updated to allow non-admin users to use this template.",
+ Value: clibase.BoolOf(&disableEveryone),
+ },
+ {
+ Flag: "autostart-requirement-weekdays",
+ // workspaces created from this template must be restarted on the given weekdays. To unset this value for the template (and disable the autostop requirement for the template), pass 'none'.
+ Description: "Edit the template autostart requirement weekdays - workspaces created from this template can only autostart on the given weekdays. To unset this value for the template (and allow autostart on all days), pass 'all'.",
+ Value: clibase.Validate(clibase.StringArrayOf(&autostartRequirementDaysOfWeek), func(value *clibase.StringArray) error {
+ v := value.GetSlice()
+ if len(v) == 1 && v[0] == "all" {
+ return nil
+ }
+ _, err := codersdk.WeekdaysToBitmap(v)
+ if err != nil {
+ return xerrors.Errorf("invalid autostart requirement days of week %q: %w", strings.Join(v, ","), err)
+ }
+ return nil
+ }),
+ },
+ {
+ Flag: "autostop-requirement-weekdays",
+ Description: "Edit the template autostop requirement weekdays - workspaces created from this template must be restarted on the given weekdays. To unset this value for the template (and disable the autostop requirement for the template), pass 'none'.",
+ // TODO(@dean): unhide when we delete max_ttl
+ Hidden: true,
+ Value: clibase.Validate(clibase.StringArrayOf(&autostopRequirementDaysOfWeek), func(value *clibase.StringArray) error {
+ v := value.GetSlice()
+ if len(v) == 1 && v[0] == "none" {
+ return nil
+ }
+ _, err := codersdk.WeekdaysToBitmap(v)
+ if err != nil {
+ return xerrors.Errorf("invalid autostop requirement days of week %q: %w", strings.Join(v, ","), err)
+ }
+ return nil
+ }),
+ },
+ {
+ Flag: "autostop-requirement-weeks",
+ Description: "Edit the template autostop requirement weeks - workspaces created from this template must be restarted on an n-weekly basis.",
+ // TODO(@dean): unhide when we delete max_ttl
+ Hidden: true,
+ Value: clibase.Int64Of(&autostopRequirementWeeks),
+ },
+ {
+ Flag: "allow-user-cancel-workspace-jobs",
+ Description: "Allow users to cancel in-progress workspace jobs.",
+ Default: "true",
+ Value: clibase.BoolOf(&allowUserCancelWorkspaceJobs),
+ },
+ {
+ Flag: "allow-user-autostart",
+ Description: "Allow users to configure autostart for workspaces on this template. This can only be disabled in enterprise.",
+ Default: "true",
+ Value: clibase.BoolOf(&allowUserAutostart),
+ },
+ {
+ Flag: "allow-user-autostop",
+ Description: "Allow users to customize the autostop TTL for workspaces on this template. This can only be disabled in enterprise.",
+ Default: "true",
+ Value: clibase.BoolOf(&allowUserAutostop),
},
cliui.SkipPromptOption(),
}
diff --git a/cli/templatepush_test.go b/cli/templatepush_test.go
index 5736df8cc2edf..0c129f9ad07f4 100644
--- a/cli/templatepush_test.go
+++ b/cli/templatepush_test.go
@@ -6,8 +6,10 @@ import (
"os"
"path/filepath"
"runtime"
+ "strconv"
"strings"
"testing"
+ "time"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
@@ -676,10 +678,9 @@ func TestTemplatePush(t *testing.T) {
args := []string{
"templates",
"push",
- templateName,
+ "my-template",
"--directory", source,
"--test.provisioner", string(database.ProvisionerTypeEcho),
- "--create",
}
inv, root := clitest.New(t, args...)
clitest.SetupConfig(t, templateAdmin, root)
@@ -709,6 +710,153 @@ func TestTemplatePush(t *testing.T) {
require.NotEqual(t, uuid.Nil, template.ActiveVersionID)
})
})
+
+ t.Run("EditMetadata", func(t *testing.T) {
+ t.Parallel()
+ client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
+ owner := coderdtest.CreateFirstUser(t, client)
+ templateAdmin, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin())
+ version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
+ _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
+
+ template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
+
+ // Test the cli command.
+ source := clitest.CreateTemplateVersionSource(t, &echo.Responses{
+ Parse: echo.ParseComplete,
+ ProvisionApply: echo.ApplyComplete,
+ })
+
+ name := "new-template-name"
+ displayName := "New Display Name 789"
+ desc := "lorem ipsum dolor sit amet et cetera"
+ icon := "/icon/new-icon.png"
+ defaultTTL := 12 * time.Hour
+ allowUserCancelWorkspaceJobs := false
+
+ inv, root := clitest.New(t,
+ "templates",
+ "push",
+ template.Name,
+ "--directory", source,
+ "--test.provisioner", string(database.ProvisionerTypeEcho),
+ "--name", name,
+ "--display-name", displayName,
+ "--description", desc,
+ "--icon", icon,
+ "--default-ttl", defaultTTL.String(),
+ "--allow-user-cancel-workspace-jobs="+strconv.FormatBool(allowUserCancelWorkspaceJobs),
+ )
+ clitest.SetupConfig(t, templateAdmin, root)
+ pty := ptytest.New(t).Attach(inv)
+
+ execDone := make(chan error)
+ go func() {
+ execDone <- inv.Run()
+ }()
+
+ matches := []struct {
+ match string
+ write string
+ }{
+ {match: "Upload", write: "yes"},
+ }
+ for _, m := range matches {
+ pty.ExpectMatch(m.match)
+ pty.WriteLine(m.write)
+ }
+
+ require.NoError(t, <-execDone)
+
+ // Assert that the template version changed.
+ templateVersions, err := client.TemplateVersionsByTemplate(context.Background(), codersdk.TemplateVersionsByTemplateRequest{
+ TemplateID: template.ID,
+ })
+ require.NoError(t, err)
+ assert.Len(t, templateVersions, 2)
+ assert.NotEqual(t, template.ActiveVersionID, templateVersions[1].ID)
+ require.Equal(t, name, templateVersions[1].Name)
+
+ // Assert that the template metadata changed.
+ updated, err := client.Template(context.Background(), template.ID)
+ require.NoError(t, err)
+ assert.Equal(t, template.Name, updated.Name)
+ assert.Equal(t, displayName, updated.DisplayName)
+ assert.Equal(t, desc, updated.Description)
+ assert.Equal(t, icon, updated.Icon)
+ assert.Equal(t, defaultTTL.Milliseconds(), updated.DefaultTTLMillis)
+ assert.Equal(t, allowUserCancelWorkspaceJobs, updated.AllowUserCancelWorkspaceJobs)
+ })
+
+ t.Run("EditMetadataKeepUnsetUnchanged", func(t *testing.T) {
+ t.Parallel()
+ client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
+ owner := coderdtest.CreateFirstUser(t, client)
+ templateAdmin, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin())
+ version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
+ _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
+
+ template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
+
+ // Test the cli command.
+ source := clitest.CreateTemplateVersionSource(t, &echo.Responses{
+ Parse: echo.ParseComplete,
+ ProvisionApply: echo.ApplyComplete,
+ })
+
+ desc := "lorem ipsum dolor sit amet et cetera"
+
+ inv, root := clitest.New(t,
+ "templates",
+ "push",
+ template.Name,
+ "--directory", source,
+ "--test.provisioner", string(database.ProvisionerTypeEcho),
+ "--description", desc,
+ )
+ clitest.SetupConfig(t, templateAdmin, root)
+ pty := ptytest.New(t).Attach(inv)
+
+ execDone := make(chan error)
+ go func() {
+ execDone <- inv.Run()
+ }()
+
+ matches := []struct {
+ match string
+ write string
+ }{
+ {match: "Upload", write: "yes"},
+ }
+ for _, m := range matches {
+ pty.ExpectMatch(m.match)
+ pty.WriteLine(m.write)
+ }
+
+ require.NoError(t, <-execDone)
+
+ // Assert that the template version changed.
+ templateVersions, err := client.TemplateVersionsByTemplate(context.Background(), codersdk.TemplateVersionsByTemplateRequest{
+ TemplateID: template.ID,
+ })
+ require.NoError(t, err)
+ assert.Len(t, templateVersions, 2)
+ assert.NotEqual(t, template.ActiveVersionID, templateVersions[1].ID)
+
+ // Assert that the template metadata changed.
+ updated, err := client.Template(context.Background(), template.ID)
+ require.NoError(t, err)
+ assert.Equal(t, template.Name, updated.Name)
+ assert.Equal(t, template.DisplayName, updated.DisplayName)
+ assert.Equal(t, desc, updated.Description)
+ assert.Equal(t, template.Icon, updated.Icon)
+ assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
+ assert.Equal(t, template.FailureTTLMillis, updated.FailureTTLMillis)
+ assert.Equal(t, template.TimeTilDormantAutoDeleteMillis, updated.TimeTilDormantAutoDeleteMillis)
+ assert.Equal(t, template.AutostartRequirement.DaysOfWeek, updated.AutostartRequirement.DaysOfWeek)
+ assert.Equal(t, template.AutostopRequirement.DaysOfWeek, updated.AutostopRequirement.DaysOfWeek)
+ assert.Equal(t, template.RequireActiveVersion, updated.RequireActiveVersion)
+ })
}
func createEchoResponsesWithTemplateVariables(templateVariables []*proto.TemplateVariable) *echo.Responses {
diff --git a/cli/testdata/coder_templates_push_--help.golden b/cli/testdata/coder_templates_push_--help.golden
index 9d255c1f8bc23..e484c143e9971 100644
--- a/cli/testdata/coder_templates_push_--help.golden
+++ b/cli/testdata/coder_templates_push_--help.golden
@@ -6,23 +6,76 @@ USAGE:
Push a new template version from the current directory or as specified by flag
OPTIONS:
+ --deprecated string
+ Sets the template as deprecated. Must be a message explaining why the
+ template is deprecated.
+
--activate bool (default: true)
Whether the new template will be marked active.
+ --allow-user-autostart bool (default: true)
+ Allow users to configure autostart for workspaces on this template.
+ This can only be disabled in enterprise.
+
+ --allow-user-autostop bool (default: true)
+ Allow users to customize the autostop TTL for workspaces on this
+ template. This can only be disabled in enterprise.
+
+ --allow-user-cancel-workspace-jobs bool (default: true)
+ Allow users to cancel in-progress workspace jobs.
+
--always-prompt bool
Always prompt all parameters. Does not pull parameter values from
active template version.
- --create bool (default: false)
- Create the template if it does not exist.
+ --autostart-requirement-weekdays string-array
+ Edit the template autostart requirement weekdays - workspaces created
+ from this template can only autostart on the given weekdays. To unset
+ this value for the template (and allow autostart on all days), pass
+ 'all'.
+
+ --default-ttl duration (default: 24h)
+ Specify a default TTL for workspaces created from this template. It is
+ the default time before shutdown - workspaces created from this
+ template default to this value. Maps to "Default autostop" in the UI.
+
+ --description string
+ Edit the template description.
-d, --directory string (default: .)
Specify the directory to create from, use '-' to read tar from stdin.
+ --display-name string
+ Edit the template display name.
+
+ --dormancy-auto-deletion duration (default: 0h)
+ Specify a duration workspaces may be in the dormant state prior to
+ being deleted. This licensed feature's default is 0h (off). Maps to
+ "Dormancy Auto-Deletion" in the UI.
+
+ --dormancy-threshold duration (default: 0h)
+ Specify a duration workspaces may be inactive prior to being moved to
+ the dormant state. This licensed feature's default is 0h (off). Maps
+ to "Dormancy threshold" in the UI.
+
+ --failure-ttl duration (default: 0h)
+ Specify a failure TTL for workspaces created from this template. It is
+ the amount of time after a failed "start" build before coder
+ automatically schedules a "stop" build to cleanup.This licensed
+ feature's default is 0h (off). Maps to "Failure cleanup"in the UI.
+
+ --icon string
+ Edit the template icon path.
+
--ignore-lockfile bool (default: false)
Ignore warnings about not having a .terraform.lock.hcl file present in
the template.
+ --max-ttl duration
+ Edit the template maximum time before shutdown - workspaces created
+ from this template must shutdown within the given duration after
+ starting. This is an enterprise-only feature.
+
-m, --message string
Specify a message describing the changes in this version of the
template. Messages longer than 72 characters will be displayed as
@@ -32,9 +85,19 @@ OPTIONS:
Specify a name for the new template version. It will be automatically
generated if not provided.
+ --private bool
+ Disable the default behavior of granting template access to the
+ 'everyone' group. The template permissions must be updated to allow
+ non-admin users to use this template.
+
--provisioner-tag string-array
Specify a set of tags to target provisioner daemons.
+ --require-active-version bool (default: false)
+ Requires workspace builds to use the active template version. This
+ setting does not apply to template admins. This is an enterprise-only
+ feature.
+
--var string-array
Alias of --variable.
diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go
index 2a1f3b316c650..81bbe52386cf9 100644
--- a/coderd/database/queries.sql.go
+++ b/coderd/database/queries.sql.go
@@ -6075,19 +6075,21 @@ SET
name = $4,
icon = $5,
display_name = $6,
- allow_user_cancel_workspace_jobs = $7
+ allow_user_cancel_workspace_jobs = $7,
+ group_acl = $8
WHERE
id = $1
`
type UpdateTemplateMetaByIDParams struct {
- ID uuid.UUID `db:"id" json:"id"`
- UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
- Description string `db:"description" json:"description"`
- Name string `db:"name" json:"name"`
- Icon string `db:"icon" json:"icon"`
- DisplayName string `db:"display_name" json:"display_name"`
- AllowUserCancelWorkspaceJobs bool `db:"allow_user_cancel_workspace_jobs" json:"allow_user_cancel_workspace_jobs"`
+ ID uuid.UUID `db:"id" json:"id"`
+ UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
+ Description string `db:"description" json:"description"`
+ Name string `db:"name" json:"name"`
+ Icon string `db:"icon" json:"icon"`
+ DisplayName string `db:"display_name" json:"display_name"`
+ AllowUserCancelWorkspaceJobs bool `db:"allow_user_cancel_workspace_jobs" json:"allow_user_cancel_workspace_jobs"`
+ GroupACL TemplateACL `db:"group_acl" json:"group_acl"`
}
func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTemplateMetaByIDParams) error {
@@ -6099,6 +6101,7 @@ func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTempl
arg.Icon,
arg.DisplayName,
arg.AllowUserCancelWorkspaceJobs,
+ arg.GroupACL,
)
return err
}
diff --git a/coderd/database/queries/templates.sql b/coderd/database/queries/templates.sql
index af8c3fe80f420..ca031bb0bd839 100644
--- a/coderd/database/queries/templates.sql
+++ b/coderd/database/queries/templates.sql
@@ -115,7 +115,8 @@ SET
name = $4,
icon = $5,
display_name = $6,
- allow_user_cancel_workspace_jobs = $7
+ allow_user_cancel_workspace_jobs = $7,
+ group_acl = $8
WHERE
id = $1
;
diff --git a/coderd/templates.go b/coderd/templates.go
index 5e6d9644a782f..d4c33a454ce16 100644
--- a/coderd/templates.go
+++ b/coderd/templates.go
@@ -667,6 +667,11 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
name = template.Name
}
+ groupACL := template.GroupACL
+ if req.DisableEveryoneGroupAccess {
+ groupACL = database.TemplateACL{}
+ }
+
var err error
err = tx.UpdateTemplateMetaByID(ctx, database.UpdateTemplateMetaByIDParams{
ID: template.ID,
@@ -676,6 +681,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
Description: req.Description,
Icon: req.Icon,
AllowUserCancelWorkspaceJobs: req.AllowUserCancelWorkspaceJobs,
+ GroupACL: groupACL,
})
if err != nil {
return xerrors.Errorf("update template metadata: %w", err)
diff --git a/codersdk/templates.go b/codersdk/templates.go
index 8164843ad0c66..1be4d931ad7a2 100644
--- a/codersdk/templates.go
+++ b/codersdk/templates.go
@@ -241,6 +241,12 @@ type UpdateTemplateMeta struct {
// If passed an empty string, will remove the deprecated message, making
// the template usable for new workspaces again.
DeprecationMessage *string `json:"deprecation_message"`
+ // DisableEveryoneGroupAccess allows optionally disabling the default
+ // behavior of granting the 'everyone' group access to use the template.
+ // 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"`
}
type TemplateExample struct {
diff --git a/docs/cli/templates_push.md b/docs/cli/templates_push.md
index bfa73fdad1151..9df46fdf69e9c 100644
--- a/docs/cli/templates_push.md
+++ b/docs/cli/templates_push.md
@@ -12,6 +12,14 @@ coder templates push [flags] [template]
## Options
+### --deprecated
+
+| | |
+| ---- | ------------------- |
+| Type | string
|
+
+Sets the template as deprecated. Must be a message explaining why the template is deprecated.
+
### --activate
| | |
@@ -21,6 +29,33 @@ coder templates push [flags] [template]
Whether the new template will be marked active.
+### --allow-user-autostart
+
+| | |
+| ------- | ----------------- |
+| Type | bool
|
+| Default | true
|
+
+Allow users to configure autostart for workspaces on this template. This can only be disabled in enterprise.
+
+### --allow-user-autostop
+
+| | |
+| ------- | ----------------- |
+| Type | bool
|
+| Default | true
|
+
+Allow users to customize the autostop TTL for workspaces on this template. This can only be disabled in enterprise.
+
+### --allow-user-cancel-workspace-jobs
+
+| | |
+| ------- | ----------------- |
+| Type | bool
|
+| Default | true
|
+
+Allow users to cancel in-progress workspace jobs.
+
### --always-prompt
| | |
@@ -29,14 +64,30 @@ Whether the new template will be marked active.
Always prompt all parameters. Does not pull parameter values from active template version.
-### --create
+### --autostart-requirement-weekdays
-| | |
-| ------- | ------------------ |
-| Type | bool
|
-| Default | false
|
+| | |
+| ---- | ------------------------- |
+| Type | string-array
|
+
+Edit the template autostart requirement weekdays - workspaces created from this template can only autostart on the given weekdays. To unset this value for the template (and allow autostart on all days), pass 'all'.
+
+### --default-ttl
+
+| | |
+| ------- | --------------------- |
+| Type | duration
|
+| Default | 24h
|
+
+Specify a default TTL for workspaces created from this template. It is the default time before shutdown - workspaces created from this template default to this value. Maps to "Default autostop" in the UI.
+
+### --description
+
+| | |
+| ---- | ------------------- |
+| Type | string
|
-Create the template if it does not exist.
+Edit the template description.
### -d, --directory
@@ -47,6 +98,49 @@ Create the template if it does not exist.
Specify the directory to create from, use '-' to read tar from stdin.
+### --display-name
+
+| | |
+| ---- | ------------------- |
+| Type | string
|
+
+Edit the template display name.
+
+### --dormancy-auto-deletion
+
+| | |
+| ------- | --------------------- |
+| Type | duration
|
+| Default | 0h
|
+
+Specify a duration workspaces may be in the dormant state prior to being deleted. This licensed feature's default is 0h (off). Maps to "Dormancy Auto-Deletion" in the UI.
+
+### --dormancy-threshold
+
+| | |
+| ------- | --------------------- |
+| Type | duration
|
+| Default | 0h
|
+
+Specify a duration workspaces may be inactive prior to being moved to the dormant state. This licensed feature's default is 0h (off). Maps to "Dormancy threshold" in the UI.
+
+### --failure-ttl
+
+| | |
+| ------- | --------------------- |
+| Type | duration
|
+| Default | 0h
|
+
+Specify a failure TTL for workspaces created from this template. It is the amount of time after a failed "start" build before coder automatically schedules a "stop" build to cleanup.This licensed feature's default is 0h (off). Maps to "Failure cleanup"in the UI.
+
+### --icon
+
+| | |
+| ---- | ------------------- |
+| Type | string
|
+
+Edit the template icon path.
+
### --ignore-lockfile
| | |
@@ -56,6 +150,14 @@ Specify the directory to create from, use '-' to read tar from stdin.
Ignore warnings about not having a .terraform.lock.hcl file present in the template.
+### --max-ttl
+
+| | |
+| ---- | --------------------- |
+| Type | duration
|
+
+Edit the template maximum time before shutdown - workspaces created from this template must shutdown within the given duration after starting. This is an enterprise-only feature.
+
### -m, --message
| | |
@@ -72,6 +174,14 @@ Specify a message describing the changes in this version of the template. Messag
Specify a name for the new template version. It will be automatically generated if not provided.
+### --private
+
+| | |
+| ---- | ----------------- |
+| Type | bool
|
+
+Disable the default behavior of granting template access to the 'everyone' group. The template permissions must be updated to allow non-admin users to use this template.
+
### --provisioner-tag
| | |
@@ -80,6 +190,15 @@ Specify a name for the new template version. It will be automatically generated
Specify a set of tags to target provisioner daemons.
+### --require-active-version
+
+| | |
+| ------- | ------------------ |
+| Type | bool
|
+| Default | false
|
+
+Requires workspace builds to use the active template version. This setting does not apply to template admins. This is an enterprise-only feature.
+
### --var
| | |
diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts
index 98def777d9a91..bd5b35ecd5aab 100644
--- a/site/src/api/typesGenerated.ts
+++ b/site/src/api/typesGenerated.ts
@@ -1264,6 +1264,7 @@ export interface UpdateTemplateMeta {
readonly update_workspace_dormant_at: boolean;
readonly require_active_version: boolean;
readonly deprecation_message?: string;
+ readonly disable_everyone_group_access: boolean;
}
// From codersdk/users.go
diff --git a/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsForm.tsx b/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsForm.tsx
index 2c37ca5729ba6..77de9c36bb583 100644
--- a/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsForm.tsx
+++ b/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsForm.tsx
@@ -77,6 +77,7 @@ export const TemplateSettingsForm: FC = ({
update_workspace_dormant_at: false,
require_active_version: template.require_active_version,
deprecation_message: template.deprecation_message,
+ disable_everyone_group_access: false,
},
validationSchema,
onSubmit,
diff --git a/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsPage.test.tsx b/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsPage.test.tsx
index be0d593c9e13e..ee6153646584a 100644
--- a/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsPage.test.tsx
+++ b/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsPage.test.tsx
@@ -47,6 +47,7 @@ const validFormValues: FormValues = {
update_workspace_last_used_at: false,
update_workspace_dormant_at: false,
require_active_version: false,
+ disable_everyone_group_access: false,
};
const renderTemplateSettingsPage = async () => {
diff --git a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateScheduleForm.tsx b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateScheduleForm.tsx
index f1f0af511ec9b..89f26cc5d451e 100644
--- a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateScheduleForm.tsx
+++ b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateScheduleForm.tsx
@@ -118,6 +118,7 @@ export const TemplateScheduleForm: FC = ({
update_workspace_last_used_at: false,
update_workspace_dormant_at: false,
require_active_version: false,
+ disable_everyone_group_access: false,
},
validationSchema,
onSubmit: () => {
@@ -238,6 +239,7 @@ export const TemplateScheduleForm: FC = ({
update_workspace_last_used_at: form.values.update_workspace_last_used_at,
update_workspace_dormant_at: form.values.update_workspace_dormant_at,
require_active_version: false,
+ disable_everyone_group_access: false,
});
};
diff --git a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.test.tsx b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.test.tsx
index 77e50d73f0657..1a5618cf3263a 100644
--- a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.test.tsx
+++ b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.test.tsx
@@ -28,6 +28,7 @@ const validFormValues: TemplateScheduleFormValues = {
inactivity_cleanup_enabled: false,
dormant_autodeletion_cleanup_enabled: false,
require_active_version: false,
+ disable_everyone_group_access: false,
autostart_requirement_days_of_week: [
"monday",
"tuesday",