github.com/nginxinc/kubernetes-ingress@v1.12.5/internal/k8s/task_queue.go (about) 1 package k8s 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/golang/glog" 8 "github.com/nginxinc/kubernetes-ingress/internal/k8s/appprotect" 9 conf_v1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1" 10 conf_v1alpha1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1alpha1" 11 v1 "k8s.io/api/core/v1" 12 networking "k8s.io/api/networking/v1beta1" 13 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 14 "k8s.io/apimachinery/pkg/util/wait" 15 "k8s.io/client-go/util/workqueue" 16 ) 17 18 // taskQueue manages a work queue through an independent worker that 19 // invokes the given sync function for every work item inserted. 20 type taskQueue struct { 21 // queue is the work queue the worker polls 22 queue *workqueue.Type 23 // sync is called for each item in the queue 24 sync func(task) 25 // workerDone is closed when the worker exits 26 workerDone chan struct{} 27 } 28 29 // newTaskQueue creates a new task queue with the given sync function. 30 // The sync function is called for every element inserted into the queue. 31 func newTaskQueue(syncFn func(task)) *taskQueue { 32 return &taskQueue{ 33 queue: workqueue.NewNamed("taskQueue"), 34 sync: syncFn, 35 workerDone: make(chan struct{}), 36 } 37 } 38 39 // Run begins running the worker for the given duration 40 func (tq *taskQueue) Run(period time.Duration, stopCh <-chan struct{}) { 41 wait.Until(tq.worker, period, stopCh) 42 } 43 44 // Enqueue enqueues ns/name of the given api object in the task queue. 45 func (tq *taskQueue) Enqueue(obj interface{}) { 46 key, err := keyFunc(obj) 47 if err != nil { 48 glog.V(3).Infof("Couldn't get key for object %v: %v", obj, err) 49 return 50 } 51 52 task, err := newTask(key, obj) 53 if err != nil { 54 glog.V(3).Infof("Couldn't create a task for object %v: %v", obj, err) 55 return 56 } 57 58 glog.V(3).Infof("Adding an element with a key: %v", task.Key) 59 tq.queue.Add(task) 60 } 61 62 // Requeue adds the task to the queue again and logs the given error 63 func (tq *taskQueue) Requeue(task task, err error) { 64 glog.Errorf("Requeuing %v, err %v", task.Key, err) 65 tq.queue.Add(task) 66 } 67 68 // Len returns the length of the queue 69 func (tq *taskQueue) Len() int { 70 glog.V(3).Infof("The queue has %v element(s)", tq.queue.Len()) 71 return tq.queue.Len() 72 } 73 74 // RequeueAfter adds the task to the queue after the given duration 75 func (tq *taskQueue) RequeueAfter(t task, err error, after time.Duration) { 76 glog.Errorf("Requeuing %v after %s, err %v", t.Key, after.String(), err) 77 go func(t task, after time.Duration) { 78 time.Sleep(after) 79 tq.queue.Add(t) 80 }(t, after) 81 } 82 83 // Worker processes work in the queue through sync. 84 func (tq *taskQueue) worker() { 85 for { 86 t, quit := tq.queue.Get() 87 if quit { 88 close(tq.workerDone) 89 return 90 } 91 glog.V(3).Infof("Syncing %v", t.(task).Key) 92 tq.sync(t.(task)) 93 tq.queue.Done(t) 94 } 95 } 96 97 // Shutdown shuts down the work queue and waits for the worker to ACK 98 func (tq *taskQueue) Shutdown() { 99 tq.queue.ShutDown() 100 <-tq.workerDone 101 } 102 103 // kind represents the kind of the Kubernetes resources of a task 104 type kind int 105 106 // resources 107 const ( 108 ingress = iota 109 endpoints 110 configMap 111 secret 112 service 113 virtualserver 114 virtualServerRoute 115 globalConfiguration 116 transportserver 117 policy 118 appProtectPolicy 119 appProtectLogConf 120 appProtectUserSig 121 ingressLink 122 ) 123 124 // task is an element of a taskQueue 125 type task struct { 126 Kind kind 127 Key string 128 } 129 130 // newTask creates a new task 131 func newTask(key string, obj interface{}) (task, error) { 132 var k kind 133 switch t := obj.(type) { 134 case *networking.Ingress: 135 k = ingress 136 case *v1.Endpoints: 137 k = endpoints 138 case *v1.ConfigMap: 139 k = configMap 140 case *v1.Secret: 141 k = secret 142 case *v1.Service: 143 k = service 144 case *conf_v1.VirtualServer: 145 k = virtualserver 146 case *conf_v1.VirtualServerRoute: 147 k = virtualServerRoute 148 case *conf_v1.Policy: 149 k = policy 150 case *conf_v1alpha1.GlobalConfiguration: 151 k = globalConfiguration 152 case *conf_v1alpha1.TransportServer: 153 k = transportserver 154 case *unstructured.Unstructured: 155 if objectKind := obj.(*unstructured.Unstructured).GetKind(); objectKind == appprotect.PolicyGVK.Kind { 156 k = appProtectPolicy 157 } else if objectKind == appprotect.LogConfGVK.Kind { 158 k = appProtectLogConf 159 } else if objectKind == ingressLinkGVK.Kind { 160 k = ingressLink 161 } else if objectKind == appprotect.UserSigGVK.Kind { 162 k = appProtectUserSig 163 } else { 164 return task{}, fmt.Errorf("Unknown unstructured kind: %v", objectKind) 165 } 166 default: 167 return task{}, fmt.Errorf("Unknown type: %v", t) 168 } 169 170 return task{k, key}, nil 171 }