Skip to content

Commit 3f26489

Browse files
committed
CORS-3256: GCP destroy updates for CAPG
** Delete global scoped resources that are created during CAPG installs. ** Update: Delete Global Resources for BackEnd services and forwarding rules ** Update: Firewall Rule filter using regular expressions
1 parent 42a1e5e commit 3f26489

File tree

5 files changed

+175
-89
lines changed

5 files changed

+175
-89
lines changed

pkg/destroy/gcp/backendservice.go

Lines changed: 73 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,69 +2,100 @@ package gcp
22

33
import (
44
"context"
5+
"fmt"
56

6-
"github.com/pkg/errors"
7+
"github.com/sirupsen/logrus"
78
"google.golang.org/api/compute/v1"
89
"google.golang.org/api/googleapi"
910

1011
"github.com/openshift/installer/pkg/types/gcp"
1112
)
1213

13-
func (o *ClusterUninstaller) listBackendServices(ctx context.Context) ([]cloudResource, error) {
14-
return o.listBackendServicesWithFilter(ctx, "items(name),nextPageToken", o.clusterIDFilter(), nil)
14+
func (o *ClusterUninstaller) listBackendServices(ctx context.Context, scope resourceScope) ([]cloudResource, error) {
15+
return o.listBackendServicesWithFilter(ctx, "items(name),nextPageToken", o.clusterIDFilter(), nil, scope)
16+
}
17+
18+
func createBackendServiceCloudResources(filterFunc func(*compute.BackendService) bool, list *compute.BackendServiceList) []cloudResource {
19+
result := []cloudResource{}
20+
21+
for _, item := range list.Items {
22+
if filterFunc == nil || filterFunc(item) {
23+
logrus.Debugf("Found backend service: %s", item.Name)
24+
result = append(result, cloudResource{
25+
key: item.Name,
26+
name: item.Name,
27+
typeName: "backendservice",
28+
quota: []gcp.QuotaUsage{{
29+
Metric: &gcp.Metric{
30+
Service: gcp.ServiceComputeEngineAPI,
31+
Limit: "backend_services",
32+
},
33+
Amount: 1,
34+
}},
35+
})
36+
}
37+
}
38+
39+
return result
1540
}
1641

1742
// listBackendServicesWithFilter lists backend services in the project that satisfy the filter criteria.
1843
// The fields parameter specifies which fields should be returned in the result, the filter string contains
1944
// a filter string passed to the API to filter results. The filterFunc is a client-side filtering function
2045
// that determines whether a particular result should be returned or not.
21-
func (o *ClusterUninstaller) listBackendServicesWithFilter(ctx context.Context, fields string, filter string, filterFunc func(*compute.BackendService) bool) ([]cloudResource, error) {
22-
o.Logger.Debugf("Listing backend services")
46+
func (o *ClusterUninstaller) listBackendServicesWithFilter(ctx context.Context, fields string, filter string, filterFunc func(*compute.BackendService) bool, scope resourceScope) ([]cloudResource, error) {
47+
o.Logger.Debugf("Listing %s backend services", scope)
2348
ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
2449
defer cancel()
2550
result := []cloudResource{}
51+
52+
if scope == gcpGlobalResource {
53+
req := o.computeSvc.BackendServices.List(o.ProjectID).Fields(googleapi.Field(fields))
54+
if len(filter) > 0 {
55+
req = req.Filter(filter)
56+
}
57+
err := req.Pages(ctx, func(list *compute.BackendServiceList) error {
58+
result = append(result, createBackendServiceCloudResources(filterFunc, list)...)
59+
return nil
60+
})
61+
if err != nil {
62+
return nil, fmt.Errorf("failed to list global backend services: %w", err)
63+
}
64+
return result, nil
65+
}
66+
67+
// Regional backend services
2668
req := o.computeSvc.RegionBackendServices.List(o.ProjectID, o.Region).Fields(googleapi.Field(fields))
2769
if len(filter) > 0 {
2870
req = req.Filter(filter)
2971
}
3072
err := req.Pages(ctx, func(list *compute.BackendServiceList) error {
31-
for _, item := range list.Items {
32-
if filterFunc == nil || filterFunc != nil && filterFunc(item) {
33-
o.Logger.Debugf("Found backend service: %s", item.Name)
34-
result = append(result, cloudResource{
35-
key: item.Name,
36-
name: item.Name,
37-
typeName: "backendservice",
38-
quota: []gcp.QuotaUsage{{
39-
Metric: &gcp.Metric{
40-
Service: gcp.ServiceComputeEngineAPI,
41-
Limit: "backend_services",
42-
},
43-
Amount: 1,
44-
}},
45-
})
46-
}
47-
}
73+
result = append(result, createBackendServiceCloudResources(filterFunc, list)...)
4874
return nil
4975
})
5076
if err != nil {
51-
return nil, errors.Wrapf(err, "failed to list backend services")
77+
return nil, fmt.Errorf("failed to list regional backend services: %w", err)
5278
}
79+
5380
return result, nil
5481
}
5582

56-
func (o *ClusterUninstaller) deleteBackendService(ctx context.Context, item cloudResource) error {
83+
func (o *ClusterUninstaller) deleteBackendService(ctx context.Context, item cloudResource, scope resourceScope) error {
5784
o.Logger.Debugf("Deleting backend service %s", item.name)
5885
ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
5986
defer cancel()
60-
op, err := o.computeSvc.RegionBackendServices.Delete(o.ProjectID, o.Region, item.name).RequestId(o.requestID(item.typeName, item.name)).Context(ctx).Do()
61-
if err != nil && !isNoOp(err) {
62-
o.resetRequestID(item.typeName, item.name)
63-
return errors.Wrapf(err, "failed to delete backend service %s", item.name)
87+
88+
var op *compute.Operation
89+
var err error
90+
if scope == gcpGlobalResource {
91+
op, err = o.computeSvc.BackendServices.Delete(o.ProjectID, item.name).RequestId(o.requestID(item.typeName, item.name)).Context(ctx).Do()
92+
} else {
93+
op, err = o.computeSvc.RegionBackendServices.Delete(o.ProjectID, o.Region, item.name).RequestId(o.requestID(item.typeName, item.name)).Context(ctx).Do()
6494
}
95+
6596
if op != nil && op.Status == "DONE" && isErrorStatus(op.HttpErrorStatusCode) {
6697
o.resetRequestID(item.typeName, item.name)
67-
return errors.Errorf("failed to delete backend service %s with error: %s", item.name, operationErrorMessage(op))
98+
return fmt.Errorf("failed to delete backend service %s with error: %s: %w", item.name, operationErrorMessage(op), err)
6899
}
69100
if (err != nil && isNoOp(err)) || (op != nil && op.Status == "DONE") {
70101
o.resetRequestID(item.typeName, item.name)
@@ -77,19 +108,21 @@ func (o *ClusterUninstaller) deleteBackendService(ctx context.Context, item clou
77108
// destroyBackendServices removes backend services with a name prefixed
78109
// with the cluster's infra ID.
79110
func (o *ClusterUninstaller) destroyBackendServices(ctx context.Context) error {
80-
found, err := o.listBackendServices(ctx)
81-
if err != nil {
82-
return err
83-
}
84-
items := o.insertPendingItems("backendservice", found)
85-
for _, item := range items {
86-
err := o.deleteBackendService(ctx, item)
111+
for _, scope := range []resourceScope{gcpGlobalResource, gcpRegionalResource} {
112+
found, err := o.listBackendServices(ctx, scope)
87113
if err != nil {
88-
o.errorTracker.suppressWarning(item.key, err, o.Logger)
114+
return fmt.Errorf("failed to list backend services: %w", err)
115+
}
116+
items := o.insertPendingItems("backendservice", found)
117+
for _, item := range items {
118+
err := o.deleteBackendService(ctx, item, scope)
119+
if err != nil {
120+
o.errorTracker.suppressWarning(item.key, err, o.Logger)
121+
}
122+
}
123+
if items = o.getPendingItems("backendservice"); len(items) > 0 {
124+
return fmt.Errorf("%d items pending", len(items))
89125
}
90-
}
91-
if items = o.getPendingItems("backendservice"); len(items) > 0 {
92-
return errors.Errorf("%d items pending", len(items))
93126
}
94127
return nil
95128
}

pkg/destroy/gcp/cloudcontroller.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func (o *ClusterUninstaller) listCloudControllerBackendServices(ctx context.Cont
3636
}
3737
}
3838
return true
39-
})
39+
}, gcpRegionalResource)
4040
}
4141

4242
// listCloudControllerTargetPools returns target pools created by the cloud controller or owned by the cloud controller.
@@ -114,7 +114,7 @@ func (o *ClusterUninstaller) discoverCloudControllerLoadBalancerResources(ctx co
114114
o.insertPendingItems("firewall", found)
115115

116116
// Discover associated forwarding rules: loadBalancerName
117-
found, err = o.listForwardingRulesWithFilter(ctx, "items(name),nextPageToken", loadBalancerNameFilter, nil)
117+
found, err = o.listForwardingRulesWithFilter(ctx, "items(name),nextPageToken", loadBalancerNameFilter, nil, gcpRegionalResource)
118118
if err != nil {
119119
return err
120120
}

pkg/destroy/gcp/firewall.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package gcp
22

33
import (
44
"context"
5+
"fmt"
56

67
"github.com/pkg/errors"
78
"google.golang.org/api/compute/v1"
@@ -11,7 +12,11 @@ import (
1112
)
1213

1314
func (o *ClusterUninstaller) listFirewalls(ctx context.Context) ([]cloudResource, error) {
14-
return o.listFirewallsWithFilter(ctx, "items(name),nextPageToken", o.clusterIDFilter(), nil)
15+
// The firewall rules that the destroyer is searching for here include a
16+
// pattern before and after the cluster ID. Use a regular expression that allows
17+
// wildcard values before and after the cluster ID.
18+
filter := fmt.Sprintf("name eq .*%s.*", o.ClusterID)
19+
return o.listFirewallsWithFilter(ctx, "items(name),nextPageToken", filter, nil)
1520
}
1621

1722
// listFirewallsWithFilter lists firewall rules in the project that satisfy the filter criteria.

pkg/destroy/gcp/forwardingrule.go

Lines changed: 84 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,77 +2,113 @@ package gcp
22

33
import (
44
"context"
5+
"fmt"
56

6-
"github.com/pkg/errors"
7+
"github.com/sirupsen/logrus"
78
"google.golang.org/api/compute/v1"
89
"google.golang.org/api/googleapi"
910

1011
"github.com/openshift/installer/pkg/types/gcp"
1112
)
1213

13-
func (o *ClusterUninstaller) listForwardingRules(ctx context.Context) ([]cloudResource, error) {
14-
return o.listForwardingRulesWithFilter(ctx, "items(name,region,loadBalancingScheme),nextPageToken", o.clusterIDFilter(), nil)
14+
func (o *ClusterUninstaller) listForwardingRules(ctx context.Context, scope resourceScope) ([]cloudResource, error) {
15+
return o.listForwardingRulesWithFilter(ctx, "items(name,region,loadBalancingScheme),nextPageToken", o.clusterIDFilter(), nil, scope)
16+
}
17+
18+
func createForwardingRuleResources(filterFunc func(*compute.ForwardingRule) bool, list *compute.ForwardingRuleList) []cloudResource {
19+
result := []cloudResource{}
20+
21+
for _, item := range list.Items {
22+
if filterFunc == nil || filterFunc(item) {
23+
logrus.Debugf("Found forwarding rule: %s", item.Name)
24+
var quota []gcp.QuotaUsage
25+
if item.LoadBalancingScheme == "EXTERNAL" {
26+
quota = []gcp.QuotaUsage{{
27+
Metric: &gcp.Metric{
28+
Service: gcp.ServiceComputeEngineAPI,
29+
Limit: "external_network_lb_forwarding_rules",
30+
Dimensions: map[string]string{
31+
"region": getNameFromURL("regions", item.Region),
32+
},
33+
},
34+
Amount: 1,
35+
}}
36+
}
37+
result = append(result, cloudResource{
38+
key: item.Name,
39+
name: item.Name,
40+
typeName: "forwardingrule",
41+
quota: quota,
42+
})
43+
}
44+
}
45+
46+
return result
1547
}
1648

1749
// listForwardingRulesWithFilter lists forwarding rules in the project that satisfy the filter criteria.
1850
// The fields parameter specifies which fields should be returned in the result, the filter string contains
1951
// a filter string passed to the API to filter results. The filterFunc is a client-side filtering function
2052
// that determines whether a particular result should be returned or not.
21-
func (o *ClusterUninstaller) listForwardingRulesWithFilter(ctx context.Context, fields string, filter string, filterFunc func(*compute.ForwardingRule) bool) ([]cloudResource, error) {
22-
o.Logger.Debugf("Listing forwarding rules")
53+
func (o *ClusterUninstaller) listForwardingRulesWithFilter(ctx context.Context, fields string, filter string, filterFunc func(*compute.ForwardingRule) bool, scope resourceScope) ([]cloudResource, error) {
54+
o.Logger.Debugf("Listing %s forwarding rules", scope)
2355
ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
2456
defer cancel()
57+
2558
result := []cloudResource{}
59+
60+
if scope == gcpGlobalResource {
61+
req := o.computeSvc.GlobalForwardingRules.List(o.ProjectID).Fields(googleapi.Field(fields))
62+
if len(filter) > 0 {
63+
req = req.Filter(filter)
64+
}
65+
err := req.Pages(ctx, func(list *compute.ForwardingRuleList) error {
66+
result = append(result, createForwardingRuleResources(filterFunc, list)...)
67+
return nil
68+
})
69+
if err != nil {
70+
return nil, fmt.Errorf("failed to list global forwarding rules: %w", err)
71+
}
72+
73+
return result, nil
74+
}
75+
76+
// Regional forwarding rules
2677
req := o.computeSvc.ForwardingRules.List(o.ProjectID, o.Region).Fields(googleapi.Field(fields))
2778
if len(filter) > 0 {
2879
req = req.Filter(filter)
2980
}
3081
err := req.Pages(ctx, func(list *compute.ForwardingRuleList) error {
31-
for _, item := range list.Items {
32-
if filterFunc == nil || filterFunc != nil && filterFunc(item) {
33-
o.Logger.Debugf("Found forwarding rule: %s", item.Name)
34-
var quota []gcp.QuotaUsage
35-
switch item.LoadBalancingScheme {
36-
case "EXTERNAL":
37-
quota = []gcp.QuotaUsage{{
38-
Metric: &gcp.Metric{
39-
Service: gcp.ServiceComputeEngineAPI,
40-
Limit: "external_network_lb_forwarding_rules",
41-
Dimensions: map[string]string{
42-
"region": getNameFromURL("regions", item.Region),
43-
},
44-
},
45-
Amount: 1,
46-
}}
47-
}
48-
result = append(result, cloudResource{
49-
key: item.Name,
50-
name: item.Name,
51-
typeName: "forwardingrule",
52-
quota: quota,
53-
})
54-
}
55-
}
82+
result = append(result, createForwardingRuleResources(filterFunc, list)...)
5683
return nil
5784
})
85+
5886
if err != nil {
59-
return nil, errors.Wrapf(err, "failed to list forwarding rules")
87+
return nil, fmt.Errorf("failed to list regional forwarding rules: %w", err)
6088
}
6189
return result, nil
6290
}
6391

64-
func (o *ClusterUninstaller) deleteForwardingRule(ctx context.Context, item cloudResource) error {
92+
func (o *ClusterUninstaller) deleteForwardingRule(ctx context.Context, item cloudResource, scope resourceScope) error {
6593
o.Logger.Debugf("Deleting forwarding rule %s", item.name)
6694
ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
6795
defer cancel()
68-
op, err := o.computeSvc.ForwardingRules.Delete(o.ProjectID, o.Region, item.name).RequestId(o.requestID(item.typeName, item.name)).Context(ctx).Do()
96+
97+
var op *compute.Operation
98+
var err error
99+
if scope == gcpGlobalResource {
100+
op, err = o.computeSvc.GlobalForwardingRules.Delete(o.ProjectID, item.name).RequestId(o.requestID(item.typeName, item.name)).Context(ctx).Do()
101+
} else {
102+
op, err = o.computeSvc.ForwardingRules.Delete(o.ProjectID, o.Region, item.name).RequestId(o.requestID(item.typeName, item.name)).Context(ctx).Do()
103+
}
104+
69105
if err != nil && !isNoOp(err) {
70106
o.resetRequestID(item.typeName, item.name)
71-
return errors.Wrapf(err, "failed to delete forwarding rule %s", item.name)
107+
return fmt.Errorf("failed to delete forwarding rule %s: %w", item.name, err)
72108
}
73109
if op != nil && op.Status == "DONE" && isErrorStatus(op.HttpErrorStatusCode) {
74110
o.resetRequestID(item.typeName, item.name)
75-
return errors.Errorf("failed to delete forwarding rule %s with error: %s", item.name, operationErrorMessage(op))
111+
return fmt.Errorf("failed to delete forwarding rule %s with error: %s: %w", item.name, operationErrorMessage(op), err)
76112
}
77113
if (err != nil && isNoOp(err)) || (op != nil && op.Status == "DONE") {
78114
o.resetRequestID(item.typeName, item.name)
@@ -85,19 +121,21 @@ func (o *ClusterUninstaller) deleteForwardingRule(ctx context.Context, item clou
85121
// destroyForwardingRules removes all forwarding rules with a name prefixed
86122
// with the cluster's infra ID.
87123
func (o *ClusterUninstaller) destroyForwardingRules(ctx context.Context) error {
88-
found, err := o.listForwardingRules(ctx)
89-
if err != nil {
90-
return err
91-
}
92-
items := o.insertPendingItems("forwardingrule", found)
93-
for _, item := range items {
94-
err := o.deleteForwardingRule(ctx, item)
124+
for _, scope := range []resourceScope{gcpGlobalResource, gcpRegionalResource} {
125+
found, err := o.listForwardingRules(ctx, scope)
95126
if err != nil {
96-
o.errorTracker.suppressWarning(item.key, err, o.Logger)
127+
return fmt.Errorf("failed to list forwarding rules: %w", err)
128+
}
129+
items := o.insertPendingItems("forwardingrule", found)
130+
for _, item := range items {
131+
if err := o.deleteForwardingRule(ctx, item, scope); err != nil {
132+
o.Logger.Errorf("error deleting forwarding rule %s: %w", item.name, err)
133+
o.errorTracker.suppressWarning(item.key, err, o.Logger)
134+
}
135+
}
136+
if items = o.getPendingItems("forwardingrule"); len(items) > 0 {
137+
return fmt.Errorf("%d items pending", len(items))
97138
}
98-
}
99-
if items = o.getPendingItems("forwardingrule"); len(items) > 0 {
100-
return errors.Errorf("%d items pending", len(items))
101139
}
102140
return nil
103141
}

0 commit comments

Comments
 (0)