/* 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 v1alpha5 import ( "encoding/json" "fmt" "sort" "github.com/mitchellh/hashstructure/v2" "github.com/samber/lo" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "knative.dev/pkg/ptr" ) // ProvisionerSpec is the top level provisioner specification. Provisioners // launch nodes in response to pods that are unschedulable. A single provisioner // is capable of managing a diverse set of nodes. Node properties are determined // from a combination of provisioner and pod scheduling constraints. type ProvisionerSpec struct { // Annotations are applied to every node. //+optional Annotations map[string]string `json:"annotations,omitempty"` // Labels are layered with Requirements and applied to every node. //+optional Labels map[string]string `json:"labels,omitempty"` // Taints will be applied to every node launched by the Provisioner. If // specified, the provisioner will not provision nodes for pods that do not // have matching tolerations. Additional taints will be created that match // pod tolerations on a per-node basis. // +optional Taints []v1.Taint `json:"taints,omitempty"` // StartupTaints are taints that are applied to nodes upon startup which are expected to be removed automatically // within a short period of time, typically by a DaemonSet that tolerates the taint. These are commonly used by // daemonsets to allow initialization and enforce startup ordering. StartupTaints are ignored for provisioning // purposes in that pods are not required to tolerate a StartupTaint in order to have nodes provisioned for them. // +optional StartupTaints []v1.Taint `json:"startupTaints,omitempty"` // Requirements are layered with Labels and applied to every node. Requirements []v1.NodeSelectorRequirement `json:"requirements,omitempty" hash:"ignore"` // KubeletConfiguration are options passed to the kubelet when provisioning nodes //+optional KubeletConfiguration *KubeletConfiguration `json:"kubeletConfiguration,omitempty"` // Provider contains fields specific to your cloudprovider. // +kubebuilder:pruning:PreserveUnknownFields Provider *Provider `json:"provider,omitempty" hash:"ignore"` // ProviderRef is a reference to a dedicated CRD for the chosen provider, that holds // additional configuration options // +optional ProviderRef *MachineTemplateRef `json:"providerRef,omitempty" hash:"ignore"` // TTLSecondsAfterEmpty is the number of seconds the controller will wait // before attempting to delete a node, measured from when the node is // detected to be empty. A Node is considered to be empty when it does not // have pods scheduled to it, excluding daemonsets. // // Termination due to no utilization is disabled if this field is not set. // +optional TTLSecondsAfterEmpty *int64 `json:"ttlSecondsAfterEmpty,omitempty" hash:"ignore"` // TTLSecondsUntilExpired is the number of seconds the controller will wait // before terminating a node, measured from when the node is created. This // is useful to implement features like eventually consistent node upgrade, // memory leak protection, and disruption testing. // // Termination due to expiration is disabled if this field is not set. // +optional TTLSecondsUntilExpired *int64 `json:"ttlSecondsUntilExpired,omitempty" hash:"ignore"` // Limits define a set of bounds for provisioning capacity. Limits *Limits `json:"limits,omitempty" hash:"ignore"` // Weight is the priority given to the provisioner during scheduling. A higher // numerical weight indicates that this provisioner will be ordered // ahead of other provisioners with lower weights. A provisioner with no weight // will be treated as if it is a provisioner with a weight of 0. // +kubebuilder:validation:Minimum:=1 // +kubebuilder:validation:Maximum:=100 // +optional Weight *int32 `json:"weight,omitempty" hash:"ignore"` // Consolidation are the consolidation parameters // +optional Consolidation *Consolidation `json:"consolidation,omitempty" hash:"ignore"` } func (p *Provisioner) Hash() string { hash, _ := hashstructure.Hash(p.Spec, hashstructure.FormatV2, &hashstructure.HashOptions{ SlicesAsSets: true, IgnoreZeroValue: true, ZeroNil: true, }) return fmt.Sprint(hash) } type Consolidation struct { // Enabled enables consolidation if it has been set Enabled *bool `json:"enabled,omitempty"` } // +kubebuilder:object:generate=false type Provider = runtime.RawExtension func ProviderAnnotation(p *Provider) map[string]string { if p == nil { return nil } raw := lo.Must(json.Marshal(p)) // Provider should already have been validated so this shouldn't fail return map[string]string{ProviderCompatabilityAnnotationKey: string(raw)} } // Provisioner is the Schema for the Provisioners API // +kubebuilder:object:root=true // +kubebuilder:resource:path=provisioners,scope=Cluster,categories=karpenter // +kubebuilder:subresource:status type Provisioner struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` Spec ProvisionerSpec `json:"spec,omitempty"` Status ProvisionerStatus `json:"status,omitempty"` } // ProvisionerList contains a list of Provisioner // +kubebuilder:object:root=true type ProvisionerList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` Items []Provisioner `json:"items"` } // OrderByWeight orders the provisioners in the ProvisionerList // by their priority weight in-place func (pl *ProvisionerList) OrderByWeight() { sort.Slice(pl.Items, func(a, b int) bool { return ptr.Int32Value(pl.Items[a].Spec.Weight) > ptr.Int32Value(pl.Items[b].Spec.Weight) }) }