Skip to content

Commit 9cbccd3

Browse files
authored
Merge pull request kubernetes#75256 from feiskyer/fix-75198
Ensure Azure load balancer cleaned up on 404 or 403
2 parents a213886 + 88907da commit 9cbccd3

File tree

4 files changed

+106
-6
lines changed

4 files changed

+106
-6
lines changed

pkg/cloudprovider/providers/azure/azure_loadbalancer.go

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,27 +169,47 @@ func (az *Cloud) UpdateLoadBalancer(ctx context.Context, clusterName string, ser
169169
func (az *Cloud) EnsureLoadBalancerDeleted(ctx context.Context, clusterName string, service *v1.Service) error {
170170
isInternal := requiresInternalLoadBalancer(service)
171171
serviceName := getServiceName(service)
172-
klog.V(5).Infof("delete(%s): START clusterName=%q", serviceName, clusterName)
172+
klog.V(5).Infof("Delete service (%s): START clusterName=%q", serviceName, clusterName)
173+
174+
ignoreErrors := func(err error) error {
175+
if ignoreStatusNotFoundFromError(err) == nil {
176+
klog.V(5).Infof("EnsureLoadBalancerDeleted: ignoring StatusNotFound error because the resource doesn't exist (%v)", err)
177+
return nil
178+
}
179+
180+
if ignoreStatusForbiddenFromError(err) == nil {
181+
klog.V(5).Infof("EnsureLoadBalancerDeleted: ignoring StatusForbidden error (%v). This may be caused by wrong configuration via service annotations", err)
182+
return nil
183+
}
184+
185+
return err
186+
}
173187

174188
serviceIPToCleanup, err := az.findServiceIPAddress(ctx, clusterName, service, isInternal)
175-
if err != nil {
189+
if ignoreErrors(err) != nil {
176190
return err
177191
}
178192

179193
klog.V(2).Infof("EnsureLoadBalancerDeleted: reconciling security group for service %q with IP %q, wantLb = false", serviceName, serviceIPToCleanup)
180194
if _, err := az.reconcileSecurityGroup(clusterName, service, &serviceIPToCleanup, false /* wantLb */); err != nil {
181-
return err
195+
if ignoreErrors(err) != nil {
196+
return err
197+
}
182198
}
183199

184200
if _, err := az.reconcileLoadBalancer(clusterName, service, nil, false /* wantLb */); err != nil {
185-
return err
201+
if ignoreErrors(err) != nil {
202+
return err
203+
}
186204
}
187205

188206
if _, err := az.reconcilePublicIP(clusterName, service, nil, false /* wantLb */); err != nil {
189-
return err
207+
if ignoreErrors(err) != nil {
208+
return err
209+
}
190210
}
191211

192-
klog.V(2).Infof("delete(%s): FINISH", serviceName)
212+
klog.V(2).Infof("Delete service (%s): FINISH", serviceName)
193213
return nil
194214
}
195215

pkg/cloudprovider/providers/azure/azure_loadbalancer_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package azure
1818

1919
import (
20+
"context"
2021
"fmt"
2122
"reflect"
2223
"testing"
@@ -308,3 +309,62 @@ func TestSubnet(t *testing.T) {
308309
assert.Equal(t, c.expected, real, fmt.Sprintf("TestCase[%d]: %s", i, c.desc))
309310
}
310311
}
312+
313+
func TestEnsureLoadBalancerDeleted(t *testing.T) {
314+
const vmCount = 8
315+
const availabilitySetCount = 4
316+
const serviceCount = 9
317+
318+
tests := []struct {
319+
desc string
320+
service v1.Service
321+
expectCreateError bool
322+
}{
323+
{
324+
desc: "external service should be created and deleted successfully",
325+
service: getTestService("test1", v1.ProtocolTCP, 80),
326+
},
327+
{
328+
desc: "internal service should be created and deleted successfully",
329+
service: getInternalTestService("test2", 80),
330+
},
331+
{
332+
desc: "annotated service with same resourceGroup should be created and deleted successfully",
333+
service: getResourceGroupTestService("test3", "rg", "", 80),
334+
},
335+
{
336+
desc: "annotated service with different resourceGroup shouldn't be created but should be deleted successfully",
337+
service: getResourceGroupTestService("test4", "random-rg", "1.2.3.4", 80),
338+
expectCreateError: true,
339+
},
340+
}
341+
342+
az := getTestCloud()
343+
for i, c := range tests {
344+
clusterResources := getClusterResources(az, vmCount, availabilitySetCount)
345+
getTestSecurityGroup(az)
346+
if c.service.Annotations[ServiceAnnotationLoadBalancerInternal] == "true" {
347+
addTestSubnet(t, az, &c.service)
348+
}
349+
350+
// create the service first.
351+
lbStatus, err := az.EnsureLoadBalancer(context.TODO(), testClusterName, &c.service, clusterResources.nodes)
352+
if c.expectCreateError {
353+
assert.NotNil(t, err, "TestCase[%d]: %s", i, c.desc)
354+
} else {
355+
assert.Nil(t, err, "TestCase[%d]: %s", i, c.desc)
356+
assert.NotNil(t, lbStatus, "TestCase[%d]: %s", i, c.desc)
357+
result, err := az.LoadBalancerClient.List(context.TODO(), az.Config.ResourceGroup)
358+
assert.Nil(t, err, "TestCase[%d]: %s", i, c.desc)
359+
assert.Equal(t, len(result), 1, "TestCase[%d]: %s", i, c.desc)
360+
assert.Equal(t, len(*result[0].LoadBalancingRules), 1, "TestCase[%d]: %s", i, c.desc)
361+
}
362+
363+
// finally, delete it.
364+
err = az.EnsureLoadBalancerDeleted(context.TODO(), testClusterName, &c.service)
365+
assert.Nil(t, err, "TestCase[%d]: %s", i, c.desc)
366+
result, err := az.LoadBalancerClient.List(context.Background(), az.Config.ResourceGroup)
367+
assert.Nil(t, err, "TestCase[%d]: %s", i, c.desc)
368+
assert.Equal(t, len(result), 0, "TestCase[%d]: %s", i, c.desc)
369+
}
370+
}

pkg/cloudprovider/providers/azure/azure_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,13 @@ func getInternalTestService(identifier string, requestedPorts ...int32) v1.Servi
11371137
return svc
11381138
}
11391139

1140+
func getResourceGroupTestService(identifier, resourceGroup, loadBalancerIP string, requestedPorts ...int32) v1.Service {
1141+
svc := getTestService(identifier, v1.ProtocolTCP, requestedPorts...)
1142+
svc.Spec.LoadBalancerIP = loadBalancerIP
1143+
svc.Annotations[ServiceAnnotationLoadBalancerResourceGroup] = resourceGroup
1144+
return svc
1145+
}
1146+
11401147
func setLoadBalancerModeAnnotation(service *v1.Service, lbMode string) {
11411148
service.Annotations[ServiceAnnotationLoadBalancerMode] = lbMode
11421149
}

pkg/cloudprovider/providers/azure/azure_wrap.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,19 @@ func ignoreStatusNotFoundFromError(err error) error {
7171
return err
7272
}
7373

74+
// ignoreStatusForbiddenFromError returns nil if the status code is StatusForbidden.
75+
// This happens when AuthorizationFailed is reported from Azure API.
76+
func ignoreStatusForbiddenFromError(err error) error {
77+
if err == nil {
78+
return nil
79+
}
80+
v, ok := err.(autorest.DetailedError)
81+
if ok && v.StatusCode == http.StatusForbidden {
82+
return nil
83+
}
84+
return err
85+
}
86+
7487
/// getVirtualMachine calls 'VirtualMachinesClient.Get' with a timed cache
7588
/// The service side has throttling control that delays responses if there're multiple requests onto certain vm
7689
/// resource request in short period.

0 commit comments

Comments
 (0)