refactor: use Namespace controller for namespaceSelector

Signed-off-by: Craig Trought <k8s@trought.ca>
This commit is contained in:
ctrought
2023-03-31 14:43:33 -04:00
parent 3907495a42
commit e39a8f6bcf
3 changed files with 52 additions and 26 deletions

View File

@@ -148,7 +148,7 @@ func startReloader(cmd *cobra.Command, args []string) {
var controllers []*controller.Controller
for k := range kube.ResourceMap {
if ignoredResourcesList.Contains(k) {
if ignoredResourcesList.Contains(k) || (len(namespaceLabelSelector) == 0 && k == "namespaces") {
continue
}

View File

@@ -1,7 +1,6 @@
package controller
import (
"context"
"fmt"
"time"
@@ -14,6 +13,7 @@ import (
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
@@ -22,6 +22,7 @@ import (
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/utils/strings/slices"
)
// Controller for checking events
@@ -41,6 +42,7 @@ type Controller struct {
// controllerInitialized flag determines whether controlled is being initialized
var secretControllerInitialized bool = false
var configmapControllerInitialized bool = false
var selectedNamespacesCache []string
// NewController for initializing a Controller
func NewController(
@@ -65,7 +67,17 @@ func NewController(
recorder := eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: fmt.Sprintf("reloader-%s", resource)})
queue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())
listWatcher := cache.NewListWatchFromClient(client.CoreV1().RESTClient(), resource, namespace, fields.Everything())
optionsModifier := func(options *metav1.ListOptions) {
if resource == "namespaces" {
labelSelector := metav1.LabelSelector{MatchLabels: c.namespaceSelector}
options.LabelSelector = labels.Set(labelSelector.MatchLabels).String()
} else {
options.FieldSelector = fields.Everything().String()
}
}
listWatcher := cache.NewFilteredListWatchFromClient(client.CoreV1().RESTClient(), resource, namespace, optionsModifier)
indexer, informer := cache.NewIndexerInformer(listWatcher, kube.ResourceMap[resource], 0, cache.ResourceEventHandlerFuncs{
AddFunc: c.Add,
@@ -84,8 +96,15 @@ func NewController(
// Add function to add a new object to the queue in case of creating a resource
func (c *Controller) Add(obj interface{}) {
switch object := obj.(type) {
case *v1.Namespace:
c.addSelectedNamespaceToCache(object)
return
}
if options.ReloadOnCreate == "true" {
if !c.resourceInIgnoredNamespace(obj) && c.resourceInNamespaceSelector(obj) && secretControllerInitialized && configmapControllerInitialized {
if !c.resourceInIgnoredNamespace(obj) && c.resourceInSelectedNamespaces(obj) && secretControllerInitialized && configmapControllerInitialized {
c.queue.Add(handler.ResourceCreatedHandler{
Resource: obj,
Collectors: c.collectors,
@@ -105,45 +124,45 @@ func (c *Controller) resourceInIgnoredNamespace(raw interface{}) bool {
return false
}
func (c *Controller) resourceInNamespaceSelector(raw interface{}) bool {
func (c *Controller) resourceInSelectedNamespaces(raw interface{}) bool {
if len(c.namespaceSelector) == 0 {
return true
}
switch object := raw.(type) {
case *v1.ConfigMap:
return c.matchLabels(object.ObjectMeta.Namespace)
if slices.Contains(selectedNamespacesCache, object.GetNamespace()) {
return true
}
case *v1.Secret:
return c.matchLabels(object.ObjectMeta.Namespace)
if slices.Contains(selectedNamespacesCache, object.GetNamespace()) {
return true
}
}
return true
return false
}
func (c *Controller) matchLabels(resourceNamespace string) bool {
namespace, err := c.client.CoreV1().Namespaces().Get(context.Background(), resourceNamespace, metav1.GetOptions{})
if err != nil {
logrus.Warn(err)
return false
}
func (c *Controller) addSelectedNamespaceToCache(namespace *v1.Namespace) {
selectedNamespacesCache = append(selectedNamespacesCache, namespace.GetName())
}
for selectorKey, selectorVal := range c.namespaceSelector {
namespaceLabelVal, namespaceLabelKeyExists := namespace.ObjectMeta.Labels[selectorKey]
if namespaceLabelKeyExists && selectorVal == "*" {
continue
}
if !namespaceLabelKeyExists || selectorVal != namespaceLabelVal {
return false
func (c *Controller) removeSelectedNamespaceFromCache(namespace *v1.Namespace) {
for i, v := range selectedNamespacesCache {
if v == namespace.GetName() {
selectedNamespacesCache = append(selectedNamespacesCache[:i], selectedNamespacesCache[i+1:]...)
return
}
}
return true
}
// Update function to add an old object and a new object to the queue in case of updating a resource
func (c *Controller) Update(old interface{}, new interface{}) {
if !c.resourceInIgnoredNamespace(new) && c.resourceInNamespaceSelector(new) {
switch new.(type) {
case *v1.Namespace:
return
}
if !c.resourceInIgnoredNamespace(new) && c.resourceInSelectedNamespaces(new) {
c.queue.Add(handler.ResourceUpdatedHandler{
Resource: new,
OldResource: old,
@@ -155,6 +174,12 @@ func (c *Controller) Update(old interface{}, new interface{}) {
// Delete function to add an object to the queue in case of deleting a resource
func (c *Controller) Delete(old interface{}) {
switch object := old.(type) {
case *v1.Namespace:
c.removeSelectedNamespaceFromCache(object)
return
}
// Todo: Any future delete event can be handled here
}

View File

@@ -9,4 +9,5 @@ import (
var ResourceMap = map[string]runtime.Object{
"configMaps": &v1.ConfigMap{},
"secrets": &v1.Secret{},
"namespaces": &v1.Namespace{},
}