From df7adf02649c911483742cd43654d17a4930c031 Mon Sep 17 00:00:00 2001 From: Cecile Robert-Michon Date: Tue, 19 Apr 2022 09:41:29 -0700 Subject: [PATCH] Delete long running operation state when resource is not found --- azure/services/async/async.go | 5 ++++- azure/services/async/async_test.go | 27 ++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/azure/services/async/async.go b/azure/services/async/async.go index a5c82043218..93d10100114 100644 --- a/azure/services/async/async.go +++ b/azure/services/async/async.go @@ -79,7 +79,10 @@ func processOngoingOperation(ctx context.Context, scope FutureScope, client Futu // Resource has been created/deleted/updated. log.V(2).Info("long running operation has completed", "service", serviceName, "resource", resourceName) result, err = client.Result(ctx, sdkFuture, future.Type) - if err == nil { + if err == nil || azure.ResourceNotFound(err) { + // Once we have the result, we can delete the long running operation state. + // If the resource is not found, we also reset the long-running operation state so we can attempt to create it again. + // This can happen if the resource was deleted by another process before we could get the result. scope.DeleteLongRunningOperationState(resourceName, serviceName) } return result, err diff --git a/azure/services/async/async_test.go b/azure/services/async/async_test.go index 87b26fadb30..883558353ec 100644 --- a/azure/services/async/async_test.go +++ b/azure/services/async/async_test.go @@ -120,8 +120,33 @@ func TestProcessOngoingOperation(t *testing.T) { expect: func(s *mock_async.MockFutureScopeMockRecorder, c *mock_async.MockFutureHandlerMockRecorder) { s.GetLongRunningOperationState("test-resource", "test-service").Return(&validDeleteFuture) c.IsDone(gomockinternal.AContext(), gomock.AssignableToTypeOf(&azureautorest.Future{})).Return(true, nil) - s.DeleteLongRunningOperationState("test-resource", "test-service") c.Result(gomockinternal.AContext(), gomock.AssignableToTypeOf(&azureautorest.Future{}), infrav1.DeleteFuture).Return(&fakeExistingResource, nil) + s.DeleteLongRunningOperationState("test-resource", "test-service") + }, + }, + { + name: "resource was deleted by an external process", + expectedError: fakeNotFoundError.Error(), + expectedResult: nil, + resourceName: "test-resource", + serviceName: "test-service", + expect: func(s *mock_async.MockFutureScopeMockRecorder, c *mock_async.MockFutureHandlerMockRecorder) { + s.GetLongRunningOperationState("test-resource", "test-service").Return(&validDeleteFuture) + c.IsDone(gomockinternal.AContext(), gomock.AssignableToTypeOf(&azureautorest.Future{})).Return(true, nil) + c.Result(gomockinternal.AContext(), gomock.AssignableToTypeOf(&azureautorest.Future{}), infrav1.DeleteFuture).Return(nil, fakeNotFoundError) + s.DeleteLongRunningOperationState("test-resource", "test-service") + }, + }, + { + name: "failed to get resulting resource", + expectedError: fakeInternalError.Error(), + expectedResult: nil, + resourceName: "test-resource", + serviceName: "test-service", + expect: func(s *mock_async.MockFutureScopeMockRecorder, c *mock_async.MockFutureHandlerMockRecorder) { + s.GetLongRunningOperationState("test-resource", "test-service").Return(&validDeleteFuture) + c.IsDone(gomockinternal.AContext(), gomock.AssignableToTypeOf(&azureautorest.Future{})).Return(true, nil) + c.Result(gomockinternal.AContext(), gomock.AssignableToTypeOf(&azureautorest.Future{}), infrav1.DeleteFuture).Return(nil, fakeInternalError) }, }, }