diff --git a/internal/features/features.go b/internal/features/features.go new file mode 100644 index 000000000..c0d330efe --- /dev/null +++ b/internal/features/features.go @@ -0,0 +1,59 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package features sets the feature gates that kustomize-controller supports, +// and their default states. +package features + +import feathelper "github.com/fluxcd/pkg/runtime/features" + +const ( + // CacheSecretsAndConfigMaps controls whether Secrets and ConfigMaps should + // be cached. + // + // When enabled, it will cache both object types, resulting in increased + // memory usage and cluster-wide RBAC permissions (list and watch). + CacheSecretsAndConfigMaps = "CacheSecretsAndConfigMaps" +) + +var features = map[string]bool{ + // CacheSecretsAndConfigMaps + // opt-in from v0.33 + CacheSecretsAndConfigMaps: false, +} + +// FeatureGates contains a list of all supported feature gates and +// their default values. +func FeatureGates() map[string]bool { + return features +} + +// Enabled verifies whether the feature is enabled or not. +// +// This is only a wrapper around the Enabled func in +// pkg/runtime/features, so callers won't need to import both packages +// for checking whether a feature is enabled. +func Enabled(feature string) (bool, error) { + return feathelper.Enabled(feature) +} + +// Disable disables the specified feature. If the feature is not +// present, it's a no-op. +func Disable(feature string) { + if _, ok := features[feature]; ok { + features[feature] = false + } +} diff --git a/main.go b/main.go index c977e90c2..d7befb967 100644 --- a/main.go +++ b/main.go @@ -18,6 +18,7 @@ package main import ( "fmt" + corev1 "k8s.io/api/core/v1" "os" "time" @@ -29,11 +30,13 @@ import ( "sigs.k8s.io/cli-utils/pkg/kstatus/polling" "sigs.k8s.io/cli-utils/pkg/kstatus/polling/engine" ctrl "sigs.k8s.io/controller-runtime" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "github.com/fluxcd/pkg/runtime/acl" runtimeClient "github.com/fluxcd/pkg/runtime/client" runtimeCtrl "github.com/fluxcd/pkg/runtime/controller" "github.com/fluxcd/pkg/runtime/events" + feathelper "github.com/fluxcd/pkg/runtime/features" "github.com/fluxcd/pkg/runtime/leaderelection" "github.com/fluxcd/pkg/runtime/logger" "github.com/fluxcd/pkg/runtime/pprof" @@ -42,6 +45,7 @@ import ( kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2" "github.com/fluxcd/kustomize-controller/controllers" + "github.com/fluxcd/kustomize-controller/internal/features" "github.com/fluxcd/kustomize-controller/internal/statusreaders" // +kubebuilder:scaffold:imports ) @@ -78,6 +82,7 @@ func main() { noRemoteBases bool httpRetry int defaultServiceAccount string + featureGates feathelper.FeatureGates ) flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") @@ -91,14 +96,22 @@ func main() { "Disallow remote bases usage in Kustomize overlays. When this flag is enabled, all resources must refer to local files included in the source artifact.") flag.IntVar(&httpRetry, "http-retry", 9, "The maximum number of retries when failing to fetch artifacts over HTTP.") flag.StringVar(&defaultServiceAccount, "default-service-account", "", "Default service account used for impersonation.") + clientOptions.BindFlags(flag.CommandLine) logOptions.BindFlags(flag.CommandLine) leaderElectionOptions.BindFlags(flag.CommandLine) aclOptions.BindFlags(flag.CommandLine) kubeConfigOpts.BindFlags(flag.CommandLine) rateLimiterOptions.BindFlags(flag.CommandLine) + featureGates.BindFlags(flag.CommandLine) + flag.Parse() + if err := featureGates.WithLogger(setupLog).SupportedFeatures(features.FeatureGates()); err != nil { + setupLog.Error(err, "unable to load feature gates") + os.Exit(1) + } + ctrl.SetLogger(logger.NewLogger(logOptions)) watchNamespace := "" @@ -106,6 +119,16 @@ func main() { watchNamespace = os.Getenv("RUNTIME_NAMESPACE") } + var disableCacheFor []ctrlclient.Object + shouldCache, err := features.Enabled(features.CacheSecretsAndConfigMaps) + if err != nil { + setupLog.Error(err, "unable to check feature gate "+features.CacheSecretsAndConfigMaps) + os.Exit(1) + } + if !shouldCache { + disableCacheFor = append(disableCacheFor, &corev1.Secret{}, &corev1.ConfigMap{}) + } + restConfig := runtimeClient.GetConfigOrDie(clientOptions) mgr, err := ctrl.NewManager(restConfig, ctrl.Options{ Scheme: scheme, @@ -120,6 +143,7 @@ func main() { LeaderElectionID: fmt.Sprintf("%s-leader-election", controllerName), Namespace: watchNamespace, Logger: ctrl.Log, + ClientDisableCacheFor: disableCacheFor, }) if err != nil { setupLog.Error(err, "unable to start manager")