@@ -257,13 +257,6 @@ func editEnvCommand(user *string) *cobra.Command {
257
257
258
258
coder envs edit back-end-env --disk 20` ,
259
259
RunE : func (cmd * cobra.Command , args []string ) error {
260
- // We're explicitly ignoring these errors because if any of these
261
- // fail we are left with the zero value for the corresponding numeric type.
262
- cpuCores , _ = cmd .Flags ().GetFloat32 ("cpu" )
263
- memGB , _ = cmd .Flags ().GetFloat32 ("memory" )
264
- diskGB , _ = cmd .Flags ().GetInt ("disk" )
265
- gpus , _ = cmd .Flags ().GetInt ("gpus" )
266
-
267
260
client , err := newClient ()
268
261
if err != nil {
269
262
return err
@@ -276,52 +269,21 @@ coder envs edit back-end-env --disk 20`,
276
269
return err
277
270
}
278
271
279
- var updateReq coder.UpdateEnvironmentReq
280
-
281
- // If any of the flags have defaulted to zero-values, it implies the user does not wish to change that value.
282
- // With that said, we can enforce this by reassigning the request field to the corresponding existing environment value.
283
- if cpuCores == 0 {
284
- updateReq .CPUCores = & env .CPUCores
285
- } else {
286
- updateReq .CPUCores = & cpuCores
287
- }
288
-
289
- if memGB == 0 {
290
- updateReq .MemoryGB = & env .MemoryGB
291
- } else {
292
- updateReq .MemoryGB = & memGB
293
- }
294
-
295
- if diskGB == 0 {
296
- updateReq .DiskGB = & env .DiskGB
297
- } else {
298
- updateReq .DiskGB = & diskGB
299
- }
300
-
301
- if gpus == 0 {
302
- updateReq .GPUs = & env .GPUs
303
- } else {
304
- updateReq .GPUs = & gpus
305
- }
306
-
307
- if img != "" {
308
- importedImg , err := findImg (cmd .Context (), client , * user , img )
309
- if err != nil {
310
- return err
311
- }
312
- updateReq .ImageID = & importedImg .ID
313
- } else {
314
- updateReq .ImageID = & env .ImageID
315
- }
316
-
317
- if tag == "" {
318
- updateReq .ImageTag = & env .ImageTag
319
- } else {
320
- updateReq .ImageTag = & tag
272
+ req , err := buildUpdateReq (updateConf {
273
+ command : cmd ,
274
+ client : client ,
275
+ environment : env ,
276
+ user : user ,
277
+ image : img ,
278
+ imageTag : tag ,
279
+ },
280
+ )
281
+ if err != nil {
282
+ return err
321
283
}
322
284
323
- if err := client .EditEnvironment (cmd .Context (), env .ID , updateReq ); err != nil {
324
- return xerrors .Errorf ("failed to apply changes to environment: '%s' " , envName )
285
+ if err := client .EditEnvironment (cmd .Context (), env .ID , * req ); err != nil {
286
+ return xerrors .Errorf ("failed to apply changes to environment %q: %w " , envName , err )
325
287
}
326
288
327
289
if follow {
@@ -406,3 +368,104 @@ func rmEnvsCommand(user *string) *cobra.Command {
406
368
cmd .Flags ().BoolVarP (& force , "force" , "f" , false , "force remove the specified environments without prompting first" )
407
369
return cmd
408
370
}
371
+
372
+ type updateConf struct {
373
+ command * cobra.Command
374
+ client * coder.Client
375
+ environment * coder.Environment
376
+ user * string
377
+ image string
378
+ imageTag string
379
+ }
380
+
381
+ func buildUpdateReq (conf updateConf ) (* coder.UpdateEnvironmentReq , error ) {
382
+ var (
383
+ updateReq coder.UpdateEnvironmentReq
384
+ defaultCPUCores float32
385
+ defaultMemGB float32
386
+ defaultDiskGB int
387
+ )
388
+
389
+ // If this is not empty it means the user is requesting to change the environment image.
390
+ if conf .image != "" {
391
+ importedImg , err := findImg (conf .command .Context (),
392
+ conf .client ,
393
+ * conf .user ,
394
+ conf .image ,
395
+ )
396
+ if err != nil {
397
+ return nil , err
398
+ }
399
+
400
+ // If the user passes an image arg of the image that
401
+ // the environment is already using, it was most likely a mistake.
402
+ if conf .image != importedImg .Repository {
403
+ return nil , xerrors .Errorf ("environment is already using image %q" , conf .image )
404
+ }
405
+
406
+ // Since the environment image is being changed,
407
+ // the resource amount defaults should be changed to
408
+ // reflect that of the default resource amounts of the new image.
409
+ defaultCPUCores = importedImg .DefaultCPUCores
410
+ defaultMemGB = importedImg .DefaultMemoryGB
411
+ defaultDiskGB = importedImg .DefaultDiskGB
412
+ updateReq .ImageID = & importedImg .ID
413
+ } else {
414
+ // if the environment image is not being changed, the default
415
+ // resource amounts should reflect the default resource amounts
416
+ // of the image the environment is already using.
417
+ defaultCPUCores = conf .environment .CPUCores
418
+ defaultMemGB = conf .environment .MemoryGB
419
+ defaultDiskGB = conf .environment .DiskGB
420
+ updateReq .ImageID = & conf .environment .ImageID
421
+ }
422
+
423
+ // The following logic checks to see if the user specified
424
+ // any resource amounts for the environment that need to be changed.
425
+ // If they did not, then we will get the zero value back
426
+ // and should set the resource amount to the default.
427
+
428
+ cpuCores , _ := conf .command .Flags ().GetFloat32 ("cpu" )
429
+ if cpuCores == 0 {
430
+ updateReq .CPUCores = & defaultCPUCores
431
+ } else {
432
+ updateReq .CPUCores = & cpuCores
433
+ }
434
+
435
+ memGB , _ := conf .command .Flags ().GetFloat32 ("memory" )
436
+ if memGB == 0 {
437
+ updateReq .MemoryGB = & defaultMemGB
438
+ } else {
439
+ updateReq .MemoryGB = & memGB
440
+ }
441
+
442
+ diskGB , _ := conf .command .Flags ().GetInt ("disk" )
443
+ if diskGB == 0 {
444
+ updateReq .DiskGB = & defaultDiskGB
445
+ } else {
446
+ updateReq .DiskGB = & diskGB
447
+ }
448
+
449
+ // Environment disks can not be shrink so we have to overwrite this
450
+ // if the user accidentally requests it or if the default diskGB value for a
451
+ // newly requested image is smaller than the current amount the environment is using.
452
+ if * updateReq .DiskGB < conf .environment .DiskGB {
453
+ updateReq .DiskGB = & conf .environment .DiskGB
454
+ }
455
+
456
+ gpus , _ := conf .command .Flags ().GetInt ("gpus" )
457
+ if gpus != 0 {
458
+ updateReq .GPUs = & gpus
459
+ }
460
+
461
+ if conf .imageTag == "" {
462
+ // We're forced to make an alloc here because untyped string consts are not addressable.
463
+ // i.e. updateReq.ImageTag = &defaultImgTag results in :
464
+ // invalid operation: cannot take address of defaultImgTag (untyped string constant "latest")
465
+ imgTag := defaultImgTag
466
+ updateReq .ImageTag = & imgTag
467
+ } else {
468
+ updateReq .ImageTag = & conf .imageTag
469
+ }
470
+ return & updateReq , nil
471
+ }
0 commit comments