From 6b1caac3f17caf38bf8cfdc1b48a5ebf9239bf55 Mon Sep 17 00:00:00 2001 From: Arthur Silva Sens Date: Thu, 2 May 2024 20:41:30 -0300 Subject: [PATCH] Add structure for feature flags Signed-off-by: Arthur Silva Sens --- Documentation/operator.md | 2 ++ cmd/operator/main.go | 18 ++++++++++ pkg/operator/feature_gates.go | 63 +++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 pkg/operator/feature_gates.go diff --git a/Documentation/operator.md b/Documentation/operator.md index 70c4d92de..2b59dc362 100644 --- a/Documentation/operator.md +++ b/Documentation/operator.md @@ -49,6 +49,8 @@ Usage of ./operator: Namespaces not to scope the interaction of the Prometheus Operator (deny list). This is mutually exclusive with --namespaces. -enable-config-reloader-probes Enable liveness and readiness for the config-reloader container. Default: false + -feature-gates value + Feature gates are a set of key=value pairs that describe Prometheus-Operator features. At the moment there are no feature gates available. -key-file string - NOT RECOMMENDED FOR PRODUCTION - Path to private TLS certificate file. -kubelet-node-address-priority value diff --git a/cmd/operator/main.go b/cmd/operator/main.go index 41c4d4122..674ad63a9 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -41,6 +41,8 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" + k8sflag "k8s.io/component-base/cli/flag" + "k8s.io/utils/ptr" logging "github.com/prometheus-operator/prometheus-operator/internal/log" "github.com/prometheus-operator/prometheus-operator/pkg/admission" @@ -114,6 +116,8 @@ var ( kubeletObject string kubeletSelector operator.LabelSelector nodeAddressPriority operator.NodeAddressPriority + + featureGates *k8sflag.MapStringBool ) func parseFlags(fs *flag.FlagSet) { @@ -166,6 +170,11 @@ func parseFlags(fs *flag.FlagSet) { fs.Var(&cfg.ThanosRulerSelector, "thanos-ruler-instance-selector", "Label selector to filter ThanosRuler Custom Resources to watch.") fs.Var(&cfg.SecretListWatchSelector, "secret-field-selector", "Field selector to filter Secrets to watch") + featureGates = k8sflag.NewMapStringBool(ptr.To(make(map[string]bool))) + fs.Var(featureGates, "feature-gates", "Feature gates are a set of key=value pairs that describe Prometheus-Operator features. At the moment there are no feature gates available.") + // Once the first feature gate is added, the line below should be uncommented and the line above deleted. + //fs.Var(featureGates, "feature-gates", fmt.Sprintf("Feature gates are a set of key=value pairs that describe Prometheus-Operator features. Available features: %q.", operator.AvailableFeatureGates())) + logging.RegisterFlags(fs, &logConfig) versionutil.RegisterFlags(fs) @@ -193,8 +202,17 @@ func run(fs *flag.FlagSet) int { level.Warn(logger).Log("msg", "Failed to set GOMAXPROCS automatically", "err", err) } + gates, err := operator.ValidateFeatureGates(featureGates) + if err != nil { + level.Error(logger).Log( + "msg", "error validating feature gates", + "error", err) + return 1 + } + level.Info(logger).Log("msg", "Starting Prometheus Operator", "version", version.Info()) level.Info(logger).Log("build_context", version.BuildContext()) + level.Info(logger).Log("feature_gates", gates) if len(cfg.Namespaces.AllowList) > 0 && len(cfg.Namespaces.DenyList) > 0 { level.Error(logger).Log( diff --git a/pkg/operator/feature_gates.go b/pkg/operator/feature_gates.go new file mode 100644 index 000000000..79cec0ea2 --- /dev/null +++ b/pkg/operator/feature_gates.go @@ -0,0 +1,63 @@ +// Copyright 2024 The prometheus-operator 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 operator + +import ( + "fmt" + "slices" + "strings" + + k8sflag "k8s.io/component-base/cli/flag" +) + +// At the moment, the are no feature gates available. +var defaultFeatureGates = map[string]bool{} + +// ValidateFeatureGates merges the feature gate default values with +// the values provided by the user. +func ValidateFeatureGates(flags *k8sflag.MapStringBool) (string, error) { + gates := defaultFeatureGates + if flags.Empty() { + return mapToString(gates), nil + } + + imgs := *flags.Map + for k, v := range imgs { + if _, ok := gates[k]; !ok { + return "", fmt.Errorf("feature gate %v is unknown", k) + } + gates[k] = v + } + return mapToString(gates), nil +} + +func AvailableFeatureGates() []string { + i := 0 + gates := make([]string, len(defaultFeatureGates)) + for k := range defaultFeatureGates { + gates[i] = k + i++ + } + slices.Sort(gates) + return gates +} + +func mapToString(m map[string]bool) string { + var s []string + for k, v := range m { + s = append(s, fmt.Sprintf("%s=%t", k, v)) + } + return strings.Join(s, ",") +}