Repository: kubernetes-sigs/cloud-provider-azure
Pull request #9156 (2025-06-06 06:16:32)

chore: Dependabot do not bump go version
<!--  Thanks for sending a pull request!  Here are some tips for you:

1. If this is your first time, please read our contributor guidelines: https://git.k8s.io/community/contributors/guide/first-contribution.md#your-first-contribution and developer guide https://git.k8s.io/community/contributors/devel/development.md#development-guide
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request. For reference on required PR/issue labels, read here:
https://git.k8s.io/community/contributors/devel/sig-release/release.md#issuepr-kind-label
3. Ensure you have added or ran the appropriate tests for your PR: https://git.k8s.io/community/contributors/devel/sig-testing/testing.md
4. If you want *faster* PR reviews, read how: https://git.k8s.io/community/contributors/guide/pull-requests.md#best-practices-for-faster-reviews
5. If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests
-->

#### What type of PR is this?

<!--
Add one of the following kinds:
/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind design

Optionally add one or more of the following kinds if applicable:
/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->

/kind cleanup

#### What this PR does / why we need it:

chore: Dependabot do not bump go version

#### Which issue(s) this PR fixes:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Fixes #

#### Special notes for your reviewer:

#### Does this PR introduce a user-facing change?
<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".

For more information on release notes see: https://git.k8s.io/community/contributors/guide/release-notes.md
-->
```release-note
NONE
```

#### Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.:

<!--
This section can be blank if this pull request does not require a release note.

When adding links which point to resources within git repositories, like
KEPs or supporting documentation, please reference a specific commit and avoid
linking directly to the master branch. This ensures that links reference a
specific point in time, rather than a document that may change over time.

See here for guidance on getting permanent links to files: https://help.github.com/en/articles/getting-permanent-links-to-files

Please use the following format for linking documentation:
- [KEP]: <link>
- [Usage]: <link>
- [Other doc]: <link>
-->
```docs

```


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

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/cloud-provider-azure/pull/9156#" title="Author self-approved">nilo19</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/master/OWNERS)~~ [nilo19]

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":[]} -->

Patch:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 61f1bbbdd..df373d795 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -4,7 +4,7 @@ updates:
     directory: "/"
     open-pull-requests-limit: 1
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -14,6 +14,8 @@ updates:
       - "kind/cleanup"
       - "lgtm"
       - "approved"
+    ignore:
+      - dependency-name: "go"
     groups:
       all:
         applies-to: version-updates
@@ -27,7 +29,7 @@ updates:
     directory: "/tests"
     open-pull-requests-limit: 1
     schedule:
-      interval: daily
+      interval: weekly
       time: "20:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -37,6 +39,8 @@ updates:
       - "kind/cleanup"
       - "lgtm"
       - "approved"
+    ignore:
+      - dependency-name: "go"
     groups:
       all:
         applies-to: version-updates
@@ -50,7 +54,7 @@ updates:
     directory: "/health-probe-proxy"
     open-pull-requests-limit: 1
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -60,6 +64,8 @@ updates:
       - "kind/cleanup"
       - "lgtm"
       - "approved"
+    ignore:
+      - dependency-name: "go"
     groups:
       all:
         applies-to: version-updates
@@ -73,7 +79,7 @@ updates:
     directory: "/kubetest2-aks"
     open-pull-requests-limit: 1
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -83,6 +89,8 @@ updates:
       - "kind/testing"
       - "lgtm"
       - "approved"
+    ignore:
+      - dependency-name: "go"
     groups:
       all:
         applies-to: version-updates
@@ -96,7 +104,7 @@ updates:
     directory: "/pkg/azclient"
     open-pull-requests-limit: 1
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -106,6 +114,8 @@ updates:
       - "kind/testing"
       - "lgtm"
       - "approved"
+    ignore:
+      - dependency-name: "go"
     groups:
       all:
         applies-to: version-updates
@@ -119,7 +129,7 @@ updates:
     directory: "/pkg/azclient/cache"
     open-pull-requests-limit: 1
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -129,6 +139,8 @@ updates:
       - "kind/cleanup"
       - "lgtm"
       - "approved"
+    ignore:
+      - dependency-name: "go"
     groups:
       all:
         applies-to: version-updates
@@ -141,7 +153,7 @@ updates:
   - package-ecosystem: gomod
     directory: /pkg/azclient/client-gen
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -151,6 +163,8 @@ updates:
       - "kind/cleanup"
       - "lgtm"
       - "approved"
+    ignore:
+      - dependency-name: "go"
     groups:
       all:
         applies-to: version-updates
@@ -163,7 +177,7 @@ updates:
   - package-ecosystem: gomod
     directory: /pkg/azclient/configloader
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -173,6 +187,8 @@ updates:
       - "kind/cleanup"
       - "lgtm"
       - "approved"
+    ignore:
+      - dependency-name: "go"
     groups:
       all:
         applies-to: version-updates
@@ -185,7 +201,7 @@ updates:
   - package-ecosystem: gomod
     directory: /pkg/azclient/trace
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -195,6 +211,8 @@ updates:
       - "kind/cleanup"
       - "lgtm"
       - "approved"
+    ignore:
+      - dependency-name: "go"
     groups:
       all:
         applies-to: version-updates
@@ -207,7 +225,7 @@ updates:
   - package-ecosystem: "docker"
     directory: "/"
     schedule:
-      interval: "daily"
+      interval: "weekly"
       time: "01:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -229,7 +247,7 @@ updates:
   - package-ecosystem: "docker"
     directory: "/health-probe-proxy"
     schedule:
-      interval: "daily"
+      interval: "weekly"
       time: "01:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -251,7 +269,7 @@ updates:
   - package-ecosystem: "github-actions"
     directory: "/"
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -275,7 +293,7 @@ updates:
     directory: "/"
     open-pull-requests-limit: 1
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -290,6 +308,7 @@ updates:
     ignore:
       - dependency-name: "k8s.io/*"
         versions: [">=0.34.0"]
+      - dependency-name: "go"
     groups:
       all:
         applies-to: version-updates
@@ -302,7 +321,7 @@ updates:
   - package-ecosystem: "github-actions"
     directory: "/"
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     target-branch: "release-1.33"
@@ -326,7 +345,7 @@ updates:
   - package-ecosystem: "docker"
     directory: "/"
     schedule:
-      interval: "daily"
+      interval: "weekly"
       time: "01:00"
       timezone: "Asia/Shanghai"
     target-branch: "release-1.33"
@@ -351,7 +370,7 @@ updates:
     directory: "/"
     open-pull-requests-limit: 1
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -366,6 +385,7 @@ updates:
     ignore:
       - dependency-name: "k8s.io/*"
         versions: [">=0.33.0"]
+      - dependency-name: "go"
     groups:
       all:
         applies-to: version-updates
@@ -378,7 +398,7 @@ updates:
   - package-ecosystem: "github-actions"
     directory: "/"
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     target-branch: "release-1.32"
@@ -402,7 +422,7 @@ updates:
   - package-ecosystem: "docker"
     directory: "/"
     schedule:
-      interval: "daily"
+      interval: "weekly"
       time: "01:00"
       timezone: "Asia/Shanghai"
     target-branch: "release-1.32"
@@ -427,7 +447,7 @@ updates:
     directory: "/"
     open-pull-requests-limit: 1
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -442,6 +462,7 @@ updates:
     ignore:
       - dependency-name: "k8s.io/*"
         versions: [">=0.31.0"]
+      - dependency-name: "go"
     groups:
       all:
         applies-to: version-updates
@@ -454,7 +475,7 @@ updates:
   - package-ecosystem: "github-actions"
     directory: "/"
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     target-branch: "release-1.30"
@@ -478,7 +499,7 @@ updates:
   - package-ecosystem: "docker"
     directory: "/"
     schedule:
-      interval: "daily"
+      interval: "weekly"
       time: "01:00"
       timezone: "Asia/Shanghai"
     target-branch: "release-1.30"
@@ -503,7 +524,7 @@ updates:
     directory: "/"
     open-pull-requests-limit: 1
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     labels:
@@ -518,6 +539,7 @@ updates:
     ignore:
       - dependency-name: "k8s.io/*"
         versions: [">=0.32.0"]
+      - dependency-name: "go"
     groups:
       all:
         applies-to: version-updates
@@ -530,7 +552,7 @@ updates:
   - package-ecosystem: "github-actions"
     directory: "/"
     schedule:
-      interval: daily
+      interval: weekly
       time: "01:00"
       timezone: "Asia/Shanghai"
     target-branch: "release-1.31"
@@ -554,7 +576,7 @@ updates:
   - package-ecosystem: "docker"
     directory: "/"
     schedule:
-      interval: "daily"
+      interval: "weekly"
       time: "01:00"
       timezone: "Asia/Shanghai"
     target-branch: "release-1.31"
@@ -575,108 +597,3 @@ updates:
         - "patch"
         - "minor"
         - "major"
