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