Skip to content

Commit f2f8c4c

Browse files
author
Uddipaan Hazarika
committed
added rollback stack
1 parent e130268 commit f2f8c4c

File tree

1 file changed

+214
-1
lines changed

1 file changed

+214
-1
lines changed

internal/provider/resource_environment.go

Lines changed: 214 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)