github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/pkg/kubernetes/watcher.go (about) 1 package kubernetes 2 3 import ( 4 "context" 5 "time" 6 7 "github.com/kyma-incubator/compass/components/director/pkg/log" 8 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 "k8s.io/apimachinery/pkg/watch" 10 ) 11 12 // Watcher is a K8S watcher that listen for resources changes and receive events based on that 13 //go:generate mockery --name=Watcher --output=automock --outpkg=automock --case=underscore --disable-version-string 14 type Watcher interface { 15 Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) 16 } 17 18 type processWatchEventsFunc func(ctx context.Context, events <-chan watch.Event) 19 20 // K8SWatcher is a structure containing dependencies for the watch mechanism 21 type K8SWatcher struct { 22 ctx context.Context 23 k8sWatcher Watcher 24 processWatchEventsFunc processWatchEventsFunc 25 reconnectInterval time.Duration 26 resourceName string 27 correlationID string 28 } 29 30 // NewWatcher return initialized K8SWatcher structure 31 func NewWatcher(ctx context.Context, k8sWatcher Watcher, processWatchEventsFunc processWatchEventsFunc, reconnectInterval time.Duration, resourceName, correlationID string) *K8SWatcher { 32 return &K8SWatcher{ 33 ctx: ctx, 34 k8sWatcher: k8sWatcher, 35 processWatchEventsFunc: processWatchEventsFunc, 36 reconnectInterval: reconnectInterval, 37 resourceName: resourceName, 38 correlationID: correlationID, 39 } 40 } 41 42 // Run starts goroutine that uses kubernetes watch mechanism to listen for resource changes 43 func (w *K8SWatcher) Run(ctx context.Context) { 44 entry := log.C(ctx) 45 entry = entry.WithField(log.FieldRequestID, w.correlationID) 46 ctx = log.ContextWithLogger(ctx, entry) 47 48 w.startKubeWatch(ctx) 49 } 50 51 func (w *K8SWatcher) startKubeWatch(ctx context.Context) { 52 for { 53 select { 54 case <-ctx.Done(): 55 log.C(ctx).Infof("Context cancelled, stopping kubernetes watcher for resource with name: %s...", w.resourceName) 56 return 57 default: 58 } 59 log.C(ctx).Info("Starting kubernetes watcher for changes...") 60 wr, err := w.k8sWatcher.Watch(ctx, metav1.ListOptions{ 61 FieldSelector: "metadata.name=" + w.resourceName, 62 Watch: true, 63 }) 64 if err != nil { 65 log.C(ctx).WithError(err).Errorf("Could not initialize watcher for resource with name: %s. Sleep for %s and try again... %v", w.resourceName, w.reconnectInterval.String(), err) 66 time.Sleep(w.reconnectInterval) 67 continue 68 } 69 log.C(ctx).Infof("Waiting for kubernetes watcher events for resource with name: %s...", w.resourceName) 70 71 w.processWatchEventsFunc(ctx, wr.ResultChan()) 72 73 log.C(ctx).Infof("Processed kubernetes watcher events for resource with name: %s", w.resourceName) 74 75 // Cleanup any allocated resources 76 wr.Stop() 77 time.Sleep(w.reconnectInterval) 78 } 79 }