@@ -630,6 +630,7 @@ func resourceEnvironmentUpdate(ctx context.Context, d *schema.ResourceData, meta
630630 var vdbs []dctapi.VDB
631631 var vdbDiags , dsourceDiags diag.Diagnostics
632632 var disableDsourceFailure bool = false
633+ rollbackActions := []func () error {}
633634 // if changedKeys contains non updatable field set a flag
634635 for _ , key := range modifiedChangedKeys {
635636 if ! updatableEnvKeys [key ] {
@@ -759,6 +760,42 @@ func resourceEnvironmentUpdate(ctx context.Context, d *schema.ResourceData, meta
759760 // return diag.Errorf("[NOT OK] Job %s %s with error %s", *res.Job.Id, job_res, job_err)
760761 }
761762 }
763+
764+ // Add rollback action for UpdateEnvironment
765+ rollbackActions = append (rollbackActions , func () error {
766+ tflog .Info (ctx , "Rolling back UpdateEnvironment" )
767+ // Capture the original value before the update
768+ oldName , _ := d .GetChange ("name" )
769+ oldClusterHome , _ := d .GetChange ("cluster_home" )
770+ oldDescription , _ := d .GetChange ("description" )
771+ // Reset parameters to their original values
772+ envUpdateParam .SetName (oldName .(string ))
773+ envUpdateParam .SetClusterHome (oldClusterHome .(string ))
774+ envUpdateParam .SetDescription (oldDescription .(string ))
775+
776+ // Execute the rollback API call
777+ res , _ , rollbackErr := client .EnvironmentsAPI .UpdateEnvironment (ctx , environmentId ).EnvironmentUpdateParameters (* envUpdateParam ).Execute ()
778+ if rollbackErr != nil {
779+ tflog .Error (ctx , "Rollback API call for UpdateEnvironment failed: " + rollbackErr .Error ())
780+ return rollbackErr
781+ }
782+
783+ // Poll the job status to ensure the rollback is complete
784+ if res != nil && res .Job != nil {
785+ jobRes , jobErr := PollJobStatus (res .Job .GetId (), ctx , client )
786+ if jobErr != "" {
787+ tflog .Error (ctx , "Rollback job polling failed for UpdateEnvironment: " + jobErr )
788+ return fmt .Errorf ("rollback job polling failed: %s" , jobErr )
789+ }
790+ if isJobTerminalFailure (jobRes ) {
791+ tflog .Error (ctx , "Rollback job failed for UpdateEnvironment: " + jobRes )
792+ return fmt .Errorf ("rollback job failed: %s" , jobRes )
793+ }
794+ tflog .Info (ctx , "Rollback job succeeded for UpdateEnvironment" )
795+ }
796+
797+ return nil
798+ })
762799 }
763800 if d .HasChanges (
764801 "username" ,
@@ -829,7 +866,109 @@ func resourceEnvironmentUpdate(ctx context.Context, d *schema.ResourceData, meta
829866 // return diag.Errorf("[NOT OK] Job %s %s with error %s", *resEnvUser.Job.Id, job_res, job_err)
830867 }
831868 }
869+ if d .HasChanges (
870+ "username" ,
871+ "password" ,
872+ ) {
873+ tflog .Info (ctx , "envUser" )
874+ // envUser Update
875+ envUserUpdateParam := dctapi .NewEnvironmentUserParams ()
876+ if d .HasChange ("username" ) || d .HasChange ("password" ) {
877+ if v , has_v := d .GetOk ("username" ); has_v {
878+ envUserUpdateParam .SetUsername (v .(string ))
879+ }
880+ if v , has_v := d .GetOk ("password" ); has_v {
881+ envUserUpdateParam .SetPassword (v .(string ))
882+ }
883+ }
884+ // get the user ref
885+ tflog .Info (ctx , "Getting the userlist" )
886+ resUserList , httpResUserList , errUserList := client .EnvironmentsAPI .ListEnvironmentUsers (ctx , environmentId ).Execute ()
887+ if diags := apiErrorResponseHelper (ctx , resUserList , httpResUserList , errUserList ); diags != nil {
888+ revertChanges (d , changedKeys )
889+ return diags
890+ }
891+
892+ var user_ref string
893+
894+ username , _ := d .GetChange ("username" )
895+ for _ , users := range resUserList .GetUsers () {
896+ tflog .Info (ctx , "Getting the users: " + users .GetUsername ())
897+ if strings .EqualFold (users .GetUsername (), username .(string )) {
898+ user_ref = users .GetUserRef ()
899+ break
900+ }
901+ }
902+ if user_ref == "" {
903+ revertChanges (d , changedKeys )
904+ return diag .Errorf ("no matching user found in the environment list to update" )
905+ }
906+
907+ // this is to propagate the value to read call which is defined at the end.
908+ // we will use the user_ref to filter from the list of users in the env
909+ tflog .Info (ctx , "Setting the user_ref: " + user_ref )
910+ d .Set ("user_ref" , user_ref )
911+
912+ tflog .Info (ctx , "Updating the user: " + user_ref )
913+ resEnvUser , httpResEnvUser , errEnvUser := client .EnvironmentsAPI .UpdateEnvironmentUser (ctx , environmentId , user_ref ).EnvironmentUserParams (* envUserUpdateParam ).Execute ()
914+ if diags := apiErrorResponseHelper (ctx , resEnvUser , httpResEnvUser , errEnvUser ); diags != nil {
915+ revertChanges (d , changedKeys )
916+ updateFailure = true
917+ if len (diags ) > 0 {
918+ failureEvents = append (failureEvents , diags [0 ].Summary )
919+ } else {
920+ tflog .Warn (ctx , "UpdateEnvironmentUser Diagnostics is empty or nil; skipping appending to failureEvents" )
921+ }
922+ }
923+
924+ if resEnvUser != nil {
925+ job_res , job_err := PollJobStatus (resEnvUser .Job .GetId (), ctx , client )
926+ if job_err != "" {
927+ tflog .Warn (ctx , DLPX + WARN + "Env User Update Job Polling failed but continuing with update. Error: " + job_err )
928+ }
929+ tflog .Info (ctx , DLPX + INFO + "Job result is " + job_res )
930+ if job_res == Failed || job_res == Canceled || job_res == Abandoned {
931+ tflog .Error (ctx , DLPX + ERROR + "Job " + job_res + " " + resEnvUser .Job .GetId ()+ "!" )
932+ revertChanges (d , changedKeys )
933+ updateFailure = true
934+ failureEvents = append (failureEvents , job_err )
935+ // return diag.Errorf("[NOT OK] Job %s %s with error %s", *resEnvUser.Job.Id, job_res, job_err)
936+ }
937+ }
938+ oldUsername , _ := d .GetChange ("username" )
939+ oldPassword , _ := d .GetChange ("password" )
940+ rollbackActions = append (rollbackActions , func () error {
941+ tflog .Info (ctx , "Rolling back UpdateEnvironmentUser" )
942+
943+ // Reset parameters to their original values
944+ envUserUpdateParam := dctapi .NewEnvironmentUserParams ()
945+ envUserUpdateParam .SetUsername (oldUsername .(string ))
946+ envUserUpdateParam .SetPassword (oldPassword .(string ))
947+
948+ // Execute the rollback API call
949+ res , _ , rollbackErr := client .EnvironmentsAPI .UpdateEnvironmentUser (ctx , environmentId , user_ref ).EnvironmentUserParams (* envUserUpdateParam ).Execute ()
950+ if rollbackErr != nil {
951+ tflog .Error (ctx , "Rollback API call for UpdateEnvironmentUser failed: " + rollbackErr .Error ())
952+ return rollbackErr
953+ }
832954
955+ // Poll the job status to ensure the rollback is complete
956+ if res != nil && res .Job != nil {
957+ jobRes , jobErr := PollJobStatus (res .Job .GetId (), ctx , client )
958+ if jobErr != "" {
959+ tflog .Error (ctx , "Rollback job polling failed for UpdateEnvironmentUser: " + jobErr )
960+ return fmt .Errorf ("rollback job polling failed: %s" , jobErr )
961+ }
962+ if isJobTerminalFailure (jobRes ) {
963+ tflog .Error (ctx , "Rollback job failed for UpdateEnvironmentUser: " + jobRes )
964+ return fmt .Errorf ("rollback job failed: %s" , jobRes )
965+ }
966+ tflog .Info (ctx , "Rollback job succeeded for UpdateEnvironmentUser" )
967+ }
968+
969+ return nil
970+ })
971+ }
833972 }
834973 if d .HasChanges (
835974 "hosts" ,
@@ -845,6 +984,10 @@ func resourceEnvironmentUpdate(ctx context.Context, d *schema.ResourceData, meta
845984 // signifies the hostname that will be updated
846985 oldHost := oldHosts .([]interface {})
847986 oldHostName := oldHost [0 ].(map [string ]interface {})["hostname" ].(string )
987+ oldSshPort := int64 (oldHost [0 ].(map [string ]interface {})["ssh_port" ].(int ))
988+ oldToolkitPath := oldHost [0 ].(map [string ]interface {})["toolkit_path" ].(string )
989+ oldJavaHome := oldHost [0 ].(map [string ]interface {})["java_home" ].(string )
990+ oldNfsAddress := oldHost [0 ].(map [string ]interface {})["nfs_addresses" ]
848991
849992 // retrieving new params for the update
850993 newHost := newHosts .([]interface {})
@@ -927,7 +1070,42 @@ func resourceEnvironmentUpdate(ctx context.Context, d *schema.ResourceData, meta
9271070 }
9281071 }
9291072 }
1073+ rollbackActions = append (rollbackActions , func () error {
1074+ tflog .Info (ctx , "Rolling back UpdateHost" )
1075+
1076+ // Reset parameters to their original values
1077+ hostUpdateParam := dctapi .NewHostUpdateParameters ()
1078+ hostUpdateParam .SetHostname (oldHostName )
1079+ hostUpdateParam .SetSshPort (oldSshPort )
1080+ hostUpdateParam .SetToolkitPath (oldToolkitPath )
1081+ hostUpdateParam .SetJavaHome (oldJavaHome )
1082+ if oldNfsAddress != nil {
1083+ hostUpdateParam .SetNfsAddresses (toStringArray (oldNfsAddress ))
1084+ }
1085+
1086+ // Execute the rollback API call
1087+ res , _ , rollbackErr := client .EnvironmentsAPI .UpdateHost (ctx , environmentId , hostId ).HostUpdateParameters (* hostUpdateParam ).Execute ()
1088+ if rollbackErr != nil {
1089+ tflog .Error (ctx , "Rollback API call for UpdateHost failed: " + rollbackErr .Error ())
1090+ return rollbackErr
1091+ }
9301092
1093+ // Poll the job status to ensure the rollback is complete
1094+ if res != nil && res .Job != nil {
1095+ jobRes , jobErr := PollJobStatus (res .Job .GetId (), ctx , client )
1096+ if jobErr != "" {
1097+ tflog .Error (ctx , "Rollback job polling failed for UpdateHost: " + jobErr )
1098+ return fmt .Errorf ("rollback job polling failed: %s" , jobErr )
1099+ }
1100+ if isJobTerminalFailure (jobRes ) {
1101+ tflog .Error (ctx , "Rollback job failed for UpdateHost: " + jobRes )
1102+ return fmt .Errorf ("rollback job failed: %s" , jobRes )
1103+ }
1104+ tflog .Info (ctx , "Rollback job succeeded for UpdateHost" )
1105+ }
1106+
1107+ return nil
1108+ })
9311109 }
9321110 if d .HasChanges (
9331111 "tags" ,
@@ -961,8 +1139,43 @@ func resourceEnvironmentUpdate(ctx context.Context, d *schema.ResourceData, meta
9611139 return diags
9621140 }
9631141 }
964- }
1142+ rollbackActions = append (rollbackActions , func () error {
1143+ tflog .Info (ctx , "Rolling back tags update" )
1144+
1145+ // Delete the new tags (if any)
1146+ if len (toTagArray (newTag )) != 0 {
1147+ tflog .Info (ctx , "Deleting new tags" )
1148+ deleteTag := * dctapi .NewDeleteTag ()
1149+ _ , rollbackErr := client .EnvironmentsAPI .DeleteEnvironmentTags (ctx , environmentId ).DeleteTag (deleteTag ).Execute ()
1150+ if rollbackErr != nil {
1151+ tflog .Error (ctx , "Rollback API call for deleting new tags failed: " + rollbackErr .Error ())
1152+ return rollbackErr
1153+ }
1154+ }
9651155
1156+ // Recreate the old tags
1157+ if len (toTagArray (oldTag )) != 0 {
1158+ tflog .Info (ctx , "Recreating old tags" )
1159+ _ , _ , rollbackErr := client .EnvironmentsAPI .CreateEnvironmentTags (ctx , environmentId ).TagsRequest (* dctapi .NewTagsRequest (toTagArray (oldTag ))).Execute ()
1160+ if rollbackErr != nil {
1161+ tflog .Error (ctx , "Rollback API call for recreating old tags failed: " + rollbackErr .Error ())
1162+ return rollbackErr
1163+ }
1164+ }
1165+
1166+ tflog .Info (ctx , "Rollback for tags update completed successfully" )
1167+ return nil
1168+ })
1169+ }
1170+ }
1171+ if updateFailure {
1172+ tflog .Error (ctx , "Update failed, rolling back changes" )
1173+ for i := len (rollbackActions ) - 1 ; i >= 0 ; i -- {
1174+ if err := rollbackActions [i ](); err != nil {
1175+ tflog .Error (ctx , "Rollback failed: " + err .Error ())
1176+ }
1177+ }
1178+ return diag .Errorf ("Update failed with errors: %v" , failureEvents )
9661179 }
9671180
9681181 if destructiveUpdate {
0 commit comments