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: SLB backend pools are empty if outbound rules are defined in a separate backend pool. This is because, although we the check for not adding the backend pools from different LBs, the lbName is not checked: The new backend pool's lbName should be also checked in above codes. What you expected to happen: SLB backend pools should be updated correctly when outbound rules are defined in a separate backend pool. 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

Discussion:
// sets, the same network interface couldn't be added to more than one load balancer of // the same type. Omit those nodes (e.g. masters) so Azure ARM won't complain // about this. <ins> newBackendPoolsIDs := make([]string, 0, len(newBackendPools)) </ins> for _, pool := range newBackendPools { <del> backendPool := *pool.ID matches := backendPoolIDRE.FindStringSubmatch(backendPool) if len(matches) == 2 { lbName := matches[1] if strings.HasSuffix(lbName, InternalLoadBalancerNameSuffix) == isInternal { klog.V(4).Infof("Node %q has already been added to LB %q, omit adding it to a new one", nodeName, lbName) return nil } </del> <ins> if pool.ID != nil { newBackendPoolsIDs = append(newBackendPoolsIDs, *pool.ID) </ins> } } <ins> isSameLB, oldLBName, err := isBackendPoolOnSameLB(backendPoolID, newBackendPoolsIDs) if err != nil { return err } if !isSameLB { klog.V(4).Infof("Node %q has already been added to LB %q, omit adding it to a new one", nodeName, oldLBName) return nil } </ins> } newBackendPools = append(newBackendPools,

// the same network interface couldn't be added to more than one load balancer of // the same type. Omit those nodes (e.g. masters) so Azure ARM won't complain // about this. <ins> newBackendPoolsIDs := make([]string, 0, len(newBackendPools)) </ins> for _, pool := range newBackendPools { <del> backendPool := *pool.ID matches := backendPoolIDRE.FindStringSubmatch(backendPool) if len(matches) == 2 { lbName := matches[1] if strings.HasSuffix(lbName, InternalLoadBalancerNameSuffix) == isInternal { klog.V(4).Infof("vmss %q has already been added to LB %q, omit adding it to a new one", vmSetName, lbName) return nil } </del> <ins> if pool.ID != nil { newBackendPoolsIDs = append(newBackendPoolsIDs, *pool.ID) </ins> } } <ins> isSameLB, oldLBName, err := isBackendPoolOnSameLB(backendPoolID, newBackendPoolsIDs) if err != nil { return err } if !isSameLB { klog.V(4).Infof("VMSS %q has already been added to LB %q, omit adding it to a new one", vmSetName, oldLBName) return nil } </ins> } newBackendPools = append(newBackendPools,

resourceGroup := matches[1] return strings.Replace(resourceID, resourceGroup, strings.ToLower(resourceGroup), 1), nil } <ins> // isBackendPoolOnSameLB checks whether newBackendPoolID is on the same load balancer as existingBackendPools. // Since both public and internal LBs are supported, lbName and lbName-internal are treated as same. // If not same, the lbName for existingBackendPools would also be returned. func isBackendPoolOnSameLB(newBackendPoolID string, existingBackendPools []string) (bool, string, error) { matches := backendPoolIDRE.FindStringSubmatch(newBackendPoolID) if len(matches) != 2 { return false, "", fmt.Errorf("new backendPoolID %q is in wrong format", newBackendPoolID) } newLBName := matches[1] newLBNameTrimmed := strings.TrimRight(newLBName, InternalLoadBalancerNameSuffix) for _, backendPool := range existingBackendPools { matches := backendPoolIDRE.FindStringSubmatch(backendPool) if len(matches) != 2 { return false, "", fmt.Errorf("existing backendPoolID %q is in wrong format", backendPool) } lbName := matches[1] if !strings.EqualFold(strings.TrimRight(lbName, InternalLoadBalancerNameSuffix), newLBNameTrimmed) { return false, lbName, nil } } return true, "", nil } </ins>

assert.Equal(t, test.expected, real, test.desc) } } <ins> func TestIsBackendPoolOnSameLB(t *testing.T) { tests := []struct { backendPoolID        string existingBackendPools []string expected             bool expectedLBName       string expectError          bool }{ { backendPoolID: "/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Network/loadBalancers/lb1/backendAddressPools/pool1", existingBackendPools: []string{ "/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Network/loadBalancers/lb1/backendAddressPools/pool2", }, expected:       true, expectedLBName: "", }, { backendPoolID: "/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Network/loadBalancers/lb1-internal/backendAddressPools/pool1", existingBackendPools: []string{ "/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Network/loadBalancers/lb1/backendAddressPools/pool2", }, expected:       true, expectedLBName: "", }, { backendPoolID: "/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Network/loadBalancers/lb1/backendAddressPools/pool1", existingBackendPools: []string{ "/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Network/loadBalancers/lb1-internal/backendAddressPools/pool2", }, expected:       true, expectedLBName: "", }, { backendPoolID: "/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Network/loadBalancers/lb1/backendAddressPools/pool1", existingBackendPools: []string{ "/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Network/loadBalancers/lb2/backendAddressPools/pool2", }, expected:       false, expectedLBName: "lb2", }, { backendPoolID: "wrong-backendpool-id", existingBackendPools: []string{ "/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Network/loadBalancers/lb1/backendAddressPools/pool2", }, expectError: true, }, { backendPoolID: "/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Network/loadBalancers/lb1/backendAddressPools/pool1", existingBackendPools: []string{ "wrong-existing-backendpool-id", }, expectError: true, }, { backendPoolID: "wrong-backendpool-id", existingBackendPools: []string{ "wrong-existing-backendpool-id", }, expectError: true, }, } for _, test := range tests { isSameLB, lbName, err := isBackendPoolOnSameLB(test.backendPoolID, test.existingBackendPools) if test.expectError { assert.Error(t, err) continue } assert.Equal(t, test.expected, isSameLB) assert.Equal(t, test.expectedLBName, lbName) } } </ins>