diff --git a/CHANGELOG.md b/CHANGELOG.md index b44e2e36f..ccea6a7ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ FEATURES: BUG FIXES: - Fix a bug when `body` contains an unknown float number, the provider will crash. - Fix the crash that occurs when no tenant ID is configured in Azure CLI. +- Fix a bug that using multiple locks can result in a deadlock. ## v2.0.1 BREAKING CHANGES: diff --git a/internal/services/azapi_data_plane_resource.go b/internal/services/azapi_data_plane_resource.go index bb9bc3760..e0c770f7d 100644 --- a/internal/services/azapi_data_plane_resource.go +++ b/internal/services/azapi_data_plane_resource.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "reflect" + "slices" "time" "github.com/Azure/terraform-provider-azapi/internal/clients" @@ -419,10 +420,11 @@ func (r *DataPlaneResource) CreateUpdate(ctx context.Context, plan tfsdk.Plan, s diagnostics.AddError("Invalid body", fmt.Sprintf(`The argument "body" is invalid: %s`, err.Error())) return } - - for _, id := range AsStringList(model.Locks) { - locks.ByID(id) - defer locks.UnlockByID(id) + lockIds := AsStringList(model.Locks) + slices.Sort(lockIds) + for _, lockId := range lockIds { + locks.ByID(lockId) + defer locks.UnlockByID(lockId) } _, err = client.CreateOrUpdateThenPoll(ctx, id, body, clients.NewRequestOptions(model.CreateHeaders, model.CreateQueryParameters)) @@ -593,7 +595,9 @@ func (r *DataPlaneResource) Delete(ctx context.Context, request resource.DeleteR return } - for _, lockId := range AsStringList(model.Locks) { + lockIds := AsStringList(model.Locks) + slices.Sort(lockIds) + for _, lockId := range lockIds { locks.ByID(lockId) defer locks.UnlockByID(lockId) } diff --git a/internal/services/azapi_resource.go b/internal/services/azapi_resource.go index 850c3cfb6..cbae91bf0 100644 --- a/internal/services/azapi_resource.go +++ b/internal/services/azapi_resource.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "reflect" + "slices" "strings" "time" @@ -670,7 +671,9 @@ func (r *AzapiResource) CreateUpdate(ctx context.Context, requestPlan tfsdk.Plan } // create/update the resource - for _, lockId := range AsStringList(plan.Locks) { + lockIds := AsStringList(plan.Locks) + slices.Sort(lockIds) + for _, lockId := range lockIds { locks.ByID(lockId) defer locks.UnlockByID(lockId) } @@ -953,7 +956,9 @@ func (r *AzapiResource) Delete(ctx context.Context, request resource.DeleteReque return } - for _, lockId := range AsStringList(model.Locks) { + lockIds := AsStringList(model.Locks) + slices.Sort(lockIds) + for _, lockId := range lockIds { locks.ByID(lockId) defer locks.UnlockByID(lockId) } diff --git a/internal/services/azapi_resource_action_resource.go b/internal/services/azapi_resource_action_resource.go index 93cfd9bad..86de97f1e 100644 --- a/internal/services/azapi_resource_action_resource.go +++ b/internal/services/azapi_resource_action_resource.go @@ -3,6 +3,7 @@ package services import ( "context" "fmt" + "slices" "time" "github.com/Azure/terraform-provider-azapi/internal/clients" @@ -315,9 +316,11 @@ func (r *ActionResource) Action(ctx context.Context, model ActionResourceModel, return } - for _, id := range AsStringList(model.Locks) { - locks.ByID(id) - defer locks.UnlockByID(id) + lockIds := AsStringList(model.Locks) + slices.Sort(lockIds) + for _, lockId := range lockIds { + locks.ByID(lockId) + defer locks.UnlockByID(lockId) } var client clients.Requester diff --git a/internal/services/azapi_resource_test.go b/internal/services/azapi_resource_test.go index 647057c78..04a5050b3 100644 --- a/internal/services/azapi_resource_test.go +++ b/internal/services/azapi_resource_test.go @@ -1464,7 +1464,7 @@ resource "azapi_resource" "test2" { } } - locks = [azapi_resource.routeTable.id, azapi_resource.resourceGroup.id] + locks = [azapi_resource.resourceGroup.id, azapi_resource.routeTable.id] } `, r.template(data), data.RandomInteger, data.RandomString) } diff --git a/internal/services/azapi_update_resource.go b/internal/services/azapi_update_resource.go index dcdfd3f29..6df914c81 100644 --- a/internal/services/azapi_update_resource.go +++ b/internal/services/azapi_update_resource.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "slices" "time" "github.com/Azure/terraform-provider-azapi/internal/clients" @@ -381,9 +382,11 @@ func (r *AzapiUpdateResource) CreateUpdate(ctx context.Context, plan tfsdk.Plan, requestBody = (*id.ResourceDef).GetWriteOnly(utils.NormalizeObject(requestBody)) } - for _, id := range AsStringList(model.Locks) { - locks.ByID(id) - defer locks.UnlockByID(id) + lockIds := AsStringList(model.Locks) + slices.Sort(lockIds) + for _, lockId := range lockIds { + locks.ByID(lockId) + defer locks.UnlockByID(lockId) } _, err = client.CreateOrUpdate(ctx, id.AzureResourceId, id.ApiVersion, requestBody, clients.NewRequestOptions(model.UpdateHeaders, model.UpdateQueryParameters))