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  }