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 {