Repository: kubernetes-sigs/cloud-provider-azure
Pull request #7620 (2024-11-19 08:22:13)

build(deps): bump sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader from 0.1.4 to 0.1.5
Bumps [sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader](https://github.com/kubernetes-sigs/cloud-provider-azure) from 0.1.4 to 0.1.5.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/kubernetes-sigs/cloud-provider-azure/commit/24cad881d65bcd165d0d660a920149daf8443f41"><code>24cad88</code></a> build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/conta...</li>
<li><a href="https://github.com/kubernetes-sigs/cloud-provider-azure/commit/71578117c66dd3771d4d809eeb410879a69a69ce"><code>7157811</code></a> build(deps): bump actions/checkout from 4.2.1 to 4.2.2 (<a href="https://redirect.github.com/kubernetes-sigs/cloud-provider-azure/issues/7409">#7409</a>)</li>
<li><a href="https://github.com/kubernetes-sigs/cloud-provider-azure/commit/22dea79f5387509e95cddf6593118b9530040fdd"><code>22dea79</code></a> build(deps): bump k8s.io/apimachinery in /kubetest2-aks (<a href="https://redirect.github.com/kubernetes-sigs/cloud-provider-azure/issues/7402">#7402</a>)</li>
<li><a href="https://github.com/kubernetes-sigs/cloud-provider-azure/commit/9031199ea36c7c9e12982da854d24eddfd759267"><code>9031199</code></a> build(deps): bump sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader ...</li>
<li><a href="https://github.com/kubernetes-sigs/cloud-provider-azure/commit/aa55b646ea906e5626385e73c988855aae54f88c"><code>aa55b64</code></a> Merge pull request <a href="https://redirect.github.com/kubernetes-sigs/cloud-provider-azure/issues/7400">#7400</a> from kubernetes-sigs/dependabot/MartinForReal-patch-1</li>
<li><a href="https://github.com/kubernetes-sigs/cloud-provider-azure/commit/6423544022b2ece03d5f04b9680fddc431cc81d7"><code>6423544</code></a> skip trivy db update</li>
<li><a href="https://github.com/kubernetes-sigs/cloud-provider-azure/commit/8940db3bbe0460e8058c979c744ca5eaa191d9b8"><code>8940db3</code></a> [StepSecurity] ci: Harden GitHub Actions (<a href="https://redirect.github.com/kubernetes-sigs/cloud-provider-azure/issues/7399">#7399</a>)</li>
<li><a href="https://github.com/kubernetes-sigs/cloud-provider-azure/commit/909a6e7c0f00cd6fe8420b698fe6738814ab1371"><code>909a6e7</code></a> Create update-trivy-db.yaml</li>
<li><a href="https://github.com/kubernetes-sigs/cloud-provider-azure/commit/1c1f121c5ed61923569412c4235398648b076bdd"><code>1c1f121</code></a> build(deps): bump github/codeql-action from 3.26.13 to 3.27.0 (<a href="https://redirect.github.com/kubernetes-sigs/cloud-provider-azure/issues/7396">#7396</a>)</li>
<li>See full diff in <a href="https://github.com/kubernetes-sigs/cloud-provider-azure/compare/pkg/azclient/v0.1.4...pkg/azclient/v0.1.5">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader&package-manager=go_modules&previous-version=0.1.4&new-version=0.1.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

Approval requirements bypassed by manually added approval.

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/cloud-provider-azure/pull/7620#" title="Author self-approved">dependabot[bot]</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fcloud-provider-azure).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes-sigs/cloud-provider-azure/blob/release-1.30/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["martinforreal"]} -->

Patch:
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index f9386782e..a1fa82427 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -55,7 +55,7 @@ jobs:
 
     steps:
     - name: Harden Runner
-      uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+      uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
       with:
         egress-policy: audit
 
diff --git a/.github/workflows/codespell.yaml b/.github/workflows/codespell.yaml
index 5f6ee4d50..9278c4567 100644
--- a/.github/workflows/codespell.yaml
+++ b/.github/workflows/codespell.yaml
@@ -12,7 +12,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+        uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml
index e908a47f3..09008de3c 100644
--- a/.github/workflows/dependency-review.yml
+++ b/.github/workflows/dependency-review.yml
@@ -17,7 +17,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+        uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/lint-ci-weekly.yaml b/.github/workflows/lint-ci-weekly.yaml
index a106dbd84..67178e0bd 100644
--- a/.github/workflows/lint-ci-weekly.yaml
+++ b/.github/workflows/lint-ci-weekly.yaml
@@ -14,7 +14,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+        uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
         with:
           egress-policy: audit
       - name: Setup Golang
diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml
index 6baef7c00..506ce874c 100644
--- a/.github/workflows/lint.yaml
+++ b/.github/workflows/lint.yaml
@@ -16,7 +16,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+        uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
         with:
           egress-policy: audit
       - name: Checkout
diff --git a/.github/workflows/release-azclient-trace.yml b/.github/workflows/release-azclient-trace.yml
index 909afa197..a2d9f4dbb 100644
--- a/.github/workflows/release-azclient-trace.yml
+++ b/.github/workflows/release-azclient-trace.yml
@@ -15,7 +15,7 @@ jobs:
       contents: write
     steps:
     - name: Harden Runner
-      uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+      uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
       with:
         egress-policy: audit
 
diff --git a/.github/workflows/release-azclient.yml b/.github/workflows/release-azclient.yml
index c673d0a69..27b29f37a 100644
--- a/.github/workflows/release-azclient.yml
+++ b/.github/workflows/release-azclient.yml
@@ -18,7 +18,7 @@ jobs:
       contents: write
     steps:
     - name: Harden Runner
-      uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+      uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
       with:
         egress-policy: audit
 
diff --git a/.github/workflows/release-configloader.yml b/.github/workflows/release-configloader.yml
index c8c2c8371..cbef4e862 100644
--- a/.github/workflows/release-configloader.yml
+++ b/.github/workflows/release-configloader.yml
@@ -15,7 +15,7 @@ jobs:
       contents: write
     steps:
     - name: Harden Runner
-      uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+      uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
       with:
         egress-policy: audit
 
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index d482a5b24..e8b1c498f 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -23,7 +23,7 @@ jobs:
             arch: arm64
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+        uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
         with:
           egress-policy: audit
 
@@ -59,7 +59,7 @@ jobs:
             arch: amd64
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+        uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
         with:
           egress-policy: audit
 
@@ -111,7 +111,7 @@ jobs:
             arch: amd64
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+        uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
         with:
           egress-policy: audit
 
@@ -158,7 +158,7 @@ jobs:
       pull-requests: write
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+        uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index 57eb6a5ff..e376cbcbd 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -32,7 +32,7 @@ jobs:
 
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+        uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/trivy.yaml b/.github/workflows/trivy.yaml
index 5559f2bbd..bcb950ee3 100644
--- a/.github/workflows/trivy.yaml
+++ b/.github/workflows/trivy.yaml
@@ -37,7 +37,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+        uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/update-vendor-license.yml b/.github/workflows/update-vendor-license.yml
index 3be6356dd..a0dc98725 100644
--- a/.github/workflows/update-vendor-license.yml
+++ b/.github/workflows/update-vendor-license.yml
@@ -37,7 +37,7 @@ jobs:
 
     steps:
     - name: Harden Runner
-      uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+      uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
       with:
         egress-policy: audit
 
diff --git a/go.mod b/go.mod
index a120cd3bc..d3a3e630e 100644
--- a/go.mod
+++ b/go.mod
@@ -50,7 +50,7 @@ require (
 	k8s.io/kubelet v0.30.6
 	k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
 	sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.1.18
-	sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.4
+	sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.5
 	sigs.k8s.io/yaml v1.4.0
 )
 
diff --git a/go.sum b/go.sum
index e61529af7..65e77d41b 100644
--- a/go.sum
+++ b/go.sum
@@ -456,8 +456,8 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RCh
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4=
 sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.1.18 h1:IWQ4QGFRFBg5qs3PqaQOMiBeL03piicaOhE42MNusIY=
 sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.1.18/go.mod h1:TBCLfYApPcLBc0AG0inEFyEtD3jk+hq097H6dXlFTnk=
-sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.4 h1:78nKI0bjXCXLKGccr2aITi0mJ1YScqMeoCiYSrzi3Ag=
-sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.4/go.mod h1:qpPLf/GsTSQV8pGzInA07hYT7OgwN5AqLoYf0i5qI2I=
+sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.5 h1:FrkM6pIC6b3dmrd3RgPqrOK44z9gFsR4NI5ZFlUtiQo=
+sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.5/go.mod h1:qpPLf/GsTSQV8pGzInA07hYT7OgwN5AqLoYf0i5qI2I=
 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
 sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
diff --git a/pkg/provider/azure_loadbalancer.go b/pkg/provider/azure_loadbalancer.go
index a4389d78b..a225ff80d 100644
--- a/pkg/provider/azure_loadbalancer.go
+++ b/pkg/provider/azure_loadbalancer.go
@@ -182,7 +182,7 @@ func (az *Cloud) reconcileService(ctx context.Context, clusterName string, servi
 		az.localServiceNameToServiceInfoMap.Store(key, newServiceInfo(getServiceIPFamily(service), lbName))
 		// There are chances that the endpointslice changes after EnsureHostsInPool, so
 		// need to check endpointslice for a second time.
-		if err := az.checkAndApplyLocalServiceBackendPoolUpdates(ctx, *lb, service); err != nil {
+		if err := az.checkAndApplyLocalServiceBackendPoolUpdates(*lb, service); err != nil {
 			logger.Error(err, "Failed to checkAndApplyLocalServiceBackendPoolUpdates")
 			return nil, err
 		}
diff --git a/pkg/provider/azure_loadbalancer_backendpool.go b/pkg/provider/azure_loadbalancer_backendpool.go
index 7cc7c2b2d..d368417eb 100644
--- a/pkg/provider/azure_loadbalancer_backendpool.go
+++ b/pkg/provider/azure_loadbalancer_backendpool.go
@@ -203,7 +203,7 @@ func (bc *backendPoolTypeNodeIPConfig) ReconcileBackendPools(
 			if bp.BackendAddressPoolPropertiesFormat != nil &&
 				bp.LoadBalancerBackendAddresses != nil &&
 				len(*bp.LoadBalancerBackendAddresses) > 0 {
-				if removeNodeIPAddressesFromBackendPool(bp, []string{}, true, false) {
+				if removeNodeIPAddressesFromBackendPool(bp, []string{}, true, false, false) {
 					isMigration = true
 					bp.VirtualNetwork = nil
 					if err := bc.CreateOrUpdateLBBackendPool(ctx, lbName, bp); err != nil {
@@ -411,7 +411,6 @@ func (bi *backendPoolTypeNodeIP) EnsureHostsInPool(ctx context.Context, service
 		changed               bool
 		numOfAdd, numOfDelete int
 		activeNodes           *utilsets.IgnoreCaseSet
-		err                   error
 	)
 	if bi.useMultipleStandardLoadBalancers() {
 		if !isLocalService(service) {
@@ -426,10 +425,12 @@ func (bi *backendPoolTypeNodeIP) EnsureHostsInPool(ctx context.Context, service
 					"current load balancer", si.lbName)
 				return nil
 			}
-			activeNodes, err = bi.getLocalServiceEndpointsNodeNames(ctx, service)
-			if err != nil {
-				return err
-			}
+			activeNodes = bi.getLocalServiceEndpointsNodeNames(service)
+		}
+
+		if isNICPool(backendPool) {
+			klog.V(4).InfoS("EnsureHostsInPool: skipping NIC-based backend pool", "backendPoolName", ptr.Deref(backendPool.Name, ""))
+			return nil
 		}
 	}
 
@@ -464,7 +465,7 @@ func (bi *backendPoolTypeNodeIP) EnsureHostsInPool(ctx context.Context, service
 			}
 
 			if bi.useMultipleStandardLoadBalancers() {
-				if !activeNodes.Has(node.Name) {
+				if activeNodes != nil && !activeNodes.Has(node.Name) {
 					klog.V(4).Infof("bi.EnsureHostsInPool: node %s should not be in load balancer %q", node.Name, lbName)
 					continue
 				}
@@ -501,7 +502,7 @@ func (bi *backendPoolTypeNodeIP) EnsureHostsInPool(ctx context.Context, service
 				}
 			}
 		}
-		removeNodeIPAddressesFromBackendPool(backendPool, nodeIPsToBeDeleted, false, bi.useMultipleStandardLoadBalancers())
+		removeNodeIPAddressesFromBackendPool(backendPool, nodeIPsToBeDeleted, false, bi.useMultipleStandardLoadBalancers(), true)
 	}
 	if changed {
 		klog.V(2).Infof("bi.EnsureHostsInPool: updating backend pool %s of load balancer %s to add %d nodes and remove %d nodes", lbBackendPoolName, lbName, numOfAdd, numOfDelete)
@@ -634,7 +635,7 @@ func (bi *backendPoolTypeNodeIP) ReconcileBackendPools(ctx context.Context, clus
 		if isMigration && bi.EnableMigrateToIPBasedBackendPoolAPI {
 			var backendPoolNames []string
 			for _, id := range lbBackendPoolIDsSlice {
-				name, err := getLBNameFromBackendPoolID(id)
+				name, err := getBackendPoolNameFromBackendPoolID(id)
 				if err != nil {
 					klog.Errorf("bi.ReconcileBackendPools for service (%s): failed to get LB name from backend pool ID: %s", serviceName, err.Error())
 					return false, false, nil, err
@@ -675,7 +676,7 @@ func (bi *backendPoolTypeNodeIP) ReconcileBackendPools(ctx context.Context, clus
 				}
 			}
 			if len(nodeIPAddressesToBeDeleted) > 0 {
-				if removeNodeIPAddressesFromBackendPool(bp, nodeIPAddressesToBeDeleted, false, false) {
+				if removeNodeIPAddressesFromBackendPool(bp, nodeIPAddressesToBeDeleted, false, false, true) {
 					updated = true
 				}
 			}
@@ -872,11 +873,13 @@ func hasIPAddressInBackendPool(backendPool *network.BackendAddressPool, ipAddres
 func removeNodeIPAddressesFromBackendPool(
 	backendPool network.BackendAddressPool,
 	nodeIPAddresses []string,
-	removeAll, useMultipleStandardLoadBalancers bool,
+	removeAll, useMultipleStandardLoadBalancers, isNodeIP bool,
 ) bool {
 	changed := false
 	nodeIPsSet := utilsets.NewString(nodeIPAddresses...)
 
+	logger := klog.Background().WithName("removeNodeIPAddressFromBackendPool")
+
 	if backendPool.BackendAddressPoolPropertiesFormat == nil ||
 		backendPool.LoadBalancerBackendAddresses == nil {
 		return false
@@ -887,7 +890,13 @@ func removeNodeIPAddressesFromBackendPool(
 		if addresses[i].LoadBalancerBackendAddressPropertiesFormat != nil {
 			ipAddress := pointer.StringDeref((*backendPool.LoadBalancerBackendAddresses)[i].IPAddress, "")
 			if ipAddress == "" {
-				klog.V(4).Infof("removeNodeIPAddressFromBackendPool: LoadBalancerBackendAddress %s is not IP-based, skipping", pointer.StringDeref(addresses[i].Name, ""))
+				if isNodeIP {
+					logger.V(4).Info("LoadBalancerBackendAddress is not IP-based, removing", "LoadBalancerBackendAddress", ptr.Deref(addresses[i].Name, ""))
+					addresses = append(addresses[:i], addresses[i+1:]...)
+					changed = true
+				} else {
+					logger.V(4).Info("LoadBalancerBackendAddress is not IP-based, skipping", "LoadBalancerBackendAddress", ptr.Deref(addresses[i].Name, ""))
+				}
 				continue
 			}
 			if removeAll || nodeIPsSet.Has(ipAddress) {
diff --git a/pkg/provider/azure_loadbalancer_repo.go b/pkg/provider/azure_loadbalancer_repo.go
index 528930b16..09642bc9d 100644
--- a/pkg/provider/azure_loadbalancer_repo.go
+++ b/pkg/provider/azure_loadbalancer_repo.go
@@ -298,7 +298,6 @@ func (az *Cloud) MigrateToIPBasedBackendPoolAndWaitForCompletion(
 		}
 		return true, nil
 	})
-
 	if err != nil {
 		if errors.Is(err, wait.ErrWaitTimeout) {
 			klog.Warningf("MigrateToIPBasedBackendPoolAndWaitForCompletion: Timeout waiting for migration to IP based backend pool for lb %s, backend pool %s", lbName, strings.Join(backendPoolNames, ","))
@@ -352,7 +351,7 @@ func (az *Cloud) getAzureLoadBalancer(ctx context.Context, name string, crt azca
 // 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 {
+	if len(matches) != 3 {
 		return false, "", fmt.Errorf("new backendPoolID %q is in wrong format", newBackendPoolID)
 	}
 
@@ -360,7 +359,7 @@ func isBackendPoolOnSameLB(newBackendPoolID string, existingBackendPools []strin
 	newLBNameTrimmed := trimSuffixIgnoreCase(newLBName, consts.InternalLoadBalancerNameSuffix)
 	for _, backendPool := range existingBackendPools {
 		matches := backendPoolIDRE.FindStringSubmatch(backendPool)
-		if len(matches) != 2 {
+		if len(matches) != 3 {
 			return false, "", fmt.Errorf("existing backendPoolID %q is in wrong format", backendPool)
 		}
 
@@ -381,3 +380,18 @@ func (az *Cloud) serviceOwnsRule(service *v1.Service, rule string) bool {
 	prefix := az.getRulePrefix(service)
 	return strings.HasPrefix(strings.ToUpper(rule), strings.ToUpper(prefix))
 }
+
+func isNICPool(bp network.BackendAddressPool) bool {
+	logger := klog.Background().WithName("isNICPool").WithValues("backendPoolName", ptr.Deref(bp.Name, ""))
+	if bp.BackendAddressPoolPropertiesFormat != nil &&
+		bp.LoadBalancerBackendAddresses != nil {
+		for _, addr := range *bp.LoadBalancerBackendAddresses {
+			if ptr.Deref(addr.IPAddress, "") == "" {
+				logger.V(4).Info("The load balancer backend address has empty ip address, assuming it is a NIC pool",
+					"loadBalancerBackendAddress", ptr.Deref(addr.Name, ""))
+				return true
+			}
+		}
+	}
+	return false
+}
diff --git a/pkg/provider/azure_local_services.go b/pkg/provider/azure_local_services.go
index 825b9c846..9cb2a8f4d 100644
--- a/pkg/provider/azure_local_services.go
+++ b/pkg/provider/azure_local_services.go
@@ -27,7 +27,6 @@ import (
 
 	v1 "k8s.io/api/core/v1"
 	discovery_v1 "k8s.io/api/discovery/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/sets"
 	"k8s.io/apimachinery/pkg/util/wait"
 	"k8s.io/client-go/informers"
@@ -211,7 +210,7 @@ func (updater *loadBalancerBackendPoolUpdater) process(ctx context.Context) {
 			lbOp := op.(*loadBalancerBackendPoolUpdateOperation)
 			switch lbOp.kind {
 			case consts.LoadBalancerBackendPoolUpdateOperationRemove:
-				removed := removeNodeIPAddressesFromBackendPool(bp, lbOp.nodeIPs, false, true)
+				removed := removeNodeIPAddressesFromBackendPool(bp, lbOp.nodeIPs, false, true, true)
 				changed = changed || removed
 			case consts.LoadBalancerBackendPoolUpdateOperationAdd:
 				added := updater.az.addNodeIPAddressesToBackendPool(&bp, lbOp.nodeIPs)
@@ -447,8 +446,10 @@ func (az *Cloud) getLocalServiceBackendPoolID(serviceName string, lbName string,
 
 // localServiceOwnsBackendPool checks if a backend pool is owned by a local service.
 func localServiceOwnsBackendPool(serviceName, bpName string) bool {
-	prefix := strings.Replace(serviceName, "/", "-", -1)
-	return strings.HasPrefix(strings.ToLower(bpName), strings.ToLower(prefix))
+	if strings.HasSuffix(strings.ToLower(bpName), consts.IPVersionIPv6StringLower) {
+		return strings.EqualFold(getLocalServiceBackendPoolName(serviceName, true), bpName)
+	}
+	return strings.EqualFold(getLocalServiceBackendPoolName(serviceName, false), bpName)
 }
 
 type serviceInfo struct {
@@ -464,50 +465,30 @@ func newServiceInfo(ipFamily, lbName string) *serviceInfo {
 }
 
 // getLocalServiceEndpointsNodeNames gets the node names that host all endpoints of the local service.
-func (az *Cloud) getLocalServiceEndpointsNodeNames(ctx context.Context, service *v1.Service) (*utilsets.IgnoreCaseSet, error) {
-	var (
-		ep           *discovery_v1.EndpointSlice
-		foundInCache bool
-	)
+func (az *Cloud) getLocalServiceEndpointsNodeNames(service *v1.Service) *utilsets.IgnoreCaseSet {
+	var eps []*discovery_v1.EndpointSlice
 	az.endpointSlicesCache.Range(func(_, value interface{}) bool {
 		endpointSlice := value.(*discovery_v1.EndpointSlice)
 		if strings.EqualFold(getServiceNameOfEndpointSlice(endpointSlice), service.Name) &&
 			strings.EqualFold(endpointSlice.Namespace, service.Namespace) {
-			ep = endpointSlice
-			foundInCache = true
-			return false
+			eps = append(eps, endpointSlice)
 		}
 		return true
 	})
-	if ep == nil {
-		klog.Infof("EndpointSlice for service %s/%s not found, try to list EndpointSlices", service.Namespace, service.Name)
-		eps, err := az.KubeClient.DiscoveryV1().EndpointSlices(service.Namespace).List(ctx, metav1.ListOptions{})
-		if err != nil {
-			klog.Errorf("Failed to list EndpointSlices for service %s/%s: %s", service.Namespace, service.Name, err.Error())
-			return nil, err
-		}
-		for _, endpointSlice := range eps.Items {
-			endpointSlice := endpointSlice
-			if strings.EqualFold(getServiceNameOfEndpointSlice(&endpointSlice), service.Name) {
-				ep = &endpointSlice
-				break
-			}
-		}
-	}
-	if ep == nil {
-		return nil, fmt.Errorf("failed to find EndpointSlice for service %s/%s", service.Namespace, service.Name)
-	}
-	if !foundInCache {
-		az.endpointSlicesCache.Store(strings.ToLower(fmt.Sprintf("%s/%s", ep.Namespace, ep.Name)), ep)
+	if len(eps) == 0 {
+		klog.Warningf("getLocalServiceEndpointsNodeNames: failed to find EndpointSlice for service %s/%s", service.Namespace, service.Name)
+		return nil
 	}
 
 	var nodeNames []string
-	for _, endpoint := range ep.Endpoints {
-		klog.V(4).Infof("EndpointSlice %s/%s has endpoint %s on node %s", ep.Namespace, ep.Name, endpoint.Addresses, pointer.StringDeref(endpoint.NodeName, ""))
-		nodeNames = append(nodeNames, pointer.StringDeref(endpoint.NodeName, ""))
+	for _, ep := range eps {
+		for _, endpoint := range ep.Endpoints {
+			klog.V(4).Infof("EndpointSlice %s/%s has endpoint %s on node %s", ep.Namespace, ep.Name, endpoint.Addresses, ptr.Deref(endpoint.NodeName, ""))
+			nodeNames = append(nodeNames, ptr.Deref(endpoint.NodeName, ""))
+		}
 	}
 
-	return utilsets.NewString(nodeNames...), nil
+	return utilsets.NewString(nodeNames...)
 }
 
 // cleanupLocalServiceBackendPool cleans up the backend pool of
@@ -549,12 +530,13 @@ func (az *Cloud) cleanupLocalServiceBackendPool(
 
 // checkAndApplyLocalServiceBackendPoolUpdates if the IPs in the backend pool are aligned
 // with the corresponding endpointslice, and update the backend pool if necessary.
-func (az *Cloud) checkAndApplyLocalServiceBackendPoolUpdates(ctx context.Context, lb network.LoadBalancer, service *v1.Service) error {
+func (az *Cloud) checkAndApplyLocalServiceBackendPoolUpdates(lb network.LoadBalancer, service *v1.Service) error {
 	serviceName := getServiceName(service)
-	endpointsNodeNames, err := az.getLocalServiceEndpointsNodeNames(ctx, service)
-	if err != nil {
-		return err
+	endpointsNodeNames := az.getLocalServiceEndpointsNodeNames(service)
+	if endpointsNodeNames == nil {
+		return nil
 	}
+
 	var expectedIPs []string
 	for _, nodeName := range endpointsNodeNames.UnsortedList() {
 		ips := az.nodePrivateIPs[strings.ToLower(nodeName)]
diff --git a/pkg/provider/azure_standard.go b/pkg/provider/azure_standard.go
index 19b1cf20e..973219f5a 100644
--- a/pkg/provider/azure_standard.go
+++ b/pkg/provider/azure_standard.go
@@ -49,7 +49,7 @@ import (
 var (
 	errNotInVMSet      = errors.New("vm is not in the vmset")
 	providerIDRE       = regexp.MustCompile(`.*/subscriptions/(?:.*)/Microsoft.Compute/virtualMachines/(.+)$`)
-	backendPoolIDRE    = regexp.MustCompile(`^/subscriptions/(?:.*)/resourceGroups/(?:.*)/providers/Microsoft.Network/loadBalancers/(.+)/backendAddressPools/(?:.*)`)
+	backendPoolIDRE    = regexp.MustCompile(`^/subscriptions/(?:.*)/resourceGroups/(?:.*)/providers/Microsoft.Network/loadBalancers/(.+)/backendAddressPools/(.+)`)
 	nicResourceGroupRE = regexp.MustCompile(`.*/subscriptions/(?:.*)/resourceGroups/(.+)/providers/Microsoft.Network/networkInterfaces/(?:.*)`)
 	nicIDRE            = regexp.MustCompile(`(?i)/subscriptions/(?:.*)/resourceGroups/(.+)/providers/Microsoft.Network/networkInterfaces/(.+)/ipConfigurations/(?:.*)`)
 	vmIDRE             = regexp.MustCompile(`(?i)/subscriptions/(?:.*)/resourceGroups/(?:.*)/providers/Microsoft.Compute/virtualMachines/(.+)`)
diff --git a/pkg/provider/azure_utils.go b/pkg/provider/azure_utils.go
index af288671a..cd1c74621 100644
--- a/pkg/provider/azure_utils.go
+++ b/pkg/provider/azure_utils.go
@@ -458,13 +458,13 @@ func getResourceIDPrefix(id string) string {
 	return id[:idx]
 }
 
-func getLBNameFromBackendPoolID(backendPoolID string) (string, error) {
+func getBackendPoolNameFromBackendPoolID(backendPoolID string) (string, error) {
 	matches := backendPoolIDRE.FindStringSubmatch(backendPoolID)
-	if len(matches) != 2 {
+	if len(matches) != 3 {
 		return "", fmt.Errorf("backendPoolID %q is in wrong format", backendPoolID)
 	}
 
-	return matches[1], nil
+	return matches[2], nil
 }
 
 func countNICsOnBackendPool(backendPool network.BackendAddressPool) int {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 431f15990..05ae5edae 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1560,7 +1560,7 @@ sigs.k8s.io/cloud-provider-azure/pkg/azclient/virtualmachinescalesetvmclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/virtualnetworkclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/virtualnetworklinkclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/virtualnetworklinkclient/mock_virtualnetworklinkclient
-# sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.4
+# sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.5
 ## explicit; go 1.23.1
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader
 # sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader/load.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader/load.go
index efa79c52b..63d6b1889 100644
--- a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader/load.go
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader/load.go
@@ -56,22 +56,22 @@ func Load[Type any](ctx context.Context, secretLoaderConfig *K8sSecretLoaderConf
 	var err error
 	if fileLoaderConfig != nil {
 		loadConfigloader := newEmptyLoader[ConfigMergeConfig](&ConfigMergeConfig{CloudConfigType: CloudConfigTypeMerge})
-		loadConfigloader = newFileLoader(fileLoaderConfig.FilePath, loadConfigloader, newYamlByteLoader[ConfigMergeConfig])
+		loadConfigloader = newFileLoader(fileLoaderConfig.FilePath, loadConfigloader, NewYamlByteLoader[ConfigMergeConfig])
 		//by default the config load type  is merge
 		loadConfig, err = loadConfigloader.Load(ctx)
 		if err != nil {
 			return nil, err
 		}
-		configloader = newFileLoader(fileLoaderConfig.FilePath, nil, newYamlByteLoader[Type])
+		configloader = newFileLoader(fileLoaderConfig.FilePath, nil, NewYamlByteLoader[Type])
 		if strings.EqualFold(string(loadConfig.CloudConfigType), string(CloudConfigTypeFile)) {
 			return configloader.Load(ctx)
 		}
 	}
 	if secretLoaderConfig != nil {
 		if loadConfig != nil && strings.EqualFold(string(loadConfig.CloudConfigType), string(CloudConfigTypeSecret)) {
-			configloader = newK8sSecretLoader(&secretLoaderConfig.K8sSecretConfig, secretLoaderConfig.KubeClient, nil, newYamlByteLoader[Type])
+			configloader = newK8sSecretLoader(&secretLoaderConfig.K8sSecretConfig, secretLoaderConfig.KubeClient, nil, NewYamlByteLoader[Type])
 		} else {
-			configloader = newK8sSecretLoader(&secretLoaderConfig.K8sSecretConfig, secretLoaderConfig.KubeClient, configloader, newYamlByteLoader[Type])
+			configloader = newK8sSecretLoader(&secretLoaderConfig.K8sSecretConfig, secretLoaderConfig.KubeClient, configloader, NewYamlByteLoader[Type])
 		}
 	}
 	return configloader.Load(ctx)
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader/loader_yaml.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader/loader_yaml.go
index c5a8a1f30..346025834 100644
--- a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader/loader_yaml.go
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader/loader_yaml.go
@@ -23,14 +23,14 @@ import (
 	"sigs.k8s.io/yaml"
 )
 
-// yamlByteLoader is a FactoryConfigLoader that loads a YAML file from a byte array.
-type yamlByteLoader[Type any] struct {
+// YamlByteLoader is a FactoryConfigLoader that loads a YAML file from a byte array.
+type YamlByteLoader[Type any] struct {
 	content []byte
 	configLoader[Type]
 }
 
 // Load loads the YAML file from the byte array and returns the client factory config.
-func (s *yamlByteLoader[Type]) Load(ctx context.Context) (*Type, error) {
+func (s *YamlByteLoader[Type]) Load(ctx context.Context) (*Type, error) {
 	if s.configLoader == nil {
 		s.configLoader = newEmptyLoader[Type](nil)
 	}
@@ -45,9 +45,9 @@ func (s *yamlByteLoader[Type]) Load(ctx context.Context) (*Type, error) {
 	return config, nil
 }
 
-// newYamlByteLoader creates a YamlByteLoader with the specified content and loader.
-func newYamlByteLoader[Type any](content []byte, loader configLoader[Type]) configLoader[Type] {
-	return &yamlByteLoader[Type]{
+// NewYamlByteLoader creates a YamlByteLoader with the specified content and loader.
+func NewYamlByteLoader[Type any](content []byte, loader configLoader[Type]) configLoader[Type] {
+	return &YamlByteLoader[Type]{
 		content:      content,
 		configLoader: loader,
 	}


Test patch:
diff --git a/pkg/provider/azure_loadbalancer_backendpool_test.go b/pkg/provider/azure_loadbalancer_backendpool_test.go
index e8057ec2e..2d9bd1640 100644
--- a/pkg/provider/azure_loadbalancer_backendpool_test.go
+++ b/pkg/provider/azure_loadbalancer_backendpool_test.go
@@ -33,6 +33,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	cloudprovider "k8s.io/cloud-provider"
 	"k8s.io/utils/pointer"
+	"k8s.io/utils/ptr"
 
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/loadbalancerclient/mockloadbalancerclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
@@ -201,19 +202,14 @@ func TestEnsureHostsInPoolNodeIP(t *testing.T) {
 			},
 		},
 		{
-			desc: "should add correct nodes to the pool and remove unwanted ones when using multi-slb",
+			desc: "should skip NIC-based backend pool when using multi-slb",
 			backendPool: network.BackendAddressPool{
-				Name: pointer.String("kubernetes"),
+				Name: ptr.To("kubernetes"),
 				BackendAddressPoolPropertiesFormat: &network.BackendAddressPoolPropertiesFormat{
 					LoadBalancerBackendAddresses: &[]network.LoadBalancerBackendAddress{
 						{
 							LoadBalancerBackendAddressPropertiesFormat: &network.LoadBalancerBackendAddressPropertiesFormat{
-								IPAddress: pointer.String("10.0.0.1"),
-							},
-						},
-						{
-							LoadBalancerBackendAddressPropertiesFormat: &network.LoadBalancerBackendAddressPropertiesFormat{
-								IPAddress: pointer.String("10.0.0.3"),
+								IPAddress: ptr.To(""),
 							},
 						},
 					},
@@ -228,49 +224,55 @@ func TestEnsureHostsInPoolNodeIP(t *testing.T) {
 				},
 			},
 			expectedBackendPool: network.BackendAddressPool{
-				Name: pointer.String("kubernetes"),
+				Name: ptr.To("kubernetes"),
 				BackendAddressPoolPropertiesFormat: &network.BackendAddressPoolPropertiesFormat{
-					VirtualNetwork: &network.SubResource{ID: pointer.String("/subscriptions/subscription/resourceGroups/rg/providers/Microsoft.Network/virtualNetworks/vnet")},
 					LoadBalancerBackendAddresses: &[]network.LoadBalancerBackendAddress{
 						{
-							Name: pointer.String("vmss-2"),
 							LoadBalancerBackendAddressPropertiesFormat: &network.LoadBalancerBackendAddressPropertiesFormat{
-								IPAddress: pointer.String("10.0.0.4"),
+								IPAddress: ptr.To(""),
 							},
 						},
 					},
 				},
 			},
+			skip: true,
 		},
 		{
-			desc:  "should add ips to the local service dedicated backend pool",
-			local: true,
+			desc: "should add correct nodes to the pool and remove unwanted ones when using multi-slb",
 			backendPool: network.BackendAddressPool{
-				Name: pointer.String("default-svc-1"),
+				Name: pointer.String("kubernetes"),
 				BackendAddressPoolPropertiesFormat: &network.BackendAddressPoolPropertiesFormat{
-					LoadBalancerBackendAddresses: &[]network.LoadBalancerBackendAddress{},
+					LoadBalancerBackendAddresses: &[]network.LoadBalancerBackendAddress{
+						{
+							LoadBalancerBackendAddressPropertiesFormat: &network.LoadBalancerBackendAddressPropertiesFormat{
+								IPAddress: pointer.String("10.0.0.1"),
+							},
+						},
+						{
+							LoadBalancerBackendAddressPropertiesFormat: &network.LoadBalancerBackendAddressPropertiesFormat{
+								IPAddress: pointer.String("10.0.0.3"),
+							},
+						},
+					},
 				},
 			},
 			multiSLBConfigs: []MultipleStandardLoadBalancerConfiguration{
 				{
 					Name: "kubernetes",
+					MultipleStandardLoadBalancerConfigurationStatus: MultipleStandardLoadBalancerConfigurationStatus{
+						ActiveNodes: utilsets.NewString("vmss-2"),
+					},
 				},
 			},
 			expectedBackendPool: network.BackendAddressPool{
-				Name: pointer.String("default-svc-1"),
+				Name: pointer.String("kubernetes"),
 				BackendAddressPoolPropertiesFormat: &network.BackendAddressPoolPropertiesFormat{
 					VirtualNetwork: &network.SubResource{ID: pointer.String("/subscriptions/subscription/resourceGroups/rg/providers/Microsoft.Network/virtualNetworks/vnet")},
 					LoadBalancerBackendAddresses: &[]network.LoadBalancerBackendAddress{
 						{
-							Name: pointer.String("vmss-0"),
-							LoadBalancerBackendAddressPropertiesFormat: &network.LoadBalancerBackendAddressPropertiesFormat{
-								IPAddress: pointer.String("10.0.0.2"),
-							},
-						},
-						{
-							Name: pointer.String("vmss-1"),
+							Name: pointer.String("vmss-2"),
 							LoadBalancerBackendAddressPropertiesFormat: &network.LoadBalancerBackendAddressPropertiesFormat{
-								IPAddress: pointer.String("10.0.0.1"),
+								IPAddress: pointer.String("10.0.0.4"),
 							},
 						},
 					},
@@ -934,12 +936,14 @@ func TestReconcileBackendPoolsNodeIPConfigToIPWithMigrationAPI(t *testing.T) {
 	mockVMSet.EXPECT().GetPrimaryVMSetName().Return("k8s-agentpool1-00000000").AnyTimes()
 
 	mockLBClient := mockloadbalancerclient.NewMockInterface(ctrl)
-	mockLBClient.EXPECT().MigrateToIPBasedBackendPool(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(retry.NewError(false, errors.New("error")))
+	mockLBClient.EXPECT().MigrateToIPBasedBackendPool(gomock.Any(), gomock.Any(), "testCluster", []string{"testCluster"}).Return(retry.NewError(false, errors.New("error")))
 
 	az := GetTestCloud(ctrl)
 	az.VMSet = mockVMSet
 	az.LoadBalancerClient = mockLBClient
 	az.EnableMigrateToIPBasedBackendPoolAPI = true
+	az.LoadBalancerSku = "standard"
+	az.MultipleStandardLoadBalancerConfigurations = []MultipleStandardLoadBalancerConfiguration{{Name: "kubernetes"}}
 
 	bi := newBackendPoolTypeNodeIP(az)
 	svc := getTestService("test", v1.ProtocolTCP, nil, false, 80)
@@ -947,7 +951,7 @@ func TestReconcileBackendPoolsNodeIPConfigToIPWithMigrationAPI(t *testing.T) {
 	assert.Error(t, err)
 	assert.Contains(t, err.Error(), "error")
 
-	mockLBClient.EXPECT().MigrateToIPBasedBackendPool(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
+	mockLBClient.EXPECT().MigrateToIPBasedBackendPool(gomock.Any(), gomock.Any(), "testCluster", []string{"testCluster"}).Return(nil)
 	bps := buildLBWithVMIPs(testClusterName, []string{"1.2.3.4", "2.3.4.5"}).BackendAddressPools
 	mockLBClient.EXPECT().GetLBBackendPool(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return((*bps)[0], nil)
 	mockLBClient.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(network.LoadBalancer{}, nil)
@@ -980,6 +984,7 @@ func TestRemoveNodeIPAddressFromBackendPool(t *testing.T) {
 		description                           string
 		removeAll, useMultiSLB                bool
 		unwantedIPs, existingIPs, expectedIPs []string
+		isNodeIP                              bool
 	}{
 		{
 			description: "removeNodeIPAddressFromBackendPool should remove the unwanted IP addresses from the backend pool",
@@ -1007,12 +1012,26 @@ func TestRemoveNodeIPAddressFromBackendPool(t *testing.T) {
 			existingIPs: []string{"1.2.3.4", "4.3.2.1", ""},
 			expectedIPs: []string{""},
 		},
+		{
+			description: "removeNodeIPAddressFromBackendPool should skip non-IP based backend addresses when isNodeIP is false",
+			unwantedIPs: []string{"1.2.3.4"},
+			existingIPs: []string{"1.2.3.4", ""},
+			expectedIPs: []string{""},
+		},
+		{
+			description: "removeNodeIPAddressFromBackendPool should remove non-IP based backend addresses when isNodeIP is true",
+			unwantedIPs: []string{"1.2.3.4"},
+			existingIPs: []string{"1.2.3.4", ""},
+			expectedIPs: []string{},
+			useMultiSLB: true,
+			isNodeIP:    true,
+		},
 	} {
 		t.Run(tc.description, func(t *testing.T) {
 			backendPool := buildTestLoadBalancerBackendPoolWithIPs("kubernetes", tc.existingIPs)
 			expectedBackendPool := buildTestLoadBalancerBackendPoolWithIPs("kubernetes", tc.expectedIPs)
 
-			removeNodeIPAddressesFromBackendPool(backendPool, tc.unwantedIPs, tc.removeAll, tc.useMultiSLB)
+			removeNodeIPAddressesFromBackendPool(backendPool, tc.unwantedIPs, tc.removeAll, tc.useMultiSLB, tc.isNodeIP)
 			assert.Equal(t, expectedBackendPool, backendPool)
 		})
 	}
diff --git a/pkg/provider/azure_loadbalancer_repo_test.go b/pkg/provider/azure_loadbalancer_repo_test.go
index 0cd3f1dc3..f478940cf 100644
--- a/pkg/provider/azure_loadbalancer_repo_test.go
+++ b/pkg/provider/azure_loadbalancer_repo_test.go
@@ -428,3 +428,101 @@ func TestServiceOwnsRuleSharedProbe(t *testing.T) {
 		})
 	}
 }
+
+func TestIsNICPool(t *testing.T) {
+	tests := []struct {
+		desc     string
+		bp       network.BackendAddressPool
+		expected bool
+	}{
+		{
+			desc: "nil BackendAddressPoolPropertiesFormat",
+			bp: network.BackendAddressPool{
+				Name: ptr.To("pool1"),
+			},
+			expected: false,
+		},
+		{
+			desc: "nil LoadBalancerBackendAddresses",
+			bp: network.BackendAddressPool{
+				Name:                               ptr.To("pool1"),
+				BackendAddressPoolPropertiesFormat: &network.BackendAddressPoolPropertiesFormat{},
+			},
+			expected: false,
+		},
+		{
+			desc: "empty LoadBalancerBackendAddresses",
+			bp: network.BackendAddressPool{
+				Name: ptr.To("pool1"),
+				BackendAddressPoolPropertiesFormat: &network.BackendAddressPoolPropertiesFormat{
+					LoadBalancerBackendAddresses: &[]network.LoadBalancerBackendAddress{},
+				},
+			},
+			expected: false,
+		},
+		{
+			desc: "LoadBalancerBackendAddress with empty IPAddress",
+			bp: network.BackendAddressPool{
+				Name: ptr.To("pool1"),
+				BackendAddressPoolPropertiesFormat: &network.BackendAddressPoolPropertiesFormat{
+					LoadBalancerBackendAddresses: &[]network.LoadBalancerBackendAddress{
+						{
+							Name: ptr.To("addr1"),
+							LoadBalancerBackendAddressPropertiesFormat: &network.LoadBalancerBackendAddressPropertiesFormat{
+								IPAddress: ptr.To(""),
+							},
+						},
+					},
+				},
+			},
+			expected: true,
+		},
+		{
+			desc: "LoadBalancerBackendAddress with non-empty IPAddress",
+			bp: network.BackendAddressPool{
+				Name: ptr.To("pool1"),
+				BackendAddressPoolPropertiesFormat: &network.BackendAddressPoolPropertiesFormat{
+					LoadBalancerBackendAddresses: &[]network.LoadBalancerBackendAddress{
+						{
+							Name: ptr.To("addr1"),
+							LoadBalancerBackendAddressPropertiesFormat: &network.LoadBalancerBackendAddressPropertiesFormat{
+								IPAddress: ptr.To("10.0.0.1"),
+							},
+						},
+					},
+				},
+			},
+			expected: false,
+		},
+		{
+			desc: "LoadBalancerBackendAddress with both empty and non-empty IPAddress",
+			bp: network.BackendAddressPool{
+				Name: ptr.To("pool1"),
+				BackendAddressPoolPropertiesFormat: &network.BackendAddressPoolPropertiesFormat{
+					LoadBalancerBackendAddresses: &[]network.LoadBalancerBackendAddress{
+						{
+							Name: ptr.To("addr1"),
+							LoadBalancerBackendAddressPropertiesFormat: &network.LoadBalancerBackendAddressPropertiesFormat{
+								IPAddress: ptr.To(""),
+							},
+						},
+						{
+							Name: ptr.To("addr2"),
+							LoadBalancerBackendAddressPropertiesFormat: &network.LoadBalancerBackendAddressPropertiesFormat{
+								IPAddress: ptr.To("10.0.0.2"),
+							},
+						},
+					},
+				},
+			},
+			expected: true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.desc, func(t *testing.T) {
+			result := isNICPool(test.bp)
+			assert.Equal(t, test.expected, result)
+		})
+	}
+}
diff --git a/pkg/provider/azure_local_services_test.go b/pkg/provider/azure_local_services_test.go
index ed6f6f238..6511a5f18 100644
--- a/pkg/provider/azure_local_services_test.go
+++ b/pkg/provider/azure_local_services_test.go
@@ -34,7 +34,6 @@ import (
 	discovery_v1 "k8s.io/api/discovery/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/informers"
-	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/utils/pointer"
 
@@ -546,27 +545,20 @@ func TestCheckAndApplyLocalServiceBackendPoolUpdates(t *testing.T) {
 	for _, tc := range []struct {
 		description string
 		existingEPS *discovery_v1.EndpointSlice
-		expectedErr error
 	}{
 		{
 			description: "should update backend pool as expected",
 			existingEPS: getTestEndpointSlice("eps1", "default", "svc1", "node2"),
 		},
 		{
-			description: "should report an error if failed to get the endpointslice",
-			expectedErr: errors.New("failed to find EndpointSlice for service default/svc1"),
+			description: "should not report an error if failed to get the endpointslice",
 		},
 	} {
 		t.Run(tc.description, func(t *testing.T) {
 			cloud := GetTestCloud(ctrl)
 			cloud.localServiceNameToServiceInfoMap.Store("default/svc1", &serviceInfo{lbName: "lb1"})
 			svc := getTestService("svc1", v1.ProtocolTCP, nil, false)
-			var client kubernetes.Interface
-			if tc.existingEPS != nil {
-				client = fake.NewSimpleClientset(&svc, tc.existingEPS)
-			} else {
-				client = fake.NewSimpleClientset(&svc)
-			}
+			client := fake.NewSimpleClientset(&svc)
 			cloud.KubeClient = client
 			informerFactory := informers.NewSharedInformerFactory(client, 0)
 			cloud.serviceLister = informerFactory.Core().V1().Services().Lister()
@@ -582,6 +574,9 @@ func TestCheckAndApplyLocalServiceBackendPoolUpdates(t *testing.T) {
 				"node1": utilsets.NewString("10.0.0.1", "fd00::1"),
 				"node2": utilsets.NewString("10.0.0.2", "fd00::2"),
 			}
+			if tc.existingEPS != nil {
+				cloud.endpointSlicesCache.Store(fmt.Sprintf("%s/%s", tc.existingEPS.Name, tc.existingEPS.Namespace), tc.existingEPS)
+			}
 
 			existingBackendPool := getTestBackendAddressPoolWithIPs("lb1", "default-svc1", []string{"10.0.0.1"})
 			existingBackendPoolIPv6 := getTestBackendAddressPoolWithIPs("lb1", "default-svc1-ipv6", []string{"fd00::1"})
@@ -611,12 +606,12 @@ func TestCheckAndApplyLocalServiceBackendPoolUpdates(t *testing.T) {
 			cloud.backendPoolUpdater = u
 			go cloud.backendPoolUpdater.run(ctx)
 
-			err := cloud.checkAndApplyLocalServiceBackendPoolUpdates(ctx, existingLB, &svc)
-			if tc.expectedErr != nil {
-				assert.Equal(t, tc.expectedErr, err)
-			} else {
-				assert.NoError(t, err)
+			if tc.existingEPS != nil {
+				_, _ = client.DiscoveryV1().EndpointSlices("default").Create(context.Background(), tc.existingEPS, metav1.CreateOptions{})
 			}
+
+			err := cloud.checkAndApplyLocalServiceBackendPoolUpdates(existingLB, &svc)
+			assert.NoError(t, err)
 			time.Sleep(2 * time.Second)
 		})
 	}