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

     1  /*
     2  Copyright 2021 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 inboundnatrules
    18  
    19  import (
    20  	"context"
    21  
    22  	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4"
    23  	"github.com/pkg/errors"
    24  	"k8s.io/utils/ptr"
    25  )
    26  
    27  // InboundNatSpec defines the specification for an inbound NAT rule.
    28  type InboundNatSpec struct {
    29  	Name                      string
    30  	LoadBalancerName          string
    31  	ResourceGroup             string
    32  	FrontendIPConfigurationID *string
    33  	SSHFrontendPort           *int32
    34  }
    35  
    36  // ResourceName returns the name of the inbound NAT rule.
    37  func (s *InboundNatSpec) ResourceName() string {
    38  	return s.Name
    39  }
    40  
    41  // ResourceGroupName returns the name of the resource group.
    42  func (s *InboundNatSpec) ResourceGroupName() string {
    43  	return s.ResourceGroup
    44  }
    45  
    46  // OwnerResourceName returns the name of the load balancer associated with an inbound NAT rule.
    47  func (s *InboundNatSpec) OwnerResourceName() string {
    48  	return s.LoadBalancerName
    49  }
    50  
    51  // Parameters returns the parameters for the inbound NAT rule.
    52  func (s *InboundNatSpec) Parameters(ctx context.Context, existing interface{}) (parameters interface{}, err error) {
    53  	if existing != nil {
    54  		if _, ok := existing.(armnetwork.InboundNatRule); !ok {
    55  			return nil, errors.Errorf("%T is not an armnetwork.InboundNatRule", existing)
    56  		}
    57  		// Skip updating the existing inbound NAT rule
    58  		return nil, nil
    59  	}
    60  
    61  	if s.FrontendIPConfigurationID == nil {
    62  		return nil, errors.Errorf("FrontendIPConfigurationID is not set")
    63  	}
    64  
    65  	rule := armnetwork.InboundNatRule{
    66  		Name: ptr.To(s.ResourceName()),
    67  		Properties: &armnetwork.InboundNatRulePropertiesFormat{
    68  			BackendPort:          ptr.To[int32](22),
    69  			EnableFloatingIP:     ptr.To(false),
    70  			IdleTimeoutInMinutes: ptr.To[int32](4),
    71  			FrontendIPConfiguration: &armnetwork.SubResource{
    72  				ID: s.FrontendIPConfigurationID,
    73  			},
    74  			Protocol:     ptr.To(armnetwork.TransportProtocolTCP),
    75  			FrontendPort: s.SSHFrontendPort,
    76  		},
    77  	}
    78  
    79  	return rule, nil
    80  }
    81  
    82  func getAvailableSSHFrontendPort(portsInUse map[int32]struct{}) (int32, error) {
    83  	// NAT rules need to use a unique port. Since we need one NAT rule per control plane and we expect to have 1, 3, 5, maybe 9 control planes, there should never be more than 9 ports in use.
    84  	// This is an artificial limit of 20 ports that we can pick from, which should be plenty enough (in reality we should never reach that limit).
    85  	// These NAT rules are used for SSH purposes which is why we start at 22 and then use 2201, 2202, etc.
    86  	var i int32 = 22
    87  	if _, ok := portsInUse[22]; ok {
    88  		for i = 2201; i < 2220; i++ {
    89  			if _, ok := portsInUse[i]; !ok {
    90  				// Found available port
    91  				return i, nil
    92  			}
    93  		}
    94  		return i, errors.Errorf("No available SSH Frontend ports")
    95  	}
    96  
    97  	return i, nil
    98  }