@@ -1392,29 +1392,18 @@ func ResourceNutanixVirtualMachineV2Create(ctx context.Context, d *schema.Resour
13921392 }
13931393 d .SetId (utils .StringValue (uuid ))
13941394
1395- // read VM
1396-
1397- readResp , errR := conn .VMAPIInstance .GetVmById (utils .StringPtr (* uuid ))
1398- if errR != nil {
1399- return diag .Errorf ("error while reading vm : %v" , errR )
1400- }
1401- args := make (map [string ]interface {})
1402- args ["If-Match" ] = getEtagHeader (readResp , conn )
1403-
14041395 var PowerTaskRef import1.TaskReference
14051396 if powerState , ok := d .GetOk ("power_state" ); ok {
1406- if powerState == "ON" {
1407- resp , err := conn .VMAPIInstance .PowerOnVm (uuid , args )
1408- if err != nil {
1409- return diag .Errorf ("error while powering on Virtual Machines : %v" , err )
1410- }
1411- PowerTaskRef = resp .Data .GetValue ().(import1.TaskReference )
1412- } else if powerState == "OFF" {
1413- resp , err := conn .VMAPIInstance .PowerOffVm (utils .StringPtr (d .Id ()), args )
1414- if err != nil {
1415- return diag .Errorf ("error while powering OFF : %v" , err )
1416- }
1417- PowerTaskRef = resp .Data .GetValue ().(import1.TaskReference )
1397+ switch powerState {
1398+ case "ON" :
1399+ PowerTaskRef , err = powerOnVMWithRetry (ctx , conn , utils .StringPtr (d .Id ()))
1400+ case "OFF" :
1401+ PowerTaskRef , err = powerOffVMWithRetry (ctx , conn , utils .StringPtr (d .Id ()))
1402+ default :
1403+ return diag .Errorf ("invalid power state: %s" , powerState )
1404+ }
1405+ if err != nil {
1406+ return diag .Errorf ("error while powering %s Virtual Machines: %v" , powerState , err )
14181407 }
14191408 }
14201409 powertaskUUID := PowerTaskRef .ExtId
@@ -3175,6 +3164,121 @@ func expandPolicyReference(pr interface{}) *config.PolicyReference {
31753164 return nil
31763165}
31773166
3167+ // extractTaskReferenceFromResponse extracts TaskReference from API response using reflection
3168+ func extractTaskReferenceFromResponse (resp interface {}) (import1.TaskReference , error ) {
3169+ respValue := reflect .ValueOf (resp )
3170+ if respValue .Kind () == reflect .Ptr {
3171+ respValue = respValue .Elem ()
3172+ }
3173+ dataField := respValue .FieldByName ("Data" )
3174+ if ! dataField .IsValid () {
3175+ return import1.TaskReference {}, fmt .Errorf ("unexpected response structure: Data field not found" )
3176+ }
3177+ getValueMethod := dataField .MethodByName ("GetValue" )
3178+ if ! getValueMethod .IsValid () {
3179+ return import1.TaskReference {}, fmt .Errorf ("unexpected response structure: GetValue method not found" )
3180+ }
3181+ result := getValueMethod .Call (nil )[0 ].Interface ()
3182+ taskRef , ok := result .(import1.TaskReference )
3183+ if ! ok {
3184+ return import1.TaskReference {}, fmt .Errorf ("unexpected response type: expected TaskReference" )
3185+ }
3186+ return taskRef , nil
3187+ }
3188+
3189+ // powerOnVMWithRetry attempts to power on a VM with retry logic
3190+ // It fetches the VM and ETag header for each retry attempt to ensure we have the latest ETag
3191+ func powerOnVMWithRetry (ctx context.Context , conn * vmm.Client , vmID * string ) (import1.TaskReference , error ) {
3192+ maxRetries := 10
3193+ retryDelay := 2500 * time .Millisecond // 2.5 seconds
3194+ var resp interface {}
3195+ var err error
3196+
3197+ for attempt := 0 ; attempt < maxRetries ; attempt ++ {
3198+ // Fetch VM to get latest ETag for each retry attempt
3199+ readResp , errR := conn .VMAPIInstance .GetVmById (vmID )
3200+ if errR != nil {
3201+ return import1.TaskReference {}, fmt .Errorf ("error while fetching vm : %v" , errR )
3202+ }
3203+
3204+ // Build args with fresh ETag for this attempt
3205+ args := make (map [string ]interface {})
3206+ args ["If-Match" ] = getEtagHeader (readResp , conn )
3207+
3208+ resp , err = conn .VMAPIInstance .PowerOnVm (vmID , args )
3209+ if err == nil {
3210+ break
3211+ }
3212+
3213+ if attempt < maxRetries {
3214+ log .Printf ("[DEBUG] Attempt %d/%d failed to power on VM, retrying in %v: %v" , attempt + 1 , maxRetries , retryDelay , err )
3215+ select {
3216+ case <- ctx .Done ():
3217+ return import1.TaskReference {}, fmt .Errorf ("context cancelled while powering on VM: %v" , ctx .Err ())
3218+ case <- time .After (retryDelay ):
3219+ // Continue to next retry
3220+ }
3221+ }
3222+ }
3223+
3224+ if err != nil {
3225+ return import1.TaskReference {}, fmt .Errorf ("error while powering on Virtual Machine after %d attempts: %v" , maxRetries , err )
3226+ }
3227+
3228+ taskRef , err := extractTaskReferenceFromResponse (resp )
3229+ if err != nil {
3230+ return import1.TaskReference {}, fmt .Errorf ("error extracting task reference from power on response: %v" , err )
3231+ }
3232+ log .Printf ("[DEBUG] PowerOn Response: TaskReference ExtId: %s" , utils .StringValue (taskRef .ExtId ))
3233+ return taskRef , nil
3234+ }
3235+
3236+ // powerOffVMWithRetry attempts to power off a VM with retry logic
3237+ // It fetches the VM and ETag header for each retry attempt to ensure we have the latest ETag
3238+ func powerOffVMWithRetry (ctx context.Context , conn * vmm.Client , vmID * string ) (import1.TaskReference , error ) {
3239+ maxRetries := 10
3240+ retryDelay := 2500 * time .Millisecond // 2.5 seconds
3241+ var resp interface {}
3242+ var err error
3243+
3244+ for attempt := 0 ; attempt < maxRetries ; attempt ++ {
3245+ // Fetch VM to get latest ETag for each retry attempt
3246+ readResp , errR := conn .VMAPIInstance .GetVmById (vmID )
3247+ if errR != nil {
3248+ return import1.TaskReference {}, fmt .Errorf ("error while fetching vm : %v" , errR )
3249+ }
3250+
3251+ // Build args with fresh ETag for this attempt
3252+ args := make (map [string ]interface {})
3253+ args ["If-Match" ] = getEtagHeader (readResp , conn )
3254+
3255+ resp , err = conn .VMAPIInstance .PowerOffVm (vmID , args )
3256+ if err == nil {
3257+ break
3258+ }
3259+
3260+ if attempt < maxRetries {
3261+ log .Printf ("[DEBUG] Attempt %d/%d failed to power off VM, retrying in %v: %v" , attempt + 1 , maxRetries , retryDelay , err )
3262+ select {
3263+ case <- ctx .Done ():
3264+ return import1.TaskReference {}, fmt .Errorf ("context cancelled while powering off VM: %v" , ctx .Err ())
3265+ case <- time .After (retryDelay ):
3266+ // Continue to next retry
3267+ }
3268+ }
3269+ }
3270+
3271+ if err != nil {
3272+ return import1.TaskReference {}, fmt .Errorf ("error while powering off Virtual Machine after %d attempts: %v" , maxRetries , err )
3273+ }
3274+ taskRef , err := extractTaskReferenceFromResponse (resp )
3275+ if err != nil {
3276+ return import1.TaskReference {}, fmt .Errorf ("error extracting task reference from power off response: %v" , err )
3277+ }
3278+ log .Printf ("[DEBUG] PowerOff Response: TaskReference ExtId: %s" , utils .StringValue (taskRef .ExtId ))
3279+ return taskRef , nil
3280+ }
3281+
31783282func flattenPowerState (pr * config.PowerState ) string {
31793283 if pr != nil {
31803284 const two , three , four , five = 2 , 3 , 4 , 5
@@ -3207,17 +3311,11 @@ func callForPowerOffVM(ctx context.Context, conn *vmm.Client, d *schema.Resource
32073311 return nil
32083312 }
32093313
3210- // Extract E-Tag Header
3211- args := make (map [string ]interface {})
3212- args ["If-Match" ] = getEtagHeader (readResp , conn )
3213-
3214- // Power off the VM
3215- powerOffResp , err := conn .VMAPIInstance .PowerOffVm (utils .StringPtr (d .Id ()), args )
3314+ // Power off the VM with retry logic (ETag is fetched inside the retry function)
3315+ TaskRef , err := powerOffVMWithRetry (ctx , conn , utils .StringPtr (d .Id ()))
32163316 if err != nil {
3217- return diag .Errorf ("error while powering off Virtual Machine : %v" , err )
3317+ return diag .Errorf ("error while powering off Virtual Machine: %v" , err )
32183318 }
3219-
3220- TaskRef := powerOffResp .Data .GetValue ().(import1.TaskReference )
32213319 taskUUID := TaskRef .ExtId
32223320
32233321 prismConn := meta .(* conns.Client ).PrismAPI
@@ -3249,19 +3347,13 @@ func callForPowerOnVM(ctx context.Context, conn *vmm.Client, d *schema.ResourceD
32493347 return nil
32503348 }
32513349
3252- // Extract E-Tag Header
3253- args := make (map [string ]interface {})
3254- args ["If-Match" ] = getEtagHeader (readResp , conn )
3255- // Power on the VM
3256- powerOnResp , err := conn .VMAPIInstance .PowerOnVm (utils .StringPtr (d .Id ()), args )
3350+ // Power on the VM with retry logic (ETag is fetched inside the retry function)
3351+ TaskRef , err := powerOnVMWithRetry (ctx , conn , utils .StringPtr (d .Id ()))
32573352 if err != nil {
3258- return diag .Errorf ("error while powering on Virtual Machine : %v" , err )
3353+ return diag .Errorf ("error while powering on Virtual Machine: %v" , err )
32593354 }
32603355
3261- aJSON , _ := json .Marshal (powerOnResp )
3262- log .Printf ("[DEBUG] PowerOn Response: %s" , string (aJSON ))
3263-
3264- TaskRef := powerOnResp .Data .GetValue ().(import1.TaskReference )
3356+ log .Printf ("[DEBUG] PowerOn Response: TaskReference ExtId: %s" , utils .StringValue (TaskRef .ExtId ))
32653357 taskUUID := TaskRef .ExtId
32663358
32673359 prismConn := meta .(* conns.Client ).PrismAPI
0 commit comments