Repository: kubernetes-sigs/cloud-provider-azure
Pull request #7517 (2024-11-08 05:35:15)

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


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

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

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

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

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

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["feiskyer"]} -->
k8s-ci-robot: Hi @zarvd. Thanks for your PR.

I'm waiting for a [kubernetes-sigs](https://github.com/orgs/kubernetes-sigs/people) member to verify that this patch is reasonable to test. If it is, they should reply with `/ok-to-test` on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should [join the org](https://git.k8s.io/community/community-membership.md#member) to skip this step.

Once the patch is verified, the new status will be reflected by the `ok-to-test` label.

I understand the commands that are listed [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fcloud-provider-azure).

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

MartinForReal: /ok-to-test
k8s-ci-robot: @zarvd: 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-unit | f3a6cea80e286f5df63acd151bf54e22aad653a7 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-unit/1854773620107120640) | true | `/test pull-cloud-provider-azure-unit`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: 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-unit | 087f43c8114a5d26eba26866280b171126102ca3 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-unit/1854778874907332608) | true | `/test pull-cloud-provider-azure-unit`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: The following tests **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-unit | 087f43c8114a5d26eba26866280b171126102ca3 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-unit/1854778874907332608) | true | `/test pull-cloud-provider-azure-unit`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | 087f43c8114a5d26eba26866280b171126102ca3 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1854778874840223744) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: The following tests **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-multi-slb-capz | 087f43c8114a5d26eba26866280b171126102ca3 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1854778874840223744) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-unit | 153b1cf02f824d1834b1af4ad50fd87dee650965 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-unit/1854797694690660352) | true | `/test pull-cloud-provider-azure-unit`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: The following tests **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-unit | 153b1cf02f824d1834b1af4ad50fd87dee650965 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-unit/1854797694690660352) | true | `/test pull-cloud-provider-azure-unit`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | 153b1cf02f824d1834b1af4ad50fd87dee650965 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1854797694640328704) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: 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 | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1855763659154788352) | 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=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: The following tests **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 | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1855763659154788352) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1855763659477749760) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz/1855763659595190272) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: The following tests **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 | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1855763659154788352) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1855763659477749760) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz/1855763659595190272) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz`
pull-cloud-provider-azure-e2e-ccm-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-capz/1855763659356114944) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: The following tests **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 | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1855763659154788352) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1855763659477749760) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz/1855763659595190272) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz`
pull-cloud-provider-azure-e2e-ccm-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-capz/1855763659356114944) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1855763659217702912) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: The following tests **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 | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1855763659154788352) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1855763659477749760) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz/1855763659595190272) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz`
pull-cloud-provider-azure-e2e-ccm-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-capz/1855763659356114944) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1855763659217702912) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1855763659414835200) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: The following tests **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 | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1855763659154788352) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1855763659477749760) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz/1855763659595190272) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz`
pull-cloud-provider-azure-e2e-ccm-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-capz/1855763659356114944) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1855763659217702912) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1855763659414835200) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`
pull-cloud-provider-azure-e2e-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-capz/1855763659293200384) | true | `/test pull-cloud-provider-azure-e2e-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: The following tests **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 | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1855763659154788352) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1855763659477749760) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz/1855763659595190272) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1855763659414835200) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`
pull-cloud-provider-azure-e2e-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-capz/1855763659293200384) | true | `/test pull-cloud-provider-azure-e2e-capz`
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1855789591898886144) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-ccm-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-capz/1855789592024715264) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: The following tests **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 | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1855763659154788352) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz/1855763659595190272) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1855763659414835200) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`
pull-cloud-provider-azure-e2e-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-capz/1855763659293200384) | true | `/test pull-cloud-provider-azure-e2e-capz`
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1855789591898886144) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-ccm-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-capz/1855789592024715264) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1855789592167321600) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: The following tests **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-shared-probe-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz/1855763659595190272) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1855763659414835200) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`
pull-cloud-provider-azure-e2e-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-capz/1855763659293200384) | true | `/test pull-cloud-provider-azure-e2e-capz`
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1855789591898886144) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-ccm-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-capz/1855789592024715264) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1855789592167321600) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1855789591840165888) | 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=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: The following tests **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-ip-lb-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1855763659414835200) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`
pull-cloud-provider-azure-e2e-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-capz/1855763659293200384) | true | `/test pull-cloud-provider-azure-e2e-capz`
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1855789591898886144) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-ccm-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-capz/1855789592024715264) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1855789592167321600) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1855789591840165888) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz/1855789592284762112) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: The following tests **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-capz | 029fb9380cc811dacb865f35e53acfdc958a367e | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-capz/1855763659293200384) | true | `/test pull-cloud-provider-azure-e2e-capz`
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1855789591898886144) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-ccm-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-capz/1855789592024715264) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1855789592167321600) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1855789591840165888) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz/1855789592284762112) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1855789592096018432) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: The following tests **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-vmssflex-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1855789591898886144) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-ccm-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-capz/1855789592024715264) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1855789592167321600) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1855789591840165888) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz/1855789592284762112) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1855789592096018432) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`
pull-cloud-provider-azure-e2e-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-capz/1855789591965995008) | true | `/test pull-cloud-provider-azure-e2e-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
zarvd: /retest
k8s-ci-robot: @zarvd: The following tests **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-vmssflex-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1855789591898886144) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-ccm-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-capz/1855789592024715264) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1855789592167321600) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-capz | f297adf718cf01bd464d60344103edf9607f3be4 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1855789591840165888) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | afd1755cd5c2ac2b3f895d790e376f3ea0a84cfd | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1855826550360903680) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
zarvd: /retest
k8s-ci-robot: @zarvd: 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-ip-lb-capz | afd1755cd5c2ac2b3f895d790e376f3ea0a84cfd | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1855924692590792704) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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
k8s-ci-robot: @zarvd: 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-ip-lb-capz | f2ad6cece500388d58159ec7e5cb2c1f347c8841 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1856123106364493824) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
k8s-ci-robot: @zarvd: The following tests **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-ip-lb-capz | f2ad6cece500388d58159ec7e5cb2c1f347c8841 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1856123106364493824) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | f2ad6cece500388d58159ec7e5cb2c1f347c8841 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7517/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1856123106448379904) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7517). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). 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 -->
zarvd: /retest
MartinForReal: /lgtm
/approve
k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/cloud-provider-azure/pull/7517#issuecomment-2469642096" title="Approved">MartinForReal</a>*, *<a href="https://github.com/kubernetes-sigs/cloud-provider-azure/pull/7517#" title="Author self-approved">zarvd</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":[]} -->

