@@ -25,9 +25,22 @@ import (
2525)
2626
2727var (
28- KarpenterGroup = "karpenter.sh"
29- KarpenterVersion = "v1"
30- kindNodeClaim = "NodeClaim"
28+ KarpenterGroup = "karpenter.sh"
29+ KarpenterVersion = "v1"
30+ kindNodeClaim = "NodeClaim"
31+ DefaultGPUResourceName = "nvidia.com/gpu"
32+ EC2NodeClassGroup = "karpenter.k8s.aws"
33+ // AWS capacity type: https://karpenter.sh/docs/concepts/scheduling/#well-known-labels
34+ AWSOnDemandType = "on-demand"
35+ AWSReservedType = "reserved"
36+ AWSSpotType = "spot"
37+
38+ // CapacityTypeMapping maps the CapacityTypeEnum to the corresponding Karpenter capacity type
39+ CapacityTypeMapping = map [tfv1.CapacityTypeEnum ]string {
40+ tfv1 .CapacityTypeOnDemand : AWSOnDemandType ,
41+ tfv1 .CapacityTypeSpot : AWSReservedType ,
42+ tfv1 .CapacityTypeReserved : AWSSpotType ,
43+ }
3144)
3245
3346// KarpenterExtraConfig holds Karpenter-specific configuration parsed from ExtraParams
@@ -83,20 +96,12 @@ func (p KarpenterGPUNodeProvider) TestConnection() error {
8396 if p .client == nil {
8497 return fmt .Errorf ("kubernetes client is not initialized" )
8598 }
86- exist := true
8799 // check if NodeClaim CRD exists
88100 if err := p .client .List (context .Background (), & karpv1.NodeClaimList {}); err != nil {
89101 log .FromContext (p .ctx ).Error (err , "karpenter NodeClaim CRD not found." )
90- exist = false
91- }
92- if exist {
93- return nil
94- }
95- // check if NodePool CRD exists
96- if err := p .client .List (context .Background (), & karpv1.NodePoolList {}); err != nil {
97- log .FromContext (p .ctx ).Error (err , "karpenter NodePool CRD not found." )
98- return fmt .Errorf ("karpenter CRD not found or not accessible" )
102+ return fmt .Errorf ("karpenter nodeclaim CRD not found or not accessible" )
99103 }
104+ log .FromContext (p .ctx ).Info ("Test connection to Karpenter nodeclaim succeeded." )
100105 return nil
101106}
102107
@@ -224,7 +229,9 @@ func (p KarpenterGPUNodeProvider) GetGPUNodeInstanceTypeInfo(region string) []ty
224229
225230// parseKarpenterConfig extracts Karpenter-specific configuration from ExtraParams
226231func (p KarpenterGPUNodeProvider ) parseKarpenterConfig (param * tfv1.GPUNodeClaimSpec ) * KarpenterExtraConfig {
227- karpenterConfig := & KarpenterExtraConfig {}
232+ karpenterConfig := & KarpenterExtraConfig {
233+ GPUResourceName : corev1 .ResourceName (DefaultGPUResourceName ),
234+ }
228235 extraParams := param .ExtraParams
229236 if extraParams == nil {
230237 return karpenterConfig
@@ -261,7 +268,7 @@ func (p KarpenterGPUNodeProvider) parseKarpenterConfig(param *tfv1.GPUNodeClaimS
261268 }
262269
263270 if karpenterConfig .GPUResourceName == "" {
264- karpenterConfig .GPUResourceName = "nvidia.com/gpu"
271+ karpenterConfig .GPUResourceName = corev1 . ResourceName ( DefaultGPUResourceName )
265272 }
266273
267274 return karpenterConfig
@@ -375,44 +382,77 @@ func (p KarpenterGPUNodeProvider) queryAndBuildNodeClassRef(ctx context.Context,
375382func (p KarpenterGPUNodeProvider ) buildRequirements (nodeClaim * karpv1.NodeClaim , param * tfv1.GPUNodeClaimSpec ) {
376383 // Build node selector requirements using Karpenter's NodeSelectorRequirement
377384 requirements := []karpv1.NodeSelectorRequirementWithMinValues {}
385+ seen := make (map [string ]struct {})
378386 // 1. instance type
379387 if param .InstanceType != "" {
388+ key := string (tfv1 .NodeRequirementKeyInstanceType )
380389 requirements = append (requirements , karpv1.NodeSelectorRequirementWithMinValues {
381390 NodeSelectorRequirement : corev1.NodeSelectorRequirement {
382- Key : string ( tfv1 . NodeRequirementKeyInstanceType ) ,
391+ Key : key ,
383392 Operator : corev1 .NodeSelectorOpIn ,
384393 Values : []string {param .InstanceType },
385394 },
386395 })
396+ seen [key ] = struct {}{}
387397 }
388398 // 2. zone
389399 if param .Zone != "" {
400+ key := string (tfv1 .NodeRequirementKeyZone )
390401 requirements = append (requirements , karpv1.NodeSelectorRequirementWithMinValues {
391402 NodeSelectorRequirement : corev1.NodeSelectorRequirement {
392- Key : string ( tfv1 . NodeRequirementKeyZone ) ,
403+ Key : key ,
393404 Operator : corev1 .NodeSelectorOpIn ,
394405 Values : []string {param .Zone },
395406 },
396407 })
408+ seen [key ] = struct {}{}
397409 }
398410
399411 // 3. region
400412 if param .Region != "" {
413+ key := string (tfv1 .NodeRequirementKeyRegion )
401414 requirements = append (requirements , karpv1.NodeSelectorRequirementWithMinValues {
402415 NodeSelectorRequirement : corev1.NodeSelectorRequirement {
403- Key : string ( tfv1 . NodeRequirementKeyRegion ) ,
416+ Key : key ,
404417 Operator : corev1 .NodeSelectorOpIn ,
405418 Values : []string {param .Region },
406419 },
407420 })
421+ seen [key ] = struct {}{}
422+ }
423+ // 4. capacity type
424+ if param .CapacityType != "" {
425+ key := string (tfv1 .NodeRequirementKeyCapacityType )
426+ value := string (param .CapacityType )
427+ // if capacity type is not in the mapping, use the original value
428+ // otherwise, use the mapping value
429+ // https://github.com/kubernetes-sigs/karpenter/blob/f8da711d7e72b678e77f4758bc73a34ba34286d2/pkg/apis/v1/labels.go#L35
430+ if _ , exists := CapacityTypeMapping [param .CapacityType ]; exists {
431+ value = CapacityTypeMapping [param .CapacityType ]
432+ }
433+
434+ requirements = append (requirements , karpv1.NodeSelectorRequirementWithMinValues {
435+ NodeSelectorRequirement : corev1.NodeSelectorRequirement {
436+ Key : key ,
437+ Operator : corev1 .NodeSelectorOpIn ,
438+ Values : []string {value },
439+ },
440+ })
441+ seen [key ] = struct {}{}
408442 }
409443
410444 // 4. custom GPU requirements
411445 if p .nodeManagerConfig .NodeProvisioner .GPURequirements != nil {
412446 for _ , requirement := range p .nodeManagerConfig .NodeProvisioner .GPURequirements {
447+ key := string (requirement .Key )
448+ // remove duplicate requirements
449+ if _ , exists := seen [key ]; exists {
450+ continue
451+ }
452+ seen [key ] = struct {}{}
413453 requirements = append (requirements , karpv1.NodeSelectorRequirementWithMinValues {
414454 NodeSelectorRequirement : corev1.NodeSelectorRequirement {
415- Key : string ( requirement . Key ) ,
455+ Key : key ,
416456 Operator : requirement .Operator ,
417457 Values : requirement .Values ,
418458 },
0 commit comments