Skip to content

Commit

Permalink
frontend: Unify delete handlers for clusters and node pools
Browse files Browse the repository at this point in the history
With the DeleteResource method, the logic flow for handling DELETE
requests for clusters and node pools is now identical.
  • Loading branch information
Matthew Barnes committed Oct 29, 2024
1 parent 71af702 commit 699de65
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 108 deletions.
29 changes: 15 additions & 14 deletions frontend/pkg/frontend/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -561,13 +561,14 @@ func (f *Frontend) ArmResourceDelete(writer http.ResponseWriter, request *http.R

f.logger.Info(fmt.Sprintf("%s: ArmResourceDelete", versionedInterface))

doc, err := f.dbClient.GetResourceDoc(ctx, resourceID)
if err != nil {
if errors.Is(err, database.ErrNotFound) {
resourceDoc, cloudError := f.DeleteResource(ctx, resourceID)
if cloudError != nil {
// For resource not found errors on deletion, ARM requires
// us to simply return 204 No Content and no response body.
if cloudError.StatusCode == http.StatusNotFound {
writer.WriteHeader(http.StatusNoContent)
} else {
f.logger.Error(err.Error())
arm.WriteInternalServerError(writer)
arm.WriteCloudError(writer, cloudError)
}
return
}
Expand All @@ -576,22 +577,22 @@ func (f *Frontend) ArmResourceDelete(writer http.ResponseWriter, request *http.R

// CheckForProvisioningStateConflict does not log conflict errors
// but does log unexpected errors like database failures.
cloudError := f.CheckForProvisioningStateConflict(ctx, operationRequest, doc)
cloudError = f.CheckForProvisioningStateConflict(ctx, operationRequest, resourceDoc)
if cloudError != nil {
arm.WriteCloudError(writer, cloudError)
return
}

err = f.clusterServiceClient.DeleteCSCluster(ctx, doc.InternalID)
err = f.clusterServiceClient.DeleteCSCluster(ctx, resourceDoc.InternalID)
if err != nil {
f.logger.Error(fmt.Sprintf("failed to delete cluster %s: %v", resourceID, err))
arm.WriteInternalServerError(writer)
return
}

// Deletion is underway; mark any active operation as canceled.
if doc.ActiveOperationID != "" {
updated, err := f.dbClient.UpdateOperationDoc(ctx, doc.ActiveOperationID, func(updateDoc *database.OperationDocument) bool {
if resourceDoc.ActiveOperationID != "" {
updated, err := f.dbClient.UpdateOperationDoc(ctx, resourceDoc.ActiveOperationID, func(updateDoc *database.OperationDocument) bool {
if updateDoc.Status != arm.ProvisioningStateCanceled {
updateDoc.LastTransitionTime = time.Now()
updateDoc.Status = arm.ProvisioningStateCanceled
Expand All @@ -605,20 +606,20 @@ func (f *Frontend) ArmResourceDelete(writer http.ResponseWriter, request *http.R
return
}
if updated {
f.logger.Info(fmt.Sprintf("canceled operation '%s'", doc.ActiveOperationID))
f.logger.Info(fmt.Sprintf("canceled operation '%s'", resourceDoc.ActiveOperationID))
}
}

operationDoc, err := f.StartOperation(writer, request, doc, operationRequest)
operationDoc, err := f.StartOperation(writer, request, resourceDoc, operationRequest)
if err != nil {
f.logger.Error(fmt.Sprintf("failed to write operation document: %v", err))
arm.WriteInternalServerError(writer)
return
}

updated, err := f.dbClient.UpdateResourceDoc(ctx, resourceID, func(doc *database.ResourceDocument) bool {
doc.ActiveOperationID = operationDoc.ID
doc.ProvisioningState = operationDoc.Status
updated, err := f.dbClient.UpdateResourceDoc(ctx, resourceID, func(updateDoc *database.ResourceDocument) bool {
updateDoc.ActiveOperationID = operationDoc.ID
updateDoc.ProvisioningState = operationDoc.Status
return true
})
if err != nil {
Expand Down
93 changes: 0 additions & 93 deletions frontend/pkg/frontend/node_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"fmt"
"maps"
"net/http"
"time"

cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"

Expand Down Expand Up @@ -260,98 +259,6 @@ func (f *Frontend) CreateOrUpdateNodePool(writer http.ResponseWriter, request *h
}
}

func (f *Frontend) DeleteNodePool(writer http.ResponseWriter, request *http.Request) {
ctx := request.Context()

versionedInterface, err := VersionFromContext(ctx)
if err != nil {
f.logger.Error(err.Error())
arm.WriteInternalServerError(writer)
return
}

resourceID, err := ResourceIDFromContext(ctx)
if err != nil {
f.logger.Error(err.Error())
arm.WriteInternalServerError(writer)
return
}

f.logger.Info(fmt.Sprintf("%s: DeleteNodePool", versionedInterface))

doc, err := f.dbClient.GetResourceDoc(ctx, resourceID)
if err != nil {
if errors.Is(err, database.ErrNotFound) {
writer.WriteHeader(http.StatusNoContent)
} else {
f.logger.Error(err.Error())
arm.WriteInternalServerError(writer)
}
return
}

operationRequest := database.OperationRequestDelete

// CheckForProvisioningStateConflict does not log conflict errors
// but does log unexpected errors like database failures.
cloudError := f.CheckForProvisioningStateConflict(ctx, operationRequest, doc)
if cloudError != nil {
arm.WriteCloudError(writer, cloudError)
return
}

err = f.clusterServiceClient.DeleteCSNodePool(ctx, doc.InternalID)
if err != nil {
f.logger.Error(fmt.Sprintf("failed to delete node pool %s: %v", resourceID, err))
arm.WriteInternalServerError(writer)
return
}

// Deletion is underway; mark any active operation as canceled.
if doc.ActiveOperationID != "" {
updated, err := f.dbClient.UpdateOperationDoc(ctx, doc.ActiveOperationID, func(updateDoc *database.OperationDocument) bool {
if updateDoc.Status != arm.ProvisioningStateCanceled {
updateDoc.LastTransitionTime = time.Now()
updateDoc.Status = arm.ProvisioningStateCanceled
return true
}
return false
})
if err != nil {
f.logger.Error(err.Error())
arm.WriteInternalServerError(writer)
return
}
if updated {
f.logger.Info(fmt.Sprintf("canceled operation '%s'", doc.ActiveOperationID))
}
}

operationDoc, err := f.StartOperation(writer, request, doc, operationRequest)
if err != nil {
f.logger.Error(fmt.Sprintf("failed to write operation document: %v", err))
arm.WriteInternalServerError(writer)
return
}

updated, err := f.dbClient.UpdateResourceDoc(ctx, resourceID, func(doc *database.ResourceDocument) bool {
doc.ActiveOperationID = operationDoc.ID
doc.ProvisioningState = operationDoc.Status
return true
})
if err != nil {
f.logger.Error(err.Error())
arm.WriteInternalServerError(writer)
return
}
if updated {
f.logger.Info(fmt.Sprintf("document updated for %s", resourceID))
}

writer.WriteHeader(http.StatusAccepted)
}

// marshalCSNodePool renders a CS NodePool object in JSON format, applying
// the necessary conversions for the API version of the request.
func marshalCSNodePool(csNodePool *cmv1.NodePool, doc *database.ResourceDocument, versionedInterface api.Version) ([]byte, error) {
hcpNodePool := ConvertCStoNodePool(doc.Key, csNodePool)
Expand Down
2 changes: 1 addition & 1 deletion frontend/pkg/frontend/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func (f *Frontend) routes() *MiddlewareMux {
postMuxMiddleware.HandlerFunc(f.CreateOrUpdateNodePool))
mux.Handle(
MuxPattern(http.MethodDelete, PatternSubscriptions, PatternResourceGroups, PatternProviders, PatternClusters, PatternNodePools),
postMuxMiddleware.HandlerFunc(f.DeleteNodePool))
postMuxMiddleware.HandlerFunc(f.ArmResourceDelete))

// Operation endpoints
postMuxMiddleware = NewMiddleware(
Expand Down

0 comments on commit 699de65

Please sign in to comment.