@@ -45,6 +45,8 @@ const (
4545
4646 // DONE represents the done status for a compute service operation.
4747 DONE = "DONE"
48+
49+ alreadyInUseStr = "is already being used by "
4850)
4951
5052// ClusterUninstaller holds the various options for the cluster we want to delete
@@ -441,6 +443,72 @@ func operationErrorMessage(op *compute.Operation) string {
441443 return strings .Join (errs , ", " )
442444}
443445
446+ func (o * ClusterUninstaller ) handleDependentResourceError (ctx context.Context , op * compute.Operation , err error ) error {
447+ errorCode := 0
448+ errMsg := ""
449+ switch {
450+ case op != nil :
451+ errorCode = int (op .HttpErrorStatusCode )
452+ errMsg = operationErrorMessage (op )
453+ case err != nil :
454+ var apiErr * googleapi.Error
455+ if errors .As (err , & apiErr ) {
456+ errorCode = apiErr .Code
457+ errMsg = apiErr .Message
458+ } else {
459+ errMsg = err .Error ()
460+ }
461+ default :
462+ return fmt .Errorf ("failed to extract information from operation or error" )
463+ }
464+
465+ if errorCode == 400 && strings .Contains (errMsg , alreadyInUseStr ) {
466+ splitDetails := strings .Split (errMsg , alreadyInUseStr )
467+ resource := strings .ReplaceAll (
468+ strings .ReplaceAll (
469+ strings .ReplaceAll (splitDetails [len (splitDetails )- 1 ], "\" " , "" ),
470+ "'" , "" ,
471+ ), ", resourceInUseByAnotherResource" , "" ,
472+ )
473+ splitResource := strings .Split (resource , "/" )
474+
475+ if len (splitResource ) > 6 || len (splitResource ) < 5 {
476+ return fmt .Errorf ("dependent resource information unable to be parsed: %s" , resource )
477+ }
478+ // global -> ex: projects/xxxxxxxxxxxxxxxx/global/resource-type/resource-name
479+ // regional -> ex: projects/xxxxxxxxxxxxxx/region/region-name/resource-type/resource-name
480+ location , resourceType , resourceName := splitResource [len (splitResource )- 3 ], splitResource [len (splitResource )- 2 ], splitResource [len (splitResource )- 1 ]
481+ o .Logger .Debugf ("found dependent resource information: %s, %s, %s" , location , resourceType , resourceName )
482+
483+ var deleteErr error
484+ switch resourceType {
485+ case "backendServices" :
486+ deleteErr = o .deleteBackendServiceByName (ctx , resourceName , location )
487+ case "firewalls" :
488+ deleteErr = o .deleteFirewallByName (ctx , resourceName )
489+ case "forwardingRules" :
490+ deleteErr = o .deleteForwardingRuleByName (ctx , resourceName , location )
491+ case "subnetworks" :
492+ deleteErr = o .deleteSubnetworkByName (ctx , resourceName )
493+ case "routers" :
494+ deleteErr = o .deleteRouterByName (ctx , resourceName )
495+ case "addresses" :
496+ deleteErr = o .deleteAddressByName (ctx , resourceName , location )
497+ case "targetPools" :
498+ deleteErr = o .deleteTargetPoolByName (ctx , resourceName )
499+ case "targetTcpProxies" :
500+ deleteErr = o .deleteTargetTCPProxyByName (ctx , resourceName )
501+ default :
502+ deleteErr = fmt .Errorf ("failed to find resource type: %s for %s" , resourceType , resourceName )
503+ }
504+
505+ if deleteErr != nil {
506+ return fmt .Errorf ("failed to delete dependent resource: %w" , deleteErr )
507+ }
508+ }
509+ return nil
510+ }
511+
444512func (o * ClusterUninstaller ) handleOperation (ctx context.Context , op * compute.Operation , err error , item cloudResource , resourceType string ) error {
445513 identifier := []string {item .typeName , item .name }
446514 if item .zone != "" {
@@ -452,14 +520,22 @@ func (o *ClusterUninstaller) handleOperation(ctx context.Context, op *compute.Op
452520 o .Logger .Debugf ("No operation found for %s %s" , resourceType , item .name )
453521 return nil
454522 }
523+
524+ err = o .handleDependentResourceError (ctx , op , err )
525+ if err != nil {
526+ o .Logger .Debugf ("failed to handle dependent resource error: %v" , err )
527+ }
455528 o .resetRequestID (identifier ... )
456529 return fmt .Errorf ("failed to delete %s %s: %w" , resourceType , item .name , err )
457530 }
458531
459532 // wait for operation to complete before checking any further
460533 op , err = o .waitFor (ctx , op , item )
461-
462534 if op != nil && op .Status == DONE && isErrorStatus (op .HttpErrorStatusCode ) {
535+ err = o .handleDependentResourceError (ctx , op , err )
536+ if err != nil {
537+ o .Logger .Debugf ("failed to handle dependent resource error: %v" , err )
538+ }
463539 o .resetRequestID (identifier ... )
464540 return fmt .Errorf ("failed to delete %s %s with error: %s" , resourceType , item .name , operationErrorMessage (op ))
465541 }
0 commit comments