sigs.k8s.io/cluster-api-provider-azure@v1.14.3/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  )
    29  
    30  // PrivateLinkServiceConnection defines the specification for a private link service connection associated with a private endpoint.
    31  type PrivateLinkServiceConnection struct {
    32  	Name                 string
    33  	PrivateLinkServiceID string
    34  	GroupIDs             []string
    35  	RequestMessage       string
    36  }
    37  
    38  // PrivateEndpointSpec defines the specification for a private endpoint.
    39  type PrivateEndpointSpec struct {
    40  	Name                          string
    41  	ResourceGroup                 string
    42  	Location                      string
    43  	CustomNetworkInterfaceName    string
    44  	PrivateIPAddresses            []string
    45  	SubnetID                      string
    46  	ApplicationSecurityGroups     []string
    47  	ManualApproval                bool
    48  	PrivateLinkServiceConnections []PrivateLinkServiceConnection
    49  	AdditionalTags                infrav1.Tags
    50  	ClusterName                   string
    51  }
    52  
    53  // ResourceRef implements azure.ASOResourceSpecGetter.
    54  func (s *PrivateEndpointSpec) ResourceRef() *asonetworkv1.PrivateEndpoint {
    55  	return &asonetworkv1.PrivateEndpoint{
    56  		ObjectMeta: metav1.ObjectMeta{
    57  			Name: s.Name,
    58  		},
    59  	}
    60  }
    61  
    62  // Parameters implements azure.ASOResourceSpecGetter.
    63  func (s *PrivateEndpointSpec) Parameters(ctx context.Context, existingPrivateEndpoint *asonetworkv1.PrivateEndpoint) (*asonetworkv1.PrivateEndpoint, error) {
    64  	privateEndpoint := &asonetworkv1.PrivateEndpoint{}
    65  	if existingPrivateEndpoint != nil {
    66  		privateEndpoint = existingPrivateEndpoint
    67  	}
    68  
    69  	if len(s.ApplicationSecurityGroups) > 0 {
    70  		applicationSecurityGroups := make([]asonetworkv1.ApplicationSecurityGroupSpec_PrivateEndpoint_SubResourceEmbedded, 0, len(s.ApplicationSecurityGroups))
    71  		for _, applicationSecurityGroup := range s.ApplicationSecurityGroups {
    72  			applicationSecurityGroups = append(applicationSecurityGroups, asonetworkv1.ApplicationSecurityGroupSpec_PrivateEndpoint_SubResourceEmbedded{
    73  				Reference: &genruntime.ResourceReference{
    74  					ARMID: applicationSecurityGroup,
    75  				},
    76  			})
    77  		}
    78  		// Sort the slices in order to get the same order of elements for both new and existing application Security Groups.
    79  		sort.SliceStable(applicationSecurityGroups, func(i, j int) bool {
    80  			return applicationSecurityGroups[i].Reference.ARMID < applicationSecurityGroups[j].Reference.ARMID
    81  		})
    82  		privateEndpoint.Spec.ApplicationSecurityGroups = applicationSecurityGroups
    83  	}
    84  
    85  	privateEndpoint.Spec.AzureName = s.Name
    86  	privateEndpoint.Spec.CustomNetworkInterfaceName = ptr.To(s.CustomNetworkInterfaceName)
    87  	privateEndpoint.Spec.Location = ptr.To(s.Location)
    88  
    89  	if len(s.PrivateIPAddresses) > 0 {
    90  		privateIPAddresses := make([]asonetworkv1.PrivateEndpointIPConfiguration, 0, len(s.PrivateIPAddresses))
    91  		for _, address := range s.PrivateIPAddresses {
    92  			ipConfig := asonetworkv1.PrivateEndpointIPConfiguration{PrivateIPAddress: ptr.To(address)}
    93  			privateIPAddresses = append(privateIPAddresses, ipConfig)
    94  		}
    95  		sort.SliceStable(privateIPAddresses, func(i, j int) bool {
    96  			return *privateIPAddresses[i].PrivateIPAddress < *privateIPAddresses[j].PrivateIPAddress
    97  		})
    98  		privateEndpoint.Spec.IpConfigurations = privateIPAddresses
    99  	}
   100  
   101  	if len(s.PrivateLinkServiceConnections) > 0 {
   102  		privateLinkServiceConnections := make([]asonetworkv1.PrivateLinkServiceConnection, 0, len(s.PrivateLinkServiceConnections))
   103  		for _, privateLinkServiceConnection := range s.PrivateLinkServiceConnections {
   104  			linkServiceConnection := asonetworkv1.PrivateLinkServiceConnection{
   105  				Name: ptr.To(privateLinkServiceConnection.Name),
   106  				PrivateLinkServiceReference: &genruntime.ResourceReference{
   107  					ARMID: privateLinkServiceConnection.PrivateLinkServiceID,
   108  				},
   109  			}
   110  
   111  			if len(privateLinkServiceConnection.GroupIDs) > 0 {
   112  				linkServiceConnection.GroupIds = privateLinkServiceConnection.GroupIDs
   113  			}
   114  
   115  			if privateLinkServiceConnection.RequestMessage != "" {
   116  				linkServiceConnection.RequestMessage = ptr.To(privateLinkServiceConnection.RequestMessage)
   117  			}
   118  			privateLinkServiceConnections = append(privateLinkServiceConnections, linkServiceConnection)
   119  		}
   120  		sort.SliceStable(privateLinkServiceConnections, func(i, j int) bool {
   121  			return *privateLinkServiceConnections[i].Name < *privateLinkServiceConnections[j].Name
   122  		})
   123  
   124  		if s.ManualApproval {
   125  			privateEndpoint.Spec.ManualPrivateLinkServiceConnections = privateLinkServiceConnections
   126  		} else {
   127  			privateEndpoint.Spec.PrivateLinkServiceConnections = privateLinkServiceConnections
   128  		}
   129  	}
   130  
   131  	privateEndpoint.Spec.Owner = &genruntime.KnownResourceReference{
   132  		Name: s.ResourceGroup,
   133  	}
   134  
   135  	privateEndpoint.Spec.Subnet = &asonetworkv1.Subnet_PrivateEndpoint_SubResourceEmbedded{
   136  		Reference: &genruntime.ResourceReference{
   137  			ARMID: s.SubnetID,
   138  		},
   139  	}
   140  
   141  	privateEndpoint.Spec.Tags = infrav1.Build(infrav1.BuildParams{
   142  		ClusterName: s.ClusterName,
   143  		Lifecycle:   infrav1.ResourceLifecycleOwned,
   144  		Name:        ptr.To(s.Name),
   145  		Additional:  s.AdditionalTags,
   146  	})
   147  
   148  	return privateEndpoint, nil
   149  }
   150  
   151  // WasManaged implements azure.ASOResourceSpecGetter.
   152  // It always returns true since CAPZ doesn't support BYO private endpoints.
   153  func (s *PrivateEndpointSpec) WasManaged(privateEndpoint *asonetworkv1.PrivateEndpoint) bool {
   154  	return true
   155  }