From 21502e2bb4f3eed8118a1d163d960c9b88180370 Mon Sep 17 00:00:00 2001 From: Avi Huly Date: Sat, 12 Nov 2022 23:00:56 +0200 Subject: [PATCH 01/12] Added namespace selector functionality Changes: modified: internal/pkg/cmd/reloader.go modified: internal/pkg/controller/controller.go modified: internal/pkg/util/util.go --- internal/pkg/cmd/reloader.go | 23 ++++++++++++++++++- internal/pkg/controller/controller.go | 32 ++++++++++++++++++++++++--- internal/pkg/util/util.go | 2 ++ 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/internal/pkg/cmd/reloader.go b/internal/pkg/cmd/reloader.go index f81fa3a9..0616f9b1 100644 --- a/internal/pkg/cmd/reloader.go +++ b/internal/pkg/cmd/reloader.go @@ -38,6 +38,7 @@ func NewReloaderCommand() *cobra.Command { cmd.PersistentFlags().StringVar(&options.LogFormat, "log-format", "", "Log format to use (empty string for text, or JSON") cmd.PersistentFlags().StringSlice("resources-to-ignore", []string{}, "list of resources to ignore (valid options 'configMaps' or 'secrets')") cmd.PersistentFlags().StringSlice("namespaces-to-ignore", []string{}, "list of namespaces to ignore") + cmd.PersistentFlags().StringSlice("namespace-selector", []string{}, "list of key:vaule namespace labels to include") cmd.PersistentFlags().StringVar(&options.IsArgoRollouts, "is-Argo-Rollouts", "false", "Add support for argo rollouts") cmd.PersistentFlags().StringVar(&options.ReloadStrategy, constants.ReloadStrategyFlag, constants.EnvVarsReloadStrategy, "Specifies the desired reload strategy") cmd.PersistentFlags().StringVar(&options.ReloadOnCreate, "reload-on-create", "false", "Add support to watch create events") @@ -132,6 +133,11 @@ func startReloader(cmd *cobra.Command, args []string) { logrus.Fatal(err) } + namespaceLabelSelector, err := getNamespaceLabelSelector(cmd) + if err != nil { + logrus.Fatal(err) + } + collectors := metrics.SetupPrometheusEndpoint() var controllers []*controller.Controller @@ -140,7 +146,7 @@ func startReloader(cmd *cobra.Command, args []string) { continue } - c, err := controller.NewController(clientset, k, currentNamespace, ignoredNamespacesList, collectors) + c, err := controller.NewController(clientset, k, currentNamespace, ignoredNamespacesList, namespaceLabelSelector, collectors) if err != nil { logrus.Fatalf("%s", err) } @@ -174,6 +180,21 @@ func getIgnoredNamespacesList(cmd *cobra.Command) (util.List, error) { return getStringSliceFromFlags(cmd, "namespaces-to-ignore") } +func getNamespaceLabelSelector(cmd *cobra.Command) (util.Map, error) { + slice, err := getStringSliceFromFlags(cmd, "namespace-selector") + if err != nil { + logrus.Fatal(err) + } + + var namespaceSelectorMap util.Map = make(util.Map) + for _, kv := range slice { + split := strings.Split(kv, ":") + namespaceSelectorMap[split[0]] = split[1] + } + + return namespaceSelectorMap, nil +} + func getStringSliceFromFlags(cmd *cobra.Command, flag string) ([]string, error) { slice, err := cmd.Flags().GetStringSlice(flag) if err != nil { diff --git a/internal/pkg/controller/controller.go b/internal/pkg/controller/controller.go index 06bc00f8..a26b8903 100644 --- a/internal/pkg/controller/controller.go +++ b/internal/pkg/controller/controller.go @@ -1,6 +1,7 @@ package controller import ( + "context" "fmt" "time" @@ -11,6 +12,7 @@ import ( "github.com/stakater/Reloader/internal/pkg/util" "github.com/stakater/Reloader/pkg/kube" v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" @@ -32,6 +34,7 @@ type Controller struct { ignoredNamespaces util.List collectors metrics.Collectors recorder record.EventRecorder + namespaceSelector map[string]string } // controllerInitialized flag determines whether controlled is being initialized @@ -39,12 +42,13 @@ var controllerInitialized bool = false // NewController for initializing a Controller func NewController( - client kubernetes.Interface, resource string, namespace string, ignoredNamespaces []string, collectors metrics.Collectors) (*Controller, error) { + client kubernetes.Interface, resource string, namespace string, ignoredNamespaces []string, namespaceLabelSelector map[string]string, collectors metrics.Collectors) (*Controller, error) { c := Controller{ client: client, namespace: namespace, ignoredNamespaces: ignoredNamespaces, + namespaceSelector: namespaceLabelSelector, } eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{ @@ -73,7 +77,7 @@ func NewController( // Add function to add a new object to the queue in case of creating a resource func (c *Controller) Add(obj interface{}) { if options.ReloadOnCreate == "true" { - if !c.resourceInIgnoredNamespace(obj) && controllerInitialized { + if !c.resourceInIgnoredNamespace(obj) && c.resourceInNamespaceSelector(obj) && controllerInitialized { c.queue.Add(handler.ResourceCreatedHandler{ Resource: obj, Collectors: c.collectors, @@ -93,9 +97,31 @@ func (c *Controller) resourceInIgnoredNamespace(raw interface{}) bool { return false } +func (c *Controller) resourceInNamespaceSelector(raw interface{}) bool { + switch object := raw.(type) { + case *v1.ConfigMap: + namespace, _ := c.client.CoreV1().Namespaces().Get(context.Background(), object.ObjectMeta.Namespace, metav1.GetOptions{}) + for k, v := range c.namespaceSelector { + if namespace.ObjectMeta.Labels[k] != v { + return false + } + } + return true + case *v1.Secret: + namespace, _ := c.client.CoreV1().Namespaces().Get(context.Background(), object.ObjectMeta.Namespace, metav1.GetOptions{}) + for k, v := range c.namespaceSelector { + if namespace.ObjectMeta.Labels[k] != v { + return false + } + } + return true + } + return false +} + // 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) { + if !c.resourceInIgnoredNamespace(new) && c.resourceInNamespaceSelector(new) { c.queue.Add(handler.ResourceUpdatedHandler{ Resource: new, OldResource: old, diff --git a/internal/pkg/util/util.go b/internal/pkg/util/util.go index 993084ab..1a2696d8 100644 --- a/internal/pkg/util/util.go +++ b/internal/pkg/util/util.go @@ -54,6 +54,8 @@ func GetSHAfromSecret(data map[string][]byte) string { type List []string +type Map map[string]string + func (l *List) Contains(s string) bool { for _, v := range *l { if v == s { From 82ee3ef3d1837036b3a03fdfa5b7e18b6f4fc28e Mon Sep 17 00:00:00 2001 From: Avi Huly Date: Sun, 13 Nov 2022 16:38:54 +0200 Subject: [PATCH 02/12] Added namespace-selector to helm chart deployment --- .../kubernetes/chart/reloader/templates/deployment.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/deployments/kubernetes/chart/reloader/templates/deployment.yaml b/deployments/kubernetes/chart/reloader/templates/deployment.yaml index 14341b96..0cf87d91 100644 --- a/deployments/kubernetes/chart/reloader/templates/deployment.yaml +++ b/deployments/kubernetes/chart/reloader/templates/deployment.yaml @@ -142,7 +142,7 @@ spec: - mountPath: /tmp/ name: tmp-volume {{- end }} - {{- if or (.Values.reloader.logFormat) (.Values.reloader.ignoreSecrets) (.Values.reloader.ignoreNamespaces) (.Values.reloader.ignoreConfigMaps) (.Values.reloader.custom_annotations) (eq .Values.reloader.isArgoRollouts true) (eq .Values.reloader.reloadOnCreate true) (ne .Values.reloader.reloadStrategy "default") (.Values.reloader.enableHA)}} + {{- if or (.Values.reloader.logFormat) (.Values.reloader.ignoreSecrets) (.Values.reloader.ignoreNamespaces) (.Values.reloader.namespaceSelector) (.Values.reloader.ignoreConfigMaps) (.Values.reloader.custom_annotations) (eq .Values.reloader.isArgoRollouts true) (eq .Values.reloader.reloadOnCreate true) (ne .Values.reloader.reloadStrategy "default") (.Values.reloader.enableHA)}} args: {{- if .Values.reloader.logFormat }} - "--log-format={{ .Values.reloader.logFormat }}" @@ -156,6 +156,9 @@ spec: {{- if .Values.reloader.ignoreNamespaces }} - "--namespaces-to-ignore={{ .Values.reloader.ignoreNamespaces }}" {{- end }} + {{- if .Values.reloader.namespaceSelector }} + - "--namespace-selector={{ .Values.reloader.namespaceSelector }}" + {{- end }} {{- if .Values.reloader.custom_annotations }} {{- if .Values.reloader.custom_annotations.configmap }} From 363fbd3b77c60756ff02ed7fb0180093705438fa Mon Sep 17 00:00:00 2001 From: Avi Huly Date: Tue, 15 Nov 2022 11:11:11 +0200 Subject: [PATCH 03/12] Test for namespace selector --- internal/pkg/controller/controller_test.go | 129 ++++++++++++++++++++- internal/pkg/leadership/leadership_test.go | 2 +- 2 files changed, 128 insertions(+), 3 deletions(-) diff --git a/internal/pkg/controller/controller_test.go b/internal/pkg/controller/controller_test.go index c266ceff..d07fdd82 100644 --- a/internal/pkg/controller/controller_test.go +++ b/internal/pkg/controller/controller_test.go @@ -1,11 +1,13 @@ package controller import ( - "github.com/stakater/Reloader/internal/pkg/constants" + "context" "os" "testing" "time" + "github.com/stakater/Reloader/internal/pkg/constants" + "github.com/stakater/Reloader/internal/pkg/metrics" "github.com/sirupsen/logrus" @@ -14,7 +16,10 @@ import ( "github.com/stakater/Reloader/internal/pkg/testutil" "github.com/stakater/Reloader/internal/pkg/util" "github.com/stakater/Reloader/pkg/kube" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/tools/cache" "k8s.io/client-go/util/workqueue" ) @@ -40,7 +45,7 @@ func TestMain(m *testing.M) { logrus.Infof("Creating controller") for k := range kube.ResourceMap { - c, err := NewController(clients.KubernetesClient, k, namespace, []string{}, collectors) + c, err := NewController(clients.KubernetesClient, k, namespace, []string{}, map[string]string{}, collectors) if err != nil { logrus.Fatalf("%s", err) } @@ -2279,3 +2284,123 @@ func TestController_resourceInIgnoredNamespace(t *testing.T) { }) } } + +func TestController_resourceInNamespaceSelector(t *testing.T) { + type fields struct { + indexer cache.Indexer + queue workqueue.RateLimitingInterface + informer cache.Controller + namespace v1.Namespace + namespaceSelector util.Map + } + type args struct { + raw interface{} + } + tests := []struct { + name string + fields fields + args args + want bool + }{ + { + name: "TestConfigMapResourceInNamespaceSelector", + fields: fields{ + namespaceSelector: util.Map{ + "select": "this", + "select2": "this2", + }, + namespace: v1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "selected-namespace", + Labels: map[string]string{ + "select": "this", + "select2": "this2", + }, + }, + }, + }, + args: args{ + raw: testutil.GetConfigmap("selected-namespace", "testcm", "test"), + }, + want: true, + }, { + name: "TestConfigMapResourceNotInNamespaceSelector", + fields: fields{ + namespaceSelector: util.Map{ + "select": "this", + "select2": "this2", + }, + namespace: v1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "not-selected-namespace", + Labels: map[string]string{}, + }, + }, + }, + args: args{ + raw: testutil.GetConfigmap("not-selected-namespace", "testcm", "test"), + }, + want: false, + }, + { + name: "TestSecretResourceInNamespaceSelector", + fields: fields{ + namespaceSelector: util.Map{ + "select": "this", + "select2": "this2", + }, + namespace: v1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "selected-namespace", + Labels: map[string]string{ + "select": "this", + "select2": "this2", + }, + }, + }, + }, + args: args{ + raw: testutil.GetSecret("selected-namespace", "testsecret", "test"), + }, + want: true, + }, { + name: "TestSecretResourceNotInNamespaceSelector", + fields: fields{ + namespaceSelector: util.Map{ + "select": "this", + "select2": "this2", + }, + namespace: v1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "not-selected-namespace", + Labels: map[string]string{}, + }, + }, + }, + args: args{ + raw: testutil.GetSecret("not-selected-namespace", "secret", "test"), + }, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClient := fake.NewSimpleClientset() + fakeClient.CoreV1().Namespaces().Create(context.Background(), &tt.fields.namespace, metav1.CreateOptions{}) + + c := &Controller{ + client: fakeClient, + indexer: tt.fields.indexer, + queue: tt.fields.queue, + informer: tt.fields.informer, + namespace: tt.fields.namespace.ObjectMeta.Name, + namespaceSelector: tt.fields.namespaceSelector, + } + + if got := c.resourceInNamespaceSelector(tt.args.raw); got != tt.want { + t.Errorf("Controller.resourceInNamespaceSelector() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/pkg/leadership/leadership_test.go b/internal/pkg/leadership/leadership_test.go index 2d64d0cb..99f638c2 100644 --- a/internal/pkg/leadership/leadership_test.go +++ b/internal/pkg/leadership/leadership_test.go @@ -119,7 +119,7 @@ func TestRunLeaderElectionWithControllers(t *testing.T) { t.Logf("Creating controller") var controllers []*controller.Controller for k := range kube.ResourceMap { - c, err := controller.NewController(testutil.Clients.KubernetesClient, k, testutil.Namespace, []string{}, metrics.NewCollectors()) + c, err := controller.NewController(testutil.Clients.KubernetesClient, k, testutil.Namespace, []string{}, map[string]string{}, metrics.NewCollectors()) if err != nil { logrus.Fatalf("%s", err) } From edbad456375e627025efb9e1ddf2c14844558ce8 Mon Sep 17 00:00:00 2001 From: Avi Huly Date: Tue, 15 Nov 2022 11:22:23 +0200 Subject: [PATCH 04/12] namespaceSelector chart value --- deployments/kubernetes/chart/reloader/values.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/deployments/kubernetes/chart/reloader/values.yaml b/deployments/kubernetes/chart/reloader/values.yaml index 4d3e0f62..a9745f34 100644 --- a/deployments/kubernetes/chart/reloader/values.yaml +++ b/deployments/kubernetes/chart/reloader/values.yaml @@ -16,6 +16,7 @@ reloader: reloadOnCreate: false reloadStrategy: default # Set to default, env-vars or annotations ignoreNamespaces: "" # Comma separated list of namespaces to ignore + namespaceSelector: "" # Comma separated list of 'key:value' labels for namespaces selection logFormat: "" #json watchGlobally: true # Set to true to enable leadership election allowing you to run multiple replicas From 08e6f81a15d00779a931865f8e04091e9d341bd3 Mon Sep 17 00:00:00 2001 From: Avi Huly Date: Tue, 15 Nov 2022 16:23:24 +0200 Subject: [PATCH 05/12] Lint fix --- internal/pkg/controller/controller_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/pkg/controller/controller_test.go b/internal/pkg/controller/controller_test.go index d07fdd82..f8d6ee34 100644 --- a/internal/pkg/controller/controller_test.go +++ b/internal/pkg/controller/controller_test.go @@ -2387,7 +2387,8 @@ func TestController_resourceInNamespaceSelector(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { fakeClient := fake.NewSimpleClientset() - fakeClient.CoreV1().Namespaces().Create(context.Background(), &tt.fields.namespace, metav1.CreateOptions{}) + namespace, _ := fakeClient.CoreV1().Namespaces().Create(context.Background(), &tt.fields.namespace, metav1.CreateOptions{}) + logrus.Infof("created fakeClient namesapce for testing = %s", namespace.Name) c := &Controller{ client: fakeClient, From e702610dc660c95fb7777639639fb345ec57ad32 Mon Sep 17 00:00:00 2001 From: Avi Huly Date: Mon, 19 Dec 2022 14:35:28 +0200 Subject: [PATCH 06/12] Readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b2d9ab1f..6df53c7c 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,7 @@ spec: - you may override the configmap annotation with the `--configmap-annotation` flag - you may override the secret annotation with the `--secret-annotation` flag - you may want to prevent watching certain namespaces with the `--namespaces-to-ignore` flag +- you may want to watch only a set of namespaces with certain labels by using the `--namespace-selector` flag - you may want to prevent watching certain resources with the `--resources-to-ignore` flag - you can configure logging in JSON format with the `--log-format=json` option - you can configure the "reload strategy" with the `--reload-strategy=` option (details below) From de21a400ab4b6933d127af4ca9ba9cba433871e5 Mon Sep 17 00:00:00 2001 From: Avi Huli Date: Thu, 22 Dec 2022 14:28:15 +0200 Subject: [PATCH 07/12] Readme namespace selector --- README.md | 23 +++++++++++++++++++ .../chart/reloader/templates/deployment.yaml | 1 - 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6df53c7c..51f25c17 100644 --- a/README.md +++ b/README.md @@ -183,6 +183,23 @@ Reloader can be configured to ignore the resources `secrets` and `configmaps` by `Note`: At one time only one of these resource can be ignored, trying to do it will cause error in Reloader. Workaround for ignoring both resources is by scaling down the reloader pods to `0`. +Reloader can be configured to watch only namespaces labeled with (one or more) labels of your choosing by using the `--namespace-selector` parameter, for example: +``` +--namespace-selector=reloder:enabled,test:true +``` + +Only namespaces labeled like the following namespace YAML will be watched: +```yaml +kind: Namespace +apiVersion: v1 +metadata: + ... + labels: + reloder: enabled + test: true + ... +``` + ### Vanilla kustomize You can also apply the vanilla manifests by running the following command @@ -234,6 +251,12 @@ Reloader can be configured to ignore the resources `secrets` and `configmaps` by `Note`: At one time only one of these resource can be ignored, trying to do it will cause error in helm template compilation. +Reloader can be configured to watch only namespaces labeled with (one or more) labels of your choosing by using the `namespaceSelector` parameter + +| Parameter | Description | Type | +| ---------------- | -------------------------------------------------------------- | ------- | +| namespaceSelector | list of comma separated key:value namespace | string | + You can also set the log format of Reloader to json by setting `logFormat` to `json` in values.yaml and apply the chart You can enable to scrape Reloader's Prometheus metrics by setting `serviceMonitor.enabled` or `podMonitor.enabled` to `true` in values.yaml file. Service monitor will be removed in future releases of reloader in favour of Pod monitor. diff --git a/deployments/kubernetes/chart/reloader/templates/deployment.yaml b/deployments/kubernetes/chart/reloader/templates/deployment.yaml index 103e0dee..786f16de 100644 --- a/deployments/kubernetes/chart/reloader/templates/deployment.yaml +++ b/deployments/kubernetes/chart/reloader/templates/deployment.yaml @@ -159,7 +159,6 @@ spec: {{- if .Values.reloader.namespaceSelector }} - "--namespace-selector={{ .Values.reloader.namespaceSelector }}" {{- end }} - {{- if .Values.reloader.custom_annotations }} {{- if .Values.reloader.custom_annotations.configmap }} - "--configmap-annotation" From 15d7263c950ebb6d4ec33fbd36548a98a7ba278c Mon Sep 17 00:00:00 2001 From: Avi Huli Date: Tue, 27 Dec 2022 18:44:59 +0200 Subject: [PATCH 08/12] Handle empty selector & ns label key not exists --- internal/pkg/controller/controller.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/internal/pkg/controller/controller.go b/internal/pkg/controller/controller.go index 6c622666..c6a1f0d4 100644 --- a/internal/pkg/controller/controller.go +++ b/internal/pkg/controller/controller.go @@ -98,19 +98,25 @@ func (c *Controller) resourceInIgnoredNamespace(raw interface{}) bool { } func (c *Controller) resourceInNamespaceSelector(raw interface{}) bool { + if len(c.namespaceSelector) == 0 { + return true + } + switch object := raw.(type) { case *v1.ConfigMap: namespace, _ := c.client.CoreV1().Namespaces().Get(context.Background(), object.ObjectMeta.Namespace, metav1.GetOptions{}) - for k, v := range c.namespaceSelector { - if namespace.ObjectMeta.Labels[k] != v { + for selectorKey, selectorVal := range c.namespaceSelector { + namespaceLabelVal, namespaceLabelKeyExists := namespace.ObjectMeta.Labels[selectorKey] + if !namespaceLabelKeyExists || selectorVal != namespaceLabelVal { return false } } return true case *v1.Secret: namespace, _ := c.client.CoreV1().Namespaces().Get(context.Background(), object.ObjectMeta.Namespace, metav1.GetOptions{}) - for k, v := range c.namespaceSelector { - if namespace.ObjectMeta.Labels[k] != v { + for selectorKey, selectorVal := range c.namespaceSelector { + namespaceLabelVal, namespaceLabelKeyExists := namespace.ObjectMeta.Labels[selectorKey] + if !namespaceLabelKeyExists || selectorVal != namespaceLabelVal { return false } } From e7cfafd6d6af4663e23808b4e76994044a3d9864 Mon Sep 17 00:00:00 2001 From: Avi Huli Date: Tue, 27 Dec 2022 18:49:23 +0200 Subject: [PATCH 09/12] Handle empty selector & ns label key not exists --- internal/pkg/controller/controller.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/internal/pkg/controller/controller.go b/internal/pkg/controller/controller.go index c6a1f0d4..ed9bf7f5 100644 --- a/internal/pkg/controller/controller.go +++ b/internal/pkg/controller/controller.go @@ -111,7 +111,6 @@ func (c *Controller) resourceInNamespaceSelector(raw interface{}) bool { return false } } - return true case *v1.Secret: namespace, _ := c.client.CoreV1().Namespaces().Get(context.Background(), object.ObjectMeta.Namespace, metav1.GetOptions{}) for selectorKey, selectorVal := range c.namespaceSelector { @@ -120,9 +119,8 @@ func (c *Controller) resourceInNamespaceSelector(raw interface{}) bool { return false } } - return true } - return false + return true } // Update function to add an old object and a new object to the queue in case of updating a resource From 9263b812eb70efab06158e749651e1e13aa92052 Mon Sep 17 00:00:00 2001 From: avihuly Date: Thu, 5 Jan 2023 12:51:41 +0200 Subject: [PATCH 10/12] Added namespace get verb to reloder clusterrole --- .../kubernetes/chart/reloader/templates/clusterrole.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/deployments/kubernetes/chart/reloader/templates/clusterrole.yaml b/deployments/kubernetes/chart/reloader/templates/clusterrole.yaml index 86b86daf..0ce01712 100644 --- a/deployments/kubernetes/chart/reloader/templates/clusterrole.yaml +++ b/deployments/kubernetes/chart/reloader/templates/clusterrole.yaml @@ -32,6 +32,14 @@ rules: - list - get - watch +{{- if .Values.reloader.namespaceSelector }} + - apiGroups: + - "" + resources: + - namespaces + verbs: + - get +{{- end }} {{- if and (.Capabilities.APIVersions.Has "apps.openshift.io/v1") (.Values.reloader.isOpenshift) }} - apiGroups: - "apps.openshift.io" From 8ebbb476b2743a6d780e4ad67df454b1bfd0a57d Mon Sep 17 00:00:00 2001 From: avihuly Date: Thu, 5 Jan 2023 12:54:08 +0200 Subject: [PATCH 11/12] Added logs on startup & get ns opration --- internal/pkg/cmd/reloader.go | 4 ++++ internal/pkg/controller/controller.go | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/internal/pkg/cmd/reloader.go b/internal/pkg/cmd/reloader.go index 0616f9b1..26c115bf 100644 --- a/internal/pkg/cmd/reloader.go +++ b/internal/pkg/cmd/reloader.go @@ -138,6 +138,10 @@ func startReloader(cmd *cobra.Command, args []string) { logrus.Fatal(err) } + if len(namespaceLabelSelector) > 0 { + logrus.Warnf("namespace-selector is set, will detect changes in namespaces with these labels: %s.", namespaceLabelSelector) + } + collectors := metrics.SetupPrometheusEndpoint() var controllers []*controller.Controller diff --git a/internal/pkg/controller/controller.go b/internal/pkg/controller/controller.go index ed9bf7f5..a923d0ed 100644 --- a/internal/pkg/controller/controller.go +++ b/internal/pkg/controller/controller.go @@ -104,7 +104,12 @@ func (c *Controller) resourceInNamespaceSelector(raw interface{}) bool { switch object := raw.(type) { case *v1.ConfigMap: - namespace, _ := c.client.CoreV1().Namespaces().Get(context.Background(), object.ObjectMeta.Namespace, metav1.GetOptions{}) + namespace, err := c.client.CoreV1().Namespaces().Get(context.Background(), object.ObjectMeta.Namespace, metav1.GetOptions{}) + if err != nil { + logrus.Warn(err) + return false + } + for selectorKey, selectorVal := range c.namespaceSelector { namespaceLabelVal, namespaceLabelKeyExists := namespace.ObjectMeta.Labels[selectorKey] if !namespaceLabelKeyExists || selectorVal != namespaceLabelVal { @@ -112,7 +117,12 @@ func (c *Controller) resourceInNamespaceSelector(raw interface{}) bool { } } case *v1.Secret: - namespace, _ := c.client.CoreV1().Namespaces().Get(context.Background(), object.ObjectMeta.Namespace, metav1.GetOptions{}) + namespace, err := c.client.CoreV1().Namespaces().Get(context.Background(), object.ObjectMeta.Namespace, metav1.GetOptions{}) + if err != nil { + logrus.Warn(err) + return false + } + for selectorKey, selectorVal := range c.namespaceSelector { namespaceLabelVal, namespaceLabelKeyExists := namespace.ObjectMeta.Labels[selectorKey] if !namespaceLabelKeyExists || selectorVal != namespaceLabelVal { From 9e7b70964e46d51ad64e3e5659647bfa58c1d7b8 Mon Sep 17 00:00:00 2001 From: avihuly Date: Thu, 5 Jan 2023 14:28:08 +0200 Subject: [PATCH 12/12] Added wildcard label vaule option --- README.md | 2 ++ internal/pkg/controller/controller.go | 42 +++++++++++----------- internal/pkg/controller/controller_test.go | 19 ++++++++++ 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 51f25c17..05b2d81a 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,8 @@ metadata: test: true ... ``` +If you want to select namespace only by the key of the label use ```*``` as the value. +For example, for ```--namespace-selector=select-this:*``` all namespaces with label-key "select-this" will be selected regardless of the labels value ### Vanilla kustomize diff --git a/internal/pkg/controller/controller.go b/internal/pkg/controller/controller.go index a923d0ed..49c3350f 100644 --- a/internal/pkg/controller/controller.go +++ b/internal/pkg/controller/controller.go @@ -104,30 +104,30 @@ func (c *Controller) resourceInNamespaceSelector(raw interface{}) bool { switch object := raw.(type) { case *v1.ConfigMap: - namespace, err := c.client.CoreV1().Namespaces().Get(context.Background(), object.ObjectMeta.Namespace, metav1.GetOptions{}) - if err != nil { - logrus.Warn(err) - return false - } - - for selectorKey, selectorVal := range c.namespaceSelector { - namespaceLabelVal, namespaceLabelKeyExists := namespace.ObjectMeta.Labels[selectorKey] - if !namespaceLabelKeyExists || selectorVal != namespaceLabelVal { - return false - } - } + return c.matchLabels(object.ObjectMeta.Namespace) case *v1.Secret: - namespace, err := c.client.CoreV1().Namespaces().Get(context.Background(), object.ObjectMeta.Namespace, metav1.GetOptions{}) - if err != nil { - logrus.Warn(err) - return false + return c.matchLabels(object.ObjectMeta.Namespace) + } + return true +} + +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 + } + + for selectorKey, selectorVal := range c.namespaceSelector { + + namespaceLabelVal, namespaceLabelKeyExists := namespace.ObjectMeta.Labels[selectorKey] + + if namespaceLabelKeyExists && selectorVal == "*" { + continue } - for selectorKey, selectorVal := range c.namespaceSelector { - namespaceLabelVal, namespaceLabelKeyExists := namespace.ObjectMeta.Labels[selectorKey] - if !namespaceLabelKeyExists || selectorVal != namespaceLabelVal { - return false - } + if !namespaceLabelKeyExists || selectorVal != namespaceLabelVal { + return false } } return true diff --git a/internal/pkg/controller/controller_test.go b/internal/pkg/controller/controller_test.go index f8d6ee34..6b9179bc 100644 --- a/internal/pkg/controller/controller_test.go +++ b/internal/pkg/controller/controller_test.go @@ -2381,6 +2381,25 @@ func TestController_resourceInNamespaceSelector(t *testing.T) { raw: testutil.GetSecret("not-selected-namespace", "secret", "test"), }, want: false, + }, { + name: "TestSecretResourceInNamespaceSelectorWiledcardValue", + fields: fields{ + namespaceSelector: util.Map{ + "select": "*", + }, + namespace: v1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "selected-namespace", + Labels: map[string]string{ + "select": "this", + }, + }, + }, + }, + args: args{ + raw: testutil.GetSecret("selected-namespace", "secret", "test"), + }, + want: true, }, }