Patch:
diff --git a/pkg/azureclients/routetableclient/azure_routetableclient.go b/pkg/azureclients/routetableclient/azure_routetableclient.go
deleted file mode 100644
index 1eea86106..000000000
--- a/pkg/azureclients/routetableclient/azure_routetableclient.go
+++ /dev/null
@@ -1,219 +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 routetableclient
-
-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"
-
-	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 routeTablesResourceType = "Microsoft.Network/routeTables"
-
-// Client implements RouteTable 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 RouteTable 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 RouteTablesClient (read ops) using rate limit config: QPS=%g, bucket=%d",
-			config.RateLimitConfig.CloudProviderRateLimitQPS,
-			config.RateLimitConfig.CloudProviderRateLimitBucket)
-		klog.V(2).Infof("Azure RouteTablesClient (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 RouteTable.
-func (c *Client) Get(ctx context.Context, resourceGroupName string, routeTableName string, expand string) (network.RouteTable, *retry.Error) {
-	mc := metrics.NewMetricContext("route_tables", "get", resourceGroupName, c.subscriptionID, "")
-
-	// Report errors if the client is rate limited.
-	if !c.rateLimiterReader.TryAccept() {
-		mc.RateLimitedCount()
-		return network.RouteTable{}, retry.GetRateLimitError(false, "RouteTableGet")
-	}
-
-	// Report errors if the client is throttled.
-	if c.RetryAfterReader.After(time.Now()) {
-		mc.ThrottledCount()
-		rerr := retry.GetThrottlingError("RouteTableGet", "client throttled", c.RetryAfterReader)
-		return network.RouteTable{}, rerr
-	}
-
-	result, rerr := c.getRouteTable(ctx, resourceGroupName, routeTableName, 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
-}
-
-// getRouteTable gets a RouteTable.
-func (c *Client) getRouteTable(ctx context.Context, resourceGroupName string, routeTableName string, expand string) (network.RouteTable, *retry.Error) {
-	resourceID := armclient.GetResourceID(
-		c.subscriptionID,
-		resourceGroupName,
-		routeTablesResourceType,
-		routeTableName,
-	)
-	result := network.RouteTable{}
-
-	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", "routetable.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", "routetable.get.respond", resourceID, err)
-		return result, retry.GetError(response, err)
-	}
-
-	result.Response = autorest.Response{Response: response}
-	return result, nil
-}
-
-// CreateOrUpdate creates or updates a RouteTable.
-func (c *Client) CreateOrUpdate(ctx context.Context, resourceGroupName string, routeTableName string, parameters network.RouteTable, etag string) *retry.Error {
-	mc := metrics.NewMetricContext("route_tables", "create_or_update", resourceGroupName, c.subscriptionID, "")
-
-	// Report errors if the client is rate limited.
-	if !c.rateLimiterWriter.TryAccept() {
-		mc.RateLimitedCount()
-		return retry.GetRateLimitError(true, "RouteTableCreateOrUpdate")
-	}
-
-	// Report errors if the client is throttled.
-	if c.RetryAfterWriter.After(time.Now()) {
-		mc.ThrottledCount()
-		rerr := retry.GetThrottlingError("RouteTableCreateOrUpdate", "client throttled", c.RetryAfterWriter)
-		return rerr
-	}
-
-	rerr := c.createOrUpdateRouteTable(ctx, resourceGroupName, routeTableName, 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
-}
-
-// createOrUpdateRouteTable creates or updates a RouteTable.
-func (c *Client) createOrUpdateRouteTable(ctx context.Context, resourceGroupName string, routeTableName string, parameters network.RouteTable, etag string) *retry.Error {
-	resourceID := armclient.GetResourceID(
-		c.subscriptionID,
-		resourceGroupName,
-		routeTablesResourceType,
-		routeTableName,
-	)
-	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", "routetable.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", "routetable.put.respond", resourceID, rerr.Error())
-			return rerr
-		}
-	}
-
-	return nil
-}
-
-func (c *Client) createOrUpdateResponder(resp *http.Response) (*network.RouteTable, *retry.Error) {
-	result := &network.RouteTable{}
-	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)
-}
diff --git a/pkg/azureclients/routetableclient/doc.go b/pkg/azureclients/routetableclient/doc.go
deleted file mode 100644
index 49d8ed616..000000000
--- a/pkg/azureclients/routetableclient/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 routetableclient implements the client for RouteTable.
-package routetableclient // import "sigs.k8s.io/cloud-provider-azure/pkg/azureclients/routetableclient"
diff --git a/pkg/azureclients/routetableclient/interface.go b/pkg/azureclients/routetableclient/interface.go
deleted file mode 100644
index 1ef8cfc08..000000000
--- a/pkg/azureclients/routetableclient/interface.go
+++ /dev/null
@@ -1,44 +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 routetableclient
-
-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 RouteTable.
-// Don't forget to run "hack/update-mock-clients.sh" command to generate the mock client.
-type Interface interface {
-	// Get gets a RouteTable.
-	Get(ctx context.Context, resourceGroupName string, routeTableName string, expand string) (result network.RouteTable, rerr *retry.Error)
-
-	// CreateOrUpdate creates or updates a RouteTable.
-	CreateOrUpdate(ctx context.Context, resourceGroupName string, routeTableName string, parameters network.RouteTable, etag string) *retry.Error
-}
diff --git a/pkg/azureclients/routetableclient/mockroutetableclient/doc.go b/pkg/azureclients/routetableclient/mockroutetableclient/doc.go
deleted file mode 100644
index c2aa4cc39..000000000
--- a/pkg/azureclients/routetableclient/mockroutetableclient/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 mockroutetableclient implements the mock client for RouteTable.
-package mockroutetableclient // import "sigs.k8s.io/cloud-provider-azure/pkg/azureclients/routetableclient/mockroutetableclient"
diff --git a/pkg/provider/azure.go b/pkg/provider/azure.go
index 677bb2ea1..b6c4ba090 100644
--- a/pkg/provider/azure.go
+++ b/pkg/provider/azure.go
@@ -48,6 +48,7 @@ import (
 	cloudnodeutil "k8s.io/cloud-provider/node/helpers"
 	nodeutil "k8s.io/component-helpers/node/util"
 	"k8s.io/klog/v2"
+	"sigs.k8s.io/yaml"
 
 	"sigs.k8s.io/cloud-provider-azure/pkg/azclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader"
@@ -60,7 +61,6 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/privatednszonegroupclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/privateendpointclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/publicipclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/routetableclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/storageaccountclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/subnetclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/vmasclient"
@@ -69,15 +69,14 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/vmssclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/vmssvmclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/privatelinkservice"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/routetable"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/securitygroup"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/subnet"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/zone"
 
-	"sigs.k8s.io/yaml"
-
 	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"
@@ -358,7 +357,6 @@ type Cloud struct {
 
 	SubnetsClient                   subnetclient.Interface
 	InterfacesClient                interfaceclient.Interface
-	RouteTablesClient               routetableclient.Interface
 	LoadBalancerClient              loadbalancerclient.Interface
 	PublicIPAddressesClient         publicipclient.Interface
 	VirtualMachinesClient           vmclient.Interface
@@ -415,13 +413,13 @@ type Cloud struct {
 	routeUpdater       batchProcessor
 	backendPoolUpdater batchProcessor
 
-	vmCache    azcache.Resource
-	lbCache    azcache.Resource
-	nsgRepo    securitygroup.Repository
-	zoneRepo   zone.Repository
-	plsRepo    privatelinkservice.Repository
-	subnetRepo subnet.Repository
-	rtCache    azcache.Resource
+	vmCache        azcache.Resource
+	lbCache        azcache.Resource
+	nsgRepo        securitygroup.Repository
+	zoneRepo       zone.Repository
+	plsRepo        privatelinkservice.Repository
+	subnetRepo     subnet.Repository
+	routeTableRepo routetable.Repository
 	// public ip cache
 	// key: [resourceGroupName]
 	// Value: sync.Map of [pipName]*PublicIPAddress
@@ -752,10 +750,16 @@ func (az *Cloud) InitializeCloudFromConfig(ctx context.Context, config *Config,
 		if err != nil {
 			return err
 		}
+
 		az.subnetRepo, err = subnet.NewRepo(networkClientFactory.GetSubnetClient())
 		if err != nil {
 			return err
 		}
+
+		az.routeTableRepo, err = routetable.NewRepo(networkClientFactory.GetRouteTableClient(), az.RouteTableResourceGroup, time.Duration(az.RouteTableCacheTTLInSeconds)*time.Second, az.DisableAPICallCache)
+		if err != nil {
+			return err
+		}
 	}
 	err = az.initCaches()
 	if err != nil {
@@ -869,11 +873,6 @@ func (az *Cloud) initCaches() (err error) {
 		return err
 	}
 
-	az.rtCache, err = az.newRouteTableCache()
-	if err != nil {
-		return err
-	}
-
 	az.pipCache, err = az.newPIPCache()
 	if err != nil {
 		return err
@@ -1033,7 +1032,6 @@ func (az *Cloud) configAzureClients(
 	az.VirtualMachineScaleSetsClient = vmssclient.New(vmssClientConfig)
 	az.VirtualMachineScaleSetVMsClient = vmssvmclient.New(vmssVMClientConfig)
 	az.SubnetsClient = subnetclient.New(subnetClientConfig)
-	az.RouteTablesClient = routetableclient.New(routeTableClientConfig)
 	az.LoadBalancerClient = loadbalancerclient.New(loadBalancerClientConfig)
 	az.PublicIPAddressesClient = publicipclient.New(publicIPClientConfig)
 	az.FileClient = fileclient.New(fileClientConfig)
diff --git a/pkg/provider/azure_fakes.go b/pkg/provider/azure_fakes.go
index 030128a85..0b1db9dfd 100644
--- a/pkg/provider/azure_fakes.go
+++ b/pkg/provider/azure_fakes.go
@@ -36,7 +36,6 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/interfaceclient/mockinterfaceclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/loadbalancerclient/mockloadbalancerclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/publicipclient/mockpublicipclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/routetableclient/mockroutetableclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/subnetclient/mocksubnetclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/vmclient/mockvmclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/vmssclient/mockvmssclient"
@@ -45,6 +44,7 @@ import (
 	"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/privatelinkservice"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/routetable"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/securitygroup"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/subnet"
 	utilsets "sigs.k8s.io/cloud-provider-azure/pkg/util/sets"
@@ -116,7 +116,6 @@ func GetTestCloud(ctrl *gomock.Controller) (az *Cloud) {
 	az.InterfacesClient = mockinterfaceclient.NewMockInterface(ctrl)
 	az.LoadBalancerClient = mockloadbalancerclient.NewMockInterface(ctrl)
 	az.PublicIPAddressesClient = mockpublicipclient.NewMockInterface(ctrl)
-	az.RouteTablesClient = mockroutetableclient.NewMockInterface(ctrl)
 	az.SubnetsClient = mocksubnetclient.NewMockInterface(ctrl)
 	az.VirtualMachineScaleSetsClient = mockvmssclient.NewMockInterface(ctrl)
 	az.VirtualMachineScaleSetVMsClient = mockvmssvmclient.NewMockInterface(ctrl)
@@ -140,11 +139,11 @@ func GetTestCloud(ctrl *gomock.Controller) (az *Cloud) {
 	az.lbCache, _ = az.newLBCache()
 	az.nsgRepo, _ = securitygroup.NewSecurityGroupRepo(az.SecurityGroupResourceGroup, az.SecurityGroupName, az.NsgCacheTTLInSeconds, az.Config.DisableAPICallCache, securtyGrouptrack2Client)
 	az.subnetRepo = subnet.NewMockRepository(ctrl)
-	az.rtCache, _ = az.newRouteTableCache()
 	az.pipCache, _ = az.newPIPCache()
 	az.LoadBalancerBackendPool = NewMockBackendPool(ctrl)
 
 	az.plsRepo = privatelinkservice.NewMockRepository(ctrl)
+	az.routeTableRepo = routetable.NewMockRepository(ctrl)
 
 	getter := func(_ context.Context, _ string) (interface{}, error) { return nil, nil }
 	az.storageAccountCache, _ = azcache.NewTimedCache(time.Minute, getter, az.Config.DisableAPICallCache)
diff --git a/pkg/provider/azure_routes.go b/pkg/provider/azure_routes.go
index c32c7a3cc..4527908ef 100644
--- a/pkg/provider/azure_routes.go
+++ b/pkg/provider/azure_routes.go
@@ -23,8 +23,7 @@ import (
 	"sync"
 	"time"
 
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-
+	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/wait"
 	cloudprovider "k8s.io/cloud-provider"
@@ -53,7 +52,7 @@ const (
 
 // delayedRouteOperation defines a delayed route operation which is used in delayedRouteUpdater.
 type delayedRouteOperation struct {
-	route          network.Route
+	route          *armnetwork.Route
 	routeTableTags map[string]*string
 	operation      routeOperation
 	result         chan batchOperationResult
@@ -119,24 +118,23 @@ func (d *delayedRouteUpdater) updateRoutes(ctx context.Context) {
 	}()
 
 	var (
-		routeTable       network.RouteTable
-		existsRouteTable bool
+		routeTable *armnetwork.RouteTable
 	)
-	routeTable, existsRouteTable, err = d.az.getRouteTable(ctx, azcache.CacheReadTypeDefault)
+	routeTable, err = d.az.routeTableRepo.Get(ctx, d.az.RouteTableName, azcache.CacheReadTypeDefault)
 	if err != nil {
 		klog.Errorf("getRouteTable() failed with error: %v", err)
 		return
 	}
 
 	// create route table if it doesn't exists yet.
-	if !existsRouteTable {
-		err = d.az.createRouteTable()
+	if routeTable == nil {
+		err = d.az.createRouteTable(ctx)
 		if err != nil {
 			klog.Errorf("createRouteTable() failed with error: %v", err)
 			return
 		}
 
-		routeTable, _, err = d.az.getRouteTable(ctx, azcache.CacheReadTypeDefault)
+		routeTable, err = d.az.routeTableRepo.Get(ctx, d.az.RouteTableName, azcache.CacheReadTypeDefault)
 		if err != nil {
 			klog.Errorf("getRouteTable() failed with error: %v", err)
 			return
@@ -145,9 +143,9 @@ func (d *delayedRouteUpdater) updateRoutes(ctx context.Context) {
 
 	// reconcile routes.
 	dirty, onlyUpdateTags := false, true
-	routes := []network.Route{}
-	if routeTable.RouteTablePropertiesFormat != nil && routeTable.RouteTablePropertiesFormat.Routes != nil {
-		routes = *routeTable.Routes
+	var routes []*armnetwork.Route
+	if routeTable.Properties != nil {
+		routes = routeTable.Properties.Routes
 	}
 
 	routes, dirty = d.cleanupOutdatedRoutes(routes)
@@ -169,10 +167,10 @@ func (d *delayedRouteUpdater) updateRoutes(ctx context.Context) {
 			if strings.EqualFold(ptr.Deref(existingRoute.Name, ""), ptr.Deref(rt.route.Name, "")) {
 				// delete the name-matched routes here (missing routes would be added later if the operation is add).
 				routes = append(routes[:i], routes[i+1:]...)
-				if existingRoute.RoutePropertiesFormat != nil &&
-					rt.route.RoutePropertiesFormat != nil &&
-					strings.EqualFold(ptr.Deref(existingRoute.AddressPrefix, ""), ptr.Deref(rt.route.AddressPrefix, "")) &&
-					strings.EqualFold(ptr.Deref(existingRoute.NextHopIPAddress, ""), ptr.Deref(rt.route.NextHopIPAddress, "")) {
+				if existingRoute.Properties != nil &&
+					rt.route.Properties != nil &&
+					strings.EqualFold(ptr.Deref(existingRoute.Properties.AddressPrefix, ""), ptr.Deref(rt.route.Properties.AddressPrefix, "")) &&
+					strings.EqualFold(ptr.Deref(existingRoute.Properties.NextHopIPAddress, ""), ptr.Deref(rt.route.Properties.NextHopIPAddress, "")) {
 					routeMatch = true
 				}
 				if rt.operation == routeOperationDelete {
@@ -198,9 +196,9 @@ func (d *delayedRouteUpdater) updateRoutes(ctx context.Context) {
 	if dirty {
 		if !onlyUpdateTags {
 			klog.V(2).Infof("updateRoutes: updating routes")
-			routeTable.Routes = &routes
+			routeTable.Properties.Routes = routes
 		}
-		err = d.az.CreateOrUpdateRouteTable(routeTable)
+		_, err := d.az.routeTableRepo.CreateOrUpdate(ctx, *routeTable)
 		if err != nil {
 			klog.Errorf("CreateOrUpdateRouteTable() failed with error: %v", err)
 			return
@@ -213,7 +211,7 @@ func (d *delayedRouteUpdater) updateRoutes(ctx context.Context) {
 
 // cleanupOutdatedRoutes deletes all non-dualstack routes when dualstack is enabled,
 // and deletes all dualstack routes when dualstack is not enabled.
-func (d *delayedRouteUpdater) cleanupOutdatedRoutes(existingRoutes []network.Route) (routes []network.Route, changed bool) {
+func (d *delayedRouteUpdater) cleanupOutdatedRoutes(existingRoutes []*armnetwork.Route) (routes []*armnetwork.Route, changed bool) {
 	for i := len(existingRoutes) - 1; i >= 0; i-- {
 		existingRouteName := ptr.Deref(existingRoutes[i].Name, "")
 		split := strings.Split(existingRouteName, consts.RouteNameSeparator)
@@ -241,7 +239,7 @@ func (d *delayedRouteUpdater) cleanupOutdatedRoutes(existingRoutes []network.Rou
 	return existingRoutes, changed
 }
 
-func getAddRouteOperation(route network.Route) batchOperation {
+func getAddRouteOperation(route *armnetwork.Route) batchOperation {
 	return &delayedRouteOperation{
 		route:     route,
 		operation: routeOperationAdd,
@@ -249,7 +247,7 @@ func getAddRouteOperation(route network.Route) batchOperation {
 	}
 }
 
-func getDeleteRouteOperation(route network.Route) batchOperation {
+func getDeleteRouteOperation(route *armnetwork.Route) batchOperation {
 	return &delayedRouteOperation{
 		route:     route,
 		operation: routeOperationDelete,
@@ -280,8 +278,8 @@ func (d *delayedRouteUpdater) removeOperation(_ string) {}
 // implements cloudprovider.Routes.ListRoutes
 func (az *Cloud) ListRoutes(ctx context.Context, clusterName string) ([]*cloudprovider.Route, error) {
 	klog.V(10).Infof("ListRoutes: START clusterName=%q", clusterName)
-	routeTable, existsRouteTable, err := az.getRouteTable(ctx, azcache.CacheReadTypeDefault)
-	routes, err := processRoutes(az.ipv6DualStackEnabled, routeTable, existsRouteTable, err)
+	routeTable, err := az.routeTableRepo.Get(ctx, az.RouteTableName, azcache.CacheReadTypeDefault)
+	routes, err := processRoutes(az.ipv6DualStackEnabled, routeTable, err)
 	if err != nil {
 		return nil, err
 	}
@@ -304,7 +302,7 @@ func (az *Cloud) ListRoutes(ctx context.Context, clusterName string) ([]*cloudpr
 	}
 
 	// ensure the route table is tagged as configured
-	tags, changed := az.ensureRouteTableTagged(&routeTable)
+	tags, changed := az.ensureRouteTableTagged(routeTable)
 	if changed {
 		klog.V(2).Infof("ListRoutes: updating tags on route table %s", ptr.Deref(routeTable.Name, ""))
 		op := az.routeUpdater.addOperation(getUpdateRouteTableTagsOperation(tags))
@@ -321,20 +319,20 @@ func (az *Cloud) ListRoutes(ctx context.Context, clusterName string) ([]*cloudpr
 }
 
 // Injectable for testing
-func processRoutes(ipv6DualStackEnabled bool, routeTable network.RouteTable, exists bool, err error) ([]*cloudprovider.Route, error) {
+func processRoutes(ipv6DualStackEnabled bool, routeTable *armnetwork.RouteTable, err error) ([]*cloudprovider.Route, error) {
 	if err != nil {
 		return nil, err
 	}
-	if !exists {
+	if routeTable == nil {
 		return []*cloudprovider.Route{}, nil
 	}
 
 	var kubeRoutes []*cloudprovider.Route
-	if routeTable.RouteTablePropertiesFormat != nil && routeTable.Routes != nil {
-		kubeRoutes = make([]*cloudprovider.Route, len(*routeTable.Routes))
-		for i, route := range *routeTable.Routes {
+	if routeTable.Properties != nil {
+		kubeRoutes = make([]*cloudprovider.Route, len(routeTable.Properties.Routes))
+		for i, route := range routeTable.Properties.Routes {
 			instance := MapRouteNameToNodeName(ipv6DualStackEnabled, *route.Name)
-			cidr := *route.AddressPrefix
+			cidr := *route.Properties.AddressPrefix
 			klog.V(10).Infof("ListRoutes: * instance=%q, cidr=%q", instance, cidr)
 
 			kubeRoutes[i] = &cloudprovider.Route{
@@ -349,22 +347,16 @@ func processRoutes(ipv6DualStackEnabled bool, routeTable network.RouteTable, exi
 	return kubeRoutes, nil
 }
 
-func (az *Cloud) createRouteTable() error {
-	routeTable := network.RouteTable{
-		Name:                       ptr.To(az.RouteTableName),
-		Location:                   ptr.To(az.Location),
-		RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{},
+func (az *Cloud) createRouteTable(ctx context.Context) error {
+	routeTable := armnetwork.RouteTable{
+		Name:       ptr.To(az.RouteTableName),
+		Location:   ptr.To(az.Location),
+		Properties: &armnetwork.RouteTablePropertiesFormat{},
 	}
 
 	klog.V(3).Infof("createRouteTableIfNotExists: creating routetable. routeTableName=%q", az.RouteTableName)
-	err := az.CreateOrUpdateRouteTable(routeTable)
-	if err != nil {
-		return err
-	}
-
-	// Invalidate the cache right after updating
-	_ = az.rtCache.Delete(az.RouteTableName)
-	return nil
+	_, err := az.routeTableRepo.CreateOrUpdate(ctx, routeTable)
+	return err
 }
 
 // CreateRoute creates the described managed route
@@ -419,11 +411,11 @@ func (az *Cloud) CreateRoute(ctx context.Context, clusterName string, _ string,
 		}
 	}
 	routeName := mapNodeNameToRouteName(az.ipv6DualStackEnabled, kubeRoute.TargetNode, kubeRoute.DestinationCIDR)
-	route := network.Route{
+	route := &armnetwork.Route{
 		Name: ptr.To(routeName),
-		RoutePropertiesFormat: &network.RoutePropertiesFormat{
+		Properties: &armnetwork.RoutePropertiesFormat{
 			AddressPrefix:    ptr.To(kubeRoute.DestinationCIDR),
-			NextHopType:      network.RouteNextHopTypeVirtualAppliance,
+			NextHopType:      ptr.To(armnetwork.RouteNextHopTypeVirtualAppliance),
 			NextHopIPAddress: ptr.To(targetIP),
 		},
 	}
@@ -470,9 +462,9 @@ func (az *Cloud) DeleteRoute(_ context.Context, clusterName string, kubeRoute *c
 
 	routeName := mapNodeNameToRouteName(az.ipv6DualStackEnabled, kubeRoute.TargetNode, kubeRoute.DestinationCIDR)
 	klog.V(2).Infof("DeleteRoute: deleting route. clusterName=%q instance=%q cidr=%q routeName=%q", clusterName, kubeRoute.TargetNode, kubeRoute.DestinationCIDR, routeName)
-	route := network.Route{
-		Name:                  ptr.To(routeName),
-		RoutePropertiesFormat: &network.RoutePropertiesFormat{},
+	route := &armnetwork.Route{
+		Name:       ptr.To(routeName),
+		Properties: &armnetwork.RoutePropertiesFormat{},
 	}
 	op := az.routeUpdater.addOperation(getDeleteRouteOperation(route))
 
@@ -487,9 +479,9 @@ func (az *Cloud) DeleteRoute(_ context.Context, clusterName string, kubeRoute *c
 	if az.ipv6DualStackEnabled {
 		routeNameWithoutIPV6Suffix := strings.Split(routeName, consts.RouteNameSeparator)[0]
 		klog.V(2).Infof("DeleteRoute: deleting route. clusterName=%q instance=%q cidr=%q routeName=%q", clusterName, kubeRoute.TargetNode, kubeRoute.DestinationCIDR, routeNameWithoutIPV6Suffix)
-		route := network.Route{
-			Name:                  ptr.To(routeNameWithoutIPV6Suffix),
-			RoutePropertiesFormat: &network.RoutePropertiesFormat{},
+		route := &armnetwork.Route{
+			Name:       ptr.To(routeNameWithoutIPV6Suffix),
+			Properties: &armnetwork.RoutePropertiesFormat{},
 		}
 		op := az.routeUpdater.addOperation(getDeleteRouteOperation(route))
 
@@ -553,7 +545,7 @@ func cidrtoRfc1035(cidr string) string {
 }
 
 // ensureRouteTableTagged ensures the route table is tagged as configured
-func (az *Cloud) ensureRouteTableTagged(rt *network.RouteTable) (map[string]*string, bool) {
+func (az *Cloud) ensureRouteTableTagged(rt *armnetwork.RouteTable) (map[string]*string, bool) {
 	if !strings.EqualFold(az.RouteTableResourceGroup, az.ResourceGroup) {
 		return nil, false
 	}
diff --git a/pkg/provider/azure_routetable_repo.go b/pkg/provider/azure_routetable_repo.go
deleted file mode 100644
index 116c9138f..000000000
--- a/pkg/provider/azure_routetable_repo.go
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package provider
-
-import (
-	"context"
-	"encoding/json"
-	"net/http"
-	"strings"
-	"time"
-
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-
-	"k8s.io/klog/v2"
-	"k8s.io/utils/ptr"
-
-	azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
-	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
-)
-
-// CreateOrUpdateRouteTable invokes az.RouteTablesClient.CreateOrUpdate with exponential backoff retry
-func (az *Cloud) CreateOrUpdateRouteTable(routeTable network.RouteTable) error {
-	ctx, cancel := getContextWithCancel()
-	defer cancel()
-
-	rerr := az.RouteTablesClient.CreateOrUpdate(ctx, az.RouteTableResourceGroup, az.RouteTableName, routeTable, ptr.Deref(routeTable.Etag, ""))
-	if rerr == nil {
-		// Invalidate the cache right after updating
-		_ = az.rtCache.Delete(*routeTable.Name)
-		return nil
-	}
-
-	rtJSON, _ := json.Marshal(routeTable)
-	klog.Warningf("RouteTablesClient.CreateOrUpdate(%s) failed: %v, RouteTable request: %s", ptr.Deref(routeTable.Name, ""), rerr.Error(), string(rtJSON))
-
-	// Invalidate the cache because etag mismatch.
-	if rerr.HTTPStatusCode == http.StatusPreconditionFailed {
-		klog.V(3).Infof("Route table cache for %s is cleanup because of http.StatusPreconditionFailed", *routeTable.Name)
-		_ = az.rtCache.Delete(*routeTable.Name)
-	}
-	// Invalidate the cache because another new operation has canceled the current request.
-	if strings.Contains(strings.ToLower(rerr.Error().Error()), consts.OperationCanceledErrorMessage) {
-		klog.V(3).Infof("Route table cache for %s is cleanup because CreateOrUpdateRouteTable is canceled by another operation", *routeTable.Name)
-		_ = az.rtCache.Delete(*routeTable.Name)
-	}
-	klog.Errorf("RouteTablesClient.CreateOrUpdate(%s) failed: %v", az.RouteTableName, rerr.Error())
-	return rerr.Error()
-}
-
-func (az *Cloud) newRouteTableCache() (azcache.Resource, error) {
-	getter := func(ctx context.Context, key string) (interface{}, error) {
-		rt, err := az.RouteTablesClient.Get(ctx, az.RouteTableResourceGroup, key, "")
-		exists, rerr := checkResourceExistsFromError(err)
-		if rerr != nil {
-			return nil, rerr.Error()
-		}
-
-		if !exists {
-			klog.V(2).Infof("Route table %q not found", key)
-			return nil, nil
-		}
-
-		return &rt, nil
-	}
-
-	if az.RouteTableCacheTTLInSeconds == 0 {
-		az.RouteTableCacheTTLInSeconds = routeTableCacheTTLDefaultInSeconds
-	}
-	return azcache.NewTimedCache(time.Duration(az.RouteTableCacheTTLInSeconds)*time.Second, getter, az.Config.DisableAPICallCache)
-}
diff --git a/pkg/provider/azure_vmsets_repo.go b/pkg/provider/azure_vmsets_repo.go
index ec7106c95..00c13e6a6 100644
--- a/pkg/provider/azure_vmsets_repo.go
+++ b/pkg/provider/azure_vmsets_repo.go
@@ -19,13 +19,10 @@ package provider
 import (
 	"context"
 	"errors"
-	"fmt"
 	"strings"
 	"time"
 
 	"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2022-08-01/compute"
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/wait"
 	cloudprovider "k8s.io/cloud-provider"
@@ -171,20 +168,3 @@ func (az *Cloud) getVirtualMachine(ctx context.Context, nodeName types.NodeName,
 
 	return *(cachedVM.(*compute.VirtualMachine)), nil
 }
-
-func (az *Cloud) getRouteTable(ctx context.Context, crt azcache.AzureCacheReadType) (routeTable network.RouteTable, exists bool, err error) {
-	if len(az.RouteTableName) == 0 {
-		return routeTable, false, fmt.Errorf("route table name is not configured")
-	}
-
-	cachedRt, err := az.rtCache.GetWithDeepCopy(ctx, az.RouteTableName, crt)
-	if err != nil {
-		return routeTable, false, err
-	}
-
-	if cachedRt == nil {
-		return routeTable, false, nil
-	}
-
-	return *(cachedRt.(*network.RouteTable)), true, nil
-}
diff --git a/pkg/provider/azure_wrap.go b/pkg/provider/azure_wrap.go
index d599ddbd2..614c01233 100644
--- a/pkg/provider/azure_wrap.go
+++ b/pkg/provider/azure_wrap.go
@@ -29,7 +29,6 @@ import (
 var (
 	vmCacheTTLDefaultInSeconds           = 60
 	loadBalancerCacheTTLDefaultInSeconds = 120
-	routeTableCacheTTLDefaultInSeconds   = 120
 	publicIPCacheTTLDefaultInSeconds     = 120
 
 	azureNodeProviderIDRE    = regexp.MustCompile(`^azure:///subscriptions/(?:.*)/resourceGroups/(?:.*)/providers/Microsoft.Compute/(?:.*)`)
diff --git a/pkg/provider/routetable/cache.go b/pkg/provider/routetable/cache.go
new file mode 100644
index 000000000..96927a51c
--- /dev/null
+++ b/pkg/provider/routetable/cache.go
@@ -0,0 +1,55 @@
+/*
+Copyright 2024 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 routetable
+
+import (
+	"context"
+	"time"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient"
+	"sigs.k8s.io/cloud-provider-azure/pkg/cache"
+	"sigs.k8s.io/cloud-provider-azure/pkg/util/errutils"
+)
+
+const (
+	DefaultCacheTTL = 120 * time.Second
+)
+
+func NewCache(
+	client routetableclient.Interface,
+	resourceGroup string,
+	cacheTTL time.Duration,
+	disableAPICallCache bool,
+) (cache.Resource, error) {
+	getter := func(ctx context.Context, key string) (interface{}, error) {
+		rt, err := client.Get(ctx, resourceGroup, key)
+		found, err := errutils.CheckResourceExistsFromAzcoreError(err)
+		if err != nil {
+			return nil, err
+		}
+		if !found {
+			return nil, nil
+		}
+
+		return rt, nil
+	}
+
+	if cacheTTL == 0 {
+		cacheTTL = DefaultCacheTTL
+	}
+	return cache.NewTimedCache(cacheTTL, getter, disableAPICallCache)
+}
diff --git a/pkg/provider/routetable/mock_repo.go b/pkg/provider/routetable/mock_repo.go
new file mode 100644
index 000000000..76988b62c
--- /dev/null
+++ b/pkg/provider/routetable/mock_repo.go
@@ -0,0 +1,88 @@
+// /*
+// 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: repo.go
+//
+// Generated by this command:
+//
+//	mockgen -destination=./mock_repo.go -package=routetable -copyright_file ../../../hack/boilerplate/boilerplate.generatego.txt -source=repo.go Repository
+//
+// Package routetable is a generated GoMock package.
+package routetable
+
+import (
+	context "context"
+	reflect "reflect"
+
+	armnetwork "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
+	gomock "go.uber.org/mock/gomock"
+	cache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
+)
+
+// 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
+}
+
+// CreateOrUpdate mocks base method.
+func (m *MockRepository) CreateOrUpdate(ctx context.Context, routeTable armnetwork.RouteTable) (*armnetwork.RouteTable, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateOrUpdate", ctx, routeTable)
+	ret0, _ := ret[0].(*armnetwork.RouteTable)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateOrUpdate indicates an expected call of CreateOrUpdate.
+func (mr *MockRepositoryMockRecorder) CreateOrUpdate(ctx, routeTable any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdate", reflect.TypeOf((*MockRepository)(nil).CreateOrUpdate), ctx, routeTable)
+}
+
+// Get mocks base method.
+func (m *MockRepository) Get(ctx context.Context, routeTableName string, crt cache.AzureCacheReadType) (*armnetwork.RouteTable, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Get", ctx, routeTableName, crt)
+	ret0, _ := ret[0].(*armnetwork.RouteTable)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Get indicates an expected call of Get.
+func (mr *MockRepositoryMockRecorder) Get(ctx, routeTableName, crt any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockRepository)(nil).Get), ctx, routeTableName, crt)
+}
diff --git a/pkg/provider/routetable/repo.go b/pkg/provider/routetable/repo.go
new file mode 100644
index 000000000..fb5400df1
--- /dev/null
+++ b/pkg/provider/routetable/repo.go
@@ -0,0 +1,87 @@
+/*
+Copyright 2024 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 routetable
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient"
+	"sigs.k8s.io/cloud-provider-azure/pkg/cache"
+)
+
+// Generate mocks for the repository interface
+//go:generate mockgen -destination=./mock_repo.go -package=routetable -copyright_file ../../../hack/boilerplate/boilerplate.generatego.txt -source=repo.go Repository
+
+var (
+	ErrMissingRouteTableName = fmt.Errorf("missing RouteTable name")
+)
+
+type Repository interface {
+	Get(ctx context.Context, routeTableName string, crt cache.AzureCacheReadType) (*armnetwork.RouteTable, error)
+	CreateOrUpdate(ctx context.Context, routeTable armnetwork.RouteTable) (*armnetwork.RouteTable, error)
+}
+
+type repo struct {
+	resourceGroup string
+	client        routetableclient.Interface
+	cache         cache.Resource
+}
+
+func NewRepo(
+	client routetableclient.Interface,
+	resourceGroup string,
+	cacheTTL time.Duration,
+	disableAPICallCache bool,
+) (Repository, error) {
+	c, err := NewCache(client, resourceGroup, cacheTTL, disableAPICallCache)
+	if err != nil {
+		return nil, fmt.Errorf("new RouteTable cache: %w", err)
+	}
+
+	return &repo{
+		resourceGroup: resourceGroup,
+		client:        client,
+		cache:         c,
+	}, nil
+}
+
+func (r *repo) Get(ctx context.Context, routeTableName string, crt cache.AzureCacheReadType) (*armnetwork.RouteTable, error) {
+	rt, err := r.cache.GetWithDeepCopy(ctx, routeTableName, crt)
+	if err != nil {
+		return nil, fmt.Errorf("get RouteTable: %w", err)
+	}
+
+	return rt.(*armnetwork.RouteTable), nil
+}
+
+func (r *repo) CreateOrUpdate(ctx context.Context, routeTable armnetwork.RouteTable) (*armnetwork.RouteTable, error) {
+	if routeTable.Name == nil {
+		return nil, ErrMissingRouteTableName
+	}
+
+	rv, err := r.client.CreateOrUpdate(ctx, r.resourceGroup, *routeTable.Name, routeTable)
+	if err != nil {
+		return nil, fmt.Errorf("create or update RouteTable: %w", err)
+	}
+	_ = r.cache.Delete(*routeTable.Name)
+
+	return rv, nil
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 35a720176..acf225214 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1570,6 +1570,7 @@ sigs.k8s.io/cloud-provider-azure/pkg/azclient/registryclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/resourcegroupclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/roleassignmentclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient
+sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient/mock_routetableclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/secretclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/securitygroupclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/securitygroupclient/mock_securitygroupclient
diff --git a/pkg/azureclients/routetableclient/mockroutetableclient/interface.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient/mock_routetableclient/interface.go
similarity index 52%
rename from pkg/azureclients/routetableclient/mockroutetableclient/interface.go
rename to vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient/mock_routetableclient/interface.go
index 200ff014c..ef6fedb42 100644
--- a/pkg/azureclients/routetableclient/mockroutetableclient/interface.go
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient/mock_routetableclient/interface.go
@@ -13,32 +13,31 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // */
-//
 
 // Code generated by MockGen. DO NOT EDIT.
-// Source: pkg/azureclients/routetableclient/interface.go
+// Source: routetableclient/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/routetableclient/interface.go -package=mockroutetableclient Interface
+//	mockgen -package mock_routetableclient -source routetableclient/interface.go
 //
 
-// Package mockroutetableclient is a generated GoMock package.
-package mockroutetableclient
+// Package mock_routetableclient is a generated GoMock package.
+package mock_routetableclient
 
 import (
 	context "context"
 	reflect "reflect"
 
-	network "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
+	armnetwork "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
 	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
+	isgomock struct{}
 }
 
 // MockInterfaceMockRecorder is the mock recorder for MockInterface.
@@ -59,30 +58,60 @@ func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder {
 }
 
 // CreateOrUpdate mocks base method.
-func (m *MockInterface) CreateOrUpdate(ctx context.Context, resourceGroupName, routeTableName string, parameters network.RouteTable, etag string) *retry.Error {
+func (m *MockInterface) CreateOrUpdate(ctx context.Context, resourceGroupName, resourceName string, resourceParam armnetwork.RouteTable) (*armnetwork.RouteTable, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateOrUpdate", ctx, resourceGroupName, routeTableName, parameters, etag)
-	ret0, _ := ret[0].(*retry.Error)
-	return ret0
+	ret := m.ctrl.Call(m, "CreateOrUpdate", ctx, resourceGroupName, resourceName, resourceParam)
+	ret0, _ := ret[0].(*armnetwork.RouteTable)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
 }
 
 // CreateOrUpdate indicates an expected call of CreateOrUpdate.
-func (mr *MockInterfaceMockRecorder) CreateOrUpdate(ctx, resourceGroupName, routeTableName, parameters, etag any) *gomock.Call {
+func (mr *MockInterfaceMockRecorder) CreateOrUpdate(ctx, resourceGroupName, resourceName, resourceParam any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdate", reflect.TypeOf((*MockInterface)(nil).CreateOrUpdate), ctx, resourceGroupName, routeTableName, parameters, etag)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdate", reflect.TypeOf((*MockInterface)(nil).CreateOrUpdate), ctx, resourceGroupName, resourceName, resourceParam)
+}
+
+// Delete mocks base method.
+func (m *MockInterface) Delete(ctx context.Context, resourceGroupName, resourceName string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Delete", ctx, resourceGroupName, resourceName)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Delete indicates an expected call of Delete.
+func (mr *MockInterfaceMockRecorder) Delete(ctx, resourceGroupName, resourceName any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockInterface)(nil).Delete), ctx, resourceGroupName, resourceName)
 }
 
 // Get mocks base method.
-func (m *MockInterface) Get(ctx context.Context, resourceGroupName, routeTableName, expand string) (network.RouteTable, *retry.Error) {
+func (m *MockInterface) Get(ctx context.Context, resourceGroupName, resourceName string) (*armnetwork.RouteTable, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Get", ctx, resourceGroupName, routeTableName, expand)
-	ret0, _ := ret[0].(network.RouteTable)
-	ret1, _ := ret[1].(*retry.Error)
+	ret := m.ctrl.Call(m, "Get", ctx, resourceGroupName, resourceName)
+	ret0, _ := ret[0].(*armnetwork.RouteTable)
+	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // Get indicates an expected call of Get.
-func (mr *MockInterfaceMockRecorder) Get(ctx, resourceGroupName, routeTableName, expand any) *gomock.Call {
+func (mr *MockInterfaceMockRecorder) Get(ctx, resourceGroupName, resourceName any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockInterface)(nil).Get), ctx, resourceGroupName, resourceName)
+}
+
+// List mocks base method.
+func (m *MockInterface) List(ctx context.Context, resourceGroupName string) ([]*armnetwork.RouteTable, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "List", ctx, resourceGroupName)
+	ret0, _ := ret[0].([]*armnetwork.RouteTable)
+	ret1, _ := ret[1].(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, "Get", reflect.TypeOf((*MockInterface)(nil).Get), ctx, resourceGroupName, routeTableName, expand)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockInterface)(nil).List), ctx, resourceGroupName)
 }


Test patch:
diff --git a/pkg/azureclients/routetableclient/azure_routetableclient_test.go b/pkg/azureclients/routetableclient/azure_routetableclient_test.go
deleted file mode 100644
index ee1d6d9d4..000000000
--- a/pkg/azureclients/routetableclient/azure_routetableclient_test.go
+++ /dev/null
@@ -1,347 +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 routetableclient
-
-import (
-	"bytes"
-	"context"
-	"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 (
-	resourceID = "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Network/routeTables/rt1"
-)
-
-// 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},
-	}
-
-	routetableClient := New(config)
-	assert.Equal(t, "sub", routetableClient.subscriptionID)
-	assert.NotEmpty(t, routetableClient.rateLimiterReader)
-	assert.NotEmpty(t, routetableClient.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},
-	}
-
-	routetableClient := New(config)
-	assert.Equal(t, "AZURESTACKCLOUD", routetableClient.cloudName)
-	assert.Equal(t, "sub", routetableClient.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(), resourceID, "").Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	routetableClient := getTestRouteTableClient(armClient)
-	expected := network.RouteTable{}
-	expected.Response = autorest.Response{Response: response}
-	result, rerr := routetableClient.Get(context.TODO(), "rg", "rt1", "")
-	assert.Equal(t, expected, result)
-	assert.Nil(t, 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(), resourceID, "").Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	rtClient := getTestRouteTableClient(armClient)
-	expected := network.RouteTable{Response: autorest.Response{}}
-	result, rerr := rtClient.Get(context.TODO(), "rg", "rt1", "")
-	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(), resourceID, "").Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	rtClient := getTestRouteTableClient(armClient)
-	expected := network.RouteTable{Response: autorest.Response{}}
-	result, rerr := rtClient.Get(context.TODO(), "rg", "rt1", "")
-	assert.Equal(t, expected, result)
-	assert.NotNil(t, rerr)
-	assert.Equal(t, http.StatusInternalServerError, rerr.HTTPStatusCode)
-}
-
-func TestGetNeverRateLimiter(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	rtGetErr := &retry.Error{
-		RawError:  fmt.Errorf("azure cloud provider rate limited(%s) for operation %q", "read", "RouteTableGet"),
-		Retriable: true,
-	}
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	routetableClient := getTestRouteTableClientWithNeverRateLimiter(armClient)
-	expected := network.RouteTable{}
-	result, rerr := routetableClient.Get(context.TODO(), "rg", "rt1", "")
-	assert.Equal(t, expected, result)
-	assert.Equal(t, rtGetErr, rerr)
-}
-
-func TestGetRetryAfterReader(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	rtGetErr := &retry.Error{
-		RawError:   fmt.Errorf("azure cloud provider throttled for operation %s with reason %q", "RouteTableGet", "client throttled"),
-		Retriable:  true,
-		RetryAfter: getFutureTime(),
-	}
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	routetableClient := getTestRouteTableClientWithRetryAfterReader(armClient)
-	expected := network.RouteTable{}
-	result, rerr := routetableClient.Get(context.TODO(), "rg", "rt1", "")
-	assert.Equal(t, expected, result)
-	assert.Equal(t, rtGetErr, 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(), resourceID, "").Return(response, throttleErr).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	routetableClient := getTestRouteTableClient(armClient)
-	result, rerr := routetableClient.Get(context.TODO(), "rg", "rt1", "")
-	assert.Empty(t, result)
-	assert.Equal(t, throttleErr, rerr)
-}
-
-func TestCreateOrUpdate(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	rt1 := getTestRouteTable("rt1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	response := &http.Response{
-		StatusCode: http.StatusOK,
-		Body:       io.NopCloser(bytes.NewReader([]byte(""))),
-	}
-	armClient.EXPECT().PutResource(gomock.Any(), ptr.Deref(rt1.ID, ""), rt1, gomock.Any()).Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	rtClient := getTestRouteTableClient(armClient)
-	rerr := rtClient.CreateOrUpdate(context.TODO(), "rg", "rt1", rt1, "*")
-	assert.Nil(t, rerr)
-}
-
-func TestCreateOrUpdateWithNeverRateLimiter(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	rcCreateOrUpdateErr := retry.GetRateLimitError(true, "RouteTableCreateOrUpdate")
-
-	rt1 := getTestRouteTable("rt1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	routetableClient := getTestRouteTableClientWithNeverRateLimiter(armClient)
-	rerr := routetableClient.CreateOrUpdate(context.TODO(), "rg", "rt1", rt1, "")
-	assert.Equal(t, rcCreateOrUpdateErr, rerr)
-}
-
-func TestCreateOrUpdateRetryAfterReader(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	rcCreateOrUpdateErr := retry.GetThrottlingError("RouteTableCreateOrUpdate", "client throttled", getFutureTime())
-
-	rt1 := getTestRouteTable("rt1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	routetableClient := getTestRouteTableClientWithRetryAfterReader(armClient)
-	rerr := routetableClient.CreateOrUpdate(context.TODO(), "rg", "rt1", rt1, "")
-	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),
-	}
-
-	rt1 := getTestRouteTable("rt1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().PutResource(gomock.Any(), ptr.Deref(rt1.ID, ""), rt1, gomock.Any()).Return(response, throttleErr).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	routetableClient := getTestRouteTableClient(armClient)
-	rerr := routetableClient.CreateOrUpdate(context.TODO(), "rg", "rt1", rt1, "")
-	assert.Equal(t, throttleErr, rerr)
-}
-
-func TestCreateOrUpdateWithCreateOrUpdateResponderError(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	rt1 := getTestRouteTable("rt1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	response := &http.Response{
-		StatusCode: http.StatusNotFound,
-		Body:       io.NopCloser(bytes.NewReader([]byte(""))),
-	}
-
-	armClient.EXPECT().PutResource(gomock.Any(), ptr.Deref(rt1.ID, ""), rt1, gomock.Any()).Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	routetableClient := getTestRouteTableClient(armClient)
-	rerr := routetableClient.CreateOrUpdate(context.TODO(), "rg", "rt1", rt1, "")
-	assert.NotNil(t, rerr)
-}
-
-func getTestRouteTable(name string) network.RouteTable {
-	return network.RouteTable{
-		ID:       ptr.To(fmt.Sprintf("/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Network/routeTables/%s", name)),
-		Name:     ptr.To(name),
-		Location: ptr.To("eastus"),
-	}
-}
-
-func getTestRouteTableClient(armClient armclient.Interface) *Client {
-	rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(&azclients.RateLimitConfig{})
-	return &Client{
-		armClient:         armClient,
-		subscriptionID:    "subscriptionID",
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-	}
-}
-
-func getTestRouteTableClientWithNeverRateLimiter(armClient armclient.Interface) *Client {
-	rateLimiterReader := flowcontrol.NewFakeNeverRateLimiter()
-	rateLimiterWriter := flowcontrol.NewFakeNeverRateLimiter()
-	return &Client{
-		armClient:         armClient,
-		subscriptionID:    "subscriptionID",
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-	}
-}
-
-func getTestRouteTableClientWithRetryAfterReader(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/provider/azure_routes_test.go b/pkg/provider/azure_routes_test.go
index b95165892..719dff4f1 100644
--- a/pkg/provider/azure_routes_test.go
+++ b/pkg/provider/azure_routes_test.go
@@ -18,13 +18,13 @@ package provider
 
 import (
 	"context"
+	"errors"
 	"fmt"
-	"net/http"
 	"reflect"
 	"testing"
 	"time"
 
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
+	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
 	"github.com/stretchr/testify/assert"
 	"go.uber.org/mock/gomock"
 
@@ -32,18 +32,18 @@ import (
 	cloudprovider "k8s.io/cloud-provider"
 	"k8s.io/utils/ptr"
 
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/routetableclient/mockroutetableclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/routetable"
 	utilsets "sigs.k8s.io/cloud-provider-azure/pkg/util/sets"
 )
 
 func TestDeleteRoute(t *testing.T) {
+	t.Parallel()
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
-	routeTableClient := mockroutetableclient.NewMockInterface(ctrl)
 
+	mockRTRepo := routetable.NewMockRepository(ctrl)
 	cloud := &Cloud{
-		RouteTablesClient: routeTableClient,
+		routeTableRepo: mockRTRepo,
 		Config: Config{
 			RouteTableResourceGroup: "foo",
 			RouteTableName:          "bar",
@@ -52,8 +52,6 @@ func TestDeleteRoute(t *testing.T) {
 		unmanagedNodes:     utilsets.NewString(),
 		nodeInformerSynced: func() bool { return true },
 	}
-	cache, _ := cloud.newRouteTableCache()
-	cloud.rtCache = cache
 	cloud.routeUpdater = newDelayedRouteUpdater(cloud, 100*time.Millisecond)
 	go cloud.routeUpdater.run(context.Background())
 	route := cloudprovider.Route{
@@ -61,26 +59,33 @@ func TestDeleteRoute(t *testing.T) {
 		DestinationCIDR: "1.2.3.4/24",
 	}
 	routeName := mapNodeNameToRouteName(false, route.TargetNode, route.DestinationCIDR)
-	routeTables := network.RouteTable{
+	routeTables := &armnetwork.RouteTable{
 		Name:     &cloud.RouteTableName,
 		Location: &cloud.Location,
-		RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-			Routes: &[]network.Route{
+		Properties: &armnetwork.RouteTablePropertiesFormat{
+			Routes: []*armnetwork.Route{
 				{
 					Name: &routeName,
 				},
 			},
 		},
 	}
-	routeTablesAfterDeletion := network.RouteTable{
+	routeTablesAfterDeletion := armnetwork.RouteTable{
 		Name:     &cloud.RouteTableName,
 		Location: &cloud.Location,
-		RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-			Routes: &[]network.Route{},
+		Properties: &armnetwork.RouteTablePropertiesFormat{
+			Routes: []*armnetwork.Route{},
 		},
 	}
-	routeTableClient.EXPECT().Get(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, "").Return(routeTables, nil).AnyTimes()
-	routeTableClient.EXPECT().CreateOrUpdate(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, routeTablesAfterDeletion, "").Return(nil)
+
+	mockRTRepo.EXPECT().Get(gomock.Any(), cloud.RouteTableName, gomock.Any()).Return(routeTables, nil).AnyTimes()
+	mockRTRepo.EXPECT().CreateOrUpdate(gomock.Any(), gomock.Any()).DoAndReturn(
+		func(_ context.Context, routeTable armnetwork.RouteTable) (*armnetwork.RouteTable, error) {
+			assert.Equal(t, routeTablesAfterDeletion, routeTable)
+			return nil, nil
+		},
+	).AnyTimes()
+
 	err := cloud.DeleteRoute(context.TODO(), "cluster", &route)
 	if err != nil {
 		t.Errorf("unexpected error deleting route: %v", err)
@@ -110,12 +115,13 @@ func TestDeleteRoute(t *testing.T) {
 }
 
 func TestDeleteRouteDualStack(t *testing.T) {
+	t.Parallel()
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
-	routeTableClient := mockroutetableclient.NewMockInterface(ctrl)
 
+	mockRTRepo := routetable.NewMockRepository(ctrl)
 	cloud := &Cloud{
-		RouteTablesClient: routeTableClient,
+		routeTableRepo: mockRTRepo,
 		Config: Config{
 			RouteTableResourceGroup: "foo",
 			RouteTableName:          "bar",
@@ -125,8 +131,6 @@ func TestDeleteRouteDualStack(t *testing.T) {
 		nodeInformerSynced:   func() bool { return true },
 		ipv6DualStackEnabled: true,
 	}
-	cache, _ := cloud.newRouteTableCache()
-	cloud.rtCache = cache
 	cloud.routeUpdater = newDelayedRouteUpdater(cloud, 100*time.Millisecond)
 	go cloud.routeUpdater.run(context.Background())
 
@@ -136,11 +140,11 @@ func TestDeleteRouteDualStack(t *testing.T) {
 	}
 	routeName := mapNodeNameToRouteName(true, route.TargetNode, route.DestinationCIDR)
 	routeNameIPV4 := mapNodeNameToRouteName(false, route.TargetNode, route.DestinationCIDR)
-	routeTables := network.RouteTable{
+	routeTables := &armnetwork.RouteTable{
 		Name:     &cloud.RouteTableName,
 		Location: &cloud.Location,
-		RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-			Routes: &[]network.Route{
+		Properties: &armnetwork.RouteTablePropertiesFormat{
+			Routes: []*armnetwork.Route{
 				{
 					Name: &routeName,
 				},
@@ -150,28 +154,38 @@ func TestDeleteRouteDualStack(t *testing.T) {
 			},
 		},
 	}
-	routeTablesAfterFirstDeletion := network.RouteTable{
+	routeTablesAfterFirstDeletion := armnetwork.RouteTable{
 		Name:     &cloud.RouteTableName,
 		Location: &cloud.Location,
-		RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-			Routes: &[]network.Route{
+		Properties: &armnetwork.RouteTablePropertiesFormat{
+			Routes: []*armnetwork.Route{
 				{
 					Name: &routeNameIPV4,
 				},
 			},
 		},
 	}
-	routeTablesAfterSecondDeletion := network.RouteTable{
+	routeTablesAfterSecondDeletion := armnetwork.RouteTable{
 		Name:     &cloud.RouteTableName,
 		Location: &cloud.Location,
-		RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-			Routes: &[]network.Route{},
+		Properties: &armnetwork.RouteTablePropertiesFormat{
+			Routes: []*armnetwork.Route{},
 		},
 	}
-	routeTableClient.EXPECT().Get(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, "").Return(routeTables, nil)
-	routeTableClient.EXPECT().Get(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, "").Return(routeTablesAfterFirstDeletion, nil)
-	routeTableClient.EXPECT().CreateOrUpdate(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, routeTablesAfterFirstDeletion, "").Return(nil)
-	routeTableClient.EXPECT().CreateOrUpdate(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, routeTablesAfterSecondDeletion, "").Return(nil)
+	mockRTRepo.EXPECT().Get(gomock.Any(), cloud.RouteTableName, gomock.Any()).Return(routeTables, nil)
+	mockRTRepo.EXPECT().Get(gomock.Any(), cloud.RouteTableName, gomock.Any()).Return(&routeTablesAfterFirstDeletion, nil)
+	mockRTRepo.EXPECT().CreateOrUpdate(gomock.Any(), gomock.Any()).DoAndReturn(
+		func(_ context.Context, routeTable armnetwork.RouteTable) (*armnetwork.RouteTable, error) {
+			assert.Equal(t, routeTablesAfterFirstDeletion, routeTable)
+			return nil, nil
+		},
+	)
+	mockRTRepo.EXPECT().CreateOrUpdate(gomock.Any(), gomock.Any()).DoAndReturn(
+		func(_ context.Context, routeTable armnetwork.RouteTable) (*armnetwork.RouteTable, error) {
+			assert.Equal(t, routeTablesAfterSecondDeletion, routeTable)
+			return nil, nil
+		},
+	)
 	err := cloud.DeleteRoute(context.TODO(), "cluster", &route)
 	if err != nil {
 		t.Errorf("unexpected error deleting route: %v", err)
@@ -181,45 +195,28 @@ func TestDeleteRouteDualStack(t *testing.T) {
 }
 
 func TestCreateRoute(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-	routeTableClient := mockroutetableclient.NewMockInterface(ctrl)
-	mockVMSet := NewMockVMSet(ctrl)
-
-	cloud := &Cloud{
-		RouteTablesClient: routeTableClient,
-		VMSet:             mockVMSet,
-		Config: Config{
-			RouteTableResourceGroup: "foo",
-			RouteTableName:          "bar",
-			Location:                "location",
-		},
-		unmanagedNodes:     utilsets.NewString(),
-		nodeInformerSynced: func() bool { return true },
-	}
-	cache, _ := cloud.newRouteTableCache()
-	cloud.rtCache = cache
-	cloud.routeUpdater = newDelayedRouteUpdater(cloud, 100*time.Millisecond)
-	go cloud.routeUpdater.run(context.Background())
+	t.Parallel()
 
-	route := cloudprovider.Route{TargetNode: "node", DestinationCIDR: "1.2.3.4/24"}
 	nodePrivateIP := "2.4.6.8"
-	networkRoute := &[]network.Route{
-		{
-			Name: ptr.To("node"),
-			RoutePropertiesFormat: &network.RoutePropertiesFormat{
-				AddressPrefix:    ptr.To("1.2.3.4/24"),
-				NextHopIPAddress: &nodePrivateIP,
-				NextHopType:      network.RouteNextHopTypeVirtualAppliance,
+
+	defaultNetworkRoute := func() []*armnetwork.Route {
+		return []*armnetwork.Route{
+			{
+				Name: ptr.To("node"),
+				Properties: &armnetwork.RoutePropertiesFormat{
+					AddressPrefix:    ptr.To("1.2.3.4/24"),
+					NextHopIPAddress: &nodePrivateIP,
+					NextHopType:      ptr.To(armnetwork.RouteNextHopTypeVirtualAppliance),
+				},
 			},
-		},
+		}
 	}
 
-	testCases := []struct {
+	tests := []struct {
 		name                  string
 		routeTableName        string
-		initialRoute          *[]network.Route
-		updatedRoute          *[]network.Route
+		initialRoute          []*armnetwork.Route
+		updatedRoute          []*armnetwork.Route
 		hasUnmanagedNodes     bool
 		nodeInformerNotSynced bool
 		ipv6DualStackEnabled  bool
@@ -229,71 +226,49 @@ func TestCreateRoute(t *testing.T) {
 		expectedRouteCIDRs    map[string]string
 
 		getIPError        error
-		getErr            *retry.Error
-		secondGetErr      *retry.Error
-		createOrUpdateErr *retry.Error
+		firstGetNotFound  bool // FIXME: it's very confusing; should refactor the whole test
+		getErr            error
+		secondGetErr      error
+		createOrUpdateErr error
 		expectedErrMsg    error
 	}{
-		{
-			name:           "CreateRoute should report an error if route table name is not configured",
-			routeTableName: "",
-			expectedErrMsg: fmt.Errorf("route table name is not configured"),
-		},
 		{
 			name:           "CreateRoute should create route if route doesn't exist",
 			routeTableName: "rt1",
-			updatedRoute:   networkRoute,
+			updatedRoute:   defaultNetworkRoute(),
 		},
 		{
-			name:           "CreateRoute should report error if error occurs when invoke CreateOrUpdateRouteTable",
-			routeTableName: "rt2",
-			updatedRoute:   networkRoute,
-			createOrUpdateErr: &retry.Error{
-				HTTPStatusCode: http.StatusInternalServerError,
-				RawError:       fmt.Errorf("CreateOrUpdate error"),
-			},
-			expectedErrMsg: fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 500, RawError: CreateOrUpdate error"),
+			name:              "CreateRoute should report error if error occurs when invoke CreateOrUpdateRouteTable",
+			routeTableName:    "rt2",
+			updatedRoute:      defaultNetworkRoute(),
+			createOrUpdateErr: errors.New("dummy"),
+			expectedErrMsg:    errors.New("dummy"),
 		},
 		{
 			name:           "CreateRoute should do nothing if route already exists",
 			routeTableName: "rt3",
-			initialRoute:   networkRoute,
-			updatedRoute:   networkRoute,
+			initialRoute:   defaultNetworkRoute(),
+			updatedRoute:   defaultNetworkRoute(),
 		},
 		{
-			name:           "CreateRoute should report error if error occurs when invoke createRouteTable",
-			routeTableName: "rt4",
-			getErr: &retry.Error{
-				HTTPStatusCode: http.StatusNotFound,
-				RawError:       cloudprovider.InstanceNotFound,
-			},
-			createOrUpdateErr: &retry.Error{
-				HTTPStatusCode: http.StatusInternalServerError,
-				RawError:       fmt.Errorf("CreateOrUpdate error"),
-			},
-			expectedErrMsg: fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 500, RawError: CreateOrUpdate error"),
+			name:              "CreateRoute should report error if error occurs when invoke createRouteTable",
+			routeTableName:    "rt4",
+			firstGetNotFound:  true,
+			createOrUpdateErr: errors.New("create or update dummy"),
+			expectedErrMsg:    errors.New("create or update dummy"),
 		},
 		{
-			name:           "CreateRoute should report error if error occurs when invoke getRouteTable for the second time",
-			routeTableName: "rt5",
-			getErr: &retry.Error{
-				HTTPStatusCode: http.StatusNotFound,
-				RawError:       cloudprovider.InstanceNotFound,
-			},
-			secondGetErr: &retry.Error{
-				HTTPStatusCode: http.StatusInternalServerError,
-				RawError:       fmt.Errorf("Get error"),
-			},
-			expectedErrMsg: fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 500, RawError: Get error"),
+			name:             "CreateRoute should report error if error occurs when invoke getRouteTable for the second time",
+			routeTableName:   "rt5",
+			firstGetNotFound: true,
+			secondGetErr:     errors.New("second get dummy"),
+			expectedErrMsg:   errors.New("second get dummy"),
 		},
 		{
 			name:           "CreateRoute should report error if error occurs when invoke routeTableClient.Get",
 			routeTableName: "rt6",
-			getErr: &retry.Error{
-				HTTPStatusCode: http.StatusInternalServerError,
-				RawError:       fmt.Errorf("Get error"),
-			},
-			expectedErrMsg: fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 500, RawError: Get error"),
+			getErr:         errors.New("first get dummy"),
+			expectedErrMsg: errors.New("first get dummy"),
 		},
 		{
 			name:           "CreateRoute should report error if error occurs when invoke GetIPByNodeName",
@@ -312,13 +287,13 @@ func TestCreateRoute(t *testing.T) {
 		{
 			name:           "CreateRoute should create route if cloud.ipv6DualStackEnabled is true and route doesn't exist",
 			routeTableName: "rt9",
-			updatedRoute: &[]network.Route{
+			updatedRoute: []*armnetwork.Route{
 				{
 					Name: ptr.To("node____123424"),
-					RoutePropertiesFormat: &network.RoutePropertiesFormat{
+					Properties: &armnetwork.RoutePropertiesFormat{
 						AddressPrefix:    ptr.To("1.2.3.4/24"),
 						NextHopIPAddress: &nodePrivateIP,
-						NextHopType:      network.RouteNextHopTypeVirtualAppliance,
+						NextHopType:      ptr.To(armnetwork.RouteNextHopTypeVirtualAppliance),
 					},
 				},
 			},
@@ -331,76 +306,111 @@ func TestCreateRoute(t *testing.T) {
 		},
 	}
 
-	for _, test := range testCases {
-		initialTable := network.RouteTable{
-			Name:     ptr.To(test.routeTableName),
-			Location: &cloud.Location,
-			RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-				Routes: test.initialRoute,
-			},
-		}
-		updatedTable := network.RouteTable{
-			Name:     ptr.To(test.routeTableName),
-			Location: &cloud.Location,
-			RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-				Routes: test.updatedRoute,
-			},
-		}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			t.Parallel()
 
-		cloud.RouteTableName = test.routeTableName
-		cloud.ipv6DualStackEnabled = test.ipv6DualStackEnabled
-		if test.hasUnmanagedNodes {
-			cloud.unmanagedNodes.Insert(test.unmanagedNodeName)
-			cloud.routeCIDRs = test.routeCIDRs
-		} else {
-			cloud.unmanagedNodes = utilsets.NewString()
-			cloud.routeCIDRs = nil
-		}
-		if test.nodeInformerNotSynced {
-			cloud.nodeInformerSynced = func() bool { return false }
-		} else {
-			cloud.nodeInformerSynced = func() bool { return true }
-		}
+			ctrl := gomock.NewController(t)
+			defer ctrl.Finish()
+			mockVMSet := NewMockVMSet(ctrl)
 
-		mockVMSet.EXPECT().GetIPByNodeName(gomock.Any(), gomock.Any()).Return(nodePrivateIP, "", test.getIPError).MaxTimes(1)
-		mockVMSet.EXPECT().GetPrivateIPsByNodeName(gomock.Any(), "node").Return([]string{nodePrivateIP, "10.10.10.10"}, nil).MaxTimes(1)
-		routeTableClient.EXPECT().Get(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, "").Return(initialTable, test.getErr).MaxTimes(1)
-		routeTableClient.EXPECT().CreateOrUpdate(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, updatedTable, "").Return(test.createOrUpdateErr).MaxTimes(1)
+			mockRTRepo := routetable.NewMockRepository(ctrl)
+			cloud := &Cloud{
+				routeTableRepo: mockRTRepo,
+				VMSet:          mockVMSet,
+				Config: Config{
+					RouteTableResourceGroup: "foo",
+					RouteTableName:          "bar",
+					Location:                "location",
+				},
+				unmanagedNodes:     utilsets.NewString(),
+				nodeInformerSynced: func() bool { return true },
+			}
+			cloud.routeUpdater = newDelayedRouteUpdater(cloud, 100*time.Millisecond)
+			go cloud.routeUpdater.run(context.Background())
 
-		//Here is the second invocation when route table doesn't exist
-		routeTableClient.EXPECT().Get(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, "").Return(initialTable, test.secondGetErr).MaxTimes(1)
+			initialTable := &armnetwork.RouteTable{
+				Name:     ptr.To(tt.routeTableName),
+				Location: &cloud.Location,
+				Properties: &armnetwork.RouteTablePropertiesFormat{
+					Routes: tt.initialRoute,
+				},
+			}
+			updatedTable := armnetwork.RouteTable{
+				Name:     ptr.To(tt.routeTableName),
+				Location: &cloud.Location,
+				Properties: &armnetwork.RouteTablePropertiesFormat{
+					Routes: tt.updatedRoute,
+				},
+			}
 
-		err := cloud.CreateRoute(context.TODO(), "cluster", "unused", &route)
-		assert.Equal(t, cloud.routeCIDRs, test.expectedRouteCIDRs, test.name)
-		if err != nil {
-			assert.EqualError(t, test.expectedErrMsg, err.Error(), test.name)
-		}
+			cloud.RouteTableName = tt.routeTableName
+			cloud.ipv6DualStackEnabled = tt.ipv6DualStackEnabled
+			if tt.hasUnmanagedNodes {
+				cloud.unmanagedNodes.Insert(tt.unmanagedNodeName)
+				cloud.routeCIDRs = tt.routeCIDRs
+			} else {
+				cloud.unmanagedNodes = utilsets.NewString()
+				cloud.routeCIDRs = nil
+			}
+			if tt.nodeInformerNotSynced {
+				cloud.nodeInformerSynced = func() bool { return false }
+			} else {
+				cloud.nodeInformerSynced = func() bool { return true }
+			}
+
+			mockVMSet.EXPECT().GetIPByNodeName(gomock.Any(), gomock.Any()).Return(nodePrivateIP, "", tt.getIPError).MaxTimes(1)
+			mockVMSet.EXPECT().GetPrivateIPsByNodeName(gomock.Any(), "node").Return([]string{nodePrivateIP, "10.10.10.10"}, nil).MaxTimes(1)
+			if tt.firstGetNotFound {
+				mockRTRepo.EXPECT().Get(gomock.Any(), cloud.RouteTableName, gomock.Any()).Return(nil, nil).MaxTimes(1)
+			} else {
+				mockRTRepo.EXPECT().Get(gomock.Any(), cloud.RouteTableName, gomock.Any()).Return(initialTable, tt.getErr).MaxTimes(1)
+			}
+
+			mockRTRepo.EXPECT().CreateOrUpdate(gomock.Any(), gomock.Any()).DoAndReturn(
+				func(_ context.Context, routeTable armnetwork.RouteTable) (*armnetwork.RouteTable, error) {
+					assert.Equal(t, updatedTable, routeTable)
+					return nil, tt.createOrUpdateErr
+				},
+			).MaxTimes(1)
+
+			//Here is the second invocation when route table doesn't exist
+			mockRTRepo.EXPECT().Get(gomock.Any(), cloud.RouteTableName, gomock.Any()).Return(initialTable, tt.secondGetErr).MaxTimes(1)
+
+			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+			defer cancel()
+			route := cloudprovider.Route{TargetNode: "node", DestinationCIDR: "1.2.3.4/24"}
+			err := cloud.CreateRoute(ctx, "cluster", "unused", &route)
+			assert.Equal(t, cloud.routeCIDRs, tt.expectedRouteCIDRs, tt.name)
+			if err != nil {
+				assert.EqualError(t, tt.expectedErrMsg, err.Error(), tt.name)
+			}
+		})
 	}
 }
 
 func TestCreateRouteTable(t *testing.T) {
+	t.Parallel()
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
-	routeTableClient := mockroutetableclient.NewMockInterface(ctrl)
 
+	mockRTRepo := routetable.NewMockRepository(ctrl)
 	cloud := &Cloud{
-		RouteTablesClient: routeTableClient,
+		routeTableRepo: mockRTRepo,
 		Config: Config{
 			RouteTableResourceGroup: "foo",
 			RouteTableName:          "bar",
 			Location:                "location",
 		},
 	}
-	cache, _ := cloud.newRouteTableCache()
-	cloud.rtCache = cache
 
-	expectedTable := network.RouteTable{
-		Name:                       &cloud.RouteTableName,
-		Location:                   &cloud.Location,
-		RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{},
+	expectedTable := armnetwork.RouteTable{
+		Name:       &cloud.RouteTableName,
+		Location:   &cloud.Location,
+		Properties: &armnetwork.RouteTablePropertiesFormat{},
 	}
-	routeTableClient.EXPECT().CreateOrUpdate(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, expectedTable, "").Return(nil)
-	err := cloud.createRouteTable()
+	mockRTRepo.EXPECT().CreateOrUpdate(gomock.Any(), expectedTable).Return(nil, nil)
+	err := cloud.createRouteTable(context.Background())
 	if err != nil {
 		t.Errorf("unexpected error in creating route table: %v", err)
 		t.FailNow()
@@ -409,9 +419,8 @@ func TestCreateRouteTable(t *testing.T) {
 
 func TestProcessRoutes(t *testing.T) {
 	tests := []struct {
-		rt            network.RouteTable
+		rt            *armnetwork.RouteTable
 		expectedRoute []cloudprovider.Route
-		exists        bool
 		expectErr     bool
 		name          string
 		expectedError string
@@ -423,35 +432,31 @@ func TestProcessRoutes(t *testing.T) {
 			expectedError: "test error",
 		},
 		{
-			exists: false,
-			name:   "doesn't exist",
+			name: "doesn't exist",
 		},
 		{
-			rt:     network.RouteTable{},
-			exists: true,
-			name:   "nil routes",
+			rt:   &armnetwork.RouteTable{},
+			name: "nil routes",
 		},
 		{
-			rt: network.RouteTable{
-				RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{},
+			rt: &armnetwork.RouteTable{
+				Properties: &armnetwork.RouteTablePropertiesFormat{},
 			},
-			exists: true,
-			name:   "no routes",
+			name: "no routes",
 		},
 		{
-			rt: network.RouteTable{
-				RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-					Routes: &[]network.Route{
+			rt: &armnetwork.RouteTable{
+				Properties: &armnetwork.RouteTablePropertiesFormat{
+					Routes: []*armnetwork.Route{
 						{
 							Name: ptr.To("name"),
-							RoutePropertiesFormat: &network.RoutePropertiesFormat{
+							Properties: &armnetwork.RoutePropertiesFormat{
 								AddressPrefix: ptr.To("1.2.3.4/16"),
 							},
 						},
 					},
 				},
 			},
-			exists: true,
 			expectedRoute: []cloudprovider.Route{
 				{
 					Name:            "name",
@@ -462,25 +467,24 @@ func TestProcessRoutes(t *testing.T) {
 			name: "one route",
 		},
 		{
-			rt: network.RouteTable{
-				RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-					Routes: &[]network.Route{
+			rt: &armnetwork.RouteTable{
+				Properties: &armnetwork.RouteTablePropertiesFormat{
+					Routes: []*armnetwork.Route{
 						{
 							Name: ptr.To("name"),
-							RoutePropertiesFormat: &network.RoutePropertiesFormat{
+							Properties: &armnetwork.RoutePropertiesFormat{
 								AddressPrefix: ptr.To("1.2.3.4/16"),
 							},
 						},
 						{
 							Name: ptr.To("name2"),
-							RoutePropertiesFormat: &network.RoutePropertiesFormat{
+							Properties: &armnetwork.RoutePropertiesFormat{
 								AddressPrefix: ptr.To("5.6.7.8/16"),
 							},
 						},
 					},
 				},
 			},
-			exists: true,
 			expectedRoute: []cloudprovider.Route{
 				{
 					Name:            "name",
@@ -497,7 +501,7 @@ func TestProcessRoutes(t *testing.T) {
 		},
 	}
 	for _, test := range tests {
-		routes, err := processRoutes(false, test.rt, test.exists, test.err)
+		routes, err := processRoutes(false, test.rt, test.err)
 		if test.expectErr {
 			if err == nil {
 				t.Errorf("%s: unexpected non-error", test.name)
@@ -590,12 +594,12 @@ func TestRouteNameFuncs(t *testing.T) {
 func TestListRoutes(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
-	routeTableClient := mockroutetableclient.NewMockInterface(ctrl)
 	mockVMSet := NewMockVMSet(ctrl)
 
+	mockRTRepo := routetable.NewMockRepository(ctrl)
 	cloud := &Cloud{
-		RouteTablesClient: routeTableClient,
-		VMSet:             mockVMSet,
+		routeTableRepo: mockRTRepo,
+		VMSet:          mockVMSet,
 		Config: Config{
 			RouteTableResourceGroup: "foo",
 			RouteTableName:          "bar",
@@ -604,34 +608,32 @@ func TestListRoutes(t *testing.T) {
 		unmanagedNodes:     utilsets.NewString(),
 		nodeInformerSynced: func() bool { return true },
 	}
-	cache, _ := cloud.newRouteTableCache()
-	cloud.rtCache = cache
 	cloud.routeUpdater = newDelayedRouteUpdater(cloud, 100*time.Millisecond)
 	go cloud.routeUpdater.run(context.Background())
 
 	testCases := []struct {
 		name                  string
 		routeTableName        string
-		routeTable            network.RouteTable
+		routeTable            *armnetwork.RouteTable
 		hasUnmanagedNodes     bool
 		nodeInformerNotSynced bool
 		unmanagedNodeName     string
 		routeCIDRs            map[string]string
 		expectedRoutes        []*cloudprovider.Route
-		getErr                *retry.Error
+		getErr                error
 		expectedErrMsg        error
 	}{
 		{
 			name:           "ListRoutes should return correct routes",
 			routeTableName: "rt1",
-			routeTable: network.RouteTable{
+			routeTable: &armnetwork.RouteTable{
 				Name:     ptr.To("rt1"),
 				Location: &cloud.Location,
-				RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-					Routes: &[]network.Route{
+				Properties: &armnetwork.RouteTablePropertiesFormat{
+					Routes: []*armnetwork.Route{
 						{
 							Name: ptr.To("node"),
-							RoutePropertiesFormat: &network.RoutePropertiesFormat{
+							Properties: &armnetwork.RoutePropertiesFormat{
 								AddressPrefix: ptr.To("1.2.3.4/24"),
 							},
 						},
@@ -652,14 +654,14 @@ func TestListRoutes(t *testing.T) {
 			hasUnmanagedNodes: true,
 			unmanagedNodeName: "unmanaged-node",
 			routeCIDRs:        map[string]string{"unmanaged-node": "2.2.3.4/24"},
-			routeTable: network.RouteTable{
+			routeTable: &armnetwork.RouteTable{
 				Name:     ptr.To("rt2"),
 				Location: &cloud.Location,
-				RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-					Routes: &[]network.Route{
+				Properties: &armnetwork.RouteTablePropertiesFormat{
+					Routes: []*armnetwork.Route{
 						{
 							Name: ptr.To("node"),
-							RoutePropertiesFormat: &network.RoutePropertiesFormat{
+							Properties: &armnetwork.RoutePropertiesFormat{
 								AddressPrefix: ptr.To("1.2.3.4/24"),
 							},
 						},
@@ -682,28 +684,22 @@ func TestListRoutes(t *testing.T) {
 		{
 			name:           "ListRoutes should return nil if routeTable don't exist",
 			routeTableName: "rt3",
-			routeTable:     network.RouteTable{},
-			getErr: &retry.Error{
-				HTTPStatusCode: http.StatusNotFound,
-				RawError:       cloudprovider.InstanceNotFound,
-			},
+			routeTable:     &armnetwork.RouteTable{},
+			getErr:         errors.New("dummy"),
 			expectedRoutes: []*cloudprovider.Route{},
 		},
 		{
 			name:           "ListRoutes should report error if error occurs when invoke routeTableClient.Get",
 			routeTableName: "rt4",
-			routeTable:     network.RouteTable{},
-			getErr: &retry.Error{
-				HTTPStatusCode: http.StatusInternalServerError,
-				RawError:       fmt.Errorf("Get error"),
-			},
-			expectedErrMsg: fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 500, RawError: Get error"),
+			routeTable:     &armnetwork.RouteTable{},
+			getErr:         errors.New("dummy"),
+			expectedErrMsg: errors.New("dummy"),
 		},
 		{
 			name:                  "ListRoutes should report error if node informer is not synced",
 			routeTableName:        "rt5",
 			nodeInformerNotSynced: true,
-			routeTable:            network.RouteTable{},
+			routeTable:            &armnetwork.RouteTable{},
 			expectedErrMsg:        fmt.Errorf("node informer is not synced when trying to GetUnmanagedNodes"),
 		},
 	}
@@ -724,11 +720,16 @@ func TestListRoutes(t *testing.T) {
 		}
 
 		cloud.RouteTableName = test.routeTableName
-		routeTableClient.EXPECT().Get(gomock.Any(), cloud.RouteTableResourceGroup, test.routeTableName, "").Return(test.routeTable, test.getErr)
+		mockRTRepo.EXPECT().Get(gomock.Any(), test.routeTableName, gomock.Any()).Return(test.routeTable, test.getErr)
 
 		routes, err := cloud.ListRoutes(context.TODO(), "cluster")
-		assert.Equal(t, test.expectedRoutes, routes, test.name)
+		if len(test.expectedRoutes) == 0 {
+			assert.Empty(t, routes, test.name)
+		} else {
+			assert.Equal(t, test.expectedRoutes, routes, test.name)
+		}
 		if test.expectedErrMsg != nil {
+			assert.Error(t, err)
 			assert.EqualError(t, test.expectedErrMsg, err.Error(), test.name)
 		}
 	}
@@ -740,17 +741,17 @@ func TestCleanupOutdatedRoutes(t *testing.T) {
 
 	for _, testCase := range []struct {
 		description                          string
-		existingRoutes, expectedRoutes       []network.Route
+		existingRoutes, expectedRoutes       []*armnetwork.Route
 		existingNodeNames                    *utilsets.IgnoreCaseSet
 		expectedChanged, enableIPV6DualStack bool
 	}{
 		{
 			description: "cleanupOutdatedRoutes should delete outdated non-dualstack routes when dualstack is enabled",
-			existingRoutes: []network.Route{
+			existingRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000____xxx")},
 				{Name: ptr.To("aks-node1-vmss000000")},
 			},
-			expectedRoutes: []network.Route{
+			expectedRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000____xxx")},
 			},
 			existingNodeNames:   utilsets.NewString("aks-node1-vmss000000"),
@@ -759,11 +760,11 @@ func TestCleanupOutdatedRoutes(t *testing.T) {
 		},
 		{
 			description: "cleanupOutdatedRoutes should delete outdated dualstack routes when dualstack is disabled",
-			existingRoutes: []network.Route{
+			existingRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000____xxx")},
 				{Name: ptr.To("aks-node1-vmss000000")},
 			},
-			expectedRoutes: []network.Route{
+			expectedRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000")},
 			},
 			existingNodeNames: utilsets.NewString("aks-node1-vmss000000"),
@@ -771,11 +772,11 @@ func TestCleanupOutdatedRoutes(t *testing.T) {
 		},
 		{
 			description: "cleanupOutdatedRoutes should not delete unmanaged routes when dualstack is enabled",
-			existingRoutes: []network.Route{
+			existingRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000____xxx")},
 				{Name: ptr.To("aks-node1-vmss000000")},
 			},
-			expectedRoutes: []network.Route{
+			expectedRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000____xxx")},
 				{Name: ptr.To("aks-node1-vmss000000")},
 			},
@@ -784,11 +785,11 @@ func TestCleanupOutdatedRoutes(t *testing.T) {
 		},
 		{
 			description: "cleanupOutdatedRoutes should not delete unmanaged routes when dualstack is disabled",
-			existingRoutes: []network.Route{
+			existingRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000____xxx")},
 				{Name: ptr.To("aks-node1-vmss000000")},
 			},
-			expectedRoutes: []network.Route{
+			expectedRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000____xxx")},
 				{Name: ptr.To("aks-node1-vmss000000")},
 			},
@@ -823,13 +824,13 @@ func TestEnsureRouteTableTagged(t *testing.T) {
 		"a": ptr.To("b"),
 		"c": ptr.To("d"),
 	}
-	rt := &network.RouteTable{}
+	rt := &armnetwork.RouteTable{}
 	tags, changed := cloud.ensureRouteTableTagged(rt)
 	assert.Equal(t, expectedTags, tags)
 	assert.True(t, changed)
 
 	cloud.RouteTableResourceGroup = "rg1"
-	rt = &network.RouteTable{}
+	rt = &armnetwork.RouteTable{}
 	tags, changed = cloud.ensureRouteTableTagged(rt)
 	assert.Nil(t, tags)
 	assert.False(t, changed)
diff --git a/pkg/provider/azure_routetable_repo_test.go b/pkg/provider/azure_routetable_repo_test.go
deleted file mode 100644
index 68737a969..000000000
--- a/pkg/provider/azure_routetable_repo_test.go
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package provider
-
-import (
-	"context"
-	"fmt"
-	"net/http"
-	"testing"
-
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-	"github.com/stretchr/testify/assert"
-
-	"go.uber.org/mock/gomock"
-
-	"k8s.io/utils/ptr"
-
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/routetableclient/mockroutetableclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/cache"
-	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-func TestCreateOrUpdateRouteTable(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	tests := []struct {
-		clientErr   *retry.Error
-		expectedErr error
-	}{
-		{
-			clientErr:   &retry.Error{HTTPStatusCode: http.StatusPreconditionFailed},
-			expectedErr: fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 412, RawError: %w", error(nil)),
-		},
-		{
-			clientErr:   &retry.Error{RawError: fmt.Errorf(consts.OperationCanceledErrorMessage)},
-			expectedErr: fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 0, RawError: %w", fmt.Errorf("canceledandsupersededduetoanotheroperation")),
-		},
-	}
-
-	for _, test := range tests {
-		az := GetTestCloud(ctrl)
-		az.rtCache.Set("rt", "test")
-
-		mockRTClient := az.RouteTablesClient.(*mockroutetableclient.MockInterface)
-		mockRTClient.EXPECT().CreateOrUpdate(gomock.Any(), az.ResourceGroup, gomock.Any(), gomock.Any(), gomock.Any()).Return(test.clientErr)
-		mockRTClient.EXPECT().Get(gomock.Any(), az.ResourceGroup, "rt", gomock.Any()).Return(network.RouteTable{}, nil)
-
-		err := az.CreateOrUpdateRouteTable(network.RouteTable{
-			Name: ptr.To("rt"),
-			Etag: ptr.To("etag"),
-		})
-		assert.EqualError(t, test.expectedErr, err.Error())
-
-		// route table should be removed from cache if the etag is mismatch or the operation is canceled
-		shouldBeEmpty, err := az.rtCache.GetWithDeepCopy(context.TODO(), "rt", cache.CacheReadTypeDefault)
-		assert.NoError(t, err)
-		assert.Empty(t, shouldBeEmpty)
-	}
-}
diff --git a/pkg/provider/privatelinkservice/repo_test.go b/pkg/provider/privatelinkservice/repo_test.go
index b6b8bee9c..4d881f218 100644
--- a/pkg/provider/privatelinkservice/repo_test.go
+++ b/pkg/provider/privatelinkservice/repo_test.go
@@ -33,7 +33,9 @@ import (
 )
 
 func TestRepo_Get(t *testing.T) {
+	t.Parallel()
 	t.Run("refresh cache", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -69,6 +71,7 @@ func TestRepo_Get(t *testing.T) {
 	})
 
 	t.Run("refresh cache with not found", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -89,6 +92,7 @@ func TestRepo_Get(t *testing.T) {
 	})
 
 	t.Run("API error", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -112,7 +116,9 @@ func TestRepo_Get(t *testing.T) {
 }
 
 func TestRepo_CreateOrUpdate(t *testing.T) {
+	t.Parallel()
 	t.Run("create one", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -148,6 +154,7 @@ func TestRepo_CreateOrUpdate(t *testing.T) {
 	})
 
 	t.Run("create one with missing PLS name", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -165,6 +172,7 @@ func TestRepo_CreateOrUpdate(t *testing.T) {
 	})
 
 	t.Run("create one with missing LoadBalancerFrontendIPConfigurations", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -185,6 +193,7 @@ func TestRepo_CreateOrUpdate(t *testing.T) {
 	})
 
 	t.Run("should clear cache", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -242,7 +251,9 @@ func TestRepo_CreateOrUpdate(t *testing.T) {
 }
 
 func TestRepo_Delete(t *testing.T) {
+	t.Parallel()
 	t.Run("delete one", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -263,6 +274,7 @@ func TestRepo_Delete(t *testing.T) {
 	})
 
 	t.Run("API error", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -286,7 +298,9 @@ func TestRepo_Delete(t *testing.T) {
 }
 
 func TestRepo_DeletePEConnection(t *testing.T) {
+	t.Parallel()
 	t.Run("delete one", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -307,6 +321,7 @@ func TestRepo_DeletePEConnection(t *testing.T) {
 	})
 
 	t.Run("API error", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
diff --git a/pkg/provider/routetable/repo_test.go b/pkg/provider/routetable/repo_test.go
new file mode 100644
index 000000000..ac6fe1648
--- /dev/null
+++ b/pkg/provider/routetable/repo_test.go
@@ -0,0 +1,196 @@
+/*
+Copyright 2024 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 routetable
+
+import (
+	"context"
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
+	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
+	"github.com/stretchr/testify/assert"
+	"go.uber.org/mock/gomock"
+	"k8s.io/utils/ptr"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient/mock_routetableclient"
+	"sigs.k8s.io/cloud-provider-azure/pkg/cache"
+)
+
+func TestRepo_Get(t *testing.T) {
+	t.Parallel()
+
+	const ResourceGroup = "testing-rg"
+
+	t.Run("refresh cache", func(t *testing.T) {
+		t.Parallel()
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_routetableclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, ResourceGroup, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			RouteTableName = "route-table-name"
+		)
+
+		cli.EXPECT().Get(gomock.Any(), ResourceGroup, gomock.Any()).Return(&armnetwork.RouteTable{
+			Name: ptr.To(RouteTableName),
+		}, nil)
+
+		v, err := repo.Get(ctx, RouteTableName, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Equal(t, RouteTableName, *v.Name)
+
+		// cache hit
+		v, err = repo.Get(ctx, RouteTableName, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Equal(t, RouteTableName, *v.Name)
+	})
+
+	t.Run("refresh cache with not found", func(t *testing.T) {
+		t.Parallel()
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_routetableclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, ResourceGroup, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			RouteTableName = "route-table-name"
+		)
+
+		cli.EXPECT().Get(gomock.Any(), ResourceGroup, gomock.Any()).Return(nil, nil)
+
+		v, err := repo.Get(ctx, RouteTableName, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Nil(t, v)
+	})
+
+	t.Run("API error", func(t *testing.T) {
+		t.Parallel()
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_routetableclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, ResourceGroup, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			RouteTableName = "route-table-name"
+		)
+
+		expectedErr := fmt.Errorf("API error")
+		cli.EXPECT().Get(gomock.Any(), ResourceGroup, gomock.Any()).Return(nil, expectedErr)
+
+		_, err = repo.Get(ctx, RouteTableName, cache.CacheReadTypeDefault)
+		assert.Error(t, err)
+		assert.ErrorIs(t, err, expectedErr)
+	})
+}
+
+func TestRepo_CreateOrUpdate(t *testing.T) {
+	t.Parallel()
+
+	const ResourceGroup = "testing-rg"
+
+	t.Run("create one", func(t *testing.T) {
+		t.Parallel()
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_routetableclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, ResourceGroup, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			RouteTableName = "route-table-name"
+		)
+
+		cli.EXPECT().CreateOrUpdate(gomock.Any(), ResourceGroup, RouteTableName, armnetwork.RouteTable{
+			Name: to.Ptr(RouteTableName),
+		}).Return(&armnetwork.RouteTable{
+			Name: to.Ptr(RouteTableName),
+		}, nil).Times(1)
+
+		v, err := repo.CreateOrUpdate(ctx, armnetwork.RouteTable{
+			Name: to.Ptr(RouteTableName),
+		})
+		assert.NoError(t, err)
+		assert.Equal(t, RouteTableName, *v.Name)
+	})
+
+	t.Run("create one with missing RouteTable name", func(t *testing.T) {
+		t.Parallel()
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_routetableclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, ResourceGroup, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		_, err = repo.CreateOrUpdate(ctx, armnetwork.RouteTable{})
+		assert.Error(t, err)
+		assert.ErrorIs(t, err, ErrMissingRouteTableName)
+	})
+
+	t.Run("should clear cache", func(t *testing.T) {
+
+		t.Parallel()
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_routetableclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, ResourceGroup, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			RouteTableName = "route-table-name"
+		)
+
+		cli.EXPECT().Get(gomock.Any(), ResourceGroup, RouteTableName).Return(&armnetwork.RouteTable{
+			Name: to.Ptr(RouteTableName),
+		}, nil).Times(2)
+
+		cli.EXPECT().CreateOrUpdate(gomock.Any(), ResourceGroup, RouteTableName, armnetwork.RouteTable{
+			Name: to.Ptr(RouteTableName),
+		}).Return(&armnetwork.RouteTable{
+			Name: to.Ptr(RouteTableName),
+		}, nil).Times(1)
+
+		v, err := repo.Get(ctx, RouteTableName, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Equal(t, RouteTableName, *v.Name)
+
+		v, err = repo.CreateOrUpdate(ctx, armnetwork.RouteTable{
+			Name: to.Ptr(RouteTableName),
+		})
+		assert.NoError(t, err)
+		assert.Equal(t, RouteTableName, *v.Name)
+
+		v, err = repo.Get(ctx, RouteTableName, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Equal(t, RouteTableName, *v.Name)
+
+		v, err = repo.Get(ctx, RouteTableName, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Equal(t, RouteTableName, *v.Name)
+	})
+}