Repository: kubernetes-sigs/cloud-provider-azure
Pull request #7465 (2024-11-01 04:42:05)

build(deps): bump sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader from 0.1.1 to 0.1.3
Bumps [sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader](https://github.com/kubernetes-sigs/cloud-provider-azure) from 0.1.1 to 0.1.3.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/kubernetes-sigs/cloud-provider-azure/commit/1dbe13e1ca63380c384e7ddb89d9c52827ecf5fa"><code>1dbe13e</code></a> override default UserAgent header in sdk (<a href="https://redirect.github.com/kubernetes-sigs/cloud-provider-azure/issues/7301">#7301</a>)</li>
<li><a href="https://github.com/kubernetes-sigs/cloud-provider-azure/commit/3c18887bae5d9fef3bd3dad1b475d94c974bb36b"><code>3c18887</code></a> enable cross sub support for file/blob service client and update recordings (...</li>
<li><a href="https://github.com/kubernetes-sigs/cloud-provider-azure/commit/197921a0648181ac2097e0f36348d1faa7ce56e0"><code>197921a</code></a> build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azcore (<a href="https://redirect.github.com/kubernetes-sigs/cloud-provider-azure/issues/7365">#7365</a>)</li>
<li><a href="https://github.com/kubernetes-sigs/cloud-provider-azure/commit/77436ff053fa57271973a16dde94ba77a632aa62"><code>77436ff</code></a> build(deps): bump sigs.k8s.io/cloud-provider-azure/pkg/azclient (<a href="https://redirect.github.com/kubernetes-sigs/cloud-provider-azure/issues/7370">#7370</a>)</li>
<li><a href="https://github.com/kubernetes-sigs/cloud-provider-azure/commit/4729c906e0fcf3618865b9674ed5c3b5e33a1fc3"><code>4729c90</code></a> build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azcore (<a href="https://redirect.github.com/kubernetes-sigs/cloud-provider-azure/issues/7369">#7369</a>)</li>
<li><a href="https://github.com/kubernetes-sigs/cloud-provider-azure/commit/e3017140f5b99140f3529ed0d220c7e9c1ab5573"><code>e301714</code></a> build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azcore (<a href="https://redirect.github.com/kubernetes-sigs/cloud-provider-azure/issues/7368">#7368</a>)</li>
<li>See full diff in <a href="https://github.com/kubernetes-sigs/cloud-provider-azure/compare/pkg/azclient/v0.1.1...pkg/azclient/v0.1.3">compare view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

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


</details>

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

Approval requirements bypassed by manually added approval.

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

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

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

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

- **[OWNERS](https://github.com/kubernetes-sigs/cloud-provider-azure/blob/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":["nilo19"]} -->
k8s-ci-robot: Hi @dependabot[bot]. 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>


Patch:
diff --git a/go.mod b/go.mod
index 6d6883209..d3dd2f975 100644
--- a/go.mod
+++ b/go.mod
@@ -50,7 +50,7 @@ require (
 	k8s.io/kubelet v0.31.2
 	k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
 	sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.1.8
-	sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.1
+	sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.3
 	sigs.k8s.io/yaml v1.4.0
 )
 
diff --git a/go.sum b/go.sum
index 96f7d78f8..9f2d5da33 100644
--- a/go.sum
+++ b/go.sum
@@ -456,8 +456,8 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsA
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
 sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.1.8 h1:znIZBk0MsNYrRhQB5UCNG+q+5eBSD0rczcHEItjPYhs=
 sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.1.8/go.mod h1:6/RG0r3fZbHIfdMlwnsGGWcH08zoLC2vEeYV3kvJMFo=
-sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.1 h1:fIfY2cov1VA+HEWdHbpRnH3AZjRFe+GLs+5IcfzwMWg=
-sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.1/go.mod h1:/5z3DKSmEdjwEJnHRN+b3MkEN0dJGCOtXnLVULqmH20=
+sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.3 h1:IiAbtW5mYf2d9sOejwBxOXm5+DxcYEOrslt909e6Sio=
+sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.3/go.mod h1:6xHgJ5wg7E/hQO578W6n2zmlqhSDByHoh52pMDudtWQ=
 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
 sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
diff --git a/pkg/provider/azure.go b/pkg/provider/azure.go
index ae8a2fdd4..0b3ab1e97 100644
--- a/pkg/provider/azure.go
+++ b/pkg/provider/azure.go
@@ -59,7 +59,6 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/loadbalancerclient"
 	"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/privatelinkserviceclient"
 	"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"
@@ -69,6 +68,7 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/vmsizeclient"
 	"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/zone"
 
 	"sigs.k8s.io/yaml"
@@ -371,7 +371,6 @@ type Cloud struct {
 	AvailabilitySetsClient          vmasclient.Interface
 	privateendpointclient           privateendpointclient.Interface
 	privatednszonegroupclient       privatednszonegroupclient.Interface
-	PrivateLinkServiceClient        privatelinkserviceclient.Interface
 	ComputeClientFactory            azclient.ClientFactory
 	NetworkClientFactory            azclient.ClientFactory
 	AuthProvider                    *azclient.AuthProvider
@@ -419,13 +418,12 @@ type Cloud struct {
 	lbCache  azcache.Resource
 	nsgRepo  securitygroup.Repository
 	zoneRepo zone.Repository
+	plsRepo  privatelinkservice.Repository
 	rtCache  azcache.Resource
 	// public ip cache
 	// key: [resourceGroupName]
 	// Value: sync.Map of [pipName]*PublicIPAddress
 	pipCache azcache.Resource
-	// use [resourceGroupName*LBFrontEndIpConfigurationID] as the key and search for PLS attached to the frontEnd
-	plsCache azcache.Resource
 	// a timed cache storing storage account properties to avoid querying storage account frequently
 	storageAccountCache azcache.Resource
 	// a timed cache storing storage account file service properties to avoid querying storage account file service properties frequently
@@ -747,6 +745,11 @@ func (az *Cloud) InitializeCloudFromConfig(ctx context.Context, config *Config,
 		if err != nil {
 			return err
 		}
+
+		az.plsRepo, err = privatelinkservice.NewRepo(az.ComputeClientFactory.GetPrivateLinkServiceClient(), time.Duration(az.PlsCacheTTLInSeconds)*time.Second, az.DisableAPICallCache)
+		if err != nil {
+			return err
+		}
 	}
 	err = az.initCaches()
 	if err != nil {
@@ -870,11 +873,6 @@ func (az *Cloud) initCaches() (err error) {
 		return err
 	}
 
-	az.plsCache, err = az.newPLSCache()
-	if err != nil {
-		return err
-	}
-
 	getter := func(_ context.Context, _ string) (interface{}, error) { return nil, nil }
 	if az.storageAccountCache, err = azcache.NewTimedCache(time.Minute, getter, az.Config.DisableAPICallCache); err != nil {
 		return err
@@ -989,7 +987,6 @@ func (az *Cloud) configAzureClients(
 	publicIPClientConfig := azClientConfig.WithRateLimiter(az.Config.PublicIPAddressRateLimit)
 	privateDNSZoenGroupConfig := azClientConfig.WithRateLimiter(az.Config.PrivateDNSZoneGroupRateLimit)
 	privateEndpointConfig := azClientConfig.WithRateLimiter(az.Config.PrivateEndpointRateLimit)
-	privateLinkServiceConfig := azClientConfig.WithRateLimiter(az.Config.PrivateLinkServiceRateLimit)
 	// TODO(ZeroMagic): add azurefileRateLimit
 	fileClientConfig := azClientConfig.WithRateLimiter(nil)
 	blobClientConfig := azClientConfig.WithRateLimiter(nil)
@@ -1038,7 +1035,6 @@ func (az *Cloud) configAzureClients(
 	az.AvailabilitySetsClient = vmasclient.New(vmasClientConfig)
 	az.privateendpointclient = privateendpointclient.New(privateEndpointConfig)
 	az.privatednszonegroupclient = privatednszonegroupclient.New(privateDNSZoenGroupConfig)
-	az.PrivateLinkServiceClient = privatelinkserviceclient.New(privateLinkServiceConfig)
 }
 
 func (az *Cloud) getAzureClientConfig(servicePrincipalToken *adal.ServicePrincipalToken) *azclients.ClientConfig {
diff --git a/pkg/provider/azure_fakes.go b/pkg/provider/azure_fakes.go
index 127b6713f..07249d8d3 100644
--- a/pkg/provider/azure_fakes.go
+++ b/pkg/provider/azure_fakes.go
@@ -34,7 +34,6 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/diskclient/mockdiskclient"
 	"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/privatelinkserviceclient/mockprivatelinkserviceclient"
 	"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"
@@ -44,6 +43,7 @@ import (
 	azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/config"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/privatelinkservice"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/securitygroup"
 	utilsets "sigs.k8s.io/cloud-provider-azure/pkg/util/sets"
 )
@@ -119,7 +119,6 @@ func GetTestCloud(ctrl *gomock.Controller) (az *Cloud) {
 	az.VirtualMachineScaleSetsClient = mockvmssclient.NewMockInterface(ctrl)
 	az.VirtualMachineScaleSetVMsClient = mockvmssvmclient.NewMockInterface(ctrl)
 	az.VirtualMachinesClient = mockvmclient.NewMockInterface(ctrl)
-	az.PrivateLinkServiceClient = mockprivatelinkserviceclient.NewMockInterface(ctrl)
 	clientFactory := mock_azclient.NewMockClientFactory(ctrl)
 	az.ComputeClientFactory = clientFactory
 	az.NetworkClientFactory = clientFactory
@@ -138,9 +137,10 @@ func GetTestCloud(ctrl *gomock.Controller) (az *Cloud) {
 	az.nsgRepo, _ = securitygroup.NewSecurityGroupRepo(az.SecurityGroupResourceGroup, az.SecurityGroupName, az.NsgCacheTTLInSeconds, az.Config.DisableAPICallCache, securtyGrouptrack2Client)
 	az.rtCache, _ = az.newRouteTableCache()
 	az.pipCache, _ = az.newPIPCache()
-	az.plsCache, _ = az.newPLSCache()
 	az.LoadBalancerBackendPool = NewMockBackendPool(ctrl)
 
+	az.plsRepo = privatelinkservice.NewMockRepository(ctrl)
+
 	getter := func(_ context.Context, _ string) (interface{}, error) { return nil, nil }
 	az.storageAccountCache, _ = azcache.NewTimedCache(time.Minute, getter, az.Config.DisableAPICallCache)
 	az.fileServicePropertiesCache, _ = azcache.NewTimedCache(5*time.Minute, getter, az.Config.DisableAPICallCache)
diff --git a/pkg/provider/azure_loadbalancer.go b/pkg/provider/azure_loadbalancer.go
index e05cceaf8..c846ff178 100644
--- a/pkg/provider/azure_loadbalancer.go
+++ b/pkg/provider/azure_loadbalancer.go
@@ -890,9 +890,13 @@ func (az *Cloud) getServiceLoadBalancer(
 			}
 		}
 		if az.HasExtendedLocation() {
+			var typ network.ExtendedLocationTypes
+			if getExtendedLocationTypeFromString(az.ExtendedLocationType) == armnetwork.ExtendedLocationTypesEdgeZone {
+				typ = network.EdgeZone
+			}
 			defaultLB.ExtendedLocation = &network.ExtendedLocation{
 				Name: &az.ExtendedLocationName,
-				Type: getExtendedLocationTypeFromString(az.ExtendedLocationType),
+				Type: typ,
 			}
 		}
 	}
@@ -940,9 +944,13 @@ func (az *Cloud) selectLoadBalancer(ctx context.Context, clusterName string, ser
 				LoadBalancerPropertiesFormat: &network.LoadBalancerPropertiesFormat{},
 			}
 			if az.HasExtendedLocation() {
+				var typ network.ExtendedLocationTypes
+				if getExtendedLocationTypeFromString(az.ExtendedLocationType) == armnetwork.ExtendedLocationTypesEdgeZone {
+					typ = network.EdgeZone
+				}
 				selectedLB.ExtendedLocation = &network.ExtendedLocation{
 					Name: &az.ExtendedLocationName,
-					Type: getExtendedLocationTypeFromString(az.ExtendedLocationType),
+					Type: typ,
 				}
 			}
 
@@ -1176,9 +1184,13 @@ func (az *Cloud) ensurePublicIPExists(ctx context.Context, service *v1.Service,
 		pip.Location = ptr.To(az.Location)
 		if az.HasExtendedLocation() {
 			klog.V(2).Infof("Using extended location with name %s, and type %s for PIP", az.ExtendedLocationName, az.ExtendedLocationType)
+			var typ network.ExtendedLocationTypes
+			if getExtendedLocationTypeFromString(az.ExtendedLocationType) == armnetwork.ExtendedLocationTypesEdgeZone {
+				typ = network.EdgeZone
+			}
 			pip.ExtendedLocation = &network.ExtendedLocation{
 				Name: &az.ExtendedLocationName,
-				Type: getExtendedLocationTypeFromString(az.ExtendedLocationType),
+				Type: typ,
 			}
 		}
 		pip.PublicIPAddressPropertiesFormat = &network.PublicIPAddressPropertiesFormat{
diff --git a/pkg/provider/azure_privatelinkservice.go b/pkg/provider/azure_privatelinkservice.go
index 259de24e9..de8fb3a9b 100644
--- a/pkg/provider/azure_privatelinkservice.go
+++ b/pkg/provider/azure_privatelinkservice.go
@@ -22,6 +22,8 @@ import (
 	"net"
 	"strings"
 
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
+	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
 	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
 
 	v1 "k8s.io/api/core/v1"
@@ -31,7 +33,7 @@ import (
 	azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 	"sigs.k8s.io/cloud-provider-azure/pkg/metrics"
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
+	fnutil "sigs.k8s.io/cloud-provider-azure/pkg/util/collectionutil"
 )
 
 // reconcilePrivateLinkService() function makes sure a PLS is created or deleted on
@@ -88,7 +90,7 @@ func (az *Cloud) reconcilePrivateLinkService(
 		}
 
 		// Secondly, check if there is a private link service already created
-		existingPLS, err := az.getPrivateLinkService(ctx, az.getPLSResourceGroup(service), fipConfigID, azcache.CacheReadTypeDefault)
+		existingPLS, err := az.plsRepo.Get(ctx, az.getPLSResourceGroup(service), *fipConfigID, azcache.CacheReadTypeDefault)
 		if err != nil {
 			klog.Errorf("reconcilePrivateLinkService for service(%s): getPrivateLinkService(%s) failed: %v", serviceName, ptr.Deref(fipConfigID, ""), err)
 			return err
@@ -97,7 +99,7 @@ func (az *Cloud) reconcilePrivateLinkService(
 		exists := !strings.EqualFold(ptr.Deref(existingPLS.ID, ""), consts.PrivateLinkServiceNotExistID)
 		if exists {
 			klog.V(4).Infof("reconcilePrivateLinkService for service(%s): found existing private link service attached(%s)", serviceName, ptr.Deref(existingPLS.Name, ""))
-			if !isManagedPrivateLinkSerivce(&existingPLS, clusterName) {
+			if !isManagedPrivateLinkSerivce(existingPLS, clusterName) {
 				return fmt.Errorf(
 					"reconcilePrivateLinkService for service(%s) failed: LB frontend(%s) already has unmanaged private link service(%s)",
 					serviceName,
@@ -106,7 +108,7 @@ func (az *Cloud) reconcilePrivateLinkService(
 				)
 			}
 			// If there is an existing private link service, only owner service can update its properties
-			ownerService := getPrivateLinkServiceOwner(&existingPLS)
+			ownerService := getPrivateLinkServiceOwner(existingPLS)
 			if !strings.EqualFold(ownerService, serviceName) {
 				if serviceHasAdditionalConfigs(service) {
 					return fmt.Errorf(
@@ -128,21 +130,21 @@ func (az *Cloud) reconcilePrivateLinkService(
 		} else {
 			existingPLS.ID = nil
 			existingPLS.Location = &az.Location
-			existingPLS.PrivateLinkServiceProperties = &network.PrivateLinkServiceProperties{}
+			existingPLS.Properties = &armnetwork.PrivateLinkServiceProperties{}
 			if az.HasExtendedLocation() {
-				existingPLS.ExtendedLocation = &network.ExtendedLocation{
+				existingPLS.ExtendedLocation = &armnetwork.ExtendedLocation{
 					Name: &az.ExtendedLocationName,
-					Type: getExtendedLocationTypeFromString(az.ExtendedLocationType),
+					Type: to.Ptr(getExtendedLocationTypeFromString(az.ExtendedLocationType)),
 				}
 			}
 		}
 
-		plsName, err := az.getPrivateLinkServiceName(&existingPLS, service, fipConfig)
+		plsName, err := az.getPrivateLinkServiceName(existingPLS, service, fipConfig)
 		if err != nil {
 			return err
 		}
 
-		dirtyPLS, err := az.getExpectedPrivateLinkService(&existingPLS, &plsName, &clusterName, service, fipConfig)
+		dirtyPLS, err := az.getExpectedPrivateLinkService(existingPLS, &plsName, &clusterName, service, fipConfig)
 		if err != nil {
 			return err
 		}
@@ -155,14 +157,14 @@ func (az *Cloud) reconcilePrivateLinkService(
 				return err
 			}
 			existingPLS.Etag = ptr.To("")
-			err = az.CreateOrUpdatePLS(service, az.getPLSResourceGroup(service), existingPLS)
+			_, err = az.plsRepo.CreateOrUpdate(ctx, az.getPLSResourceGroup(service), *existingPLS)
 			if err != nil {
 				klog.Errorf("reconcilePrivateLinkService for service(%s) abort backoff: pls(%s) - updating: %s", serviceName, plsName, err.Error())
 				return err
 			}
 		}
 	} else if !wantPLS {
-		existingPLS, err := az.getPrivateLinkService(ctx, az.getPLSResourceGroup(service), fipConfigID, azcache.CacheReadTypeDefault)
+		existingPLS, err := az.plsRepo.Get(ctx, az.getPLSResourceGroup(service), *fipConfigID, azcache.CacheReadTypeDefault)
 		if err != nil {
 			klog.Errorf("reconcilePrivateLinkService for service(%s): getPrivateLinkService(%s) failed: %v", serviceName, ptr.Deref(fipConfigID, ""), err)
 			return err
@@ -170,10 +172,10 @@ func (az *Cloud) reconcilePrivateLinkService(
 
 		exists := !strings.EqualFold(ptr.Deref(existingPLS.ID, ""), consts.PrivateLinkServiceNotExistID)
 		if exists {
-			deleteErr := az.safeDeletePLS(&existingPLS, service)
+			deleteErr := az.safeDeletePLS(ctx, existingPLS, service)
 			if deleteErr != nil {
 				klog.Errorf("reconcilePrivateLinkService for service(%s): deletePLS for frontEnd(%s) failed: %v", serviceName, ptr.Deref(fipConfigID, ""), err)
-				return deleteErr.Error()
+				return deleteErr
 			}
 		}
 	}
@@ -222,23 +224,24 @@ func (az *Cloud) disablePLSNetworkPolicy(service *v1.Service) error {
 	return nil
 }
 
-func (az *Cloud) safeDeletePLS(pls *network.PrivateLinkService, service *v1.Service) *retry.Error {
+func (az *Cloud) safeDeletePLS(ctx context.Context, pls *armnetwork.PrivateLinkService, service *v1.Service) error {
 	if pls == nil {
 		return nil
 	}
 
-	peConns := pls.PrivateEndpointConnections
-	if peConns != nil {
-		for _, peConn := range *peConns {
-			klog.V(2).Infof("deletePLS: deleting PEConnection %s", ptr.Deref(peConn.Name, ""))
-			rerr := az.DeletePEConn(service, az.getPLSResourceGroup(service), ptr.Deref(pls.Name, ""), ptr.Deref(peConn.Name, ""))
-			if rerr != nil {
-				return rerr
-			}
+	peConns := pls.Properties.PrivateEndpointConnections
+	for _, peConn := range peConns {
+		klog.V(2).Infof("deletePLS: deleting PEConnection %s", ptr.Deref(peConn.Name, ""))
+		err := az.plsRepo.DeletePEConnection(ctx, az.getPLSResourceGroup(service), ptr.Deref(pls.Name, ""), ptr.Deref(peConn.Name, ""))
+		if err != nil {
+			return err
 		}
 	}
 
-	rerr := az.DeletePLS(service, az.getPLSResourceGroup(service), ptr.Deref(pls.Name, ""), ptr.Deref((*pls.LoadBalancerFrontendIPConfigurations)[0].ID, ""))
+	resourceGroup := az.getPLSResourceGroup(service)
+	plsName := ptr.Deref(pls.Name, "")
+	lbFrontendID := ptr.Deref((pls.Properties.LoadBalancerFrontendIPConfigurations)[0].ID, "")
+	rerr := az.plsRepo.Delete(ctx, resourceGroup, plsName, lbFrontendID)
 	if rerr != nil {
 		return rerr
 	}
@@ -248,7 +251,7 @@ func (az *Cloud) safeDeletePLS(pls *network.PrivateLinkService, service *v1.Serv
 
 // getPrivateLinkServiceName() returns the name of private link service, or any error
 func (az *Cloud) getPrivateLinkServiceName(
-	existingPLS *network.PrivateLinkService,
+	existingPLS *armnetwork.PrivateLinkService,
 	service *v1.Service,
 	fipConfig *network.FrontendIPConfiguration,
 ) (string, error) {
@@ -278,7 +281,7 @@ func (az *Cloud) getPrivateLinkServiceName(
 
 // getExpectedPrivateLinkService builds expected PLS object from service spec
 func (az *Cloud) getExpectedPrivateLinkService(
-	existingPLS *network.PrivateLinkService,
+	existingPLS *armnetwork.PrivateLinkService,
 	plsName *string,
 	clusterName *string,
 	service *v1.Service,
@@ -297,17 +300,17 @@ func (az *Cloud) getExpectedPrivateLinkService(
 	}
 
 	// Set failed PLS as dirty so that provision can be retried
-	if existingPLS.ProvisioningState == network.ProvisioningStateFailed {
+	if existingPLS.Properties.ProvisioningState != nil && *existingPLS.Properties.ProvisioningState == armnetwork.ProvisioningStateFailed {
 		dirtyPLS = true
 	}
 
 	// Shadow copy properties to avoid changing pls cache
-	plsProperties := *existingPLS.PrivateLinkServiceProperties
-	existingPLS.PrivateLinkServiceProperties = &plsProperties
+	plsProperties := *existingPLS.Properties
+	existingPLS.Properties = &plsProperties
 
 	// Set LBFrontendIpConfiguration
-	if existingPLS.LoadBalancerFrontendIPConfigurations == nil {
-		existingPLS.LoadBalancerFrontendIPConfigurations = &[]network.FrontendIPConfiguration{{ID: fipConfig.ID}}
+	if existingPLS.Properties.LoadBalancerFrontendIPConfigurations == nil {
+		existingPLS.Properties.LoadBalancerFrontendIPConfigurations = []*armnetwork.FrontendIPConfiguration{{ID: fipConfig.ID}}
 		dirtyPLS = true
 	}
 
@@ -344,7 +347,7 @@ func (az *Cloud) getExpectedPrivateLinkService(
 
 // reconcile Private link service's IP configurations
 func (az *Cloud) reconcilePLSIpConfigs(
-	existingPLS *network.PrivateLinkService,
+	existingPLS *armnetwork.PrivateLinkService,
 	service *v1.Service,
 ) (bool, error) {
 	changed := false
@@ -376,30 +379,30 @@ func (az *Cloud) reconcilePLSIpConfigs(
 		return false, fmt.Errorf("checkAndUpdatePLSIPConfigs: ipConfigCount(%d) must be no smaller than number of static IPs specified(%d)", ipConfigCount, len(staticIps))
 	}
 
-	if existingPLS.IPConfigurations == nil {
-		existingPLS.IPConfigurations = &[]network.PrivateLinkServiceIPConfiguration{}
+	if existingPLS.Properties.IPConfigurations == nil {
+		existingPLS.Properties.IPConfigurations = []*armnetwork.PrivateLinkServiceIPConfiguration{}
 		changed = true
 	}
 
-	if int32(len(*existingPLS.IPConfigurations)) != ipConfigCount {
+	if int32(len(existingPLS.Properties.IPConfigurations)) != ipConfigCount {
 		changed = true
 	}
 
 	existingStaticIps := make([]string, 0)
-	for _, ipConfig := range *existingPLS.IPConfigurations {
-		if !strings.EqualFold(ptr.Deref(subnet.ID, ""), ptr.Deref(ipConfig.Subnet.ID, "")) {
+	for _, ipConfig := range existingPLS.Properties.IPConfigurations {
+		if !strings.EqualFold(ptr.Deref(subnet.ID, ""), ptr.Deref(ipConfig.Properties.Subnet.ID, "")) {
 			changed = true
 		}
-		if strings.EqualFold(string(ipConfig.PrivateIPAllocationMethod), string(network.Static)) {
-			klog.V(10).Infof("Found static IP: %s", ptr.Deref(ipConfig.PrivateIPAddress, ""))
-			if _, found := staticIps[ptr.Deref(ipConfig.PrivateIPAddress, "")]; !found {
+		if *ipConfig.Properties.PrivateIPAllocationMethod == armnetwork.IPAllocationMethodStatic {
+			klog.V(10).Infof("Found static IP: %s", ptr.Deref(ipConfig.Properties.PrivateIPAddress, ""))
+			if _, found := staticIps[ptr.Deref(ipConfig.Properties.PrivateIPAddress, "")]; !found {
 				changed = true
 			}
-			existingStaticIps = append(existingStaticIps, ptr.Deref(ipConfig.PrivateIPAddress, ""))
+			existingStaticIps = append(existingStaticIps, ptr.Deref(ipConfig.Properties.PrivateIPAddress, ""))
 		}
-		if *ipConfig.Primary {
-			if strings.EqualFold(string(ipConfig.PrivateIPAllocationMethod), string(network.Static)) {
-				if !strings.EqualFold(primaryIP, ptr.Deref(ipConfig.PrivateIPAddress, "")) {
+		if *ipConfig.Properties.Primary {
+			if *ipConfig.Properties.PrivateIPAllocationMethod == armnetwork.IPAllocationMethodStatic {
+				if !strings.EqualFold(primaryIP, ptr.Deref(ipConfig.Properties.PrivateIPAddress, "")) {
 					changed = true
 				}
 			} else {
@@ -428,7 +431,7 @@ func (az *Cloud) reconcilePLSIpConfigs(
 			return prefix + suffix, nil
 		}
 
-		ipConfigs := []network.PrivateLinkServiceIPConfiguration{}
+		var ipConfigs []*armnetwork.PrivateLinkServiceIPConfiguration
 		for k := range staticIps {
 			ip := k
 			isPrimary := strings.EqualFold(ip, primaryIP)
@@ -437,16 +440,16 @@ func (az *Cloud) reconcilePLSIpConfigs(
 			if err != nil {
 				return false, err
 			}
-			ipConfigs = append(ipConfigs, network.PrivateLinkServiceIPConfiguration{
+			ipConfigs = append(ipConfigs, &armnetwork.PrivateLinkServiceIPConfiguration{
 				Name: &configName,
-				PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
+				Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
 					PrivateIPAddress:          &ip,
-					PrivateIPAllocationMethod: network.Static,
-					Subnet: &network.Subnet{
+					PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodStatic),
+					Subnet: &armnetwork.Subnet{
 						ID: subnet.ID,
 					},
 					Primary:                 &isPrimary,
-					PrivateIPAddressVersion: network.IPv4,
+					PrivateIPAddressVersion: to.Ptr(armnetwork.IPVersionIPv4),
 				},
 			})
 		}
@@ -457,19 +460,19 @@ func (az *Cloud) reconcilePLSIpConfigs(
 			if err != nil {
 				return false, err
 			}
-			ipConfigs = append(ipConfigs, network.PrivateLinkServiceIPConfiguration{
+			ipConfigs = append(ipConfigs, &armnetwork.PrivateLinkServiceIPConfiguration{
 				Name: &configName,
-				PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-					PrivateIPAllocationMethod: network.Dynamic,
-					Subnet: &network.Subnet{
+				Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+					PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+					Subnet: &armnetwork.Subnet{
 						ID: subnet.ID,
 					},
 					Primary:                 &isPrimary,
-					PrivateIPAddressVersion: network.IPv4,
+					PrivateIPAddressVersion: to.Ptr(armnetwork.IPVersionIPv4),
 				},
 			})
 		}
-		existingPLS.IPConfigurations = &ipConfigs
+		existingPLS.Properties.IPConfigurations = ipConfigs
 	}
 	return changed, nil
 }
@@ -479,79 +482,85 @@ func serviceRequiresPLS(service *v1.Service) bool {
 }
 
 func reconcilePLSEnableProxyProtocol(
-	existingPLS *network.PrivateLinkService,
+	existingPLS *armnetwork.PrivateLinkService,
 	service *v1.Service,
 ) bool {
 	changed := false
 	enableProxyProtocol := getBoolValueFromServiceAnnotations(service, consts.ServiceAnnotationPLSProxyProtocol)
-	if enableProxyProtocol && (existingPLS.EnableProxyProtocol == nil || !*existingPLS.EnableProxyProtocol) {
+	if enableProxyProtocol && (existingPLS.Properties.EnableProxyProtocol == nil || !*existingPLS.Properties.EnableProxyProtocol) {
 		changed = true
-	} else if !enableProxyProtocol && (existingPLS.EnableProxyProtocol != nil && *existingPLS.EnableProxyProtocol) {
+	} else if !enableProxyProtocol && (existingPLS.Properties.EnableProxyProtocol != nil && *existingPLS.Properties.EnableProxyProtocol) {
 		changed = true
 	}
 	if changed {
-		existingPLS.EnableProxyProtocol = &enableProxyProtocol
+		existingPLS.Properties.EnableProxyProtocol = &enableProxyProtocol
 	}
 	return changed
 }
 
 func reconcilePLSFqdn(
-	existingPLS *network.PrivateLinkService,
+	existingPLS *armnetwork.PrivateLinkService,
 	service *v1.Service,
 ) bool {
 	changed := false
 	fqdns := getPLSFqdns(service)
-	if existingPLS.Fqdns == nil {
+	if existingPLS.Properties.Fqdns == nil {
 		if len(fqdns) != 0 {
 			changed = true
 		}
-	} else if !sameContentInSlices(fqdns, *existingPLS.Fqdns) {
+	} else if !sameContentInSlices(fqdns, fnutil.Map(func(s *string) string {
+		return *s
+	}, existingPLS.Properties.Fqdns)) {
 		changed = true
 	}
 
 	if changed {
-		existingPLS.Fqdns = &fqdns
+		existingPLS.Properties.Fqdns = fnutil.Map(func(s string) *string { return &s }, fqdns)
 	}
 	return changed
 }
 
 func reconcilePLSVisibility(
-	existingPLS *network.PrivateLinkService,
+	existingPLS *armnetwork.PrivateLinkService,
 	service *v1.Service,
 ) (bool, error) {
 	changed := false
 	visibilitySubs, _ := getPLSVisibility(service)
 	autoApprovalSubs := getPLSAutoApproval(service)
 
-	if existingPLS.Visibility == nil || existingPLS.Visibility.Subscriptions == nil {
+	if existingPLS.Properties.Visibility == nil || existingPLS.Properties.Visibility.Subscriptions == nil {
 		if len(visibilitySubs) != 0 {
 			changed = true
 		}
-	} else if !sameContentInSlices(visibilitySubs, *existingPLS.Visibility.Subscriptions) {
+	} else if !sameContentInSlices(visibilitySubs, fnutil.Map(func(s *string) string {
+		return *s
+	}, existingPLS.Properties.Visibility.Subscriptions)) {
 		changed = true
 	}
 
-	if existingPLS.AutoApproval == nil || existingPLS.AutoApproval.Subscriptions == nil {
+	if existingPLS.Properties.AutoApproval == nil || existingPLS.Properties.AutoApproval.Subscriptions == nil {
 		if len(autoApprovalSubs) != 0 {
 			changed = true
 		}
-	} else if !sameContentInSlices(autoApprovalSubs, *existingPLS.AutoApproval.Subscriptions) {
+	} else if !sameContentInSlices(autoApprovalSubs, fnutil.Map(func(s *string) string {
+		return *s
+	}, existingPLS.Properties.AutoApproval.Subscriptions)) {
 		changed = true
 	}
 
 	if changed {
-		existingPLS.Visibility = &network.PrivateLinkServicePropertiesVisibility{
-			Subscriptions: &visibilitySubs,
+		existingPLS.Properties.Visibility = &armnetwork.PrivateLinkServicePropertiesVisibility{
+			Subscriptions: to.SliceOfPtrs(visibilitySubs...),
 		}
-		existingPLS.AutoApproval = &network.PrivateLinkServicePropertiesAutoApproval{
-			Subscriptions: &autoApprovalSubs,
+		existingPLS.Properties.AutoApproval = &armnetwork.PrivateLinkServicePropertiesAutoApproval{
+			Subscriptions: to.SliceOfPtrs(autoApprovalSubs...),
 		}
 	}
 	return changed, nil
 }
 
 func (az *Cloud) reconcilePLSTags(
-	existingPLS *network.PrivateLinkService,
+	existingPLS *armnetwork.PrivateLinkService,
 	clusterName *string,
 	service *v1.Service,
 ) bool {
@@ -702,14 +711,14 @@ func getPLSStaticIPs(service *v1.Service) (map[string]bool, string, error) {
 	return result, primaryIP, nil
 }
 
-func isManagedPrivateLinkSerivce(existingPLS *network.PrivateLinkService, clusterName string) bool {
+func isManagedPrivateLinkSerivce(existingPLS *armnetwork.PrivateLinkService, clusterName string) bool {
 	tags := existingPLS.Tags
 	v, ok := tags[consts.ClusterNameTagKey]
 	return ok && v != nil && strings.EqualFold(strings.TrimSpace(*v), clusterName)
 }
 
 // find owner service for an existing private link service from its tags
-func getPrivateLinkServiceOwner(existingPLS *network.PrivateLinkService) string {
+func getPrivateLinkServiceOwner(existingPLS *armnetwork.PrivateLinkService) string {
 	tags := existingPLS.Tags
 	v, ok := tags[consts.OwnerServiceTagKey]
 	if ok && v != nil {
diff --git a/pkg/provider/azure_privatelinkservice_repo.go b/pkg/provider/azure_privatelinkservice_repo.go
deleted file mode 100644
index b58278fb0..000000000
--- a/pkg/provider/azure_privatelinkservice_repo.go
+++ /dev/null
@@ -1,153 +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"
-	"fmt"
-	"net/http"
-	"strings"
-	"time"
-
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-
-	v1 "k8s.io/api/core/v1"
-	"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"
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-func (az *Cloud) CreateOrUpdatePLS(_ *v1.Service, resourceGroup string, pls network.PrivateLinkService) error {
-	ctx, cancel := getContextWithCancel()
-	defer cancel()
-
-	rerr := az.PrivateLinkServiceClient.CreateOrUpdate(ctx, resourceGroup, ptr.Deref(pls.Name, ""), pls, ptr.Deref(pls.Etag, ""))
-	if rerr == nil {
-		// Invalidate the cache right after updating
-		_ = az.plsCache.Delete(getPLSCacheKey(resourceGroup, ptr.Deref((*pls.LoadBalancerFrontendIPConfigurations)[0].ID, "")))
-		return nil
-	}
-
-	rtJSON, _ := json.Marshal(pls)
-	klog.Warningf("PrivateLinkServiceClient.CreateOrUpdate(%s) failed: %v, PrivateLinkService request: %s", ptr.Deref(pls.Name, ""), rerr.Error(), string(rtJSON))
-
-	// Invalidate the cache because etag mismatch.
-	if rerr.HTTPStatusCode == http.StatusPreconditionFailed {
-		klog.V(3).Infof("Private link service cache for %s is cleanup because of http.StatusPreconditionFailed", ptr.Deref(pls.Name, ""))
-		_ = az.plsCache.Delete(getPLSCacheKey(resourceGroup, ptr.Deref((*pls.LoadBalancerFrontendIPConfigurations)[0].ID, "")))
-	}
-	// 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("Private link service for %s is cleanup because CreateOrUpdatePrivateLinkService is canceled by another operation", ptr.Deref(pls.Name, ""))
-		_ = az.plsCache.Delete(getPLSCacheKey(resourceGroup, ptr.Deref((*pls.LoadBalancerFrontendIPConfigurations)[0].ID, "")))
-	}
-	klog.Errorf("PrivateLinkServiceClient.CreateOrUpdate(%s) failed: %v", ptr.Deref(pls.Name, ""), rerr.Error())
-	return rerr.Error()
-}
-
-// DeletePLS invokes az.PrivateLinkServiceClient.Delete with exponential backoff retry
-func (az *Cloud) DeletePLS(service *v1.Service, resourceGroup, plsName, plsLBFrontendID string) *retry.Error {
-	ctx, cancel := getContextWithCancel()
-	defer cancel()
-
-	rerr := az.PrivateLinkServiceClient.Delete(ctx, resourceGroup, plsName)
-	if rerr == nil {
-		// Invalidate the cache right after deleting
-		_ = az.plsCache.Delete(getPLSCacheKey(resourceGroup, plsLBFrontendID))
-		return nil
-	}
-
-	klog.Errorf("PrivateLinkServiceClient.DeletePLS(%s) failed: %s", plsName, rerr.Error().Error())
-	az.Event(service, v1.EventTypeWarning, "DeletePrivateLinkService", rerr.Error().Error())
-	return rerr
-}
-
-// DeletePEConn invokes az.PrivateLinkServiceClient.DeletePEConnection with exponential backoff retry
-func (az *Cloud) DeletePEConn(service *v1.Service, resourceGroup, plsName, peConnName string) *retry.Error {
-	ctx, cancel := getContextWithCancel()
-	defer cancel()
-
-	rerr := az.PrivateLinkServiceClient.DeletePEConnection(ctx, resourceGroup, plsName, peConnName)
-	if rerr == nil {
-		return nil
-	}
-
-	klog.Errorf("PrivateLinkServiceClient.DeletePEConnection(%s-%s) failed: %s", plsName, peConnName, rerr.Error().Error())
-	az.Event(service, v1.EventTypeWarning, "DeletePrivateEndpointConnection", rerr.Error().Error())
-	return rerr
-}
-
-func (az *Cloud) newPLSCache() (azcache.Resource, error) {
-	// for PLS cache, key is LBFrontendIPConfiguration ID
-	getter := func(ctx context.Context, key string) (interface{}, error) {
-		resourceGroup, frontendID := parsePLSCacheKey(key)
-		plsList, err := az.PrivateLinkServiceClient.List(ctx, resourceGroup)
-		exists, rerr := checkResourceExistsFromError(err)
-		if rerr != nil {
-			return nil, rerr.Error()
-		}
-
-		if exists {
-			for i := range plsList {
-				pls := plsList[i]
-				if pls.PrivateLinkServiceProperties == nil {
-					continue
-				}
-				fipConfigs := pls.PrivateLinkServiceProperties.LoadBalancerFrontendIPConfigurations
-				if fipConfigs == nil {
-					continue
-				}
-				for _, fipConfig := range *fipConfigs {
-					if strings.EqualFold(*fipConfig.ID, frontendID) {
-						return &pls, nil
-					}
-				}
-
-			}
-		}
-
-		klog.V(2).Infof("No privateLinkService found for frontendIPConfig %q in rg %q", frontendID, resourceGroup)
-		plsNotExistID := consts.PrivateLinkServiceNotExistID
-		return &network.PrivateLinkService{ID: &plsNotExistID}, nil
-	}
-
-	if az.PlsCacheTTLInSeconds == 0 {
-		az.PlsCacheTTLInSeconds = plsCacheTTLDefaultInSeconds
-	}
-	return azcache.NewTimedCache(time.Duration(az.PlsCacheTTLInSeconds)*time.Second, getter, az.Config.DisableAPICallCache)
-}
-
-func (az *Cloud) getPrivateLinkService(ctx context.Context, resourceGroup string, frontendIPConfigID *string, crt azcache.AzureCacheReadType) (pls network.PrivateLinkService, err error) {
-	cachedPLS, err := az.plsCache.GetWithDeepCopy(ctx, getPLSCacheKey(resourceGroup, *frontendIPConfigID), crt)
-	if err != nil {
-		return pls, err
-	}
-	return *(cachedPLS.(*network.PrivateLinkService)), nil
-}
-
-func getPLSCacheKey(resourceGroup, plsLBFrontendID string) string {
-	return fmt.Sprintf("%s*%s", resourceGroup, plsLBFrontendID)
-}
-
-func parsePLSCacheKey(key string) (string, string) {
-	splits := strings.Split(key, "*")
-	return splits[0], splits[1]
-}
diff --git a/pkg/provider/azure_utils.go b/pkg/provider/azure_utils.go
index 306b76c0c..65fef0f21 100644
--- a/pkg/provider/azure_utils.go
+++ b/pkg/provider/azure_utils.go
@@ -43,8 +43,8 @@ const (
 	IPVersionIPv4 bool = false
 )
 
-var strToExtendedLocationType = map[string]network.ExtendedLocationTypes{
-	"edgezone": network.EdgeZone,
+var strToExtendedLocationType = map[string]armnetwork.ExtendedLocationTypes{
+	"edgezone": armnetwork.ExtendedLocationTypesEdgeZone,
 }
 
 // LockMap used to lock on entries
@@ -205,12 +205,12 @@ func (az *Cloud) reconcileTags(currentTagsOnResource, newTags map[string]*string
 	return currentTagsOnResource, changed
 }
 
-func getExtendedLocationTypeFromString(extendedLocationType string) network.ExtendedLocationTypes {
+func getExtendedLocationTypeFromString(extendedLocationType string) armnetwork.ExtendedLocationTypes {
 	extendedLocationType = strings.ToLower(extendedLocationType)
 	if val, ok := strToExtendedLocationType[extendedLocationType]; ok {
 		return val
 	}
-	return network.EdgeZone
+	return armnetwork.ExtendedLocationTypesEdgeZone
 }
 
 func getNodePrivateIPAddress(node *v1.Node, isIPv6 bool) string {
diff --git a/pkg/provider/azure_wrap.go b/pkg/provider/azure_wrap.go
index 6a819329a..d599ddbd2 100644
--- a/pkg/provider/azure_wrap.go
+++ b/pkg/provider/azure_wrap.go
@@ -31,7 +31,6 @@ var (
 	loadBalancerCacheTTLDefaultInSeconds = 120
 	routeTableCacheTTLDefaultInSeconds   = 120
 	publicIPCacheTTLDefaultInSeconds     = 120
-	plsCacheTTLDefaultInSeconds          = 120
 
 	azureNodeProviderIDRE    = regexp.MustCompile(`^azure:///subscriptions/(?:.*)/resourceGroups/(?:.*)/providers/Microsoft.Compute/(?:.*)`)
 	azureResourceGroupNameRE = regexp.MustCompile(`.*/subscriptions/(?:.*)/resourceGroups/(.+)/providers/(?:.*)`)
diff --git a/pkg/provider/privatelinkservice/cache.go b/pkg/provider/privatelinkservice/cache.go
new file mode 100644
index 000000000..e13c38349
--- /dev/null
+++ b/pkg/provider/privatelinkservice/cache.go
@@ -0,0 +1,80 @@
+/*
+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 privatelinkservice
+
+import (
+	"context"
+	"fmt"
+	"strings"
+	"time"
+
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
+	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatelinkserviceclient"
+	"sigs.k8s.io/cloud-provider-azure/pkg/cache"
+	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
+)
+
+const (
+	DefaultCacheTTL = 120 * time.Second
+)
+
+func NewCache(
+	client privatelinkserviceclient.Interface,
+	cacheTTL time.Duration,
+	disableAPICallCache bool,
+) (cache.Resource, error) {
+	getter := func(ctx context.Context, key string) (interface{}, error) {
+		resourceGroup, frontendID := parsePLSCacheKey(key)
+		plsList, err := client.List(ctx, resourceGroup)
+		if err != nil {
+			return nil, err
+		}
+
+		for i := range plsList {
+			pls := plsList[i]
+			if pls.Properties == nil {
+				continue
+			}
+			for _, fipConfig := range pls.Properties.LoadBalancerFrontendIPConfigurations {
+				if strings.EqualFold(*fipConfig.ID, frontendID) {
+					return pls, nil
+				}
+			}
+		}
+
+		notFound := &armnetwork.PrivateLinkService{
+			ID: to.Ptr(consts.PrivateLinkServiceNotExistID),
+		}
+		return notFound, nil
+	}
+
+	if cacheTTL == 0 {
+		cacheTTL = DefaultCacheTTL
+	}
+	return cache.NewTimedCache(cacheTTL, getter, disableAPICallCache)
+}
+
+func getPLSCacheKey(resourceGroup, plsLBFrontendID string) string {
+	return fmt.Sprintf("%s*%s", resourceGroup, plsLBFrontendID)
+}
+
+func parsePLSCacheKey(key string) (string, string) {
+	splits := strings.Split(key, "*")
+	return splits[0], splits[1]
+}
diff --git a/pkg/provider/privatelinkservice/mock_repo.go b/pkg/provider/privatelinkservice/mock_repo.go
new file mode 100644
index 000000000..a19bd8a5c
--- /dev/null
+++ b/pkg/provider/privatelinkservice/mock_repo.go
@@ -0,0 +1,131 @@
+// /*
+// 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=privatelinkservice -copyright_file ../../../hack/boilerplate/boilerplate.generatego.txt -source=repo.go Repository
+//
+// Package privatelinkservice is a generated GoMock package.
+package privatelinkservice
+
+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, resourceGroup string, pls armnetwork.PrivateLinkService) (*armnetwork.PrivateLinkService, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateOrUpdate", ctx, resourceGroup, pls)
+	ret0, _ := ret[0].(*armnetwork.PrivateLinkService)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateOrUpdate indicates an expected call of CreateOrUpdate.
+func (mr *MockRepositoryMockRecorder) CreateOrUpdate(ctx, resourceGroup, pls any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdate", reflect.TypeOf((*MockRepository)(nil).CreateOrUpdate), ctx, resourceGroup, pls)
+}
+
+// Delete mocks base method.
+func (m *MockRepository) Delete(ctx context.Context, resourceGroup, plsName, lbFrontendID string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Delete", ctx, resourceGroup, plsName, lbFrontendID)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Delete indicates an expected call of Delete.
+func (mr *MockRepositoryMockRecorder) Delete(ctx, resourceGroup, plsName, lbFrontendID any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockRepository)(nil).Delete), ctx, resourceGroup, plsName, lbFrontendID)
+}
+
+// DeletePEConnection mocks base method.
+func (m *MockRepository) DeletePEConnection(ctx context.Context, resourceGroup, plsName, peConnName string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DeletePEConnection", ctx, resourceGroup, plsName, peConnName)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// DeletePEConnection indicates an expected call of DeletePEConnection.
+func (mr *MockRepositoryMockRecorder) DeletePEConnection(ctx, resourceGroup, plsName, peConnName any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePEConnection", reflect.TypeOf((*MockRepository)(nil).DeletePEConnection), ctx, resourceGroup, plsName, peConnName)
+}
+
+// Get mocks base method.
+func (m *MockRepository) Get(ctx context.Context, resourceGroup, frontendIPConfigID string, crt cache.AzureCacheReadType) (*armnetwork.PrivateLinkService, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Get", ctx, resourceGroup, frontendIPConfigID, crt)
+	ret0, _ := ret[0].(*armnetwork.PrivateLinkService)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Get indicates an expected call of Get.
+func (mr *MockRepositoryMockRecorder) Get(ctx, resourceGroup, frontendIPConfigID, crt any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockRepository)(nil).Get), ctx, resourceGroup, frontendIPConfigID, crt)
+}
+
+// List mocks base method.
+func (m *MockRepository) List(ctx context.Context, resourceGroup string) ([]*armnetwork.PrivateLinkService, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "List", ctx, resourceGroup)
+	ret0, _ := ret[0].([]*armnetwork.PrivateLinkService)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// List indicates an expected call of List.
+func (mr *MockRepositoryMockRecorder) List(ctx, resourceGroup any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockRepository)(nil).List), ctx, resourceGroup)
+}
diff --git a/pkg/provider/privatelinkservice/repo.go b/pkg/provider/privatelinkservice/repo.go
new file mode 100644
index 000000000..0b3cea734
--- /dev/null
+++ b/pkg/provider/privatelinkservice/repo.go
@@ -0,0 +1,128 @@
+/*
+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 privatelinkservice
+
+// Generate mocks for the repository interface
+//go:generate mockgen -destination=./mock_repo.go -package=privatelinkservice -copyright_file ../../../hack/boilerplate/boilerplate.generatego.txt -source=repo.go Repository
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatelinkserviceclient"
+	"sigs.k8s.io/cloud-provider-azure/pkg/cache"
+)
+
+type Repository interface {
+	Get(ctx context.Context, resourceGroup, frontendIPConfigID string, crt cache.AzureCacheReadType) (*armnetwork.PrivateLinkService, error)
+	List(ctx context.Context, resourceGroup string) ([]*armnetwork.PrivateLinkService, error)
+	CreateOrUpdate(ctx context.Context, resourceGroup string, pls armnetwork.PrivateLinkService) (*armnetwork.PrivateLinkService, error)
+	Delete(ctx context.Context, resourceGroup, plsName, lbFrontendID string) error
+	DeletePEConnection(ctx context.Context, resourceGroup, plsName, peConnName string) error
+}
+
+type repo struct {
+	client privatelinkserviceclient.Interface
+	cache  cache.Resource
+}
+
+func NewRepo(
+	client privatelinkserviceclient.Interface,
+	cacheTTL time.Duration,
+	disableAPICallCache bool,
+) (Repository, error) {
+	c, err := NewCache(client, cacheTTL, disableAPICallCache)
+	if err != nil {
+		return nil, fmt.Errorf("new PLS cache: %w", err)
+	}
+
+	return &repo{
+		client: client,
+		cache:  c,
+	}, nil
+}
+
+var (
+	ErrMissingPLSName                               = fmt.Errorf("missing PLS name")
+	ErrLoadBalancerFrontendIPConfigurationsNotFound = fmt.Errorf("load balancer frontend IP configurations not found")
+)
+
+func (r *repo) Get(ctx context.Context, resourceGroup, frontendIPConfigID string, crt cache.AzureCacheReadType) (*armnetwork.PrivateLinkService, error) {
+	cacheKey := getPLSCacheKey(resourceGroup, frontendIPConfigID)
+
+	cachedPLS, err := r.cache.GetWithDeepCopy(ctx, cacheKey, crt)
+	if err != nil {
+		return nil, fmt.Errorf("get PLS: %w", err)
+	}
+
+	return cachedPLS.(*armnetwork.PrivateLinkService), nil
+}
+
+func (r *repo) List(ctx context.Context, resourceGroup string) ([]*armnetwork.PrivateLinkService, error) {
+	return r.client.List(ctx, resourceGroup)
+}
+
+func (r *repo) CreateOrUpdate(ctx context.Context, resourceGroup string, pls armnetwork.PrivateLinkService) (*armnetwork.PrivateLinkService, error) {
+	if pls.Name == nil {
+		return nil, ErrMissingPLSName
+	}
+	if pls.Properties == nil ||
+		len(pls.Properties.LoadBalancerFrontendIPConfigurations) == 0 ||
+		pls.Properties.LoadBalancerFrontendIPConfigurations[0].ID == nil {
+		return nil, ErrLoadBalancerFrontendIPConfigurationsNotFound
+	}
+	cacheKey := getPLSCacheKey(resourceGroup, *pls.Properties.LoadBalancerFrontendIPConfigurations[0].ID)
+
+	resp, err := r.client.CreateOrUpdate(ctx, resourceGroup, *pls.Name, pls)
+	if err != nil {
+		return nil, fmt.Errorf("create or update PLS: %w", err)
+	}
+	// clear cache
+	_ = r.cache.Delete(cacheKey)
+
+	return resp, nil
+}
+
+func (r *repo) Delete(ctx context.Context, resourceGroup, plsName, lbFrontendID string) error {
+	if plsName == "" {
+		return ErrMissingPLSName
+	}
+	cacheKey := getPLSCacheKey(resourceGroup, lbFrontendID)
+
+	if err := r.client.Delete(ctx, resourceGroup, plsName); err != nil {
+		return fmt.Errorf("delete PLS: %w", err)
+	}
+	// clear cache
+	_ = r.cache.Delete(cacheKey)
+
+	return nil
+}
+
+func (r *repo) DeletePEConnection(ctx context.Context, resourceGroup, plsName, peConnName string) error {
+	if plsName == "" {
+		return ErrMissingPLSName
+	}
+
+	if err := r.client.DeletePrivateEndpointConnection(ctx, resourceGroup, plsName, peConnName); err != nil {
+		return fmt.Errorf("delete PLS PE connection: %w", err)
+	}
+
+	return nil
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index d3bfae79c..0b844955c 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1558,6 +1558,7 @@ sigs.k8s.io/cloud-provider-azure/pkg/azclient/policy/retryrepectthrottled
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/policy/useragent
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/privateendpointclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatelinkserviceclient
+sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatelinkserviceclient/mock_privatelinkserviceclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatezoneclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatezoneclient/mock_privatezoneclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/providerclient
@@ -1583,7 +1584,7 @@ sigs.k8s.io/cloud-provider-azure/pkg/azclient/virtualmachinescalesetvmclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/virtualnetworkclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/virtualnetworklinkclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/virtualnetworklinkclient/mock_virtualnetworklinkclient
-# sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.1
+# sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.3
 ## explicit; go 1.23.1
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader
 # sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatelinkserviceclient/mock_privatelinkserviceclient/interface.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatelinkserviceclient/mock_privatelinkserviceclient/interface.go
new file mode 100644
index 000000000..630b2663e
--- /dev/null
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatelinkserviceclient/mock_privatelinkserviceclient/interface.go
@@ -0,0 +1,131 @@
+// /*
+// 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: privatelinkserviceclient/interface.go
+//
+// Generated by this command:
+//
+//	mockgen -package mock_privatelinkserviceclient -source privatelinkserviceclient/interface.go
+//
+
+// Package mock_privatelinkserviceclient is a generated GoMock package.
+package mock_privatelinkserviceclient
+
+import (
+	context "context"
+	reflect "reflect"
+
+	armnetwork "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
+	gomock "go.uber.org/mock/gomock"
+)
+
+// MockInterface is a mock of Interface interface.
+type MockInterface struct {
+	ctrl     *gomock.Controller
+	recorder *MockInterfaceMockRecorder
+	isgomock struct{}
+}
+
+// MockInterfaceMockRecorder is the mock recorder for MockInterface.
+type MockInterfaceMockRecorder struct {
+	mock *MockInterface
+}
+
+// NewMockInterface creates a new mock instance.
+func NewMockInterface(ctrl *gomock.Controller) *MockInterface {
+	mock := &MockInterface{ctrl: ctrl}
+	mock.recorder = &MockInterfaceMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder {
+	return m.recorder
+}
+
+// CreateOrUpdate mocks base method.
+func (m *MockInterface) CreateOrUpdate(ctx context.Context, resourceGroupName, resourceName string, resourceParam armnetwork.PrivateLinkService) (*armnetwork.PrivateLinkService, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateOrUpdate", ctx, resourceGroupName, resourceName, resourceParam)
+	ret0, _ := ret[0].(*armnetwork.PrivateLinkService)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateOrUpdate indicates an expected call of CreateOrUpdate.
+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, 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)
+}
+
+// DeletePrivateEndpointConnection mocks base method.
+func (m *MockInterface) DeletePrivateEndpointConnection(ctx context.Context, resourceGroupName, serviceName, peConnectionName string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DeletePrivateEndpointConnection", ctx, resourceGroupName, serviceName, peConnectionName)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// DeletePrivateEndpointConnection indicates an expected call of DeletePrivateEndpointConnection.
+func (mr *MockInterfaceMockRecorder) DeletePrivateEndpointConnection(ctx, resourceGroupName, serviceName, peConnectionName any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePrivateEndpointConnection", reflect.TypeOf((*MockInterface)(nil).DeletePrivateEndpointConnection), ctx, resourceGroupName, serviceName, peConnectionName)
+}
+
+// Get mocks base method.
+func (m *MockInterface) Get(ctx context.Context, resourceGroupName, resourceName string, expand *string) (*armnetwork.PrivateLinkService, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Get", ctx, resourceGroupName, resourceName, expand)
+	ret0, _ := ret[0].(*armnetwork.PrivateLinkService)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Get indicates an expected call of Get.
+func (mr *MockInterfaceMockRecorder) Get(ctx, resourceGroupName, resourceName, expand any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockInterface)(nil).Get), ctx, resourceGroupName, resourceName, expand)
+}
+
+// List mocks base method.
+func (m *MockInterface) List(ctx context.Context, resourceGroupName string) ([]*armnetwork.PrivateLinkService, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "List", ctx, resourceGroupName)
+	ret0, _ := ret[0].([]*armnetwork.PrivateLinkService)
+	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, "List", reflect.TypeOf((*MockInterface)(nil).List), ctx, resourceGroupName)
+}


Test patch:
diff --git a/pkg/provider/azure_loadbalancer_test.go b/pkg/provider/azure_loadbalancer_test.go
index 83eb8acb6..ca8b3ffb0 100644
--- a/pkg/provider/azure_loadbalancer_test.go
+++ b/pkg/provider/azure_loadbalancer_test.go
@@ -28,15 +28,14 @@ import (
 	"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/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"
 	"github.com/stretchr/testify/assert"
-
 	"go.uber.org/mock/gomock"
-
 	"golang.org/x/text/cases"
 	"golang.org/x/text/language"
-
 	coordinationv1 "k8s.io/api/coordination/v1"
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -48,11 +47,11 @@ import (
 	"k8s.io/utils/ptr"
 
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/loadbalancerclient/mockloadbalancerclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/privatelinkserviceclient/mockprivatelinkserviceclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/publicipclient/mockpublicipclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/subnetclient/mocksubnetclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/vmssclient/mockvmssclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/privatelinkservice"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/zone"
 	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
 	utilsets "sigs.k8s.io/cloud-provider-azure/pkg/util/sets"
@@ -756,9 +755,9 @@ func TestEnsureLoadBalancerDeleted(t *testing.T) {
 		expectedLBs := make([]network.LoadBalancer, 0)
 		setMockLBs(az, ctrl, &expectedLBs, "service", 1, i+1, c.isInternalSvc)
 
-		mockPLSClient := mockprivatelinkserviceclient.NewMockInterface(ctrl)
-		mockPLSClient.EXPECT().List(gomock.Any(), az.Config.ResourceGroup).Return([]network.PrivateLinkService{}, nil).MaxTimes(2)
-		az.PrivateLinkServiceClient = mockPLSClient
+		mockPLSRepo := privatelinkservice.NewMockRepository(ctrl)
+		mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil).AnyTimes()
+		az.plsRepo = mockPLSRepo
 
 		// create the service first.
 		lbStatus, err := az.EnsureLoadBalancer(context.TODO(), testClusterName, &service, clusterResources.nodes)
@@ -1888,7 +1887,6 @@ func TestGetServiceLoadBalancerMultiSLB(t *testing.T) {
 			cloud := GetTestCloud(ctrl)
 			cloud.LoadBalancerSku = "Standard"
 			cloud.MultipleStandardLoadBalancerConfigurations = tc.multiSLBConfigs
-			cloud.plsCache, _ = cloud.newPLSCache()
 			lbClient := mockloadbalancerclient.NewMockInterface(ctrl)
 			lbClient.EXPECT().Delete(gomock.Any(), gomock.Any(), "lb1-internal").MaxTimes(1)
 			lbClient.EXPECT().DeleteLBBackendPool(gomock.Any(), gomock.Any(), "lb1", "default-test1").Return(nil).MaxTimes(1)
@@ -1896,9 +1894,8 @@ func TestGetServiceLoadBalancerMultiSLB(t *testing.T) {
 			lbClient.EXPECT().CreateOrUpdate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).MaxTimes(1)
 			cloud.LoadBalancerClient = lbClient
 
-			expectedPLS := make([]network.PrivateLinkService, 0)
-			mockPLSClient := cloud.PrivateLinkServiceClient.(*mockprivatelinkserviceclient.MockInterface)
-			mockPLSClient.EXPECT().List(gomock.Any(), gomock.Any()).Return(expectedPLS, nil)
+			mockPLSRepo := cloud.plsRepo.(*privatelinkservice.MockRepository)
+			mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil)
 
 			mockPIPClient := mockpublicipclient.NewMockInterface(ctrl)
 			mockPIPClient.EXPECT().List(gomock.Any(), gomock.Any()).Return([]network.PublicIPAddress{}, nil).MaxTimes(2)
@@ -2039,11 +2036,6 @@ func TestGetServiceLoadBalancerCommon(t *testing.T) {
 			mockLBsClient.EXPECT().Delete(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
 			az.LoadBalancerClient = mockLBsClient
 
-			expectedPLS := make([]network.PrivateLinkService, 0)
-			mockPLSClient := mockprivatelinkserviceclient.NewMockInterface(ctrl)
-			mockPLSClient.EXPECT().List(gomock.Any(), "rg").Return(expectedPLS, nil).MaxTimes(1)
-			az.PrivateLinkServiceClient = mockPLSClient
-
 			for _, existingLB := range test.existingLBs {
 				err := az.LoadBalancerClient.CreateOrUpdate(context.TODO(), "rg", *existingLB.Name, existingLB, "")
 				assert.NoError(t, err.Error())
@@ -6188,9 +6180,8 @@ func TestRemoveFrontendIPConfigurationFromLoadBalancerDelete(t *testing.T) {
 		cloud := GetTestCloud(ctrl)
 		mockLBClient := cloud.LoadBalancerClient.(*mockloadbalancerclient.MockInterface)
 		mockLBClient.EXPECT().Delete(gomock.Any(), "rg", "lb").Return(nil)
-		expectedPLS := make([]network.PrivateLinkService, 0)
-		mockPLSClient := cloud.PrivateLinkServiceClient.(*mockprivatelinkserviceclient.MockInterface)
-		mockPLSClient.EXPECT().List(gomock.Any(), "rg").Return(expectedPLS, nil).MaxTimes(1)
+		mockPLSRepo := cloud.plsRepo.(*privatelinkservice.MockRepository)
+		mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil)
 		existingLBs := []network.LoadBalancer{{Name: ptr.To("lb")}}
 		_, err := cloud.removeFrontendIPConfigurationFromLoadBalancer(context.TODO(), &lb, &existingLBs, []*network.FrontendIPConfiguration{fip}, "testCluster", &service)
 		assert.NoError(t, err)
@@ -6220,9 +6211,8 @@ func TestRemoveFrontendIPConfigurationFromLoadBalancerUpdate(t *testing.T) {
 		cloud := GetTestCloud(ctrl)
 		mockLBClient := cloud.LoadBalancerClient.(*mockloadbalancerclient.MockInterface)
 		mockLBClient.EXPECT().CreateOrUpdate(gomock.Any(), "rg", "lb", gomock.Any(), gomock.Any()).Return(nil)
-		expectedPLS := make([]network.PrivateLinkService, 0)
-		mockPLSClient := cloud.PrivateLinkServiceClient.(*mockprivatelinkserviceclient.MockInterface)
-		mockPLSClient.EXPECT().List(gomock.Any(), "rg").Return(expectedPLS, nil).MaxTimes(1)
+		mockPLSRepo := cloud.plsRepo.(*privatelinkservice.MockRepository)
+		mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil)
 		_, err := cloud.removeFrontendIPConfigurationFromLoadBalancer(context.TODO(), &lb, &[]network.LoadBalancer{}, []*network.FrontendIPConfiguration{fip}, "testCluster", &service)
 		assert.NoError(t, err)
 	})
diff --git a/pkg/provider/azure_privatelinkservice_repo_test.go b/pkg/provider/azure_privatelinkservice_repo_test.go
deleted file mode 100644
index 22b337cd2..000000000
--- a/pkg/provider/azure_privatelinkservice_repo_test.go
+++ /dev/null
@@ -1,151 +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"
-
-	v1 "k8s.io/api/core/v1"
-	"k8s.io/utils/ptr"
-
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/privatelinkserviceclient/mockprivatelinkserviceclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/cache"
-	azcache "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 TestCreateOrUpdatePLS(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.pipCache.Set("rg*frontendID", "test")
-
-		mockPLSClient := az.PrivateLinkServiceClient.(*mockprivatelinkserviceclient.MockInterface)
-		mockPLSClient.EXPECT().CreateOrUpdate(gomock.Any(), "rg", gomock.Any(), gomock.Any(), gomock.Any()).Return(test.clientErr)
-		mockPLSClient.EXPECT().List(gomock.Any(), az.ResourceGroup).Return([]network.PrivateLinkService{}, nil)
-
-		err := az.CreateOrUpdatePLS(&v1.Service{}, "rg", network.PrivateLinkService{
-			Name: ptr.To("pls"),
-			Etag: ptr.To("etag"),
-			PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-				LoadBalancerFrontendIPConfigurations: &[]network.FrontendIPConfiguration{
-					{
-						ID: ptr.To("frontendID"),
-					},
-				},
-			},
-		})
-		assert.EqualError(t, test.expectedErr, err.Error())
-
-		// loadbalancer should be removed from cache if the etag is mismatch or the operation is canceled
-		pls, err := az.plsCache.GetWithDeepCopy(context.TODO(), "rg*frontendID", cache.CacheReadTypeDefault)
-		assert.NoError(t, err)
-		assert.Equal(t, consts.PrivateLinkServiceNotExistID, *pls.(*network.PrivateLinkService).ID)
-	}
-}
-
-func TestDeletePLS(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	az := GetTestCloud(ctrl)
-	mockPLSClient := az.PrivateLinkServiceClient.(*mockprivatelinkserviceclient.MockInterface)
-	mockPLSClient.EXPECT().Delete(gomock.Any(), "rg", "pls").Return(&retry.Error{HTTPStatusCode: http.StatusInternalServerError})
-
-	err := az.DeletePLS(&v1.Service{}, "rg", "pls", "frontendID")
-	assert.EqualError(t, fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 500, RawError: %w", error(nil)), fmt.Sprintf("%s", err.Error()))
-}
-
-func TestDeletePEConn(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	az := GetTestCloud(ctrl)
-	mockPLSClient := az.PrivateLinkServiceClient.(*mockprivatelinkserviceclient.MockInterface)
-	mockPLSClient.EXPECT().DeletePEConnection(gomock.Any(), "rg", "pls", "peConn").Return(&retry.Error{HTTPStatusCode: http.StatusInternalServerError})
-
-	err := az.DeletePEConn(&v1.Service{}, "rg", "pls", "peConn")
-	assert.EqualError(t, fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 500, RawError: %w", error(nil)), fmt.Sprintf("%s", err.Error()))
-}
-
-func TestGetPrivateLinkService(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	az := GetTestCloud(ctrl)
-	az.plsCache.Set("rg*frontendID", &network.PrivateLinkService{Name: ptr.To("pls")})
-
-	// cache hit
-	pls, err := az.getPrivateLinkService(context.TODO(), "rg", ptr.To("frontendID"), azcache.CacheReadTypeDefault)
-	assert.NoError(t, err)
-	assert.Equal(t, "pls", *pls.Name)
-
-	// cache miss
-	mockPLSClient := az.PrivateLinkServiceClient.(*mockprivatelinkserviceclient.MockInterface)
-	mockPLSClient.EXPECT().List(gomock.Any(), "rg1").Return([]network.PrivateLinkService{
-		{
-			Name: ptr.To("pls1"),
-			PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-				LoadBalancerFrontendIPConfigurations: &[]network.FrontendIPConfiguration{
-					{
-						ID: ptr.To("frontendID1"),
-					},
-				},
-			},
-		},
-	}, nil)
-	pls, err = az.getPrivateLinkService(context.TODO(), "rg1", ptr.To("frontendID1"), azcache.CacheReadTypeDefault)
-	assert.NoError(t, err)
-	assert.Equal(t, "pls1", *pls.Name)
-}
-
-func TestGetPLSCacheKey(t *testing.T) {
-	rg, frontendID := "rg", "/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Network/loadBalancers/lb/frontendIPConfigurations/ipconfig"
-	assert.Equal(t, "rg*/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Network/loadBalancers/lb/frontendIPConfigurations/ipconfig", getPLSCacheKey(rg, frontendID))
-}
-
-func TestParsePLSCacheKey(t *testing.T) {
-	key := "rg*/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Network/loadBalancers/lb/frontendIPConfigurations/ipconfig"
-	rg, frontendID := parsePLSCacheKey(key)
-	assert.Equal(t, "rg", rg)
-	assert.Equal(t, "/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Network/loadBalancers/lb/frontendIPConfigurations/ipconfig", frontendID)
-}
diff --git a/pkg/provider/azure_privatelinkservice_test.go b/pkg/provider/azure_privatelinkservice_test.go
index 15c518280..3de34e9e2 100644
--- a/pkg/provider/azure_privatelinkservice_test.go
+++ b/pkg/provider/azure_privatelinkservice_test.go
@@ -22,18 +22,19 @@ import (
 	"strings"
 	"testing"
 
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
+	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
 	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
 	"github.com/stretchr/testify/assert"
-
 	"go.uber.org/mock/gomock"
-
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/ptr"
 
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/privatelinkserviceclient/mockprivatelinkserviceclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/subnetclient/mocksubnetclient"
+	"sigs.k8s.io/cloud-provider-azure/pkg/cache"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/privatelinkservice"
 	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
 )
 
@@ -48,9 +49,9 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 		expectedSubnetGet bool
 		existingSubnet    *network.Subnet
 		expectedPLSList   bool
-		existingPLSList   []network.PrivateLinkService
+		existingPLSList   []*armnetwork.PrivateLinkService
 		expectedPLSCreate bool
-		expectedPLS       *network.PrivateLinkService
+		expectedPLS       *armnetwork.PrivateLinkService
 		expectedPLSDelete bool
 		expectedError     bool
 	}{
@@ -82,9 +83,9 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 				},
 			},
 			expectedPLSList:   true,
-			existingPLSList:   []network.PrivateLinkService{},
+			existingPLSList:   []*armnetwork.PrivateLinkService{},
 			expectedPLSCreate: true,
-			expectedPLS:       &network.PrivateLinkService{Name: ptr.To("pls-fipConfig")},
+			expectedPLS:       &armnetwork.PrivateLinkService{Name: ptr.To("pls-fipConfig")},
 		},
 		{
 			desc: "reconcilePrivateLinkService should create a new PLS if no existing PLS attached to the LB frontend",
@@ -103,9 +104,9 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 				},
 			},
 			expectedPLSList:   true,
-			existingPLSList:   []network.PrivateLinkService{},
+			existingPLSList:   []*armnetwork.PrivateLinkService{},
 			expectedPLSCreate: true,
-			expectedPLS:       &network.PrivateLinkService{Name: ptr.To("testpls")},
+			expectedPLS:       &armnetwork.PrivateLinkService{Name: ptr.To("testpls")},
 		},
 		{
 			desc: "reconcilePrivateLinkService should report error if existing PLS attached to LB frontEnd is unmanaged",
@@ -116,18 +117,18 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 			},
 			wantPLS:         true,
 			expectedPLSList: true,
-			existingPLSList: []network.PrivateLinkService{
+			existingPLSList: []*armnetwork.PrivateLinkService{
 				{
 					Name: ptr.To("testpls"),
-					PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-						LoadBalancerFrontendIPConfigurations: &[]network.FrontendIPConfiguration{{ID: ptr.To("fipConfigID")}},
-						IPConfigurations: &[]network.PrivateLinkServiceIPConfiguration{
+					Properties: &armnetwork.PrivateLinkServiceProperties{
+						LoadBalancerFrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{{ID: ptr.To("fipConfigID")}},
+						IPConfigurations: []*armnetwork.PrivateLinkServiceIPConfiguration{
 							{
-								PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-									PrivateIPAllocationMethod: network.Dynamic,
-									Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+								Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+									PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+									Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 									Primary:                   ptr.To(true),
-									PrivateIPAddressVersion:   network.IPv4,
+									PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 								},
 							},
 						},
@@ -145,18 +146,18 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 			},
 			wantPLS:         true,
 			expectedPLSList: true,
-			existingPLSList: []network.PrivateLinkService{
+			existingPLSList: []*armnetwork.PrivateLinkService{
 				{
 					Name: ptr.To("testpls"),
-					PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-						LoadBalancerFrontendIPConfigurations: &[]network.FrontendIPConfiguration{{ID: ptr.To("fipConfigID")}},
-						IPConfigurations: &[]network.PrivateLinkServiceIPConfiguration{
+					Properties: &armnetwork.PrivateLinkServiceProperties{
+						LoadBalancerFrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{{ID: ptr.To("fipConfigID")}},
+						IPConfigurations: []*armnetwork.PrivateLinkServiceIPConfiguration{
 							{
-								PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-									PrivateIPAllocationMethod: network.Dynamic,
-									Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+								Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+									PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+									Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 									Primary:                   ptr.To(true),
-									PrivateIPAddressVersion:   network.IPv4,
+									PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 								},
 							},
 						},
@@ -177,19 +178,19 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 			},
 			wantPLS:         true,
 			expectedPLSList: true,
-			existingPLSList: []network.PrivateLinkService{
+			existingPLSList: []*armnetwork.PrivateLinkService{
 				{
 					Name: ptr.To("testpls"),
-					PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-						LoadBalancerFrontendIPConfigurations: &[]network.FrontendIPConfiguration{{ID: ptr.To("fipConfigID")}},
-						IPConfigurations: &[]network.PrivateLinkServiceIPConfiguration{
+					Properties: &armnetwork.PrivateLinkServiceProperties{
+						LoadBalancerFrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{{ID: ptr.To("fipConfigID")}},
+						IPConfigurations: []*armnetwork.PrivateLinkServiceIPConfiguration{
 							{
-								PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-									PrivateIPAllocationMethod: network.Static,
+								Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+									PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodStatic),
 									PrivateIPAddress:          ptr.To("10.2.0.4"),
-									Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+									Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 									Primary:                   ptr.To(true),
-									PrivateIPAddressVersion:   network.IPv4,
+									PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 								},
 							},
 						},
@@ -218,18 +219,18 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 				},
 			},
 			expectedPLSList: true,
-			existingPLSList: []network.PrivateLinkService{
+			existingPLSList: []*armnetwork.PrivateLinkService{
 				{
 					Name: ptr.To("testpls"),
-					PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-						LoadBalancerFrontendIPConfigurations: &[]network.FrontendIPConfiguration{{ID: ptr.To("fipConfigID")}},
-						IPConfigurations: &[]network.PrivateLinkServiceIPConfiguration{
+					Properties: &armnetwork.PrivateLinkServiceProperties{
+						LoadBalancerFrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{{ID: ptr.To("fipConfigID")}},
+						IPConfigurations: []*armnetwork.PrivateLinkServiceIPConfiguration{
 							{
-								PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-									PrivateIPAllocationMethod: network.Dynamic,
-									Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+								Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+									PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+									Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 									Primary:                   ptr.To(true),
-									PrivateIPAddressVersion:   network.IPv4,
+									PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 								},
 							},
 						},
@@ -259,18 +260,18 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 				},
 			},
 			expectedPLSList: true,
-			existingPLSList: []network.PrivateLinkService{
+			existingPLSList: []*armnetwork.PrivateLinkService{
 				{
 					Name: ptr.To("testpls"),
-					PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-						LoadBalancerFrontendIPConfigurations: &[]network.FrontendIPConfiguration{{ID: ptr.To("fipConfigID")}},
-						IPConfigurations: &[]network.PrivateLinkServiceIPConfiguration{
+					Properties: &armnetwork.PrivateLinkServiceProperties{
+						LoadBalancerFrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{{ID: ptr.To("fipConfigID")}},
+						IPConfigurations: []*armnetwork.PrivateLinkServiceIPConfiguration{
 							{
-								PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-									PrivateIPAllocationMethod: network.Dynamic,
-									Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+								Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+									PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+									Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 									Primary:                   ptr.To(true),
-									PrivateIPAddressVersion:   network.IPv4,
+									PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 								},
 							},
 						},
@@ -282,7 +283,7 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 				},
 			},
 			expectedPLSCreate: true,
-			expectedPLS:       &network.PrivateLinkService{Name: ptr.To("testpls")},
+			expectedPLS:       &armnetwork.PrivateLinkService{Name: ptr.To("testpls")},
 		},
 		{
 			desc: "reconcilePrivateLinkService should not do anything if no existing PLS attached to the LB frontend when deleting",
@@ -292,11 +293,11 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 				consts.ServiceAnnotationPLSName:              "testpls",
 			},
 			expectedPLSList: true,
-			existingPLSList: []network.PrivateLinkService{
+			existingPLSList: []*armnetwork.PrivateLinkService{
 				{
 					Name: ptr.To("testpls"),
-					PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-						LoadBalancerFrontendIPConfigurations: &[]network.FrontendIPConfiguration{{ID: ptr.To("fipConfigID2")}},
+					Properties: &armnetwork.PrivateLinkServiceProperties{
+						LoadBalancerFrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{{ID: ptr.To("fipConfigID2")}},
 					},
 				},
 			},
@@ -309,11 +310,11 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 				consts.ServiceAnnotationPLSName:              "testpls",
 			},
 			expectedPLSList: true,
-			existingPLSList: []network.PrivateLinkService{
+			existingPLSList: []*armnetwork.PrivateLinkService{
 				{
 					Name: ptr.To("testpls"),
-					PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-						LoadBalancerFrontendIPConfigurations: &[]network.FrontendIPConfiguration{{ID: ptr.To("fipConfigID")}},
+					Properties: &armnetwork.PrivateLinkServiceProperties{
+						LoadBalancerFrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{{ID: ptr.To("fipConfigID")}},
 					},
 				},
 			},
@@ -340,21 +341,29 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 			clusterName := testClusterName
 
 			mockSubnetsClient := az.SubnetsClient.(*mocksubnetclient.MockInterface)
-			mockPLSsClient := az.PrivateLinkServiceClient.(*mockprivatelinkserviceclient.MockInterface)
+			mockPLSRepo := az.plsRepo.(*privatelinkservice.MockRepository)
 			if test.expectedSubnetGet {
 				mockSubnetsClient.EXPECT().Get(gomock.Any(), "rg", "vnet", "subnet", "").Return(*test.existingSubnet, nil).MaxTimes(2)
 			}
 			if test.expectedPLSList {
-				mockPLSsClient.EXPECT().List(gomock.Any(), "rg").Return(test.existingPLSList, nil).MaxTimes(1)
+				mockPLSRepo.EXPECT().Get(gomock.Any(), "rg", *fipConfig.ID, gomock.Any()).DoAndReturn(func(_ context.Context, _, frontendIPConfigID string, _ cache.AzureCacheReadType) (*armnetwork.PrivateLinkService, error) {
+					for _, pls := range test.existingPLSList {
+						if strings.EqualFold(*pls.Properties.LoadBalancerFrontendIPConfigurations[0].ID, frontendIPConfigID) {
+							return pls, nil
+						}
+					}
+					return &armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil
+				}).MaxTimes(1)
+				mockPLSRepo.EXPECT().List(gomock.Any(), "rg").Return(test.existingPLSList, nil).MaxTimes(1)
 			}
 			if test.expectedPLSCreate {
-				mockPLSsClient.EXPECT().CreateOrUpdate(gomock.Any(), "rg", ptr.Deref(test.expectedPLS.Name, ""), gomock.Any(), gomock.Any()).Return(nil).Times(1)
+				mockPLSRepo.EXPECT().CreateOrUpdate(gomock.Any(), "rg", gomock.Any()).Return(nil, nil).Times(1)
 			}
 			if test.expectedPLSDelete {
-				mockPLSsClient.EXPECT().Delete(gomock.Any(), "rg", "testpls").Return(nil).Times(1)
+				mockPLSRepo.EXPECT().Delete(gomock.Any(), "rg", "testpls", *fipConfig.ID).Return(nil).Times(1)
 			}
 			err := az.reconcilePrivateLinkService(context.TODO(), clusterName, &service, fipConfig, test.wantPLS)
-			assert.Equal(t, test.expectedError, err != nil)
+			assert.Equal(t, test.expectedError, err != nil, "error: %v", err)
 		})
 	}
 }
@@ -447,16 +456,16 @@ func TestSafeDeletePLS(t *testing.T) {
 
 	testCases := []struct {
 		desc          string
-		pls           *network.PrivateLinkService
+		pls           *armnetwork.PrivateLinkService
 		expectedError bool
 	}{
 		{
 			desc: "safeDeletePLS shall delete all PE connections and pls itself",
-			pls: &network.PrivateLinkService{
+			pls: &armnetwork.PrivateLinkService{
 				Name: ptr.To("testpls"),
-				PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-					LoadBalancerFrontendIPConfigurations: &[]network.FrontendIPConfiguration{{ID: ptr.To("FipConfigID")}},
-					PrivateEndpointConnections: &[]network.PrivateEndpointConnection{
+				Properties: &armnetwork.PrivateLinkServiceProperties{
+					LoadBalancerFrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{{ID: ptr.To("FipConfigID")}},
+					PrivateEndpointConnections: []*armnetwork.PrivateEndpointConnection{
 						{Name: ptr.To("pe1")},
 						{Name: ptr.To("pe2")},
 					},
@@ -467,12 +476,12 @@ func TestSafeDeletePLS(t *testing.T) {
 
 	for i, test := range testCases {
 		az := GetTestCloud(ctrl)
-		mockPLSsClient := az.PrivateLinkServiceClient.(*mockprivatelinkserviceclient.MockInterface)
-		mockPLSsClient.EXPECT().DeletePEConnection(gomock.Any(), "rg", "testpls", "pe1").Return(nil).Times(1)
-		mockPLSsClient.EXPECT().DeletePEConnection(gomock.Any(), "rg", "testpls", "pe2").Return(nil).Times(1)
-		mockPLSsClient.EXPECT().Delete(gomock.Any(), "rg", "testpls").Return(nil).Times(1)
+		mockPLSRepo := az.plsRepo.(*privatelinkservice.MockRepository)
+		mockPLSRepo.EXPECT().DeletePEConnection(gomock.Any(), "rg", "testpls", "pe1").Return(nil).Times(1)
+		mockPLSRepo.EXPECT().DeletePEConnection(gomock.Any(), "rg", "testpls", "pe2").Return(nil).Times(1)
+		mockPLSRepo.EXPECT().Delete(gomock.Any(), "rg", "testpls", gomock.Any()).Return(nil).Times(1)
 		service := getTestService("test1", v1.ProtocolTCP, nil, false, 80)
-		rerr := az.safeDeletePLS(test.pls, &service)
+		rerr := az.safeDeletePLS(context.Background(), test.pls, &service)
 		assert.Equal(t, test.expectedError, rerr != nil, "TestCase[%d]: %s", i, test.desc)
 	}
 }
@@ -485,14 +494,14 @@ func TestGetPrivateLinkServiceName(t *testing.T) {
 	tests := []struct {
 		desc         string
 		annotations  map[string]string
-		pls          *network.PrivateLinkService
+		pls          *armnetwork.PrivateLinkService
 		fipConfig    *network.FrontendIPConfiguration
 		expectedName string
 		expectedErr  bool
 	}{
 		{
 			desc: "If pls name does not set, sets it as what service configures",
-			pls:  &network.PrivateLinkService{},
+			pls:  &armnetwork.PrivateLinkService{},
 			annotations: map[string]string{
 				consts.ServiceAnnotationPLSName: "testpls",
 			},
@@ -500,7 +509,7 @@ func TestGetPrivateLinkServiceName(t *testing.T) {
 		},
 		{
 			desc: "If pls name does not set, and service does not configure, sets it as default(pls-fipConfigName)",
-			pls:  &network.PrivateLinkService{},
+			pls:  &armnetwork.PrivateLinkService{},
 			fipConfig: &network.FrontendIPConfiguration{
 				Name: ptr.To("fipname"),
 			},
@@ -508,7 +517,7 @@ func TestGetPrivateLinkServiceName(t *testing.T) {
 		},
 		{
 			desc: "If pls name is not equal to service configuration, error should be reported",
-			pls: &network.PrivateLinkService{
+			pls: &armnetwork.PrivateLinkService{
 				Name: ptr.To("testpls"),
 			},
 			annotations: map[string]string{
@@ -518,7 +527,7 @@ func TestGetPrivateLinkServiceName(t *testing.T) {
 		},
 		{
 			desc: "If pls name is same as service configuration, simply return it",
-			pls: &network.PrivateLinkService{
+			pls: &armnetwork.PrivateLinkService{
 				Name: ptr.To("testpls"),
 			},
 			annotations: map[string]string{
@@ -564,7 +573,7 @@ func TestGetExpectedPrivateLinkService(t *testing.T) {
 		plsName := "testPLS"
 		clusterName := testClusterName
 		fipConfig := &network.FrontendIPConfiguration{ID: ptr.To("fipConfigID")}
-		pls := &network.PrivateLinkService{PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{}}
+		pls := &armnetwork.PrivateLinkService{Properties: &armnetwork.PrivateLinkServiceProperties{}}
 		subnetClient := cloud.SubnetsClient.(*mocksubnetclient.MockInterface)
 		subnetClient.EXPECT().Get(gomock.Any(), "rg", "vnet", "subnet", gomock.Any()).Return(
 			network.Subnet{
@@ -578,53 +587,53 @@ func TestGetExpectedPrivateLinkService(t *testing.T) {
 
 		assert.Equal(t, pls.Name, &plsName)
 
-		expectedLBFrontendConfig := &[]network.FrontendIPConfiguration{{ID: fipConfig.ID}}
-		assert.Equal(t, pls.LoadBalancerFrontendIPConfigurations, expectedLBFrontendConfig)
+		expectedLBFrontendConfig := []*armnetwork.FrontendIPConfiguration{{ID: fipConfig.ID}}
+		assert.Equal(t, pls.Properties.LoadBalancerFrontendIPConfigurations, expectedLBFrontendConfig)
 
-		expectedConfigs := []network.PrivateLinkServiceIPConfiguration{
+		expectedConfigs := []*armnetwork.PrivateLinkServiceIPConfiguration{
 			{
 				Name: ptr.To("subnet-testPLS-static-10.2.0.4"),
-				PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-					PrivateIPAllocationMethod: network.Static,
+				Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+					PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodStatic),
 					PrivateIPAddress:          ptr.To("10.2.0.4"),
-					Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+					Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 					Primary:                   ptr.To(true),
-					PrivateIPAddressVersion:   network.IPv4,
+					PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 				},
 			},
 			{
 				Name: ptr.To("subnet-testPLS-static-10.2.0.5"),
-				PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-					PrivateIPAllocationMethod: network.Static,
+				Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+					PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodStatic),
 					PrivateIPAddress:          ptr.To("10.2.0.5"),
-					Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+					Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 					Primary:                   ptr.To(false),
-					PrivateIPAddressVersion:   network.IPv4,
+					PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 				},
 			},
 			{
 				Name: ptr.To("subnet-testPLS-dynamic-0"),
-				PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-					PrivateIPAllocationMethod: network.Dynamic,
-					Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+				Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+					PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+					Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 					Primary:                   ptr.To(false),
-					PrivateIPAddressVersion:   network.IPv4,
+					PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 				},
 			},
 		}
 
-		testSamePLSIpConfigs(t, *pls.IPConfigurations, expectedConfigs)
+		testSamePLSIpConfigs(t, pls.Properties.IPConfigurations, expectedConfigs)
 
-		expectedFqdns := []string{"fqdns1", "fqdns2", "fqdns3"}
-		assert.Equal(t, *pls.Fqdns, expectedFqdns)
+		expectedFqdns := to.SliceOfPtrs("fqdns1", "fqdns2", "fqdns3")
+		assert.Equal(t, expectedFqdns, pls.Properties.Fqdns)
 
-		assert.True(t, *pls.EnableProxyProtocol)
+		assert.True(t, *pls.Properties.EnableProxyProtocol)
 
-		expectedVisibility := []string{"*"}
-		assert.Equal(t, *pls.Visibility.Subscriptions, expectedVisibility)
+		expectedVisibility := to.SliceOfPtrs("*")
+		assert.Equal(t, expectedVisibility, pls.Properties.Visibility.Subscriptions)
 
-		expectedAutoApproval := []string{"sub1", "sub2", "sub3"}
-		assert.Equal(t, *pls.AutoApproval.Subscriptions, expectedAutoApproval)
+		expectedAutoApproval := to.SliceOfPtrs("sub1", "sub2", "sub3")
+		assert.Equal(t, expectedAutoApproval, pls.Properties.AutoApproval.Subscriptions)
 	})
 }
 
@@ -636,8 +645,8 @@ func TestReconcilePLSIpConfigs(t *testing.T) {
 		desc              string
 		annotations       map[string]string
 		plsName           string
-		existingIPConfigs *[]network.PrivateLinkServiceIPConfiguration
-		expectedIPConfigs *[]network.PrivateLinkServiceIPConfiguration
+		existingIPConfigs []*armnetwork.PrivateLinkServiceIPConfiguration
+		expectedIPConfigs []*armnetwork.PrivateLinkServiceIPConfiguration
 		getSubnetError    *retry.Error
 		expectedChanged   bool
 		expectedErr       bool
@@ -664,14 +673,14 @@ func TestReconcilePLSIpConfigs(t *testing.T) {
 		{
 			desc:    "reconcilePLSIpConfigs should change existingPLS if its ipConfig is nil",
 			plsName: "testpls",
-			expectedIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			expectedIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-testpls-dynamic-0"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Dynamic,
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
@@ -683,34 +692,34 @@ func TestReconcilePLSIpConfigs(t *testing.T) {
 			annotations: map[string]string{
 				consts.ServiceAnnotationPLSIpConfigurationIPAddressCount: "2",
 			},
-			existingIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			existingIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-testpls-dynamic-0"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Dynamic,
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
-			expectedIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			expectedIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-testpls-dynamic-0"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Dynamic,
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 				{
 					Name: ptr.To("subnet-testpls-dynamic-1"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Dynamic,
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(false),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
@@ -719,25 +728,25 @@ func TestReconcilePLSIpConfigs(t *testing.T) {
 		{
 			desc:    "reconcilePLSIpConfigs should change existingPLS if its subnetID is different",
 			plsName: "testpls",
-			existingIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			existingIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-testpls-dynamic-0"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Dynamic,
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID1")},
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID1")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
-			expectedIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			expectedIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-testpls-dynamic-0"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Dynamic,
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
@@ -750,35 +759,35 @@ func TestReconcilePLSIpConfigs(t *testing.T) {
 				consts.ServiceAnnotationPLSIpConfigurationIPAddressCount: "2",
 				consts.ServiceAnnotationPLSIpConfigurationIPAddress:      "10.2.0.4",
 			},
-			existingIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			existingIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-testpls-dynamic-0"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Dynamic,
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
-			expectedIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			expectedIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-testpls-static-10.2.0.4"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Static,
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodStatic),
 						PrivateIPAddress:          ptr.To("10.2.0.4"),
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 				{
 					Name: ptr.To("subnet-testpls-dynamic-0"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Dynamic,
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(false),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
@@ -787,26 +796,26 @@ func TestReconcilePLSIpConfigs(t *testing.T) {
 		{
 			desc:    "reconcilePLSIpConfigs should change existingPLS if ip allocation type is changed from static to dynamic",
 			plsName: "testpls",
-			existingIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			existingIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-testpls-static-10.2.0.4"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Static,
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodStatic),
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						PrivateIPAddress:          ptr.To("10.2.0.4"),
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
-			expectedIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			expectedIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-testpls-dynamic-0"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Dynamic,
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
@@ -818,27 +827,27 @@ func TestReconcilePLSIpConfigs(t *testing.T) {
 			annotations: map[string]string{
 				consts.ServiceAnnotationPLSIpConfigurationIPAddress: "10.2.0.5",
 			},
-			existingIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			existingIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-testpls-static-10.2.0.4"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Static,
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodStatic),
 						PrivateIPAddress:          ptr.To("10.2.0.4"),
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
-			expectedIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			expectedIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-testpls-static-10.2.0.5"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Static,
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodStatic),
 						PrivateIPAddress:          ptr.To("10.2.0.5"),
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
@@ -847,25 +856,25 @@ func TestReconcilePLSIpConfigs(t *testing.T) {
 		{
 			desc:    "reconcilePLSIpConfigs should not change existingPLS if ip allocation type is dynamic only",
 			plsName: "testpls",
-			existingIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			existingIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-testpls-dynamic-0"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Dynamic,
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
-			expectedIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			expectedIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-testpls-dynamic-0"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Dynamic,
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
@@ -876,27 +885,27 @@ func TestReconcilePLSIpConfigs(t *testing.T) {
 			annotations: map[string]string{
 				consts.ServiceAnnotationPLSIpConfigurationIPAddress: "10.2.0.5",
 			},
-			existingIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			existingIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-testpls-static-10.2.0.5"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Static,
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodStatic),
 						PrivateIPAddress:          ptr.To("10.2.0.5"),
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
-			expectedIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			expectedIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-testpls-static-10.2.0.5"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Static,
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodStatic),
 						PrivateIPAddress:          ptr.To("10.2.0.5"),
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
@@ -908,25 +917,25 @@ func TestReconcilePLSIpConfigs(t *testing.T) {
 				consts.ServiceAnnotationPLSIpConfigurationIPAddress:      "10.2.0.5",
 				consts.ServiceAnnotationPLSIpConfigurationIPAddressCount: "2",
 			},
-			existingIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{},
-			expectedIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			existingIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{},
+			expectedIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-" + strings.Repeat("12345678", 7) + "1" + "-static-10.2.0.5"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Static,
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodStatic),
 						PrivateIPAddress:          ptr.To("10.2.0.5"),
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 				{
 					Name: ptr.To("subnet-" + strings.Repeat("12345678", 7) + "1234567" + "-dynamic-0"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Dynamic,
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(false),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
@@ -939,45 +948,45 @@ func TestReconcilePLSIpConfigs(t *testing.T) {
 				consts.ServiceAnnotationPLSIpConfigurationIPAddress:      "10.2.0.5",
 				consts.ServiceAnnotationPLSIpConfigurationIPAddressCount: "2",
 			},
-			existingIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			existingIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-" + strings.Repeat("12345678", 7) + "1" + "-static-10.2.0.5"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Static,
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodStatic),
 						PrivateIPAddress:          ptr.To("10.2.0.5"),
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 				{
 					Name: ptr.To("subnet-" + strings.Repeat("12345678", 7) + "1234567" + "-dynamic-0"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Dynamic,
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(false),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
-			expectedIPConfigs: &[]network.PrivateLinkServiceIPConfiguration{
+			expectedIPConfigs: []*armnetwork.PrivateLinkServiceIPConfiguration{
 				{
 					Name: ptr.To("subnet-" + strings.Repeat("12345678", 7) + "1" + "-static-10.2.0.5"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Static,
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodStatic),
 						PrivateIPAddress:          ptr.To("10.2.0.5"),
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(true),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 				{
 					Name: ptr.To("subnet-" + strings.Repeat("12345678", 7) + "1234567" + "-dynamic-0"),
-					PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{
-						PrivateIPAllocationMethod: network.Dynamic,
-						Subnet:                    &network.Subnet{ID: ptr.To("subnetID")},
+					Properties: &armnetwork.PrivateLinkServiceIPConfigurationProperties{
+						PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic),
+						Subnet:                    &armnetwork.Subnet{ID: ptr.To("subnetID")},
 						Primary:                   ptr.To(false),
-						PrivateIPAddressVersion:   network.IPv4,
+						PrivateIPAddressVersion:   to.Ptr(armnetwork.IPVersionIPv4),
 					},
 				},
 			},
@@ -991,9 +1000,9 @@ func TestReconcilePLSIpConfigs(t *testing.T) {
 				Annotations: test.annotations,
 			},
 		}
-		pls := &network.PrivateLinkService{
+		pls := &armnetwork.PrivateLinkService{
 			Name: ptr.To(test.plsName),
-			PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
+			Properties: &armnetwork.PrivateLinkServiceProperties{
 				IPConfigurations: test.existingIPConfigs,
 			},
 		}
@@ -1009,21 +1018,30 @@ func TestReconcilePLSIpConfigs(t *testing.T) {
 			assert.Error(t, err, "TestCase[%d]: %s", i, test.desc)
 		} else {
 			assert.Equal(t, test.expectedChanged, changed, "TestCase[%d]: %s", i, test.desc)
-			testSamePLSIpConfigs(t, *pls.IPConfigurations, *test.expectedIPConfigs)
+			testSamePLSIpConfigs(t, pls.Properties.IPConfigurations, test.expectedIPConfigs)
 		}
 	}
 }
 
-func testSamePLSIpConfigs(t *testing.T, actual []network.PrivateLinkServiceIPConfiguration, expected []network.PrivateLinkServiceIPConfiguration) {
-	actualIPConfigs := make(map[string]network.PrivateLinkServiceIPConfiguration)
-	expectedIPConfigs := make(map[string]network.PrivateLinkServiceIPConfiguration)
+func testSamePLSIpConfigs(t *testing.T, actual []*armnetwork.PrivateLinkServiceIPConfiguration, expected []*armnetwork.PrivateLinkServiceIPConfiguration) {
+	t.Helper()
+	actualIPConfigs := make(map[string]armnetwork.PrivateLinkServiceIPConfiguration)
+	expectedIPConfigs := make(map[string]armnetwork.PrivateLinkServiceIPConfiguration)
 	for _, ipConfig := range actual {
-		actualIPConfigs[ptr.Deref(ipConfig.Name, "")] = ipConfig
+		actualIPConfigs[ptr.Deref(ipConfig.Name, "")] = *ipConfig
 	}
 	for _, ipConfig := range expected {
-		expectedIPConfigs[ptr.Deref(ipConfig.Name, "")] = ipConfig
+		expectedIPConfigs[ptr.Deref(ipConfig.Name, "")] = *ipConfig
 	}
-	assert.Equal(t, actualIPConfigs, expectedIPConfigs)
+
+	for name, expectedIPConfig := range expectedIPConfigs {
+		actualIPConfig, ok := actualIPConfigs[name]
+		assert.True(t, ok, "Expected IPConfig %s not found", name)
+		assert.Equal(t, expectedIPConfig, actualIPConfig, "IPConfig %s not equal", name)
+		delete(actualIPConfigs, name)
+	}
+
+	assert.Empty(t, actualIPConfigs)
 }
 
 func TestServiceRequiresPLS(t *testing.T) {
@@ -1065,15 +1083,15 @@ func TestReconcilePLSEnableProxyProtocol(t *testing.T) {
 	tests := []struct {
 		desc            string
 		annotations     map[string]string
-		pls             *network.PrivateLinkService
+		pls             *armnetwork.PrivateLinkService
 		expectedChanged bool
 		expectedEnabled *bool
 	}{
 		{
 			desc:        "empty service enableProxyProto and empty pls enableProxyProto should not trigger any change",
 			annotations: map[string]string{},
-			pls: &network.PrivateLinkService{
-				PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{},
+			pls: &armnetwork.PrivateLinkService{
+				Properties: &armnetwork.PrivateLinkServiceProperties{},
 			},
 		},
 		{
@@ -1081,8 +1099,8 @@ func TestReconcilePLSEnableProxyProtocol(t *testing.T) {
 			annotations: map[string]string{
 				consts.ServiceAnnotationPLSProxyProtocol: "False",
 			},
-			pls: &network.PrivateLinkService{
-				PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{},
+			pls: &armnetwork.PrivateLinkService{
+				Properties: &armnetwork.PrivateLinkServiceProperties{},
 			},
 		},
 		{
@@ -1090,8 +1108,8 @@ func TestReconcilePLSEnableProxyProtocol(t *testing.T) {
 			annotations: map[string]string{
 				consts.ServiceAnnotationPLSProxyProtocol: "False",
 			},
-			pls: &network.PrivateLinkService{
-				PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
+			pls: &armnetwork.PrivateLinkService{
+				Properties: &armnetwork.PrivateLinkServiceProperties{
 					EnableProxyProtocol: ptr.To(false),
 				},
 			},
@@ -1102,8 +1120,8 @@ func TestReconcilePLSEnableProxyProtocol(t *testing.T) {
 			annotations: map[string]string{
 				consts.ServiceAnnotationPLSProxyProtocol: "True",
 			},
-			pls: &network.PrivateLinkService{
-				PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
+			pls: &armnetwork.PrivateLinkService{
+				Properties: &armnetwork.PrivateLinkServiceProperties{
 					EnableProxyProtocol: ptr.To(true),
 				},
 			},
@@ -1114,8 +1132,8 @@ func TestReconcilePLSEnableProxyProtocol(t *testing.T) {
 			annotations: map[string]string{
 				consts.ServiceAnnotationPLSProxyProtocol: "True",
 			},
-			pls: &network.PrivateLinkService{
-				PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{},
+			pls: &armnetwork.PrivateLinkService{
+				Properties: &armnetwork.PrivateLinkServiceProperties{},
 			},
 			expectedEnabled: ptr.To(true),
 			expectedChanged: true,
@@ -1125,8 +1143,8 @@ func TestReconcilePLSEnableProxyProtocol(t *testing.T) {
 			annotations: map[string]string{
 				consts.ServiceAnnotationPLSProxyProtocol: "False",
 			},
-			pls: &network.PrivateLinkService{
-				PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
+			pls: &armnetwork.PrivateLinkService{
+				Properties: &armnetwork.PrivateLinkServiceProperties{
 					EnableProxyProtocol: ptr.To(true),
 				},
 			},
@@ -1139,7 +1157,7 @@ func TestReconcilePLSEnableProxyProtocol(t *testing.T) {
 		s.Annotations = test.annotations
 		changed := reconcilePLSEnableProxyProtocol(test.pls, s)
 		assert.Equal(t, test.expectedChanged, changed, "TestCase[%d]: %s", i, test.desc)
-		assert.Equal(t, test.expectedEnabled, test.pls.EnableProxyProtocol, "TestCase[%d]: %s", i, test.desc)
+		assert.Equal(t, test.expectedEnabled, test.pls.Properties.EnableProxyProtocol, "TestCase[%d]: %s", i, test.desc)
 	}
 }
 
@@ -1147,15 +1165,15 @@ func TestReconcilePLSFqdn(t *testing.T) {
 	tests := []struct {
 		desc            string
 		annotations     map[string]string
-		pls             *network.PrivateLinkService
+		pls             *armnetwork.PrivateLinkService
 		expectedChanged bool
-		expectedfqdns   *[]string
+		expectedFQDNs   []*string
 	}{
 		{
 			desc:        "Empty service fqdns + empty pls fqdns should not trigger any change",
 			annotations: map[string]string{},
-			pls: &network.PrivateLinkService{
-				PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{},
+			pls: &armnetwork.PrivateLinkService{
+				Properties: &armnetwork.PrivateLinkServiceProperties{},
 			},
 		},
 		{
@@ -1163,49 +1181,49 @@ func TestReconcilePLSFqdn(t *testing.T) {
 			annotations: map[string]string{
 				consts.ServiceAnnotationPLSFqdns: "fqdns1 fqdns2 fqdns3",
 			},
-			pls: &network.PrivateLinkService{
-				PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-					Fqdns: &[]string{"fqdns2", "fqdns3", "fqdns1"},
+			pls: &armnetwork.PrivateLinkService{
+				Properties: &armnetwork.PrivateLinkServiceProperties{
+					Fqdns: to.SliceOfPtrs("fqdns2", "fqdns3", "fqdns1"),
 				},
 			},
-			expectedfqdns: &[]string{"fqdns2", "fqdns3", "fqdns1"},
+			expectedFQDNs: to.SliceOfPtrs("fqdns2", "fqdns3", "fqdns1"),
 		},
 		{
 			desc: "fqdns should be changed according to service - 0",
 			annotations: map[string]string{
 				consts.ServiceAnnotationPLSFqdns: "",
 			},
-			pls: &network.PrivateLinkService{
-				PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-					Fqdns: &[]string{"fqdns2", "fqdns3", "fqdns1"},
+			pls: &armnetwork.PrivateLinkService{
+				Properties: &armnetwork.PrivateLinkServiceProperties{
+					Fqdns: to.SliceOfPtrs("fqdns2", "fqdns3", "fqdns1"),
 				},
 			},
 			expectedChanged: true,
-			expectedfqdns:   &[]string{},
+			expectedFQDNs:   []*string{},
 		},
 		{
 			desc: "fqdns should be changed according to service - 1",
 			annotations: map[string]string{
 				consts.ServiceAnnotationPLSFqdns: "fqdns1 fqdns2",
 			},
-			pls: &network.PrivateLinkService{
-				PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{},
+			pls: &armnetwork.PrivateLinkService{
+				Properties: &armnetwork.PrivateLinkServiceProperties{},
 			},
 			expectedChanged: true,
-			expectedfqdns:   &[]string{"fqdns1", "fqdns2"},
+			expectedFQDNs:   to.SliceOfPtrs("fqdns1", "fqdns2"),
 		},
 		{
 			desc: "fqdns should be changed according to service - 2",
 			annotations: map[string]string{
 				consts.ServiceAnnotationPLSFqdns: "fqdns1 fqdns2",
 			},
-			pls: &network.PrivateLinkService{
-				PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-					Fqdns: &[]string{"fqdns2", "fqdns3", "fqdns1"},
+			pls: &armnetwork.PrivateLinkService{
+				Properties: &armnetwork.PrivateLinkServiceProperties{
+					Fqdns: to.SliceOfPtrs("fqdns2", "fqdns3", "fqdns1"),
 				},
 			},
 			expectedChanged: true,
-			expectedfqdns:   &[]string{"fqdns1", "fqdns2"},
+			expectedFQDNs:   to.SliceOfPtrs("fqdns1", "fqdns2"),
 		},
 	}
 	for i, test := range tests {
@@ -1213,7 +1231,7 @@ func TestReconcilePLSFqdn(t *testing.T) {
 		s.Annotations = test.annotations
 		changed := reconcilePLSFqdn(test.pls, s)
 		assert.Equal(t, test.expectedChanged, changed, "TestCase[%d]: %s", i, test.desc)
-		assert.Equal(t, test.expectedfqdns, test.pls.Fqdns, "TestCase[%d]: %s", i, test.desc)
+		assert.Equal(t, test.expectedFQDNs, test.pls.Properties.Fqdns, "TestCase[%d]: %s", i, test.desc)
 	}
 }
 
@@ -1223,8 +1241,8 @@ func TestReconcilePLSVisibility(t *testing.T) {
 			Annotations: map[string]string{},
 		},
 	}
-	pls := network.PrivateLinkService{
-		PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{},
+	pls := armnetwork.PrivateLinkService{
+		Properties: &armnetwork.PrivateLinkServiceProperties{},
 	}
 
 	t.Run("reconcilePLSVisibility should change nothing when both visibility and auto-approval are nil", func(t *testing.T) {
@@ -1238,8 +1256,8 @@ func TestReconcilePLSVisibility(t *testing.T) {
 			consts.ServiceAnnotationPLSVisibility: "sub1 sub2",
 		}
 		service.Annotations = annotations
-		pls.Visibility = &network.PrivateLinkServicePropertiesVisibility{
-			Subscriptions: &[]string{"sub2", "sub1"},
+		pls.Properties.Visibility = &armnetwork.PrivateLinkServicePropertiesVisibility{
+			Subscriptions: to.SliceOfPtrs("sub2", "sub1"),
 		}
 		changed, err := reconcilePLSVisibility(&pls, &service)
 		assert.NoError(t, err)
@@ -1252,11 +1270,11 @@ func TestReconcilePLSVisibility(t *testing.T) {
 			consts.ServiceAnnotationPLSAutoApproval: "sub1 sub2",
 		}
 		service.Annotations = annotations
-		pls.Visibility = &network.PrivateLinkServicePropertiesVisibility{
-			Subscriptions: &[]string{"*"},
+		pls.Properties.Visibility = &armnetwork.PrivateLinkServicePropertiesVisibility{
+			Subscriptions: to.SliceOfPtrs("*"),
 		}
-		pls.AutoApproval = &network.PrivateLinkServicePropertiesAutoApproval{
-			Subscriptions: &[]string{"sub1", "sub2"},
+		pls.Properties.AutoApproval = &armnetwork.PrivateLinkServicePropertiesAutoApproval{
+			Subscriptions: to.SliceOfPtrs("sub1", "sub2"),
 		}
 		changed, err := reconcilePLSVisibility(&pls, &service)
 		assert.NoError(t, err)
@@ -1268,15 +1286,15 @@ func TestReconcilePLSVisibility(t *testing.T) {
 			consts.ServiceAnnotationPLSVisibility:   "*",
 			consts.ServiceAnnotationPLSAutoApproval: "sub1 sub2",
 		}
-		pls.Visibility = nil
-		pls.AutoApproval = nil
-		expectedPLS := network.PrivateLinkService{
-			PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-				Visibility: &network.PrivateLinkServicePropertiesVisibility{
-					Subscriptions: &[]string{"*"},
+		pls.Properties.Visibility = nil
+		pls.Properties.AutoApproval = nil
+		expectedPLS := armnetwork.PrivateLinkService{
+			Properties: &armnetwork.PrivateLinkServiceProperties{
+				Visibility: &armnetwork.PrivateLinkServicePropertiesVisibility{
+					Subscriptions: to.SliceOfPtrs("*"),
 				},
-				AutoApproval: &network.PrivateLinkServicePropertiesAutoApproval{
-					Subscriptions: &[]string{"sub1", "sub2"},
+				AutoApproval: &armnetwork.PrivateLinkServicePropertiesAutoApproval{
+					Subscriptions: to.SliceOfPtrs("sub1", "sub2"),
 				},
 			},
 		}
@@ -1291,15 +1309,15 @@ func TestReconcilePLSVisibility(t *testing.T) {
 		annotations := map[string]string{
 			consts.ServiceAnnotationPLSVisibility: "sub1 sub2",
 		}
-		pls.Visibility = nil
-		pls.AutoApproval = nil
-		expectedPLS := network.PrivateLinkService{
-			PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-				Visibility: &network.PrivateLinkServicePropertiesVisibility{
-					Subscriptions: &[]string{"sub1", "sub2"},
+		pls.Properties.Visibility = nil
+		pls.Properties.AutoApproval = nil
+		expectedPLS := armnetwork.PrivateLinkService{
+			Properties: &armnetwork.PrivateLinkServiceProperties{
+				Visibility: &armnetwork.PrivateLinkServicePropertiesVisibility{
+					Subscriptions: to.SliceOfPtrs("sub1", "sub2"),
 				},
-				AutoApproval: &network.PrivateLinkServicePropertiesAutoApproval{
-					Subscriptions: &[]string{},
+				AutoApproval: &armnetwork.PrivateLinkServicePropertiesAutoApproval{
+					Subscriptions: []*string{},
 				},
 			},
 		}
@@ -1314,23 +1332,23 @@ func TestReconcilePLSVisibility(t *testing.T) {
 		annotations := map[string]string{
 			consts.ServiceAnnotationPLSVisibility: "sub1 sub2",
 		}
-		pls = network.PrivateLinkService{
-			PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-				Visibility: &network.PrivateLinkServicePropertiesVisibility{
-					Subscriptions: &[]string{"*"},
+		pls = armnetwork.PrivateLinkService{
+			Properties: &armnetwork.PrivateLinkServiceProperties{
+				Visibility: &armnetwork.PrivateLinkServicePropertiesVisibility{
+					Subscriptions: to.SliceOfPtrs("*"),
 				},
-				AutoApproval: &network.PrivateLinkServicePropertiesAutoApproval{
-					Subscriptions: &[]string{"sub1"},
+				AutoApproval: &armnetwork.PrivateLinkServicePropertiesAutoApproval{
+					Subscriptions: to.SliceOfPtrs("sub1"),
 				},
 			},
 		}
-		expectedPLS := network.PrivateLinkService{
-			PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-				Visibility: &network.PrivateLinkServicePropertiesVisibility{
-					Subscriptions: &[]string{"sub1", "sub2"},
+		expectedPLS := armnetwork.PrivateLinkService{
+			Properties: &armnetwork.PrivateLinkServiceProperties{
+				Visibility: &armnetwork.PrivateLinkServicePropertiesVisibility{
+					Subscriptions: to.SliceOfPtrs("sub1", "sub2"),
 				},
-				AutoApproval: &network.PrivateLinkServicePropertiesAutoApproval{
-					Subscriptions: &[]string{},
+				AutoApproval: &armnetwork.PrivateLinkServicePropertiesAutoApproval{
+					Subscriptions: []*string{},
 				},
 			},
 		}
@@ -1346,23 +1364,23 @@ func TestReconcilePLSVisibility(t *testing.T) {
 			consts.ServiceAnnotationPLSVisibility:   "*",
 			consts.ServiceAnnotationPLSAutoApproval: "sub1 sub2",
 		}
-		pls = network.PrivateLinkService{
-			PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-				Visibility: &network.PrivateLinkServicePropertiesVisibility{
-					Subscriptions: &[]string{"*"},
+		pls = armnetwork.PrivateLinkService{
+			Properties: &armnetwork.PrivateLinkServiceProperties{
+				Visibility: &armnetwork.PrivateLinkServicePropertiesVisibility{
+					Subscriptions: to.SliceOfPtrs("*"),
 				},
-				AutoApproval: &network.PrivateLinkServicePropertiesAutoApproval{
-					Subscriptions: &[]string{"sub3"},
+				AutoApproval: &armnetwork.PrivateLinkServicePropertiesAutoApproval{
+					Subscriptions: to.SliceOfPtrs("sub3"),
 				},
 			},
 		}
-		expectedPLS := network.PrivateLinkService{
-			PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{
-				Visibility: &network.PrivateLinkServicePropertiesVisibility{
-					Subscriptions: &[]string{"*"},
+		expectedPLS := armnetwork.PrivateLinkService{
+			Properties: &armnetwork.PrivateLinkServiceProperties{
+				Visibility: &armnetwork.PrivateLinkServicePropertiesVisibility{
+					Subscriptions: to.SliceOfPtrs("*"),
 				},
-				AutoApproval: &network.PrivateLinkServicePropertiesAutoApproval{
-					Subscriptions: &[]string{"sub1", "sub2"},
+				AutoApproval: &armnetwork.PrivateLinkServicePropertiesAutoApproval{
+					Subscriptions: to.SliceOfPtrs("sub1", "sub2"),
 				},
 			},
 		}
@@ -1387,7 +1405,7 @@ func TestReconcilePLSTags(t *testing.T) {
 			Name:      "test-svc",
 		},
 	}
-	pls := network.PrivateLinkService{
+	pls := armnetwork.PrivateLinkService{
 		Tags: map[string]*string{
 			"foo": ptr.To("bar"),
 			"a":   ptr.To("j"),
@@ -1397,7 +1415,7 @@ func TestReconcilePLSTags(t *testing.T) {
 	clusterName := testClusterName
 
 	t.Run("reconcilePLSTags should ensure the pls is tagged as configured", func(t *testing.T) {
-		expectedPLS := network.PrivateLinkService{
+		expectedPLS := armnetwork.PrivateLinkService{
 			Tags: map[string]*string{
 				consts.ClusterNameTagKey:  ptr.To(testClusterName),
 				consts.OwnerServiceTagKey: ptr.To("test-ns/test-svc"),
@@ -1414,7 +1432,7 @@ func TestReconcilePLSTags(t *testing.T) {
 
 	t.Run("reconcilePLSTags should delete the old tags if the SystemTags is set", func(t *testing.T) {
 		cloud.SystemTags = "a,foo,b"
-		expectedPLS := network.PrivateLinkService{
+		expectedPLS := armnetwork.PrivateLinkService{
 			Tags: map[string]*string{
 				consts.ClusterNameTagKey:  ptr.To(testClusterName),
 				consts.OwnerServiceTagKey: ptr.To("test-ns/test-svc"),
@@ -1431,7 +1449,7 @@ func TestReconcilePLSTags(t *testing.T) {
 	t.Run("reconcilePLSTags should support TagsMap", func(t *testing.T) {
 		cloud.SystemTags = "a,foo,b"
 		cloud.TagsMap = map[string]string{"a": "c", "a=b": "c=d", "Y": "zz"}
-		expectedPLS := network.PrivateLinkService{
+		expectedPLS := armnetwork.PrivateLinkService{
 			Tags: map[string]*string{
 				consts.ClusterNameTagKey:  ptr.To(testClusterName),
 				consts.OwnerServiceTagKey: ptr.To("test-ns/test-svc"),
@@ -1449,7 +1467,7 @@ func TestReconcilePLSTags(t *testing.T) {
 	pls.Tags[consts.OwnerServiceTagKey] = ptr.To("default/svc")
 
 	t.Run("reconcilePLSTags should respect cluster and owner service tag keys", func(t *testing.T) {
-		expectedPLS := network.PrivateLinkService{
+		expectedPLS := armnetwork.PrivateLinkService{
 			Tags: map[string]*string{
 				consts.ClusterNameTagKey:  ptr.To("testCluster1"),
 				consts.OwnerServiceTagKey: ptr.To("default/svc"),
@@ -1819,23 +1837,23 @@ func TestGetPLSStaticIPs(t *testing.T) {
 func TestIsManagedPrivateLinkSerivce(t *testing.T) {
 	tests := []struct {
 		desc        string
-		pls         *network.PrivateLinkService
+		pls         *armnetwork.PrivateLinkService
 		clusterName string
 		expected    bool
 	}{
 		{
 			desc: "Private link service with nil tag should return false",
-			pls:  &network.PrivateLinkService{},
+			pls:  &armnetwork.PrivateLinkService{},
 		},
 		{
 			desc: "Private link service with empty tag should return false",
-			pls: &network.PrivateLinkService{
+			pls: &armnetwork.PrivateLinkService{
 				Tags: map[string]*string{},
 			},
 		},
 		{
 			desc: "Private link service with different cluster name should return false",
-			pls: &network.PrivateLinkService{
+			pls: &armnetwork.PrivateLinkService{
 				Tags: map[string]*string{
 					"k8s-azure-cluster-name": ptr.To("test-cluster1"),
 				},
@@ -1844,7 +1862,7 @@ func TestIsManagedPrivateLinkSerivce(t *testing.T) {
 		},
 		{
 			desc: "Private link service with same cluster name should return true",
-			pls: &network.PrivateLinkService{
+			pls: &armnetwork.PrivateLinkService{
 				Tags: map[string]*string{
 					"k8s-azure-cluster-name": ptr.To("test-cluster"),
 				},
@@ -1862,22 +1880,22 @@ func TestIsManagedPrivateLinkSerivce(t *testing.T) {
 func TestGetPrivateLinkServiceOwner(t *testing.T) {
 	tests := []struct {
 		desc     string
-		pls      *network.PrivateLinkService
+		pls      *armnetwork.PrivateLinkService
 		expected string
 	}{
 		{
 			desc: "Private link service with nil tag should return empty string",
-			pls:  &network.PrivateLinkService{},
+			pls:  &armnetwork.PrivateLinkService{},
 		},
 		{
 			desc: "Private link service with empty tag should return empty string",
-			pls: &network.PrivateLinkService{
+			pls: &armnetwork.PrivateLinkService{
 				Tags: map[string]*string{},
 			},
 		},
 		{
 			desc: "Private link service with service owner tag should return service owner",
-			pls: &network.PrivateLinkService{
+			pls: &armnetwork.PrivateLinkService{
 				Tags: map[string]*string{"k8s-azure-owner-service": ptr.To("test-service")},
 			},
 			expected: "test-service",
diff --git a/pkg/provider/azure_test.go b/pkg/provider/azure_test.go
index 2eed65922..69ed7018c 100644
--- a/pkg/provider/azure_test.go
+++ b/pkg/provider/azure_test.go
@@ -27,6 +27,7 @@ import (
 	"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/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"
@@ -48,12 +49,12 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/securitygroupclient/mock_securitygroupclient"
 	"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/privatelinkserviceclient/mockprivatelinkserviceclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/publicipclient/mockpublicipclient"
 	"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/consts"
 	providerconfig "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/zone"
 	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
 	utilsets "sigs.k8s.io/cloud-provider-azure/pkg/util/sets"
@@ -522,10 +523,9 @@ func testLoadBalancerServiceDefaultModeSelection(t *testing.T, isInternal bool)
 
 		expectedLBName := setMockLBs(az, ctrl, &expectedLBs, "service", 1, index, isInternal)
 
-		expectedPLS := make([]network.PrivateLinkService, 0)
-		mockPLSClient := mockprivatelinkserviceclient.NewMockInterface(ctrl)
-		mockPLSClient.EXPECT().List(gomock.Any(), az.Config.ResourceGroup).Return(expectedPLS, nil).MinTimes(1).MaxTimes(1)
-		az.PrivateLinkServiceClient = mockPLSClient
+		mockPLSRepo := privatelinkservice.NewMockRepository(ctrl)
+		mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil).AnyTimes()
+		az.plsRepo = mockPLSRepo
 
 		lbStatus, err := az.EnsureLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes)
 		if err != nil {
@@ -592,10 +592,9 @@ func testLoadBalancerServiceAutoModeSelection(t *testing.T, isInternal bool) {
 
 		setMockLBs(az, ctrl, &expectedLBs, "service", availabilitySetCount, index, isInternal)
 
-		expectedPLS := make([]network.PrivateLinkService, 0)
-		mockPLSClient := mockprivatelinkserviceclient.NewMockInterface(ctrl)
-		mockPLSClient.EXPECT().List(gomock.Any(), az.Config.ResourceGroup).Return(expectedPLS, nil).MinTimes(1).MaxTimes(1)
-		az.PrivateLinkServiceClient = mockPLSClient
+		mockPLSRepo := privatelinkservice.NewMockRepository(ctrl)
+		mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil).AnyTimes()
+		az.plsRepo = mockPLSRepo
 
 		lbStatus, err := az.EnsureLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes)
 		assert.Nil(t, err)
@@ -670,10 +669,10 @@ func testLoadBalancerServicesSpecifiedSelection(t *testing.T, isInternal bool) {
 
 		setMockLBs(az, ctrl, &expectedLBs, "service", 1, index, isInternal)
 
-		expectedPLS := make([]network.PrivateLinkService, 0)
-		mockPLSClient := mockprivatelinkserviceclient.NewMockInterface(ctrl)
-		mockPLSClient.EXPECT().List(gomock.Any(), az.Config.ResourceGroup).Return(expectedPLS, nil).MinTimes(1).MaxTimes(1)
-		az.PrivateLinkServiceClient = mockPLSClient
+		expectedPLS := make([]*armnetwork.PrivateLinkService, 0)
+		mockPLSRepo := privatelinkservice.NewMockRepository(ctrl)
+		mockPLSRepo.EXPECT().List(gomock.Any(), az.Config.ResourceGroup).Return(expectedPLS, nil).MinTimes(1).MaxTimes(1)
+		az.plsRepo = mockPLSRepo
 
 		lbStatus, err := az.EnsureLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes)
 		if err != nil {
@@ -729,10 +728,10 @@ func testLoadBalancerMaxRulesServices(t *testing.T, isInternal bool) {
 
 		setMockLBs(az, ctrl, &expectedLBs, "service", az.Config.MaximumLoadBalancerRuleCount, index, isInternal)
 
-		expectedPLS := make([]network.PrivateLinkService, 0)
-		mockPLSClient := mockprivatelinkserviceclient.NewMockInterface(ctrl)
-		mockPLSClient.EXPECT().List(gomock.Any(), az.Config.ResourceGroup).Return(expectedPLS, nil).MinTimes(1).MaxTimes(1)
-		az.PrivateLinkServiceClient = mockPLSClient
+		expectedPLS := make([]*armnetwork.PrivateLinkService, 0)
+		mockPLSRepo := privatelinkservice.NewMockRepository(ctrl)
+		mockPLSRepo.EXPECT().List(gomock.Any(), az.Config.ResourceGroup).Return(expectedPLS, nil).MinTimes(1).MaxTimes(1)
+		az.plsRepo = mockPLSRepo
 
 		lbStatus, err := az.EnsureLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes)
 		if err != nil {
@@ -817,10 +816,9 @@ func testLoadBalancerServiceAutoModeDeleteSelection(t *testing.T, isInternal boo
 
 		setMockLBs(az, ctrl, &expectedLBs, "service", availabilitySetCount, index, isInternal)
 
-		expectedPLS := make([]network.PrivateLinkService, 0)
-		mockPLSClient := mockprivatelinkserviceclient.NewMockInterface(ctrl)
-		mockPLSClient.EXPECT().List(gomock.Any(), az.Config.ResourceGroup).Return(expectedPLS, nil).MinTimes(1).MaxTimes(1)
-		az.PrivateLinkServiceClient = mockPLSClient
+		mockPLSRepo := privatelinkservice.NewMockRepository(ctrl)
+		mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil).AnyTimes()
+		az.plsRepo = mockPLSRepo
 
 		lbStatus, err := az.EnsureLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes)
 		if err != nil {
@@ -862,10 +860,9 @@ func testLoadBalancerServiceAutoModeDeleteSelection(t *testing.T, isInternal boo
 			t.Errorf("Unexpected number of LB's: Expected (%d) Found (%d)", expectedNumOfLB, lbCount)
 		}
 
-		expectedPLS := make([]network.PrivateLinkService, 0)
-		mockPLSClient := mockprivatelinkserviceclient.NewMockInterface(ctrl)
-		mockPLSClient.EXPECT().List(gomock.Any(), az.Config.ResourceGroup).Return(expectedPLS, nil).MinTimes(1).MaxTimes(1)
-		az.PrivateLinkServiceClient = mockPLSClient
+		mockPLSRepo := privatelinkservice.NewMockRepository(ctrl)
+		mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil).AnyTimes()
+		az.plsRepo = mockPLSRepo
 
 		err := az.EnsureLoadBalancerDeleted(context.TODO(), testClusterName, &svc)
 		if err != nil {
@@ -978,9 +975,9 @@ func TestReconcileLoadBalancerEditServiceSubnet(t *testing.T) {
 	}).AnyTimes()
 	mockLBBackendPool.EXPECT().EnsureHostsInPool(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
 
-	expectedPLS := make([]network.PrivateLinkService, 0)
-	mockPLSClient := az.PrivateLinkServiceClient.(*mockprivatelinkserviceclient.MockInterface)
-	mockPLSClient.EXPECT().List(gomock.Any(), az.Config.ResourceGroup).Return(expectedPLS, nil).MinTimes(1).MaxTimes(1)
+	mockPLSRepo := privatelinkservice.NewMockRepository(ctrl)
+	mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil).AnyTimes()
+	az.plsRepo = mockPLSRepo
 
 	lb, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc, clusterResources.nodes, true /* wantLb */)
 	if err != nil {
@@ -1170,9 +1167,10 @@ func TestReconcileLoadBalancerMultipleServices(t *testing.T) {
 	}).AnyTimes()
 	mockLBBackendPool.EXPECT().EnsureHostsInPool(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
 
-	expectedPLS := make([]network.PrivateLinkService, 0)
-	mockPLSClient := az.PrivateLinkServiceClient.(*mockprivatelinkserviceclient.MockInterface)
-	mockPLSClient.EXPECT().List(gomock.Any(), az.Config.ResourceGroup).Return(expectedPLS, nil).MinTimes(1).MaxTimes(1)
+	expectedPLS := make([]*armnetwork.PrivateLinkService, 0)
+	mockPLSRepo := privatelinkservice.NewMockRepository(ctrl)
+	mockPLSRepo.EXPECT().List(gomock.Any(), az.Config.ResourceGroup).Return(expectedPLS, nil).MinTimes(1).MaxTimes(1)
+	az.plsRepo = mockPLSRepo
 
 	_, err := az.reconcileLoadBalancer(context.TODO(), testClusterName, &svc1, clusterResources.nodes, true /* wantLb */)
 	assert.Nil(t, err)
@@ -1285,9 +1283,9 @@ func TestServiceRespectsNoSessionAffinity(t *testing.T) {
 	mockPIPsClient.EXPECT().List(gomock.Any(), az.ResourceGroup).Return([]network.PublicIPAddress{expectedPIP}, nil).AnyTimes()
 	mockPIPsClient.EXPECT().Get(gomock.Any(), az.ResourceGroup, "testCluster-aservicesanone", gomock.Any()).Return(expectedPIP, nil).AnyTimes()
 
-	expectedPLS := make([]network.PrivateLinkService, 0)
-	mockPLSClient := az.PrivateLinkServiceClient.(*mockprivatelinkserviceclient.MockInterface)
-	mockPLSClient.EXPECT().List(gomock.Any(), az.Config.ResourceGroup).Return(expectedPLS, nil).MinTimes(1).MaxTimes(1)
+	mockPLSRepo := privatelinkservice.NewMockRepository(ctrl)
+	mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil).AnyTimes()
+	az.plsRepo = mockPLSRepo
 
 	mockLBBackendPool := az.LoadBalancerBackendPool.(*MockBackendPool)
 	mockLBBackendPool.EXPECT().ReconcileBackendPools(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_ context.Context, _ string, _ *v1.Service, lb *network.LoadBalancer) (bool, bool, *network.LoadBalancer, error) {
@@ -1348,9 +1346,9 @@ func TestServiceRespectsClientIPSessionAffinity(t *testing.T) {
 	mockPIPsClient.EXPECT().Get(gomock.Any(), az.ResourceGroup, "testCluster-aservicesaclientip", gomock.Any()).Return(expectedPIP, nil).AnyTimes()
 	mockPIPsClient.EXPECT().List(gomock.Any(), az.ResourceGroup).Return([]network.PublicIPAddress{expectedPIP}, nil).AnyTimes()
 
-	expectedPLS := make([]network.PrivateLinkService, 0)
-	mockPLSClient := az.PrivateLinkServiceClient.(*mockprivatelinkserviceclient.MockInterface)
-	mockPLSClient.EXPECT().List(gomock.Any(), az.Config.ResourceGroup).Return(expectedPLS, nil).MinTimes(1).MaxTimes(1)
+	mockPLSRepo := privatelinkservice.NewMockRepository(ctrl)
+	mockPLSRepo.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&armnetwork.PrivateLinkService{ID: to.Ptr(consts.PrivateLinkServiceNotExistID)}, nil).AnyTimes()
+	az.plsRepo = mockPLSRepo
 
 	mockLBBackendPool := az.LoadBalancerBackendPool.(*MockBackendPool)
 	mockLBBackendPool.EXPECT().ReconcileBackendPools(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_ context.Context, _ string, _ *v1.Service, lb *network.LoadBalancer) (bool, bool, *network.LoadBalancer, error) {
diff --git a/pkg/provider/privatelinkservice/repo_test.go b/pkg/provider/privatelinkservice/repo_test.go
new file mode 100644
index 000000000..b6b8bee9c
--- /dev/null
+++ b/pkg/provider/privatelinkservice/repo_test.go
@@ -0,0 +1,331 @@
+/*
+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 privatelinkservice
+
+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"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatelinkserviceclient/mock_privatelinkserviceclient"
+	"sigs.k8s.io/cloud-provider-azure/pkg/cache"
+	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
+)
+
+func TestRepo_Get(t *testing.T) {
+	t.Run("refresh cache", func(t *testing.T) {
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			rg                 = "resource-group"
+			frontendIPConfigID = "frontend-ip-config-id"
+			plsID              = "pls-id"
+		)
+
+		cli.EXPECT().List(gomock.Any(), rg).Return([]*armnetwork.PrivateLinkService{
+			{
+				ID: to.Ptr(plsID),
+				Properties: &armnetwork.PrivateLinkServiceProperties{
+					LoadBalancerFrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{
+						{ID: to.Ptr(frontendIPConfigID)},
+					},
+				},
+			},
+		}, nil).Times(1)
+
+		v, err := repo.Get(ctx, rg, frontendIPConfigID, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Equal(t, plsID, *v.ID)
+
+		// cache hit
+		v, err = repo.Get(ctx, rg, frontendIPConfigID, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Equal(t, plsID, *v.ID)
+	})
+
+	t.Run("refresh cache with not found", func(t *testing.T) {
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			rg                 = "resource-group"
+			frontendIPConfigID = "frontend-ip-config-id"
+		)
+
+		cli.EXPECT().List(gomock.Any(), rg).Return([]*armnetwork.PrivateLinkService{}, nil).Times(1)
+
+		v, err := repo.Get(ctx, rg, frontendIPConfigID, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Equal(t, consts.PrivateLinkServiceNotExistID, *v.ID)
+	})
+
+	t.Run("API error", func(t *testing.T) {
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			rg                 = "resource-group"
+			frontendIPConfigID = "frontend-ip-config-id"
+		)
+
+		expectedErr := fmt.Errorf("API error")
+
+		cli.EXPECT().List(gomock.Any(), rg).Return(nil, expectedErr).Times(1)
+
+		_, err = repo.Get(ctx, rg, frontendIPConfigID, cache.CacheReadTypeDefault)
+		assert.Error(t, err)
+		assert.ErrorIs(t, err, expectedErr)
+	})
+}
+
+func TestRepo_CreateOrUpdate(t *testing.T) {
+	t.Run("create one", func(t *testing.T) {
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			rg                 = "resource-group"
+			plsName            = "pls-name"
+			frontendIPConfigID = "frontend-ip-config-id"
+		)
+
+		cli.EXPECT().CreateOrUpdate(gomock.Any(), rg, plsName, gomock.Any()).Return(&armnetwork.PrivateLinkService{
+			Name: to.Ptr(plsName),
+			Properties: &armnetwork.PrivateLinkServiceProperties{
+				LoadBalancerFrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{
+					{ID: to.Ptr(frontendIPConfigID)},
+				},
+			},
+		}, nil).Times(1)
+
+		v, err := repo.CreateOrUpdate(ctx, rg, armnetwork.PrivateLinkService{
+			Name: to.Ptr(plsName),
+			Properties: &armnetwork.PrivateLinkServiceProperties{
+				LoadBalancerFrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{
+					{ID: to.Ptr(frontendIPConfigID)},
+				},
+			},
+		})
+		assert.NoError(t, err)
+		assert.Equal(t, plsName, *v.Name)
+	})
+
+	t.Run("create one with missing PLS name", func(t *testing.T) {
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			rg = "resource-group"
+		)
+
+		_, err = repo.CreateOrUpdate(ctx, rg, armnetwork.PrivateLinkService{})
+		assert.Error(t, err)
+		assert.ErrorIs(t, err, ErrMissingPLSName)
+	})
+
+	t.Run("create one with missing LoadBalancerFrontendIPConfigurations", func(t *testing.T) {
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			rg      = "resource-group"
+			plsName = "pls-name"
+		)
+
+		_, err = repo.CreateOrUpdate(ctx, rg, armnetwork.PrivateLinkService{
+			Name: to.Ptr(plsName),
+		})
+		assert.Error(t, err)
+		assert.ErrorIs(t, err, ErrLoadBalancerFrontendIPConfigurationsNotFound)
+	})
+
+	t.Run("should clear cache", func(t *testing.T) {
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			rg                 = "resource-group"
+			plsName            = "pls-name"
+			frontendIPConfigID = "frontend-ip-config-id"
+		)
+
+		cli.EXPECT().List(gomock.Any(), rg).Return([]*armnetwork.PrivateLinkService{
+			{
+				Name: to.Ptr(plsName),
+				Properties: &armnetwork.PrivateLinkServiceProperties{
+					LoadBalancerFrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{
+						{ID: to.Ptr(frontendIPConfigID)},
+					},
+				},
+			},
+		}, nil).Times(2)
+
+		cli.EXPECT().CreateOrUpdate(gomock.Any(), rg, plsName, gomock.Any()).Return(&armnetwork.PrivateLinkService{
+			Name: to.Ptr(plsName),
+			Properties: &armnetwork.PrivateLinkServiceProperties{
+				LoadBalancerFrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{
+					{ID: to.Ptr(frontendIPConfigID)},
+				},
+			},
+		}, nil).Times(1)
+
+		v, err := repo.Get(ctx, rg, frontendIPConfigID, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Equal(t, plsName, *v.Name)
+
+		v, err = repo.CreateOrUpdate(ctx, rg, armnetwork.PrivateLinkService{
+			Name: to.Ptr(plsName),
+			Properties: &armnetwork.PrivateLinkServiceProperties{
+				LoadBalancerFrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{
+					{ID: to.Ptr(frontendIPConfigID)},
+				},
+			},
+		})
+		assert.NoError(t, err)
+		assert.Equal(t, plsName, *v.Name)
+
+		// cache miss
+		v, err = repo.Get(ctx, rg, frontendIPConfigID, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Equal(t, plsName, *v.Name)
+
+	})
+}
+
+func TestRepo_Delete(t *testing.T) {
+	t.Run("delete one", func(t *testing.T) {
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			rg                 = "resource-group"
+			plsName            = "pls-name"
+			frontendIPConfigID = "frontend-ip-config-id"
+		)
+
+		cli.EXPECT().Delete(gomock.Any(), rg, plsName).Return(nil).Times(1)
+
+		err = repo.Delete(ctx, rg, plsName, frontendIPConfigID)
+		assert.NoError(t, err)
+	})
+
+	t.Run("API error", func(t *testing.T) {
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			rg      = "resource-group"
+			plsName = "pls-name"
+		)
+
+		expectedErr := fmt.Errorf("API error")
+
+		cli.EXPECT().Delete(gomock.Any(), rg, plsName).Return(expectedErr).Times(1)
+
+		err = repo.Delete(ctx, rg, plsName, "")
+		assert.Error(t, err)
+		assert.ErrorIs(t, err, expectedErr)
+	})
+}
+
+func TestRepo_DeletePEConnection(t *testing.T) {
+	t.Run("delete one", func(t *testing.T) {
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			rg         = "resource-group"
+			plsName    = "pls-name"
+			peConnName = "pe-conn-name"
+		)
+
+		cli.EXPECT().DeletePrivateEndpointConnection(gomock.Any(), rg, plsName, peConnName).Return(nil).Times(1)
+
+		err = repo.DeletePEConnection(ctx, rg, plsName, peConnName)
+		assert.NoError(t, err)
+	})
+
+	t.Run("API error", func(t *testing.T) {
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			rg         = "resource-group"
+			plsName    = "pls-name"
+			peConnName = "pe-conn-name"
+		)
+
+		expectedErr := fmt.Errorf("API error")
+
+		cli.EXPECT().DeletePrivateEndpointConnection(gomock.Any(), rg, plsName, peConnName).Return(expectedErr).Times(1)
+
+		err = repo.DeletePEConnection(ctx, rg, plsName, peConnName)
+		assert.Error(t, err)
+		assert.ErrorIs(t, err, expectedErr)
+	})
+}