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
+ }