diff --git a/cmd/cainjector/app/BUILD.bazel b/cmd/cainjector/app/BUILD.bazel index 7eef134da..2862dd1f2 100644 --- a/cmd/cainjector/app/BUILD.bazel +++ b/cmd/cainjector/app/BUILD.bazel @@ -11,6 +11,7 @@ go_library( "//pkg/controller/cainjector:go_default_library", "//pkg/logs:go_default_library", "//pkg/util:go_default_library", + "//pkg/util/feature:go_default_library", "//pkg/util/profiling:go_default_library", "@com_github_go_logr_logr//:go_default_library", "@com_github_spf13_cobra//:go_default_library", diff --git a/cmd/cainjector/app/start.go b/cmd/cainjector/app/start.go index bd3a655df..c191395db 100644 --- a/cmd/cainjector/app/start.go +++ b/cmd/cainjector/app/start.go @@ -36,6 +36,7 @@ import ( "github.com/cert-manager/cert-manager/pkg/controller/cainjector" logf "github.com/cert-manager/cert-manager/pkg/logs" "github.com/cert-manager/cert-manager/pkg/util" + utilfeature "github.com/cert-manager/cert-manager/pkg/util/feature" "github.com/cert-manager/cert-manager/pkg/util/profiling" ) @@ -88,6 +89,8 @@ func (o *InjectorControllerOptions) AddFlags(fs *pflag.FlagSet) { fs.BoolVar(&o.EnablePprof, "enable-profiling", cmdutil.DefaultEnableProfiling, "Enable profiling for cainjector") fs.StringVar(&o.PprofAddr, "profiler-address", cmdutil.DefaultProfilerAddr, "Address of the Go profiler (pprof) if enabled. This should never be exposed on a public interface.") + + utilfeature.DefaultMutableFeatureGate.AddFlag(fs) } // NewInjectorControllerOptions returns a new InjectorControllerOptions diff --git a/devel/addon/certmanager/install.sh b/devel/addon/certmanager/install.sh index 803b97c75..bb2dc7ad8 100755 --- a/devel/addon/certmanager/install.sh +++ b/devel/addon/certmanager/install.sh @@ -25,10 +25,23 @@ RELEASE_NAME="${RELEASE_NAME:-cert-manager}" # Default feature gates to enable FEATURE_GATES="${FEATURE_GATES:-ExperimentalCertificateSigningRequestControllers=true,ExperimentalGatewayAPISupport=true,AdditionalCertificateOutputFormats=true}" +# As Feature Gates are added/removed, these lists should be updated. +declare -a FEATURE_GATES_CONTROLLER_ALL=(\ +"AllAlpha","AllBeta","ValidateCAA","ExperimentalCertificateSigningRequestControllers",\ +"ExperimentalGatewayAPISupport","AdditionalCertificateOutputFormats") +declare -a FEATURE_GATES_WEBHOOK_ALL=(\ +"AllAlpha","AllBeta","AdditionalCertificateOutputFormats") +declare -a FEATURE_GATES_CAINJECTOR_ALL=(\ +"AllAlpha","AllBeta") + SCRIPT_ROOT=$(dirname "${BASH_SOURCE}") source "${SCRIPT_ROOT}/../../lib/lib.sh" SCRIPT_ROOT=$(dirname "${BASH_SOURCE}") +FEATURE_GATES_CONTROLLER=$(registered_feature_gates_for $FEATURE_GATES_CONTROLLER_ALL "${FEATURE_GATES}") +FEATURE_GATES_WEBHOOK=$(registered_feature_gates_for $FEATURE_GATES_WEBHOOK_ALL "${FEATURE_GATES}") +FEATURE_GATES_CAINJECTOR=$(registered_feature_gates_for $FEATURE_GATES_CAINJECTOR_ALL "${FEATURE_GATES}") + # Require kubectl & helm available on PATH check_tool kubectl check_tool kubectl-cert_manager @@ -71,8 +84,10 @@ helm upgrade \ --set webhook.image.tag="${APP_VERSION}" \ --set startupapicheck.image.tag="${APP_VERSION}" \ --set installCRDs=true \ - --set featureGates="${FEATURE_GATES//,/\\,}" `# escape commas in --set by replacing , with \, (see https://github.com/helm/helm/issues/2952)` \ - --set "webhook.extraArgs={--feature-gates=AllAlpha=true}" \ + `# escape commas in --set by replacing , with \, (see https://github.com/helm/helm/issues/2952)` \ + --set featureGates="${FEATURE_GATES_CONTROLLER//,/\\,}" \ + --set "webhook.extraArgs={--feature-gates=${FEATURE_GATES_WEBHOOK//,/\\,}}" \ + --set "cainjector.extraArgs={--feature-gates=${FEATURE_GATES_CAINJECTOR//,/\\,}}"\ --set "extraArgs={--dns01-recursive-nameservers=${SERVICE_IP_PREFIX}.16:53,--dns01-recursive-nameservers-only=true}" \ "$RELEASE_NAME" \ "$REPO_ROOT/bazel-bin/deploy/charts/cert-manager/cert-manager.tgz" diff --git a/devel/lib/lib.sh b/devel/lib/lib.sh index feb56add8..8a4180c28 100644 --- a/devel/lib/lib.sh +++ b/devel/lib/lib.sh @@ -115,3 +115,27 @@ export_logs() { echo "Exporting cluster logs to artifacts..." "${SCRIPT_ROOT}/cluster/export-logs.sh" } + +# join_by joins a list of strings by a string. +# e.g. `join_by , a b c` -> `a,b,c` +join_by() { + local d=${1-} f=${2-} + if shift 2; then + printf %s "$f" "${@/#/$d}" + fi +} + +# registered_feature_gates_for returns the subset of supported of feature gates +# from the given enabled features. Supported features is the first argument, +# features that are enabled is second. +registered_feature_gates_for() { + declare -a FEATURE_GATES_SUPPORTED=($1) + FEATURE_GATES="$2" + declare -a FEATURE_GATES_TO_RUN=() + for val in ${FEATURE_GATES//,/ }; do + if [[ "${FEATURE_GATES_SUPPORTED[*]}" =~ "${val%=*}" ]]; then + FEATURE_GATES_TO_RUN+=($val) + fi + done + join_by , ${FEATURE_GATES_TO_RUN[@]} +} diff --git a/internal/BUILD.bazel b/internal/BUILD.bazel index e3fd2d84e..ccecdfa16 100644 --- a/internal/BUILD.bazel +++ b/internal/BUILD.bazel @@ -13,6 +13,7 @@ filegroup( "//internal/apis/certmanager:all-srcs", "//internal/apis/config/webhook:all-srcs", "//internal/apis/meta:all-srcs", + "//internal/cainjector/feature:all-srcs", "//internal/controller/certificates:all-srcs", "//internal/controller/feature:all-srcs", "//internal/ingress:all-srcs", diff --git a/internal/cainjector/feature/BUILD.bazel b/internal/cainjector/feature/BUILD.bazel new file mode 100644 index 000000000..f5f702218 --- /dev/null +++ b/internal/cainjector/feature/BUILD.bazel @@ -0,0 +1,26 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["features.go"], + importpath = "github.com/cert-manager/cert-manager/internal/cainjector/feature", + visibility = ["//:__subpackages__"], + deps = [ + "//pkg/util/feature:go_default_library", + "@io_k8s_component_base//featuregate:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/internal/cainjector/feature/features.go b/internal/cainjector/feature/features.go new file mode 100644 index 000000000..828316448 --- /dev/null +++ b/internal/cainjector/feature/features.go @@ -0,0 +1,44 @@ +/* +Copyright 2022 The cert-manager 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 feature + +import ( + "k8s.io/component-base/featuregate" + + utilfeature "github.com/cert-manager/cert-manager/pkg/util/feature" +) + +const ( +// FeatureName will enable XYZ feature. +// Fill this section out with additional details about the feature. +// +// Owner (responsible for graduating feature through to GA): @username +// Alpha: vX.Y +// Beta: ... +//FeatureName featuregate.Feature = "FeatureName" +) + +func init() { + utilfeature.DefaultMutableFeatureGate.Add(cainjectorFeatureGates) +} + +// cainjectorFeatureGates defines all feature gates for the cainjector component. +// To add a new feature, define a key for it above and add it here. +// To check whether a feature is enabled, use: +// utilfeature.DefaultFeatureGate.Enabled(feature.FeatureName) +// Where utilfeature is github.com/cert-manager/cert-manager/pkg/util/feature. +var cainjectorFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{}