@@ -12,6 +12,7 @@ import (
1212 "github.com/github/deployment-tracker/pkg/deploymentrecord"
1313 "github.com/github/deployment-tracker/pkg/image"
1414 "github.com/github/deployment-tracker/pkg/metrics"
15+ "k8s.io/apimachinery/pkg/types"
1516
1617 corev1 "k8s.io/api/core/v1"
1718 k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -421,10 +422,10 @@ func (c *Controller) recordContainer(ctx context.Context, pod *corev1.Pod, conta
421422 // Extract image name and tag
422423 imageName , version := image .ExtractName (container .Image )
423424
424- // Gather aggregate metadata
425- metadata := c .aggregateMetadata (ctx , pod )
425+ // Gather aggregate metadata for adds/updates
426426 var runtimeRisks []deploymentrecord.RuntimeRisk
427427 if status != deploymentrecord .StatusDecommissioned {
428+ metadata := c .aggregateMetadata (ctx , pod )
428429 for risk := range metadata .RuntimeRisks {
429430 runtimeRisks = append (runtimeRisks , risk )
430431 }
@@ -496,36 +497,39 @@ func (c *Controller) aggregateMetadata(ctx context.Context, obj metav1.Object) A
496497 metadata := AggregatePodMetadata {
497498 RuntimeRisks : make (map [deploymentrecord.RuntimeRisk ]bool ),
498499 }
499- visited := make (map [string ]bool )
500+ queue := []metav1.Object {obj }
501+ visited := make (map [types.UID ]bool )
500502
501- getMetadataFromObject (obj , metadata )
502- c .getMetadataFromOwners (ctx , obj , metadata , visited )
503+ for len (queue ) > 0 {
504+ current := queue [0 ]
505+ queue = queue [1 :]
506+
507+ if visited [current .GetUID ()] {
508+ slog .Warn ("Already visited object, skipping to avoid cycles" ,
509+ "UID" , current .GetUID (),
510+ "name" , current .GetName (),
511+ )
512+ continue
513+ }
514+ visited [current .GetUID ()] = true
515+
516+ getMetadataFromObject (current , metadata )
517+ c .addOwnersToQueue (ctx , current , & queue )
518+ }
503519
504520 return metadata
505521}
506522
507- // collectRuntimeRisksFromOwners recursively collects metadata from owner references
508- // in the ownership chain
509- // Visited map prevents infinite recursion on circular ownership references.
510- func (c * Controller ) getMetadataFromOwners (ctx context.Context , obj metav1.Object , metadata AggregatePodMetadata , visited map [string ]bool ) {
511- ownerRefs := obj .GetOwnerReferences ()
523+ // collectRuntimeRisksFromOwners takes a current object and looks up its owners, adding them to the queue for processing
524+ // to collect their metadata.
525+ func (c * Controller ) addOwnersToQueue (ctx context.Context , current metav1.Object , queue * []metav1.Object ) {
526+ ownerRefs := current .GetOwnerReferences ()
512527
513528 for _ , owner := range ownerRefs {
514- ownerKey := fmt .Sprintf ("%s/%s/%s" , obj .GetNamespace (), owner .Kind , owner .Name )
515- if visited [ownerKey ] {
516- slog .Debug ("Cycle detected in ownership chain, skipping" ,
517- "namespace" , obj .GetNamespace (),
518- "owner_kind" , owner .Kind ,
519- "owner_name" , owner .Name ,
520- )
521- continue
522- }
523- visited [ownerKey ] = true
524-
525- ownerObj , err := c .getOwnerObject (ctx , obj .GetNamespace (), owner )
529+ ownerObj , err := c .getOwnerObject (ctx , current .GetNamespace (), owner )
526530 if err != nil {
527531 slog .Warn ("Failed to get owner object for metadata collection" ,
528- "namespace" , obj .GetNamespace (),
532+ "namespace" , current .GetNamespace (),
529533 "owner_kind" , owner .Kind ,
530534 "owner_name" , owner .Name ,
531535 "error" , err ,
@@ -537,8 +541,7 @@ func (c *Controller) getMetadataFromOwners(ctx context.Context, obj metav1.Objec
537541 continue
538542 }
539543
540- getMetadataFromObject (ownerObj , metadata )
541- c .getMetadataFromOwners (ctx , ownerObj , metadata , visited )
544+ * queue = append (* queue , ownerObj )
542545 }
543546}
544547
0 commit comments