Skip to content

Commit 7b3e25d

Browse files
committed
Check for GCE finalizer in GetLoadBalancer.
This is a more accurate check that looking for the forwarding rule, which could be deleted if delete flow was partially complete and abrupted by an upgrade, or if deleted by user manually. Added unit test. Addressed review comments.
1 parent dd552e2 commit 7b3e25d

File tree

3 files changed

+56
-1
lines changed

3 files changed

+56
-1
lines changed

staging/src/k8s.io/legacy-cloud-providers/gce/gce_loadbalancer.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ func (g *Cloud) GetLoadBalancer(ctx context.Context, clusterName string, svc *v1
111111

112112
return status, true, nil
113113
}
114+
// Checking for finalizer is more accurate because controller restart could happen in the middle of resource
115+
// deletion. So even though forwarding rule was deleted, cleanup might not have been complete.
116+
if hasFinalizer(svc, ILBFinalizerV1) {
117+
return &v1.LoadBalancerStatus{}, true, nil
118+
}
114119
return nil, false, ignoreNotFound(err)
115120
}
116121

staging/src/k8s.io/legacy-cloud-providers/gce/gce_loadbalancer_internal.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ func (g *Cloud) ensureInternalLoadBalancer(clusterName, clusterID string, svc *v
6262
"Skipped ensureInternalLoadBalancer as service contains '%s' finalizer.", ILBFinalizerV2)
6363
return nil, cloudprovider.ImplementedElsewhere
6464
}
65+
66+
loadBalancerName := g.GetLoadBalancerName(context.TODO(), clusterName, svc)
67+
klog.V(2).Infof("ensureInternalLoadBalancer(%v): Attaching %q finalizer", loadBalancerName, ILBFinalizerV1)
6568
if err := addFinalizer(svc, g.client.CoreV1(), ILBFinalizerV1); err != nil {
6669
klog.Errorf("Failed to attach finalizer '%s' on service %s/%s - %v", ILBFinalizerV1, svc.Namespace, svc.Name, err)
6770
return nil, err
@@ -85,7 +88,6 @@ func (g *Cloud) ensureInternalLoadBalancer(clusterName, clusterID string, svc *v
8588
}
8689
}
8790

88-
loadBalancerName := g.GetLoadBalancerName(context.TODO(), clusterName, svc)
8991
sharedBackend := shareBackendService(svc)
9092
backendServiceName := makeBackendServiceName(loadBalancerName, clusterID, sharedBackend, scheme, protocol, svc.Spec.SessionAffinity)
9193
backendServiceLink := g.getBackendServiceLink(backendServiceName)
@@ -317,10 +319,12 @@ func (g *Cloud) ensureInternalLoadBalancerDeleted(clusterName, clusterID string,
317319

318320
// Try deleting instance groups - expect ResourceInuse error if needed by other LBs
319321
igName := makeInstanceGroupName(clusterID)
322+
klog.V(2).Infof("ensureInternalLoadBalancerDeleted(%v): Attempting delete of instanceGroup %v", loadBalancerName, igName)
320323
if err := g.ensureInternalInstanceGroupsDeleted(igName); err != nil && !isInUsedByError(err) {
321324
return err
322325
}
323326

327+
klog.V(2).Infof("ensureInternalLoadBalancerDeleted(%v): Removing %q finalizer", loadBalancerName, ILBFinalizerV1)
324328
if err := removeFinalizer(svc, g.client.CoreV1(), ILBFinalizerV1); err != nil {
325329
klog.Errorf("Failed to remove finalizer '%s' on service %s/%s - %v", ILBFinalizerV1, svc.Namespace, svc.Name, err)
326330
return err

staging/src/k8s.io/legacy-cloud-providers/gce/gce_loadbalancer_internal_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,5 +1590,51 @@ func TestEnsureLoadBalancerSkipped(t *testing.T) {
15901590
// No loadbalancer resources will be created due to the ILB Feature Gate
15911591
assert.Empty(t, status)
15921592
assertInternalLbResourcesDeleted(t, gce, svc, vals, true)
1593+
}
1594+
1595+
// TestEnsureLoadBalancerPartialDelete simulates a partial delete and checks whether deletion completes after a second
1596+
// attempt.
1597+
func TestEnsureLoadBalancerPartialDelete(t *testing.T) {
1598+
t.Parallel()
1599+
1600+
vals := DefaultTestClusterValues()
1601+
nodeNames := []string{"test-node-1"}
1602+
1603+
gce, err := fakeGCECloud(vals)
1604+
require.NoError(t, err)
15931605

1606+
svc := fakeLoadbalancerService(string(LBTypeInternal))
1607+
svc, err = gce.client.CoreV1().Services(svc.Namespace).Create(context.TODO(), svc, metav1.CreateOptions{})
1608+
require.NoError(t, err)
1609+
status, err := createInternalLoadBalancer(gce, svc, nil, nodeNames, vals.ClusterName, vals.ClusterID, vals.ZoneName)
1610+
require.NoError(t, err)
1611+
assert.NotEmpty(t, status.Ingress)
1612+
assertInternalLbResources(t, gce, svc, vals, nodeNames)
1613+
svc, err = gce.client.CoreV1().Services(svc.Namespace).Get(context.TODO(), svc.Name, metav1.GetOptions{})
1614+
require.NoError(t, err)
1615+
if !hasFinalizer(svc, ILBFinalizerV1) {
1616+
t.Errorf("Expected finalizer '%s' not found in Finalizer list - %v", ILBFinalizerV1, svc.Finalizers)
1617+
}
1618+
// Delete the forwarding rule to simulate controller getting shut down on partial cleanup
1619+
lbName := gce.GetLoadBalancerName(context.TODO(), "", svc)
1620+
err = gce.DeleteRegionForwardingRule(lbName, gce.region)
1621+
require.NoError(t, err)
1622+
// Check output of GetLoadBalancer
1623+
_, exists, err := gce.GetLoadBalancer(context.TODO(), vals.ClusterName, svc)
1624+
require.NoError(t, err)
1625+
assert.True(t, exists)
1626+
// call EnsureDeleted again
1627+
err = gce.EnsureLoadBalancerDeleted(context.TODO(), vals.ClusterName, svc)
1628+
require.NoError(t, err)
1629+
// Make sure all resources are gone
1630+
assertInternalLbResourcesDeleted(t, gce, svc, vals, true)
1631+
// Ensure that the finalizer has been deleted
1632+
svc, err = gce.client.CoreV1().Services(svc.Namespace).Get(context.TODO(), svc.Name, metav1.GetOptions{})
1633+
require.NoError(t, err)
1634+
if hasFinalizer(svc, ILBFinalizerV1) {
1635+
t.Errorf("Finalizer '%s' not deleted from service - %v", ILBFinalizerV1, svc.Finalizers)
1636+
}
1637+
_, exists, err = gce.GetLoadBalancer(context.TODO(), vals.ClusterName, svc)
1638+
require.NoError(t, err)
1639+
assert.False(t, exists)
15941640
}

0 commit comments

Comments
 (0)