Skip to content

Commit a0fb341

Browse files
committed
add metadata client, switch to using PartialObjectMetadata
1 parent 7fb224e commit a0fb341

2 files changed

Lines changed: 59 additions & 29 deletions

File tree

cmd/deployment-tracker/main.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"time"
1414

1515
"github.com/github/deployment-tracker/internal/controller"
16+
"k8s.io/client-go/metadata"
1617

1718
"github.com/prometheus/client_golang/prometheus/promhttp"
1819
"k8s.io/client-go/kubernetes"
@@ -112,6 +113,14 @@ func main() {
112113
os.Exit(1)
113114
}
114115

116+
// Create metadata client
117+
metadataClient, err := metadata.NewForConfig(k8sCfg)
118+
if err != nil {
119+
slog.Error("Error creating Kubernetes metadata client",
120+
"error", err)
121+
os.Exit(1)
122+
}
123+
115124
// Start the metrics server
116125
var promSrv = &http.Server{
117126
Addr: ":" + metricsPort,
@@ -151,7 +160,7 @@ func main() {
151160
cancel()
152161
}()
153162

154-
cntrl, err := controller.New(clientset, namespace, excludeNamespaces, &cntrlCfg)
163+
cntrl, err := controller.New(clientset, metadataClient, namespace, excludeNamespaces, &cntrlCfg)
155164
if err != nil {
156165
slog.Error("Failed to create controller",
157166
"error", err)

internal/controller/controller.go

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
5052
type 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

573584
func 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

Comments
 (0)