-
Notifications
You must be signed in to change notification settings - Fork 108
Expand file tree
/
Copy pathaksnodeclass.go
More file actions
457 lines (420 loc) · 22.8 KB
/
aksnodeclass.go
File metadata and controls
457 lines (420 loc) · 22.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
/*
Portions Copyright (c) Microsoft Corporation.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha2
import (
"fmt"
"strings"
"github.com/blang/semver/v4"
"github.com/mitchellh/hashstructure/v2"
"github.com/samber/lo"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
karpv1 "sigs.k8s.io/karpenter/pkg/apis/v1"
)
type FIPSMode string
var (
FIPSModeFIPS = FIPSMode("FIPS")
FIPSModeDisabled = FIPSMode("Disabled")
)
// AKSNodeClassSpec is the top level specification for the AKS Karpenter Provider.
// This will contain configuration necessary to launch instances in AKS.
// +kubebuilder:validation:XValidation:message="FIPS is not yet supported for Ubuntu2204 or Ubuntu2404",rule="has(self.fipsMode) && self.fipsMode == 'FIPS' ? (has(self.imageFamily) && self.imageFamily != 'Ubuntu2204' && self.imageFamily != 'Ubuntu2404') : true"
type AKSNodeClassSpec struct {
// vnetSubnetID is the subnet used by nics provisioned with this nodeclass.
// If not specified, we will use the default --vnet-subnet-id specified in karpenter's options config
// +kubebuilder:validation:Pattern=`(?i)^\/subscriptions\/[^\/]+\/resourceGroups\/[a-zA-Z0-9_\-().]{0,89}[a-zA-Z0-9_\-()]\/providers\/Microsoft\.Network\/virtualNetworks\/[^\/]+\/subnets\/[^\/]+$`
// +optional
VNETSubnetID *string `json:"vnetSubnetID,omitempty"`
// osDiskSizeGB is the size of the OS disk in GB.
// +default=128
// +kubebuilder:validation:Minimum=30
// +kubebuilder:validation:Maximum=2048
// +optional
OSDiskSizeGB *int32 `json:"osDiskSizeGB,omitempty"`
// ImageID is the ID of the image that instances use.
// Not exposed in the API yet
ImageID *string `json:"-"`
// imageFamily is the image family that instances use.
// +default="Ubuntu"
// +kubebuilder:validation:Enum:={Ubuntu,Ubuntu2204,Ubuntu2404,AzureLinux}
// +optional
ImageFamily *string `json:"imageFamily,omitempty"`
// fipsMode controls FIPS compliance for the provisioned nodes
// +kubebuilder:validation:Enum:={FIPS,Disabled}
// +optional
FIPSMode *FIPSMode `json:"fipsMode,omitempty"`
// tags to be applied on Azure resources like instances.
// +kubebuilder:validation:XValidation:message="tags keys must be less than 512 characters",rule="self.all(k, size(k) <= 512)"
// +kubebuilder:validation:XValidation:message="tags keys must not contain '<', '>', '%', '&', or '?'",rule="self.all(k, !k.matches('[<>%&?]'))"
// +kubebuilder:validation:XValidation:message="tags keys must not contain '\\'",rule="self.all(k, !k.contains('\\\\'))"
// +kubebuilder:validation:XValidation:message="tags values must be less than 256 characters",rule="self.all(k, size(self[k]) <= 256)"
// +optional
Tags map[string]string `json:"tags,omitempty" hash:"ignore"`
// kubelet defines args to be used when configuring kubelet on provisioned nodes.
// They are a subset of the upstream types, recognizing not all options may be supported.
// Wherever possible, the types and names should reflect the upstream kubelet types.
// +kubebuilder:validation:XValidation:message="imageGCHighThresholdPercent must be greater than imageGCLowThresholdPercent",rule="has(self.imageGCHighThresholdPercent) && has(self.imageGCLowThresholdPercent) ? self.imageGCHighThresholdPercent > self.imageGCLowThresholdPercent : true"
// +optional
Kubelet *KubeletConfiguration `json:"kubelet,omitempty"`
// maxPods is an override for the maximum number of pods that can run on a worker node instance.
// See minimum + maximum pods per node documentation: https://learn.microsoft.com/en-us/azure/aks/concepts-network-ip-address-planning#maximum-pods-per-node
// Default behavior if this is not specified depends on the network plugin:
// - If Network Plugin is Azure with "" (v1 or NodeSubnet), the default is 30.
// - If Network Plugin is Azure with "overlay", the default is 250.
// - If Network Plugin is None, the default is 250.
// - Otherwise, the default is 110 (the usual Kubernetes default).
//
// +kubebuilder:validation:Minimum:=10
// +kubebuilder:validation:Maximum:=250
// +optional
MaxPods *int32 `json:"maxPods,omitempty"`
// security is a collection of security related karpenter fields
// +optional
Security *Security `json:"security,omitempty"`
// localDNS configures the per-node local DNS, with VnetDNS and KubeDNS overrides.
// LocalDNS helps improve performance and reliability of DNS resolution in an AKS cluster.
// For more details see aka.ms/aks/localdns.
// +optional
LocalDNS *LocalDNS `json:"localDNS,omitempty"`
}
// TODO: Add link for the aka.ms/nap/aksnodeclass-enable-host-encryption docs
type Security struct {
// encryptionAtHost specifies whether host-level encryption is enabled for provisioned nodes.
// For more information, see:
// https://learn.microsoft.com/en-us/azure/aks/enable-host-encryption
// https://learn.microsoft.com/en-us/azure/virtual-machines/disk-encryption#encryption-at-host---end-to-end-encryption-for-your-vm-data
// +optional
EncryptionAtHost *bool `json:"encryptionAtHost,omitempty"`
}
// +kubebuilder:validation:Enum:={Preferred,Required,Disabled}
type LocalDNSMode string
const (
// If the current orchestrator version supports this feature, prefer enabling localDNS.
LocalDNSModePreferred LocalDNSMode = "Preferred"
// Enable localDNS.
LocalDNSModeRequired LocalDNSMode = "Required"
// Disable localDNS.
LocalDNSModeDisabled LocalDNSMode = "Disabled"
)
// LocalDNS configures the per-node local DNS, with VnetDNS and KubeDNS overrides.
// LocalDNS helps improve performance and reliability of DNS resolution in an AKS cluster.
// For more details see aka.ms/aks/localdns.
type LocalDNS struct {
// mode of enablement for localDNS.
// +required
Mode LocalDNSMode `json:"mode,omitempty"`
// vnetDNSOverrides apply to DNS traffic from pods with dnsPolicy:default or kubelet (referred to as VnetDNS traffic).
// +required
// +listType=map
// +listMapKey=zone
// +kubebuilder:validation:XValidation:message="must contain required zones '.' and 'cluster.local'",rule="['.', 'cluster.local'].all(z, self.exists(x, x.zone == z))"
// +kubebuilder:validation:XValidation:message="root zone '.' cannot be forwarded to ClusterCoreDNS from vnetDNSOverrides",rule="!self.exists(x, x.zone == '.' && x.forwardDestination == 'ClusterCoreDNS')"
// +kubebuilder:validation:XValidation:message="external domains cannot be forwarded to ClusterCoreDNS from vnetDNSOverrides",rule="!self.exists(x, x.zone != '.' && !x.zone.endsWith('cluster.local') && x.forwardDestination == 'ClusterCoreDNS')"
// +kubebuilder:validation:MaxItems=100
VnetDNSOverrides []LocalDNSZoneOverride `json:"vnetDNSOverrides,omitempty"`
// kubeDNSOverrides apply to DNS traffic from pods with dnsPolicy:ClusterFirst (referred to as KubeDNS traffic).
// +required
// +listType=map
// +listMapKey=zone
// +kubebuilder:validation:XValidation:message="must contain required zones '.' and 'cluster.local'",rule="['.', 'cluster.local'].all(z, self.exists(x, x.zone == z))"
// +kubebuilder:validation:MaxItems=100
KubeDNSOverrides []LocalDNSZoneOverride `json:"kubeDNSOverrides,omitempty"`
}
// LocalDNSZoneOverride specifies DNS override configuration for a specific zone
// +kubebuilder:validation:XValidation:message="'cluster.local' cannot be forwarded to VnetDNS",rule="!(self.zone.endsWith('cluster.local') && self.forwardDestination == 'VnetDNS')"
// +kubebuilder:validation:XValidation:message="serveStale Verify cannot be used with protocol ForceTCP",rule="!(self.serveStale == 'Verify' && self.protocol == 'ForceTCP')"
type LocalDNSZoneOverride struct {
// zone is the DNS zone this override applies to (e.g., ".", "cluster.local").
// +required
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=254
// +kubebuilder:validation:Pattern=`^(\.|[A-Za-z0-9]([A-Za-z0-9_-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9_-]{0,61}[A-Za-z0-9])?)*\.?)$`
Zone string `json:"zone,omitempty"`
// queryLogging is the log level for DNS queries in localDNS.
// +required
QueryLogging LocalDNSQueryLogging `json:"queryLogging,omitempty"`
// protocol enforces TCP or prefers UDP protocol for connections from localDNS to upstream DNS server.
// +required
Protocol LocalDNSProtocol `json:"protocol,omitempty"`
// forwardDestination is the destination server for DNS queries to be forwarded from localDNS.
// +required
ForwardDestination LocalDNSForwardDestination `json:"forwardDestination,omitempty"`
// forwardPolicy is the forward policy for selecting upstream DNS server. See [forward plugin](https://coredns.io/plugins/forward) for more information.
// +required
ForwardPolicy LocalDNSForwardPolicy `json:"forwardPolicy,omitempty"`
// maxConcurrent is the maximum number of concurrent queries. See [forward plugin](https://coredns.io/plugins/forward) for more information.
// +kubebuilder:validation:Minimum=0
// +required
MaxConcurrent *int32 `json:"maxConcurrent,omitempty"`
// Cache max TTL. See [cache plugin](https://coredns.io/plugins/cache) for more information.
// +kubebuilder:validation:Pattern=`^([0-9]+(s|m|h))+$`
// +kubebuilder:validation:Type="string"
// +kubebuilder:validation:Schemaless
// +required
CacheDuration karpv1.NillableDuration `json:"cacheDuration"`
// Serve stale duration. See [cache plugin](https://coredns.io/plugins/cache) for more information.
// +kubebuilder:validation:Pattern=`^([0-9]+(s|m|h))+$`
// +kubebuilder:validation:Type="string"
// +kubebuilder:validation:Schemaless
// +required
ServeStaleDuration karpv1.NillableDuration `json:"serveStaleDuration"`
// serveStale is the policy for serving stale data. See [cache plugin](https://coredns.io/plugins/cache) for more information.
// +required
ServeStale LocalDNSServeStale `json:"serveStale,omitempty"`
}
// LocalDNSOverrides specifies DNS override configuration
// Deprecated: Use LocalDNSZoneOverride instead
type LocalDNSOverrides struct {
// queryLogging is the log level for DNS queries in localDNS.
// +required
QueryLogging LocalDNSQueryLogging `json:"queryLogging,omitempty"`
// protocol enforces TCP or prefers UDP protocol for connections from localDNS to upstream DNS server.
// +required
Protocol LocalDNSProtocol `json:"protocol,omitempty"`
// forwardDestination is the destination server for DNS queries to be forwarded from localDNS.
// +required
ForwardDestination LocalDNSForwardDestination `json:"forwardDestination,omitempty"`
// forwardPolicy is the forward policy for selecting upstream DNS server. See [forward plugin](https://coredns.io/plugins/forward) for more information.
// +required
ForwardPolicy LocalDNSForwardPolicy `json:"forwardPolicy,omitempty"`
// maxConcurrent is the maximum number of concurrent queries. See [forward plugin](https://coredns.io/plugins/forward) for more information.
// +kubebuilder:validation:Minimum=0
// +required
MaxConcurrent *int32 `json:"maxConcurrent,omitempty"`
// Cache max TTL. See [cache plugin](https://coredns.io/plugins/cache) for more information.
// +kubebuilder:validation:Pattern=`^([0-9]+(s|m|h))+$`
// +kubebuilder:validation:Type="string"
// +kubebuilder:validation:Schemaless
// +required
CacheDuration karpv1.NillableDuration `json:"cacheDuration"`
// Serve stale duration. See [cache plugin](https://coredns.io/plugins/cache) for more information.
// +kubebuilder:validation:Pattern=`^([0-9]+(s|m|h))+$`
// +kubebuilder:validation:Type="string"
// +kubebuilder:validation:Schemaless
// +required
ServeStaleDuration karpv1.NillableDuration `json:"serveStaleDuration"`
// serveStale is the policy for serving stale data. See [cache plugin](https://coredns.io/plugins/cache) for more information.
// +required
ServeStale LocalDNSServeStale `json:"serveStale,omitempty"`
}
// +kubebuilder:validation:Enum:={Error,Log}
type LocalDNSQueryLogging string
const (
// Enables error logging in localDNS. See [errors plugin](https://coredns.io/plugins/errors) for more information.
LocalDNSQueryLoggingError LocalDNSQueryLogging = "Error"
// Enables query logging in localDNS. See [log plugin](https://coredns.io/plugins/log) for more information.
LocalDNSQueryLoggingLog LocalDNSQueryLogging = "Log"
)
// +kubebuilder:validation:Enum:={PreferUDP,ForceTCP}
type LocalDNSProtocol string
const (
// Prefer UDP protocol for connections from localDNS to upstream DNS server.
LocalDNSProtocolPreferUDP LocalDNSProtocol = "PreferUDP"
// Enforce TCP protocol for connections from localDNS to upstream DNS server.
LocalDNSProtocolForceTCP LocalDNSProtocol = "ForceTCP"
)
// +kubebuilder:validation:Enum:={ClusterCoreDNS,VnetDNS}
type LocalDNSForwardDestination string
const (
// Forward DNS queries from localDNS to cluster CoreDNS.
LocalDNSForwardDestinationClusterCoreDNS LocalDNSForwardDestination = "ClusterCoreDNS"
// Forward DNS queries from localDNS to DNS server configured in the VNET. A VNET can have multiple DNS servers configured.
LocalDNSForwardDestinationVnetDNS LocalDNSForwardDestination = "VnetDNS"
)
// +kubebuilder:validation:Enum:={Sequential,RoundRobin,Random}
type LocalDNSForwardPolicy string
const (
// Implements sequential upstream DNS server selection. See [forward plugin](https://coredns.io/plugins/forward) for more information.
LocalDNSForwardPolicySequential LocalDNSForwardPolicy = "Sequential"
// Implements round robin upstream DNS server selection. See [forward plugin](https://coredns.io/plugins/forward) for more information.
LocalDNSForwardPolicyRoundRobin LocalDNSForwardPolicy = "RoundRobin"
// Implements random upstream DNS server selection. See [forward plugin](https://coredns.io/plugins/forward) for more information.
LocalDNSForwardPolicyRandom LocalDNSForwardPolicy = "Random"
)
// +kubebuilder:validation:Enum:={Verify,Immediate,Disable}
type LocalDNSServeStale string
const (
// Serve stale data with verification. First verify that an entry is still unavailable from the source before sending the expired entry to the client. See [cache plugin](https://coredns.io/plugins/cache) for more information.
LocalDNSServeStaleVerify LocalDNSServeStale = "Verify"
// Serve stale data immediately. Send the expired entry to the client before checking to see if the entry is available from the source. See [cache plugin](https://coredns.io/plugins/cache) for more information.
LocalDNSServeStaleImmediate LocalDNSServeStale = "Immediate"
// Disable serving stale data.
LocalDNSServeStaleDisable LocalDNSServeStale = "Disable"
)
// KubeletConfiguration defines args to be used when configuring kubelet on provisioned nodes.
// They are a subset of the upstream types, recognizing not all options may be supported.
// Wherever possible, the types and names should reflect the upstream kubelet types.
// https://pkg.go.dev/k8s.io/kubelet/config/v1beta1#KubeletConfiguration
// https://github.com/kubernetes/kubernetes/blob/9f82d81e55cafdedab619ea25cabf5d42736dacf/cmd/kubelet/app/options/options.go#L53
//
// AKS CustomKubeletConfig w/o CPUReserved,MemoryReserved,SeccompDefault
// https://learn.microsoft.com/en-us/azure/aks/custom-node-configuration?tabs=linux-node-pools
type KubeletConfiguration struct {
// cpuManagerPolicy is the name of the policy to use.
// +kubebuilder:validation:Enum:={none,static}
// +default="none"
// +optional
//nolint:kubeapilinter // optionalfields: changing to pointer would be a breaking change
CPUManagerPolicy string `json:"cpuManagerPolicy,omitempty"`
// cpuCFSQuota enables CPU CFS quota enforcement for containers that specify CPU limits.
// Note: AKS CustomKubeletConfig uses cpuCfsQuota (camelCase)
// +default=true
// +optional
CPUCFSQuota *bool `json:"cpuCFSQuota,omitempty"`
// cpuCFSQuotaPeriod sets the CPU CFS quota period value, `cpu.cfs_period_us`.
// The value must be between 1 ms and 1 second, inclusive.
// Default: "100ms"
// +optional
// +default="100ms"
// TODO: validation
//nolint:kubeapilinter // nodurations: using Duration for compatibility with upstream kubelet types
CPUCFSQuotaPeriod metav1.Duration `json:"cpuCFSQuotaPeriod,omitempty"`
// imageGCHighThresholdPercent is the percent of disk usage after which image
// garbage collection is always run. The percent is calculated by dividing this
// field value by 100, so this field must be between 0 and 100, inclusive.
// When specified, the value must be greater than ImageGCLowThresholdPercent.
// Note: AKS CustomKubeletConfig does not have "Percent" in the field name
// +kubebuilder:validation:Minimum:=0
// +kubebuilder:validation:Maximum:=100
// +optional
ImageGCHighThresholdPercent *int32 `json:"imageGCHighThresholdPercent,omitempty"`
// imageGCLowThresholdPercent is the percent of disk usage before which image
// garbage collection is never run. Lowest disk usage to garbage collect to.
// The percent is calculated by dividing this field value by 100,
// so the field value must be between 0 and 100, inclusive.
// When specified, the value must be less than imageGCHighThresholdPercent
// Note: AKS CustomKubeletConfig does not have "Percent" in the field name
// +kubebuilder:validation:Minimum:=0
// +kubebuilder:validation:Maximum:=100
// +optional
ImageGCLowThresholdPercent *int32 `json:"imageGCLowThresholdPercent,omitempty"`
// topologyManagerPolicy is the name of the topology manager policy to use.
// Valid values include:
//
// - `restricted`: kubelet only allows pods with optimal NUMA node alignment for requested resources;
// - `best-effort`: kubelet will favor pods with NUMA alignment of CPU and device resources;
// - `none`: kubelet has no knowledge of NUMA alignment of a pod's CPU and device resources.
// - `single-numa-node`: kubelet only allows pods with a single NUMA alignment
// of CPU and device resources.
//
// +kubebuilder:validation:Enum:={restricted,best-effort,none,single-numa-node}
// +default="none"
// +optional
//nolint:kubeapilinter // optionalfields: changing to pointer would be a breaking change
TopologyManagerPolicy string `json:"topologyManagerPolicy,omitempty"`
// allowedUnsafeSysctls is a comma separated whitelist of unsafe sysctls or sysctl patterns (ending in `*`).
// Unsafe sysctl groups are `kernel.shm*`, `kernel.msg*`, `kernel.sem`, `fs.mqueue.*`,
// and `net.*`. For example: "`kernel.msg*,net.ipv4.route.min_pmtu`"
// Default: []
// TODO: validation
// +optional
//nolint:kubeapilinter // ssatags: adding listType marker would be a breaking change
AllowedUnsafeSysctls []string `json:"allowedUnsafeSysctls,omitempty"`
// containerLogMaxSize is a quantity defining the maximum size of the container log
// file before it is rotated. For example: "5Mi" or "256Ki".
// Default: "10Mi"
// AKS CustomKubeletConfig has containerLogMaxSizeMB (with units), defaults to 50
// +kubebuilder:validation:Pattern=`^\d+(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$`
// +default="50Mi"
// +optional
//nolint:kubeapilinter // optionalfields: changing to pointer would be a breaking change
ContainerLogMaxSize string `json:"containerLogMaxSize,omitempty"`
// containerLogMaxFiles specifies the maximum number of container log files that can be present for a container.
// Default: 5
// +kubebuilder:validation:Minimum:=2
// +default=5
// +optional
ContainerLogMaxFiles *int32 `json:"containerLogMaxFiles,omitempty"`
// podPidsLimit is the maximum number of PIDs in any pod.
// AKS CustomKubeletConfig uses PodMaxPids, int32 (!)
// Default: -1
// +optional
PodPidsLimit *int64 `json:"podPidsLimit,omitempty"`
}
// AKSNodeClass is the Schema for the AKSNodeClass API
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=aksnodeclasses,scope=Cluster,categories={karpenter,nap},shortName={aksnc,aksncs}
// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=".status.conditions[?(@.type=='Ready')].status"
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=".metadata.creationTimestamp"
// +kubebuilder:printcolumn:name="ImageFamily",type=string,JSONPath=".spec.imageFamily",priority=1
// +kubebuilder:subresource:status
// +kubebuilder:deprecatedversion:warning="use v1beta1.AKSNodeClass instead"
type AKSNodeClass struct {
metav1.TypeMeta `json:",inline"`
// metadata is standard object metadata.
// +optional
metav1.ObjectMeta `json:"metadata,omitempty"`
// spec is the top level specification for the AKS Karpenter Provider.
// This will contain configuration necessary to launch instances in AKS.
// +optional
//nolint:kubeapilinter // optionalfields: changing to pointer would be a breaking change
Spec AKSNodeClassSpec `json:"spec,omitempty"`
// status contains the resolved state of the AKSNodeClass.
// +optional
//nolint:kubeapilinter // optionalfields: changing to pointer would be a breaking change
Status AKSNodeClassStatus `json:"status,omitempty"`
}
// We need to bump the AKSNodeClassHashVersion when we make an update to the AKSNodeClass CRD under these conditions:
// 1. A field changes its default value for an existing field that is already hashed
// 2. A field is added to the hash calculation with an already-set value
// 3. A field is removed from the hash calculations
const AKSNodeClassHashVersion = "v3"
func (in *AKSNodeClass) Hash() string {
return fmt.Sprint(lo.Must(hashstructure.Hash(in.Spec, hashstructure.FormatV2, &hashstructure.HashOptions{
SlicesAsSets: true,
IgnoreZeroValue: true,
ZeroNil: true,
})))
}
// AKSNodeClassList contains a list of AKSNodeClass
// +kubebuilder:object:root=true
type AKSNodeClassList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []AKSNodeClass `json:"items"`
}
// GetEncryptionAtHost returns whether encryption at host is enabled for the node class.
// Returns false if Security or EncryptionAtHost is nil.
func (in *AKSNodeClass) GetEncryptionAtHost() bool {
if in.Spec.Security != nil && in.Spec.Security.EncryptionAtHost != nil {
return *in.Spec.Security.EncryptionAtHost
}
return false
}
// IsLocalDNSEnabled returns whether LocalDNS should be enabled for this node class.
// Returns true for Required mode, false for Disabled mode, and for Preferred mode,
// returns true only if the Kubernetes version is >= 1.35.
func (in *AKSNodeClass) IsLocalDNSEnabled() bool {
if in.Spec.LocalDNS == nil || in.Spec.LocalDNS.Mode == "" {
return false
}
switch in.Spec.LocalDNS.Mode {
case LocalDNSModeRequired:
return true
case LocalDNSModeDisabled:
return false
case LocalDNSModePreferred:
// For Preferred mode, check if K8s version >= 1.35
kubernetesVersion, err := in.GetKubernetesVersion()
if err != nil {
return false // If we can't get version, don't enable
}
// Parse version
parsedVersion, err := semver.ParseTolerant(strings.TrimPrefix(kubernetesVersion, "v"))
if err != nil {
return false
}
return parsedVersion.GE(semver.Version{Major: 1, Minor: 35})
default:
return false
}
}