github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/monitor/internal/k8s/monitor.go (about) 1 package k8smonitor 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "sync" 8 9 criapi "k8s.io/cri-api/pkg/apis" 10 11 "go.aporeto.io/enforcerd/internal/extractors/containermetadata" 12 "go.aporeto.io/enforcerd/trireme-lib/monitor/config" 13 "go.aporeto.io/enforcerd/trireme-lib/monitor/constants" 14 "go.aporeto.io/enforcerd/trireme-lib/monitor/extractors" 15 "go.aporeto.io/enforcerd/trireme-lib/monitor/registerer" 16 "k8s.io/client-go/kubernetes" 17 listersv1 "k8s.io/client-go/listers/core/v1" 18 "k8s.io/client-go/rest" 19 "k8s.io/client-go/tools/clientcmd" 20 ) 21 22 // K8sMonitor is the monitor for Kubernetes. 23 type K8sMonitor struct { 24 nodename string 25 handlers *config.ProcessorConfig 26 metadataExtractor extractors.PodMetadataExtractor 27 kubeClient kubernetes.Interface 28 podLister listersv1.PodLister 29 criRuntimeService criapi.RuntimeService 30 podCache podCacheInterface 31 runtimeCache runtimeCacheInterface 32 startEventRetry startEventRetryFunc 33 cniInstalledOrRuncProxyStartedCh chan struct{} 34 cniInstalledOrRuncProxyStarted bool 35 extMonitorStartedLock sync.RWMutex 36 } 37 38 // New returns a new kubernetes monitor. 39 func New(ctx context.Context) *K8sMonitor { 40 m := &K8sMonitor{} 41 m.podCache = newPodCache(m.updateEvent) 42 m.runtimeCache = newRuntimeCache(ctx, m.stopEvent) 43 m.cniInstalledOrRuncProxyStartedCh = make(chan struct{}) 44 return m 45 } 46 47 // SetupConfig provides a configuration to implmentations. Every implmentation 48 // can have its own config type. 49 func (m *K8sMonitor) SetupConfig(_ registerer.Registerer, cfg interface{}) error { 50 51 defaultConfig := DefaultConfig() 52 53 if cfg == nil { 54 cfg = defaultConfig 55 } 56 57 kubernetesconfig, ok := cfg.(*Config) 58 if !ok { 59 return fmt.Errorf("Invalid configuration specified (type '%T')", cfg) 60 } 61 62 kubernetesconfig = SetupDefaultConfig(kubernetesconfig) 63 64 // simple config checks 65 if kubernetesconfig.MetadataExtractor == nil { 66 return fmt.Errorf("missing metadata extractor") 67 } 68 if kubernetesconfig.CRIRuntimeService == nil { 69 return fmt.Errorf("missing CRIRuntimeService implementation") 70 } 71 72 // Initialize most of our monitor 73 m.nodename = kubernetesconfig.Nodename 74 m.metadataExtractor = kubernetesconfig.MetadataExtractor 75 m.criRuntimeService = kubernetesconfig.CRIRuntimeService 76 77 // build kubernetes client config 78 var kubeCfg *rest.Config 79 if len(kubernetesconfig.Kubeconfig) > 0 { 80 var err error 81 kubeCfg, err = clientcmd.BuildConfigFromFlags("", kubernetesconfig.Kubeconfig) 82 if err != nil { 83 return err 84 } 85 } else { 86 var err error 87 kubeCfg, err = rest.InClusterConfig() 88 if err != nil { 89 return err 90 } 91 } 92 93 // and initialize client from it 94 var err error 95 m.kubeClient, err = kubernetes.NewForConfig(kubeCfg) 96 return err 97 } 98 99 // SetupHandlers sets up handlers for monitors to invoke for various events such as 100 // processing unit events and synchronization events. This will be called before Start() 101 // by the consumer of the monitor 102 func (m *K8sMonitor) SetupHandlers(c *config.ProcessorConfig) { 103 m.handlers = c 104 } 105 106 // Run starts the monitor implementation. 107 func (m *K8sMonitor) Run(ctx context.Context) error { 108 m.startEventRetry = newStartEventRetryFunc(ctx, containermetadata.AutoDetect(), m.startEvent) 109 if m.kubeClient == nil { 110 return errors.New("K8sMonitor: missing Kubernetes client") 111 } 112 113 if err := m.handlers.IsComplete(); err != nil { 114 return fmt.Errorf("K8sMonitor: handlers are not complete: %s", err.Error()) 115 } 116 117 if m.handlers.ExternalEventSender == nil { 118 return fmt.Errorf("K8sMonitor: external event sender option must be used together with this monitor") 119 } 120 121 // setup informer for update events (this starts the informer as well) 122 // this also returns a pod lister which uses the same underlying cache as the informer 123 m.podLister = m.podCache.SetupInformer(ctx, m.kubeClient, m.nodename, defaultNeedsUpdate) 124 125 // register ourselves with the gRPC server to receive events 126 var registered bool 127 for _, evs := range m.handlers.ExternalEventSender { 128 if evs.SenderName() == constants.MonitorExtSenderName { 129 if err := evs.Register(constants.K8sMonitorRegistrationName, m); err != nil { 130 return fmt.Errorf("K8sMonitor: failed to register with the grpcMonitorServer external events sender: %w", err) 131 } 132 registered = true 133 break 134 } 135 } 136 if !registered { 137 return fmt.Errorf("K8sMonitor: failed to register with the grpcMonitorServer external events sender: unavailable") 138 } 139 140 // get list of pods on node, and handle them 141 if err := m.onStartup(ctx, m.startEvent); err != nil { 142 return fmt.Errorf("K8sMonitor: failed to get list of pods running sandboxes from CRI and generating events for them: %s", err) 143 } 144 145 return nil 146 } 147 148 // Resync should resynchronize PUs. This should be done while starting up. 149 func (m *K8sMonitor) Resync(ctx context.Context) error { 150 return nil 151 }