Repository: kubernetes-sigs/cloud-provider-azure
Pull request #8420 (2025-02-24 07:55:08)

[release-1.32] Refactor: send patch vm requests to channel
This is an automated cherry-pick of #8268

/assign feiskyer

```release-note
Fetch async update result as soon as the vm update operation id is returned.
```

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

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/cloud-provider-azure/pull/8420#" title="Author self-approved">k8s-infra-cherrypick-robot</a>*
**Once this PR has been reviewed and has the lgtm label**, please assign [lzhecheng](https://github.com/lzhecheng) for approval. For more information see [the Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

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).

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

- **[OWNERS](https://github.com/kubernetes-sigs/cloud-provider-azure/blob/release-1.32/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":["lzhecheng"]} -->
MartinForReal: /lgtm
/approve
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/8420#" title="Author self-approved">k8s-infra-cherrypick-robot</a>*, *<a href="https://github.com/kubernetes-sigs/cloud-provider-azure/pull/8420#issuecomment-2677735336" title="Approved">MartinForReal</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.32/OWNERS)~~ [MartinForReal]

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: /kind feature

Patch:
diff --git a/pkg/provider/azure_vmss.go b/pkg/provider/azure_vmss.go
index 284b1e041..114f34efc 100644
--- a/pkg/provider/azure_vmss.go
+++ b/pkg/provider/azure_vmss.go
@@ -25,13 +25,13 @@ import (
 	"strings"
 	"sync"
 	"sync/atomic"
+	"time"
 
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
 	"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
 	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6"
 	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
 	"github.com/samber/lo"
-	"golang.org/x/sync/errgroup"
-
 	v1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/types"
 	utilerrors "k8s.io/apimachinery/pkg/util/errors"
@@ -1452,40 +1452,29 @@ func (ss *ScaleSet) ensureHostsInPool(ctx context.Context, service *v1.Service,
 		meta := meta
 		update := update
 		hostUpdates = append(hostUpdates, func() error {
-			ctx, cancel := getContextWithCancel()
-			defer cancel()
-
 			logFields := []interface{}{
 				"operation", "EnsureHostsInPool UpdateVMSSVMs",
 				"vmssName", meta.vmssName,
 				"resourceGroup", meta.resourceGroup,
 				"backendPoolID", backendPoolID,
 			}
-
+			logger := klog.LoggerWithValues(klog.FromContext(ctx), logFields...)
 			batchSize, err := ss.VMSSBatchSize(ctx, meta.vmssName)
 			if err != nil {
-				klog.ErrorS(err, "Failed to get vmss batch size", logFields...)
+				logger.Error(err, "Failed to get vmss batch size")
 				return err
 			}
+			ctx = klog.NewContext(ctx, logger)
 
-			klog.V(2).InfoS("Begin to update VMs for VMSS with new backendPoolID", logFields...)
-			grp, ctx := errgroup.WithContext(ctx)
-			grp.SetLimit(batchSize)
-			for instanceID, vm := range update {
-				instanceID := instanceID
-				vm := vm
-				grp.Go(func() error {
-					_, rerr := ss.ComputeClientFactory.GetVirtualMachineScaleSetVMClient().Update(ctx, meta.resourceGroup, meta.vmssName, instanceID, vm)
-					return rerr
-				})
-			}
-			rerr := grp.Wait()
-			if rerr != nil {
-				klog.ErrorS(err, "Failed to update VMs for VMSS", logFields...)
-				return rerr
-			}
+			errChan := ss.UpdateVMSSVMsInBatch(ctx, meta, update, batchSize)
 
-			return nil
+			errs := make([]error, 0)
+			for err := range errChan {
+				if err != nil {
+					errs = append(errs, err)
+				}
+			}
+			return utilerrors.NewAggregate(errs)
 		})
 	}
 	errs := utilerrors.AggregateGoroutines(hostUpdates...)
@@ -1955,18 +1944,15 @@ func (ss *ScaleSet) ensureBackendPoolDeleted(ctx context.Context, service *v1.Se
 				klog.ErrorS(err, "Failed to get vmss batch size", logFields...)
 				return err
 			}
-			grp, ctx := errgroup.WithContext(ctx)
-			grp.SetLimit(batchSize)
-			for instanceID, vm := range update {
-				instanceID := instanceID
-				vm := vm
-				grp.Go(func() error {
-					klog.V(2).InfoS("Begin to update VMs for VMSS with new backendPoolID", logFields...)
-					_, rerr := ss.ComputeClientFactory.GetVirtualMachineScaleSetVMClient().Update(ctx, meta.resourceGroup, meta.vmssName, instanceID, vm)
-					return rerr
-				})
+
+			errChan := ss.UpdateVMSSVMsInBatch(ctx, meta, update, batchSize)
+			errs := make([]error, 0)
+			for err := range errChan {
+				if err != nil {
+					errs = append(errs, err)
+				}
 			}
-			err = grp.Wait()
+			err = utilerrors.NewAggregate(errs)
 			if err != nil {
 				klog.ErrorS(err, "Failed to update VMs for VMSS", logFields...)
 				return err
@@ -2359,3 +2345,90 @@ func (ss *ScaleSet) VMSSBatchSize(ctx context.Context, vmssName string) (int, er
 	klog.V(2).InfoS("Fetch VMSS batch size", "vmss", vmssName, "size", batchSize)
 	return batchSize, nil
 }
+
+func (ss *ScaleSet) UpdateVMSSVMsInBatch(ctx context.Context, meta vmssMetaInfo, update map[string]armcompute.VirtualMachineScaleSetVM, batchSize int) <-chan error {
+	logger := klog.FromContext(ctx)
+	patchVMFn := func(ctx context.Context, instanceID string, vm *armcompute.VirtualMachineScaleSetVM) (*runtime.Poller[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse], error) {
+		return ss.ComputeClientFactory.GetVirtualMachineScaleSetVMClient().BeginUpdate(ctx, meta.resourceGroup, meta.vmssName, instanceID, *vm, &armcompute.VirtualMachineScaleSetVMsClientBeginUpdateOptions{
+			IfMatch: vm.Etag,
+		})
+	}
+	ctx, cancel := context.WithCancel(ctx)
+	defer cancel()
+	errChan := make(chan error, len(update))
+	pollerChannel := make(chan *runtime.Poller[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse], len(update))
+	var pollerGroup sync.WaitGroup
+	pollerGroup.Add(1)
+	go func() {
+		defer pollerGroup.Done()
+		for {
+			select {
+			case poller, ok := <-pollerChannel:
+				if !ok {
+					// pollerChannel is closed
+					return
+				}
+				if poller == nil {
+					continue
+				}
+				pollerGroup.Add(1)
+				go func() {
+					defer pollerGroup.Done()
+					_, err := poller.PollUntilDone(ctx, &runtime.PollUntilDoneOptions{
+						Frequency: 10 * time.Second,
+					})
+					if err != nil {
+						logger.Error(err, "Failed to update VMs for VMSS with new vm config")
+						errChan <- err
+					}
+				}()
+			case <-ctx.Done():
+				return
+			}
+		}
+	}()
+	// logger.Info("Begin to update VMs for VMSS with new vm config")
+	if batchSize > 1 {
+		concurrentLock := make(chan struct{}, batchSize)
+		var requestGroup sync.WaitGroup
+		for instanceID, vm := range update {
+			instanceID := instanceID
+			vm := vm
+			concurrentLock <- struct{}{}
+			requestGroup.Add(1)
+			go func() {
+				defer func() {
+					requestGroup.Done()
+					<-concurrentLock
+				}()
+				poller, rerr := patchVMFn(ctx, instanceID, &vm)
+				if rerr != nil {
+					errChan <- rerr
+					return
+				}
+				if poller != nil {
+					pollerChannel <- poller
+				}
+			}()
+		}
+		requestGroup.Wait()
+		close(concurrentLock)
+	} else {
+		for instanceID, vm := range update {
+			instanceID := instanceID
+			vm := vm
+			poller, rerr := patchVMFn(ctx, instanceID, &vm)
+			if rerr != nil {
+				errChan <- rerr
+				continue
+			}
+			if poller != nil {
+				pollerChannel <- poller
+			}
+		}
+	}
+	close(pollerChannel)
+	pollerGroup.Wait()
+	close(errChan)
+	return errChan
+}


Test patch:
diff --git a/pkg/provider/azure_vmss_bench_test.go b/pkg/provider/azure_vmss_bench_test.go
new file mode 100644
index 000000000..d97ae2d87
--- /dev/null
+++ b/pkg/provider/azure_vmss_bench_test.go
@@ -0,0 +1,201 @@
+/*
+Copyright 2022 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package provider
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"testing"
+	"time"
+
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
+	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6"
+	"go.uber.org/mock/gomock"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/mock_azclient"
+	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/virtualmachinescalesetvmclient/mock_virtualmachinescalesetvmclient"
+)
+
+// go test -benchmem -run=^$ -count=5 -bench '^BenchmarkUpdateVMSSVMs$' sigs.k8s.io/cloud-provider-azure/pkg/provider -timeout=0
+// goos: linux
+// goarch: amd64
+// pkg: sigs.k8s.io/cloud-provider-azure/pkg/provider
+// cpu: 11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_1-5                      1        1004777082 ns/op           23776 B/op        230 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_1-5                      1        1008032167 ns/op           14120 B/op        192 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_1-5                      1        1009558083 ns/op           14104 B/op        191 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_1-5                      1        1013932469 ns/op           12856 B/op        184 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_1-5                      1        1013594680 ns/op           13560 B/op        189 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_2-5                      2         621996992 ns/op           15524 B/op        206 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_2-5                      2         603486975 ns/op           14124 B/op        198 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_2-5                      2         602413756 ns/op           15636 B/op        206 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_2-5                      2         612644862 ns/op           16244 B/op        207 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_2-5                      2         604255015 ns/op           14220 B/op        199 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_5-5                      5         201733780 ns/op           14587 B/op        200 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_5-5                      5         203302041 ns/op           14299 B/op        200 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_5-5                      5         202940754 ns/op           14408 B/op        199 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_5-5                      5         204206352 ns/op           13902 B/op        197 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_5-5                      5         206062474 ns/op           14206 B/op        199 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_10-5                     5         201421461 ns/op           13908 B/op        197 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_10-5                     5         201394075 ns/op           13995 B/op        197 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_10-5                     5         202607347 ns/op           15156 B/op        200 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_10-5                     5         203024935 ns/op           14529 B/op        198 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_5_batch_size_10-5                     5         201167823 ns/op           13905 B/op        197 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_1-5                     1        4045789026 ns/op           46824 B/op        693 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_1-5                     1        4057585219 ns/op           47032 B/op        695 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_1-5                     1        4063713311 ns/op           46824 B/op        693 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_1-5                     1        4037911161 ns/op           47640 B/op        699 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_1-5                     1        4061475309 ns/op           47240 B/op        696 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_2-5                     1        2027122993 ns/op           55976 B/op        768 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_2-5                     1        2026314668 ns/op           55208 B/op        766 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_2-5                     1        2010009442 ns/op           54840 B/op        761 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_2-5                     1        2016806787 ns/op           55736 B/op        768 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_2-5                     1        2028124950 ns/op           54008 B/op        757 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_5-5                     2         806128331 ns/op           53340 B/op        754 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_5-5                     2         804287660 ns/op           53236 B/op        753 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_5-5                     2         808459508 ns/op           53236 B/op        753 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_5-5                     2         804472248 ns/op           54300 B/op        761 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_5-5                     2         809618154 ns/op           53236 B/op        753 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_10-5                    3         409055472 ns/op           55176 B/op        756 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_10-5                    3         410879465 ns/op           53538 B/op        757 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_10-5                    3         417658955 ns/op           53485 B/op        754 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_10-5                    3         407526162 ns/op           53298 B/op        754 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_20_batch_size_10-5                    3         408291112 ns/op           53208 B/op        753 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_1-5                    1        20347847465 ns/op         228872 B/op       3413 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_1-5                    1        20278994738 ns/op         229688 B/op       3419 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_1-5                    1        20333078305 ns/op         230072 B/op       3422 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_1-5                    1        20335095823 ns/op         228888 B/op       3413 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_1-5                    1        20265588975 ns/op         228888 B/op       3413 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_2-5                    1        10122421534 ns/op         263320 B/op       3720 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_2-5                    1        10178407998 ns/op         263736 B/op       3723 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_2-5                    1        10199717421 ns/op         262520 B/op       3714 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_2-5                    1        10166139835 ns/op         262520 B/op       3714 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_2-5                    1        10114398628 ns/op         262920 B/op       3717 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_5-5                    1        4083103843 ns/op          262520 B/op       3714 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_5-5                    1        4056605556 ns/op          262504 B/op       3714 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_5-5                    1        4068758430 ns/op          262520 B/op       3714 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_5-5                    1        4029400400 ns/op          262520 B/op       3714 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_5-5                    1        4073177810 ns/op          262520 B/op       3714 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_10-5                   1        2012005065 ns/op          262520 B/op       3714 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_10-5                   1        2011972323 ns/op          262776 B/op       3715 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_10-5                   1        2041940768 ns/op          262520 B/op       3714 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_10-5                   1        2014742464 ns/op          262520 B/op       3714 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_100_batch_size_10-5                   1        2017203321 ns/op          262520 B/op       3714 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_1-5                   1        101900562893 ns/op       1137672 B/op      17013 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_1-5                    1        101412493739 ns/op       1137672 B/op      17013 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_1-5                    1        101685370283 ns/op       1138072 B/op      17016 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_1-5                    1        101514837421 ns/op       1138488 B/op      17019 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_1-5                    1        101622046419 ns/op       1137672 B/op      17013 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_2-5                    1        51031012310 ns/op        1306920 B/op      18523 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_2-5                    1        50895108034 ns/op        1305720 B/op      18514 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_2-5                    1        50797118749 ns/op        1305720 B/op      18514 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_2-5                    1        50773342073 ns/op        1305720 B/op      18514 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_2-5                    1        50605629098 ns/op        1305720 B/op      18514 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_5-5                    1        20299650018 ns/op        1305720 B/op      18514 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_5-5                    1        20107559039 ns/op        1305704 B/op      18512 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_5-5                    1        20354770109 ns/op        1305720 B/op      18514 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_5-5                    1        20316420918 ns/op        1305720 B/op      18514 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_5-5                    1        20082889384 ns/op        1305720 B/op      18514 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_10-5                   1        10050288652 ns/op        1313016 B/op      18535 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_10-5                   1        10053444017 ns/op        1307032 B/op      18526 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_10-5                   1        10050662117 ns/op        1306392 B/op      18520 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_10-5                   1        10056109620 ns/op        1306200 B/op      18519 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_500_batch_size_10-5                   1        10052595290 ns/op        1306488 B/op      18522 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_1-5                   1        202184504123 ns/op       2274688 B/op      34015 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_1-5                   1        202621583245 ns/op       2274704 B/op      34015 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_1-5                   1        203072169346 ns/op       2274704 B/op      34015 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_1-5                   1        203493224379 ns/op       2274688 B/op      34015 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_1-5                   1        203044039412 ns/op       2274704 B/op      34015 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_2-5                   1        101410877061 ns/op       2611648 B/op      37023 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_2-5                   1        101730978024 ns/op       2610848 B/op      37017 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_2-5                   1        101555260048 ns/op       2611728 B/op      37025 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_2-5                   1        101659685526 ns/op       2612080 B/op      37019 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_2-5                   1        101649890958 ns/op       2611024 B/op      37019 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_5-5                   1        40679144168 ns/op        2611776 B/op      37027 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_5-5                   1        40826075485 ns/op        2611632 B/op      37015 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_5-5                   1        40706661152 ns/op        2610928 B/op      37018 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_5-5                   1        40719464773 ns/op        2615440 B/op      37032 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_5-5                   1        40683037070 ns/op        2610752 B/op      37014 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_10-5                  1        20396002069 ns/op        2611520 B/op      37022 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_10-5                  1        20284312819 ns/op        2612368 B/op      37033 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_10-5                  1        20335551936 ns/op        2612592 B/op      37030 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_10-5                  1        20344432668 ns/op        2614112 B/op      37051 allocs/op
+// BenchmarkUpdateVMSSVMs/vmss_size_1000_batch_size_10-5                  1        20292074046 ns/op        2613632 B/op      37024 allocs/op
+// PASS
+// ok      sigs.k8s.io/cloud-provider-azure/pkg/provider   3013.951s
+func BenchmarkUpdateVMSSVMs(b *testing.B) {
+	ctrl := gomock.NewController(b)
+	defer ctrl.Finish()
+	vmssvmClient := mock_virtualmachinescalesetvmclient.NewMockInterface(ctrl)
+	vmssvmClient.EXPECT().BeginUpdate(gomock.Any(), "rg", "vmss", gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_ context.Context, _, _, _ string, _ armcompute.VirtualMachineScaleSetVM, _ *armcompute.VirtualMachineScaleSetVMsClientBeginUpdateOptions) (*runtime.Poller[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse], error) {
+		time.Sleep(200 * time.Millisecond)
+		poller, _ := runtime.NewPoller[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse](
+			&http.Response{
+				Header: http.Header{"Fake-Poller-Status": []string{"https://fake/operation"}},
+			},
+			runtime.Pipeline{},
+			&runtime.NewPollerOptions[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse]{
+				Handler: &vmssvmMockPutHandler{
+					sleep: 559669,
+					resp: &http.Response{
+						StatusCode: http.StatusAccepted,
+					},
+				},
+			},
+		)
+		return poller, nil
+	}).AnyTimes()
+	clientFactory := mock_azclient.NewMockClientFactory(ctrl)
+	clientFactory.EXPECT().GetVirtualMachineScaleSetVMClient().Return(vmssvmClient).AnyTimes()
+	scaleset := ScaleSet{
+		Cloud: &Cloud{ComputeClientFactory: clientFactory},
+	}
+	for _, vmsssize := range []int{5, 20, 100, 500, 1000} {
+		for _, batchSize := range []int{1, 2, 5, 10} {
+			b.Run("vmss size "+strconv.Itoa(vmsssize)+" batch size "+strconv.Itoa(batchSize), func(b *testing.B) {
+				vmssMetaInfo := vmssMetaInfo{
+					resourceGroup: "rg",
+					vmssName:      "vmss",
+				}
+				vmUpdates := genTestvms(vmsssize)
+				b.ResetTimer()
+				for i := 0; i < b.N; i++ {
+					b.StartTimer()
+					errChan := scaleset.UpdateVMSSVMsInBatch(context.Background(), vmssMetaInfo, vmUpdates, batchSize)
+					b.StopTimer()
+					for err := range errChan {
+						if err != nil {
+							b.Error(err)
+						}
+					}
+				}
+			})
+		}
+	}
+}
+
+func genTestvms(size int) map[string]armcompute.VirtualMachineScaleSetVM {
+	vms := make(map[string]armcompute.VirtualMachineScaleSetVM)
+	for i := 0; i < size; i++ {
+		vms[strconv.Itoa(i)] = armcompute.VirtualMachineScaleSetVM{
+			InstanceID: to.Ptr(strconv.Itoa(i)),
+		}
+	}
+	return vms
+}
diff --git a/pkg/provider/azure_vmss_test.go b/pkg/provider/azure_vmss_test.go
index a6e1ec2f4..e7c286e7b 100644
--- a/pkg/provider/azure_vmss_test.go
+++ b/pkg/provider/azure_vmss_test.go
@@ -24,15 +24,15 @@ import (
 	"reflect"
 	"strings"
 	"testing"
+	"time"
 
 	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
 	"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
 	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6"
 	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
-
 	"github.com/stretchr/testify/assert"
 	"go.uber.org/mock/gomock"
-
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
@@ -2766,7 +2766,25 @@ func TestEnsureHostsInPool(t *testing.T) {
 			expectedVMSSVMs, _, _ := buildTestVirtualMachineEnv(ss.Cloud, testVMSSName, "", 0, []string{"vmss-vm-000000", "vmss-vm-000001", "vmss-vm-000002"}, "", false)
 			mockVMSSVMClient := ss.ComputeClientFactory.GetVirtualMachineScaleSetVMClient().(*mock_virtualmachinescalesetvmclient.MockInterface)
 			mockVMSSVMClient.EXPECT().ListVMInstanceView(gomock.Any(), ss.ResourceGroup, testVMSSName).Return(expectedVMSSVMs, nil).AnyTimes()
-			mockVMSSVMClient.EXPECT().Update(gomock.Any(), ss.ResourceGroup, testVMSSName, gomock.Any(), gomock.Any()).Return(nil, nil).Times(test.expectedVMSSVMPutTimes)
+
+			mockVMSSVMClient.EXPECT().BeginUpdate(gomock.Any(), ss.ResourceGroup, testVMSSName, gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(
+				func(_ context.Context, _, _, _ string, _ armcompute.VirtualMachineScaleSetVM, _ *armcompute.VirtualMachineScaleSetVMsClientBeginUpdateOptions) (*runtime.Poller[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse], error) {
+					poller, err := runtime.NewPoller[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse](
+						&http.Response{
+							Header: http.Header{"Fake-Poller-Status": []string{"https://fake/operation"}},
+						},
+						runtime.Pipeline{},
+						&runtime.NewPollerOptions[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse]{
+							Handler: &vmssvmMockPutHandler{
+								resp: &http.Response{
+									StatusCode: http.StatusAccepted,
+								},
+							},
+						},
+					)
+					assert.NoError(t, err)
+					return poller, nil
+				}).Times(test.expectedVMSSVMPutTimes)
 
 			mockVMClient := ss.ComputeClientFactory.GetVirtualMachineClient().(*mock_virtualmachineclient.MockInterface)
 			mockVMClient.EXPECT().List(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
@@ -2901,7 +2919,7 @@ func TestEnsureHostsInPoolEtagMismatch(t *testing.T) {
 				},
 				Etag: copiedVMSSVM.Etag,
 			}
-			mockVMSSVMClient.EXPECT().Update(gomock.Any(), ss.ResourceGroup, testVMSSName, gomock.Any(), vmssVMMatcher).Return(nil, test.vmssvmClientPutError).Times(test.expectedVMSSVMPutTimes)
+			mockVMSSVMClient.EXPECT().BeginUpdate(gomock.Any(), ss.ResourceGroup, testVMSSName, gomock.Any(), vmssVMMatcher, gomock.Any()).Return(nil, test.vmssvmClientPutError).Times(test.expectedVMSSVMPutTimes)
 
 			mockVMClient := ss.ComputeClientFactory.GetVirtualMachineClient().(*mock_virtualmachineclient.MockInterface)
 			mockVMClient.EXPECT().List(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
@@ -3078,7 +3096,7 @@ func TestEnsureBackendPoolDeletedEtagMismatch(t *testing.T) {
 			}
 			mockVMSSVMClient := ss.ComputeClientFactory.GetVirtualMachineScaleSetVMClient().(*mock_virtualmachinescalesetvmclient.MockInterface)
 			mockVMSSVMClient.EXPECT().ListVMInstanceView(gomock.Any(), ss.ResourceGroup, testVMSSName).Return(expectedVMSSVMs, nil).AnyTimes()
-			mockVMSSVMClient.EXPECT().Update(gomock.Any(), ss.ResourceGroup, testVMSSName, gomock.Any(), vmssVMMatcher).Return(nil, test.vmssvmClientPutError).Times(test.expectedVMSSVMPutTimes)
+			mockVMSSVMClient.EXPECT().BeginUpdate(gomock.Any(), ss.ResourceGroup, testVMSSName, gomock.Any(), vmssVMMatcher, gomock.Any()).Return(nil, test.vmssvmClientPutError).Times(test.expectedVMSSVMPutTimes)
 
 			mockVMsClient := ss.ComputeClientFactory.GetVirtualMachineClient().(*mock_virtualmachineclient.MockInterface)
 			mockVMsClient.EXPECT().List(gomock.Any(), gomock.Any()).Return([]*armcompute.VirtualMachine{}, nil).AnyTimes()
@@ -3404,7 +3422,7 @@ func TestEnsureBackendPoolDeleted(t *testing.T) {
 			expectedVMSSVMs, _, _ := buildTestVirtualMachineEnv(ss.Cloud, testVMSSName, "", 0, []string{"vmss-vm-000000", "vmss-vm-000001", "vmss-vm-000002"}, "", false)
 			mockVMSSVMClient := ss.ComputeClientFactory.GetVirtualMachineScaleSetVMClient().(*mock_virtualmachinescalesetvmclient.MockInterface)
 			mockVMSSVMClient.EXPECT().ListVMInstanceView(gomock.Any(), ss.ResourceGroup, testVMSSName).Return(expectedVMSSVMs, nil).AnyTimes()
-			mockVMSSVMClient.EXPECT().Update(gomock.Any(), ss.ResourceGroup, testVMSSName, gomock.Any(), gomock.Any()).Return(nil, test.vmClientErr).Times(test.expectedVMSSVMPutTimes)
+			mockVMSSVMClient.EXPECT().BeginUpdate(gomock.Any(), ss.ResourceGroup, testVMSSName, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, test.vmClientErr).Times(test.expectedVMSSVMPutTimes)
 
 			mockVMsClient := ss.ComputeClientFactory.GetVirtualMachineClient().(*mock_virtualmachineclient.MockInterface)
 			mockVMsClient.EXPECT().List(gomock.Any(), gomock.Any()).Return([]*armcompute.VirtualMachine{}, nil).AnyTimes()
@@ -3418,6 +3436,150 @@ func TestEnsureBackendPoolDeleted(t *testing.T) {
 	}
 }
 
+func TestEnsureHostsInPoolInParallel(t *testing.T) {
+
+	testCases := []struct {
+		description            string
+		nodes                  []*v1.Node
+		backendpoolID          string
+		vmSetName              string
+		expectedVMSSVMPutTimes int
+		expectedErr            bool
+	}{
+		{
+			description: "EnsureHostsInPool should skip the invalid node and update the VMSS VM correctly",
+			nodes: []*v1.Node{
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:   "vmss-vm-000000",
+						Labels: map[string]string{consts.NodeLabelRole: "master"},
+					},
+					Spec: v1.NodeSpec{
+						ProviderID: "azure:///subscriptions/sub/resourceGroups/rg/providers/Microsoft.Compute/virtualMachineScaleSets/vmss/virtualMachines/0",
+					},
+				},
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:   "vmss-vm-000001",
+						Labels: map[string]string{consts.ManagedByAzureLabel: "false"},
+					},
+					Spec: v1.NodeSpec{
+						ProviderID: "azure:///subscriptions/sub/resourceGroups/rg/providers/Microsoft.Compute/virtualMachineScaleSets/vmss/virtualMachines/1",
+					},
+				},
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name: "vmss-vm-000002",
+					},
+					Spec: v1.NodeSpec{
+						ProviderID: "azure:///subscriptions/sub/resourceGroups/rg/providers/Microsoft.Compute/virtualMachineScaleSets/vmss/virtualMachines/2",
+					},
+				},
+			},
+			backendpoolID:          testLBBackendpoolID1,
+			vmSetName:              testVMSSName,
+			expectedVMSSVMPutTimes: 1,
+		},
+		{
+			description: "EnsureHostsInPool should skip not found nodes",
+			nodes: []*v1.Node{
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name: "vmss-vm-000003",
+					},
+					Spec: v1.NodeSpec{
+						ProviderID: "azure:///subscriptions/sub/resourceGroups/rg/providers/Microsoft.Compute/virtualMachineScaleSets/vmss/virtualMachines/3",
+					},
+				},
+			},
+			backendpoolID:          testLBBackendpoolID1,
+			vmSetName:              testVMSSName,
+			expectedVMSSVMPutTimes: 0,
+			expectedErr:            false,
+		},
+	}
+
+	for _, test := range testCases {
+		test := test
+		t.Run(test.description, func(t *testing.T) {
+			ctrl := gomock.NewController(t)
+			defer ctrl.Finish()
+
+			ss, err := NewTestScaleSet(ctrl)
+			assert.NoError(t, err, test.description)
+
+			for _, node := range test.nodes {
+				if node.Labels[consts.ManagedByAzureLabel] == "false" {
+					ss.excludeLoadBalancerNodes = utilsets.NewString(node.Name)
+				}
+			}
+			ss.PutVMSSVMBatchSize = 2
+			ss.LoadBalancerSKU = consts.LoadBalancerSKUStandard
+			ss.ExcludeMasterFromStandardLB = ptr.To(true)
+			expectedVMSS := buildTestVMSSWithLB(testVMSSName, "vmss-vm-", []string{testLBBackendpoolID0}, false)
+			expectedVMSS.Tags = map[string]*string{
+				"aks-managed-coordination": to.Ptr("true"),
+			}
+			mockVMSSClient := ss.ComputeClientFactory.GetVirtualMachineScaleSetClient().(*mock_virtualmachinescalesetclient.MockInterface)
+			mockVMSSClient.EXPECT().List(gomock.Any(), ss.ResourceGroup).Return([]*armcompute.VirtualMachineScaleSet{expectedVMSS}, nil).AnyTimes()
+			mockVMSSClient.EXPECT().Get(gomock.Any(), ss.ResourceGroup, testVMSSName, nil).Return(expectedVMSS, nil).MaxTimes(1)
+			mockVMSSClient.EXPECT().CreateOrUpdate(gomock.Any(), ss.ResourceGroup, testVMSSName, gomock.Any()).Return(nil, nil).MaxTimes(1)
+
+			expectedVMSSVMs, _, _ := buildTestVirtualMachineEnv(ss.Cloud, testVMSSName, "", 0, []string{"vmss-vm-000000", "vmss-vm-000001", "vmss-vm-000002"}, "", false)
+			mockVMSSVMClient := ss.ComputeClientFactory.GetVirtualMachineScaleSetVMClient().(*mock_virtualmachinescalesetvmclient.MockInterface)
+			mockVMSSVMClient.EXPECT().ListVMInstanceView(gomock.Any(), ss.ResourceGroup, testVMSSName).Return(expectedVMSSVMs, nil).AnyTimes()
+
+			mockVMSSVMClient.EXPECT().BeginUpdate(gomock.Any(), ss.ResourceGroup, testVMSSName, gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(
+				func(_ context.Context, _, _, _ string, _ armcompute.VirtualMachineScaleSetVM, _ *armcompute.VirtualMachineScaleSetVMsClientBeginUpdateOptions) (*runtime.Poller[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse], error) {
+					poller, err := runtime.NewPoller[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse](
+						&http.Response{
+							Header: http.Header{"Fake-Poller-Status": []string{"https://fake/operation"}},
+						},
+						runtime.Pipeline{},
+						&runtime.NewPollerOptions[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse]{
+							Handler: &vmssvmMockPutHandler{
+								resp: &http.Response{
+									StatusCode: http.StatusAccepted,
+								},
+							},
+						},
+					)
+					assert.NoError(t, err)
+					return poller, nil
+				}).Times(test.expectedVMSSVMPutTimes)
+
+			mockVMClient := ss.ComputeClientFactory.GetVirtualMachineClient().(*mock_virtualmachineclient.MockInterface)
+			mockVMClient.EXPECT().List(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
+			err = ss.EnsureHostsInPool(context.Background(), &v1.Service{}, test.nodes, test.backendpoolID, test.vmSetName)
+			assert.Equal(t, test.expectedErr, err != nil, test.description+errMsgSuffix)
+		})
+	}
+}
+
+type vmssvmMockPutHandler struct {
+	sleep int
+	resp  *http.Response
+}
+
+// Done returns true if the LRO has reached a terminal state.
+func (h *vmssvmMockPutHandler) Done() bool {
+	return true
+}
+
+// Poll fetches the latest state of the LRO.
+func (h *vmssvmMockPutHandler) Poll(context.Context) (*http.Response, error) {
+	if h.sleep != 0 {
+		time.Sleep(time.Duration(h.sleep) * time.Second)
+	}
+	return h.resp, nil
+}
+
+// Result is called once the LRO has reached a terminal state. It populates the out parameter
+// with the result of the operation.
+func (h *vmssvmMockPutHandler) Result(_ context.Context, _ *armcompute.VirtualMachineScaleSetVMsClientUpdateResponse) error {
+	return nil
+}
+
 func TestEnsureBackendPoolDeletedConcurrentlyLoop(t *testing.T) {
 	// run TestEnsureBackendPoolDeletedConcurrently 20 times to detect race conditions
 	for i := 0; i < 20; i++ {
@@ -3493,7 +3655,45 @@ func TestEnsureBackendPoolDeletedConcurrently(t *testing.T) {
 	mockVMSSVMClient.EXPECT().ListVMInstanceView(gomock.Any(), "rg1", "vmss-0").Return(nil, nil).AnyTimes()
 	mockVMSSVMClient.EXPECT().ListVMInstanceView(gomock.Any(), ss.ResourceGroup, "vmss-0").Return(expectedVMSSVMsOfVMSS0, nil).AnyTimes()
 	mockVMSSVMClient.EXPECT().ListVMInstanceView(gomock.Any(), ss.ResourceGroup, "vmss-1").Return(expectedVMSSVMsOfVMSS1, nil).AnyTimes()
-	mockVMSSVMClient.EXPECT().Update(gomock.Any(), ss.ResourceGroup, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).Times(2)
+	mockVMSSVMClient.EXPECT().BeginUpdate(gomock.Any(), ss.ResourceGroup, "vmss-0", gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(
+		func(_ context.Context, _, _, _ string, _ armcompute.VirtualMachineScaleSetVM, _ *armcompute.VirtualMachineScaleSetVMsClientBeginUpdateOptions) (*runtime.Poller[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse], error) {
+			poller, err := runtime.NewPoller[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse](
+				&http.Response{
+					Header: http.Header{"Fake-Poller-Status": []string{"https://fake/operation"}},
+				},
+				runtime.Pipeline{},
+				&runtime.NewPollerOptions[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse]{
+					Handler: &vmssvmMockPutHandler{
+						resp: &http.Response{
+							StatusCode: http.StatusAccepted,
+						},
+					},
+				},
+			)
+			assert.NoError(t, err)
+			return poller, nil
+		},
+	).Times(1)
+
+	mockVMSSVMClient.EXPECT().BeginUpdate(gomock.Any(), ss.ResourceGroup, "vmss-1", gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(
+		func(_ context.Context, _, _, _ string, _ armcompute.VirtualMachineScaleSetVM, _ *armcompute.VirtualMachineScaleSetVMsClientBeginUpdateOptions) (*runtime.Poller[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse], error) {
+			poller, err := runtime.NewPoller[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse](
+				&http.Response{
+					Header: http.Header{"Fake-Poller-Status": []string{"https://fake/operation"}},
+				},
+				runtime.Pipeline{},
+				&runtime.NewPollerOptions[armcompute.VirtualMachineScaleSetVMsClientUpdateResponse]{
+					Handler: &vmssvmMockPutHandler{
+						resp: &http.Response{
+							StatusCode: http.StatusAccepted,
+						},
+					},
+				},
+			)
+			assert.NoError(t, err)
+			return poller, nil
+		},
+	).Times(1)
 
 	backendpoolAddressIDs := []string{testLBBackendpoolID0, testLBBackendpoolID1, testLBBackendpoolID2}
 	testVMSSNames := []string{"vmss-0", "vmss-1", "vmss-2"}
diff --git a/pkg/provider/main_test.go b/pkg/provider/main_test.go
deleted file mode 100644
index 902b8d3c9..000000000
--- a/pkg/provider/main_test.go
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
-Copyright 2020 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package provider
-
-import (
-	"math/rand"
-	"os"
-	"testing"
-	"time"
-)
-
-func TestMain(m *testing.M) {
-	rand.Seed(time.Now().UnixNano())
-	os.Exit(m.Run())
-}