@@ -35,6 +35,7 @@ type KarpenterCollector struct {
3535 informers map [string ]cache.SharedIndexInformer
3636 informerStopChs map [string ]chan struct {}
3737 excludedResources map [string ]map [string ]bool // resourceType -> resourceName -> excluded
38+ version string
3839 mu sync.RWMutex
3940}
4041
@@ -324,13 +325,13 @@ func (c *KarpenterCollector) handleKarpenterResourceEvent(
324325 // Add more detailed logging before sending to batch channel
325326 c .logger .Info ("Karpenter resource details" ,
326327 "resourceType" , Karpenter ,
327- "key" , key ,
328- "eventType" , eventType .String (),
329- "kind" , kind ,
330- "name" , name ,
331- "namespace" , namespace ,
332- "apiVersion" , obj .GetAPIVersion (),
333- "processedFields" , processedObj )
328+ "key" , key ,
329+ "eventType" , eventType .String (),
330+ "kind" , kind ,
331+ "name" , name ,
332+ "namespace" , namespace ,
333+ "apiVersion" , obj .GetAPIVersion (),
334+ "processedFields" , processedObj )
334335
335336 // Send the Karpenter resource to the batch channel
336337 c .batchChan <- CollectedResource {
@@ -544,6 +545,7 @@ func (c *KarpenterCollector) extractCommonFields(obj *unstructured.Unstructured)
544545 // Basic metadata
545546 result := map [string ]interface {}{
546547 "name" : obj .GetName (),
548+ "karpenterVersion" : c .version ,
547549 "namespace" : obj .GetNamespace (),
548550 "uid" : string (obj .GetUID ()),
549551 "kind" : obj .GetKind (),
@@ -666,36 +668,92 @@ func (c *KarpenterCollector) GetType() string {
666668 return "karpenter"
667669}
668670
669- // IsAvailable checks if Karpenter resources can be accessed in the cluster
671+ // detectKarpenterVersion detects the version of Karpenter from the deployment object
672+ func (c * KarpenterCollector ) detectKarpenterVersion (obj * unstructured.Unstructured ) {
673+ containers , found , _ := unstructured .NestedSlice (obj .Object , "spec" , "template" , "spec" , "containers" )
674+ if ! found {
675+ return
676+ }
677+
678+ for _ , container := range containers {
679+ containerMap , ok := container .(map [string ]interface {})
680+ if ! ok {
681+ continue
682+ }
683+
684+ name , found , _ := unstructured .NestedString (containerMap , "name" )
685+ if ! found || name != "controller" {
686+ continue
687+ }
688+
689+ image , found , _ := unstructured .NestedString (containerMap , "image" )
690+ if ! found {
691+ continue
692+ }
693+
694+ // Image format: public.ecr.aws/karpenter/controller:0.37.7@sha256:...
695+ imageParts := strings .Split (image , "@" )[0 ]
696+ versionParts := strings .Split (imageParts , ":" )
697+ if len (versionParts ) != 2 {
698+ c .logger .V (4 ).Info ("Invalid image format" , "image" , image )
699+ continue
700+ }
701+
702+ version := versionParts [1 ]
703+ c .mu .Lock ()
704+ c .version = version
705+ c .mu .Unlock ()
706+ c .logger .Info ("Detected Karpenter version" , "version" , version )
707+ return
708+ }
709+
710+ c .logger .V (4 ).Info ("Could not detect Karpenter version from deployment" )
711+ }
712+
713+ // Update IsAvailable to detect version
670714func (c * KarpenterCollector ) IsAvailable (ctx context.Context ) bool {
671- // Try to list NodePools to see if Karpenter is installed
672- // Check both v1beta1 and v1 api versions
673- gvrs := []schema.GroupVersionResource {
674- {
675- Group : "karpenter.sh" ,
676- Version : "v1" ,
677- Resource : "nodepools" ,
678- },
679- {
680- Group : "karpenter.sh" ,
681- Version : "v1beta1" ,
682- Resource : "nodepools" ,
683- },
684- {
685- Group : "karpenter.sh" ,
686- Version : "v1alpha5" ,
687- Resource : "provisioners" ,
688- },
715+ gvr := schema.GroupVersionResource {
716+ Group : "apps" ,
717+ Version : "v1" ,
718+ Resource : "deployments" ,
689719 }
690720
691- for _ , gvr := range gvrs {
692- _ , err := c .dynamicClient .Resource (gvr ).List (ctx , metav1.ListOptions {Limit : 1 })
693- if err == nil {
694- c .logger .Info ("Karpenter resources available" , "gvr" , gvr .String ())
695- return true
721+ // Karpenter deployment has these labels
722+ labelSelector := "app.kubernetes.io/name=karpenter,app.kubernetes.io/instance=karpenter"
723+
724+ // List deployments across all namespaces with the Karpenter labels
725+ deployments , err := c .dynamicClient .Resource (gvr ).List (ctx , metav1.ListOptions {
726+ LabelSelector : labelSelector ,
727+ })
728+ if err != nil {
729+ c .logger .Error (err , "Failed to list deployments" )
730+ return false
731+ }
732+
733+ if len (deployments .Items ) == 0 {
734+ c .logger .Info ("No Karpenter deployment found" )
735+ return false
736+ }
737+
738+ // Check if at least one deployment is ready
739+ for _ , d := range deployments .Items {
740+ status , found , _ := unstructured .NestedMap (d .Object , "status" )
741+ if found {
742+ readyReplicas , found , _ := unstructured .NestedInt64 (status , "readyReplicas" )
743+ if found && readyReplicas > 0 {
744+ c .detectKarpenterVersion (& d )
745+
746+ ns , _ , _ := unstructured .NestedString (d .Object , "metadata" , "namespace" )
747+ name , _ , _ := unstructured .NestedString (d .Object , "metadata" , "name" )
748+ c .logger .Info ("Found running Karpenter deployment" ,
749+ "namespace" , ns ,
750+ "name" , name ,
751+ "version" , c .version )
752+ return true
753+ }
696754 }
697755 }
698756
699- c .logger .Info ("Karpenter resources not available in the cluster " )
757+ c .logger .Info ("No ready Karpenter deployment found " )
700758 return false
701- }
759+ }
0 commit comments