github.com/jenkins-x/jx/v2@v2.1.155/pkg/kube/pipeline_cache.go (about)

     1  package kube
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	v1 "github.com/jenkins-x/jx-api/pkg/apis/jenkins.io/v1"
     8  	"github.com/jenkins-x/jx-api/pkg/client/clientset/versioned"
     9  	"github.com/jenkins-x/jx-logging/pkg/log"
    10  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    11  	"k8s.io/apimachinery/pkg/fields"
    12  	"k8s.io/client-go/tools/cache"
    13  )
    14  
    15  // PipelineNamespaceCache caches the pipelines for a single namespace
    16  type PipelineNamespaceCache struct {
    17  	pipelines sync.Map
    18  	stop      chan struct{}
    19  	//Flag to indicate whether the cache has done its initial load & is in sync.
    20  	ready bool
    21  }
    22  
    23  // NewPipelineCache creates a cache of pipelines for a namespace
    24  func NewPipelineCache(jxClient versioned.Interface, ns string) *PipelineNamespaceCache {
    25  	pipeline := &v1.PipelineActivity{}
    26  	pipelineListWatch := cache.NewListWatchFromClient(jxClient.JenkinsV1().RESTClient(), "pipelineactivities", ns, fields.Everything())
    27  
    28  	pipelineCache := &PipelineNamespaceCache{
    29  		stop: make(chan struct{}),
    30  	}
    31  
    32  	// lets pre-populate the cache on startup as there's not yet a way to know when the informer has completed its first list operation
    33  	pipelines, _ := jxClient.JenkinsV1().PipelineActivities(ns).List(metav1.ListOptions{})
    34  	if pipelines != nil {
    35  		for _, pipeline := range pipelines.Items {
    36  			copy := pipeline
    37  			pipelineCache.pipelines.Store(pipeline.Name, &copy)
    38  		}
    39  	}
    40  	_, pipelineController := cache.NewInformer(
    41  		pipelineListWatch,
    42  		pipeline,
    43  		time.Minute*10,
    44  		cache.ResourceEventHandlerFuncs{
    45  			AddFunc: func(obj interface{}) {
    46  				pipelineCache.onPipelineObj(obj, jxClient, ns)
    47  			},
    48  			UpdateFunc: func(oldObj, newObj interface{}) {
    49  				pipelineCache.onPipelineObj(newObj, jxClient, ns)
    50  			},
    51  			DeleteFunc: func(obj interface{}) {
    52  				pipelineCache.onPipelineDelete(obj, jxClient, ns)
    53  			},
    54  		},
    55  	)
    56  
    57  	go pipelineController.Run(pipelineCache.stop)
    58  
    59  	pipelineCache.ready = true
    60  
    61  	return pipelineCache
    62  }
    63  
    64  // Ready returns true if this cache has done its initial load and is in sync.
    65  func (c *PipelineNamespaceCache) Ready() bool {
    66  	return c.ready
    67  }
    68  
    69  // Stop closes the underlying chanel processing events which stops consuming watch events
    70  func (c *PipelineNamespaceCache) Stop() {
    71  	c.ready = false
    72  	close(c.stop)
    73  }
    74  
    75  // Pipelines returns the pipelines in this namespace sorted in name order
    76  func (c *PipelineNamespaceCache) Pipelines() []*v1.PipelineActivity {
    77  	answer := []*v1.PipelineActivity{}
    78  	onEntry := func(key interface{}, value interface{}) bool {
    79  		pipeline, ok := value.(*v1.PipelineActivity)
    80  		if ok && pipeline != nil {
    81  			answer = append(answer, pipeline)
    82  		}
    83  		return true
    84  	}
    85  	c.pipelines.Range(onEntry)
    86  	return answer
    87  }
    88  
    89  // ForEach runs the supplied function on every element in the Map. In no particular order.
    90  func (c *PipelineNamespaceCache) ForEach(callback func(*v1.PipelineActivity)) {
    91  	onEntry := func(key interface{}, value interface{}) bool {
    92  		pipeline, ok := value.(*v1.PipelineActivity)
    93  		if ok && pipeline != nil {
    94  			callback(pipeline)
    95  		}
    96  		return true
    97  	}
    98  	c.pipelines.Range(onEntry)
    99  }
   100  
   101  func (c *PipelineNamespaceCache) onPipelineObj(obj interface{}, jxClient versioned.Interface, ns string) {
   102  	pipeline, ok := obj.(*v1.PipelineActivity)
   103  	if !ok {
   104  		log.Logger().Warnf("Object is not a PipelineActivity %#v", obj)
   105  		return
   106  	}
   107  	if pipeline != nil {
   108  		c.pipelines.Store(pipeline.Name, pipeline)
   109  	}
   110  }
   111  
   112  func (c *PipelineNamespaceCache) onPipelineDelete(obj interface{}, jxClient versioned.Interface, ns string) {
   113  	pipeline, ok := obj.(*v1.PipelineActivity)
   114  	if !ok {
   115  		log.Logger().Warnf("Object is not a PipelineActivity %#v", obj)
   116  		return
   117  	}
   118  	if pipeline != nil {
   119  		c.pipelines.Delete(pipeline.Name)
   120  	}
   121  }