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, ©) 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 }