@@ -6,8 +6,12 @@ package provider
6
6
import (
7
7
"context"
8
8
"fmt"
9
+ "os"
10
+ "strconv"
11
+ "time"
9
12
10
13
"github.com/hashicorp/terraform-plugin-framework/attr"
14
+ "github.com/hashicorp/terraform-plugin-framework/diag"
11
15
"github.com/hashicorp/terraform-plugin-framework/path"
12
16
"github.com/hashicorp/terraform-plugin-framework/resource"
13
17
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
@@ -393,6 +397,12 @@ func (r *HypercoreVMResource) Delete(ctx context.Context, req resource.DeleteReq
393
397
394
398
restClient := * r .client
395
399
vm_uuid := data .Id .ValueString ()
400
+ err := shutdownVM (ctx , vm_uuid , & restClient )
401
+ if err != nil {
402
+ resp .Diagnostics .AddError ("Client Error" , fmt .Sprintf ("Unable to delete shutdown VM, got error: %s" , err ))
403
+ return
404
+ }
405
+
396
406
taskTag := restClient .DeleteRecord (
397
407
fmt .Sprintf ("/rest/v1/VirDomain/%s" , vm_uuid ),
398
408
- 1 ,
@@ -405,3 +415,91 @@ func (r *HypercoreVMResource) ImportState(ctx context.Context, req resource.Impo
405
415
tflog .Info (ctx , "TTRT HypercoreVMResource IMPORT_STATE" )
406
416
resource .ImportStatePassthroughID (ctx , path .Root ("id" ), req , resp )
407
417
}
418
+
419
+ func shutdownVM (ctx context.Context , vmUUID string , restClient * utils.RestClient ) diag.Diagnostic {
420
+ currentState , err := utils .GetVMPowerState (vmUUID , * restClient )
421
+ if err != nil {
422
+ return err
423
+ }
424
+ if currentState == "SHUTOFF" {
425
+ return nil
426
+ }
427
+ // VM needs to be shutdown
428
+
429
+ // VM shutdown might be already initiated, but not yet fully done.
430
+ // Send ACPI shutdown if needed.
431
+ desiredState , err := utils .GetVMDesiredState (vmUUID , * restClient )
432
+ if err != nil {
433
+ return err
434
+ }
435
+ if desiredState != "SHUTOFF" {
436
+ err = utils .ModifyVMPowerState (* restClient , vmUUID , "SHUTDOWN" , ctx )
437
+ if err != nil {
438
+ return err
439
+ }
440
+ }
441
+ var maxWaitTime time.Duration = 300
442
+ envMaxWaitTime := os .Getenv ("HC_VM_SHUTDOWN_TIMEOUT" )
443
+ if envMaxWaitTime != "" {
444
+ val , err := strconv .Atoi (envMaxWaitTime )
445
+ if err != nil {
446
+ err_msg := fmt .Sprintf ("TTRT HypercoreVMResource Destroy, environ HC_VM_SHUTDOWN_TIMEOUT=%s is not number, err=%s" , envMaxWaitTime , err )
447
+ tflog .Error (ctx , err_msg )
448
+ var diags diag.Diagnostics
449
+ diags .AddError (
450
+ "Invalid environ variable HC_VM_SHUTDOWN_TIMEOUT" ,
451
+ err_msg ,
452
+ )
453
+ return diags [0 ]
454
+ }
455
+ maxWaitTime = time .Duration (val )
456
+ }
457
+ var waitSleep time.Duration = 5
458
+ var waitTime time.Duration = 0
459
+ for {
460
+ // wait on VM to stop
461
+ currentState , err := utils .GetVMPowerState (vmUUID , * restClient )
462
+ if err != nil {
463
+ return err
464
+ }
465
+ if currentState == "SHUTOFF" {
466
+ return nil
467
+ }
468
+ if waitTime > maxWaitTime {
469
+ break
470
+ }
471
+ time .Sleep (waitSleep * time .Second )
472
+ waitTime += waitSleep
473
+ }
474
+
475
+ // force shutdown is needed
476
+ tflog .Warn (ctx , "TTRT HypercoreVMResource Destroy, VM is still running after nice ACPI shutdown, VM will be force shutoff." )
477
+ err = utils .ModifyVMPowerState (* restClient , vmUUID , "STOP" , ctx )
478
+ if err != nil {
479
+ return err
480
+ }
481
+ waitTime = 0
482
+ for {
483
+ // wait on VM to stop
484
+ currentState , err := utils .GetVMPowerState (vmUUID , * restClient )
485
+ if err != nil {
486
+ return err
487
+ }
488
+ if currentState == "SHUTOFF" {
489
+ return nil
490
+ }
491
+ if waitTime > maxWaitTime {
492
+ break
493
+ }
494
+ time .Sleep (waitSleep * time .Second )
495
+ waitTime += waitSleep
496
+ }
497
+
498
+ tflog .Error (ctx , "TTRT HypercoreVMResource Destroy, VM is still running after force shutdown" )
499
+ var diags diag.Diagnostics
500
+ diags .AddError (
501
+ "Error Shutting down VM" ,
502
+ "Unable to shutdown VM with ACPI shutdown or force shutdown." ,
503
+ )
504
+ return diags [0 ]
505
+ }
0 commit comments