sigs.k8s.io/cluster-api-provider-azure@v1.17.0/azure/services/privateendpoints/spec.go (about)

     1  /*
     2  Copyright 2023 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package privateendpoints
    18  
    19  import (
    20  	"context"
    21  	"sort"
    22  
    23  	asonetworkv1 "github.com/Azure/azure-service-operator/v2/api/network/v1api20220701"
    24  	"github.com/Azure/azure-service-operator/v2/pkg/genruntime"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/utils/ptr"
    27  	infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    28  	"sigs.k8s.io/cluster-api-provider-azure/azure"
    29  )
    30  
    31  // PrivateLinkServiceConnection defines the specification for a private link service connection associated with a private endpoint.
    32  type PrivateLinkServiceConnection struct {
    33  	Name                 string
    34  	PrivateLinkServiceID string
    35  	GroupIDs             []string
    36  	RequestMessage       string
    37  }
    38  
    39  // PrivateEndpointSpec defines the specification for a private endpoint.
    40  type PrivateEndpointSpec struct {
    41  	Name                          string
    42  	ResourceGroup                 string
    43  	Location                      string
    44  	CustomNetworkInterfaceName    string
    45  	PrivateIPAddresses            []string
    46  	SubnetID                      string
    47  	ApplicationSecurityGroups     []string
    48  	ManualApproval                bool
    49  	PrivateLinkServiceConnections []PrivateLinkServiceConnection
    50  	AdditionalTags                infrav1.Tags
    51  	ClusterName                   string
    52  }
    53  
    54  // ResourceRef implements azure.ASOResourceSpecGetter.
    55  func (s *PrivateEndpointSpec) ResourceRef() *asonetworkv1.PrivateEndpoint {
    56  	return &asonetworkv1.PrivateEndpoint{
    57  		ObjectMeta: metav1.ObjectMeta{
    58  			Name: azure.GetNormalizedKubernetesName(s.Name),
    59  		},
    60  	}
    61  }
    62  
    63  // Parameters implements azure.ASOResourceSpecGetter.
    64  func (s *PrivateEndpointSpec) Parameters(ctx context.Context, existingPrivateEndpoint *asonetworkv1.PrivateEndpoint) (*asonetworkv1.PrivateEndpoint, error) {
    65  	privateEndpoint := &asonetworkv1.PrivateEndpoint{}
    66  	if existingPrivateEndpoint != nil {
    67  		privateEndpoint = existingPrivateEndpoint
    68  	}
    69  
    70  	if len(s.ApplicationSecurityGroups) > 0 {
    71  		applicationSecurityGroups := make([]asonetworkv1.ApplicationSecurityGroupSpec_PrivateEndpoint_SubResourceEmbedded, 0, len(s.ApplicationSecurityGroups))
    72  		for _, applicationSecurityGroup := range s.ApplicationSecurityGroups {
    73  			applicationSecurityGroups = append(applicationSecurityGroups, asonetworkv1.ApplicationSecurityGroupSpec_PrivateEndpoint_SubResourceEmbedded{
    74  				Reference: &genruntime.ResourceReference{
    75  					ARMID: applicationSecurityGroup,
    76  				},
    77  			})
    78  		}
    79  		// Sort the slices in order to get the same order of elements for both new and existing application Security Groups.
    80  		sort.SliceStable(applicationSecurityGroups, func(i, j int) bool {
    81  			return applicationSecurityGroups[i].Reference.ARMID < applicationSecurityGroups[j].Reference.ARMID
    82  		})
    83  		privateEndpoint.Spec.ApplicationSecurityGroups = applicationSecurityGroups
    84  	}
    85  
    86  	privateEndpoint.Spec.AzureName = s.Name
    87  	privateEndpoint.Spec.CustomNetworkInterfaceName = ptr.To(s.CustomNetworkInterfaceName)
    88  	privateEndpoint.Spec.Location = ptr.To(s.Location)
    89  
    90  	if len(s.PrivateIPAddresses) > 0 {
    91  		privateIPAddresses := make([]asonetworkv1.PrivateEndpointIPConfiguration, 0, len(s.PrivateIPAddresses))
    92  		for _, address := range s.PrivateIPAddresses {
    93  			ipConfig := asonetworkv1.PrivateEndpointIPConfiguration{PrivateIPAddress: ptr.To(address)}
    94  			privateIPAddresses = append(privateIPAddresses, ipConfig)
    95  		}
    96  		sort.SliceStable(privateIPAddresses, func(i, j int) bool {
    97  			return *privateIPAddresses[i].PrivateIPAddress < *privateIPAddresses[j].PrivateIPAddress
    98  		})
    99  		privateEndpoint.Spec.IpConfigurations = privateIPAddresses
   100  	}
   101  
   102  	if len(s.PrivateLinkServiceConnections) > 0 {
   103  		privateLinkServiceConnections := make([]asonetworkv1.PrivateLinkServiceConnection, 0, len(s.PrivateLinkServiceConnections))
   104  		for _, privateLinkServiceConnection := range s.PrivateLinkServiceConnections {
   105  			linkServiceConnection := asonetworkv1.PrivateLinkServiceConnection{
   106  				Name: ptr.To(privateLinkServiceConnection.Name),
   107  				PrivateLinkServiceReference: &genruntime.ResourceReference{
   108  					ARMID: privateLinkServiceConnection.PrivateLinkServiceID,
   109  				},
   110  			}
   111  
   112  			if len(privateLinkServiceConnection.GroupIDs) > 0 {
   113  				linkServiceConnection.GroupIds = privateLinkServiceConnection.GroupIDs
   114  			}
   115  
   116  			if privateLinkServiceConnection.RequestMessage != "" {
   117  				linkServiceConnection.RequestMessage = ptr.To(privateLinkServiceConnection.RequestMessage)
   118  			}
   119  			privateLinkServiceConnections = append(privateLinkServiceConnections, linkServiceConnection)
   120  		}
   121  		sort.SliceStable(privateLinkServiceConnections, func(i, j int) bool {
   122  			return *privateLinkServiceConnections[i].Name < *privateLinkServiceConnections[j].Name
   123  		})
   124  
   125  		if s.ManualApproval {
   126  			privateEndpoint.Spec.ManualPrivateLinkServiceConnections = privateLinkServiceConnections
   127  		} else {
   128  			privateEndpoint.Spec.PrivateLinkServiceConnections = privateLinkServiceConnections
   129  		}
   130  	}
   131  
   132  	privateEndpoint.Spec.Owner = &genruntime.KnownResourceReference{
   133  		Name: azure.GetNormalizedKubernetesName(s.ResourceGroup),
   134  	}
   135  
   136  	privateEndpoint.Spec.Subnet = &asonetworkv1.Subnet_PrivateEndpoint_SubResourceEmbedded{
   137  		Reference: &genruntime.ResourceReference{
   138  			ARMID: s.SubnetID,
   139  		},
   140  	}
   141  
   142  	privateEndpoint.Spec.Tags = infrav1.Build(infrav1.BuildParams{
   143  		ClusterName: s.ClusterName,
   144  		Lifecycle:   infrav1.ResourceLifecycleOwned,
   145  		Name:        ptr.To(s.Name),
   146  		Additional:  s.AdditionalTags,
   147  	})
   148  
   149  	return privateEndpoint, nil
   150  }
   151  
   152  // WasManaged implements azure.ASOResourceSpecGetter.
   153  // It always returns true since CAPZ doesn't support BYO private endpoints.
   154  func (s *PrivateEndpointSpec) WasManaged(privateEndpoint *asonetworkv1.PrivateEndpoint) bool {
   155  	return true
   156  }