Skip to content

Commit 631c430

Browse files
committed
OCPBUGS-90710: Destroy all private cluster backend service resources
When a private cluster was created, the destroy process would not find and destroy backend services. This was happening specifically when no backends were created/found. Enhanced backend service discovery to check firewall rules for cluster ID tags when backends are empty. This allows proper identification of orphaned backend services that should be deleted during cluster destroy. Also added global health check discovery to ensure all related resources are properly cleaned up.
1 parent 5a9a61b commit 631c430

1 file changed

Lines changed: 74 additions & 1 deletion

File tree

pkg/destroy/gcp/cloudcontroller.go

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ package gcp
33
import (
44
"context"
55
"fmt"
6+
"strings"
67

78
compute "google.golang.org/api/compute/v1"
9+
"google.golang.org/api/googleapi"
810
"k8s.io/apimachinery/pkg/util/sets"
11+
12+
"github.com/openshift/installer/pkg/types/gcp"
913
)
1014

1115
// listCloudControllerInstanceGroups returns instance groups created by the cloud controller.
@@ -21,12 +25,81 @@ func (o *ClusterUninstaller) listCloudControllerInstanceGroups(ctx context.Conte
2125
// It list all backend services matching the cloud controller name convention that contain
2226
// only cluster instance groups.
2327
func (o *ClusterUninstaller) listCloudControllerBackendServices(ctx context.Context, instanceGroups []cloudResource) ([]cloudResource, error) {
28+
o.Logger.Debugf("Listing cloud controller backend services")
2429
urls := sets.Set[string]{}
2530
for _, instanceGroup := range instanceGroups {
2631
urls.Insert(instanceGroup.url)
2732
}
33+
2834
filter := "name eq \"a[0-9a-f]{30,50}\""
29-
return o.listBackendServicesWithFilter(ctx, regionBackendServiceResource, "items(name,backends),nextPageToken", filter, urls)
35+
result := []cloudResource{}
36+
37+
// Fetch firewall rules once (fully paginated); used to validate backend
38+
// services that have no backends.
39+
var firewalls []*compute.Firewall
40+
if err := o.computeSvc.Firewalls.List(o.ProjectID).
41+
Fields(googleapi.Field("items(name,targetTags),nextPageToken")).
42+
Pages(ctx, func(list *compute.FirewallList) error {
43+
firewalls = append(firewalls, list.Items...)
44+
return nil
45+
}); err != nil {
46+
return nil, err
47+
}
48+
49+
req := o.computeSvc.RegionBackendServices.List(o.ProjectID, o.Region).Fields(googleapi.Field("items(name,backends),nextPageToken")).Filter(filter)
50+
err := req.Pages(ctx, func(list *compute.BackendServiceList) error {
51+
for _, item := range list.Items {
52+
if len(item.Backends) == 0 {
53+
o.Logger.Debugf("Backend service %s has no backends, checking firewall rules for cluster ID", item.Name)
54+
found := false
55+
for _, fw := range firewalls {
56+
if strings.Contains(fw.Name, item.Name) {
57+
for _, tag := range fw.TargetTags {
58+
if strings.Contains(tag, o.ClusterID) {
59+
found = true
60+
break
61+
}
62+
}
63+
}
64+
if found {
65+
break
66+
}
67+
}
68+
if !found {
69+
continue
70+
}
71+
} else {
72+
allBackendsMatch := true
73+
for _, backend := range item.Backends {
74+
if !urls.Has(backend.Group) {
75+
allBackendsMatch = false
76+
break
77+
}
78+
}
79+
if !allBackendsMatch {
80+
continue
81+
}
82+
}
83+
o.Logger.Debugf("Found backend service: %s", item.Name)
84+
result = append(result, cloudResource{
85+
key: item.Name,
86+
name: item.Name,
87+
typeName: regionBackendServiceResource,
88+
quota: []gcp.QuotaUsage{{
89+
Metric: &gcp.Metric{
90+
Service: gcp.ServiceComputeEngineAPI,
91+
Limit: "backend_services",
92+
},
93+
Amount: 1,
94+
}},
95+
})
96+
}
97+
return nil
98+
})
99+
if err != nil {
100+
return nil, err
101+
}
102+
return result, nil
30103
}
31104

32105
// listCloudControllerTargetPools returns target pools created by the cloud controller or owned by the cloud controller.

0 commit comments

Comments
 (0)