github.com/Azure/aad-pod-identity@v1.8.17/pkg/pod/pod.go (about) 1 package pod 2 3 import ( 4 "strings" 5 "time" 6 7 aadpodid "github.com/Azure/aad-pod-identity/pkg/apis/aadpodidentity" 8 "github.com/Azure/aad-pod-identity/pkg/stats" 9 10 v1 "k8s.io/api/core/v1" 11 "k8s.io/apimachinery/pkg/labels" 12 "k8s.io/apimachinery/pkg/selection" 13 "k8s.io/client-go/informers" 14 informersv1 "k8s.io/client-go/informers/core/v1" 15 "k8s.io/client-go/tools/cache" 16 "k8s.io/klog/v2" 17 ) 18 19 // Client represents new pod client 20 type Client struct { 21 PodWatcher informersv1.PodInformer 22 } 23 24 // ClientInt represents pod client interface 25 type ClientInt interface { 26 GetPods() (pods []*v1.Pod, err error) 27 Start(exit <-chan struct{}) 28 } 29 30 // NewPodClient returns new pod client 31 func NewPodClient(i informers.SharedInformerFactory, eventCh chan aadpodid.EventType) ClientInt { 32 podInformer := i.Core().V1().Pods() 33 addPodHandler(podInformer, eventCh) 34 35 return &Client{ 36 PodWatcher: podInformer, 37 } 38 } 39 40 func addPodHandler(i informersv1.PodInformer, eventCh chan aadpodid.EventType) { 41 i.Informer().AddEventHandler( 42 cache.ResourceEventHandlerFuncs{ 43 AddFunc: func(obj interface{}) { 44 klog.V(6).Infof("pod created") 45 eventCh <- aadpodid.PodCreated 46 }, 47 DeleteFunc: func(obj interface{}) { 48 klog.V(6).Infof("pod deleted") 49 eventCh <- aadpodid.PodDeleted 50 }, 51 UpdateFunc: func(oldObj, newObj interface{}) { 52 // We are only interested in updates to pod if the node or label changes. 53 // Having this check will ensure that mic sync loop does not do extra work 54 // for every pod update. 55 oldPod, newPod := oldObj.(*v1.Pod), newObj.(*v1.Pod) 56 if oldPod.Spec.NodeName != newPod.Spec.NodeName || oldPod.ObjectMeta.Labels[aadpodid.CRDLabelKey] != newPod.ObjectMeta.Labels[aadpodid.CRDLabelKey] { 57 klog.V(6).Infof("pod updated") 58 eventCh <- aadpodid.PodUpdated 59 } 60 }, 61 }, 62 ) 63 } 64 65 func (c *Client) syncCache(exit <-chan struct{}) { 66 cacheSyncStarted := time.Now() 67 klog.V(6).Infof("wait for cache to sync") 68 if !cache.WaitForCacheSync(exit, c.PodWatcher.Informer().HasSynced) { 69 klog.Error("wait for pod cache sync failed") 70 return 71 } 72 klog.Infof("pod cache synchronized. Took %s", time.Since(cacheSyncStarted).String()) 73 } 74 75 // Start starts watching for any pod-related changes. 76 func (c *Client) Start(exit <-chan struct{}) { 77 go c.PodWatcher.Informer().Run(exit) 78 c.syncCache(exit) 79 klog.Info("pod watcher started !!") 80 } 81 82 // GetPods returns list of all pods 83 func (c *Client) GetPods() ([]*v1.Pod, error) { 84 begin := time.Now() 85 crdReq, err := labels.NewRequirement(aadpodid.CRDLabelKey, selection.Exists, nil) 86 if err != nil { 87 return nil, err 88 } 89 crdSelector := labels.NewSelector().Add(*crdReq) 90 listPods, err := c.PodWatcher.Lister().List(crdSelector) 91 if err != nil { 92 return nil, err 93 } 94 stats.Put(stats.PodList, time.Since(begin)) 95 return listPods, nil 96 } 97 98 // IsPodExcepted returns true if pod label is part of exception crd 99 func IsPodExcepted(podLabels map[string]string, exceptionList []aadpodid.AzurePodIdentityException) bool { 100 return len(exceptionList) > 0 && labelInExceptionList(podLabels, exceptionList) 101 } 102 103 // labelInExceptionList checks if the labels defined in azurepodidentityexception match label defined in pods 104 func labelInExceptionList(podLabels map[string]string, exceptionList []aadpodid.AzurePodIdentityException) bool { 105 for _, exception := range exceptionList { 106 for exceptionLabelKey, exceptionLabelValue := range exception.Spec.PodLabels { 107 if val, ok := podLabels[exceptionLabelKey]; ok { 108 if strings.EqualFold(val, exceptionLabelValue) { 109 return true 110 } 111 } 112 } 113 } 114 return false 115 }