-  - package-ecosystem: "gomod"
-    directory: "/"
-    open-pull-requests-limit: 1
-    schedule:
-      interval: daily
-      time: "01:00"
-      timezone: "Asia/Shanghai"
-    labels:
-      - "area/dependency"
-      - "release-note-none"
-      - "ok-to-test"
-      - "kind/cleanup"
-      - "lgtm"
-      - "approved"
-      - "release-1.29"
-    target-branch: "release-1.29"
-    ignore:
-      - dependency-name: "k8s.io/*"
-        versions: [">=0.30.0"]
-    groups:
-      all:
-        applies-to: version-updates
-        patterns:
-        - "*"
-        update-types:
-        - "patch"
-        - "minor"
-        - "major"
-  - package-ecosystem: "github-actions"
-    directory: "/"
-    schedule:
-      interval: daily
-      time: "01:00"
-      timezone: "Asia/Shanghai"
-    target-branch: "release-1.29"
-    labels:
-      - "area/dependency"
-      - "release-note-none"
-      - "ok-to-test"
-      - "kind/testing"
-      - "lgtm"
-      - "approved"
-      - "release-1.29"
-    groups:
-      all:
-        applies-to: version-updates
-        patterns:
-        - "*"
-        update-types:
-        - "patch"
-        - "minor"
-        - "major"
-  - package-ecosystem: "docker"
-    directory: "/"
-    schedule:
-      interval: "daily"
-      time: "01:00"
-      timezone: "Asia/Shanghai"
-    target-branch: "release-1.29"
-    labels:
-      - "area/dependency"
-      - "release-note-none"
-      - "ok-to-test"
-      - "kind/cleanup"
-      - "lgtm"
-      - "approved"
-      - "release-1.29"
-    groups:
-      all:
-        applies-to: version-updates
-        patterns:
-        - "*"
-        update-types:
-        - "patch"
-        - "minor"
-        - "major"
-  - package-ecosystem: gomod
-    directory: /
-    schedule:
-      interval: daily
-      time: "01:00"
-      timezone: "Asia/Shanghai"
-    target-branch: "documentation"
-    labels:
-      - "area/dependency"
-      - "release-note-none"
-      - "ok-to-test"
-      - "kind/cleanup"
-      - "lgtm"
-      - "approved"
-
-  - package-ecosystem: npm
-    directory: /
-    schedule:
-      interval: daily
-      time: "01:00"
-      timezone: "Asia/Shanghai"
-    target-branch: "documentation"
-    labels:
-      - "area/dependency"
-      - "release-note-none"
-      - "ok-to-test"
-      - "kind/cleanup"
-      - "lgtm"
-      - "approved"
diff --git a/pkg/provider/azure_loadbalancer.go b/pkg/provider/azure_loadbalancer.go
index 81679821d..4d9bc6662 100644
--- a/pkg/provider/azure_loadbalancer.go
+++ b/pkg/provider/azure_loadbalancer.go
@@ -103,13 +103,13 @@ func (az *Cloud) GetLoadBalancer(ctx context.Context, clusterName string, servic
 		return nil, az.existsPip(ctx, clusterName, service), err
 	}
 
-	_, _, status, _, existsLb, err := az.getServiceLoadBalancer(ctx, service, clusterName, nil, false, existingLBs)
+	_, _, status, _, existsLb, _, err := az.getServiceLoadBalancer(ctx, service, clusterName, nil, false, existingLBs)
 	if err != nil || existsLb {
 		return status, existsLb || az.existsPip(ctx, clusterName, service), err
 	}
 
 	flippedService := flipServiceInternalAnnotation(service)
-	_, _, status, _, existsLb, err = az.getServiceLoadBalancer(ctx, flippedService, clusterName, nil, false, existingLBs)
+	_, _, status, _, existsLb, _, err = az.getServiceLoadBalancer(ctx, flippedService, clusterName, nil, false, existingLBs)
 	if err != nil || existsLb {
 		return status, existsLb || az.existsPip(ctx, clusterName, service), err
 	}
