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

     1  /*
     2  Copyright 2022 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 agentpools
    18  
    19  import (
    20  	"context"
    21  
    22  	asocontainerservicev1 "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001"
    23  	asocontainerservicev1hub "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001/storage"
    24  	asocontainerservicev1preview "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231102preview"
    25  	"github.com/Azure/azure-service-operator/v2/pkg/genruntime"
    26  	"k8s.io/apimachinery/pkg/api/resource"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"k8s.io/utils/ptr"
    29  	infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    30  	"sigs.k8s.io/cluster-api-provider-azure/azure"
    31  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/aso"
    32  	"sigs.k8s.io/cluster-api-provider-azure/util/tele"
    33  	"sigs.k8s.io/cluster-api-provider-azure/util/versions"
    34  	"sigs.k8s.io/controller-runtime/pkg/conversion"
    35  )
    36  
    37  // KubeletConfig defines the set of kubelet configurations for nodes in pools.
    38  type KubeletConfig struct {
    39  	// CPUManagerPolicy - CPU Manager policy to use.
    40  	CPUManagerPolicy *string
    41  	// CPUCfsQuota - Enable CPU CFS quota enforcement for containers that specify CPU limits.
    42  	CPUCfsQuota *bool
    43  	// CPUCfsQuotaPeriod - Sets CPU CFS quota period value.
    44  	CPUCfsQuotaPeriod *string
    45  	// ImageGcHighThreshold - The percent of disk usage after which image garbage collection is always run.
    46  	ImageGcHighThreshold *int
    47  	// ImageGcLowThreshold - The percent of disk usage before which image garbage collection is never run.
    48  	ImageGcLowThreshold *int
    49  	// TopologyManagerPolicy - Topology Manager policy to use.
    50  	TopologyManagerPolicy *string
    51  	// AllowedUnsafeSysctls - Allowlist of unsafe sysctls or unsafe sysctl patterns (ending in `*`).
    52  	AllowedUnsafeSysctls []string
    53  	// FailSwapOn - If set to true it will make the Kubelet fail to start if swap is enabled on the node.
    54  	FailSwapOn *bool
    55  	// ContainerLogMaxSizeMB - The maximum size (e.g. 10Mi) of container log file before it is rotated.
    56  	ContainerLogMaxSizeMB *int
    57  	// ContainerLogMaxFiles - The maximum number of container log files that can be present for a container. The number must be ≥ 2.
    58  	ContainerLogMaxFiles *int
    59  	// PodMaxPids - The maximum number of processes per pod.
    60  	PodMaxPids *int
    61  }
    62  
    63  // AgentPoolSpec contains agent pool specification details.
    64  type AgentPoolSpec struct {
    65  	// Name is the name of the ASO ManagedClustersAgentPool resource.
    66  	Name string
    67  
    68  	// AzureName is the name of the agentpool resource in Azure.
    69  	AzureName string
    70  
    71  	// ResourceGroup is the name of the Azure resource group for the AKS Cluster.
    72  	ResourceGroup string
    73  
    74  	// Cluster is the name of the AKS cluster.
    75  	Cluster string
    76  
    77  	// Version defines the desired Kubernetes version.
    78  	Version *string
    79  
    80  	// SKU defines the Azure VM size for the agent pool VMs.
    81  	SKU string
    82  
    83  	// Replicas is the number of desired machines.
    84  	Replicas int
    85  
    86  	// OSDiskSizeGB is the OS disk size in GB for every machine in this agent pool.
    87  	OSDiskSizeGB int
    88  
    89  	// VnetSubnetID is the Azure Resource ID for the subnet which should contain nodes.
    90  	VnetSubnetID string
    91  
    92  	// Mode represents mode of an agent pool. Possible values include: 'System', 'User'.
    93  	Mode string
    94  
    95  	//  Maximum number of nodes for auto-scaling
    96  	MaxCount *int `json:"maxCount,omitempty"`
    97  
    98  	// Minimum number of nodes for auto-scaling
    99  	MinCount *int `json:"minCount,omitempty"`
   100  
   101  	// Node labels - labels for all of the nodes present in node pool
   102  	NodeLabels map[string]string `json:"nodeLabels,omitempty"`
   103  
   104  	// NodeTaints specifies the taints for nodes present in this agent pool.
   105  	NodeTaints []string `json:"nodeTaints,omitempty"`
   106  
   107  	// EnableAutoScaling - Whether to enable auto-scaler
   108  	EnableAutoScaling bool `json:"enableAutoScaling,omitempty"`
   109  
   110  	// AvailabilityZones represents the Availability zones for nodes in the AgentPool.
   111  	AvailabilityZones []string
   112  
   113  	// MaxPods specifies the kubelet --max-pods configuration for the agent pool.
   114  	MaxPods *int `json:"maxPods,omitempty"`
   115  
   116  	// OsDiskType specifies the OS disk type for each node in the pool. Allowed values are 'Ephemeral' and 'Managed'.
   117  	OsDiskType *string `json:"osDiskType,omitempty"`
   118  
   119  	// EnableUltraSSD enables the storage type UltraSSD_LRS for the agent pool.
   120  	EnableUltraSSD *bool `json:"enableUltraSSD,omitempty"`
   121  
   122  	// OSType specifies the operating system for the node pool. Allowed values are 'Linux' and 'Windows'
   123  	OSType *string `json:"osType,omitempty"`
   124  
   125  	// EnableNodePublicIP controls whether or not nodes in the agent pool each have a public IP address.
   126  	EnableNodePublicIP *bool `json:"enableNodePublicIP,omitempty"`
   127  
   128  	// NodePublicIPPrefixID specifies the public IP prefix resource ID which VM nodes should use IPs from.
   129  	NodePublicIPPrefixID string `json:"nodePublicIPPrefixID,omitempty"`
   130  
   131  	// ScaleSetPriority specifies the ScaleSetPriority for the node pool. Allowed values are 'Spot' and 'Regular'
   132  	ScaleSetPriority *string `json:"scaleSetPriority,omitempty"`
   133  
   134  	// ScaleDownMode affects the cluster autoscaler behavior. Allowed values are 'Deallocate' and 'Delete'
   135  	ScaleDownMode *string `json:"scaleDownMode,omitempty"`
   136  
   137  	// SpotMaxPrice defines max price to pay for spot instance. Allowed values are any decimal value greater than zero or -1 which indicates the willingness to pay any on-demand price.
   138  	SpotMaxPrice *resource.Quantity `json:"spotMaxPrice,omitempty"`
   139  
   140  	// KubeletConfig specifies the kubelet configurations for nodes.
   141  	KubeletConfig *KubeletConfig `json:"kubeletConfig,omitempty"`
   142  
   143  	// KubeletDiskType specifies the kubelet disk type for each node in the pool. Allowed values are 'OS' and 'Temporary'
   144  	KubeletDiskType *infrav1.KubeletDiskType `json:"kubeletDiskType,omitempty"`
   145  
   146  	// AdditionalTags is an optional set of tags to add to Azure resources managed by the Azure provider, in addition to the ones added by default.
   147  	AdditionalTags infrav1.Tags
   148  
   149  	// LinuxOSConfig specifies the custom Linux OS settings and configurations
   150  	LinuxOSConfig *infrav1.LinuxOSConfig
   151  
   152  	// EnableFIPS indicates whether FIPS is enabled on the node pool
   153  	EnableFIPS *bool
   154  
   155  	// EnableEncryptionAtHost indicates whether host encryption is enabled on the node pool
   156  	EnableEncryptionAtHost *bool
   157  
   158  	// Patches are extra patches to be applied to the ASO resource.
   159  	Patches []string
   160  
   161  	// Preview indicates whether the agent pool is using a preview version of ASO.
   162  	Preview bool
   163  }
   164  
   165  // ResourceRef implements azure.ASOResourceSpecGetter.
   166  func (s *AgentPoolSpec) ResourceRef() genruntime.MetaObject {
   167  	if s.Preview {
   168  		return &asocontainerservicev1preview.ManagedClustersAgentPool{
   169  			ObjectMeta: metav1.ObjectMeta{
   170  				Name: azure.GetNormalizedKubernetesName(s.Name),
   171  			},
   172  		}
   173  	}
   174  	return &asocontainerservicev1.ManagedClustersAgentPool{
   175  		ObjectMeta: metav1.ObjectMeta{
   176  			Name: azure.GetNormalizedKubernetesName(s.Name),
   177  		},
   178  	}
   179  }
   180  
   181  // getManagedMachinePoolVersion gets the desired managed Kubernetes version.
   182  // If the auto upgrade channel is set to patch, stable or rapid, clusters can be upgraded to a higher version by AKS.
   183  // If auto upgrade is triggered, the existing Kubernetes version will be higher than the user's desired Kubernetes version.
   184  // CAPZ should honour the upgrade and it should not downgrade to the lower desired version.
   185  func (s *AgentPoolSpec) getManagedMachinePoolVersion(existing *asocontainerservicev1hub.ManagedClustersAgentPool) *string {
   186  	if existing == nil || existing.Spec.OrchestratorVersion == nil {
   187  		return s.Version
   188  	}
   189  	if s.Version == nil {
   190  		return existing.Spec.OrchestratorVersion
   191  	}
   192  	v := versions.GetHigherK8sVersion(*s.Version, *existing.Spec.OrchestratorVersion)
   193  	return ptr.To(v)
   194  }
   195  
   196  // Parameters returns the parameters for the agent pool.
   197  func (s *AgentPoolSpec) Parameters(ctx context.Context, existingObj genruntime.MetaObject) (params genruntime.MetaObject, err error) {
   198  	_, _, done := tele.StartSpanWithLogger(ctx, "agentpools.Service.Parameters")
   199  	defer done()
   200  
   201  	// If existing is preview, convert to stable then back to preview at the end of the function.
   202  	var existing *asocontainerservicev1hub.ManagedClustersAgentPool
   203  	if existingObj != nil {
   204  		hub := &asocontainerservicev1hub.ManagedClustersAgentPool{}
   205  		if err := existingObj.(conversion.Convertible).ConvertTo(hub); err != nil {
   206  			return nil, err
   207  		}
   208  		existing = hub
   209  	}
   210  
   211  	agentPool := existing
   212  	if agentPool == nil {
   213  		agentPool = &asocontainerservicev1hub.ManagedClustersAgentPool{}
   214  	}
   215  
   216  	agentPool.Spec.AzureName = s.AzureName
   217  	agentPool.Spec.Owner = &genruntime.KnownResourceReference{
   218  		Name: s.Cluster,
   219  	}
   220  	agentPool.Spec.AvailabilityZones = s.AvailabilityZones
   221  	agentPool.Spec.Count = &s.Replicas
   222  	agentPool.Spec.EnableAutoScaling = ptr.To(s.EnableAutoScaling)
   223  	agentPool.Spec.EnableUltraSSD = s.EnableUltraSSD
   224  	agentPool.Spec.KubeletDiskType = azure.AliasOrNil[string]((*string)(s.KubeletDiskType))
   225  	agentPool.Spec.MaxCount = s.MaxCount
   226  	agentPool.Spec.MaxPods = s.MaxPods
   227  	agentPool.Spec.MinCount = s.MinCount
   228  	agentPool.Spec.Mode = ptr.To(string(asocontainerservicev1.AgentPoolMode(s.Mode)))
   229  	agentPool.Spec.NodeLabels = s.NodeLabels
   230  	agentPool.Spec.NodeTaints = s.NodeTaints
   231  	agentPool.Spec.OsDiskSizeGB = ptr.To(int(asocontainerservicev1.ContainerServiceOSDisk(s.OSDiskSizeGB)))
   232  	agentPool.Spec.OsDiskType = azure.AliasOrNil[string](s.OsDiskType)
   233  	agentPool.Spec.OsType = azure.AliasOrNil[string](s.OSType)
   234  	agentPool.Spec.ScaleSetPriority = azure.AliasOrNil[string](s.ScaleSetPriority)
   235  	agentPool.Spec.ScaleDownMode = azure.AliasOrNil[string](s.ScaleDownMode)
   236  	agentPool.Spec.Type = ptr.To(string(asocontainerservicev1.AgentPoolType_VirtualMachineScaleSets))
   237  	agentPool.Spec.EnableNodePublicIP = s.EnableNodePublicIP
   238  	agentPool.Spec.Tags = s.AdditionalTags
   239  	agentPool.Spec.EnableFIPS = s.EnableFIPS
   240  	agentPool.Spec.EnableEncryptionAtHost = s.EnableEncryptionAtHost
   241  	if kubernetesVersion := s.getManagedMachinePoolVersion(existing); kubernetesVersion != nil {
   242  		agentPool.Spec.OrchestratorVersion = kubernetesVersion
   243  	}
   244  
   245  	if s.KubeletConfig != nil {
   246  		agentPool.Spec.KubeletConfig = &asocontainerservicev1hub.KubeletConfig{
   247  			CpuManagerPolicy:      s.KubeletConfig.CPUManagerPolicy,
   248  			CpuCfsQuota:           s.KubeletConfig.CPUCfsQuota,
   249  			CpuCfsQuotaPeriod:     s.KubeletConfig.CPUCfsQuotaPeriod,
   250  			ImageGcHighThreshold:  s.KubeletConfig.ImageGcHighThreshold,
   251  			ImageGcLowThreshold:   s.KubeletConfig.ImageGcLowThreshold,
   252  			TopologyManagerPolicy: s.KubeletConfig.TopologyManagerPolicy,
   253  			FailSwapOn:            s.KubeletConfig.FailSwapOn,
   254  			ContainerLogMaxSizeMB: s.KubeletConfig.ContainerLogMaxSizeMB,
   255  			ContainerLogMaxFiles:  s.KubeletConfig.ContainerLogMaxFiles,
   256  			PodMaxPids:            s.KubeletConfig.PodMaxPids,
   257  			AllowedUnsafeSysctls:  s.KubeletConfig.AllowedUnsafeSysctls,
   258  		}
   259  	}
   260  
   261  	if s.SKU != "" {
   262  		agentPool.Spec.VmSize = &s.SKU
   263  	}
   264  
   265  	if s.SpotMaxPrice != nil {
   266  		agentPool.Spec.SpotMaxPrice = ptr.To(s.SpotMaxPrice.AsApproximateFloat64())
   267  	}
   268  
   269  	if s.VnetSubnetID != "" {
   270  		agentPool.Spec.VnetSubnetReference = &genruntime.ResourceReference{
   271  			ARMID: s.VnetSubnetID,
   272  		}
   273  	}
   274  
   275  	if s.NodePublicIPPrefixID != "" {
   276  		agentPool.Spec.NodePublicIPPrefixReference = &genruntime.ResourceReference{
   277  			ARMID: s.NodePublicIPPrefixID,
   278  		}
   279  	}
   280  
   281  	if s.LinuxOSConfig != nil {
   282  		agentPool.Spec.LinuxOSConfig = &asocontainerservicev1hub.LinuxOSConfig{
   283  			SwapFileSizeMB:             s.LinuxOSConfig.SwapFileSizeMB,
   284  			TransparentHugePageEnabled: (*string)(s.LinuxOSConfig.TransparentHugePageEnabled),
   285  			TransparentHugePageDefrag:  (*string)(s.LinuxOSConfig.TransparentHugePageDefrag),
   286  		}
   287  		if s.LinuxOSConfig.Sysctls != nil {
   288  			agentPool.Spec.LinuxOSConfig.Sysctls = &asocontainerservicev1hub.SysctlConfig{
   289  				FsAioMaxNr:                     s.LinuxOSConfig.Sysctls.FsAioMaxNr,
   290  				FsFileMax:                      s.LinuxOSConfig.Sysctls.FsFileMax,
   291  				FsInotifyMaxUserWatches:        s.LinuxOSConfig.Sysctls.FsInotifyMaxUserWatches,
   292  				FsNrOpen:                       s.LinuxOSConfig.Sysctls.FsNrOpen,
   293  				KernelThreadsMax:               s.LinuxOSConfig.Sysctls.KernelThreadsMax,
   294  				NetCoreNetdevMaxBacklog:        s.LinuxOSConfig.Sysctls.NetCoreNetdevMaxBacklog,
   295  				NetCoreOptmemMax:               s.LinuxOSConfig.Sysctls.NetCoreOptmemMax,
   296  				NetCoreRmemDefault:             s.LinuxOSConfig.Sysctls.NetCoreRmemDefault,
   297  				NetCoreRmemMax:                 s.LinuxOSConfig.Sysctls.NetCoreRmemMax,
   298  				NetCoreSomaxconn:               s.LinuxOSConfig.Sysctls.NetCoreSomaxconn,
   299  				NetCoreWmemDefault:             s.LinuxOSConfig.Sysctls.NetCoreWmemDefault,
   300  				NetCoreWmemMax:                 s.LinuxOSConfig.Sysctls.NetCoreWmemMax,
   301  				NetIpv4IpLocalPortRange:        s.LinuxOSConfig.Sysctls.NetIpv4IPLocalPortRange,
   302  				NetIpv4NeighDefaultGcThresh1:   s.LinuxOSConfig.Sysctls.NetIpv4NeighDefaultGcThresh1,
   303  				NetIpv4NeighDefaultGcThresh2:   s.LinuxOSConfig.Sysctls.NetIpv4NeighDefaultGcThresh2,
   304  				NetIpv4NeighDefaultGcThresh3:   s.LinuxOSConfig.Sysctls.NetIpv4NeighDefaultGcThresh3,
   305  				NetIpv4TcpFinTimeout:           s.LinuxOSConfig.Sysctls.NetIpv4TCPFinTimeout,
   306  				NetIpv4TcpKeepaliveProbes:      s.LinuxOSConfig.Sysctls.NetIpv4TCPKeepaliveProbes,
   307  				NetIpv4TcpKeepaliveTime:        s.LinuxOSConfig.Sysctls.NetIpv4TCPKeepaliveTime,
   308  				NetIpv4TcpMaxSynBacklog:        s.LinuxOSConfig.Sysctls.NetIpv4TCPMaxSynBacklog,
   309  				NetIpv4TcpMaxTwBuckets:         s.LinuxOSConfig.Sysctls.NetIpv4TCPMaxTwBuckets,
   310  				NetIpv4TcpTwReuse:              s.LinuxOSConfig.Sysctls.NetIpv4TCPTwReuse,
   311  				NetIpv4TcpkeepaliveIntvl:       s.LinuxOSConfig.Sysctls.NetIpv4TCPkeepaliveIntvl,
   312  				NetNetfilterNfConntrackBuckets: s.LinuxOSConfig.Sysctls.NetNetfilterNfConntrackBuckets,
   313  				NetNetfilterNfConntrackMax:     s.LinuxOSConfig.Sysctls.NetNetfilterNfConntrackMax,
   314  				VmMaxMapCount:                  s.LinuxOSConfig.Sysctls.VMMaxMapCount,
   315  				VmSwappiness:                   s.LinuxOSConfig.Sysctls.VMSwappiness,
   316  				VmVfsCachePressure:             s.LinuxOSConfig.Sysctls.VMVfsCachePressure,
   317  			}
   318  		}
   319  	}
   320  
   321  	// When autoscaling is set, the count of the nodes differ based on the autoscaler and should not depend on the
   322  	// count present in MachinePool or AzureManagedMachinePool, hence we should not make an update API call based
   323  	// on difference in count.
   324  	if s.EnableAutoScaling && agentPool.Status.Count != nil {
   325  		agentPool.Spec.Count = agentPool.Status.Count
   326  	}
   327  
   328  	if s.Preview {
   329  		prev := &asocontainerservicev1preview.ManagedClustersAgentPool{}
   330  		if err := prev.ConvertFrom(agentPool); err != nil {
   331  			return nil, err
   332  		}
   333  		return prev, nil
   334  	}
   335  
   336  	stable := &asocontainerservicev1.ManagedClustersAgentPool{}
   337  	if err := stable.ConvertFrom(agentPool); err != nil {
   338  		return nil, err
   339  	}
   340  
   341  	return stable, nil
   342  }
   343  
   344  // WasManaged implements azure.ASOResourceSpecGetter.
   345  func (s *AgentPoolSpec) WasManaged(resource genruntime.MetaObject) bool {
   346  	// CAPZ has never supported BYO agent pools.
   347  	return true
   348  }
   349  
   350  var _ aso.Patcher = (*AgentPoolSpec)(nil)
   351  
   352  // ExtraPatches implements aso.Patcher.
   353  func (s *AgentPoolSpec) ExtraPatches() []string {
   354  	return s.Patches
   355  }