Change:
<!-- Please use this template while reporting a bug and provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner. Thanks! If the matter is security related, please disclose it privately via --What happened: When the Idle Timeout annotation was set to "3" which isn't a supported case, kube-controller-manager is stuck in deleting Azure LB. New service with the same name couldn't be created again even without the annotation. What you expected to happen: New service should be created successfully. How to reproduce it (as minimally and precisely as possible): Anything else we need to know?: Environment: Kubernetes version (use ): Cloud provider or hardware configuration: OS (e.g: ): Kernel (e.g. ): Install tools: Others: /sig azure /kind bug
/assign Since I'm seeing this on some of our clusters
/priority important-soon
Thanks
- The problem here seems that when we want to call (when processing a delete event) it reconciles the loadbalancer which in turn tries to get the idleTimeout, resulting in an error. one of the strategies is to still construct our diff in case of a delete and exercise the code path at the end. This basically translate into ignoring the error when getting idleTimeout and excluding it from finding if the rule is dirty or not when we are . toughts ? Generally speaking, whenever we update a loadbalancer with unsupported values on annotations, ensuring load balancer will fail resulting in an un-cleaned LB, this is a cross-provider issue. /sig cloud-provider cc
cc
lgtm. the delete operation should continue to do cleanup job even some wrong options are provided from users.

Discussion:
lbBackendPoolID := az.getBackendPoolID(lbName, lbBackendPoolName) lbIdleTimeout, err := getIdleTimeout(service) <del> if err != nil { </del> <ins> if wantLb && err != nil { </ins> return nil, err }

if az.serviceOwnsRule(service, *existingRule.Name) { keepRule := false klog.V(10).Infof("reconcileLoadBalancer for service (%s)(%t): lb rule(%s) - considering evicting", serviceName, wantLb, *existingRule.Name) <del> if findRule(expectedRules, existingRule) { </del> <ins> if findRule(expectedRules, existingRule, wantLb) { </ins> klog.V(10).Infof("reconcileLoadBalancer for service (%s)(%t): lb rule(%s) - keeping", serviceName, wantLb, *existingRule.Name) keepRule = true }

// update rules: add needed for _, expectedRule := range expectedRules { foundRule := false <del> if findRule(updatedRules, expectedRule) { </del> <ins> if findRule(updatedRules, expectedRule, wantLb) { </ins> klog.V(10).Infof("reconcileLoadBalancer for service (%s)(%t): lb rule(%s) - already exists", serviceName, wantLb, *expectedRule.Name) foundRule = true }

return false } <del> func findRule(rules []network.LoadBalancingRule, rule network.LoadBalancingRule) bool { </del> <ins> func findRule(rules []network.LoadBalancingRule, rule network.LoadBalancingRule, wantLB bool) bool { </ins> for _, existingRule := range rules { if strings.EqualFold(to.String(existingRule.Name), to.String(rule.Name)) && <del> equalLoadBalancingRulePropertiesFormat(existingRule.LoadBalancingRulePropertiesFormat, rule.LoadBalancingRulePropertiesFormat) { </del> <ins> equalLoadBalancingRulePropertiesFormat(existingRule.LoadBalancingRulePropertiesFormat, rule.LoadBalancingRulePropertiesFormat, wantLB) { </ins> return true } }

// equalLoadBalancingRulePropertiesFormat checks whether the provided LoadBalancingRulePropertiesFormat are equal. // Note: only fields used in reconcileLoadBalancer are considered. <del> func equalLoadBalancingRulePropertiesFormat(s, t *network.LoadBalancingRulePropertiesFormat) bool { </del> <ins> func equalLoadBalancingRulePropertiesFormat(s *network.LoadBalancingRulePropertiesFormat, t *network.LoadBalancingRulePropertiesFormat, wantLB bool) bool { </ins> if s == nil || t == nil { return false } <del> return reflect.DeepEqual(s.Protocol, t.Protocol) && </del> <ins> properties := reflect.DeepEqual(s.Protocol, t.Protocol) && </ins> reflect.DeepEqual(s.FrontendIPConfiguration, t.FrontendIPConfiguration) && reflect.DeepEqual(s.BackendAddressPool, t.BackendAddressPool) && reflect.DeepEqual(s.LoadDistribution, t.LoadDistribution) && reflect.DeepEqual(s.FrontendPort, t.FrontendPort) && reflect.DeepEqual(s.BackendPort, t.BackendPort) && <del> reflect.DeepEqual(s.EnableFloatingIP, t.EnableFloatingIP) && reflect.DeepEqual(s.IdleTimeoutInMinutes, t.IdleTimeoutInMinutes) </del> <ins> reflect.DeepEqual(s.EnableFloatingIP, t.EnableFloatingIP) if wantLB { return properties && reflect.DeepEqual(s.IdleTimeoutInMinutes, t.IdleTimeoutInMinutes) } return properties </ins> } // This compares rule's Name, Protocol, SourcePortRange, DestinationPortRange, SourceAddressPrefix, Access, and Direction.

} for i, test := range tests { <del> findResult := findRule(test.existingRule, test.curRule) </del> <ins> findResult := findRule(test.existingRule, test.curRule, true) </ins> assert.Equal(t, test.expected, findResult, fmt.Sprintf("TestCase[%d]: %s", i, test.msg)) } }