1
1
package cli
2
2
3
3
import (
4
+ "context"
4
5
"fmt"
5
6
"net/http"
6
7
"strings"
@@ -46,58 +47,6 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
46
47
),
47
48
Short : "Edit the metadata of a template by name." ,
48
49
Handler : func (inv * clibase.Invocation ) error {
49
- // This clause can be removed when workspace_actions is no longer experimental
50
- if failureTTL != 0 || dormancyThreshold != 0 || dormancyAutoDeletion != 0 {
51
- experiments , exErr := client .Experiments (inv .Context ())
52
- if exErr != nil {
53
- return xerrors .Errorf ("get experiments: %w" , exErr )
54
- }
55
-
56
- if ! experiments .Enabled (codersdk .ExperimentWorkspaceActions ) {
57
- 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." )
58
- }
59
- }
60
-
61
- unsetAutostopRequirementDaysOfWeek := len (autostopRequirementDaysOfWeek ) == 1 && autostopRequirementDaysOfWeek [0 ] == "none"
62
- requiresScheduling := (len (autostopRequirementDaysOfWeek ) > 0 && ! unsetAutostopRequirementDaysOfWeek ) ||
63
- autostopRequirementWeeks > 0 ||
64
- ! allowUserAutostart ||
65
- ! allowUserAutostop ||
66
- maxTTL != 0 ||
67
- failureTTL != 0 ||
68
- dormancyThreshold != 0 ||
69
- dormancyAutoDeletion != 0 ||
70
- len (autostartRequirementDaysOfWeek ) > 0
71
-
72
- requiresEntitlement := requiresScheduling || requireActiveVersion
73
- if requiresEntitlement {
74
- entitlements , err := client .Entitlements (inv .Context ())
75
- if cerr , ok := codersdk .AsError (err ); ok && cerr .StatusCode () == http .StatusNotFound {
76
- return xerrors .Errorf ("your deployment appears to be an AGPL deployment, so you cannot set enterprise-only flags" )
77
- } else if err != nil {
78
- return xerrors .Errorf ("get entitlements: %w" , err )
79
- }
80
-
81
- if requiresScheduling && ! entitlements .Features [codersdk .FeatureAdvancedTemplateScheduling ].Enabled {
82
- 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" )
83
- }
84
-
85
- if requireActiveVersion {
86
- if ! entitlements .Features [codersdk .FeatureAccessControl ].Enabled {
87
- return xerrors .Errorf ("your license is not entitled to use enterprise access control, so you cannot set --require-active-version" )
88
- }
89
-
90
- experiments , exErr := client .Experiments (inv .Context ())
91
- if exErr != nil {
92
- return xerrors .Errorf ("get experiments: %w" , exErr )
93
- }
94
-
95
- if ! experiments .Enabled (codersdk .ExperimentTemplateUpdatePolicies ) {
96
- return xerrors .Errorf ("--require-active-version is an experimental feature, contact an administrator to enable the 'template_update_policies' experiment on your Coder server" )
97
- }
98
- }
99
- }
100
-
101
50
organization , err := CurrentOrganization (inv , client )
102
51
if err != nil {
103
52
return xerrors .Errorf ("get current organization: %w" , err )
@@ -107,71 +56,55 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
107
56
return xerrors .Errorf ("get workspace template: %w" , err )
108
57
}
109
58
110
- // Copy the default value if the list is empty, or if the user
111
- // specified the "none" value clear the list.
112
- if len (autostopRequirementDaysOfWeek ) == 0 {
113
- autostopRequirementDaysOfWeek = template .AutostopRequirement .DaysOfWeek
114
- }
115
- if len (autostartRequirementDaysOfWeek ) == 1 && autostartRequirementDaysOfWeek [0 ] == "all" {
116
- // Set it to every day of the week
117
- autostartRequirementDaysOfWeek = []string {"monday" , "tuesday" , "wednesday" , "thursday" , "friday" , "saturday" , "sunday" }
118
- } else if len (autostartRequirementDaysOfWeek ) == 0 {
119
- autostartRequirementDaysOfWeek = template .AutostartRequirement .DaysOfWeek
120
- }
121
- if unsetAutostopRequirementDaysOfWeek {
122
- autostopRequirementDaysOfWeek = []string {}
123
- }
124
- if failureTTL == 0 {
125
- failureTTL = time .Duration (template .FailureTTLMillis ) * time .Millisecond
126
- }
127
- if dormancyThreshold == 0 {
128
- dormancyThreshold = time .Duration (template .TimeTilDormantMillis ) * time .Millisecond
129
- }
130
- if dormancyAutoDeletion == 0 {
131
- dormancyAutoDeletion = time .Duration (template .TimeTilDormantAutoDeleteMillis ) * time .Millisecond
132
- }
133
-
134
- // Default values
135
- if ! userSetOption (inv , "description" ) {
136
- description = template .Description
137
- }
59
+ unsetAutostopRequirementDaysOfWeek , err := editTemplateEntitlementsCheck (inv .Context (), editTemplateEntitlementsArgs {
60
+ client : client ,
61
+ inv : inv ,
62
+ template : template ,
138
63
139
- if ! userSetOption (inv , "icon" ) {
140
- icon = template .Icon
141
- }
64
+ name : name ,
65
+ displayName : displayName ,
66
+ description : description ,
67
+ icon : icon ,
68
+ defaultTTL : defaultTTL ,
69
+ maxTTL : maxTTL ,
70
+ autostopRequirementDaysOfWeek : autostopRequirementDaysOfWeek ,
71
+ autostopRequirementWeeks : autostopRequirementWeeks ,
72
+ autostartRequirementDaysOfWeek : autostartRequirementDaysOfWeek ,
73
+ failureTTL : failureTTL ,
74
+ dormancyThreshold : dormancyThreshold ,
75
+ dormancyAutoDeletion : dormancyAutoDeletion ,
76
+ allowUserCancelWorkspaceJobs : allowUserCancelWorkspaceJobs ,
77
+ allowUserAutostart : allowUserAutostart ,
78
+ allowUserAutostop : allowUserAutostop ,
79
+ requireActiveVersion : requireActiveVersion ,
80
+ deprecationMessage : deprecationMessage ,
81
+ disableEveryone : false , // TODO: Add new flag
82
+ })
142
83
143
- if ! userSetOption (inv , "display-name" ) {
144
- displayName = template .DisplayName
145
- }
84
+ req := updateTemplateMetaRequest (updateTemplateMetaArgs {
85
+ client : client ,
86
+ inv : inv ,
87
+ template : template ,
88
+ unsetAutostopRequirementDaysOfWeek : unsetAutostopRequirementDaysOfWeek ,
146
89
147
- var deprecated * string
148
- if ! userSetOption (inv , "deprecated" ) {
149
- deprecated = & deprecationMessage
150
- }
151
-
152
- req := codersdk.UpdateTemplateMeta {
153
- Name : name ,
154
- DisplayName : displayName ,
155
- Description : description ,
156
- Icon : icon ,
157
- DefaultTTLMillis : defaultTTL .Milliseconds (),
158
- MaxTTLMillis : maxTTL .Milliseconds (),
159
- AutostopRequirement : & codersdk.TemplateAutostopRequirement {
160
- DaysOfWeek : autostopRequirementDaysOfWeek ,
161
- Weeks : autostopRequirementWeeks ,
162
- },
163
- AutostartRequirement : & codersdk.TemplateAutostartRequirement {
164
- DaysOfWeek : autostartRequirementDaysOfWeek ,
165
- },
166
- FailureTTLMillis : failureTTL .Milliseconds (),
167
- TimeTilDormantMillis : dormancyThreshold .Milliseconds (),
168
- TimeTilDormantAutoDeleteMillis : dormancyAutoDeletion .Milliseconds (),
169
- AllowUserCancelWorkspaceJobs : allowUserCancelWorkspaceJobs ,
170
- AllowUserAutostart : allowUserAutostart ,
171
- AllowUserAutostop : allowUserAutostop ,
172
- RequireActiveVersion : requireActiveVersion ,
173
- DeprecationMessage : deprecated ,
174
- }
90
+ name : name ,
91
+ displayName : displayName ,
92
+ description : description ,
93
+ icon : icon ,
94
+ defaultTTL : defaultTTL ,
95
+ maxTTL : maxTTL ,
96
+ autostopRequirementDaysOfWeek : autostopRequirementDaysOfWeek ,
97
+ autostopRequirementWeeks : autostopRequirementWeeks ,
98
+ autostartRequirementDaysOfWeek : autostartRequirementDaysOfWeek ,
99
+ failureTTL : failureTTL ,
100
+ dormancyThreshold : dormancyThreshold ,
101
+ dormancyAutoDeletion : dormancyAutoDeletion ,
102
+ allowUserCancelWorkspaceJobs : allowUserCancelWorkspaceJobs ,
103
+ allowUserAutostart : allowUserAutostart ,
104
+ allowUserAutostop : allowUserAutostop ,
105
+ requireActiveVersion : requireActiveVersion ,
106
+ deprecationMessage : deprecationMessage ,
107
+ })
175
108
176
109
_ , err = client .UpdateTemplateMeta (inv .Context (), template .ID , req )
177
110
if err != nil {
@@ -306,3 +239,171 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
306
239
307
240
return cmd
308
241
}
242
+
243
+ type editTemplateEntitlementsArgs struct {
244
+ client * codersdk.Client
245
+ inv * clibase.Invocation
246
+
247
+ defaultTTL time.Duration
248
+ maxTTL time.Duration
249
+ autostopRequirementDaysOfWeek []string
250
+ autostopRequirementWeeks int64
251
+ autostartRequirementDaysOfWeek []string
252
+ failureTTL time.Duration
253
+ dormancyThreshold time.Duration
254
+ dormancyAutoDeletion time.Duration
255
+ allowUserCancelWorkspaceJobs bool
256
+ allowUserAutostart bool
257
+ allowUserAutostop bool
258
+ requireActiveVersion bool
259
+ }
260
+
261
+ func editTemplateEntitlementsCheck (ctx context.Context , args editTemplateEntitlementsArgs ) (bool , error ) {
262
+ // This clause can be removed when workspace_actions is no longer experimental
263
+ if args .failureTTL != 0 || args .dormancyThreshold != 0 || args .dormancyAutoDeletion != 0 {
264
+ experiments , exErr := args .client .Experiments (ctx )
265
+ if exErr != nil {
266
+ return false , xerrors .Errorf ("get experiments: %w" , exErr )
267
+ }
268
+
269
+ if ! experiments .Enabled (codersdk .ExperimentWorkspaceActions ) {
270
+ 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." )
271
+ }
272
+ }
273
+
274
+ unsetAutostopRequirementDaysOfWeek := len (args .autostopRequirementDaysOfWeek ) == 1 && args .autostopRequirementDaysOfWeek [0 ] == "none"
275
+ requiresScheduling := (len (args .autostopRequirementDaysOfWeek ) > 0 && ! unsetAutostopRequirementDaysOfWeek ) ||
276
+ args .autostopRequirementWeeks > 0 ||
277
+ ! args .allowUserAutostart ||
278
+ ! args .allowUserAutostop ||
279
+ args .maxTTL != 0 ||
280
+ args .failureTTL != 0 ||
281
+ args .dormancyThreshold != 0 ||
282
+ args .dormancyAutoDeletion != 0 ||
283
+ len (args .autostartRequirementDaysOfWeek ) > 0
284
+
285
+ requiresEntitlement := requiresScheduling || args .requireActiveVersion
286
+ if requiresEntitlement {
287
+ entitlements , err := args .client .Entitlements (ctx )
288
+ if cerr , ok := codersdk .AsError (err ); ok && cerr .StatusCode () == http .StatusNotFound {
289
+ return false , xerrors .Errorf ("your deployment appears to be an AGPL deployment, so you cannot set enterprise-only flags" )
290
+ } else if err != nil {
291
+ return false , xerrors .Errorf ("get entitlements: %w" , err )
292
+ }
293
+
294
+ if requiresScheduling && ! entitlements .Features [codersdk .FeatureAdvancedTemplateScheduling ].Enabled {
295
+ 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" )
296
+ }
297
+
298
+ if args .requireActiveVersion {
299
+ if ! entitlements .Features [codersdk .FeatureAccessControl ].Enabled {
300
+ return false , xerrors .Errorf ("your license is not entitled to use enterprise access control, so you cannot set --require-active-version" )
301
+ }
302
+
303
+ experiments , exErr := args .client .Experiments (ctx )
304
+ if exErr != nil {
305
+ return false , xerrors .Errorf ("get experiments: %w" , exErr )
306
+ }
307
+
308
+ if ! experiments .Enabled (codersdk .ExperimentTemplateUpdatePolicies ) {
309
+ return false , xerrors .Errorf ("--require-active-version is an experimental feature, contact an administrator to enable the 'template_update_policies' experiment on your Coder server" )
310
+ }
311
+ }
312
+ }
313
+
314
+ return unsetAutostopRequirementDaysOfWeek , nil
315
+ }
316
+
317
+ type updateTemplateMetaArgs struct {
318
+ client * codersdk.Client
319
+ inv * clibase.Invocation
320
+ template codersdk.Template
321
+ unsetAutostopRequirementDaysOfWeek bool
322
+
323
+ name string
324
+ displayName string
325
+ description string
326
+ icon string
327
+ defaultTTL time.Duration
328
+ maxTTL time.Duration
329
+ autostopRequirementDaysOfWeek []string
330
+ autostopRequirementWeeks int64
331
+ autostartRequirementDaysOfWeek []string
332
+ failureTTL time.Duration
333
+ dormancyThreshold time.Duration
334
+ dormancyAutoDeletion time.Duration
335
+ allowUserCancelWorkspaceJobs bool
336
+ allowUserAutostart bool
337
+ allowUserAutostop bool
338
+ requireActiveVersion bool
339
+ deprecationMessage string
340
+ disableEveryone bool
341
+ }
342
+
343
+ func updateTemplateMetaRequest (args updateTemplateMetaArgs ) codersdk.UpdateTemplateMeta {
344
+ // Copy the default value if the list is empty, or if the user
345
+ // specified the "none" value clear the list.
346
+ if len (args .autostopRequirementDaysOfWeek ) == 0 {
347
+ args .autostopRequirementDaysOfWeek = args .template .AutostopRequirement .DaysOfWeek
348
+ }
349
+ if len (args .autostartRequirementDaysOfWeek ) == 1 && args .autostartRequirementDaysOfWeek [0 ] == "all" {
350
+ // Set it to every day of the week
351
+ args .autostartRequirementDaysOfWeek = []string {"monday" , "tuesday" , "wednesday" , "thursday" , "friday" , "saturday" , "sunday" }
352
+ } else if len (args .autostartRequirementDaysOfWeek ) == 0 {
353
+ args .autostartRequirementDaysOfWeek = args .template .AutostartRequirement .DaysOfWeek
354
+ }
355
+ if args .unsetAutostopRequirementDaysOfWeek {
356
+ args .autostopRequirementDaysOfWeek = []string {}
357
+ }
358
+ if args .failureTTL == 0 {
359
+ args .failureTTL = time .Duration (args .template .FailureTTLMillis ) * time .Millisecond
360
+ }
361
+ if args .dormancyThreshold == 0 {
362
+ args .dormancyThreshold = time .Duration (args .template .TimeTilDormantMillis ) * time .Millisecond
363
+ }
364
+ if args .dormancyAutoDeletion == 0 {
365
+ args .dormancyAutoDeletion = time .Duration (args .template .TimeTilDormantAutoDeleteMillis ) * time .Millisecond
366
+ }
367
+
368
+ // Default values
369
+ if ! userSetOption (args .inv , "description" ) {
370
+ args .description = args .template .Description
371
+ }
372
+
373
+ if ! userSetOption (args .inv , "icon" ) {
374
+ args .icon = args .template .Icon
375
+ }
376
+
377
+ if ! userSetOption (args .inv , "display-name" ) {
378
+ args .displayName = args .template .DisplayName
379
+ }
380
+
381
+ var deprecated * string
382
+ if ! userSetOption (args .inv , "deprecated" ) {
383
+ deprecated = & args .deprecationMessage
384
+ }
385
+
386
+ return codersdk.UpdateTemplateMeta {
387
+ Name : args .name ,
388
+ DisplayName : args .displayName ,
389
+ Description : args .description ,
390
+ Icon : args .icon ,
391
+ DefaultTTLMillis : args .defaultTTL .Milliseconds (),
392
+ MaxTTLMillis : args .maxTTL .Milliseconds (),
393
+ AutostopRequirement : & codersdk.TemplateAutostopRequirement {
394
+ DaysOfWeek : args .autostopRequirementDaysOfWeek ,
395
+ Weeks : args .autostopRequirementWeeks ,
396
+ },
397
+ AutostartRequirement : & codersdk.TemplateAutostartRequirement {
398
+ DaysOfWeek : args .autostartRequirementDaysOfWeek ,
399
+ },
400
+ FailureTTLMillis : args .failureTTL .Milliseconds (),
401
+ TimeTilDormantMillis : args .dormancyThreshold .Milliseconds (),
402
+ TimeTilDormantAutoDeleteMillis : args .dormancyAutoDeletion .Milliseconds (),
403
+ AllowUserCancelWorkspaceJobs : args .allowUserCancelWorkspaceJobs ,
404
+ AllowUserAutostart : args .allowUserAutostart ,
405
+ AllowUserAutostop : args .allowUserAutostop ,
406
+ RequireActiveVersion : args .requireActiveVersion ,
407
+ DeprecationMessage : deprecated ,
408
+ }
409
+ }
0 commit comments