Repository: kubernetes-sigs/cloud-provider-azure
Pull request #7266 (2024-10-10 09:02:19)

Chores: remove nsg/privatedns/virtualnetworklink client from code base
<!--  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?
/kind cleanup

<!--
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
-->

#### What this PR does / why we need it:
Chores: remove nsg client from code base
#### 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: Adding the "do-not-merge/release-note-label-needed" label because no release-note block was detected, please follow our [release note process](https://git.k8s.io/community/contributors/guide/release-notes.md) to remove it.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository.
</details>
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/7266#" title="Author self-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/master/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":[]} -->
k8s-ci-robot: @MartinForReal: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cloud-provider-azure-e2e-ccm-vmss-capz | 4f80300ba7bb370329e80c5c75994d3796214f6d | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7266/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1844304368413708288) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7266). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3AMartinForReal). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cloud-provider-azure/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
MartinForReal: /retest

Patch:
diff --git a/go.mod b/go.mod
index 2a622e997..2133299d5 100644
--- a/go.mod
+++ b/go.mod
@@ -36,7 +36,7 @@ require (
 	go.opentelemetry.io/otel/trace v1.30.0
 	go.uber.org/mock v0.4.0
 	golang.org/x/sync v0.8.0
-	golang.org/x/sys v0.25.0
+	golang.org/x/sys v0.26.0
 	golang.org/x/text v0.19.0
 	k8s.io/api v0.31.1
 	k8s.io/apimachinery v0.31.1
@@ -49,7 +49,7 @@ require (
 	k8s.io/klog/v2 v2.130.1
 	k8s.io/kubelet v0.31.1
 	k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
-	sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.0.62
+	sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.0.65
 	sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.0.29
 	sigs.k8s.io/yaml v1.4.0
 )
@@ -135,12 +135,12 @@ require (
 	go.opentelemetry.io/proto/otlp v1.3.1 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/zap v1.26.0 // indirect
-	golang.org/x/crypto v0.27.0 // indirect
+	golang.org/x/crypto v0.28.0 // indirect
 	golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
 	golang.org/x/net v0.29.0 // indirect
 	golang.org/x/oauth2 v0.22.0 // indirect
-	golang.org/x/term v0.24.0 // indirect
-	golang.org/x/time v0.6.0 // indirect
+	golang.org/x/term v0.25.0 // indirect
+	golang.org/x/time v0.7.0 // indirect
 	golang.org/x/tools v0.24.0 // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20240725223205-93522f1f2a9f // indirect
diff --git a/go.sum b/go.sum
index 75284057a..a40570e5b 100644
--- a/go.sum
+++ b/go.sum
@@ -321,8 +321,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
 golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
-golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
-golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
+golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
+golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -364,15 +364,15 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
-golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
+golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
 golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
 golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
-golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
-golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
+golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
+golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -383,8 +383,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
 golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
-golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
-golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
+golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@@ -454,8 +454,8 @@ k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1
 k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
-sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.0.62 h1:ZIr9JZrnw8vY9ALtV08BhhY86H9hddXliAy0T6IrMT0=
-sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.0.62/go.mod h1:/KS2mpgt5p1PWmHmDfo3oc5x71+8RMkpwhb6sRuTrk0=
+sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.0.65 h1:7bpkysrGvlXA+eFrRZuAoINsTGwBkqIixcBhdAquCyw=
+sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.0.65/go.mod h1:6Nw45MHQamZ9cB5BY4dCXfsYRL6e9uPWm17wSH0U1MM=
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.0.29 h1:AixTSBLVc89XycjD+GxbR26wMJyzcZGmyKE4Si5eIzY=
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.0.29/go.mod h1:1OgjkvC3qbeJeFj7Ogl+17WQxE149kUDS3TLVJtfPDI=
 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
diff --git a/pkg/azclient/client-gen/go.mod b/pkg/azclient/client-gen/go.mod
index f9d2eaa7d..6d5701cb1 100644
--- a/pkg/azclient/client-gen/go.mod
+++ b/pkg/azclient/client-gen/go.mod
@@ -4,7 +4,7 @@ go 1.23.1
 
 require (
 	github.com/spf13/cobra v1.8.1
-	sigs.k8s.io/controller-tools v0.16.3
+	sigs.k8s.io/controller-tools v0.16.4
 )
 
 require (
@@ -13,10 +13,10 @@ require (
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
-	golang.org/x/mod v0.20.0 // indirect
+	golang.org/x/mod v0.21.0 // indirect
 	golang.org/x/sync v0.8.0 // indirect
-	golang.org/x/sys v0.24.0 // indirect
-	golang.org/x/tools v0.24.0 // indirect
+	golang.org/x/sys v0.26.0 // indirect
+	golang.org/x/tools v0.26.0 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
-	k8s.io/apimachinery v0.31.0 // indirect
+	k8s.io/apimachinery v0.31.1 // indirect
 )
diff --git a/pkg/azclient/client-gen/go.sum b/pkg/azclient/client-gen/go.sum
index 26164816e..f1bda0c72 100644
--- a/pkg/azclient/client-gen/go.sum
+++ b/pkg/azclient/client-gen/go.sum
@@ -23,20 +23,20 @@ github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
 github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
-golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
-golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
+golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
+golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
+golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
 golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
 golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
-golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
-golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
-golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
-golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
+golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
+golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
+golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
+golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
@@ -45,7 +45,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 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/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc=
-k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
-sigs.k8s.io/controller-tools v0.16.3 h1:z48C5/d4jCVQQvtiSBL5MYyZ3EO2eFIOXrIKMgHVhFY=
-sigs.k8s.io/controller-tools v0.16.3/go.mod h1:AEj6k+w1kYpLZv2einOH3mj52ips4W/6FUjnB5tkJGs=
+k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U=
+k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
+sigs.k8s.io/controller-tools v0.16.4 h1:VXmar78eDXbx1by/H09ikEq1hiq3bqInxuV3lMr3GmQ=
+sigs.k8s.io/controller-tools v0.16.4/go.mod h1:kcsZyYMXiOFuBhofSPtkB90zTSxVRxVVyvtKQcx3q1A=
diff --git a/pkg/azureclients/privatednsclient/azure_privatednsclient.go b/pkg/azureclients/privatednsclient/azure_privatednsclient.go
deleted file mode 100644
index b3fcab3b7..000000000
--- a/pkg/azureclients/privatednsclient/azure_privatednsclient.go
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
-Copyright 2021 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 privatednsclient
-
-import (
-	"context"
-	"net/http"
-	"strings"
-	"time"
-
-	"github.com/Azure/azure-sdk-for-go/services/privatedns/mgmt/2018-09-01/privatedns"
-	"github.com/Azure/go-autorest/autorest"
-	"github.com/Azure/go-autorest/autorest/azure"
-
-	"k8s.io/client-go/util/flowcontrol"
-	"k8s.io/klog/v2"
-
-	azclients "sigs.k8s.io/cloud-provider-azure/pkg/azureclients"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/metrics"
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-var _ Interface = &Client{}
-
-const (
-	privateDNSZoneResourceType = "Microsoft.Network/privateDnsZones"
-)
-
-// Client implements privatednsclient Interface.
-type Client struct {
-	armClient      armclient.Interface
-	subscriptionID string
-	cloudName      string
-
-	// Rate limiting configures.
-	rateLimiterReader flowcontrol.RateLimiter
-	rateLimiterWriter flowcontrol.RateLimiter
-
-	// ARM throttling configures.
-	RetryAfterReader time.Time
-	RetryAfterWriter time.Time
-}
-
-// New creates a new private dns client with ratelimiting.
-func New(config *azclients.ClientConfig) *Client {
-	baseURI := config.ResourceManagerEndpoint
-	authorizer := config.Authorizer
-	apiVersion := APIVersion
-	if strings.EqualFold(config.CloudName, AzureStackCloudName) && !config.DisableAzureStackCloud {
-		klog.Warningf("Azure Stack is not supported for Private DNS Zone API")
-	}
-	armClient := armclient.New(authorizer, *config, baseURI, apiVersion)
-	rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(config.RateLimitConfig)
-
-	if azclients.RateLimitEnabled(config.RateLimitConfig) {
-		klog.V(2).Infof("Azure PrivateDNSZoneClient (read ops) using rate limit config: QPS=%g, bucket=%d",
-			config.RateLimitConfig.CloudProviderRateLimitQPS,
-			config.RateLimitConfig.CloudProviderRateLimitBucket)
-		klog.V(2).Infof("Azure PrivateDNSZoneClient (write ops) using rate limit config: QPS=%g, bucket=%d",
-			config.RateLimitConfig.CloudProviderRateLimitQPSWrite,
-			config.RateLimitConfig.CloudProviderRateLimitBucketWrite)
-	}
-
-	client := &Client{
-		armClient:         armClient,
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-		subscriptionID:    config.SubscriptionID,
-		cloudName:         config.CloudName,
-	}
-
-	return client
-}
-
-// CreateOrUpdate creates or updates a private DNS zone.
-func (c *Client) CreateOrUpdate(ctx context.Context, resourceGroupName, privateZoneName string, parameters privatedns.PrivateZone, etag string, waitForCompletion bool) *retry.Error {
-	mc := metrics.NewMetricContext("private_dns_zone", "create_or_update", resourceGroupName, c.subscriptionID, "")
-
-	// Report errors if the client is rate limited.
-	if !c.rateLimiterWriter.TryAccept() {
-		mc.RateLimitedCount()
-		return retry.GetRateLimitError(true, "PrivateDNSZoneCreateOrUpdate")
-	}
-
-	// Report errors if the client is throttled.
-	if c.RetryAfterWriter.After(time.Now()) {
-		mc.ThrottledCount()
-		rerr := retry.GetThrottlingError("PrivateDNSZoneCreateOrUpdate", "client throttled", c.RetryAfterWriter)
-		return rerr
-	}
-
-	rerr := c.createOrUpdatePrivateDNSZone(ctx, resourceGroupName, privateZoneName, parameters, etag, waitForCompletion)
-	mc.Observe(rerr)
-	if rerr != nil {
-		if rerr.IsThrottled() {
-			// Update RetryAfterReader so that no more requests would be sent until RetryAfter expires.
-			c.RetryAfterWriter = rerr.RetryAfter
-		}
-
-		return rerr
-	}
-
-	return nil
-}
-
-// createOrUpdatePrivateDNSZone creates or updates a private DNS zone.
-func (c *Client) createOrUpdatePrivateDNSZone(ctx context.Context, resourceGroupName, privateDNSZoneName string, parameters privatedns.PrivateZone, etag string, waitForCompletion bool) *retry.Error {
-	resourceID := armclient.GetResourceID(
-		c.subscriptionID,
-		resourceGroupName,
-		privateDNSZoneResourceType,
-		privateDNSZoneName,
-	)
-	decorators := []autorest.PrepareDecorator{}
-	if etag != "" {
-		decorators = append(decorators, autorest.WithHeader("If-Match", autorest.String(etag)))
-	}
-
-	var response *http.Response
-	var rerr *retry.Error
-	if waitForCompletion {
-		response, rerr = c.armClient.PutResource(ctx, resourceID, parameters, decorators...)
-		defer c.armClient.CloseResponse(ctx, response)
-	} else {
-		_, rerr = c.armClient.PutResourceAsync(ctx, resourceID, parameters, decorators...)
-	}
-	if rerr != nil {
-		klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "privatednszone.put.request", resourceID, rerr.Error())
-		return rerr
-	}
-	if !waitForCompletion {
-		return nil
-	}
-
-	if response != nil && response.StatusCode != http.StatusNoContent {
-		_, rerr = c.createOrUpdateResponder(response)
-		if rerr != nil {
-			klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "privatednszone.put.respond", resourceID, rerr.Error())
-			return rerr
-		}
-	}
-
-	return nil
-}
-
-func (c *Client) createOrUpdateResponder(resp *http.Response) (*privatedns.PrivateZone, *retry.Error) {
-	result := &privatedns.PrivateZone{}
-	err := autorest.Respond(
-		resp,
-		azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated),
-		autorest.ByUnmarshallingJSON(&result))
-	result.Response = autorest.Response{Response: resp}
-	return result, retry.GetError(resp, err)
-}
-
-// Get gets a private dns zone.
-func (c *Client) Get(ctx context.Context, resourceGroupName, privateZoneName string) (privatedns.PrivateZone, *retry.Error) {
-	mc := metrics.NewMetricContext("private_dns_zones", "get", resourceGroupName, c.subscriptionID, "")
-
-	// Report errors if the client is rate limited.
-	if !c.rateLimiterReader.TryAccept() {
-		mc.RateLimitedCount()
-		return privatedns.PrivateZone{}, retry.GetRateLimitError(false, "PrivateDNSZoneGet")
-	}
-
-	// Report errors if the client is throttled.
-	if c.RetryAfterReader.After(time.Now()) {
-		mc.ThrottledCount()
-		rerr := retry.GetThrottlingError("PrivateDNSZoneGet", "client throttled", c.RetryAfterReader)
-		return privatedns.PrivateZone{}, rerr
-	}
-
-	result, rerr := c.getPrivateDNSZone(ctx, resourceGroupName, privateZoneName)
-	mc.Observe(rerr)
-	if rerr != nil {
-		if rerr.IsThrottled() {
-			// Update RetryAfterReader so that no more requests would be sent until RetryAfter expires.
-			c.RetryAfterReader = rerr.RetryAfter
-		}
-
-		return result, rerr
-	}
-
-	return result, nil
-}
-
-// getPrivateDNSZone gets a private DNS zone.
-func (c *Client) getPrivateDNSZone(ctx context.Context, resourceGroupName, privateDNSZoneName string) (privatedns.PrivateZone, *retry.Error) {
-	resourceID := armclient.GetResourceID(
-		c.subscriptionID,
-		resourceGroupName,
-		privateDNSZoneResourceType,
-		privateDNSZoneName,
-	)
-	result := privatedns.PrivateZone{}
-
-	response, rerr := c.armClient.GetResource(ctx, resourceID)
-	defer c.armClient.CloseResponse(ctx, response)
-	if rerr != nil {
-		klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "privatednszone.get.request", resourceID, rerr.Error())
-		return result, rerr
-	}
-
-	err := autorest.Respond(
-		response,
-		azure.WithErrorUnlessStatusCode(http.StatusOK),
-		autorest.ByUnmarshallingJSON(&result))
-	if err != nil {
-		klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "privatednszone.get.respond", resourceID, err)
-		return result, retry.GetError(response, err)
-	}
-
-	result.Response = autorest.Response{Response: response}
-	return result, nil
-}
diff --git a/pkg/azureclients/privatednsclient/interface.go b/pkg/azureclients/privatednsclient/interface.go
deleted file mode 100644
index 63ae62a0a..000000000
--- a/pkg/azureclients/privatednsclient/interface.go
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-Copyright 2021 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 privatednsclient
-
-import (
-	"context"
-
-	"github.com/Azure/azure-sdk-for-go/services/privatedns/mgmt/2018-09-01/privatedns"
-
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-const (
-	// APIVersion is the API version.
-	APIVersion = "2018-09-01"
-	// AzureStackCloudName is the cloud name of Azure Stack
-	AzureStackCloudName = "AZURESTACKCLOUD"
-)
-
-// Interface is the client interface for Private DNS Zones
-// Don't forget to run "hack/update-mock-clients.sh" command to generate the mock client.
-type Interface interface {
-	// Get gets a private DNS zone
-	Get(ctx context.Context, resourceGroupName, privateZoneName string) (privatedns.PrivateZone, *retry.Error)
-
-	// CreateOrUpdate creates or updates a private DNS zone.
-	CreateOrUpdate(ctx context.Context, resourceGroupName, privateZoneName string, parameters privatedns.PrivateZone, etag string, waitForCompletion bool) *retry.Error
-}
diff --git a/pkg/azureclients/privatednsclient/mockprivatednsclient/doc.go b/pkg/azureclients/privatednsclient/mockprivatednsclient/doc.go
deleted file mode 100644
index 388fe4c9c..000000000
--- a/pkg/azureclients/privatednsclient/mockprivatednsclient/doc.go
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
-Copyright 2021 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 mockprivatednsclient implements the mock client for PrivateDNS.
-package mockprivatednsclient // import "sigs.k8s.io/cloud-provider-azure/pkg/azureclients/privatednsclient/mockprivatednsclient"
diff --git a/pkg/azureclients/privatednsclient/mockprivatednsclient/interface.go b/pkg/azureclients/privatednsclient/mockprivatednsclient/interface.go
deleted file mode 100644
index c1f6616c8..000000000
--- a/pkg/azureclients/privatednsclient/mockprivatednsclient/interface.go
+++ /dev/null
@@ -1,88 +0,0 @@
-// /*
-// Copyright 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.
-// */
-//
-
-// Code generated by MockGen. DO NOT EDIT.
-// Source: pkg/azureclients/privatednsclient/interface.go
-//
-// Generated by this command:
-//
-//	mockgen -copyright_file=/home/runner/work/cloud-provider-azure/cloud-provider-azure/hack/boilerplate/boilerplate.generatego.txt -source=pkg/azureclients/privatednsclient/interface.go -package=mockprivatednsclient Interface
-//
-
-// Package mockprivatednsclient is a generated GoMock package.
-package mockprivatednsclient
-
-import (
-	context "context"
-	reflect "reflect"
-
-	privatedns "github.com/Azure/azure-sdk-for-go/services/privatedns/mgmt/2018-09-01/privatedns"
-	gomock "go.uber.org/mock/gomock"
-	retry "sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-// MockInterface is a mock of Interface interface.
-type MockInterface struct {
-	ctrl     *gomock.Controller
-	recorder *MockInterfaceMockRecorder
-}
-
-// MockInterfaceMockRecorder is the mock recorder for MockInterface.
-type MockInterfaceMockRecorder struct {
-	mock *MockInterface
-}
-
-// NewMockInterface creates a new mock instance.
-func NewMockInterface(ctrl *gomock.Controller) *MockInterface {
-	mock := &MockInterface{ctrl: ctrl}
-	mock.recorder = &MockInterfaceMockRecorder{mock}
-	return mock
-}
-
-// EXPECT returns an object that allows the caller to indicate expected use.
-func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder {
-	return m.recorder
-}
-
-// CreateOrUpdate mocks base method.
-func (m *MockInterface) CreateOrUpdate(ctx context.Context, resourceGroupName, privateZoneName string, parameters privatedns.PrivateZone, etag string, waitForCompletion bool) *retry.Error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateOrUpdate", ctx, resourceGroupName, privateZoneName, parameters, etag, waitForCompletion)
-	ret0, _ := ret[0].(*retry.Error)
-	return ret0
-}
-
-// CreateOrUpdate indicates an expected call of CreateOrUpdate.
-func (mr *MockInterfaceMockRecorder) CreateOrUpdate(ctx, resourceGroupName, privateZoneName, parameters, etag, waitForCompletion any) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdate", reflect.TypeOf((*MockInterface)(nil).CreateOrUpdate), ctx, resourceGroupName, privateZoneName, parameters, etag, waitForCompletion)
-}
-
-// Get mocks base method.
-func (m *MockInterface) Get(ctx context.Context, resourceGroupName, privateZoneName string) (privatedns.PrivateZone, *retry.Error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Get", ctx, resourceGroupName, privateZoneName)
-	ret0, _ := ret[0].(privatedns.PrivateZone)
-	ret1, _ := ret[1].(*retry.Error)
-	return ret0, ret1
-}
-
-// Get indicates an expected call of Get.
-func (mr *MockInterfaceMockRecorder) Get(ctx, resourceGroupName, privateZoneName any) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockInterface)(nil).Get), ctx, resourceGroupName, privateZoneName)
-}
diff --git a/pkg/azureclients/securitygroupclient/azure_securitygroupclient.go b/pkg/azureclients/securitygroupclient/azure_securitygroupclient.go
deleted file mode 100644
index d3056e0cd..000000000
--- a/pkg/azureclients/securitygroupclient/azure_securitygroupclient.go
+++ /dev/null
@@ -1,422 +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 securitygroupclient
-
-import (
-	"context"
-	"net/http"
-	"strings"
-	"time"
-
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-	"github.com/Azure/go-autorest/autorest"
-	"github.com/Azure/go-autorest/autorest/azure"
-
-	"k8s.io/client-go/util/flowcontrol"
-	"k8s.io/klog/v2"
-	"k8s.io/utils/ptr"
-
-	azclients "sigs.k8s.io/cloud-provider-azure/pkg/azureclients"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/metrics"
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-var _ Interface = &Client{}
-
-const nsgResourceType = "Microsoft.Network/networkSecurityGroups"
-
-// Client implements SecurityGroup client Interface.
-type Client struct {
-	armClient      armclient.Interface
-	subscriptionID string
-	cloudName      string
-
-	// Rate limiting configures.
-	rateLimiterReader flowcontrol.RateLimiter
-	rateLimiterWriter flowcontrol.RateLimiter
-
-	// ARM throttling configures.
-	RetryAfterReader time.Time
-	RetryAfterWriter time.Time
-}
-
-// New creates a new SecurityGroup client with ratelimiting.
-func New(config *azclients.ClientConfig) *Client {
-	baseURI := config.ResourceManagerEndpoint
-	authorizer := config.Authorizer
-	apiVersion := APIVersion
-	if strings.EqualFold(config.CloudName, AzureStackCloudName) && !config.DisableAzureStackCloud {
-		apiVersion = AzureStackCloudAPIVersion
-	}
-	armClient := armclient.New(authorizer, *config, baseURI, apiVersion)
-	rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(config.RateLimitConfig)
-
-	if azclients.RateLimitEnabled(config.RateLimitConfig) {
-		klog.V(2).Infof("Azure SecurityGroupsClient (read ops) using rate limit config: QPS=%g, bucket=%d",
-			config.RateLimitConfig.CloudProviderRateLimitQPS,
-			config.RateLimitConfig.CloudProviderRateLimitBucket)
-		klog.V(2).Infof("Azure SecurityGroupsClient (write ops) using rate limit config: QPS=%g, bucket=%d",
-			config.RateLimitConfig.CloudProviderRateLimitQPSWrite,
-			config.RateLimitConfig.CloudProviderRateLimitBucketWrite)
-	}
-
-	client := &Client{
-		armClient:         armClient,
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-		subscriptionID:    config.SubscriptionID,
-		cloudName:         config.CloudName,
-	}
-
-	return client
-}
-
-// Get gets a SecurityGroup.
-func (c *Client) Get(ctx context.Context, resourceGroupName string, networkSecurityGroupName string, expand string) (network.SecurityGroup, *retry.Error) {
-	mc := metrics.NewMetricContext("security_groups", "get", resourceGroupName, c.subscriptionID, "")
-
-	// Report errors if the client is rate limited.
-	if !c.rateLimiterReader.TryAccept() {
-		mc.RateLimitedCount()
-		return network.SecurityGroup{}, retry.GetRateLimitError(false, "NSGGet")
-	}
-
-	// Report errors if the client is throttled.
-	if c.RetryAfterReader.After(time.Now()) {
-		mc.ThrottledCount()
-		rerr := retry.GetThrottlingError("NSGGet", "client throttled", c.RetryAfterReader)
-		return network.SecurityGroup{}, rerr
-	}
-
-	result, rerr := c.getSecurityGroup(ctx, resourceGroupName, networkSecurityGroupName, expand)
-	mc.Observe(rerr)
-	if rerr != nil {
-		if rerr.IsThrottled() {
-			// Update RetryAfterReader so that no more requests would be sent until RetryAfter expires.
-			c.RetryAfterReader = rerr.RetryAfter
-		}
-
-		return result, rerr
-	}
-
-	return result, nil
-}
-
-// getSecurityGroup gets a SecurityGroup.
-func (c *Client) getSecurityGroup(ctx context.Context, resourceGroupName string, networkSecurityGroupName string, expand string) (network.SecurityGroup, *retry.Error) {
-	resourceID := armclient.GetResourceID(
-		c.subscriptionID,
-		resourceGroupName,
-		nsgResourceType,
-		networkSecurityGroupName,
-	)
-	result := network.SecurityGroup{}
-
-	response, rerr := c.armClient.GetResourceWithExpandQuery(ctx, resourceID, expand)
-	defer c.armClient.CloseResponse(ctx, response)
-	if rerr != nil {
-		klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "securitygroup.get.request", resourceID, rerr.Error())
-		return result, rerr
-	}
-
-	err := autorest.Respond(
-		response,
-		azure.WithErrorUnlessStatusCode(http.StatusOK),
-		autorest.ByUnmarshallingJSON(&result))
-	if err != nil {
-		klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "securitygroup.get.respond", resourceID, err)
-		return result, retry.GetError(response, err)
-	}
-
-	result.Response = autorest.Response{Response: response}
-	return result, nil
-}
-
-// List gets a list of SecurityGroups in the resource group.
-func (c *Client) List(ctx context.Context, resourceGroupName string) ([]network.SecurityGroup, *retry.Error) {
-	mc := metrics.NewMetricContext("security_groups", "list", resourceGroupName, c.subscriptionID, "")
-
-	// Report errors if the client is rate limited.
-	if !c.rateLimiterReader.TryAccept() {
-		mc.RateLimitedCount()
-		return nil, retry.GetRateLimitError(false, "NSGList")
-	}
-
-	// Report errors if the client is throttled.
-	if c.RetryAfterReader.After(time.Now()) {
-		mc.ThrottledCount()
-		rerr := retry.GetThrottlingError("NSGList", "client throttled", c.RetryAfterReader)
-		return nil, rerr
-	}
-
-	result, rerr := c.listSecurityGroup(ctx, resourceGroupName)
-	mc.Observe(rerr)
-	if rerr != nil {
-		if rerr.IsThrottled() {
-			// Update RetryAfterReader so that no more requests would be sent until RetryAfter expires.
-			c.RetryAfterReader = rerr.RetryAfter
-		}
-
-		return result, rerr
-	}
-
-	return result, nil
-}
-
-// listSecurityGroup gets a list of SecurityGroups in the resource group.
-func (c *Client) listSecurityGroup(ctx context.Context, resourceGroupName string) ([]network.SecurityGroup, *retry.Error) {
-	resourceID := armclient.GetResourceListID(c.subscriptionID, resourceGroupName, nsgResourceType)
-	result := make([]network.SecurityGroup, 0)
-	page := &SecurityGroupListResultPage{}
-	page.fn = c.listNextResults
-
-	resp, rerr := c.armClient.GetResource(ctx, resourceID)
-	defer c.armClient.CloseResponse(ctx, resp)
-	if rerr != nil {
-		klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "securitygroup.list.request", resourceID, rerr.Error())
-		return result, rerr
-	}
-
-	var err error
-	page.sglr, err = c.listResponder(resp)
-	if err != nil {
-		klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "securitygroup.list.respond", resourceID, err)
-		return result, retry.GetError(resp, err)
-	}
-
-	for {
-		result = append(result, page.Values()...)
-
-		// Abort the loop when there's no nextLink in the response.
-		if ptr.Deref(page.Response().NextLink, "") == "" {
-			break
-		}
-
-		if err = page.NextWithContext(ctx); err != nil {
-			klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "securitygroup.list.next", resourceID, err)
-			return result, retry.GetError(page.Response().Response.Response, err)
-		}
-	}
-
-	return result, nil
-}
-
-// CreateOrUpdate creates or updates a SecurityGroup.
-func (c *Client) CreateOrUpdate(ctx context.Context, resourceGroupName string, networkSecurityGroupName string, parameters network.SecurityGroup, etag string) *retry.Error {
-	mc := metrics.NewMetricContext("security_groups", "create_or_update", resourceGroupName, c.subscriptionID, "")
-
-	// Report errors if the client is rate limited.
-	if !c.rateLimiterWriter.TryAccept() {
-		mc.RateLimitedCount()
-		return retry.GetRateLimitError(true, "NSGCreateOrUpdate")
-	}
-
-	// Report errors if the client is throttled.
-	if c.RetryAfterWriter.After(time.Now()) {
-		mc.ThrottledCount()
-		rerr := retry.GetThrottlingError("NSGCreateOrUpdate", "client throttled", c.RetryAfterWriter)
-		return rerr
-	}
-
-	rerr := c.createOrUpdateNSG(ctx, resourceGroupName, networkSecurityGroupName, parameters, etag)
-	mc.Observe(rerr)
-	if rerr != nil {
-		if rerr.IsThrottled() {
-			// Update RetryAfterReader so that no more requests would be sent until RetryAfter expires.
-			c.RetryAfterWriter = rerr.RetryAfter
-		}
-
-		return rerr
-	}
-
-	return nil
-}
-
-// createOrUpdateNSG creates or updates a SecurityGroup.
-func (c *Client) createOrUpdateNSG(ctx context.Context, resourceGroupName string, networkSecurityGroupName string, parameters network.SecurityGroup, etag string) *retry.Error {
-	resourceID := armclient.GetResourceID(
-		c.subscriptionID,
-		resourceGroupName,
-		nsgResourceType,
-		networkSecurityGroupName,
-	)
-	decorators := []autorest.PrepareDecorator{}
-	if etag != "" {
-		decorators = append(decorators, autorest.WithHeader("If-Match", autorest.String(etag)))
-	}
-
-	response, rerr := c.armClient.PutResource(ctx, resourceID, parameters, decorators...)
-	defer c.armClient.CloseResponse(ctx, response)
-	if rerr != nil {
-		klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "securityGroup.put.request", resourceID, rerr.Error())
-		return rerr
-	}
-
-	if response != nil && response.StatusCode != http.StatusNoContent {
-		_, rerr = c.createOrUpdateResponder(response)
-		if rerr != nil {
-			klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "securityGroup.put.respond", resourceID, rerr.Error())
-			return rerr
-		}
-	}
-
-	return nil
-}
-
-func (c *Client) createOrUpdateResponder(resp *http.Response) (*network.SecurityGroup, *retry.Error) {
-	result := &network.SecurityGroup{}
-	err := autorest.Respond(
-		resp,
-		azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated),
-		autorest.ByUnmarshallingJSON(&result))
-	result.Response = autorest.Response{Response: resp}
-	return result, retry.GetError(resp, err)
-}
-
-// Delete deletes a SecurityGroup by name.
-func (c *Client) Delete(ctx context.Context, resourceGroupName string, networkSecurityGroupName string) *retry.Error {
-	mc := metrics.NewMetricContext("security_groups", "delete", resourceGroupName, c.subscriptionID, "")
-
-	// Report errors if the client is rate limited.
-	if !c.rateLimiterWriter.TryAccept() {
-		mc.RateLimitedCount()
-		return retry.GetRateLimitError(true, "NSGDelete")
-	}
-
-	// Report errors if the client is throttled.
-	if c.RetryAfterWriter.After(time.Now()) {
-		mc.ThrottledCount()
-		rerr := retry.GetThrottlingError("NSGDelete", "client throttled", c.RetryAfterWriter)
-		return rerr
-	}
-
-	rerr := c.deleteNSG(ctx, resourceGroupName, networkSecurityGroupName)
-	mc.Observe(rerr)
-	if rerr != nil {
-		if rerr.IsThrottled() {
-			// Update RetryAfterReader so that no more requests would be sent until RetryAfter expires.
-			c.RetryAfterWriter = rerr.RetryAfter
-		}
-
-		return rerr
-	}
-
-	return nil
-}
-
-// deleteNSG deletes a SecurityGroup by name.
-func (c *Client) deleteNSG(ctx context.Context, resourceGroupName string, networkSecurityGroupName string) *retry.Error {
-	resourceID := armclient.GetResourceID(
-		c.subscriptionID,
-		resourceGroupName,
-		nsgResourceType,
-		networkSecurityGroupName,
-	)
-
-	return c.armClient.DeleteResource(ctx, resourceID)
-}
-
-func (c *Client) listResponder(resp *http.Response) (result network.SecurityGroupListResult, err error) {
-	err = autorest.Respond(
-		resp,
-		autorest.ByIgnoring(),
-		azure.WithErrorUnlessStatusCode(http.StatusOK),
-		autorest.ByUnmarshallingJSON(&result))
-	result.Response = autorest.Response{Response: resp}
-	return
-}
-
-// securityGroupListResultPreparer prepares a request to retrieve the next set of results.
-// It returns nil if no more results exist.
-func (c *Client) securityGroupListResultPreparer(ctx context.Context, sglr network.SecurityGroupListResult) (*http.Request, error) {
-	if sglr.NextLink == nil || len(ptr.Deref(sglr.NextLink, "")) < 1 {
-		return nil, nil
-	}
-
-	decorators := []autorest.PrepareDecorator{
-		autorest.WithBaseURL(ptr.Deref(sglr.NextLink, "")),
-	}
-	return c.armClient.PrepareGetRequest(ctx, decorators...)
-}
-
-// listNextResults retrieves the next set of results, if any.
-func (c *Client) listNextResults(ctx context.Context, lastResults network.SecurityGroupListResult) (result network.SecurityGroupListResult, err error) {
-	req, err := c.securityGroupListResultPreparer(ctx, lastResults)
-	if err != nil {
-		return result, autorest.NewErrorWithError(err, "securitygroupclient", "listNextResults", nil, "Failure preparing next results request")
-	}
-	if req == nil {
-		return
-	}
-
-	resp, rerr := c.armClient.Send(ctx, req)
-	defer c.armClient.CloseResponse(ctx, resp)
-	if rerr != nil {
-		result.Response = autorest.Response{Response: resp}
-		return result, autorest.NewErrorWithError(rerr.Error(), "securitygroupclient", "listNextResults", resp, "Failure sending next results request")
-	}
-
-	result, err = c.listResponder(resp)
-	if err != nil {
-		err = autorest.NewErrorWithError(err, "securitygroupclient", "listNextResults", resp, "Failure responding to next results request")
-	}
-
-	return
-}
-
-// SecurityGroupListResultPage contains a page of SecurityGroup values.
-type SecurityGroupListResultPage struct {
-	fn   func(context.Context, network.SecurityGroupListResult) (network.SecurityGroupListResult, error)
-	sglr network.SecurityGroupListResult
-}
-
-// NextWithContext advances to the next page of values.  If there was an error making
-// the request the page does not advance and the error is returned.
-func (page *SecurityGroupListResultPage) NextWithContext(ctx context.Context) (err error) {
-	next, err := page.fn(ctx, page.sglr)
-	if err != nil {
-		return err
-	}
-	page.sglr = next
-	return nil
-}
-
-// Next advances to the next page of values.  If there was an error making
-// the request the page does not advance and the error is returned.
-// Deprecated: Use NextWithContext() instead.
-func (page *SecurityGroupListResultPage) Next() error {
-	return page.NextWithContext(context.Background())
-}
-
-// NotDone returns true if the page enumeration should be started or is not yet complete.
-func (page SecurityGroupListResultPage) NotDone() bool {
-	return !page.sglr.IsEmpty()
-}
-
-// Response returns the raw server response from the last page request.
-func (page SecurityGroupListResultPage) Response() network.SecurityGroupListResult {
-	return page.sglr
-}
-
-// Values returns the slice of values for the current page or nil if there are no values.
-func (page SecurityGroupListResultPage) Values() []network.SecurityGroup {
-	if page.sglr.IsEmpty() {
-		return nil
-	}
-	return *page.sglr.Value
-}
diff --git a/pkg/azureclients/securitygroupclient/doc.go b/pkg/azureclients/securitygroupclient/doc.go
deleted file mode 100644
index 4b806d3ad..000000000
--- a/pkg/azureclients/securitygroupclient/doc.go
+++ /dev/null
@@ -1,18 +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 securitygroupclient implements the client for SecurityGroups.
-package securitygroupclient // import "sigs.k8s.io/cloud-provider-azure/pkg/azureclients/securitygroupclient"
diff --git a/pkg/azureclients/securitygroupclient/interface.go b/pkg/azureclients/securitygroupclient/interface.go
deleted file mode 100644
index 983834c56..000000000
--- a/pkg/azureclients/securitygroupclient/interface.go
+++ /dev/null
@@ -1,50 +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 securitygroupclient
-
-import (
-	"context"
-
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-const (
-	// APIVersion is the API version for network.
-	APIVersion = "2022-07-01"
-	// AzureStackCloudAPIVersion is the API version for Azure Stack
-	AzureStackCloudAPIVersion = "2018-11-01"
-	// AzureStackCloudName is the cloud name of Azure Stack
-	AzureStackCloudName = "AZURESTACKCLOUD"
-)
-
-// Interface is the client interface for SecurityGroups.
-// Don't forget to run "hack/update-mock-clients.sh" command to generate the mock client.
-type Interface interface {
-	// Get gets a SecurityGroup.
-	Get(ctx context.Context, resourceGroupName string, networkSecurityGroupName string, expand string) (result network.SecurityGroup, rerr *retry.Error)
-
-	// List gets a list of SecurityGroup in the resource group.
-	List(ctx context.Context, resourceGroupName string) (result []network.SecurityGroup, rerr *retry.Error)
-
-	// CreateOrUpdate creates or updates a SecurityGroup.
-	CreateOrUpdate(ctx context.Context, resourceGroupName string, networkSecurityGroupName string, parameters network.SecurityGroup, etag string) *retry.Error
-
-	// Delete deletes a SecurityGroup by name.
-	Delete(ctx context.Context, resourceGroupName string, networkSecurityGroupName string) *retry.Error
-}
diff --git a/pkg/azureclients/securitygroupclient/mocksecuritygroupclient/doc.go b/pkg/azureclients/securitygroupclient/mocksecuritygroupclient/doc.go
deleted file mode 100644
index ee6d0eb38..000000000
--- a/pkg/azureclients/securitygroupclient/mocksecuritygroupclient/doc.go
+++ /dev/null
@@ -1,18 +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 mocksecuritygroupclient implements the mock client for SecurityGroups.
-package mocksecuritygroupclient // import "sigs.k8s.io/cloud-provider-azure/pkg/azureclients/securitygroupclient/mocksecuritygroupclient"
diff --git a/pkg/azureclients/securitygroupclient/mocksecuritygroupclient/interface.go b/pkg/azureclients/securitygroupclient/mocksecuritygroupclient/interface.go
deleted file mode 100644
index e93756b92..000000000
--- a/pkg/azureclients/securitygroupclient/mocksecuritygroupclient/interface.go
+++ /dev/null
@@ -1,117 +0,0 @@
-// /*
-// Copyright 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.
-// */
-//
-
-// Code generated by MockGen. DO NOT EDIT.
-// Source: pkg/azureclients/securitygroupclient/interface.go
-//
-// Generated by this command:
-//
-//	mockgen -copyright_file=/home/runner/work/cloud-provider-azure/cloud-provider-azure/hack/boilerplate/boilerplate.generatego.txt -source=pkg/azureclients/securitygroupclient/interface.go -package=mocksecuritygroupclient Interface
-//
-
-// Package mocksecuritygroupclient is a generated GoMock package.
-package mocksecuritygroupclient
-
-import (
-	context "context"
-	reflect "reflect"
-
-	network "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-	gomock "go.uber.org/mock/gomock"
-	retry "sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-// MockInterface is a mock of Interface interface.
-type MockInterface struct {
-	ctrl     *gomock.Controller
-	recorder *MockInterfaceMockRecorder
-}
-
-// MockInterfaceMockRecorder is the mock recorder for MockInterface.
-type MockInterfaceMockRecorder struct {
-	mock *MockInterface
-}
-
-// NewMockInterface creates a new mock instance.
-func NewMockInterface(ctrl *gomock.Controller) *MockInterface {
-	mock := &MockInterface{ctrl: ctrl}
-	mock.recorder = &MockInterfaceMockRecorder{mock}
-	return mock
-}
-
-// EXPECT returns an object that allows the caller to indicate expected use.
-func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder {
-	return m.recorder
-}
-
-// CreateOrUpdate mocks base method.
-func (m *MockInterface) CreateOrUpdate(ctx context.Context, resourceGroupName, networkSecurityGroupName string, parameters network.SecurityGroup, etag string) *retry.Error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateOrUpdate", ctx, resourceGroupName, networkSecurityGroupName, parameters, etag)
-	ret0, _ := ret[0].(*retry.Error)
-	return ret0
-}
-
-// CreateOrUpdate indicates an expected call of CreateOrUpdate.
-func (mr *MockInterfaceMockRecorder) CreateOrUpdate(ctx, resourceGroupName, networkSecurityGroupName, parameters, etag any) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdate", reflect.TypeOf((*MockInterface)(nil).CreateOrUpdate), ctx, resourceGroupName, networkSecurityGroupName, parameters, etag)
-}
-
-// Delete mocks base method.
-func (m *MockInterface) Delete(ctx context.Context, resourceGroupName, networkSecurityGroupName string) *retry.Error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Delete", ctx, resourceGroupName, networkSecurityGroupName)
-	ret0, _ := ret[0].(*retry.Error)
-	return ret0
-}
-
-// Delete indicates an expected call of Delete.
-func (mr *MockInterfaceMockRecorder) Delete(ctx, resourceGroupName, networkSecurityGroupName any) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockInterface)(nil).Delete), ctx, resourceGroupName, networkSecurityGroupName)
-}
-
-// Get mocks base method.
-func (m *MockInterface) Get(ctx context.Context, resourceGroupName, networkSecurityGroupName, expand string) (network.SecurityGroup, *retry.Error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Get", ctx, resourceGroupName, networkSecurityGroupName, expand)
-	ret0, _ := ret[0].(network.SecurityGroup)
-	ret1, _ := ret[1].(*retry.Error)
-	return ret0, ret1
-}
-
-// Get indicates an expected call of Get.
-func (mr *MockInterfaceMockRecorder) Get(ctx, resourceGroupName, networkSecurityGroupName, expand any) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockInterface)(nil).Get), ctx, resourceGroupName, networkSecurityGroupName, expand)
-}
-
-// List mocks base method.
-func (m *MockInterface) List(ctx context.Context, resourceGroupName string) ([]network.SecurityGroup, *retry.Error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "List", ctx, resourceGroupName)
-	ret0, _ := ret[0].([]network.SecurityGroup)
-	ret1, _ := ret[1].(*retry.Error)
-	return ret0, ret1
-}
-
-// List indicates an expected call of List.
-func (mr *MockInterfaceMockRecorder) List(ctx, resourceGroupName any) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockInterface)(nil).List), ctx, resourceGroupName)
-}
diff --git a/pkg/azureclients/virtualnetworklinksclient/azure_virtualnetworklinksclient.go b/pkg/azureclients/virtualnetworklinksclient/azure_virtualnetworklinksclient.go
deleted file mode 100644
index 8d2ab07de..000000000
--- a/pkg/azureclients/virtualnetworklinksclient/azure_virtualnetworklinksclient.go
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
-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 virtualnetworklinksclient
-
-import (
-	"context"
-	"net/http"
-	"strings"
-	"time"
-
-	"github.com/Azure/azure-sdk-for-go/services/privatedns/mgmt/2018-09-01/privatedns"
-	"github.com/Azure/go-autorest/autorest"
-	"github.com/Azure/go-autorest/autorest/azure"
-	"k8s.io/client-go/util/flowcontrol"
-	"k8s.io/klog/v2"
-
-	azclients "sigs.k8s.io/cloud-provider-azure/pkg/azureclients"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/metrics"
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-var _ Interface = &Client{}
-
-const (
-	privateDNSZoneResourceType     = "Microsoft.Network/privateDnsZones"
-	virtualNetworkLinkResourceType = "virtualNetworkLinks"
-)
-
-// Client implements virtualnetworklinksclient Interface.
-type Client struct {
-	armClient      armclient.Interface
-	cloudName      string
-	subscriptionID string
-
-	// Rate limiting configures.
-	rateLimiterReader flowcontrol.RateLimiter
-	rateLimiterWriter flowcontrol.RateLimiter
-
-	// ARM throttling configures.
-	RetryAfterReader time.Time
-	RetryAfterWriter time.Time
-}
-
-// New creates a new virtualnetworklinks client.
-func New(config *azclients.ClientConfig) *Client {
-	apiVersion := APIVersion
-	if strings.EqualFold(config.CloudName, AzureStackCloudName) && !config.DisableAzureStackCloud {
-		klog.Warningf("Azure Stack is not supported for Virtual Network Link API")
-	}
-	armClient := armclient.New(config.Authorizer, *config, config.ResourceManagerEndpoint, apiVersion)
-
-	rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(config.RateLimitConfig)
-	if azclients.RateLimitEnabled(config.RateLimitConfig) {
-		klog.V(2).Infof("Azure VirtualNetworkLinksClient (read ops) using rate limit config: QPS=%g, bucket=%d",
-			config.RateLimitConfig.CloudProviderRateLimitQPS,
-			config.RateLimitConfig.CloudProviderRateLimitBucket)
-		klog.V(2).Infof("Azure VirtualNetworkLinksClient (write ops) using rate limit config: QPS=%g, bucket=%d",
-			config.RateLimitConfig.CloudProviderRateLimitQPSWrite,
-			config.RateLimitConfig.CloudProviderRateLimitBucketWrite)
-	}
-
-	client := &Client{
-		armClient:         armClient,
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-		subscriptionID:    config.SubscriptionID,
-		cloudName:         config.CloudName,
-	}
-	return client
-}
-
-// CreateOrUpdate creates or updates a virtual network link
-func (c *Client) CreateOrUpdate(ctx context.Context, resourceGroupName string, privateZoneName string, virtualNetworkLinkName string, parameters privatedns.VirtualNetworkLink, etag string, waitForCompletion bool) *retry.Error {
-	mc := metrics.NewMetricContext("virtual_network_links", "create_or_update", resourceGroupName, c.subscriptionID, "")
-
-	// Report errors if the client is rate limited.
-	if !c.rateLimiterWriter.TryAccept() {
-		mc.RateLimitedCount()
-		return retry.GetRateLimitError(true, "VirtualNetworkLinkCreateOrUpdate")
-	}
-
-	// Report errors if the client is throttled.
-	if c.RetryAfterWriter.After(time.Now()) {
-		mc.ThrottledCount()
-		rerr := retry.GetThrottlingError("VirtualNetworkLinkCreateOrUpdate", "client throttled", c.RetryAfterWriter)
-		return rerr
-	}
-
-	rerr := c.createOrUpdateVirtualNetworkLink(ctx, resourceGroupName, privateZoneName, virtualNetworkLinkName, parameters, etag, waitForCompletion)
-	mc.Observe(rerr)
-	if rerr != nil {
-		if rerr.IsThrottled() {
-			// Update RetryAfterReader so that no more requests would be sent until RetryAfter expires.
-			c.RetryAfterWriter = rerr.RetryAfter
-		}
-
-		return rerr
-	}
-	return nil
-}
-
-// createOrUpdateVirtualNetworkLink creates or updates a virtual network link.
-func (c *Client) createOrUpdateVirtualNetworkLink(ctx context.Context, resourceGroupName, privateZoneName, virtualNetworkLinkName string, parameters privatedns.VirtualNetworkLink, etag string, waitForCompletion bool) *retry.Error {
-	resourceID := armclient.GetChildResourceID(
-		c.subscriptionID,
-		resourceGroupName,
-		privateDNSZoneResourceType,
-		privateZoneName,
-		virtualNetworkLinkResourceType,
-		virtualNetworkLinkName,
-	)
-	decorators := []autorest.PrepareDecorator{}
-	if etag != "" {
-		decorators = append(decorators, autorest.WithHeader("If-Match", autorest.String(etag)))
-	}
-
-	var response *http.Response
-	var rerr *retry.Error
-	if waitForCompletion {
-		response, rerr = c.armClient.PutResource(ctx, resourceID, parameters, decorators...)
-	} else {
-		_, rerr = c.armClient.PutResourceAsync(ctx, resourceID, parameters, decorators...)
-	}
-	defer c.armClient.CloseResponse(ctx, response)
-	if rerr != nil {
-		klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "virtualnetworklink.put.request", resourceID, rerr.Error())
-		return rerr
-	}
-
-	if !waitForCompletion {
-		return nil
-	}
-
-	if response != nil && response.StatusCode != http.StatusNoContent {
-		_, rerr = c.createOrUpdateResponder(response)
-		if rerr != nil {
-			klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "virtualnetworklink.put.request", resourceID, rerr.Error())
-			return rerr
-		}
-	}
-	return nil
-}
-
-func (c *Client) createOrUpdateResponder(resp *http.Response) (*privatedns.VirtualNetworkLink, *retry.Error) {
-	result := &privatedns.VirtualNetworkLink{}
-	err := autorest.Respond(
-		resp,
-		azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated),
-		autorest.ByUnmarshallingJSON(&result))
-	result.Response = autorest.Response{Response: resp}
-	return result, retry.GetError(resp, err)
-}
-
-// Get gets a virtual network link
-func (c *Client) Get(ctx context.Context, resourceGroupName string, privateZoneName string, virtualNetworkLinkName string) (result privatedns.VirtualNetworkLink, err *retry.Error) {
-	mc := metrics.NewMetricContext("virtual_network_links", "get", resourceGroupName, c.subscriptionID, "")
-
-	// Report errors if the client is rate limited.
-	if !c.rateLimiterReader.TryAccept() {
-		mc.RateLimitedCount()
-		return privatedns.VirtualNetworkLink{}, retry.GetRateLimitError(false, "VirtualNetworkLinkGet")
-	}
-
-	// Report errors if the client is throttled.
-	if c.RetryAfterReader.After(time.Now()) {
-		mc.ThrottledCount()
-		rerr := retry.GetThrottlingError("VirtualNetworkLinkGet", "client throttled", c.RetryAfterReader)
-		return privatedns.VirtualNetworkLink{}, rerr
-	}
-	result, rerr := c.getVirtualNetworkLink(ctx, resourceGroupName, privateZoneName, virtualNetworkLinkName)
-
-	mc.Observe(rerr)
-	if rerr != nil {
-		if rerr.IsThrottled() {
-			// Update RetryAfterReader so that no more requests would be sent until RetryAfter expires.
-			c.RetryAfterReader = rerr.RetryAfter
-		}
-		return result, rerr
-	}
-	return result, nil
-}
-
-// getVirtualNetworkLink gets a virtual network link.
-func (c *Client) getVirtualNetworkLink(ctx context.Context, resourceGroupName string, privateZoneName string, virtualNetworkLinkName string) (privatedns.VirtualNetworkLink, *retry.Error) {
-	resourceID := armclient.GetChildResourceID(
-		c.subscriptionID,
-		resourceGroupName,
-		privateDNSZoneResourceType,
-		privateZoneName,
-		virtualNetworkLinkResourceType,
-		virtualNetworkLinkName,
-	)
-	result := privatedns.VirtualNetworkLink{}
-	response, rerr := c.armClient.GetResourceWithExpandQuery(ctx, resourceID, "")
-	defer c.armClient.CloseResponse(ctx, response)
-	if rerr != nil {
-		klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "virtualnetworklink.get.request", resourceID, rerr.Error())
-		return result, rerr
-	}
-
-	err := autorest.Respond(
-		response,
-		azure.WithErrorUnlessStatusCode(http.StatusOK),
-		autorest.ByUnmarshallingJSON(&result))
-	if err != nil {
-		klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "virtualnetworklink.get.respond", resourceID, err)
-		return result, retry.GetError(response, err)
-	}
-
-	result.Response = autorest.Response{Response: response}
-	return result, nil
-}
diff --git a/pkg/azureclients/virtualnetworklinksclient/doc.go b/pkg/azureclients/virtualnetworklinksclient/doc.go
deleted file mode 100644
index 219f7df49..000000000
--- a/pkg/azureclients/virtualnetworklinksclient/doc.go
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
-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 virtualnetworklinksclient implements the client for Virtual Network Link.
-package virtualnetworklinksclient // import "sigs.k8s.io/cloud-provider-azure/pkg/azureclients/virtualnetworklinksclient"
diff --git a/pkg/azureclients/virtualnetworklinksclient/interface.go b/pkg/azureclients/virtualnetworklinksclient/interface.go
deleted file mode 100644
index 5087bf601..000000000
--- a/pkg/azureclients/virtualnetworklinksclient/interface.go
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-Copyright 2021 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 virtualnetworklinksclient
-
-import (
-	"context"
-
-	"github.com/Azure/azure-sdk-for-go/services/privatedns/mgmt/2018-09-01/privatedns"
-
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-const (
-	// APIVersion is the API version.
-	// 2020-06-01 is the latest supported version
-	APIVersion = "2020-06-01"
-	// AzureStackCloudName is the cloud name of Azure Stack
-	AzureStackCloudName = "AZURESTACKCLOUD"
-)
-
-// Interface is the client interface for Virtual Network Link.
-// Don't forget to run "hack/update-mock-clients.sh" command to generate the mock client.
-type Interface interface {
-	// Get gets a virtual network link
-	Get(ctx context.Context, resourceGroupName string, privateZoneName string, virtualNetworkLinkName string) (privatedns.VirtualNetworkLink, *retry.Error)
-
-	// CreateOrUpdate creates or updates a virtual network link.
-	CreateOrUpdate(ctx context.Context, resourceGroupName string, privateZoneName string, virtualNetworkLinkName string, parameters privatedns.VirtualNetworkLink, etag string, waitForCompletion bool) *retry.Error
-}
diff --git a/pkg/azureclients/virtualnetworklinksclient/mockvirtualnetworklinksclient/interface.go b/pkg/azureclients/virtualnetworklinksclient/mockvirtualnetworklinksclient/interface.go
deleted file mode 100644
index 5612d6cda..000000000
--- a/pkg/azureclients/virtualnetworklinksclient/mockvirtualnetworklinksclient/interface.go
+++ /dev/null
@@ -1,88 +0,0 @@
-// /*
-// Copyright 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.
-// */
-//
-
-// Code generated by MockGen. DO NOT EDIT.
-// Source: pkg/azureclients/virtualnetworklinksclient/interface.go
-//
-// Generated by this command:
-//
-//	mockgen -copyright_file=/home/runner/work/cloud-provider-azure/cloud-provider-azure/hack/boilerplate/boilerplate.generatego.txt -source=pkg/azureclients/virtualnetworklinksclient/interface.go -package=mockvirtualnetworklinksclient Interface
-//
-
-// Package mockvirtualnetworklinksclient is a generated GoMock package.
-package mockvirtualnetworklinksclient
-
-import (
-	context "context"
-	reflect "reflect"
-
-	privatedns "github.com/Azure/azure-sdk-for-go/services/privatedns/mgmt/2018-09-01/privatedns"
-	gomock "go.uber.org/mock/gomock"
-	retry "sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-// MockInterface is a mock of Interface interface.
-type MockInterface struct {
-	ctrl     *gomock.Controller
-	recorder *MockInterfaceMockRecorder
-}
-
-// MockInterfaceMockRecorder is the mock recorder for MockInterface.
-type MockInterfaceMockRecorder struct {
-	mock *MockInterface
-}
-
-// NewMockInterface creates a new mock instance.
-func NewMockInterface(ctrl *gomock.Controller) *MockInterface {
-	mock := &MockInterface{ctrl: ctrl}
-	mock.recorder = &MockInterfaceMockRecorder{mock}
-	return mock
-}
-
-// EXPECT returns an object that allows the caller to indicate expected use.
-func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder {
-	return m.recorder
-}
-
-// CreateOrUpdate mocks base method.
-func (m *MockInterface) CreateOrUpdate(ctx context.Context, resourceGroupName, privateZoneName, virtualNetworkLinkName string, parameters privatedns.VirtualNetworkLink, etag string, waitForCompletion bool) *retry.Error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateOrUpdate", ctx, resourceGroupName, privateZoneName, virtualNetworkLinkName, parameters, etag, waitForCompletion)
-	ret0, _ := ret[0].(*retry.Error)
-	return ret0
-}
-
-// CreateOrUpdate indicates an expected call of CreateOrUpdate.
-func (mr *MockInterfaceMockRecorder) CreateOrUpdate(ctx, resourceGroupName, privateZoneName, virtualNetworkLinkName, parameters, etag, waitForCompletion any) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdate", reflect.TypeOf((*MockInterface)(nil).CreateOrUpdate), ctx, resourceGroupName, privateZoneName, virtualNetworkLinkName, parameters, etag, waitForCompletion)
-}
-
-// Get mocks base method.
-func (m *MockInterface) Get(ctx context.Context, resourceGroupName, privateZoneName, virtualNetworkLinkName string) (privatedns.VirtualNetworkLink, *retry.Error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Get", ctx, resourceGroupName, privateZoneName, virtualNetworkLinkName)
-	ret0, _ := ret[0].(privatedns.VirtualNetworkLink)
-	ret1, _ := ret[1].(*retry.Error)
-	return ret0, ret1
-}
-
-// Get indicates an expected call of Get.
-func (mr *MockInterfaceMockRecorder) Get(ctx, resourceGroupName, privateZoneName, virtualNetworkLinkName any) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockInterface)(nil).Get), ctx, resourceGroupName, privateZoneName, virtualNetworkLinkName)
-}
diff --git a/pkg/provider/azure.go b/pkg/provider/azure.go
index d61bef4b4..4f2b178fc 100644
--- a/pkg/provider/azure.go
+++ b/pkg/provider/azure.go
@@ -65,7 +65,6 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/publicipclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/routeclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/routetableclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/securitygroupclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/snapshotclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/storageaccountclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/subnetclient"
@@ -81,6 +80,7 @@ import (
 	azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 	ratelimitconfig "sigs.k8s.io/cloud-provider-azure/pkg/provider/config"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/securitygroup"
 	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
 	utilsets "sigs.k8s.io/cloud-provider-azure/pkg/util/sets"
 	"sigs.k8s.io/cloud-provider-azure/pkg/util/taints"
@@ -365,7 +365,6 @@ type Cloud struct {
 	RouteTablesClient               routetableclient.Interface
 	LoadBalancerClient              loadbalancerclient.Interface
 	PublicIPAddressesClient         publicipclient.Interface
-	SecurityGroupsClient            securitygroupclient.Interface
 	VirtualMachinesClient           vmclient.Interface
 	StorageAccountClient            storageaccountclient.Interface
 	DisksClient                     diskclient.Interface
@@ -425,10 +424,10 @@ type Cloud struct {
 	routeUpdater       batchProcessor
 	backendPoolUpdater batchProcessor
 
-	vmCache  azcache.Resource
-	lbCache  azcache.Resource
-	nsgCache azcache.Resource
-	rtCache  azcache.Resource
+	vmCache azcache.Resource
+	lbCache azcache.Resource
+	nsgRepo securitygroup.Repository
+	rtCache azcache.Resource
 	// public ip cache
 	// key: [resourceGroupName]
 	// Value: sync.Map of [pipName]*PublicIPAddress
@@ -729,8 +728,16 @@ func (az *Cloud) InitializeCloudFromConfig(ctx context.Context, config *Config,
 		if err != nil {
 			return err
 		}
-	}
 
+		networkClientFactory := az.NetworkClientFactory
+		if networkClientFactory == nil {
+			networkClientFactory = az.ComputeClientFactory
+		}
+		az.nsgRepo, err = securitygroup.NewSecurityGroupRepo(az.SecurityGroupResourceGroup, az.SecurityGroupName, az.NsgCacheTTLInSeconds, az.DisableAPICallCache, networkClientFactory.GetSecurityGroupClient())
+		if err != nil {
+			return err
+		}
+	}
 	err = az.initCaches()
 	if err != nil {
 		return err
@@ -843,11 +850,6 @@ func (az *Cloud) initCaches() (err error) {
 		return err
 	}
 
-	az.nsgCache, err = az.newNSGCache()
-	if err != nil {
-		return err
-	}
-
 	az.rtCache, err = az.newRouteTableCache()
 	if err != nil {
 		return err
@@ -975,7 +977,6 @@ func (az *Cloud) configAzureClients(
 	subnetClientConfig := azClientConfig.WithRateLimiter(az.Config.SubnetsRateLimit)
 	routeTableClientConfig := azClientConfig.WithRateLimiter(az.Config.RouteTableRateLimit)
 	loadBalancerClientConfig := azClientConfig.WithRateLimiter(az.Config.LoadBalancerRateLimit)
-	securityGroupClientConfig := azClientConfig.WithRateLimiter(az.Config.SecurityGroupRateLimit)
 	publicIPClientConfig := azClientConfig.WithRateLimiter(az.Config.PublicIPAddressRateLimit)
 	containerServiceConfig := azClientConfig.WithRateLimiter(az.Config.ContainerServiceRateLimit)
 	deploymentConfig := azClientConfig.WithRateLimiter(az.Config.DeploymentRateLimit)
@@ -1005,7 +1006,6 @@ func (az *Cloud) configAzureClients(
 		subnetClientConfig.Authorizer = networkResourceServicePrincipalTokenAuthorizer
 		routeTableClientConfig.Authorizer = networkResourceServicePrincipalTokenAuthorizer
 		loadBalancerClientConfig.Authorizer = networkResourceServicePrincipalTokenAuthorizer
-		securityGroupClientConfig.Authorizer = networkResourceServicePrincipalTokenAuthorizer
 		publicIPClientConfig.Authorizer = networkResourceServicePrincipalTokenAuthorizer
 	}
 
@@ -1014,7 +1014,6 @@ func (az *Cloud) configAzureClients(
 		subnetClientConfig.SubscriptionID = az.Config.NetworkResourceSubscriptionID
 		routeTableClientConfig.SubscriptionID = az.Config.NetworkResourceSubscriptionID
 		loadBalancerClientConfig.SubscriptionID = az.Config.NetworkResourceSubscriptionID
-		securityGroupClientConfig.SubscriptionID = az.Config.NetworkResourceSubscriptionID
 		publicIPClientConfig.SubscriptionID = az.Config.NetworkResourceSubscriptionID
 	}
 
@@ -1031,7 +1030,6 @@ func (az *Cloud) configAzureClients(
 	az.SubnetsClient = subnetclient.New(subnetClientConfig)
 	az.RouteTablesClient = routetableclient.New(routeTableClientConfig)
 	az.LoadBalancerClient = loadbalancerclient.New(loadBalancerClientConfig)
-	az.SecurityGroupsClient = securitygroupclient.New(securityGroupClientConfig)
 	az.PublicIPAddressesClient = publicipclient.New(publicIPClientConfig)
 	az.FileClient = fileclient.New(fileClientConfig)
 	az.BlobClient = blobclient.New(blobClientConfig)
diff --git a/pkg/provider/azure_fakes.go b/pkg/provider/azure_fakes.go
index b86c4fcae..c7c42ab3f 100644
--- a/pkg/provider/azure_fakes.go
+++ b/pkg/provider/azure_fakes.go
@@ -46,6 +46,7 @@ import (
 	azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/config"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/securitygroup"
 	utilsets "sigs.k8s.io/cloud-provider-azure/pkg/util/sets"
 )
 
@@ -138,7 +139,7 @@ func GetTestCloud(ctrl *gomock.Controller) (az *Cloud) {
 	az.VMSet, _ = newAvailabilitySet(az)
 	az.vmCache, _ = az.newVMCache()
 	az.lbCache, _ = az.newLBCache()
-	az.nsgCache, _ = az.newNSGCache()
+	az.nsgRepo, _ = securitygroup.NewSecurityGroupRepo(az.SecurityGroupResourceGroup, az.SecurityGroupName, az.NsgCacheTTLInSeconds, az.Config.DisableAPICallCache, securtyGrouptrack2Client)
 	az.rtCache, _ = az.newRouteTableCache()
 	az.pipCache, _ = az.newPIPCache()
 	az.plsCache, _ = az.newPLSCache()
diff --git a/pkg/provider/azure_loadbalancer.go b/pkg/provider/azure_loadbalancer.go
index 0b7e8643e..c4aae51c2 100644
--- a/pkg/provider/azure_loadbalancer.go
+++ b/pkg/provider/azure_loadbalancer.go
@@ -46,10 +46,10 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/log"
 	"sigs.k8s.io/cloud-provider-azure/pkg/metrics"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/iputil"
 	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
 	"sigs.k8s.io/cloud-provider-azure/pkg/trace"
 	"sigs.k8s.io/cloud-provider-azure/pkg/trace/attributes"
+	"sigs.k8s.io/cloud-provider-azure/pkg/util/iputil"
 	utilsets "sigs.k8s.io/cloud-provider-azure/pkg/util/sets"
 )
 
@@ -2924,7 +2924,7 @@ func (az *Cloud) reconcileSecurityGroup(
 
 	var accessControl *loadbalancer.AccessControl
 	{
-		sg, err := az.getSecurityGroup(ctx, azcache.CacheReadTypeDefault)
+		sg, err := az.nsgRepo.GetSecurityGroup(ctx)
 		if err != nil {
 			return nil, err
 		}
@@ -3036,13 +3036,12 @@ func (az *Cloud) reconcileSecurityGroup(
 	if updated {
 		logger.V(2).Info("Preparing to update security group")
 		logger.V(5).Info("CreateOrUpdateSecurityGroup begin")
-		err := az.CreateOrUpdateSecurityGroup(rv)
+		err := az.nsgRepo.CreateOrUpdateSecurityGroup(ctx, rv)
 		if err != nil {
 			logger.Error(err, "Failed to update security group")
 			return nil, err
 		}
 		logger.V(5).Info("CreateOrUpdateSecurityGroup end")
-		_ = az.nsgCache.Delete(ptr.Deref(rv.Name, ""))
 	}
 	return rv, nil
 }
diff --git a/pkg/provider/azure_loadbalancer_accesscontrol.go b/pkg/provider/azure_loadbalancer_accesscontrol.go
index 60394aa77..e2e48a799 100644
--- a/pkg/provider/azure_loadbalancer_accesscontrol.go
+++ b/pkg/provider/azure_loadbalancer_accesscontrol.go
@@ -28,7 +28,7 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 	"sigs.k8s.io/cloud-provider-azure/pkg/log"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/fnutil"
+	fnutil "sigs.k8s.io/cloud-provider-azure/pkg/util/collectionutil"
 )
 
 func filterServicesByIngressIPs(services []*v1.Service, ips []netip.Addr) []*v1.Service {
diff --git a/pkg/provider/azure_wrap.go b/pkg/provider/azure_wrap.go
index 1e270b998..6a819329a 100644
--- a/pkg/provider/azure_wrap.go
+++ b/pkg/provider/azure_wrap.go
@@ -17,14 +17,11 @@ limitations under the License.
 package provider
 
 import (
-	"errors"
 	"fmt"
 	"net/http"
 	"regexp"
 	"strings"
 
-	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
-
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
 )
@@ -32,7 +29,6 @@ import (
 var (
 	vmCacheTTLDefaultInSeconds           = 60
 	loadBalancerCacheTTLDefaultInSeconds = 120
-	nsgCacheTTLDefaultInSeconds          = 120
 	routeTableCacheTTLDefaultInSeconds   = 120
 	publicIPCacheTTLDefaultInSeconds     = 120
 	plsCacheTTLDefaultInSeconds          = 120
@@ -56,20 +52,6 @@ func checkResourceExistsFromError(err *retry.Error) (bool, *retry.Error) {
 	return false, err
 }
 
-func checkResourceExistsFromAzcoreError(err error) (bool, error) {
-	if err == nil {
-		return true, nil
-	}
-	var respError *azcore.ResponseError
-	if errors.As(err, &respError) && respError != nil {
-		if respError.StatusCode == http.StatusNotFound {
-			return false, nil
-		}
-	}
-
-	return false, err
-}
-
 func (az *Cloud) useStandardLoadBalancer() bool {
 	return strings.EqualFold(az.LoadBalancerSku, consts.LoadBalancerSkuStandard)
 }
diff --git a/pkg/provider/loadbalancer/accesscontrol.go b/pkg/provider/loadbalancer/accesscontrol.go
index 9372895b1..b2044610e 100644
--- a/pkg/provider/loadbalancer/accesscontrol.go
+++ b/pkg/provider/loadbalancer/accesscontrol.go
@@ -27,9 +27,9 @@ import (
 	"k8s.io/utils/ptr"
 
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/fnutil"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/iputil"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/securitygroup"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/securitygroup"
+	fnutil "sigs.k8s.io/cloud-provider-azure/pkg/util/collectionutil"
+	"sigs.k8s.io/cloud-provider-azure/pkg/util/iputil"
 )
 
 var (
diff --git a/pkg/provider/loadbalancer/configuration.go b/pkg/provider/loadbalancer/configuration.go
index 04d04d448..dd8055f05 100644
--- a/pkg/provider/loadbalancer/configuration.go
+++ b/pkg/provider/loadbalancer/configuration.go
@@ -25,7 +25,7 @@ import (
 	v1 "k8s.io/api/core/v1"
 
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/iputil"
+	"sigs.k8s.io/cloud-provider-azure/pkg/util/iputil"
 )
 
 // IsInternal returns true if the given service is internal load balancer.
diff --git a/pkg/provider/azure_securitygroup_repo.go b/pkg/provider/securitygroup/azure_securitygroup_repo.go
similarity index 55%
rename from pkg/provider/azure_securitygroup_repo.go
rename to pkg/provider/securitygroup/azure_securitygroup_repo.go
index c33c3e012..0c602b8ee 100644
--- a/pkg/provider/azure_securitygroup_repo.go
+++ b/pkg/provider/securitygroup/azure_securitygroup_repo.go
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package provider
+package securitygroup
 
 import (
 	"context"
@@ -31,20 +31,66 @@ import (
 	"k8s.io/klog/v2"
 	"k8s.io/utils/ptr"
 
+	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/securitygroupclient"
 	azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
+	"sigs.k8s.io/cloud-provider-azure/pkg/util/errutils"
 )
 
-// CreateOrUpdateSecurityGroup invokes az.SecurityGroupsClient.CreateOrUpdate with exponential backoff retry
-func (az *Cloud) CreateOrUpdateSecurityGroup(sg *armnetwork.SecurityGroup) error {
-	ctx, cancel := getContextWithCancel()
-	defer cancel()
-	clientFactory := az.NetworkClientFactory
-	if clientFactory == nil {
-		clientFactory = az.ComputeClientFactory
+const (
+	nsgCacheTTLDefaultInSeconds = 120
+)
+
+type Repository interface {
+	GetSecurityGroup(ctx context.Context) (*armnetwork.SecurityGroup, error)
+	CreateOrUpdateSecurityGroup(ctx context.Context, sg *armnetwork.SecurityGroup) error
+}
+
+type securityGroupRepo struct {
+	securityGroupResourceGroup string
+	securityGroupName          string
+	nsgCacheTTLInSeconds       int
+	securigyGroupClient        securitygroupclient.Interface
+	nsgCache                   azcache.Resource
+}
+
+func NewSecurityGroupRepo(securityGroupResourceGroup string, securityGroupName string, nsgCacheTTLInSeconds int, disableAPICallCache bool, securityGroupClient securitygroupclient.Interface) (Repository, error) {
+	getter := func(ctx context.Context, key string) (interface{}, error) {
+		nsg, err := securityGroupClient.Get(ctx, securityGroupResourceGroup, key)
+		exists, rerr := errutils.CheckResourceExistsFromAzcoreError(err)
+		if rerr != nil {
+			return nil, err
+		}
+
+		if !exists {
+			klog.V(2).Infof("Security group %q not found", key)
+			return nil, nil
+		}
+
+		return nsg, nil
+	}
+
+	if nsgCacheTTLInSeconds == 0 {
+		nsgCacheTTLInSeconds = nsgCacheTTLDefaultInSeconds
+	}
+	cache, err := azcache.NewTimedCache(time.Duration(nsgCacheTTLInSeconds)*time.Second, getter, disableAPICallCache)
+	if err != nil {
+		klog.Errorf("Failed to create cache for security group %q: %v", securityGroupName, err)
+		return nil, err
 	}
-	sgClient := clientFactory.GetSecurityGroupClient()
-	_, rerr := sgClient.CreateOrUpdate(ctx, az.SecurityGroupResourceGroup, *sg.Name, *sg)
+
+	return &securityGroupRepo{
+		securityGroupResourceGroup: securityGroupResourceGroup,
+		securityGroupName:          securityGroupName,
+		nsgCacheTTLInSeconds:       nsgCacheTTLDefaultInSeconds,
+		securigyGroupClient:        securityGroupClient,
+		nsgCache:                   cache,
+	}, nil
+}
+
+// CreateOrUpdateSecurityGroup invokes az.SecurityGroupsClient.CreateOrUpdate with exponential backoff retry
+func (az *securityGroupRepo) CreateOrUpdateSecurityGroup(ctx context.Context, sg *armnetwork.SecurityGroup) error {
+	_, rerr := az.securigyGroupClient.CreateOrUpdate(ctx, az.securityGroupResourceGroup, *sg.Name, *sg)
 	klog.V(10).Infof("SecurityGroupsClient.CreateOrUpdate(%s): end", *sg.Name)
 	if rerr == nil {
 		// Invalidate the cache right after updating
@@ -71,47 +117,19 @@ func (az *Cloud) CreateOrUpdateSecurityGroup(sg *armnetwork.SecurityGroup) error
 	return rerr
 }
 
-func (az *Cloud) newNSGCache() (azcache.Resource, error) {
-	getter := func(ctx context.Context, key string) (interface{}, error) {
-		clientFactory := az.NetworkClientFactory
-		if clientFactory == nil {
-			clientFactory = az.ComputeClientFactory
-		}
-		sgClient := clientFactory.GetSecurityGroupClient()
-
-		nsg, err := sgClient.Get(ctx, az.SecurityGroupResourceGroup, key)
-		exists, rerr := checkResourceExistsFromAzcoreError(err)
-		if rerr != nil {
-			return nil, err
-		}
-
-		if !exists {
-			klog.V(2).Infof("Security group %q not found", key)
-			return nil, nil
-		}
-
-		return nsg, nil
-	}
-
-	if az.NsgCacheTTLInSeconds == 0 {
-		az.NsgCacheTTLInSeconds = nsgCacheTTLDefaultInSeconds
-	}
-	return azcache.NewTimedCache(time.Duration(az.NsgCacheTTLInSeconds)*time.Second, getter, az.Config.DisableAPICallCache)
-}
-
-func (az *Cloud) getSecurityGroup(ctx context.Context, crt azcache.AzureCacheReadType) (*armnetwork.SecurityGroup, error) {
+func (az *securityGroupRepo) GetSecurityGroup(ctx context.Context) (*armnetwork.SecurityGroup, error) {
 	nsg := &armnetwork.SecurityGroup{}
-	if az.SecurityGroupName == "" {
+	if az.securityGroupName == "" {
 		return nsg, fmt.Errorf("securityGroupName is not configured")
 	}
 
-	securityGroup, err := az.nsgCache.GetWithDeepCopy(ctx, az.SecurityGroupName, crt)
+	securityGroup, err := az.nsgCache.GetWithDeepCopy(ctx, az.securityGroupName, azcache.CacheReadTypeDefault)
 	if err != nil {
 		return nsg, err
 	}
 
 	if securityGroup == nil {
-		return nsg, fmt.Errorf("nsg %q not found", az.SecurityGroupName)
+		return nsg, fmt.Errorf("nsg %q not found", az.securityGroupName)
 	}
 
 	return securityGroup.(*armnetwork.SecurityGroup), nil
diff --git a/pkg/provider/securitygroup/azure_securitygroup_repo_mock.go b/pkg/provider/securitygroup/azure_securitygroup_repo_mock.go
new file mode 100644
index 000000000..017bc064b
--- /dev/null
+++ b/pkg/provider/securitygroup/azure_securitygroup_repo_mock.go
@@ -0,0 +1,87 @@
+// /*
+// Copyright 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.
+// */
+//
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: azure_securitygroup_repo.go
+//
+// Generated by this command:
+//
+//	mockgen -package securitygroup -source azure_securitygroup_repo.go -self_package sigs.k8s.io/cloud-provider-azure/pkg/provider/securitygroup -copyright_file ../../../hack/boilerplate/boilerplate.generatego.txt
+//
+
+// Package securitygroup is a generated GoMock package.
+package securitygroup
+
+import (
+	context "context"
+	reflect "reflect"
+
+	armnetwork "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
+	gomock "go.uber.org/mock/gomock"
+)
+
+// MockRepository is a mock of Repository interface.
+type MockRepository struct {
+	ctrl     *gomock.Controller
+	recorder *MockRepositoryMockRecorder
+}
+
+// MockRepositoryMockRecorder is the mock recorder for MockRepository.
+type MockRepositoryMockRecorder struct {
+	mock *MockRepository
+}
+
+// NewMockRepository creates a new mock instance.
+func NewMockRepository(ctrl *gomock.Controller) *MockRepository {
+	mock := &MockRepository{ctrl: ctrl}
+	mock.recorder = &MockRepositoryMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder {
+	return m.recorder
+}
+
+// CreateOrUpdateSecurityGroup mocks base method.
+func (m *MockRepository) CreateOrUpdateSecurityGroup(ctx context.Context, sg *armnetwork.SecurityGroup) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateOrUpdateSecurityGroup", ctx, sg)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// CreateOrUpdateSecurityGroup indicates an expected call of CreateOrUpdateSecurityGroup.
+func (mr *MockRepositoryMockRecorder) CreateOrUpdateSecurityGroup(ctx, sg any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdateSecurityGroup", reflect.TypeOf((*MockRepository)(nil).CreateOrUpdateSecurityGroup), ctx, sg)
+}
+
+// GetSecurityGroup mocks base method.
+func (m *MockRepository) GetSecurityGroup(ctx context.Context) (*armnetwork.SecurityGroup, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetSecurityGroup", ctx)
+	ret0, _ := ret[0].(*armnetwork.SecurityGroup)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetSecurityGroup indicates an expected call of GetSecurityGroup.
+func (mr *MockRepositoryMockRecorder) GetSecurityGroup(ctx any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSecurityGroup", reflect.TypeOf((*MockRepository)(nil).GetSecurityGroup), ctx)
+}
diff --git a/pkg/provider/loadbalancer/securitygroup/securitygroup.go b/pkg/provider/securitygroup/securitygroup.go
similarity index 99%
rename from pkg/provider/loadbalancer/securitygroup/securitygroup.go
rename to pkg/provider/securitygroup/securitygroup.go
index 8fb6213fc..7ed4be70f 100644
--- a/pkg/provider/loadbalancer/securitygroup/securitygroup.go
+++ b/pkg/provider/securitygroup/securitygroup.go
@@ -30,8 +30,8 @@ import (
 	"k8s.io/utils/ptr"
 
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/fnutil"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/iputil"
+	fnutil "sigs.k8s.io/cloud-provider-azure/pkg/util/collectionutil"
+	"sigs.k8s.io/cloud-provider-azure/pkg/util/iputil"
 )
 
 const (
diff --git a/pkg/provider/loadbalancer/securitygroup/securityrule.go b/pkg/provider/securitygroup/securityrule.go
similarity index 97%
rename from pkg/provider/loadbalancer/securitygroup/securityrule.go
rename to pkg/provider/securitygroup/securityrule.go
index 1cd843d44..481c26f13 100644
--- a/pkg/provider/loadbalancer/securitygroup/securityrule.go
+++ b/pkg/provider/securitygroup/securityrule.go
@@ -27,8 +27,8 @@ import (
 	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
 	v1 "k8s.io/api/core/v1"
 
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/fnutil"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/iputil"
+	fnutil "sigs.k8s.io/cloud-provider-azure/pkg/util/collectionutil"
+	"sigs.k8s.io/cloud-provider-azure/pkg/util/iputil"
 )
 
 // GenerateAllowSecurityRuleName returns the AllowInbound rule name based on the given rule properties.
diff --git a/pkg/provider/loadbalancer/fnutil/map.go b/pkg/util/collectionutil/map.go
similarity index 100%
rename from pkg/provider/loadbalancer/fnutil/map.go
rename to pkg/util/collectionutil/map.go
diff --git a/pkg/provider/loadbalancer/fnutil/slice.go b/pkg/util/collectionutil/slice.go
similarity index 100%
rename from pkg/provider/loadbalancer/fnutil/slice.go
rename to pkg/util/collectionutil/slice.go
diff --git a/pkg/azureclients/virtualnetworklinksclient/mockvirtualnetworklinksclient/doc.go b/pkg/util/errutils/err.go
similarity index 58%
rename from pkg/azureclients/virtualnetworklinksclient/mockvirtualnetworklinksclient/doc.go
rename to pkg/util/errutils/err.go
index 23cc1c691..477b816e4 100644
--- a/pkg/azureclients/virtualnetworklinksclient/mockvirtualnetworklinksclient/doc.go
+++ b/pkg/util/errutils/err.go
@@ -14,5 +14,24 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-// Package mockvirtualnetworklinksclient implements the mock client for VirtualNetworkLinks.
-package mockvirtualnetworklinksclient // import "sigs.k8s.io/cloud-provider-azure/pkg/azureclients/virtualnetworklinksclient/mockvirtualnetworklinksclient"
+package errutils
+
+import (
+	"errors"
+	"net/http"
+
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
+)
+
+func CheckResourceExistsFromAzcoreError(err error) (bool, error) {
+	if err == nil {
+		return true, nil
+	}
+	var respError *azcore.ResponseError
+	if errors.As(err, &respError) && respError != nil {
+		if respError.StatusCode == http.StatusNotFound {
+			return false, nil
+		}
+	}
+	return false, err
+}
diff --git a/pkg/provider/loadbalancer/iputil/addr.go b/pkg/util/iputil/addr.go
similarity index 100%
rename from pkg/provider/loadbalancer/iputil/addr.go
rename to pkg/util/iputil/addr.go
diff --git a/pkg/provider/loadbalancer/iputil/addr_test.go b/pkg/util/iputil/addr_test.go
similarity index 100%
rename from pkg/provider/loadbalancer/iputil/addr_test.go
rename to pkg/util/iputil/addr_test.go
diff --git a/pkg/provider/loadbalancer/iputil/family.go b/pkg/util/iputil/family.go
similarity index 94%
rename from pkg/provider/loadbalancer/iputil/family.go
rename to pkg/util/iputil/family.go
index 9ac42b92f..65a8ce220 100644
--- a/pkg/provider/loadbalancer/iputil/family.go
+++ b/pkg/util/iputil/family.go
@@ -19,7 +19,7 @@ package iputil
 import (
 	"net/netip"
 
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/fnutil"
+	fnutil "sigs.k8s.io/cloud-provider-azure/pkg/util/collectionutil"
 )
 
 type Family string
diff --git a/pkg/provider/loadbalancer/iputil/family_test.go b/pkg/util/iputil/family_test.go
similarity index 100%
rename from pkg/provider/loadbalancer/iputil/family_test.go
rename to pkg/util/iputil/family_test.go
diff --git a/pkg/provider/loadbalancer/iputil/prefix.go b/pkg/util/iputil/prefix.go
similarity index 100%
rename from pkg/provider/loadbalancer/iputil/prefix.go
rename to pkg/util/iputil/prefix.go
diff --git a/pkg/provider/loadbalancer/iputil/prefix_test.go b/pkg/util/iputil/prefix_test.go
similarity index 100%
rename from pkg/provider/loadbalancer/iputil/prefix_test.go
rename to pkg/util/iputil/prefix_test.go
diff --git a/pkg/provider/loadbalancer/iputil/prefix_tree.go b/pkg/util/iputil/prefix_tree.go
similarity index 100%
rename from pkg/provider/loadbalancer/iputil/prefix_tree.go
rename to pkg/util/iputil/prefix_tree.go
diff --git a/pkg/provider/loadbalancer/iputil/prefix_tree_test.go b/pkg/util/iputil/prefix_tree_test.go
similarity index 100%
rename from pkg/provider/loadbalancer/iputil/prefix_tree_test.go
rename to pkg/util/iputil/prefix_tree_test.go
diff --git a/vendor/golang.org/x/sys/unix/README.md b/vendor/golang.org/x/sys/unix/README.md
index 7d3c060e1..6e08a76a7 100644
--- a/vendor/golang.org/x/sys/unix/README.md
+++ b/vendor/golang.org/x/sys/unix/README.md
@@ -156,7 +156,7 @@ from the generated architecture-specific files listed below, and merge these
 into a common file for each OS.
 
 The merge is performed in the following steps:
-1. Construct the set of common code that is idential in all architecture-specific files.
+1. Construct the set of common code that is identical in all architecture-specific files.
 2. Write this common code to the merged file.
 3. Remove the common code from all architecture-specific files.
 
diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh
index e14b766a3..ac54ecaba 100644
--- a/vendor/golang.org/x/sys/unix/mkerrors.sh
+++ b/vendor/golang.org/x/sys/unix/mkerrors.sh
@@ -656,7 +656,7 @@ errors=$(
 signals=$(
 	echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
 	awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
-	grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' |
+	grep -E -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' |
 	sort
 )
 
@@ -666,7 +666,7 @@ echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
 	sort >_error.grep
 echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
 	awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
-	grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' |
+	grep -E -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' |
 	sort >_signal.grep
 
 echo '// mkerrors.sh' "$@"
diff --git a/vendor/golang.org/x/sys/unix/syscall_aix.go b/vendor/golang.org/x/sys/unix/syscall_aix.go
index 67ce6cef2..6f15ba1ea 100644
--- a/vendor/golang.org/x/sys/unix/syscall_aix.go
+++ b/vendor/golang.org/x/sys/unix/syscall_aix.go
@@ -360,7 +360,7 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int,
 	var status _C_int
 	var r Pid_t
 	err = ERESTART
-	// AIX wait4 may return with ERESTART errno, while the processus is still
+	// AIX wait4 may return with ERESTART errno, while the process is still
 	// active.
 	for err == ERESTART {
 		r, err = wait4(Pid_t(pid), &status, options, rusage)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go
index 3f1d3d4cb..f08abd434 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux.go
@@ -1295,6 +1295,48 @@ func GetsockoptTCPInfo(fd, level, opt int) (*TCPInfo, error) {
 	return &value, err
 }
 
+// GetsockoptTCPCCVegasInfo returns algorithm specific congestion control information for a socket using the "vegas"
+// algorithm.
+//
+// The socket's congestion control algorighm can be retrieved via [GetsockoptString] with the [TCP_CONGESTION] option:
+//
+//	algo, err := unix.GetsockoptString(fd, unix.IPPROTO_TCP, unix.TCP_CONGESTION)
+func GetsockoptTCPCCVegasInfo(fd, level, opt int) (*TCPVegasInfo, error) {
+	var value [SizeofTCPCCInfo / 4]uint32 // ensure proper alignment
+	vallen := _Socklen(SizeofTCPCCInfo)
+	err := getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
+	out := (*TCPVegasInfo)(unsafe.Pointer(&value[0]))
+	return out, err
+}
+
+// GetsockoptTCPCCDCTCPInfo returns algorithm specific congestion control information for a socket using the "dctp"
+// algorithm.
+//
+// The socket's congestion control algorighm can be retrieved via [GetsockoptString] with the [TCP_CONGESTION] option:
+//
+//	algo, err := unix.GetsockoptString(fd, unix.IPPROTO_TCP, unix.TCP_CONGESTION)
+func GetsockoptTCPCCDCTCPInfo(fd, level, opt int) (*TCPDCTCPInfo, error) {
+	var value [SizeofTCPCCInfo / 4]uint32 // ensure proper alignment
+	vallen := _Socklen(SizeofTCPCCInfo)
+	err := getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
+	out := (*TCPDCTCPInfo)(unsafe.Pointer(&value[0]))
+	return out, err
+}
+
+// GetsockoptTCPCCBBRInfo returns algorithm specific congestion control information for a socket using the "bbr"
+// algorithm.
+//
+// The socket's congestion control algorighm can be retrieved via [GetsockoptString] with the [TCP_CONGESTION] option:
+//
+//	algo, err := unix.GetsockoptString(fd, unix.IPPROTO_TCP, unix.TCP_CONGESTION)
+func GetsockoptTCPCCBBRInfo(fd, level, opt int) (*TCPBBRInfo, error) {
+	var value [SizeofTCPCCInfo / 4]uint32 // ensure proper alignment
+	vallen := _Socklen(SizeofTCPCCInfo)
+	err := getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
+	out := (*TCPBBRInfo)(unsafe.Pointer(&value[0]))
+	return out, err
+}
+
 // GetsockoptString returns the string value of the socket option opt for the
 // socket associated with fd at the given socket level.
 func GetsockoptString(fd, level, opt int) (string, error) {
@@ -1959,7 +2001,26 @@ func Getpgrp() (pid int) {
 //sysnb	Getpid() (pid int)
 //sysnb	Getppid() (ppid int)
 //sys	Getpriority(which int, who int) (prio int, err error)
-//sys	Getrandom(buf []byte, flags int) (n int, err error)
+
+func Getrandom(buf []byte, flags int) (n int, err error) {
+	vdsoRet, supported := vgetrandom(buf, uint32(flags))
+	if supported {
+		if vdsoRet < 0 {
+			return 0, errnoErr(syscall.Errno(-vdsoRet))
+		}
+		return vdsoRet, nil
+	}
+	var p *byte
+	if len(buf) > 0 {
+		p = &buf[0]
+	}
+	r, _, e := Syscall(SYS_GETRANDOM, uintptr(unsafe.Pointer(p)), uintptr(len(buf)), uintptr(flags))
+	if e != 0 {
+		return 0, errnoErr(e)
+	}
+	return int(r), nil
+}
+
 //sysnb	Getrusage(who int, rusage *Rusage) (err error)
 //sysnb	Getsid(pid int) (sid int, err error)
 //sysnb	Gettid() (tid int)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
index cf2ee6c75..745e5c7e6 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
@@ -182,3 +182,5 @@ func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error
 	}
 	return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags)
 }
+
+const SYS_FSTATAT = SYS_NEWFSTATAT
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go b/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go
index 3d0e98451..dd2262a40 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go
@@ -214,3 +214,5 @@ func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error
 	}
 	return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags)
 }
+
+const SYS_FSTATAT = SYS_NEWFSTATAT
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
index 6f5a28894..8cf3670bd 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
@@ -187,3 +187,5 @@ func RISCVHWProbe(pairs []RISCVHWProbePairs, set *CPUSet, flags uint) (err error
 	}
 	return riscvHWProbe(pairs, setSize, set, flags)
 }
+
+const SYS_FSTATAT = SYS_NEWFSTATAT
diff --git a/vendor/golang.org/x/sys/unix/vgetrandom_linux.go b/vendor/golang.org/x/sys/unix/vgetrandom_linux.go
new file mode 100644
index 000000000..07ac8e09d
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/vgetrandom_linux.go
@@ -0,0 +1,13 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux && go1.24
+
+package unix
+
+import _ "unsafe"
+
+//go:linkname vgetrandom runtime.vgetrandom
+//go:noescape
+func vgetrandom(p []byte, flags uint32) (ret int, supported bool)
diff --git a/vendor/golang.org/x/sys/unix/vgetrandom_unsupported.go b/vendor/golang.org/x/sys/unix/vgetrandom_unsupported.go
new file mode 100644
index 000000000..297e97bce
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/vgetrandom_unsupported.go
@@ -0,0 +1,11 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !linux || !go1.24
+
+package unix
+
+func vgetrandom(p []byte, flags uint32) (ret int, supported bool) {
+	return -1, false
+}
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go
index 01a70b246..de3b46248 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go
@@ -495,6 +495,7 @@ const (
 	BPF_F_TEST_REG_INVARIANTS                   = 0x80
 	BPF_F_TEST_RND_HI32                         = 0x4
 	BPF_F_TEST_RUN_ON_CPU                       = 0x1
+	BPF_F_TEST_SKB_CHECKSUM_COMPLETE            = 0x4
 	BPF_F_TEST_STATE_FREQ                       = 0x8
 	BPF_F_TEST_XDP_LIVE_FRAMES                  = 0x2
 	BPF_F_XDP_DEV_BOUND_ONLY                    = 0x40
@@ -1922,6 +1923,7 @@ const (
 	MNT_EXPIRE                                  = 0x4
 	MNT_FORCE                                   = 0x1
 	MNT_ID_REQ_SIZE_VER0                        = 0x18
+	MNT_ID_REQ_SIZE_VER1                        = 0x20
 	MODULE_INIT_COMPRESSED_FILE                 = 0x4
 	MODULE_INIT_IGNORE_MODVERSIONS              = 0x1
 	MODULE_INIT_IGNORE_VERMAGIC                 = 0x2
@@ -2187,7 +2189,7 @@ const (
 	NFT_REG_SIZE                                = 0x10
 	NFT_REJECT_ICMPX_MAX                        = 0x3
 	NFT_RT_MAX                                  = 0x4
-	NFT_SECMARK_CTX_MAXLEN                      = 0x100
+	NFT_SECMARK_CTX_MAXLEN                      = 0x1000
 	NFT_SET_MAXNAMELEN                          = 0x100
 	NFT_SOCKET_MAX                              = 0x3
 	NFT_TABLE_F_MASK                            = 0x7
@@ -2356,9 +2358,11 @@ const (
 	PERF_MEM_LVLNUM_IO                          = 0xa
 	PERF_MEM_LVLNUM_L1                          = 0x1
 	PERF_MEM_LVLNUM_L2                          = 0x2
+	PERF_MEM_LVLNUM_L2_MHB                      = 0x5
 	PERF_MEM_LVLNUM_L3                          = 0x3
 	PERF_MEM_LVLNUM_L4                          = 0x4
 	PERF_MEM_LVLNUM_LFB                         = 0xc
+	PERF_MEM_LVLNUM_MSC                         = 0x6
 	PERF_MEM_LVLNUM_NA                          = 0xf
 	PERF_MEM_LVLNUM_PMEM                        = 0xe
 	PERF_MEM_LVLNUM_RAM                         = 0xd
@@ -2431,6 +2435,7 @@ const (
 	PRIO_PGRP                                   = 0x1
 	PRIO_PROCESS                                = 0x0
 	PRIO_USER                                   = 0x2
+	PROCFS_IOCTL_MAGIC                          = 'f'
 	PROC_SUPER_MAGIC                            = 0x9fa0
 	PROT_EXEC                                   = 0x4
 	PROT_GROWSDOWN                              = 0x1000000
@@ -2933,11 +2938,12 @@ const (
 	RUSAGE_SELF                                 = 0x0
 	RUSAGE_THREAD                               = 0x1
 	RWF_APPEND                                  = 0x10
+	RWF_ATOMIC                                  = 0x40
 	RWF_DSYNC                                   = 0x2
 	RWF_HIPRI                                   = 0x1
 	RWF_NOAPPEND                                = 0x20
 	RWF_NOWAIT                                  = 0x8
-	RWF_SUPPORTED                               = 0x3f
+	RWF_SUPPORTED                               = 0x7f
 	RWF_SYNC                                    = 0x4
 	RWF_WRITE_LIFE_NOT_SET                      = 0x0
 	SCHED_BATCH                                 = 0x3
@@ -3210,6 +3216,7 @@ const (
 	STATX_ATTR_MOUNT_ROOT                       = 0x2000
 	STATX_ATTR_NODUMP                           = 0x40
 	STATX_ATTR_VERITY                           = 0x100000
+	STATX_ATTR_WRITE_ATOMIC                     = 0x400000
 	STATX_BASIC_STATS                           = 0x7ff
 	STATX_BLOCKS                                = 0x400
 	STATX_BTIME                                 = 0x800
@@ -3226,6 +3233,7 @@ const (
 	STATX_SUBVOL                                = 0x8000
 	STATX_TYPE                                  = 0x1
 	STATX_UID                                   = 0x8
+	STATX_WRITE_ATOMIC                          = 0x10000
 	STATX__RESERVED                             = 0x80000000
 	SYNC_FILE_RANGE_WAIT_AFTER                  = 0x4
 	SYNC_FILE_RANGE_WAIT_BEFORE                 = 0x1
@@ -3624,6 +3632,7 @@ const (
 	XDP_UMEM_PGOFF_COMPLETION_RING              = 0x180000000
 	XDP_UMEM_PGOFF_FILL_RING                    = 0x100000000
 	XDP_UMEM_REG                                = 0x4
+	XDP_UMEM_TX_METADATA_LEN                    = 0x4
 	XDP_UMEM_TX_SW_CSUM                         = 0x2
 	XDP_UMEM_UNALIGNED_CHUNK_FLAG               = 0x1
 	XDP_USE_NEED_WAKEUP                         = 0x8
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
index 684a5168d..8aa6d77c0 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
@@ -153,9 +153,14 @@ const (
 	NFDBITS                          = 0x20
 	NLDLY                            = 0x100
 	NOFLSH                           = 0x80
+	NS_GET_MNTNS_ID                  = 0x8008b705
 	NS_GET_NSTYPE                    = 0xb703
 	NS_GET_OWNER_UID                 = 0xb704
 	NS_GET_PARENT                    = 0xb702
+	NS_GET_PID_FROM_PIDNS            = 0x8004b706
+	NS_GET_PID_IN_PIDNS              = 0x8004b708
+	NS_GET_TGID_FROM_PIDNS           = 0x8004b707
+	NS_GET_TGID_IN_PIDNS             = 0x8004b709
 	NS_GET_USERNS                    = 0xb701
 	OLCUC                            = 0x2
 	ONLCR                            = 0x4
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
index 61d74b592..da428f425 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
@@ -153,9 +153,14 @@ const (
 	NFDBITS                          = 0x40
 	NLDLY                            = 0x100
 	NOFLSH                           = 0x80
+	NS_GET_MNTNS_ID                  = 0x8008b705
 	NS_GET_NSTYPE                    = 0xb703
 	NS_GET_OWNER_UID                 = 0xb704
 	NS_GET_PARENT                    = 0xb702
+	NS_GET_PID_FROM_PIDNS            = 0x8004b706
+	NS_GET_PID_IN_PIDNS              = 0x8004b708
+	NS_GET_TGID_FROM_PIDNS           = 0x8004b707
+	NS_GET_TGID_IN_PIDNS             = 0x8004b709
 	NS_GET_USERNS                    = 0xb701
 	OLCUC                            = 0x2
 	ONLCR                            = 0x4
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
index a28c9e3e8..bf45bfec7 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
@@ -150,9 +150,14 @@ const (
 	NFDBITS                          = 0x20
 	NLDLY                            = 0x100
 	NOFLSH                           = 0x80
+	NS_GET_MNTNS_ID                  = 0x8008b705
 	NS_GET_NSTYPE                    = 0xb703
 	NS_GET_OWNER_UID                 = 0xb704
 	NS_GET_PARENT                    = 0xb702
+	NS_GET_PID_FROM_PIDNS            = 0x8004b706
+	NS_GET_PID_IN_PIDNS              = 0x8004b708
+	NS_GET_TGID_FROM_PIDNS           = 0x8004b707
+	NS_GET_TGID_IN_PIDNS             = 0x8004b709
 	NS_GET_USERNS                    = 0xb701
 	OLCUC                            = 0x2
 	ONLCR                            = 0x4
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
index ab5d1fe8e..71c67162b 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
@@ -154,9 +154,14 @@ const (
 	NFDBITS                          = 0x40
 	NLDLY                            = 0x100
 	NOFLSH                           = 0x80
+	NS_GET_MNTNS_ID                  = 0x8008b705
 	NS_GET_NSTYPE                    = 0xb703
 	NS_GET_OWNER_UID                 = 0xb704
 	NS_GET_PARENT                    = 0xb702
+	NS_GET_PID_FROM_PIDNS            = 0x8004b706
+	NS_GET_PID_IN_PIDNS              = 0x8004b708
+	NS_GET_TGID_FROM_PIDNS           = 0x8004b707
+	NS_GET_TGID_IN_PIDNS             = 0x8004b709
 	NS_GET_USERNS                    = 0xb701
 	OLCUC                            = 0x2
 	ONLCR                            = 0x4
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
index c523090e7..9476628fa 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
@@ -154,9 +154,14 @@ const (
 	NFDBITS                          = 0x40
 	NLDLY                            = 0x100
 	NOFLSH                           = 0x80
+	NS_GET_MNTNS_ID                  = 0x8008b705
 	NS_GET_NSTYPE                    = 0xb703
 	NS_GET_OWNER_UID                 = 0xb704
 	NS_GET_PARENT                    = 0xb702
+	NS_GET_PID_FROM_PIDNS            = 0x8004b706
+	NS_GET_PID_IN_PIDNS              = 0x8004b708
+	NS_GET_TGID_FROM_PIDNS           = 0x8004b707
+	NS_GET_TGID_IN_PIDNS             = 0x8004b709
 	NS_GET_USERNS                    = 0xb701
 	OLCUC                            = 0x2
 	ONLCR                            = 0x4
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
index 01e6ea780..b9e85f3cf 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
@@ -150,9 +150,14 @@ const (
 	NFDBITS                          = 0x20
 	NLDLY                            = 0x100
 	NOFLSH                           = 0x80
+	NS_GET_MNTNS_ID                  = 0x4008b705
 	NS_GET_NSTYPE                    = 0x2000b703
 	NS_GET_OWNER_UID                 = 0x2000b704
 	NS_GET_PARENT                    = 0x2000b702
+	NS_GET_PID_FROM_PIDNS            = 0x4004b706
+	NS_GET_PID_IN_PIDNS              = 0x4004b708
+	NS_GET_TGID_FROM_PIDNS           = 0x4004b707
+	NS_GET_TGID_IN_PIDNS             = 0x4004b709
 	NS_GET_USERNS                    = 0x2000b701
 	OLCUC                            = 0x2
 	ONLCR                            = 0x4
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
index 7aa610b1e..a48b68a76 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
@@ -150,9 +150,14 @@ const (
 	NFDBITS                          = 0x40
 	NLDLY                            = 0x100
 	NOFLSH                           = 0x80
+	NS_GET_MNTNS_ID                  = 0x4008b705
 	NS_GET_NSTYPE                    = 0x2000b703
 	NS_GET_OWNER_UID                 = 0x2000b704
 	NS_GET_PARENT                    = 0x2000b702
+	NS_GET_PID_FROM_PIDNS            = 0x4004b706
+	NS_GET_PID_IN_PIDNS              = 0x4004b708
+	NS_GET_TGID_FROM_PIDNS           = 0x4004b707
+	NS_GET_TGID_IN_PIDNS             = 0x4004b709
 	NS_GET_USERNS                    = 0x2000b701
 	OLCUC                            = 0x2
 	ONLCR                            = 0x4
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
index 92af771b4..ea00e8522 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
@@ -150,9 +150,14 @@ const (
 	NFDBITS                          = 0x40
 	NLDLY                            = 0x100
 	NOFLSH                           = 0x80
+	NS_GET_MNTNS_ID                  = 0x4008b705
 	NS_GET_NSTYPE                    = 0x2000b703
 	NS_GET_OWNER_UID                 = 0x2000b704
 	NS_GET_PARENT                    = 0x2000b702
+	NS_GET_PID_FROM_PIDNS            = 0x4004b706
+	NS_GET_PID_IN_PIDNS              = 0x4004b708
+	NS_GET_TGID_FROM_PIDNS           = 0x4004b707
+	NS_GET_TGID_IN_PIDNS             = 0x4004b709
 	NS_GET_USERNS                    = 0x2000b701
 	OLCUC                            = 0x2
 	ONLCR                            = 0x4
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
index b27ef5e6f..91c646871 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
@@ -150,9 +150,14 @@ const (
 	NFDBITS                          = 0x20
 	NLDLY                            = 0x100
 	NOFLSH                           = 0x80
+	NS_GET_MNTNS_ID                  = 0x4008b705
 	NS_GET_NSTYPE                    = 0x2000b703
 	NS_GET_OWNER_UID                 = 0x2000b704
 	NS_GET_PARENT                    = 0x2000b702
+	NS_GET_PID_FROM_PIDNS            = 0x4004b706
+	NS_GET_PID_IN_PIDNS              = 0x4004b708
+	NS_GET_TGID_FROM_PIDNS           = 0x4004b707
+	NS_GET_TGID_IN_PIDNS             = 0x4004b709
 	NS_GET_USERNS                    = 0x2000b701
 	OLCUC                            = 0x2
 	ONLCR                            = 0x4
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
index 237a2cefb..8cbf38d63 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
@@ -152,9 +152,14 @@ const (
 	NL3                              = 0x300
 	NLDLY                            = 0x300
 	NOFLSH                           = 0x80000000
+	NS_GET_MNTNS_ID                  = 0x4008b705
 	NS_GET_NSTYPE                    = 0x2000b703
 	NS_GET_OWNER_UID                 = 0x2000b704
 	NS_GET_PARENT                    = 0x2000b702
+	NS_GET_PID_FROM_PIDNS            = 0x4004b706
+	NS_GET_PID_IN_PIDNS              = 0x4004b708
+	NS_GET_TGID_FROM_PIDNS           = 0x4004b707
+	NS_GET_TGID_IN_PIDNS             = 0x4004b709
 	NS_GET_USERNS                    = 0x2000b701
 	OLCUC                            = 0x4
 	ONLCR                            = 0x2
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
index 4a5c555a3..a2df73419 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
@@ -152,9 +152,14 @@ const (
 	NL3                              = 0x300
 	NLDLY                            = 0x300
 	NOFLSH                           = 0x80000000
+	NS_GET_MNTNS_ID                  = 0x4008b705
 	NS_GET_NSTYPE                    = 0x2000b703
 	NS_GET_OWNER_UID                 = 0x2000b704
 	NS_GET_PARENT                    = 0x2000b702
+	NS_GET_PID_FROM_PIDNS            = 0x4004b706
+	NS_GET_PID_IN_PIDNS              = 0x4004b708
+	NS_GET_TGID_FROM_PIDNS           = 0x4004b707
+	NS_GET_TGID_IN_PIDNS             = 0x4004b709
 	NS_GET_USERNS                    = 0x2000b701
 	OLCUC                            = 0x4
 	ONLCR                            = 0x2
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
index a02fb49a5..247913792 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
@@ -152,9 +152,14 @@ const (
 	NL3                              = 0x300
 	NLDLY                            = 0x300
 	NOFLSH                           = 0x80000000
+	NS_GET_MNTNS_ID                  = 0x4008b705
 	NS_GET_NSTYPE                    = 0x2000b703
 	NS_GET_OWNER_UID                 = 0x2000b704
 	NS_GET_PARENT                    = 0x2000b702
+	NS_GET_PID_FROM_PIDNS            = 0x4004b706
+	NS_GET_PID_IN_PIDNS              = 0x4004b708
+	NS_GET_TGID_FROM_PIDNS           = 0x4004b707
+	NS_GET_TGID_IN_PIDNS             = 0x4004b709
 	NS_GET_USERNS                    = 0x2000b701
 	OLCUC                            = 0x4
 	ONLCR                            = 0x2
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
index e26a7c61b..d265f146e 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
@@ -150,9 +150,14 @@ const (
 	NFDBITS                          = 0x40
 	NLDLY                            = 0x100
 	NOFLSH                           = 0x80
+	NS_GET_MNTNS_ID                  = 0x8008b705
 	NS_GET_NSTYPE                    = 0xb703
 	NS_GET_OWNER_UID                 = 0xb704
 	NS_GET_PARENT                    = 0xb702
+	NS_GET_PID_FROM_PIDNS            = 0x8004b706
+	NS_GET_PID_IN_PIDNS              = 0x8004b708
+	NS_GET_TGID_FROM_PIDNS           = 0x8004b707
+	NS_GET_TGID_IN_PIDNS             = 0x8004b709
 	NS_GET_USERNS                    = 0xb701
 	OLCUC                            = 0x2
 	ONLCR                            = 0x4
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
index c48f7c210..3f2d64439 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
@@ -150,9 +150,14 @@ const (
 	NFDBITS                          = 0x40
 	NLDLY                            = 0x100
 	NOFLSH                           = 0x80
+	NS_GET_MNTNS_ID                  = 0x8008b705
 	NS_GET_NSTYPE                    = 0xb703
 	NS_GET_OWNER_UID                 = 0xb704
 	NS_GET_PARENT                    = 0xb702
+	NS_GET_PID_FROM_PIDNS            = 0x8004b706
+	NS_GET_PID_IN_PIDNS              = 0x8004b708
+	NS_GET_TGID_FROM_PIDNS           = 0x8004b707
+	NS_GET_TGID_IN_PIDNS             = 0x8004b709
 	NS_GET_USERNS                    = 0xb701
 	OLCUC                            = 0x2
 	ONLCR                            = 0x4
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
index ad4b9aace..5d8b727a1 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
@@ -155,9 +155,14 @@ const (
 	NFDBITS                          = 0x40
 	NLDLY                            = 0x100
 	NOFLSH                           = 0x80
+	NS_GET_MNTNS_ID                  = 0x4008b705
 	NS_GET_NSTYPE                    = 0x2000b703
 	NS_GET_OWNER_UID                 = 0x2000b704
 	NS_GET_PARENT                    = 0x2000b702
+	NS_GET_PID_FROM_PIDNS            = 0x4004b706
+	NS_GET_PID_IN_PIDNS              = 0x4004b708
+	NS_GET_TGID_FROM_PIDNS           = 0x4004b707
+	NS_GET_TGID_IN_PIDNS             = 0x4004b709
 	NS_GET_USERNS                    = 0x2000b701
 	OLCUC                            = 0x2
 	ONLCR                            = 0x4
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux.go b/vendor/golang.org/x/sys/unix/zsyscall_linux.go
index 1bc1a5adb..af30da557 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux.go
@@ -971,23 +971,6 @@ func Getpriority(which int, who int) (prio int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getrandom(buf []byte, flags int) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(buf) > 0 {
-		_p0 = unsafe.Pointer(&buf[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall(SYS_GETRANDOM, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
-	n = int(r0)
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go
index d3e38f681..f485dbf45 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go
@@ -341,6 +341,7 @@ const (
 	SYS_STATX                   = 332
 	SYS_IO_PGETEVENTS           = 333
 	SYS_RSEQ                    = 334
+	SYS_URETPROBE               = 335
 	SYS_PIDFD_SEND_SIGNAL       = 424
 	SYS_IO_URING_SETUP          = 425
 	SYS_IO_URING_ENTER          = 426
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go
index 6c778c232..1893e2fe8 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go
@@ -85,7 +85,7 @@ const (
 	SYS_SPLICE                  = 76
 	SYS_TEE                     = 77
 	SYS_READLINKAT              = 78
-	SYS_FSTATAT                 = 79
+	SYS_NEWFSTATAT              = 79
 	SYS_FSTAT                   = 80
 	SYS_SYNC                    = 81
 	SYS_FSYNC                   = 82
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go
index 37281cf51..16a4017da 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go
@@ -84,6 +84,8 @@ const (
 	SYS_SPLICE                  = 76
 	SYS_TEE                     = 77
 	SYS_READLINKAT              = 78
+	SYS_NEWFSTATAT              = 79
+	SYS_FSTAT                   = 80
 	SYS_SYNC                    = 81
 	SYS_FSYNC                   = 82
 	SYS_FDATASYNC               = 83
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go
index 9889f6a55..a5459e766 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go
@@ -84,7 +84,7 @@ const (
 	SYS_SPLICE                  = 76
 	SYS_TEE                     = 77
 	SYS_READLINKAT              = 78
-	SYS_FSTATAT                 = 79
+	SYS_NEWFSTATAT              = 79
 	SYS_FSTAT                   = 80
 	SYS_SYNC                    = 81
 	SYS_FSYNC                   = 82
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go
index 9f2550dc3..3a69e4549 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go
@@ -87,31 +87,35 @@ type StatxTimestamp struct {
 }
 
 type Statx_t struct {
-	Mask             uint32
-	Blksize          uint32
-	Attributes       uint64
-	Nlink            uint32
-	Uid              uint32
-	Gid              uint32
-	Mode             uint16
-	_                [1]uint16
-	Ino              uint64
-	Size             uint64
-	Blocks           uint64
-	Attributes_mask  uint64
-	Atime            StatxTimestamp
-	Btime            StatxTimestamp
-	Ctime            StatxTimestamp
-	Mtime            StatxTimestamp
-	Rdev_major       uint32
-	Rdev_minor       uint32
-	Dev_major        uint32
-	Dev_minor        uint32
-	Mnt_id           uint64
-	Dio_mem_align    uint32
-	Dio_offset_align uint32
-	Subvol           uint64
-	_                [11]uint64
+	Mask                      uint32
+	Blksize                   uint32
+	Attributes                uint64
+	Nlink                     uint32
+	Uid                       uint32
+	Gid                       uint32
+	Mode                      uint16
+	_                         [1]uint16
+	Ino                       uint64
+	Size                      uint64
+	Blocks                    uint64
+	Attributes_mask           uint64
+	Atime                     StatxTimestamp
+	Btime                     StatxTimestamp
+	Ctime                     StatxTimestamp
+	Mtime                     StatxTimestamp
+	Rdev_major                uint32
+	Rdev_minor                uint32
+	Dev_major                 uint32
+	Dev_minor                 uint32
+	Mnt_id                    uint64
+	Dio_mem_align             uint32
+	Dio_offset_align          uint32
+	Subvol                    uint64
+	Atomic_write_unit_min     uint32
+	Atomic_write_unit_max     uint32
+	Atomic_write_segments_max uint32
+	_                         [1]uint32
+	_                         [9]uint64
 }
 
 type Fsid struct {
@@ -516,6 +520,29 @@ type TCPInfo struct {
 	Total_rto_time       uint32
 }
 
+type TCPVegasInfo struct {
+	Enabled uint32
+	Rttcnt  uint32
+	Rtt     uint32
+	Minrtt  uint32
+}
+
+type TCPDCTCPInfo struct {
+	Enabled  uint16
+	Ce_state uint16
+	Alpha    uint32
+	Ab_ecn   uint32
+	Ab_tot   uint32
+}
+
+type TCPBBRInfo struct {
+	Bw_lo       uint32
+	Bw_hi       uint32
+	Min_rtt     uint32
+	Pacing_gain uint32
+	Cwnd_gain   uint32
+}
+
 type CanFilter struct {
 	Id   uint32
 	Mask uint32
@@ -557,6 +584,7 @@ const (
 	SizeofICMPv6Filter      = 0x20
 	SizeofUcred             = 0xc
 	SizeofTCPInfo           = 0xf8
+	SizeofTCPCCInfo         = 0x14
 	SizeofCanFilter         = 0x8
 	SizeofTCPRepairOpt      = 0x8
 )
@@ -3766,7 +3794,7 @@ const (
 	ETHTOOL_MSG_PSE_GET                       = 0x24
 	ETHTOOL_MSG_PSE_SET                       = 0x25
 	ETHTOOL_MSG_RSS_GET                       = 0x26
-	ETHTOOL_MSG_USER_MAX                      = 0x2b
+	ETHTOOL_MSG_USER_MAX                      = 0x2c
 	ETHTOOL_MSG_KERNEL_NONE                   = 0x0
 	ETHTOOL_MSG_STRSET_GET_REPLY              = 0x1
 	ETHTOOL_MSG_LINKINFO_GET_REPLY            = 0x2
@@ -3806,7 +3834,7 @@ const (
 	ETHTOOL_MSG_MODULE_NTF                    = 0x24
 	ETHTOOL_MSG_PSE_GET_REPLY                 = 0x25
 	ETHTOOL_MSG_RSS_GET_REPLY                 = 0x26
-	ETHTOOL_MSG_KERNEL_MAX                    = 0x2b
+	ETHTOOL_MSG_KERNEL_MAX                    = 0x2c
 	ETHTOOL_FLAG_COMPACT_BITSETS              = 0x1
 	ETHTOOL_FLAG_OMIT_REPLY                   = 0x2
 	ETHTOOL_FLAG_STATS                        = 0x4
@@ -3951,7 +3979,7 @@ const (
 	ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL   = 0x17
 	ETHTOOL_A_COALESCE_USE_CQE_MODE_TX        = 0x18
 	ETHTOOL_A_COALESCE_USE_CQE_MODE_RX        = 0x19
-	ETHTOOL_A_COALESCE_MAX                    = 0x1c
+	ETHTOOL_A_COALESCE_MAX                    = 0x1e
 	ETHTOOL_A_PAUSE_UNSPEC                    = 0x0
 	ETHTOOL_A_PAUSE_HEADER                    = 0x1
 	ETHTOOL_A_PAUSE_AUTONEG                   = 0x2
@@ -4609,7 +4637,7 @@ const (
 	NL80211_ATTR_MAC_HINT                                   = 0xc8
 	NL80211_ATTR_MAC_MASK                                   = 0xd7
 	NL80211_ATTR_MAX_AP_ASSOC_STA                           = 0xca
-	NL80211_ATTR_MAX                                        = 0x14a
+	NL80211_ATTR_MAX                                        = 0x14c
 	NL80211_ATTR_MAX_CRIT_PROT_DURATION                     = 0xb4
 	NL80211_ATTR_MAX_CSA_COUNTERS                           = 0xce
 	NL80211_ATTR_MAX_MATCH_SETS                             = 0x85
@@ -5213,7 +5241,7 @@ const (
 	NL80211_FREQUENCY_ATTR_GO_CONCURRENT                    = 0xf
 	NL80211_FREQUENCY_ATTR_INDOOR_ONLY                      = 0xe
 	NL80211_FREQUENCY_ATTR_IR_CONCURRENT                    = 0xf
-	NL80211_FREQUENCY_ATTR_MAX                              = 0x20
+	NL80211_FREQUENCY_ATTR_MAX                              = 0x21
 	NL80211_FREQUENCY_ATTR_MAX_TX_POWER                     = 0x6
 	NL80211_FREQUENCY_ATTR_NO_10MHZ                         = 0x11
 	NL80211_FREQUENCY_ATTR_NO_160MHZ                        = 0xc
diff --git a/vendor/golang.org/x/sys/windows/dll_windows.go b/vendor/golang.org/x/sys/windows/dll_windows.go
index 115341fba..4e613cf63 100644
--- a/vendor/golang.org/x/sys/windows/dll_windows.go
+++ b/vendor/golang.org/x/sys/windows/dll_windows.go
@@ -65,7 +65,7 @@ func LoadDLL(name string) (dll *DLL, err error) {
 	return d, nil
 }
 
-// MustLoadDLL is like LoadDLL but panics if load operation failes.
+// MustLoadDLL is like LoadDLL but panics if load operation fails.
 func MustLoadDLL(name string) *DLL {
 	d, e := LoadDLL(name)
 	if e != nil {
diff --git a/vendor/golang.org/x/time/rate/rate.go b/vendor/golang.org/x/time/rate/rate.go
index 8f6c7f493..93a798ab6 100644
--- a/vendor/golang.org/x/time/rate/rate.go
+++ b/vendor/golang.org/x/time/rate/rate.go
@@ -99,8 +99,9 @@ func (lim *Limiter) Tokens() float64 {
 // bursts of at most b tokens.
 func NewLimiter(r Limit, b int) *Limiter {
 	return &Limiter{
-		limit: r,
-		burst: b,
+		limit:  r,
+		burst:  b,
+		tokens: float64(b),
 	}
 }
 
@@ -344,18 +345,6 @@ func (lim *Limiter) reserveN(t time.Time, n int, maxFutureReserve time.Duration)
 			tokens:    n,
 			timeToAct: t,
 		}
-	} else if lim.limit == 0 {
-		var ok bool
-		if lim.burst >= n {
-			ok = true
-			lim.burst -= n
-		}
-		return Reservation{
-			ok:        ok,
-			lim:       lim,
-			tokens:    lim.burst,
-			timeToAct: t,
-		}
 	}
 
 	t, tokens := lim.advance(t)
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 567e2890b..75eb43741 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -579,7 +579,7 @@ go.uber.org/zap/internal/pool
 go.uber.org/zap/internal/stacktrace
 go.uber.org/zap/zapcore
 go.uber.org/zap/zapgrpc
-# golang.org/x/crypto v0.27.0
+# golang.org/x/crypto v0.28.0
 ## explicit; go 1.20
 golang.org/x/crypto/cryptobyte
 golang.org/x/crypto/cryptobyte/asn1
@@ -617,7 +617,7 @@ golang.org/x/oauth2/internal
 golang.org/x/sync/errgroup
 golang.org/x/sync/semaphore
 golang.org/x/sync/singleflight
-# golang.org/x/sys v0.25.0
+# golang.org/x/sys v0.26.0
 ## explicit; go 1.18
 golang.org/x/sys/cpu
 golang.org/x/sys/plan9
@@ -625,7 +625,7 @@ golang.org/x/sys/unix
 golang.org/x/sys/windows
 golang.org/x/sys/windows/registry
 golang.org/x/sys/windows/svc
-# golang.org/x/term v0.24.0
+# golang.org/x/term v0.25.0
 ## explicit; go 1.18
 golang.org/x/term
 # golang.org/x/text v0.19.0
@@ -660,7 +660,7 @@ golang.org/x/text/transform
 golang.org/x/text/unicode/bidi
 golang.org/x/text/unicode/norm
 golang.org/x/text/width
-# golang.org/x/time v0.6.0
+# golang.org/x/time v0.7.0
 ## explicit; go 1.18
 golang.org/x/time/rate
 # golang.org/x/tools v0.24.0
@@ -1534,7 +1534,7 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client/metrics
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/common/metrics
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client
-# sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.0.62
+# sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.0.65
 ## explicit; go 1.23.1
 sigs.k8s.io/cloud-provider-azure/pkg/azclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/accountclient


Test patch:
diff --git a/internal/testutil/fixture/azure_securitygroup.go b/internal/testutil/fixture/azure_securitygroup.go
index 721e381aa..a979fa364 100644
--- a/internal/testutil/fixture/azure_securitygroup.go
+++ b/internal/testutil/fixture/azure_securitygroup.go
@@ -27,9 +27,9 @@ import (
 
 	"sigs.k8s.io/cloud-provider-azure/internal/testutil"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/fnutil"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/iputil"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/securitygroup"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/securitygroup"
+	fnutil "sigs.k8s.io/cloud-provider-azure/pkg/util/collectionutil"
+	"sigs.k8s.io/cloud-provider-azure/pkg/util/iputil"
 )
 
 // NoiseSecurityRules returns 3 non cloud-provider-specific security rules.
diff --git a/internal/testutil/fixture/fixture.go b/internal/testutil/fixture/fixture.go
index 3278676ad..92aeba488 100644
--- a/internal/testutil/fixture/fixture.go
+++ b/internal/testutil/fixture/fixture.go
@@ -24,7 +24,7 @@ import (
 	"math/big"
 	"net/netip"
 
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/fnutil"
+	fnutil "sigs.k8s.io/cloud-provider-azure/pkg/util/collectionutil"
 )
 
 type Fixture struct{}
diff --git a/pkg/azureclients/privatednsclient/azure_privatednsclient_test.go b/pkg/azureclients/privatednsclient/azure_privatednsclient_test.go
deleted file mode 100644
index 46c13b47c..000000000
--- a/pkg/azureclients/privatednsclient/azure_privatednsclient_test.go
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
-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 privatednsclient
-
-import (
-	"bytes"
-	"context"
-	"fmt"
-	"io"
-	"net/http"
-	"testing"
-	"time"
-
-	"github.com/Azure/azure-sdk-for-go/services/privatedns/mgmt/2018-09-01/privatedns"
-	"github.com/Azure/go-autorest/autorest"
-	"github.com/stretchr/testify/assert"
-
-	"go.uber.org/mock/gomock"
-
-	"k8s.io/client-go/util/flowcontrol"
-	"k8s.io/utils/ptr"
-
-	azclients "sigs.k8s.io/cloud-provider-azure/pkg/azureclients"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient/mockarmclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-const (
-	sub0 = "sub0"
-	rg0  = "rg0"
-	pz0  = "pz0"
-
-	testResourceID     = "/subscriptions/sub0/resourceGroups/rg0/providers/" + privateDNSZoneResourceType + "/" + pz0
-	testResourcePrefix = "/subscriptions/sub0/resourceGroups/rg0/providers/" + privateDNSZoneResourceType
-)
-
-func TestNew(t *testing.T) {
-	config := &azclients.ClientConfig{
-		SubscriptionID:          sub0,
-		ResourceManagerEndpoint: "endpoint",
-		Location:                "eastus",
-		RateLimitConfig: &azclients.RateLimitConfig{
-			CloudProviderRateLimit:            true,
-			CloudProviderRateLimitQPS:         0.5,
-			CloudProviderRateLimitBucket:      1,
-			CloudProviderRateLimitQPSWrite:    0.5,
-			CloudProviderRateLimitBucketWrite: 1,
-		},
-		Backoff: &retry.Backoff{Steps: 1},
-	}
-
-	pzClient := New(config)
-	assert.Equal(t, sub0, pzClient.subscriptionID)
-	assert.NotEmpty(t, pzClient.rateLimiterReader)
-	assert.NotEmpty(t, pzClient.rateLimiterWriter)
-}
-
-func TestCreateOrUpdate(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	pz := getTestPrivateDNSZone(pz0)
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	response := &http.Response{
-		StatusCode: http.StatusOK,
-		Body:       io.NopCloser(bytes.NewReader([]byte(""))),
-	}
-	armClient.EXPECT().PutResource(gomock.Any(), ptr.Deref(pz.ID, ""), pz, gomock.Any()).Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	pzClient := getTestPrivateDNSZoneClient(armClient)
-	rerr := pzClient.CreateOrUpdate(context.TODO(), rg0, pz0, pz, "", true)
-	assert.Nil(t, rerr)
-}
-
-func TestCreateOrUpdateWithNeverRateLimiter(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	rcCreateOrUpdateErr := retry.GetRateLimitError(true, "PrivateDNSZoneCreateOrUpdate")
-
-	pz := getTestPrivateDNSZone(pz0)
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	pzClient := getTestPrivateDNSZoneClientWithNeverRateLimiter(armClient)
-	rerr := pzClient.CreateOrUpdate(context.TODO(), rg0, pz0, pz, "", true)
-	assert.Equal(t, rcCreateOrUpdateErr, rerr)
-}
-
-func TestCreateOrUpdateRetryAfterReader(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	rcCreateOrUpdateErr := retry.GetThrottlingError("PrivateDNSZoneCreateOrUpdate", "client throttled", getFutureTime())
-
-	pz := getTestPrivateDNSZone(pz0)
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	pzClient := getTestPrivateDNSZoneClientWithRetryAfterReader(armClient)
-	rerr := pzClient.CreateOrUpdate(context.TODO(), rg0, pz0, pz, "", true)
-	assert.NotNil(t, rerr)
-	assert.Equal(t, rcCreateOrUpdateErr, rerr)
-}
-
-func TestCreateOrUpdateThrottle(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusTooManyRequests,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	throttleErr := &retry.Error{
-		HTTPStatusCode: http.StatusTooManyRequests,
-		RawError:       fmt.Errorf("error"),
-		Retriable:      true,
-		RetryAfter:     time.Unix(100, 0),
-	}
-
-	pz := getTestPrivateDNSZone(pz0)
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().PutResource(gomock.Any(), ptr.Deref(pz.ID, ""), pz, gomock.Any()).Return(response, throttleErr).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	pzClient := getTestPrivateDNSZoneClient(armClient)
-	rerr := pzClient.CreateOrUpdate(context.TODO(), rg0, pz0, pz, "", true)
-	assert.Equal(t, throttleErr, rerr)
-}
-
-func TestCreateOrUpdateWithCreateOrUpdateResponderError(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	pz := getTestPrivateDNSZone(pz0)
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	response := &http.Response{
-		StatusCode: http.StatusNotFound,
-		Body:       io.NopCloser(bytes.NewReader([]byte(""))),
-	}
-
-	armClient.EXPECT().PutResource(gomock.Any(), ptr.Deref(pz.ID, ""), pz, gomock.Any()).Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	pzClient := getTestPrivateDNSZoneClient(armClient)
-	rerr := pzClient.CreateOrUpdate(context.TODO(), rg0, pz0, pz, "", true)
-	assert.NotNil(t, rerr)
-}
-
-func getTestPrivateDNSZone(name string) privatedns.PrivateZone {
-	return privatedns.PrivateZone{
-		ID:       ptr.To(fmt.Sprintf("%s/%s", testResourcePrefix, name)),
-		Name:     ptr.To(name),
-		Location: ptr.To("eastus"),
-	}
-}
-
-func getTestPrivateDNSZoneClient(armClient armclient.Interface) *Client {
-	rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(&azclients.RateLimitConfig{})
-	return &Client{
-		armClient:         armClient,
-		subscriptionID:    sub0,
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-	}
-}
-
-func getTestPrivateDNSZoneClientWithNeverRateLimiter(armClient armclient.Interface) *Client {
-	rateLimiterReader := flowcontrol.NewFakeNeverRateLimiter()
-	rateLimiterWriter := flowcontrol.NewFakeNeverRateLimiter()
-	return &Client{
-		armClient:         armClient,
-		subscriptionID:    sub0,
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-	}
-}
-
-func getTestPrivateDNSZoneClientWithRetryAfterReader(armClient armclient.Interface) *Client {
-	rateLimiterReader := flowcontrol.NewFakeAlwaysRateLimiter()
-	rateLimiterWriter := flowcontrol.NewFakeAlwaysRateLimiter()
-	return &Client{
-		armClient:         armClient,
-		subscriptionID:    sub0,
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-		RetryAfterReader:  getFutureTime(),
-		RetryAfterWriter:  getFutureTime(),
-	}
-}
-
-func TestGetNotFound(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusNotFound,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().GetResource(gomock.Any(), testResourceID).Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	pzClient := getTestPrivateDNSZoneClient(armClient)
-	expected := privatedns.PrivateZone{Response: autorest.Response{}}
-	result, rerr := pzClient.Get(context.TODO(), rg0, pz0)
-	assert.Equal(t, expected, result)
-	assert.NotNil(t, rerr)
-	assert.Equal(t, http.StatusNotFound, rerr.HTTPStatusCode)
-}
-
-func TestGetInternalError(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusInternalServerError,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().GetResource(gomock.Any(), testResourceID).Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	pzClient := getTestPrivateDNSZoneClient(armClient)
-	expected := privatedns.PrivateZone{Response: autorest.Response{}}
-	result, rerr := pzClient.Get(context.TODO(), rg0, pz0)
-	assert.Equal(t, expected, result)
-	assert.NotNil(t, rerr)
-	assert.Equal(t, http.StatusInternalServerError, rerr.HTTPStatusCode)
-}
-
-func TestGetThrottle(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusTooManyRequests,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	throttleErr := &retry.Error{
-		HTTPStatusCode: http.StatusTooManyRequests,
-		RawError:       fmt.Errorf("error"),
-		Retriable:      true,
-		RetryAfter:     time.Unix(100, 0),
-	}
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().GetResource(gomock.Any(), testResourceID).Return(response, throttleErr).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	pzClient := getTestPrivateDNSZoneClient(armClient)
-	result, rerr := pzClient.Get(context.TODO(), rg0, pz0)
-	assert.Empty(t, result)
-	assert.Equal(t, throttleErr, rerr)
-}
-
-// 2065-01-24 05:20:00 +0000 UTC
-func getFutureTime() time.Time {
-	return time.Unix(3000000000, 0)
-}
diff --git a/pkg/azureclients/securitygroupclient/azure_securitygroupclient_test.go b/pkg/azureclients/securitygroupclient/azure_securitygroupclient_test.go
deleted file mode 100644
index 009bd4f92..000000000
--- a/pkg/azureclients/securitygroupclient/azure_securitygroupclient_test.go
+++ /dev/null
@@ -1,641 +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 securitygroupclient
-
-import (
-	"bytes"
-	"context"
-	"encoding/json"
-	"fmt"
-	"io"
-	"net/http"
-	"testing"
-	"time"
-
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-	"github.com/Azure/go-autorest/autorest"
-	"github.com/stretchr/testify/assert"
-	"go.uber.org/mock/gomock"
-
-	"k8s.io/client-go/util/flowcontrol"
-	"k8s.io/utils/ptr"
-
-	azclients "sigs.k8s.io/cloud-provider-azure/pkg/azureclients"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient/mockarmclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-const (
-	testResourceID     = "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Network/networkSecurityGroups/nsg1"
-	testResourcePrefix = "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Network/networkSecurityGroups"
-)
-
-// 2065-01-24 05:20:00 +0000 UTC
-func getFutureTime() time.Time {
-	return time.Unix(3000000000, 0)
-}
-
-func TestNew(t *testing.T) {
-	config := &azclients.ClientConfig{
-		SubscriptionID:          "sub",
-		ResourceManagerEndpoint: "endpoint",
-		Location:                "eastus",
-		RateLimitConfig: &azclients.RateLimitConfig{
-			CloudProviderRateLimit:            true,
-			CloudProviderRateLimitQPS:         0.5,
-			CloudProviderRateLimitBucket:      1,
-			CloudProviderRateLimitQPSWrite:    0.5,
-			CloudProviderRateLimitBucketWrite: 1,
-		},
-		Backoff: &retry.Backoff{Steps: 1},
-	}
-
-	nsgClient := New(config)
-	assert.Equal(t, "sub", nsgClient.subscriptionID)
-	assert.NotEmpty(t, nsgClient.rateLimiterReader)
-	assert.NotEmpty(t, nsgClient.rateLimiterWriter)
-}
-
-func TestNewAzureStack(t *testing.T) {
-	config := &azclients.ClientConfig{
-		CloudName:               "AZURESTACKCLOUD",
-		SubscriptionID:          "sub",
-		ResourceManagerEndpoint: "endpoint",
-		Location:                "eastus",
-		RateLimitConfig: &azclients.RateLimitConfig{
-			CloudProviderRateLimit:            true,
-			CloudProviderRateLimitQPS:         0.5,
-			CloudProviderRateLimitBucket:      1,
-			CloudProviderRateLimitQPSWrite:    0.5,
-			CloudProviderRateLimitBucketWrite: 1,
-		},
-		Backoff: &retry.Backoff{Steps: 1},
-	}
-
-	nsgClient := New(config)
-	assert.Equal(t, "AZURESTACKCLOUD", nsgClient.cloudName)
-	assert.Equal(t, "sub", nsgClient.subscriptionID)
-}
-
-func TestGet(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusOK,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().GetResourceWithExpandQuery(gomock.Any(), testResourceID, "").Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	expected := network.SecurityGroup{}
-	expected.Response = autorest.Response{Response: response}
-	nsgClient := getTestSecurityGroupClient(armClient)
-	result, rerr := nsgClient.Get(context.TODO(), "rg", "nsg1", "")
-	assert.Equal(t, expected, result)
-	assert.Nil(t, rerr)
-}
-
-func TestGetNeverRateLimiter(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	nsgGetErr := &retry.Error{
-		RawError:  fmt.Errorf("azure cloud provider rate limited(%s) for operation %q", "read", "NSGGet"),
-		Retriable: true,
-	}
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	nsgClient := getTestSecurityGroupClientWithNeverRateLimiter(armClient)
-	expected := network.SecurityGroup{}
-	result, rerr := nsgClient.Get(context.TODO(), "rg", "nsg1", "")
-	assert.Equal(t, expected, result)
-	assert.Equal(t, nsgGetErr, rerr)
-}
-
-func TestGetRetryAfterReader(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	nsgGetErr := &retry.Error{
-		RawError:   fmt.Errorf("azure cloud provider throttled for operation %s with reason %q", "NSGGet", "client throttled"),
-		Retriable:  true,
-		RetryAfter: getFutureTime(),
-	}
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	nsgClient := getTestSecurityGroupClientWithRetryAfterReader(armClient)
-	expected := network.SecurityGroup{}
-	result, rerr := nsgClient.Get(context.TODO(), "rg", "nsg1", "")
-	assert.Equal(t, expected, result)
-	assert.Equal(t, nsgGetErr, rerr)
-}
-
-func TestGetThrottle(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusTooManyRequests,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	throttleErr := &retry.Error{
-		HTTPStatusCode: http.StatusTooManyRequests,
-		RawError:       fmt.Errorf("error"),
-		Retriable:      true,
-		RetryAfter:     time.Unix(100, 0),
-	}
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().GetResourceWithExpandQuery(gomock.Any(), testResourceID, "").Return(response, throttleErr).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	nsgClient := getTestSecurityGroupClient(armClient)
-	result, rerr := nsgClient.Get(context.TODO(), "rg", "nsg1", "")
-	assert.Empty(t, result)
-	assert.Equal(t, throttleErr, rerr)
-}
-
-func TestGetNotFound(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusNotFound,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().GetResourceWithExpandQuery(gomock.Any(), testResourceID, "").Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	nsgClient := getTestSecurityGroupClient(armClient)
-	expected := network.SecurityGroup{Response: autorest.Response{}}
-	result, rerr := nsgClient.Get(context.TODO(), "rg", "nsg1", "")
-	assert.Equal(t, expected, result)
-	assert.NotNil(t, rerr)
-	assert.Equal(t, http.StatusNotFound, rerr.HTTPStatusCode)
-}
-
-func TestGetInternalError(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusInternalServerError,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().GetResourceWithExpandQuery(gomock.Any(), testResourceID, "").Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	nsgClient := getTestSecurityGroupClient(armClient)
-	expected := network.SecurityGroup{Response: autorest.Response{}}
-	result, rerr := nsgClient.Get(context.TODO(), "rg", "nsg1", "")
-	assert.Equal(t, expected, result)
-	assert.NotNil(t, rerr)
-	assert.Equal(t, http.StatusInternalServerError, rerr.HTTPStatusCode)
-}
-
-func TestList(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	nsgList := []network.SecurityGroup{getTestSecurityGroup("nsg1"), getTestSecurityGroup("nsg2"), getTestSecurityGroup("nsg3")}
-	responseBody, err := json.Marshal(network.SecurityGroupListResult{Value: &nsgList})
-	assert.NoError(t, err)
-	armClient.EXPECT().GetResource(gomock.Any(), testResourcePrefix).Return(
-		&http.Response{
-			StatusCode: http.StatusOK,
-			Body:       io.NopCloser(bytes.NewReader(responseBody)),
-		}, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	nsgClient := getTestSecurityGroupClient(armClient)
-	result, rerr := nsgClient.List(context.TODO(), "rg")
-	assert.Nil(t, rerr)
-	assert.Equal(t, 3, len(result))
-}
-
-func TestListNextResultsMultiPages(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	tests := []struct {
-		prepareErr error
-		sendErr    *retry.Error
-		statusCode int
-	}{
-		{
-			prepareErr: nil,
-			sendErr:    nil,
-		},
-		{
-			prepareErr: fmt.Errorf("error"),
-		},
-		{
-			sendErr: &retry.Error{RawError: fmt.Errorf("error")},
-		},
-	}
-
-	lastResult := network.SecurityGroupListResult{
-		NextLink: ptr.To("next"),
-	}
-
-	for _, test := range tests {
-		armClient := mockarmclient.NewMockInterface(ctrl)
-		req := &http.Request{
-			Method: "GET",
-		}
-		armClient.EXPECT().PrepareGetRequest(gomock.Any(), gomock.Any()).Return(req, test.prepareErr)
-		if test.prepareErr == nil {
-			armClient.EXPECT().Send(gomock.Any(), req).Return(&http.Response{
-				StatusCode: http.StatusOK,
-				Body:       io.NopCloser(bytes.NewReader([]byte(`{"foo":"bar"}`))),
-			}, test.sendErr)
-			armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any())
-		}
-
-		sgClient := getTestSecurityGroupClient(armClient)
-		result, err := sgClient.listNextResults(context.TODO(), lastResult)
-		if test.prepareErr != nil || test.sendErr != nil {
-			assert.Error(t, err)
-		} else {
-			assert.NoError(t, err)
-		}
-		if test.prepareErr != nil {
-			assert.Empty(t, result)
-		} else {
-			assert.NotEmpty(t, result)
-		}
-	}
-}
-
-func TestListNextResultsMultiPagesWithListResponderError(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	test := struct {
-		prepareErr error
-		sendErr    *retry.Error
-	}{
-		prepareErr: nil,
-		sendErr:    nil,
-	}
-
-	lastResult := network.SecurityGroupListResult{
-		NextLink: ptr.To("next"),
-	}
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	req := &http.Request{
-		Method: "GET",
-	}
-	armClient.EXPECT().PrepareGetRequest(gomock.Any(), gomock.Any()).Return(req, test.prepareErr)
-	if test.prepareErr == nil {
-		armClient.EXPECT().Send(gomock.Any(), req).Return(&http.Response{
-			StatusCode: http.StatusNotFound,
-			Body:       io.NopCloser(bytes.NewReader([]byte(`{"foo":"bar"}`))),
-		}, test.sendErr)
-		armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any())
-	}
-
-	response := &http.Response{
-		StatusCode: http.StatusNotFound,
-		Body:       io.NopCloser(bytes.NewBuffer([]byte(`{"foo":"bar"}`))),
-	}
-	expected := network.SecurityGroupListResult{}
-	expected.Response = autorest.Response{Response: response}
-	sgClient := getTestSecurityGroupClient(armClient)
-	result, err := sgClient.listNextResults(context.TODO(), lastResult)
-	assert.Error(t, err)
-	assert.Equal(t, expected, result)
-}
-
-func TestListWithListResponderError(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	nsgList := []network.SecurityGroup{getTestSecurityGroup("nsg1"), getTestSecurityGroup("nsg2"), getTestSecurityGroup("nsg3")}
-	responseBody, err := json.Marshal(network.SecurityGroupListResult{Value: &nsgList})
-	assert.NoError(t, err)
-	armClient.EXPECT().GetResource(gomock.Any(), testResourcePrefix).Return(
-		&http.Response{
-			StatusCode: http.StatusNotFound,
-			Body:       io.NopCloser(bytes.NewReader(responseBody)),
-		}, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-	nsgClient := getTestSecurityGroupClient(armClient)
-	result, rerr := nsgClient.List(context.TODO(), "rg")
-	assert.NotNil(t, rerr)
-	assert.Equal(t, 0, len(result))
-}
-
-func TestListWithNextPage(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	nsgList := []network.SecurityGroup{getTestSecurityGroup("nsg1"), getTestSecurityGroup("nsg2"), getTestSecurityGroup("nsg3")}
-	partialResponse, err := json.Marshal(network.SecurityGroupListResult{Value: &nsgList, NextLink: ptr.To("nextLink")})
-	assert.NoError(t, err)
-	pagedResponse, err := json.Marshal(network.SecurityGroupListResult{Value: &nsgList})
-	assert.NoError(t, err)
-	armClient.EXPECT().PrepareGetRequest(gomock.Any(), gomock.Any()).Return(&http.Request{}, nil)
-	armClient.EXPECT().Send(gomock.Any(), gomock.Any()).Return(
-		&http.Response{
-			StatusCode: http.StatusOK,
-			Body:       io.NopCloser(bytes.NewReader(pagedResponse)),
-		}, nil)
-	armClient.EXPECT().GetResource(gomock.Any(), testResourcePrefix).Return(
-		&http.Response{
-			StatusCode: http.StatusOK,
-			Body:       io.NopCloser(bytes.NewReader(partialResponse)),
-		}, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(2)
-	nsgClient := getTestSecurityGroupClient(armClient)
-	result, rerr := nsgClient.List(context.TODO(), "rg")
-	assert.Nil(t, rerr)
-	assert.Equal(t, 6, len(result))
-}
-
-func TestListNeverRateLimiter(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	nsgListErr := &retry.Error{
-		RawError:  fmt.Errorf("azure cloud provider rate limited(%s) for operation %q", "read", "NSGList"),
-		Retriable: true,
-	}
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	nsgClient := getTestSecurityGroupClientWithNeverRateLimiter(armClient)
-	result, rerr := nsgClient.List(context.TODO(), "rg")
-	assert.Equal(t, 0, len(result))
-	assert.NotNil(t, rerr)
-	assert.Equal(t, nsgListErr, rerr)
-}
-
-func TestListRetryAfterReader(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	nsgListErr := &retry.Error{
-		RawError:   fmt.Errorf("azure cloud provider throttled for operation %s with reason %q", "NSGList", "client throttled"),
-		Retriable:  true,
-		RetryAfter: getFutureTime(),
-	}
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	nsgClient := getTestSecurityGroupClientWithRetryAfterReader(armClient)
-	result, rerr := nsgClient.List(context.TODO(), "rg")
-	assert.Equal(t, 0, len(result))
-	assert.NotNil(t, rerr)
-	assert.Equal(t, nsgListErr, rerr)
-}
-
-func TestListThrottle(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusTooManyRequests,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	throttleErr := &retry.Error{
-		HTTPStatusCode: http.StatusTooManyRequests,
-		RawError:       fmt.Errorf("error"),
-		Retriable:      true,
-		RetryAfter:     time.Unix(100, 0),
-	}
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().GetResource(gomock.Any(), testResourcePrefix).Return(response, throttleErr).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	nsgClient := getTestSecurityGroupClient(armClient)
-	result, rerr := nsgClient.List(context.TODO(), "rg")
-	assert.Empty(t, result)
-	assert.NotNil(t, rerr)
-	assert.Equal(t, throttleErr, rerr)
-}
-
-func TestCreateOrUpdate(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	nsg := getTestSecurityGroup("nsg1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	response := &http.Response{
-		StatusCode: http.StatusOK,
-		Body:       io.NopCloser(bytes.NewReader([]byte(""))),
-	}
-	armClient.EXPECT().PutResource(gomock.Any(), ptr.Deref(nsg.ID, ""), nsg, gomock.Any()).Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	nsgClient := getTestSecurityGroupClient(armClient)
-	rerr := nsgClient.CreateOrUpdate(context.TODO(), "rg", "nsg1", nsg, "*")
-	assert.Nil(t, rerr)
-}
-
-func TestCreateOrUpdateWithCreateOrUpdateResponderError(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-	nsg := getTestSecurityGroup("nsg1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	response := &http.Response{
-		StatusCode: http.StatusNotFound,
-		Body:       io.NopCloser(bytes.NewReader([]byte(""))),
-	}
-	armClient.EXPECT().PutResource(gomock.Any(), ptr.Deref(nsg.ID, ""), nsg, gomock.Any()).Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	nsgClient := getTestSecurityGroupClient(armClient)
-	rerr := nsgClient.CreateOrUpdate(context.TODO(), "rg", "nsg1", nsg, "")
-	assert.NotNil(t, rerr)
-}
-
-func TestCreateOrUpdateNeverRateLimiter(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	nsgCreateOrUpdateErr := retry.GetRateLimitError(true, "NSGCreateOrUpdate")
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	nsgClient := getTestSecurityGroupClientWithNeverRateLimiter(armClient)
-	nsg := getTestSecurityGroup("nsg1")
-	rerr := nsgClient.CreateOrUpdate(context.TODO(), "rg", "nsg1", nsg, "")
-	assert.NotNil(t, rerr)
-	assert.Equal(t, nsgCreateOrUpdateErr, rerr)
-}
-
-func TestCreateOrUpdateRetryAfterReader(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	nsgCreateOrUpdateErr := retry.GetThrottlingError("NSGCreateOrUpdate", "client throttled", getFutureTime())
-
-	nsg := getTestSecurityGroup("nsg1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	nsgClient := getTestSecurityGroupClientWithRetryAfterReader(armClient)
-	rerr := nsgClient.CreateOrUpdate(context.TODO(), "rg", "nsg1", nsg, "")
-	assert.NotNil(t, rerr)
-	assert.Equal(t, nsgCreateOrUpdateErr, rerr)
-}
-
-func TestCreateOrUpdateThrottle(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusTooManyRequests,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	throttleErr := &retry.Error{
-		HTTPStatusCode: http.StatusTooManyRequests,
-		RawError:       fmt.Errorf("error"),
-		Retriable:      true,
-		RetryAfter:     time.Unix(100, 0),
-	}
-
-	nsg := getTestSecurityGroup("nsg1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().PutResource(gomock.Any(), ptr.Deref(nsg.ID, ""), nsg, gomock.Any()).Return(response, throttleErr).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	nsgClient := getTestSecurityGroupClient(armClient)
-	rerr := nsgClient.CreateOrUpdate(context.TODO(), "rg", "nsg1", nsg, "")
-	assert.NotNil(t, rerr)
-	assert.Equal(t, throttleErr, rerr)
-}
-
-func TestDelete(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	r := getTestSecurityGroup("nsg1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().DeleteResource(gomock.Any(), ptr.Deref(r.ID, "")).Return(nil).Times(1)
-
-	rtClient := getTestSecurityGroupClient(armClient)
-	rerr := rtClient.Delete(context.TODO(), "rg", "nsg1")
-	assert.Nil(t, rerr)
-}
-
-func TestDeleteNeverRateLimiter(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	nsgDeleteErr := &retry.Error{
-		RawError:  fmt.Errorf("azure cloud provider rate limited(%s) for operation %q", "write", "NSGDelete"),
-		Retriable: true,
-	}
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	nsgClient := getTestSecurityGroupClientWithNeverRateLimiter(armClient)
-	rerr := nsgClient.Delete(context.TODO(), "rg", "nsg1")
-	assert.NotNil(t, rerr)
-	assert.Equal(t, nsgDeleteErr, rerr)
-}
-
-func TestDeleteRetryAfterReader(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	nsgDeleteErr := &retry.Error{
-		RawError:   fmt.Errorf("azure cloud provider throttled for operation %s with reason %q", "NSGDelete", "client throttled"),
-		Retriable:  true,
-		RetryAfter: getFutureTime(),
-	}
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	nsgClient := getTestSecurityGroupClientWithRetryAfterReader(armClient)
-	rerr := nsgClient.Delete(context.TODO(), "rg", "nsg1")
-	assert.NotNil(t, rerr)
-	assert.Equal(t, nsgDeleteErr, rerr)
-}
-
-func TestDeleteThrottle(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	throttleErr := &retry.Error{
-		HTTPStatusCode: http.StatusTooManyRequests,
-		RawError:       fmt.Errorf("error"),
-		Retriable:      true,
-		RetryAfter:     time.Unix(100, 0),
-	}
-
-	nsg := getTestSecurityGroup("nsg1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().DeleteResource(gomock.Any(), ptr.Deref(nsg.ID, "")).Return(throttleErr).Times(1)
-
-	nsgClient := getTestSecurityGroupClient(armClient)
-	rerr := nsgClient.Delete(context.TODO(), "rg", "nsg1")
-	assert.NotNil(t, rerr)
-	assert.Equal(t, throttleErr, rerr)
-}
-
-func getTestSecurityGroup(name string) network.SecurityGroup {
-	return network.SecurityGroup{
-		ID:       ptr.To(fmt.Sprintf("/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Network/networkSecurityGroups/%s", name)),
-		Name:     ptr.To(name),
-		Location: ptr.To("eastus"),
-	}
-}
-
-func getTestSecurityGroupClient(armClient armclient.Interface) *Client {
-	rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(&azclients.RateLimitConfig{})
-	return &Client{
-		armClient:         armClient,
-		subscriptionID:    "subscriptionID",
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-	}
-}
-
-func getTestSecurityGroupClientWithNeverRateLimiter(armClient armclient.Interface) *Client {
-	rateLimiterReader := flowcontrol.NewFakeNeverRateLimiter()
-	rateLimiterWriter := flowcontrol.NewFakeNeverRateLimiter()
-	return &Client{
-		armClient:         armClient,
-		subscriptionID:    "subscriptionID",
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-	}
-}
-
-func getTestSecurityGroupClientWithRetryAfterReader(armClient armclient.Interface) *Client {
-	rateLimiterReader := flowcontrol.NewFakeAlwaysRateLimiter()
-	rateLimiterWriter := flowcontrol.NewFakeAlwaysRateLimiter()
-	return &Client{
-		armClient:         armClient,
-		subscriptionID:    "subscriptionID",
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-		RetryAfterReader:  getFutureTime(),
-		RetryAfterWriter:  getFutureTime(),
-	}
-}
diff --git a/pkg/azureclients/virtualnetworklinksclient/azure_virtualnetworklinksclient_test.go b/pkg/azureclients/virtualnetworklinksclient/azure_virtualnetworklinksclient_test.go
deleted file mode 100644
index 83684c3ae..000000000
--- a/pkg/azureclients/virtualnetworklinksclient/azure_virtualnetworklinksclient_test.go
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
-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 virtualnetworklinksclient implements the client for VirtualNetworkLinks.
-package virtualnetworklinksclient
-
-import (
-	"bytes"
-	"context"
-	"fmt"
-	"io"
-	"net/http"
-	"testing"
-	"time"
-
-	"github.com/Azure/azure-sdk-for-go/services/privatedns/mgmt/2018-09-01/privatedns"
-	"github.com/Azure/go-autorest/autorest"
-	"github.com/Azure/go-autorest/autorest/azure"
-	"github.com/stretchr/testify/assert"
-
-	"go.uber.org/mock/gomock"
-
-	"k8s.io/utils/ptr"
-
-	azclients "sigs.k8s.io/cloud-provider-azure/pkg/azureclients"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient/mockarmclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-const (
-	testResourceID       = "/subscriptions/subscriptionID/resourceGroups/rg/providers/" + privateDNSZoneResourceType + "/pz1/" + virtualNetworkLinkResourceType + "/vnl1"
-	testResourceIDFormat = "/subscriptions/subscriptionID/resourceGroups/rg/providers/" + privateDNSZoneResourceType + "/%s/" + virtualNetworkLinkResourceType + "/%s"
-)
-
-func TestNew(t *testing.T) {
-	config := &azclients.ClientConfig{
-		SubscriptionID:          "sub",
-		ResourceManagerEndpoint: "endpoint",
-		Location:                "eastus",
-		RateLimitConfig: &azclients.RateLimitConfig{
-			CloudProviderRateLimit:            true,
-			CloudProviderRateLimitQPS:         0.5,
-			CloudProviderRateLimitBucket:      1,
-			CloudProviderRateLimitQPSWrite:    0.5,
-			CloudProviderRateLimitBucketWrite: 1,
-		},
-		Backoff: &retry.Backoff{Steps: 1},
-	}
-
-	vnlClient := New(config)
-	assert.Equal(t, "sub", vnlClient.subscriptionID)
-	assert.NotEmpty(t, vnlClient.rateLimiterReader)
-	assert.NotEmpty(t, vnlClient.rateLimiterWriter)
-}
-
-func TestGetNotFound(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusNotFound,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().GetResourceWithExpandQuery(gomock.Any(), testResourceID, "").Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	vnlClient := getTestVirtualNetworkLinkClient(armClient)
-	expected := privatedns.VirtualNetworkLink{Response: autorest.Response{}}
-	result, rerr := vnlClient.Get(context.TODO(), "rg", "pz1", "vnl1")
-	assert.Equal(t, expected, result)
-	assert.NotNil(t, rerr)
-	assert.Equal(t, http.StatusNotFound, rerr.HTTPStatusCode)
-}
-
-func TestGetInternalError(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusInternalServerError,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().GetResourceWithExpandQuery(gomock.Any(), testResourceID, "").Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	vnlClient := getTestVirtualNetworkLinkClient(armClient)
-	expected := privatedns.VirtualNetworkLink{Response: autorest.Response{}}
-	result, rerr := vnlClient.Get(context.TODO(), "rg", "pz1", "vnl1")
-	assert.Equal(t, expected, result)
-	assert.NotNil(t, rerr)
-	assert.Equal(t, http.StatusInternalServerError, rerr.HTTPStatusCode)
-}
-
-func TestGetThrottle(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusTooManyRequests,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	throttleErr := &retry.Error{
-		HTTPStatusCode: http.StatusTooManyRequests,
-		RawError:       fmt.Errorf("error"),
-		Retriable:      true,
-		RetryAfter:     time.Unix(100, 0),
-	}
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().GetResourceWithExpandQuery(gomock.Any(), testResourceID, "").Return(response, throttleErr).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	vnlClient := getTestVirtualNetworkLinkClient(armClient)
-	result, rerr := vnlClient.Get(context.TODO(), "rg", "pz1", "vnl1")
-	assert.Empty(t, result)
-	assert.Equal(t, throttleErr, rerr)
-}
-
-func TestCreateOrUpdate(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	vnl := getTestVirtualNetworkLink("pz1", "vnl1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	response := &http.Response{
-		StatusCode: http.StatusOK,
-		Body:       io.NopCloser(bytes.NewReader([]byte(""))),
-	}
-	armClient.EXPECT().PutResource(gomock.Any(), ptr.Deref(vnl.ID, ""), vnl, gomock.Any()).Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	vnlClient := getTestVirtualNetworkLinkClient(armClient)
-	rerr := vnlClient.CreateOrUpdate(context.TODO(), "rg", "pz1", "vnl1", vnl, "", true)
-	assert.Nil(t, rerr)
-}
-
-func TestCreateOrUpdateAsync(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	vnl := getTestVirtualNetworkLink("pz1", "vnl1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().PutResourceAsync(gomock.Any(), ptr.Deref(vnl.ID, ""), vnl, gomock.Any()).Return(&azure.Future{}, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	vnlClient := getTestVirtualNetworkLinkClient(armClient)
-	rerr := vnlClient.CreateOrUpdate(context.TODO(), "rg", "pz1", "vnl1", vnl, "", false)
-	assert.Nil(t, rerr)
-}
-
-func getTestVirtualNetworkLink(privateZoneName, virtualNetworkLinkName string) privatedns.VirtualNetworkLink {
-	return privatedns.VirtualNetworkLink{
-		ID:       ptr.To(fmt.Sprintf(testResourceIDFormat, privateZoneName, virtualNetworkLinkName)),
-		Name:     ptr.To(virtualNetworkLinkName),
-		Location: ptr.To("eastus"),
-	}
-}
-
-func getTestVirtualNetworkLinkClient(armClient armclient.Interface) *Client {
-	rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(&azclients.RateLimitConfig{})
-	return &Client{
-		armClient:         armClient,
-		subscriptionID:    "subscriptionID",
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-	}
-}
diff --git a/pkg/provider/azure_loadbalancer_accesscontrol_test.go b/pkg/provider/azure_loadbalancer_accesscontrol_test.go
index 3f6cdfed2..cd853b50e 100644
--- a/pkg/provider/azure_loadbalancer_accesscontrol_test.go
+++ b/pkg/provider/azure_loadbalancer_accesscontrol_test.go
@@ -42,9 +42,9 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 	"sigs.k8s.io/cloud-provider-azure/pkg/log"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/iputil"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/securitygroup"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/securitygroup"
 	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
+	"sigs.k8s.io/cloud-provider-azure/pkg/util/iputil"
 )
 
 func TestCloud_reconcileSecurityGroup(t *testing.T) {
diff --git a/pkg/provider/loadbalancer/accesscontrol_test.go b/pkg/provider/loadbalancer/accesscontrol_test.go
index 548e930eb..8d7288a91 100644
--- a/pkg/provider/loadbalancer/accesscontrol_test.go
+++ b/pkg/provider/loadbalancer/accesscontrol_test.go
@@ -29,9 +29,9 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/internal/testutil"
 	"sigs.k8s.io/cloud-provider-azure/internal/testutil/fixture"
 	"sigs.k8s.io/cloud-provider-azure/pkg/log"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/fnutil"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/iputil"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/securitygroup"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/securitygroup"
+	fnutil "sigs.k8s.io/cloud-provider-azure/pkg/util/collectionutil"
+	"sigs.k8s.io/cloud-provider-azure/pkg/util/iputil"
 )
 
 func TestAccessControl_IsAllowFromInternet(t *testing.T) {
diff --git a/pkg/provider/azure_securitygroup_repo_test.go b/pkg/provider/securitygroup/azure_securitygroup_repo_test.go
similarity index 66%
rename from pkg/provider/azure_securitygroup_repo_test.go
rename to pkg/provider/securitygroup/azure_securitygroup_repo_test.go
index 4d6be443c..7bfd7ae11 100644
--- a/pkg/provider/azure_securitygroup_repo_test.go
+++ b/pkg/provider/securitygroup/azure_securitygroup_repo_test.go
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package provider
+package securitygroup
 
 import (
 	"context"
@@ -31,7 +31,6 @@ import (
 
 	"k8s.io/utils/ptr"
 
-	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/mock_azclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/securitygroupclient/mock_securitygroupclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/cache"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
@@ -40,24 +39,23 @@ import (
 func TestCreateOrUpdateSecurityGroupCanceled(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
+	mockSGClient := mock_securitygroupclient.NewMockInterface(ctrl)
+	az, err := NewSecurityGroupRepo("rg", "sg", 120, false, mockSGClient)
+	assert.NoError(t, err)
+	az.(*securityGroupRepo).nsgCache.Set("sg", "test")
 
-	az := GetTestCloud(ctrl)
-	az.nsgCache.Set("sg", "test")
-	clientFactory := az.NetworkClientFactory.(*mock_azclient.MockClientFactory)
-	mockSGClient := clientFactory.GetSecurityGroupClient().(*mock_securitygroupclient.MockInterface)
-
-	mockSGClient.EXPECT().CreateOrUpdate(gomock.Any(), az.ResourceGroup, gomock.Any(), gomock.Any()).Return(nil, &azcore.ResponseError{
+	mockSGClient.EXPECT().CreateOrUpdate(gomock.Any(), "rg", "sg", gomock.Any()).Return(nil, &azcore.ResponseError{
 		RawResponse: &http.Response{
 			Body: io.NopCloser(strings.NewReader(consts.OperationCanceledErrorMessage)),
 		},
 	})
-	mockSGClient.EXPECT().Get(gomock.Any(), az.ResourceGroup, "sg").Return(&armnetwork.SecurityGroup{}, nil)
+	mockSGClient.EXPECT().Get(gomock.Any(), "rg", "sg").Return(&armnetwork.SecurityGroup{}, nil)
 
-	err := az.CreateOrUpdateSecurityGroup(&armnetwork.SecurityGroup{Name: ptr.To("sg")})
+	err = az.CreateOrUpdateSecurityGroup(context.TODO(), &armnetwork.SecurityGroup{Name: ptr.To("sg")})
 	assert.Contains(t, err.Error(), "canceledandsupersededduetoanotheroperation")
 
 	// security group should be removed from cache if the operation is canceled
-	shouldBeEmpty, err := az.nsgCache.GetWithDeepCopy(context.TODO(), "sg", cache.CacheReadTypeDefault)
+	shouldBeEmpty, err := az.(*securityGroupRepo).nsgCache.GetWithDeepCopy(context.TODO(), "sg", cache.CacheReadTypeDefault)
 	assert.NoError(t, err)
 	assert.Empty(t, shouldBeEmpty)
 }
diff --git a/pkg/provider/loadbalancer/securitygroup/securitygroup_test.go b/pkg/provider/securitygroup/securitygroup_test.go
similarity index 99%
rename from pkg/provider/loadbalancer/securitygroup/securitygroup_test.go
rename to pkg/provider/securitygroup/securitygroup_test.go
index dd7c3e5cb..90b5dfbc4 100644
--- a/pkg/provider/loadbalancer/securitygroup/securitygroup_test.go
+++ b/pkg/provider/securitygroup/securitygroup_test.go
@@ -29,9 +29,9 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/internal/testutil"
 	"sigs.k8s.io/cloud-provider-azure/internal/testutil/fixture"
 	"sigs.k8s.io/cloud-provider-azure/pkg/log"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/fnutil"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/iputil"
-	. "sigs.k8s.io/cloud-provider-azure/pkg/provider/loadbalancer/securitygroup" //nolint:revive
+	. "sigs.k8s.io/cloud-provider-azure/pkg/provider/securitygroup" //nolint:revive
+	fnutil "sigs.k8s.io/cloud-provider-azure/pkg/util/collectionutil"
+	"sigs.k8s.io/cloud-provider-azure/pkg/util/iputil"
 )
 
 func ExpectNewSecurityGroupHelper(t *testing.T, sg *armnetwork.SecurityGroup) *RuleHelper {