Repository: kubernetes-sigs/cloud-provider-azure
Pull request #2074 (2022-07-25 06:57:18)

[release-1.24] Allow external service with floating ip disabled to use PLS
This is an automated cherry-pick of #2073

/assign jwtty

```release-note
Allow external service with floating ip disabled to create PLS.
```


Patch:
diff --git a/pkg/provider/azure_privatelinkservice.go b/pkg/provider/azure_privatelinkservice.go
index a4a6d4f9e..43c356a6f 100644
--- a/pkg/provider/azure_privatelinkservice.go
+++ b/pkg/provider/azure_privatelinkservice.go
@@ -47,8 +47,8 @@ func (az *Cloud) reconcilePrivateLinkService(
 
 	if createPLS {
 		// Firstly, make sure it's internal service
-		if !requiresInternalLoadBalancer(service) {
-			return fmt.Errorf("reconcilePrivateLinkService for service(%s): service requiring private link service must be internal", serviceName)
+		if !requiresInternalLoadBalancer(service) && !consts.IsK8sServiceDisableLoadBalancerFloatingIP(service) {
+			return fmt.Errorf("reconcilePrivateLinkService for service(%s): service requiring private link service must be internal or disable floating ip", serviceName)
 		}
 
 		// Secondly, check if there is a private link service already created
@@ -518,8 +518,10 @@ func getPLSSubnetName(service *v1.Service) *string {
 		return &l
 	}
 
-	if l, found := service.Annotations[consts.ServiceAnnotationLoadBalancerInternalSubnet]; found && strings.TrimSpace(l) != "" {
-		return &l
+	if requiresInternalLoadBalancer(service) {
+		if l, found := service.Annotations[consts.ServiceAnnotationLoadBalancerInternalSubnet]; found && strings.TrimSpace(l) != "" {
+			return &l
+		}
 	}
 
 	return nil


Test patch:
diff --git a/pkg/provider/azure_privatelinkservice_test.go b/pkg/provider/azure_privatelinkservice_test.go
index e95140c1f..83cfb4973 100644
--- a/pkg/provider/azure_privatelinkservice_test.go
+++ b/pkg/provider/azure_privatelinkservice_test.go
@@ -56,13 +56,33 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 			wantPLS: true,
 		},
 		{
-			desc: "reconcilePrivateLinkService should return error if service requires PLS but needs external LB",
+			desc: "reconcilePrivateLinkService should return error if service requires PLS but needs external LB and floating ip enabled",
 			annotations: map[string]string{
 				consts.ServiceAnnotationPLSCreation: "true",
 			},
 			wantPLS:       true,
 			expectedError: true,
 		},
+		{
+			desc: "reconcilePrivateLinkService should create a new PLS for external service with floating ip disabled",
+			annotations: map[string]string{
+				consts.ServiceAnnotationPLSCreation:                   "true",
+				consts.ServiceAnnotationDisableLoadBalancerFloatingIP: "true",
+			},
+			wantPLS:           true,
+			expectedSubnetGet: true,
+			existingSubnet: &network.Subnet{
+				Name: to.StringPtr("subnet"),
+				ID:   to.StringPtr("subnetID"),
+				SubnetPropertiesFormat: &network.SubnetPropertiesFormat{
+					PrivateLinkServiceNetworkPolicies: network.VirtualNetworkPrivateLinkServiceNetworkPoliciesDisabled,
+				},
+			},
+			expectedPLSList:   true,
+			existingPLSList:   []network.PrivateLinkService{},
+			expectedPLSCreate: true,
+			expectedPLS:       &network.PrivateLinkService{Name: to.StringPtr("pls-fipConfig")},
+		},
 		{
 			desc: "reconcilePrivateLinkService should create a new PLS if no existing PLS attached to the LB frontend",
 			annotations: map[string]string{
@@ -300,7 +320,10 @@ func TestReconcilePrivateLinkService(t *testing.T) {
 	for i, test := range testCases {
 		az := GetTestCloud(ctrl)
 		service := getTestServiceWithAnnotation("test", test.annotations, 80)
-		fipConfig := &network.FrontendIPConfiguration{ID: to.StringPtr("fipConfigID")}
+		fipConfig := &network.FrontendIPConfiguration{
+			Name: to.StringPtr("fipConfig"),
+			ID:   to.StringPtr("fipConfigID"),
+		}
 		clusterName := testClusterName
 
 		mockSubnetsClient := az.SubnetsClient.(*mocksubnetclient.MockInterface)
@@ -1329,6 +1352,7 @@ func TestGetPLSSubnetName(t *testing.T) {
 		{
 			desc: "Service with empty private link subnet specified but LB subnet specified should return LB subnet",
 			annotations: map[string]string{
+				consts.ServiceAnnotationLoadBalancerInternal:       "true",
 				consts.ServiceAnnotationPLSIpConfigurationSubnet:   "",
 				consts.ServiceAnnotationLoadBalancerInternalSubnet: "lb-subnet",
 			},
@@ -1337,6 +1361,7 @@ func TestGetPLSSubnetName(t *testing.T) {
 		{
 			desc: "Service with LB subnet specified should return it",
 			annotations: map[string]string{
+				consts.ServiceAnnotationLoadBalancerInternal:       "true",
 				consts.ServiceAnnotationLoadBalancerInternalSubnet: "lb-subnet",
 			},
 			expectedSubnet: to.StringPtr("lb-subnet"),
@@ -1344,6 +1369,7 @@ func TestGetPLSSubnetName(t *testing.T) {
 		{
 			desc: "Service with both empty subnets specified should return nil",
 			annotations: map[string]string{
+				consts.ServiceAnnotationLoadBalancerInternal:       "true",
 				consts.ServiceAnnotationPLSIpConfigurationSubnet:   "",
 				consts.ServiceAnnotationLoadBalancerInternalSubnet: "",
 			},