@@ -137,11 +137,19 @@ func (az *Cloud) reconcileService(ctx context.Context, clusterName string, servi
 
 	logger.V(2).Info("Start reconciling Service", "lb", az.GetLoadBalancerName(ctx, clusterName, service))
 
-	lb, err := az.reconcileLoadBalancer(ctx, clusterName, service, nodes, true /* wantLb */)
+	lb, needRetry, err := az.reconcileLoadBalancer(ctx, clusterName, service, nodes, true /* wantLb */)
 	if err != nil {
 		logger.Error(err, "Failed to reconcile LoadBalancer")
 		return nil, err
 	}
+	if needRetry {
+		logger.V(2).Info("Reconciling Service again after deleting PLS, as the LB ETag has changed.")
+		lb, _, err = az.reconcileLoadBalancer(ctx, clusterName, service, nodes, true /* wantLb */)
+		if err != nil {
+			logger.Error(err, "Failed to reconcile LoadBalancer")
+			return nil, err
+		}
+	}
 
 	lbStatus, lbIPsPrimaryPIPs, fipConfigs, err := az.getServiceLoadBalancerStatus(ctx, service, lb)
 	if err != nil {
@@ -157,7 +165,7 @@ func (az *Cloud) reconcileService(ctx context.Context, clusterName string, servi
 	}
 
 	for _, fipConfig := range fipConfigs {
-		if err := az.reconcilePrivateLinkService(ctx, clusterName, service, fipConfig, true /* wantPLS */); err != nil {
+		if _, err := az.reconcilePrivateLinkService(ctx, clusterName, service, fipConfig, true /* wantPLS */); err != nil {
 			logger.Error(err, "Failed to reconcile PrivateLinkService")
 			return nil, err
 		}
@@ -165,7 +173,7 @@ func (az *Cloud) reconcileService(ctx context.Context, clusterName string, servi
 
 	updateService := updateServiceLoadBalancerIPs(service, lbIPsPrimaryPIPs)
 	flippedService := flipServiceInternalAnnotation(updateService)
-	if _, err := az.reconcileLoadBalancer(ctx, clusterName, flippedService, nil, false /* wantLb */); err != nil {
+	if _, _, err := az.reconcileLoadBalancer(ctx, clusterName, flippedService, nil, false /* wantLb */); err != nil {
 		logger.Error(err, "Failed to reconcile flipped LoadBalancer")
 		return nil, err
 	}
@@ -465,7 +473,7 @@ func (az *Cloud) EnsureLoadBalancerDeleted(ctx context.Context, clusterName stri
 		}
 	}()
 
-	lb, _, _, lbIPsPrimaryPIPs, _, err := az.getServiceLoadBalancer(ctx, service, clusterName, nil, false, []*armnetwork.LoadBalancer{})
+	lb, _, _, lbIPsPrimaryPIPs, _, _, err := az.getServiceLoadBalancer(ctx, service, clusterName, nil, false, []*armnetwork.LoadBalancer{})
 	if err != nil && !errutils.HasStatusForbiddenOrIgnoredError(err) {
 		return err
 	}
@@ -475,14 +483,20 @@ func (az *Cloud) EnsureLoadBalancerDeleted(ctx context.Context, clusterName stri
 		return err
 	}
 
-	_, err = az.reconcileLoadBalancer(ctx, clusterName, service, nil, false /* wantLb */)
+	_, needRetry, err := az.reconcileLoadBalancer(ctx, clusterName, service, nil, false /* wantLb */)
 	if err != nil && !errutils.HasStatusForbiddenOrIgnoredError(err) {
 		return err
 	}
+	if needRetry {
+		_, _, err := az.reconcileLoadBalancer(ctx, clusterName, service, nil, false /* wantLb */)
+		if err != nil && !errutils.HasStatusForbiddenOrIgnoredError(err) {
+			return err
+		}
+	}
 
 	// check flipped service also
 	flippedService := flipServiceInternalAnnotation(service)
-	if _, err := az.reconcileLoadBalancer(ctx, clusterName, flippedService, nil, false /* wantLb */); err != nil {
+	if _, _, err := az.reconcileLoadBalancer(ctx, clusterName, flippedService, nil, false /* wantLb */); err != nil {
 		return err
 	}
 
@@ -560,9 +574,9 @@ func (az *Cloud) shouldChangeLoadBalancer(service *v1.Service, currLBName, clust
 // removeFrontendIPConfigurationFromLoadBalancer removes the given ip configs from the load balancer
 // and delete the load balancer if there is no ip config on it. It returns the name of the deleted load balancer
 // and it will be used in reconcileLoadBalancer to remove the load balancer from the list.
-func (az *Cloud) removeFrontendIPConfigurationFromLoadBalancer(ctx context.Context, lb *armnetwork.LoadBalancer, existingLBs []*armnetwork.LoadBalancer, fips []*armnetwork.FrontendIPConfiguration, clusterName string, service *v1.Service) (string, error) {
+func (az *Cloud) removeFrontendIPConfigurationFromLoadBalancer(ctx context.Context, lb *armnetwork.LoadBalancer, existingLBs []*armnetwork.LoadBalancer, fips []*armnetwork.FrontendIPConfiguration, clusterName string, service *v1.Service) (string, bool /* deleted PLS */, error) {
 	if lb == nil || lb.Properties == nil || lb.Properties.FrontendIPConfigurations == nil {
-		return "", nil
+		return "", false, nil
 	}
 	fipConfigs := lb.Properties.FrontendIPConfigurations
 	for i, fipConfig := range fipConfigs {
@@ -600,13 +614,24 @@ func (az *Cloud) removeFrontendIPConfigurationFromLoadBalancer(ctx context.Conte
 	}
 
 	// PLS does not support IPv6 so there will not be additional API calls.
+	var deletedPLS bool
 	for _, fip := range fips {
 		// clean up any private link service associated with the frontEndIPConfig
-		if err := az.reconcilePrivateLinkService(ctx, clusterName, service, fip, false /* wantPLS */); err != nil {
+		var (
+			deleted bool
+			err     error
+		)
+		if deleted, err = az.reconcilePrivateLinkService(ctx, clusterName, service, fip, false /* wantPLS */); err != nil {
 			klog.Errorf("removeFrontendIPConfigurationFromLoadBalancer(%s, %s, %s, %s): failed to clean up PLS: %v", ptr.Deref(lb.Name, ""), ptr.Deref(fip.Name, ""), clusterName, service.Name, err)
-			return "", err
+			return "", false, err
+		}
+		if deleted {
+			deletedPLS = true
 		}
 	}
+	if deletedPLS {
+		return "", true, nil
+	}
 
 	var deletedLBName string
 	fipNames := []string{}
@@ -619,7 +644,7 @@ func (az *Cloud) removeFrontendIPConfigurationFromLoadBalancer(ctx context.Conte
 		err := az.cleanOrphanedLoadBalancer(ctx, lb, existingLBs, service, clusterName)
 		if err != nil {
 			klog.Errorf("%s: failed to cleanupOrphanedLoadBalancer: %v", logPrefix, err)
-			return "", err
+			return "", false, err
 		}
 		deletedLBName = ptr.Deref(lb.Name, "")
 	} else {
@@ -627,11 +652,11 @@ func (az *Cloud) removeFrontendIPConfigurationFromLoadBalancer(ctx context.Conte
 		err := az.CreateOrUpdateLB(ctx, service, *lb)
 		if err != nil {
 			klog.Errorf("%s: failed to CreateOrUpdateLB: %v", logPrefix, err)
-			return "", err
+			return "", false, err
 		}
 		_ = az.lbCache.Delete(ptr.Deref(lb.Name, ""))
 	}
-	return deletedLBName, nil
+	return deletedLBName, false, nil
 }
 
 func (az *Cloud) cleanOrphanedLoadBalancer(ctx context.Context, lb *armnetwork.LoadBalancer, existingLBs []*armnetwork.LoadBalancer, service *v1.Service, clusterName string) error {
@@ -759,7 +784,7 @@ func (az *Cloud) getServiceLoadBalancer(
 	nodes []*v1.Node,
 	wantLb bool,
 	existingLBs []*armnetwork.LoadBalancer,
-) (lb *armnetwork.LoadBalancer, refreshedLBs []*armnetwork.LoadBalancer, status *v1.LoadBalancerStatus, lbIPsPrimaryPIPs []string, exists bool, err error) {
+) (lb *armnetwork.LoadBalancer, refreshedLBs []*armnetwork.LoadBalancer, status *v1.LoadBalancerStatus, lbIPsPrimaryPIPs []string, exists, deletedPLS bool, err error) {
 	logger := log.FromContextOrBackground(ctx)
 
 	isInternal := requiresInternalLoadBalancer(service)
@@ -767,14 +792,14 @@ func (az *Cloud) getServiceLoadBalancer(
 	primaryVMSetName := az.VMSet.GetPrimaryVMSetName()
 	defaultLBName, err := az.getAzureLoadBalancerName(ctx, service, existingLBs, clusterName, primaryVMSetName, isInternal)
 	if err != nil {
-		return nil, nil, nil, nil, false, err
+		return nil, nil, nil, nil, false, false, err
 	}
 
 	// reuse the lb list from reconcileSharedLoadBalancer to reduce the api call
 	if len(existingLBs) == 0 {
 		lbs, err := az.ListLB(ctx, service)
 		if err != nil {
-			return nil, nil, nil, nil, false, err
+			return nil, nil, nil, nil, false, false, err
 		}
 		existingLBs = lbs
 	}
@@ -794,7 +819,7 @@ func (az *Cloud) getServiceLoadBalancer(
 		var fipConfigs []*armnetwork.FrontendIPConfiguration
 		status, lbIPsPrimaryPIPs, fipConfigs, err = az.getServiceLoadBalancerStatus(ctx, service, existingLB)
 		if err != nil {
-			return nil, nil, nil, nil, false, err
+			return nil, nil, nil, nil, false, false, err
 		}
 		if status == nil {
 			// service is not on this load balancer
@@ -814,10 +839,13 @@ func (az *Cloud) getServiceLoadBalancer(
 			for _, fipConfig := range fipConfigs {
 				fipConfigNames = append(fipConfigNames, ptr.Deref(fipConfig.Name, ""))
 			}
-			deletedLBName, err = az.removeFrontendIPConfigurationFromLoadBalancer(ctx, existingLB, existingLBs, fipConfigs, clusterName, service)
+			deletedLBName, deletedPLS, err = az.removeFrontendIPConfigurationFromLoadBalancer(ctx, existingLB, existingLBs, fipConfigs, clusterName, service)
 			if err != nil {
 				logger.Error(err, fmt.Sprintf("getServiceLoadBalancer(%s, %s, %v): failed to remove frontend IP configurations %q from load balancer", service.Name, clusterName, wantLb, fipConfigNames))
-				return nil, nil, nil, nil, false, err
+				return nil, nil, nil, nil, false, false, err
+			}
+			if deletedPLS {
+				return nil, nil, nil, nil, false, true, nil
 			}
 			if deletedLBName != "" {
 				removeLBFromList(&existingLBs, deletedLBName)
@@ -842,7 +870,7 @@ func (az *Cloud) getServiceLoadBalancer(
 					newLBs, err := az.cleanupLocalServiceBackendPool(ctx, service, nodes, existingLBs, clusterName)
 					if err != nil {
 						logger.Error(err, fmt.Sprintf("getServiceLoadBalancer(%s, %s, %v): failed to cleanup backend pool for local service", service.Name, clusterName, wantLb))
-						return nil, nil, nil, nil, false, err
+						return nil, nil, nil, nil, false, false, err
 					}
 					existingLBs = newLBs
 				}
@@ -850,7 +878,7 @@ func (az *Cloud) getServiceLoadBalancer(
 			break
 		}
 
-		return existingLB, existingLBs, status, lbIPsPrimaryPIPs, true, nil
+		return existingLB, existingLBs, status, lbIPsPrimaryPIPs, true, false, nil
 	}
 
 	// Service does not have a load balancer, select one.
@@ -860,10 +888,10 @@ func (az *Cloud) getServiceLoadBalancer(
 		// select new load balancer for service
 		selectedLB, exists, err := az.selectLoadBalancer(ctx, clusterName, service, existingLBs, nodes)
 		if err != nil {
-			return nil, existingLBs, nil, nil, false, err
+			return nil, existingLBs, nil, nil, false, false, err
 		}
 
-		return selectedLB, existingLBs, status, lbIPsPrimaryPIPs, exists, err
+		return selectedLB, existingLBs, status, lbIPsPrimaryPIPs, exists, false, err
 	}
 
 	// If the service moves to a different load balancer, return the one
@@ -871,7 +899,7 @@ func (az *Cloud) getServiceLoadBalancer(
 	if shouldChangeLB {
 		for _, existingLB := range existingLBs {
 			if strings.EqualFold(ptr.Deref(existingLB.Name, ""), defaultLBName) {
-				return existingLB, existingLBs, status, lbIPsPrimaryPIPs, true, nil
+				return existingLB, existingLBs, status, lbIPsPrimaryPIPs, true, false, nil
 			}
 		}
 	}
@@ -900,7 +928,7 @@ func (az *Cloud) getServiceLoadBalancer(
 		}
 	}
 
-	return defaultLB, existingLBs, nil, nil, false, nil
+	return defaultLB, existingLBs, nil, nil, false, false, nil
 }
 
 // selectLoadBalancer selects load balancer for the service in the cluster.
@@ -1778,19 +1806,19 @@ func (az *Cloud) reconcileMultipleStandardLoadBalancerConfigurations(
 // This also reconciles the Service's Ports with the LoadBalancer config.
 // This entails adding rules/probes for expected Ports and removing stale rules/ports.
 // nodes only used if wantLb is true
-func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string, service *v1.Service, nodes []*v1.Node, wantLb bool) (*armnetwork.LoadBalancer, error) {
+func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string, service *v1.Service, nodes []*v1.Node, wantLb bool) (*armnetwork.LoadBalancer, bool /*needRetry*/, error) {
 	isBackendPoolPreConfigured := az.isBackendPoolPreConfigured(service)
 	serviceName := getServiceName(service)
 	klog.V(2).Infof("reconcileLoadBalancer for service(%s) - wantLb(%t): started", serviceName, wantLb)
 
 	existingLBs, err := az.ListManagedLBs(ctx, service, nodes, clusterName)
 	if err != nil {
-		return nil, fmt.Errorf("reconcileLoadBalancer: failed to list managed LB: %w", err)
+		return nil, false, fmt.Errorf("reconcileLoadBalancer: failed to list managed LB: %w", err)
 	}
 
 	if existingLBs, err = az.cleanupBasicLoadBalancer(ctx, clusterName, service, existingLBs); err != nil {
 		klog.ErrorS(err, "reconcileLoadBalancer: failed to check and remove outdated basic load balancers", "service", serviceName)
-		return nil, err
+		return nil, false, err
 	}
 
 	// Delete backend pools for local service if:
@@ -1800,19 +1828,23 @@ func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string,
 		existingLBs, err = az.cleanupLocalServiceBackendPool(ctx, service, nodes, existingLBs, clusterName)
 		if err != nil {
 			klog.Errorf("reconcileLoadBalancer: failed to cleanup local service backend pool for service %q, error: %s", serviceName, err.Error())
-			return nil, err
+			return nil, false, err
 		}
 	}
 
 	if err := az.reconcileMultipleStandardLoadBalancerConfigurations(ctx, existingLBs, service, clusterName, existingLBs, nodes); err != nil {
 		klog.Errorf("reconcileLoadBalancer: failed to reconcile multiple standard load balancer configurations: %s", err.Error())
-		return nil, err
+		return nil, false, err
 	}
 
-	lb, newLBs, lbStatus, _, _, err := az.getServiceLoadBalancer(ctx, service, clusterName, nodes, wantLb, existingLBs)
+	lb, newLBs, lbStatus, _, _, deletedPLS, err := az.getServiceLoadBalancer(ctx, service, clusterName, nodes, wantLb, existingLBs)
 	if err != nil {
 		klog.Errorf("reconcileLoadBalancer: failed to get load balancer for service %q, error: %v", serviceName, err)
-		return nil, err
+		return nil, false, err
+	}
+	if deletedPLS {
+		klog.V(2).InfoS("reconcileLoadBalancer: PLS is deleted and the LB ETag has changed, need to retry", "service", serviceName)
+		return lb, true, nil
 	}
 	existingLBs = newLBs
 
@@ -1836,7 +1868,7 @@ func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string,
 		)
 		preConfig, backendPoolsUpdated, lb, err = az.LoadBalancerBackendPool.ReconcileBackendPools(ctx, clusterName, service, lb)
 		if err != nil {
-			return lb, err
+			return lb, false, err
 		}
 		if backendPoolsUpdated {
 			dirtyLb = true
@@ -1851,7 +1883,7 @@ func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string,
 	// reconcile the load balancer's frontend IP configurations.
 	ownedFIPConfigs, toDeleteConfigs, fipChanged, err := az.reconcileFrontendIPConfigs(ctx, clusterName, service, lb, lbStatus, wantLb, lbFrontendIPConfigNames)
 	if err != nil {
-		return lb, err
+		return lb, false, err
 	}
 	if fipChanged {
 		dirtyLb = true
@@ -1863,7 +1895,7 @@ func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string,
 			continue
 		}
 		if ownedFIPConfig.ID == nil {
-			return nil, fmt.Errorf("reconcileLoadBalancer for service (%s)(%t): nil ID for frontend IP config", serviceName, wantLb)
+			return nil, false, fmt.Errorf("reconcileLoadBalancer for service (%s)(%t): nil ID for frontend IP config", serviceName, wantLb)
 		}
 
 		var isIPv6 bool
@@ -1873,7 +1905,7 @@ func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string,
 			isIPv6 = fipIPVersion == to.Ptr(armnetwork.IPVersionIPv6)
 		} else {
 			if isIPv6, err = az.isFIPIPv6(service, ownedFIPConfig); err != nil {
-				return nil, err
+				return nil, false, err
 			}
 		}
 		lbFrontendIPConfigIDs[isIPv6] = *ownedFIPConfig.ID
@@ -1893,18 +1925,18 @@ func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string,
 	v4Enabled, v6Enabled := getIPFamiliesEnabled(service)
 	if wantLb && v4Enabled {
 		if err = az.checkLoadBalancerResourcesConflicts(lb, lbFrontendIPConfigIDs[false], service); err != nil {
-			return nil, err
+			return nil, false, err
 		}
 		if err := getExpectedLBRule(consts.IPVersionIPv4); err != nil {
-			return nil, err
+			return nil, false, err
 		}
 	}
 	if wantLb && v6Enabled {
 		if err = az.checkLoadBalancerResourcesConflicts(lb, lbFrontendIPConfigIDs[true], service); err != nil {
-			return nil, err
+			return nil, false, err
 		}
 		if err := getExpectedLBRule(consts.IPVersionIPv6); err != nil {
-			return nil, err
+			return nil, false, err
 		}
 	}
 
@@ -1924,9 +1956,10 @@ func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string,
 	// If it is not exist, and no change to that, we don't CreateOrUpdate LB
 	if dirtyLb {
 		if len(toDeleteConfigs) > 0 {
+			var needRetry bool
 			for i := range toDeleteConfigs {
 				fipConfigToDel := toDeleteConfigs[i]
-				err := az.reconcilePrivateLinkService(ctx, clusterName, service, fipConfigToDel, false /* wantPLS */)
+				deletedPLS, err = az.reconcilePrivateLinkService(ctx, clusterName, service, fipConfigToDel, false /* wantPLS */)
 				if err != nil {
 					klog.Errorf(
 						"reconcileLoadBalancer for service(%s): lb(%s) - failed to clean up PrivateLinkService for frontEnd(%s): %v",
@@ -1936,6 +1969,13 @@ func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string,
 						err,
 					)
 				}
+				if deletedPLS {
+					needRetry = true
+				}
+			}
+			if needRetry {
+				klog.V(2).InfoS("reconcileLoadBalancer: PLS is deleted and the LB ETag has changed, need to retry", "service", serviceName)
+				return lb, true, nil
 			}
 		}
 
@@ -1943,24 +1983,24 @@ func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string,
 			err := az.cleanOrphanedLoadBalancer(ctx, lb, existingLBs, service, clusterName)
 			if err != nil {
 				klog.Errorf("reconcileLoadBalancer for service(%s): lb(%s) - failed to cleanOrphanedLoadBalancer: %v", serviceName, lbName, err)
-				return nil, err
+				return nil, false, err
 			}
 		} else {
 			klog.V(2).Infof("reconcileLoadBalancer: reconcileLoadBalancer for service(%s): lb(%s) - updating", serviceName, lbName)
 			err := az.CreateOrUpdateLB(ctx, service, *lb)
 			if err != nil {
 				klog.Errorf("reconcileLoadBalancer for service(%s) abort backoff: lb(%s) - updating: %s", serviceName, lbName, err.Error())
-				return nil, err
+				return nil, false, err
 			}
 
 			// Refresh updated lb which will be used later in other places.
 			newLB, exist, err := az.getAzureLoadBalancer(ctx, lbName, azcache.CacheReadTypeForceRefresh)
 			if err != nil {
 				klog.Errorf("reconcileLoadBalancer for service(%s): getAzureLoadBalancer(%s) failed: %v", serviceName, lbName, err)
-				return nil, err
+				return nil, false, err
 			}
 			if !exist {
-				return nil, fmt.Errorf("load balancer %q not found", lbName)
+				return nil, false, fmt.Errorf("load balancer %q not found", lbName)
 			}
 			lb = newLB
 
@@ -1979,7 +2019,7 @@ func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string,
 		if az.UseMultipleStandardLoadBalancers() {
 			err := az.reconcileMultipleStandardLoadBalancerBackendNodes(ctx, clusterName, lbName, existingLBs, service, nodes, false)
 			if err != nil {
-				return nil, err
+				return nil, false, err
 			}
 		}
 
@@ -1994,7 +2034,7 @@ func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string,
 		}
 		lb, err = az.reconcileBackendPoolHosts(ctx, lb, lbToReconcile, service, nodes, clusterName, vmSetName, lbBackendPoolIDs)
 		if err != nil {
-			return nil, err
+			return nil, false, err
 		}
 	}
 
@@ -2003,7 +2043,7 @@ func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string,
 	}
 
 	klog.V(2).Infof("reconcileLoadBalancer for service(%s): lb(%s) finished", serviceName, lbName)
-	return lb, nil
+	return lb, false, nil
 }
 
 func (az *Cloud) reconcileBackendPoolHosts(
@@ -3190,7 +3230,7 @@ func (az *Cloud) shouldUpdateLoadBalancer(ctx context.Context, clusterName strin
 		return false, fmt.Errorf("shouldUpdateLoadBalancer: failed to list managed load balancers: %w", err)
 	}
 
-	_, _, _, _, existsLb, _ := az.getServiceLoadBalancer(ctx, service, clusterName, nodes, false, existingManagedLBs)
+	_, _, _, _, existsLb, _, _ := az.getServiceLoadBalancer(ctx, service, clusterName, nodes, false, existingManagedLBs)
 	return existsLb && service.ObjectMeta.DeletionTimestamp == nil && service.Spec.Type == v1.ServiceTypeLoadBalancer, nil
 }
 
diff --git a/pkg/provider/azure_privatelinkservice.go b/pkg/provider/azure_privatelinkservice.go
index 08f5efc96..45522aa88 100644
--- a/pkg/provider/azure_privatelinkservice.go
+++ b/pkg/provider/azure_privatelinkservice.go
@@ -46,7 +46,7 @@ func (az *Cloud) reconcilePrivateLinkService(
 	service *v1.Service,
 	fipConfig *armnetwork.FrontendIPConfiguration,
 	wantPLS bool,
-) error {
+) (bool /*deleted PLS*/, error) {
 	isinternal := requiresInternalLoadBalancer(service)
 	_, _, fipIPVersion := az.serviceOwnsFrontendIP(ctx, fipConfig, service)
 	serviceName := getServiceName(service)
@@ -57,7 +57,7 @@ func (az *Cloud) reconcilePrivateLinkService(
 	} else {
 		if isIPv6, err = az.isFIPIPv6(service, fipConfig); err != nil {
 			klog.Errorf("reconcilePrivateLinkService for service(%s): failed to get FIP IP family: %v", serviceName, err)
-			return err
+			return false, err
 		}
 	}
 	createPLS := wantPLS && serviceRequiresPLS(service)
@@ -65,9 +65,9 @@ func (az *Cloud) reconcilePrivateLinkService(
 	if isIPv6 {
 		if isDualStack || !createPLS {
 			klog.V(2).Infof("IPv6 is not supported for private link service, skip reconcilePrivateLinkService for service(%s)", serviceName)
-			return nil
+			return false, nil
 		}
-		return fmt.Errorf("IPv6 is not supported for private link service")
+		return false, fmt.Errorf("IPv6 is not supported for private link service")
 	}
 
 	fipConfigID := fipConfig.ID
@@ -87,21 +87,21 @@ func (az *Cloud) reconcilePrivateLinkService(
 	if createPLS {
 		// Firstly, make sure it's internal service
 		if !isinternal && !consts.IsK8sServiceDisableLoadBalancerFloatingIP(service) {
-			return fmt.Errorf("reconcilePrivateLinkService for service(%s): service requiring private link service must be internal or disable floating ip", serviceName)
+			return false, fmt.Errorf("reconcilePrivateLinkService for service(%s): service requiring private link service must be internal or disable floating ip", serviceName)
 		}
 
 		// Secondly, check if there is a private link service already created
 		existingPLS, err := az.plsRepo.Get(ctx, az.getPLSResourceGroup(service), *fipConfigID, azcache.CacheReadTypeDefault)
 		if err != nil {
 			klog.Errorf("reconcilePrivateLinkService for service(%s): getPrivateLinkService(%s) failed: %v", serviceName, ptr.Deref(fipConfigID, ""), err)
-			return err
+			return false, err
 		}
 
 		exists := !strings.EqualFold(ptr.Deref(existingPLS.ID, ""), consts.PrivateLinkServiceNotExistID)
 		if exists {
 			klog.V(4).Infof("reconcilePrivateLinkService for service(%s): found existing private link service attached(%s)", serviceName, ptr.Deref(existingPLS.Name, ""))
 			if !isManagedPrivateLinkSerivce(existingPLS, clusterName) {
-				return fmt.Errorf(
+				return false, fmt.Errorf(
 					"reconcilePrivateLinkService for service(%s) failed: LB frontend(%s) already has unmanaged private link service(%s)",
 					serviceName,
 					ptr.Deref(fipConfigID, ""),
@@ -112,7 +112,7 @@ func (az *Cloud) reconcilePrivateLinkService(
 			ownerService := getPrivateLinkServiceOwner(existingPLS)
 			if !strings.EqualFold(ownerService, serviceName) {
 				if serviceHasAdditionalConfigs(service) {
-					return fmt.Errorf(
+					return false, fmt.Errorf(
 						"reconcilePrivateLinkService for service(%s) failed: LB frontend(%s) already has existing private link service(%s) owned by service(%s)",
 						serviceName,
 						ptr.Deref(fipConfigID, ""),
@@ -126,7 +126,7 @@ func (az *Cloud) reconcilePrivateLinkService(
 					ptr.Deref(existingPLS.Name, ""),
 					ownerService,
 				)
-				return nil
+				return false, nil
 			}
 		} else {
 			existingPLS.ID = nil
@@ -142,12 +142,12 @@ func (az *Cloud) reconcilePrivateLinkService(
 
 		plsName, err := az.getPrivateLinkServiceName(existingPLS, service, fipConfig)
 		if err != nil {
-			return err
+			return false, err
 		}
 
 		dirtyPLS, err := az.getExpectedPrivateLinkService(ctx, existingPLS, &plsName, &clusterName, service, fipConfig)
 		if err != nil {
-			return err
+			return false, err
 		}
 
 		if dirtyPLS {
@@ -155,20 +155,20 @@ func (az *Cloud) reconcilePrivateLinkService(
 			err := az.disablePLSNetworkPolicy(ctx, service)
 			if err != nil {
 				klog.Errorf("reconcilePrivateLinkService for service(%s) disable PLS network policy failed for pls(%s): %v", serviceName, plsName, err.Error())
-				return err
+				return false, err
 			}
 			existingPLS.Etag = ptr.To("")
 			_, err = az.plsRepo.CreateOrUpdate(ctx, az.getPLSResourceGroup(service), *existingPLS)
 			if err != nil {
 				klog.Errorf("reconcilePrivateLinkService for service(%s) abort backoff: pls(%s) - updating: %s", serviceName, plsName, err.Error())
-				return err
+				return false, err
 			}
 		}
 	} else if !wantPLS {
 		existingPLS, err := az.plsRepo.Get(ctx, az.getPLSResourceGroup(service), *fipConfigID, azcache.CacheReadTypeDefault)
 		if err != nil {
 			klog.Errorf("reconcilePrivateLinkService for service(%s): getPrivateLinkService(%s) failed: %v", serviceName, ptr.Deref(fipConfigID, ""), err)
-			return err
+			return false, err
 		}
 
 		exists := !strings.EqualFold(ptr.Deref(existingPLS.ID, ""), consts.PrivateLinkServiceNotExistID)
@@ -176,14 +176,17 @@ func (az *Cloud) reconcilePrivateLinkService(
 			deleteErr := az.safeDeletePLS(ctx, existingPLS, service)
 			if deleteErr != nil {
 				klog.Errorf("reconcilePrivateLinkService for service(%s): deletePLS for frontEnd(%s) failed: %v", serviceName, ptr.Deref(fipConfigID, ""), err)
-				return deleteErr
+				return false, deleteErr
 			}
+			isOperationSucceeded = true
+			klog.V(2).Infof("reconcilePrivateLinkService for service(%s) finished", serviceName)
+			return true, nil // return true for successfully deleted PLS
 		}
 	}
 
 	isOperationSucceeded = true
 	klog.V(2).Infof("reconcilePrivateLinkService for service(%s) finished", serviceName)
-	return nil
+	return false, nil
 }
 
 func (az *Cloud) getPLSResourceGroup(service *v1.Service) string {


Test patch:
diff --git a/pkg/provider/azure_loadbalancer_test.go b/pkg/provider/azure_loadbalancer_test.go
index d5cd0f5a4..31a4fb740 100644
--- a/pkg/provider/azure_loadbalancer_test.go
+++ b/pkg/provider/azure_loadbalancer_test.go
@@ -1902,7 +1902,7 @@ func TestGetServiceLoadBalancerMultiSLB(t *testing.T) {
 				tc.service.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal
 			}
 
-			lb, lbs, _, _, _, err := cloud.getServiceLoadBalancer(context.TODO(), &tc.service, testClusterName,
+			lb, lbs, _, _, _, _, err := cloud.getServiceLoadBalancer(context.TODO(), &tc.service, testClusterName,
 				[]*v1.Node{}, true, tc.existingLBs)
 			assert.Equal(t, tc.expectedError, err)
 			assert.Equal(t, tc.expectedLB, lb)
@@ -2082,7 +2082,7 @@ func TestGetServiceLoadBalancerCommon(t *testing.T) {
 			}
 			az.LoadBalancerSKU = test.SKU
 			service := test.service
-			lb, _, status, _, exists, err := az.getServiceLoadBalancer(context.TODO(), &service, testClusterName,
+			lb, _, status, _, exists, _, err := az.getServiceLoadBalancer(context.TODO(), &service, testClusterName,
 				clusterResources.nodes, test.wantLB, []*armnetwork.LoadBalancer{})
 			assert.Equal(t, test.expectedLB, lb)
 			if test.expectedStatus != nil {
@@ -2118,7 +2118,7 @@ func TestGetServiceLoadBalancerWithExtendedLocation(t *testing.T) {
 	mockLBsClient := az.NetworkClientFactory.GetLoadBalancerClient().(*mock_loadbalancerclient.MockInterface)
 	mockLBsClient.EXPECT().List(gomock.Any(), "rg").Return(nil, nil)
 
-	lb, _, status, _, exists, err := az.getServiceLoadBalancer(context.TODO(), &service, testClusterName,
+	lb, _, status, _, exists, _, err := az.getServiceLoadBalancer(context.TODO(), &service, testClusterName,
 		clusterResources.nodes, false, []*armnetwork.LoadBalancer{})
 	assert.Equal(t, expectedLB, lb, "GetServiceLoadBalancer shall return a default LB with expected location.")
 	assert.Nil(t, status, "GetServiceLoadBalancer: Status should be nil for default LB.")
@@ -2141,7 +2141,7 @@ func TestGetServiceLoadBalancerWithExtendedLocation(t *testing.T) {
 	mockLBsClient = az.NetworkClientFactory.GetLoadBalancerClient().(*mock_loadbalancerclient.MockInterface)
 	mockLBsClient.EXPECT().List(gomock.Any(), "rg").Return(nil, nil)
 
-	lb, _, status, _, exists, err = az.getServiceLoadBalancer(context.TODO(), &service, testClusterName,
+	lb, _, status, _, exists, _, err = az.getServiceLoadBalancer(context.TODO(), &service, testClusterName,
 		clusterResources.nodes, true, []*armnetwork.LoadBalancer{})
 	assert.Equal(t, *expectedLB, *lb, "GetServiceLoadBalancer shall return a new LB with expected location.")
 	assert.Nil(t, status, "GetServiceLoadBalancer: Status should be nil for new LB.")
@@ -4043,7 +4043,7 @@ func TestReconcileLoadBalancerCommon(t *testing.T) {
 			mockPLSRepo := az.plsRepo.(*privatelinkservice.MockRepository)
 			mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil).AnyTimes()
 
-			lb, rerr := az.reconcileLoadBalancer(context.TODO(), "testCluster", &service, clusterResources.nodes, test.wantLb)
+			lb, _, rerr := az.reconcileLoadBalancer(context.TODO(), "testCluster", &service, clusterResources.nodes, test.wantLb)
 			if test.expectedError != nil {
 				assert.EqualError(t, rerr, test.expectedError.Error())
 			} else {
@@ -6340,7 +6340,7 @@ func TestRemoveFrontendIPConfigurationFromLoadBalancerDelete(t *testing.T) {
 		mockPLSRepo := cloud.plsRepo.(*privatelinkservice.MockRepository)
 		mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil)
 		existingLBs := []*armnetwork.LoadBalancer{{Name: ptr.To("lb")}}
-		_, err := cloud.removeFrontendIPConfigurationFromLoadBalancer(context.TODO(), lb, existingLBs, []*armnetwork.FrontendIPConfiguration{fip}, "testCluster", &service)
+		_, _, err := cloud.removeFrontendIPConfigurationFromLoadBalancer(context.TODO(), lb, existingLBs, []*armnetwork.FrontendIPConfiguration{fip}, "testCluster", &service)
 		assert.NoError(t, err)
 	})
 }
@@ -6371,7 +6371,7 @@ func TestRemoveFrontendIPConfigurationFromLoadBalancerUpdate(t *testing.T) {
 		mockLBClient.EXPECT().CreateOrUpdate(gomock.Any(), "rg", "lb", gomock.Any()).Return(nil, nil)
 		mockPLSRepo := cloud.plsRepo.(*privatelinkservice.MockRepository)
 		mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil)
-		_, err := cloud.removeFrontendIPConfigurationFromLoadBalancer(context.TODO(), lb, []*armnetwork.LoadBalancer{}, []*armnetwork.FrontendIPConfiguration{fip}, "testCluster", &service)
+		_, _, err := cloud.removeFrontendIPConfigurationFromLoadBalancer(context.TODO(), lb, []*armnetwork.LoadBalancer{}, []*armnetwork.FrontendIPConfiguration{fip}, "testCluster", &service)
 		assert.NoError(t, err)
 	})
 }
diff --git a/pkg/provider/azure_privatelinkservice_test.go b/pkg/provider/azure_privatelinkservice_test.go
index 6c8292764..0f302940b 100644
--- a/pkg/provider/azure_privatelinkservice_test.go
+++ b/pkg/provider/azure_privatelinkservice_test.go
@@ -53,6 +53,7 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 		expectedPLS       *armnetwork.PrivateLinkService
 		expectedPLSDelete bool
 		expectedError     bool
+		expectedDeleted   bool // new field to test the deleted PLS return value
 	}{
 		{
 			desc:    "reconcilePrivateLinkService should do nothing if service does not create any PLS",
@@ -318,6 +319,42 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 				},
 			},
 			expectedPLSDelete: true,
+			expectedDeleted:   true, // PLS should be successfully deleted
+		},
+		{
+			desc: "reconcilePrivateLinkService should delete existing PLS when wantPLS is false",
+			annotations: map[string]string{
+				consts.ServiceAnnotationPLSCreation:          "true",
+				consts.ServiceAnnotationLoadBalancerInternal: "true",
+				consts.ServiceAnnotationPLSName:              "testpls",
+			},
+			wantPLS:         false, // This is the key - we don't want PLS anymore
+			expectedPLSList: true,
+			existingPLSList: []*armnetwork.PrivateLinkService{
+				{
+					Name: ptr.To("testpls"),
+					Properties: &armnetwork.PrivateLinkServiceProperties{
+						LoadBalancerFrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{{ID: ptr.To("fipConfigID")}},
+					},
+					Tags: map[string]*string{
+						consts.ClusterNameTagKey:  ptr.To(testClusterName),
+						consts.OwnerServiceTagKey: ptr.To("default/test"),
+					},
+				},
+			},
+			expectedPLSDelete: true,
+			expectedDeleted:   true, // PLS should be successfully deleted and return true
+		},
+		{
+			desc: "reconcilePrivateLinkService should return false when wantPLS is false but no PLS exists",
+			annotations: map[string]string{
+				consts.ServiceAnnotationPLSCreation:          "true",
+				consts.ServiceAnnotationLoadBalancerInternal: "true",
+			},
+			wantPLS:         false, // We don't want PLS
+			expectedPLSList: true,
+			existingPLSList: []*armnetwork.PrivateLinkService{}, // No existing PLS
+			expectedDeleted: false,                              // Should return false since nothing was deleted
 		},
 	}
 	for _, test := range testCases {
@@ -362,8 +399,9 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 			if test.expectedPLSDelete {
 				mockPLSRepo.EXPECT().Delete(gomock.Any(), "rg", "testpls", *fipConfig.ID).Return(nil).Times(1)
 			}
-			err := az.reconcilePrivateLinkService(context.TODO(), clusterName, &service, fipConfig, test.wantPLS)
+			deleted, err := az.reconcilePrivateLinkService(context.TODO(), clusterName, &service, fipConfig, test.wantPLS)
 			assert.Equal(t, test.expectedError, err != nil, "error: %v", err)
+			assert.Equal(t, test.expectedDeleted, deleted, "expected deleted PLS return value mismatch")
 		})
 	}
 }
diff --git a/pkg/provider/azure_test.go b/pkg/provider/azure_test.go
index 6d9c613da..d5362ac34 100644
--- a/pkg/provider/azure_test.go
+++ b/pkg/provider/azure_test.go
@@ -118,7 +118,7 @@ func TestAddPort(t *testing.T) {
 
 	mockPLSRepo := az.plsRepo.(*privatelinkservice.MockRepository)
 	mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil).AnyTimes()
-	lb, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
+	lb, _, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
 	assert.Nil(t, err)
 
 	// ensure we got a frontend ip configuration
@@ -501,7 +501,7 @@ func TestReconcileLoadBalancerAddServiceOnInternalSubnet(t *testing.T) {
 	}).AnyTimes()
 	mockLBBackendPool.EXPECT().EnsureHostsInPool(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
 
-	lb, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
+	lb, _, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
 	assert.Nil(t, err)
 
 	// ensure we got 2 frontend ip configurations
@@ -534,7 +534,7 @@ func TestReconcileLoadBalancerAddServicesOnMultipleSubnets(t *testing.T) {
 	mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil)
 
 	// svc1 is using LB without "-internal" suffix
-	lb, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc1, clusterResources.nodes, true /* wantLb */)
+	lb, _, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc1, clusterResources.nodes, true /* wantLb */)
 	if err != nil {
 		t.Errorf("Unexpected error reconciling svc1: %q", err)
 	}
@@ -551,7 +551,7 @@ func TestReconcileLoadBalancerAddServicesOnMultipleSubnets(t *testing.T) {
 	setMockLBsDualStack(az, &expectedLBs, "service", 1, 2, true)
 
 	// svc2 is using LB with "-internal" suffix
-	lb, err = az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc2, clusterResources.nodes, true /* wantLb */)
+	lb, _, err = az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc2, clusterResources.nodes, true /* wantLb */)
 	if err != nil {
 		t.Errorf("Unexpected error reconciling svc2: %q", err)
 	}
@@ -587,7 +587,7 @@ func TestReconcileLoadBalancerEditServiceSubnet(t *testing.T) {
 	mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil).AnyTimes()
 	az.plsRepo = mockPLSRepo
 
-	lb, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
+	lb, _, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
 	if err != nil {
 		t.Errorf("Unexpected error reconciling initial svc: %q", err)
 	}
@@ -600,7 +600,7 @@ func TestReconcileLoadBalancerEditServiceSubnet(t *testing.T) {
 	expectedLBs = make([]*armnetwork.LoadBalancer, 0)
 	setMockLBsDualStack(az, &expectedLBs, "service", 1, 1, true)
 
-	lb, err = az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
+	lb, _, err = az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
 	if err != nil {
 		t.Errorf("Unexpected error reconciling edits to svc: %q", err)
 	}
@@ -635,7 +635,7 @@ func TestReconcileLoadBalancerNodeHealth(t *testing.T) {
 	mockPLSRepo := az.plsRepo.(*privatelinkservice.MockRepository)
 	mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil).AnyTimes()
 
-	lb, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
+	lb, _, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
 	assert.Nil(t, err)
 
 	// ensure we got a frontend ip configuration
@@ -666,7 +666,7 @@ func TestReconcileLoadBalancerRemoveService(t *testing.T) {
 	mockPLSRepo := az.plsRepo.(*privatelinkservice.MockRepository)
 	mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil).AnyTimes()
 
-	_, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
+	_, _, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
 	assert.Nil(t, err)
 
 	expectedLBs[0].Properties.FrontendIPConfigurations = []*armnetwork.FrontendIPConfiguration{}
@@ -675,7 +675,7 @@ func TestReconcileLoadBalancerRemoveService(t *testing.T) {
 	mockLBsClient.EXPECT().Get(gomock.Any(), az.ResourceGroup, expectedLBs[0].Name, gomock.Any()).Return(expectedLBs[0], nil).MaxTimes(2)
 	mockLBsClient.EXPECT().List(gomock.Any(), az.ResourceGroup).Return(expectedLBs, nil).MaxTimes(3)
 
-	lb, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, false /* wantLb */)
+	lb, _, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, false /* wantLb */)
 	assert.Nil(t, err)
 
 	// ensure we abandoned the frontend ip configuration
@@ -707,7 +707,7 @@ func TestReconcileLoadBalancerRemoveAllPortsRemovesFrontendConfig(t *testing.T)
 	mockPLSRepo := az.plsRepo.(*privatelinkservice.MockRepository)
 	mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil).AnyTimes()
 
-	lb, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
+	lb, _, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
 	assert.Nil(t, err)
 	validateLoadBalancer(t, az, lb, svc)
 
@@ -719,7 +719,7 @@ func TestReconcileLoadBalancerRemoveAllPortsRemovesFrontendConfig(t *testing.T)
 	mockLBsClient.EXPECT().Get(gomock.Any(), az.ResourceGroup, expectedLBs[0].Name, gomock.Any()).Return(expectedLBs[0], nil).MaxTimes(2)
 	mockLBsClient.EXPECT().List(gomock.Any(), az.ResourceGroup).Return(expectedLBs, nil).MaxTimes(3)
 
-	lb, err = az.reconcileLoadBalancer(context.TODO(), testClusterName, &svcUpdated, clusterResources.nodes, false /* wantLb*/)
+	lb, _, err = az.reconcileLoadBalancer(context.TODO(), testClusterName, &svcUpdated, clusterResources.nodes, false /* wantLb*/)
 	assert.Nil(t, err)
 
 	// ensure we abandoned the frontend ip configuration
@@ -747,13 +747,13 @@ func TestReconcileLoadBalancerRemovesPort(t *testing.T) {
 	expectedLBs := make([]*armnetwork.LoadBalancer, 0)
 	setMockLBsDualStack(az, &expectedLBs, "service", 1, 1, false)
 	svc := getTestServiceDualStack("service1", v1.ProtocolTCP, nil, 80, 443)
-	_, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
+	_, _, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
 	assert.Nil(t, err)
 
 	expectedLBs = make([]*armnetwork.LoadBalancer, 0)
 	setMockLBsDualStack(az, &expectedLBs, "service", 1, 1, false)
 	svcUpdated := getTestServiceDualStack("service1", v1.ProtocolTCP, nil, 80)
-	lb, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svcUpdated, clusterResources.nodes, true /* wantLb */)
+	lb, _, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svcUpdated, clusterResources.nodes, true /* wantLb */)
 	assert.Nil(t, err)
 
 	validateLoadBalancer(t, az, lb, svcUpdated)
@@ -783,12 +783,12 @@ func TestReconcileLoadBalancerMultipleServices(t *testing.T) {
 	mockPLSRepo := az.plsRepo.(*privatelinkservice.MockRepository)
 	mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil).AnyTimes()
 
-	_, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc1, clusterResources.nodes, true /* wantLb */)
+	_, _, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc1, clusterResources.nodes, true /* wantLb */)
 	assert.Nil(t, err)
 
 	setMockLBsDualStack(az, &expectedLBs, "service", 1, 2, false)
 
-	updatedLoadBalancer, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc2, clusterResources.nodes, true /* wantLb */)
+	updatedLoadBalancer, _, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc2, clusterResources.nodes, true /* wantLb */)
 	assert.Nil(t, err)
 
 	validateLoadBalancer(t, az, updatedLoadBalancer, svc1, svc2)
@@ -845,7 +845,7 @@ func TestServiceDefaultsToNoSessionPersistence(t *testing.T) {
 	}).AnyTimes()
 	mockLBBackendPool.EXPECT().EnsureHostsInPool(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
 
-	lb, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
+	lb, _, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
 	if err != nil {
 		t.Errorf("Unexpected error reconciling svc1: %q", err)
 	}
@@ -905,7 +905,7 @@ func TestServiceRespectsNoSessionAffinity(t *testing.T) {
 	}).AnyTimes()
 	mockLBBackendPool.EXPECT().EnsureHostsInPool(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
 
-	lb, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
+	lb, _, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
 	if err != nil {
 		t.Errorf("Unexpected error reconciling svc1: %q", err)
 	}
@@ -966,7 +966,7 @@ func TestServiceRespectsClientIPSessionAffinity(t *testing.T) {
 	}).AnyTimes()
 	mockLBBackendPool.EXPECT().EnsureHostsInPool(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
 
-	lb, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
+	lb, _, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
 	if err != nil {
 		t.Errorf("Unexpected error reconciling svc1: %q", err)
 	}
diff --git a/tests/go.mod b/tests/go.mod
index b6df59de8..e6258c045 100644
--- a/tests/go.mod
+++ b/tests/go.mod
@@ -1,11 +1,12 @@
 module sigs.k8s.io/cloud-provider-azure/tests
 
-go 1.24
+go 1.24.0
+
 toolchain go1.24.1
 
 require (
-	github.com/Azure/azure-kusto-go/azkustodata v1.0.2
-	github.com/Azure/azure-kusto-go/azkustoingest v1.0.2
+	github.com/Azure/azure-kusto-go/azkustodata v1.0.3
+	github.com/Azure/azure-kusto-go/azkustoingest v1.0.3
 	github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.4.0
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerregistry/armcontainerregistry v1.2.0
@@ -14,14 +15,14 @@ require (
 	github.com/onsi/ginkgo/v2 v2.23.4
 	github.com/onsi/gomega v1.37.0
 	github.com/stretchr/testify v1.10.0
-	k8s.io/api v0.33.0
-	k8s.io/apimachinery v0.33.0
-	k8s.io/client-go v0.33.0
-	k8s.io/cloud-provider v0.33.0
+	k8s.io/api v0.33.1
+	k8s.io/apimachinery v0.33.1
+	k8s.io/client-go v0.33.1
+	k8s.io/cloud-provider v0.33.1
 	k8s.io/klog/v2 v2.130.1
 	k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e
 	sigs.k8s.io/cloud-provider-azure v0.0.0-00010101000000-000000000000
-	sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.6.2
+	sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.8.2
 )
 
 require (
@@ -77,7 +78,7 @@ require (
 	github.com/prometheus/client_model v0.6.1 // indirect
 	github.com/prometheus/common v0.62.0 // indirect
 	github.com/prometheus/procfs v0.15.1 // indirect
-	github.com/samber/lo v1.49.1 // indirect
+	github.com/samber/lo v1.50.0 // indirect
 	github.com/shopspring/decimal v1.4.0 // indirect
 	github.com/spf13/cobra v1.9.1 // indirect
 	github.com/spf13/pflag v1.0.6 // indirect
@@ -90,13 +91,13 @@ require (
 	go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
 	go.opentelemetry.io/otel/trace v1.35.0 // indirect
 	go.uber.org/automaxprocs v1.6.0 // indirect
-	go.uber.org/mock v0.5.1 // indirect
+	go.uber.org/mock v0.5.2 // indirect
 	golang.org/x/crypto v0.36.0 // indirect
 	golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
 	golang.org/x/net v0.38.0 // indirect
 	golang.org/x/oauth2 v0.27.0 // indirect
-	golang.org/x/sync v0.13.0 // indirect
-	golang.org/x/sys v0.32.0 // indirect
+	golang.org/x/sync v0.14.0 // indirect
+	golang.org/x/sys v0.33.0 // indirect
 	golang.org/x/term v0.30.0 // indirect
 	golang.org/x/text v0.24.0 // indirect
 	golang.org/x/time v0.11.0 // indirect
@@ -105,10 +106,10 @@ require (
 	gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
-	k8s.io/component-base v0.33.0 // indirect
-	k8s.io/component-helpers v0.33.0 // indirect
+	k8s.io/component-base v0.33.1 // indirect
+	k8s.io/component-helpers v0.33.1 // indirect
 	k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
-	sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.5.2 // indirect
+	sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.5.3 // indirect
 	sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
 	sigs.k8s.io/randfill v1.0.0 // indirect
 	sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
diff --git a/tests/go.sum b/tests/go.sum
index 3ad62c2e5..5953f0d09 100644
--- a/tests/go.sum
+++ b/tests/go.sum
@@ -1,7 +1,7 @@
-github.com/Azure/azure-kusto-go/azkustodata v1.0.2 h1:4SUtoUTgPFRn0dd6IkS7bdQj048TPu40JfkyOM07AII=
-github.com/Azure/azure-kusto-go/azkustodata v1.0.2/go.mod h1:78h24leam8Qh/qHmboHHW1du6mwtAr/6o5EMB5iOci0=
-github.com/Azure/azure-kusto-go/azkustoingest v1.0.2 h1:zdHrxzVYG5W34s2SYYWWi0gCF7oXmQaRGubsVu7g5D4=
-github.com/Azure/azure-kusto-go/azkustoingest v1.0.2/go.mod h1:jdeDwLZSMyK4rQ2pfvO0SEaCaWqe0Bmuoh4lOLED/Wc=
+github.com/Azure/azure-kusto-go/azkustodata v1.0.3 h1:7RZmg7TsMLqcJHD4Ktzbg5Wx1IOjXqU/2NV6yx5CYKk=
+github.com/Azure/azure-kusto-go/azkustodata v1.0.3/go.mod h1:78h24leam8Qh/qHmboHHW1du6mwtAr/6o5EMB5iOci0=
+github.com/Azure/azure-kusto-go/azkustoingest v1.0.3 h1:nukuK1f/IDrIdu3PHbPBS9zOtUNHuKp7+GXd7W+QuB8=
+github.com/Azure/azure-kusto-go/azkustoingest v1.0.3/go.mod h1:YhgxEcTty1N4AaxeGsCZI6mhTM9LlwSWr+6S81VcqRQ=
 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U=
 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 h1:OVoM452qUFBrX+URdH3VpR299ma4kfom0yB0URYky9g=
@@ -163,8 +163,8 @@ github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRl
 github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
 github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
-github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
+github.com/samber/lo v1.50.0 h1:XrG0xOeHs+4FQ8gJR97zDz5uOFMW7OwFWiFVzqopKgY=
+github.com/samber/lo v1.50.0/go.mod h1:RjZyNk6WSnUFRKK6EyOhsRJMqft3G+pg7dCWHQCWvsc=
 github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
 github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
 github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
@@ -201,8 +201,8 @@ go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
 go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
 go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
 go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
-go.uber.org/mock v0.5.1 h1:ASgazW/qBmR+A32MYFDB6E2POoTgOwT509VP0CT/fjs=
-go.uber.org/mock v0.5.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
+go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
+go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
 go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
 go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
 go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
@@ -227,14 +227,14 @@ golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
-golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
+golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
-golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
 golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -266,28 +266,28 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU=
-k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM=
-k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ=
-k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
-k8s.io/client-go v0.33.0 h1:UASR0sAYVUzs2kYuKn/ZakZlcs2bEHaizrrHUZg0G98=
-k8s.io/client-go v0.33.0/go.mod h1:kGkd+l/gNGg8GYWAPr0xF1rRKvVWvzh9vmZAMXtaKOg=
-k8s.io/cloud-provider v0.33.0 h1:nVU2Q9QK7O50yaNx+pE61oDPqflsSsKygN43f5js9+I=
-k8s.io/cloud-provider v0.33.0/go.mod h1:2reyEBbsimZJKHF325vxLBD5fcJGNeJHeLjJ+jGM8Qg=
-k8s.io/component-base v0.33.0 h1:Ot4PyJI+0JAD9covDhwLp9UNkUja209OzsJ4FzScBNk=
-k8s.io/component-base v0.33.0/go.mod h1:aXYZLbw3kihdkOPMDhWbjGCO6sg+luw554KP51t8qCU=
-k8s.io/component-helpers v0.33.0 h1:0AdW0A0mIgljLgtG0hJDdJl52PPqTrtMgOgtm/9i/Ys=
-k8s.io/component-helpers v0.33.0/go.mod h1:9SRiXfLldPw9lEEuSsapMtvT8j/h1JyFFapbtybwKvU=
+k8s.io/api v0.33.1 h1:tA6Cf3bHnLIrUK4IqEgb2v++/GYUtqiu9sRVk3iBXyw=
+k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw=
+k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
+k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
+k8s.io/client-go v0.33.1 h1:ZZV/Ks2g92cyxWkRRnfUDsnhNn28eFpt26aGc8KbXF4=
+k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA=
+k8s.io/cloud-provider v0.33.1 h1:nOmby9fIKCBJr9fNKXpLK5IBbS1snX82+JIxfxGvhI8=
+k8s.io/cloud-provider v0.33.1/go.mod h1:2lvWqPsvBOzbtGWjGfVDX/ttpvSeI9ZdB8d4TbYnt9s=
+k8s.io/component-base v0.33.1 h1:EoJ0xA+wr77T+G8p6T3l4efT2oNwbqBVKR71E0tBIaI=
+k8s.io/component-base v0.33.1/go.mod h1:guT/w/6piyPfTgq7gfvgetyXMIh10zuXA6cRRm3rDuY=
+k8s.io/component-helpers v0.33.1 h1:DdQMww8jOr+sGhIrkz70Lp9Qerq/JzeZDBRd508DHDo=
+k8s.io/component-helpers v0.33.1/go.mod h1:LQwxW5L3dH7341Unj+phndJu0Ic5UjxA//7FT8YVP5U=
 k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
 k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
 k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
 k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
 k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro=
 k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
-sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.6.2 h1:9vsKWUUg5ZPrgx1OTvuJ+tbXU5zt2nOhEt7T1ZlmQ+U=
-sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.6.2/go.mod h1:QFx8YimjDv3fcvpJ1vGey5i8ZDOYmUXWAP1XV9eLVlg=
-sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.5.2 h1:jjFJF0PmS9IHLokD41mM6RVoqQF3BQtVDmQd6ZMnN6E=
-sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.5.2/go.mod h1:7DdZ9ipIsmPLpBlfT4gueejcUlJBZQKWhdljQE5SKvc=
+sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.8.2 h1:O+AgJ/e4t7xQiAbZlwoZTUONeFhMUOfuynTWjYuGBU0=
+sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.8.2/go.mod h1:2LFS9udLmEoJ3vjUNpyzmfRRszdwPHTQNuiJNUH8JPI=
+sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.5.3 h1:PiQy1U20uPkBgdpbERnX3BZ4bB6tljBJKU9wXmn1GrI=
+sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.5.3/go.mod h1:eBK7J+xfuzLATTK5ALuERxsZv7O4kncWnCW5ILCLX0w=
 sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
 sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
 sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=