@@ -66,6 +66,13 @@ type Informers struct {
6666 services cache.SharedIndexInformer
6767 // replicaSets caches the ReplicaSets as partially-filled *ObjectMeta pointers
6868 replicaSets cache.SharedIndexInformer
69+ // New informers for ownership tracking
70+ deployments cache.SharedIndexInformer
71+ virtualMachineInstances cache.SharedIndexInformer
72+ virtualMachines cache.SharedIndexInformer
73+ gateways cache.SharedIndexInformer
74+ // Config and channels
75+ config Config
6976 stopChan chan struct {}
7077 mdStopChan chan struct {}
7178 indexerHitMetric * prometheus.CounterVec
@@ -178,18 +185,125 @@ func (k *Informers) GetNodeByName(name string) (*model.ResourceMetaData, error)
178185}
179186
180187func (k * Informers ) checkParent (info * model.ResourceMetaData ) {
181- if info .OwnerKind == "ReplicaSet" {
182- item , ok , err := k .replicaSets .GetIndexer ().GetByKey (info .Namespace + "/" + info .OwnerName )
183- if err != nil {
184- log .WithError (err ).WithField ("key" , info .Namespace + "/" + info .OwnerName ).
185- Debug ("can't get ReplicaSet info from informer. Ignoring" )
186- } else if ok {
187- rsInfo := item .(* metav1.ObjectMeta )
188- if len (rsInfo .OwnerReferences ) > 0 {
189- info .OwnerKind = rsInfo .OwnerReferences [0 ].Kind
190- info .OwnerName = rsInfo .OwnerReferences [0 ].Name
188+ // Maximum 3 ownership hops: Pod → ReplicaSet → Deployment → Gateway
189+ // This allows tracking up to 3 levels beyond the initial resource
190+ const maxHops = 3
191+
192+ // If trackedKinds is empty, use legacy behavior (stop after ReplicaSet resolution)
193+ if len (k .config .trackedKinds ) == 0 {
194+ // Legacy behavior: only resolve ReplicaSet
195+ if info .OwnerKind == "ReplicaSet" {
196+ item , ok , err := k .replicaSets .GetIndexer ().GetByKey (info .Namespace + "/" + info .OwnerName )
197+ if err != nil {
198+ log .WithError (err ).WithField ("key" , info .Namespace + "/" + info .OwnerName ).
199+ Debug ("can't get ReplicaSet info from informer. Ignoring" )
200+ return
201+ }
202+ if ok {
203+ rsInfo := item .(* metav1.ObjectMeta )
204+ if len (rsInfo .OwnerReferences ) > 0 {
205+ info .OwnerKind = rsInfo .OwnerReferences [0 ].Kind
206+ info .OwnerName = rsInfo .OwnerReferences [0 ].Name
207+ }
191208 }
192209 }
210+ return
211+ }
212+
213+ // New behavior with trackedKinds: traverse ownership chain until we find a tracked kind or hit max depth
214+ for i := 0 ; i < maxHops ; i ++ {
215+ // Check if current owner is in trackedKinds
216+ if k .isTracked (info .OwnerKind ) {
217+ // This owner IS tracked. Try to get its parent to see if we can go higher.
218+ parent := k .getOwnerFromInformer (info .OwnerKind , info .Namespace , info .OwnerName )
219+ if parent == nil {
220+ // No parent exists → STOP at current tracked kind
221+ break
222+ }
223+ // Parent exists - check if parent is ALSO tracked
224+ if k .isTracked (parent .Kind ) {
225+ // Parent is also tracked → update and continue (prefer higher level)
226+ info .OwnerKind = parent .Kind
227+ info .OwnerName = parent .Name
228+ continue
229+ }
230+ // Parent exists but is NOT tracked → STOP at current tracked kind
231+ break
232+ }
233+
234+ // Current owner is NOT tracked → try to find a tracked parent
235+ parent := k .getOwnerFromInformer (info .OwnerKind , info .Namespace , info .OwnerName )
236+ if parent == nil {
237+ // No parent found → STOP at current (untracked) owner
238+ break
239+ }
240+
241+ // Update to parent and continue
242+ info .OwnerKind = parent .Kind
243+ info .OwnerName = parent .Name
244+ }
245+ }
246+
247+ // isTracked returns true if the given kind is in the trackedKinds configuration
248+ func (k * Informers ) isTracked (kind string ) bool {
249+ for _ , tracked := range k .config .trackedKinds {
250+ if tracked == kind {
251+ return true
252+ }
253+ }
254+ return false
255+ }
256+
257+ // OwnerInfo contains basic ownership information
258+ type OwnerInfo struct {
259+ Kind string
260+ Name string
261+ }
262+
263+ // getOwnerFromInformer retrieves the owner of a resource from the appropriate informer
264+ func (k * Informers ) getOwnerFromInformer (kind , namespace , name string ) * OwnerInfo {
265+ var informer cache.SharedIndexInformer
266+
267+ switch kind {
268+ case "ReplicaSet" :
269+ informer = k .replicaSets
270+ case "Deployment" :
271+ informer = k .deployments
272+ case "Gateway" :
273+ informer = k .gateways
274+ case "VirtualMachineInstance" :
275+ informer = k .virtualMachineInstances
276+ case "VirtualMachine" :
277+ informer = k .virtualMachines
278+ default :
279+ return nil
280+ }
281+
282+ if informer == nil {
283+ log .WithField ("kind" , kind ).Debug ("informer not initialized for this kind" )
284+ return nil
285+ }
286+
287+ item , ok , err := informer .GetIndexer ().GetByKey (namespace + "/" + name )
288+ if err != nil {
289+ log .WithError (err ).
290+ WithField ("kind" , kind ).
291+ WithField ("key" , namespace + "/" + name ).
292+ Debug ("can't get resource info from informer" )
293+ return nil
294+ }
295+ if ! ok {
296+ return nil
297+ }
298+
299+ meta := item .(* metav1.ObjectMeta )
300+ if len (meta .OwnerReferences ) == 0 {
301+ return nil
302+ }
303+
304+ return & OwnerInfo {
305+ Kind : meta .OwnerReferences [0 ].Kind ,
306+ Name : meta .OwnerReferences [0 ].Name ,
193307 }
194308}
195309
@@ -376,8 +490,101 @@ func (k *Informers) initReplicaSetInformer(informerFactory metadatainformer.Shar
376490 return nil
377491}
378492
493+ func (k * Informers ) initDeploymentInformer (informerFactory metadatainformer.SharedInformerFactory ) error {
494+ k .deployments = informerFactory .ForResource (
495+ schema.GroupVersionResource {
496+ Group : "apps" ,
497+ Version : "v1" ,
498+ Resource : "deployments" ,
499+ }).Informer ()
500+ if err := k .deployments .SetTransform (func (i interface {}) (interface {}, error ) {
501+ deploy , ok := i .(* metav1.PartialObjectMetadata )
502+ if ! ok {
503+ return nil , fmt .Errorf ("was expecting a Deployment. Got: %T" , i )
504+ }
505+ return & metav1.ObjectMeta {
506+ Name : deploy .Name ,
507+ Namespace : deploy .Namespace ,
508+ OwnerReferences : deploy .OwnerReferences ,
509+ }, nil
510+ }); err != nil {
511+ return fmt .Errorf ("can't set Deployments transform: %w" , err )
512+ }
513+ return nil
514+ }
515+
516+ func (k * Informers ) initGatewayInformer (informerFactory metadatainformer.SharedInformerFactory ) error {
517+ k .gateways = informerFactory .ForResource (
518+ schema.GroupVersionResource {
519+ Group : "gateway.networking.k8s.io" ,
520+ Version : "v1" ,
521+ Resource : "gateways" ,
522+ }).Informer ()
523+ if err := k .gateways .SetTransform (func (i interface {}) (interface {}, error ) {
524+ gw , ok := i .(* metav1.PartialObjectMetadata )
525+ if ! ok {
526+ return nil , fmt .Errorf ("was expecting a Gateway. Got: %T" , i )
527+ }
528+ return & metav1.ObjectMeta {
529+ Name : gw .Name ,
530+ Namespace : gw .Namespace ,
531+ OwnerReferences : gw .OwnerReferences ,
532+ }, nil
533+ }); err != nil {
534+ return fmt .Errorf ("can't set Gateways transform: %w" , err )
535+ }
536+ return nil
537+ }
538+
539+ func (k * Informers ) initVirtualMachineInstanceInformer (informerFactory metadatainformer.SharedInformerFactory ) error {
540+ k .virtualMachineInstances = informerFactory .ForResource (
541+ schema.GroupVersionResource {
542+ Group : "kubevirt.io" ,
543+ Version : "v1" ,
544+ Resource : "virtualmachineinstances" ,
545+ }).Informer ()
546+ if err := k .virtualMachineInstances .SetTransform (func (i interface {}) (interface {}, error ) {
547+ vmi , ok := i .(* metav1.PartialObjectMetadata )
548+ if ! ok {
549+ return nil , fmt .Errorf ("was expecting a VirtualMachineInstance. Got: %T" , i )
550+ }
551+ return & metav1.ObjectMeta {
552+ Name : vmi .Name ,
553+ Namespace : vmi .Namespace ,
554+ OwnerReferences : vmi .OwnerReferences ,
555+ }, nil
556+ }); err != nil {
557+ return fmt .Errorf ("can't set VirtualMachineInstances transform: %w" , err )
558+ }
559+ return nil
560+ }
561+
562+ func (k * Informers ) initVirtualMachineInformer (informerFactory metadatainformer.SharedInformerFactory ) error {
563+ k .virtualMachines = informerFactory .ForResource (
564+ schema.GroupVersionResource {
565+ Group : "kubevirt.io" ,
566+ Version : "v1" ,
567+ Resource : "virtualmachines" ,
568+ }).Informer ()
569+ if err := k .virtualMachines .SetTransform (func (i interface {}) (interface {}, error ) {
570+ vm , ok := i .(* metav1.PartialObjectMetadata )
571+ if ! ok {
572+ return nil , fmt .Errorf ("was expecting a VirtualMachine. Got: %T" , i )
573+ }
574+ return & metav1.ObjectMeta {
575+ Name : vm .Name ,
576+ Namespace : vm .Namespace ,
577+ OwnerReferences : vm .OwnerReferences ,
578+ }, nil
579+ }); err != nil {
580+ return fmt .Errorf ("can't set VirtualMachines transform: %w" , err )
581+ }
582+ return nil
583+ }
584+
379585func (k * Informers ) InitFromConfig (kubeconfig string , infConfig Config , opMetrics * operational.Metrics ) error {
380586 // Initialization variables
587+ k .config = infConfig
381588 k .stopChan = make (chan struct {})
382589 k .mdStopChan = make (chan struct {})
383590
@@ -430,6 +637,32 @@ func (k *Informers) initInformers(client kubernetes.Interface, metaClient metada
430637 return err
431638 }
432639
640+ // Initialize additional informers based on trackedKinds configuration
641+ for _ , kind := range cfg .trackedKinds {
642+ switch kind {
643+ case "Deployment" :
644+ log .Debugf ("initializing Deployment informer (trackedKinds)" )
645+ if err := k .initDeploymentInformer (metadataInformerFactory ); err != nil {
646+ return err
647+ }
648+ case "Gateway" :
649+ log .Debugf ("initializing Gateway informer (trackedKinds)" )
650+ if err := k .initGatewayInformer (metadataInformerFactory ); err != nil {
651+ return err
652+ }
653+ case "VirtualMachineInstance" :
654+ log .Debugf ("initializing VirtualMachineInstance informer (trackedKinds)" )
655+ if err := k .initVirtualMachineInstanceInformer (metadataInformerFactory ); err != nil {
656+ return err
657+ }
658+ case "VirtualMachine" :
659+ log .Debugf ("initializing VirtualMachine informer (trackedKinds)" )
660+ if err := k .initVirtualMachineInformer (metadataInformerFactory ); err != nil {
661+ return err
662+ }
663+ }
664+ }
665+
433666 // Informers expose an indexer
434667 log .Debugf ("adding indexers" )
435668 byIP := cache.Indexers {IndexIP : ipIndexer }
0 commit comments