From 353d9e96d07ffd2994b6885bee5476b884390d24 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Mon, 2 Dec 2024 13:47:00 -0500 Subject: [PATCH] frontend: Add DeleteAllResources method Called when a subscription is deleted. The method is idempotent in case of multiple subscription PUT requests. --- frontend/pkg/frontend/frontend.go | 9 ++++++++ frontend/pkg/frontend/helpers.go | 37 +++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/frontend/pkg/frontend/frontend.go b/frontend/pkg/frontend/frontend.go index 8665b300a..be8e3450a 100644 --- a/frontend/pkg/frontend/frontend.go +++ b/frontend/pkg/frontend/frontend.go @@ -726,6 +726,15 @@ func (f *Frontend) ArmSubscriptionPut(writer http.ResponseWriter, request *http. "state": string(subscription.State), }) + // Clean up resources if subscription is deleted. + if subscription.State == arm.SubscriptionStateDeleted { + cloudError := f.DeleteAllResources(ctx, subscriptionID) + if cloudError != nil { + arm.WriteCloudError(writer, cloudError) + return + } + } + _, err = arm.WriteJSONResponse(writer, http.StatusOK, subscription) if err != nil { f.logger.Error(err.Error()) diff --git a/frontend/pkg/frontend/helpers.go b/frontend/pkg/frontend/helpers.go index 90d280862..dfbe73635 100644 --- a/frontend/pkg/frontend/helpers.go +++ b/frontend/pkg/frontend/helpers.go @@ -70,6 +70,43 @@ func (f *Frontend) CheckForProvisioningStateConflict(ctx context.Context, operat return nil } +func (f *Frontend) DeleteAllResources(ctx context.Context, subscriptionID string) *arm.CloudError { + prefix, err := arm.ParseResourceID("/subscriptions/" + subscriptionID) + if err != nil { + f.logger.Error(err.Error()) + return arm.NewInternalServerError() + } + + dbIterator := f.dbClient.ListResourceDocs(ctx, prefix, -1, nil) + + // Start a deletion operation for all clusters under the subscription. + // Cluster Service will delete all node pools belonging to these clusters + // so we don't need to explicitly delete node pools here. + for item := range dbIterator.Items(ctx) { + var resourceDoc *database.ResourceDocument + + err = json.Unmarshal(item, &resourceDoc) + if err != nil { + f.logger.Error(err.Error()) + return arm.NewInternalServerError() + } + + if !strings.EqualFold(resourceDoc.Key.ResourceType.String(), api.ClusterResourceType.String()) { + continue + } + + // Allow this method to be idempotent. + if resourceDoc.ProvisioningState != arm.ProvisioningStateDeleting { + _, cloudError := f.DeleteResource(ctx, resourceDoc) + if cloudError != nil { + return cloudError + } + } + } + + return nil +} + func (f *Frontend) DeleteResource(ctx context.Context, resourceDoc *database.ResourceDocument) (string, *arm.CloudError) { const operationRequest = database.OperationRequestDelete var err error