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  }