@@ -12,7 +12,9 @@ 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/runtime/schema"
1516 "k8s.io/apimachinery/pkg/types"
17+ "k8s.io/client-go/metadata"
1618
1719 corev1 "k8s.io/api/core/v1"
1820 k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -48,19 +50,20 @@ type AggregatePodMetadata struct {
4850
4951// Controller is the Kubernetes controller for tracking deployments.
5052type Controller struct {
51- clientset kubernetes.Interface
52- podInformer cache.SharedIndexInformer
53- workqueue workqueue.TypedRateLimitingInterface [PodEvent ]
54- apiClient * deploymentrecord.Client
55- cfg * Config
53+ clientset kubernetes.Interface
54+ metadataClient metadata.Interface
55+ podInformer cache.SharedIndexInformer
56+ workqueue workqueue.TypedRateLimitingInterface [PodEvent ]
57+ apiClient * deploymentrecord.Client
58+ cfg * Config
5659 // best effort cache to avoid redundant posts
5760 // post requests are idempotent, so if this cache fails due to
5861 // restarts or other events, nothing will break.
5962 observedDeployments sync.Map
6063}
6164
6265// New creates a new deployment tracker controller.
63- func New (clientset kubernetes.Interface , namespace string , excludeNamespaces string , cfg * Config ) (* Controller , error ) {
66+ func New (clientset kubernetes.Interface , metadataClient metadata. Interface , namespace string , excludeNamespaces string , cfg * Config ) (* Controller , error ) {
6467 // Create informer factory
6568 factory := createInformerFactory (clientset , namespace , excludeNamespaces )
6669
@@ -92,11 +95,12 @@ func New(clientset kubernetes.Interface, namespace string, excludeNamespaces str
9295 }
9396
9497 cntrl := & Controller {
95- clientset : clientset ,
96- podInformer : podInformer ,
97- workqueue : queue ,
98- apiClient : apiClient ,
99- cfg : cfg ,
98+ clientset : clientset ,
99+ metadataClient : metadataClient ,
100+ podInformer : podInformer ,
101+ workqueue : queue ,
102+ apiClient : apiClient ,
103+ cfg : cfg ,
100104 }
101105
102106 // Add event handlers to the informer
@@ -425,7 +429,7 @@ func (c *Controller) recordContainer(ctx context.Context, pod *corev1.Pod, conta
425429 // Gather aggregate metadata for adds/updates
426430 var runtimeRisks []deploymentrecord.RuntimeRisk
427431 if status != deploymentrecord .StatusDecommissioned {
428- metadata := c .aggregateMetadata (ctx , pod )
432+ metadata := c .aggregateMetadata (ctx , podToPartialMetadata ( pod ) )
429433 for risk := range metadata .RuntimeRisks {
430434 runtimeRisks = append (runtimeRisks , risk )
431435 }
@@ -493,11 +497,11 @@ func (c *Controller) recordContainer(ctx context.Context, pod *corev1.Pod, conta
493497}
494498
495499// aggregateRuntimeRisks aggregates metadata for a pod and its owners.
496- func (c * Controller ) aggregateMetadata (ctx context.Context , obj metav1.Object ) AggregatePodMetadata {
500+ func (c * Controller ) aggregateMetadata (ctx context.Context , obj * metav1.PartialObjectMetadata ) AggregatePodMetadata {
497501 metadata := AggregatePodMetadata {
498502 RuntimeRisks : make (map [deploymentrecord.RuntimeRisk ]bool ),
499503 }
500- queue := []metav1.Object {obj }
504+ queue := []* metav1.PartialObjectMetadata {obj }
501505 visited := make (map [types.UID ]bool )
502506
503507 for len (queue ) > 0 {
@@ -522,11 +526,11 @@ func (c *Controller) aggregateMetadata(ctx context.Context, obj metav1.Object) A
522526
523527// collectRuntimeRisksFromOwners takes a current object and looks up its owners, adding them to the queue for processing
524528// to collect their metadata.
525- func (c * Controller ) addOwnersToQueue (ctx context.Context , current metav1.Object , queue * []metav1.Object ) {
529+ func (c * Controller ) addOwnersToQueue (ctx context.Context , current * metav1.PartialObjectMetadata , queue * []* metav1.PartialObjectMetadata ) {
526530 ownerRefs := current .GetOwnerReferences ()
527531
528532 for _ , owner := range ownerRefs {
529- ownerObj , err := c .getOwnerObject (ctx , current .GetNamespace (), owner )
533+ ownerObj , err := c .getOwnerMetadata (ctx , current .GetNamespace (), owner )
530534 if err != nil {
531535 slog .Warn ("Failed to get owner object for metadata collection" ,
532536 "namespace" , current .GetNamespace (),
@@ -545,29 +549,36 @@ func (c *Controller) addOwnersToQueue(ctx context.Context, current metav1.Object
545549 }
546550}
547551
548- // getOwnerObject retrieves the owner object based on its kind, namespace, and name.
549- func (c * Controller ) getOwnerObject (ctx context.Context , namespace string , owner metav1.OwnerReference ) (metav1.Object , error ) {
552+ // getOwnerMetadata retrieves partial object metadata for an owner ref.
553+ func (c * Controller ) getOwnerMetadata (ctx context.Context , namespace string , owner metav1.OwnerReference ) (* metav1.PartialObjectMetadata , error ) {
554+ var gvr schema.GroupVersionResource
555+
550556 switch owner .Kind {
551557 case "ReplicaSet" :
552- rs , err := c .clientset .AppsV1 ().ReplicaSets (namespace ).Get (ctx , owner .Name , metav1.GetOptions {})
553- if err != nil {
554- return nil , err
558+ gvr = schema.GroupVersionResource {
559+ Group : "apps" ,
560+ Version : "v1" ,
561+ Resource : "replicasets" ,
555562 }
556- return rs , nil
557563 case "Deployment" :
558- deployment , err := c .clientset .AppsV1 ().Deployments (namespace ).Get (ctx , owner .Name , metav1.GetOptions {})
559- if err != nil {
560- return nil , err
564+ gvr = schema.GroupVersionResource {
565+ Group : "apps" ,
566+ Version : "v1" ,
567+ Resource : "deployments" ,
561568 }
562- return deployment , nil
563569 default :
564- // Unsupported kinds
565570 slog .Debug ("Unsupported owner kind for runtime risk collection" ,
566571 "kind" , owner .Kind ,
567572 "name" , owner .Name ,
568573 )
569574 return nil , nil
570575 }
576+
577+ obj , err := c .metadataClient .Resource (gvr ).Namespace (namespace ).Get (ctx , owner .Name , metav1.GetOptions {})
578+ if err != nil {
579+ return nil , err
580+ }
581+ return obj , nil
571582}
572583
573584func getCacheKey (dn , digest string ) string {
@@ -679,7 +690,7 @@ func getDeploymentName(pod *corev1.Pod) string {
679690}
680691
681692// getMetadataFromObject extracts metadata from an object.
682- func getMetadataFromObject (obj metav1.Object , metadata AggregatePodMetadata ) {
693+ func getMetadataFromObject (obj * metav1.PartialObjectMetadata , metadata AggregatePodMetadata ) {
683694 annotations := obj .GetAnnotations ()
684695 if risks , exists := annotations [RuntimeRiskAnnotationKey ]; exists {
685696 for _ , risk := range strings .Split (risks , "," ) {
@@ -690,3 +701,13 @@ func getMetadataFromObject(obj metav1.Object, metadata AggregatePodMetadata) {
690701 }
691702 }
692703}
704+
705+ func podToPartialMetadata (pod * corev1.Pod ) * metav1.PartialObjectMetadata {
706+ return & metav1.PartialObjectMetadata {
707+ TypeMeta : metav1.TypeMeta {
708+ APIVersion : "v1" ,
709+ Kind : "Pod" ,
710+ },
711+ ObjectMeta : pod .ObjectMeta ,
712+ }
713+ }
0 commit comments