diff --git a/.env b/.env index 3906a4f7c..6ccb31548 100644 --- a/.env +++ b/.env @@ -1,6 +1,6 @@ OPERATOR_SDK_VERSION=v1.42.0 REVIEWERS=vivekr-splunk,rlieberman-splunk,patrykw-splunk,Igor-splunk,kasiakoziol,kubabuczak,gabrielm-splunk,minjieqiu,qingw-splunk -GO_VERSION=1.25.8 +GO_VERSION=1.26.2 AWSCLI_URL=https://awscli.amazonaws.com/awscli-exe-linux-x86_64-2.8.6.zip KUBECTL_VERSION=v1.29.1 AZ_CLI_VERSION=2.79.0 diff --git a/.github/workflows/arm-AL2023-build-test-push-workflow-AL2023.yml b/.github/workflows/arm-AL2023-build-test-push-workflow-AL2023.yml index df24959a7..0830d9596 100644 --- a/.github/workflows/arm-AL2023-build-test-push-workflow-AL2023.yml +++ b/.github/workflows/arm-AL2023-build-test-push-workflow-AL2023.yml @@ -135,7 +135,7 @@ jobs: appframeworksS1, managersecret, managermc, - indingsep, + indexingestionsep, licensemanager, ] runs-on: ubuntu-latest diff --git a/.github/workflows/arm-AL2023-int-test-workflow.yml b/.github/workflows/arm-AL2023-int-test-workflow.yml index 39986ebca..a65cf941f 100644 --- a/.github/workflows/arm-AL2023-int-test-workflow.yml +++ b/.github/workflows/arm-AL2023-int-test-workflow.yml @@ -69,7 +69,7 @@ jobs: managercrcrud, licensemanager, managerdeletecr, - indingsep, + indexingestionsep, ] runs-on: ubuntu-latest needs: build-operator-image-arm-al2023 diff --git a/.github/workflows/arm-RHEL-build-test-push-workflow.yml b/.github/workflows/arm-RHEL-build-test-push-workflow.yml index 07848683c..f86a5e632 100644 --- a/.github/workflows/arm-RHEL-build-test-push-workflow.yml +++ b/.github/workflows/arm-RHEL-build-test-push-workflow.yml @@ -69,7 +69,7 @@ jobs: managercrcrud, licensemanager, managerdeletecr, - indingsep, + indexingestionsep, ] runs-on: ubuntu-latest needs: build-operator-image-arm-rhel diff --git a/.github/workflows/arm-RHEL-int-test-workflow.yml b/.github/workflows/arm-RHEL-int-test-workflow.yml index 83c7e8fb9..d2a127ca8 100644 --- a/.github/workflows/arm-RHEL-int-test-workflow.yml +++ b/.github/workflows/arm-RHEL-int-test-workflow.yml @@ -69,7 +69,7 @@ jobs: managercrcrud, licensemanager, managerdeletecr, - indingsep, + indexingestionsep, ] runs-on: ubuntu-latest needs: build-operator-image-arm-rhel diff --git a/.github/workflows/arm-Ubuntu-build-test-push-workflow.yml b/.github/workflows/arm-Ubuntu-build-test-push-workflow.yml index 9d1be84a5..c00f8e73a 100644 --- a/.github/workflows/arm-Ubuntu-build-test-push-workflow.yml +++ b/.github/workflows/arm-Ubuntu-build-test-push-workflow.yml @@ -135,7 +135,7 @@ jobs: appframeworksS1, managersecret, managermc, - indingsep, + indexingestionsep, licensemanager, ] runs-on: ubuntu-latest diff --git a/.github/workflows/arm-Ubuntu-int-test-workflow.yml b/.github/workflows/arm-Ubuntu-int-test-workflow.yml index b3f133abe..8d138f5bb 100644 --- a/.github/workflows/arm-Ubuntu-int-test-workflow.yml +++ b/.github/workflows/arm-Ubuntu-int-test-workflow.yml @@ -69,7 +69,7 @@ jobs: managercrcrud, licensemanager, managerdeletecr, - indingsep, + indexingestionsep, ] runs-on: ubuntu-latest needs: build-operator-image-arm-ubuntu diff --git a/.github/workflows/build-test-push-workflow.yml b/.github/workflows/build-test-push-workflow.yml index c398af65c..299a61a9c 100644 --- a/.github/workflows/build-test-push-workflow.yml +++ b/.github/workflows/build-test-push-workflow.yml @@ -218,7 +218,7 @@ jobs: managerappframeworkm4, managersecret, managermc, - indingsep, + indexingestionsep, licensemanager, ] runs-on: ubuntu-latest diff --git a/.github/workflows/distroless-build-test-push-workflow.yml b/.github/workflows/distroless-build-test-push-workflow.yml index 5da0848a0..b45264645 100644 --- a/.github/workflows/distroless-build-test-push-workflow.yml +++ b/.github/workflows/distroless-build-test-push-workflow.yml @@ -194,7 +194,7 @@ jobs: managerappframeworkm4, managersecret, managermc, - indingsep, + indexingestionsep, licensemanager, ] runs-on: ubuntu-latest diff --git a/.github/workflows/distroless-int-test-workflow.yml b/.github/workflows/distroless-int-test-workflow.yml index 01a024247..5f16a8472 100644 --- a/.github/workflows/distroless-int-test-workflow.yml +++ b/.github/workflows/distroless-int-test-workflow.yml @@ -73,7 +73,7 @@ jobs: managercrcrud, licensemanager, managerdeletecr, - indingsep, + indexingestionsep, ] runs-on: ubuntu-latest needs: build-operator-image-distroless diff --git a/.github/workflows/int-test-workflow.yml b/.github/workflows/int-test-workflow.yml index 8ffc0ec0c..1e7d04f03 100644 --- a/.github/workflows/int-test-workflow.yml +++ b/.github/workflows/int-test-workflow.yml @@ -70,7 +70,7 @@ jobs: managercrcrud, licensemanager, managerdeletecr, - indingsep, + indexingestionsep, ] runs-on: ubuntu-latest needs: build-operator-image diff --git a/.github/workflows/manual-int-test-workflow.yml b/.github/workflows/manual-int-test-workflow.yml index 96629316e..0e3e5d357 100644 --- a/.github/workflows/manual-int-test-workflow.yml +++ b/.github/workflows/manual-int-test-workflow.yml @@ -29,7 +29,7 @@ jobs: managerscaling, managercrcrud, licensemanager, - indingsep, + indexingestionsep, ] runs-on: ubuntu-latest env: diff --git a/.github/workflows/namespace-scope-int-workflow.yml b/.github/workflows/namespace-scope-int-workflow.yml index fc3d3554f..640f74dc6 100644 --- a/.github/workflows/namespace-scope-int-workflow.yml +++ b/.github/workflows/namespace-scope-int-workflow.yml @@ -25,7 +25,7 @@ jobs: managerscaling, managercrcrud, licensemanager, - indingsep, + indexingestionsep, ] runs-on: ubuntu-latest env: diff --git a/.github/workflows/nightly-int-test-workflow.yml b/.github/workflows/nightly-int-test-workflow.yml index 3f886dd9a..184927f04 100644 --- a/.github/workflows/nightly-int-test-workflow.yml +++ b/.github/workflows/nightly-int-test-workflow.yml @@ -66,7 +66,7 @@ jobs: managerscaling, managercrcrud, licensemanager, - indingsep, + indexingestionsep, ] runs-on: ubuntu-latest needs: build-operator-image diff --git a/Dockerfile b/Dockerfile index 33f8a9f80..cd43c949e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,10 +2,10 @@ ARG PLATFORMS=linux/amd64,linux/arm64 ARG BASE_IMAGE=registry.access.redhat.com/ubi8/ubi-minimal -ARG BASE_IMAGE_VERSION=8.10-1775152441 +ARG BASE_IMAGE_VERSION=8.10-1776645784 # Build the manager binary -FROM golang:1.25.8 AS builder +FROM golang:1.26.2 AS builder WORKDIR /workspace diff --git a/Dockerfile.distroless b/Dockerfile.distroless index a2ac2afc0..83ce1ad65 100644 --- a/Dockerfile.distroless +++ b/Dockerfile.distroless @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.25.8 AS builder +FROM golang:1.26.2 AS builder WORKDIR /workspace # Copy the Go Modules manifests diff --git a/Makefile b/Makefile index 77b11ad51..a8e5ed31e 100644 --- a/Makefile +++ b/Makefile @@ -149,6 +149,21 @@ docs-preview: ## Preview documentation locally with Jekyll (requires Ruby and bu @cd docs && bundle exec jekyll serve --livereload @echo "Documentation available at http://localhost:4000/splunk-operator" +##@ Helm + +HELM_OPERATOR_CHART = helm-chart/splunk-operator + +.PHONY: helm-lint +helm-lint: ## Lint Helm charts + helm lint $(HELM_OPERATOR_CHART) + +.PHONY: helm-test +helm-test: setup/helm-unittest ## Run Helm chart unit tests + helm unittest $(HELM_OPERATOR_CHART) + +.PHONY: helm-check +helm-check: helm-lint helm-test ## Run Helm lint and unit tests + ##@ Build build: setup/ginkgo manifests generate fmt vet ## Build manager binary. @@ -168,12 +183,12 @@ docker-push: ## Push docker image with the manager. # Defaults: # Build Platform: linux/amd64,linux/arm64 # Build Base OS: registry.access.redhat.com/ubi8/ubi-minimal -# Build Base OS Version: 8.10-1775152441 +# Build Base OS Version: 8.10-1776645784 # Pass only what is required, the rest will be defaulted # Setup defaults for build arguments PLATFORMS ?= linux/amd64,linux/arm64 BASE_IMAGE ?= registry.access.redhat.com/ubi8/ubi-minimal -BASE_IMAGE_VERSION ?= 8.10-1775152441 +BASE_IMAGE_VERSION ?= 8.10-1776645784 docker-buildx: @if [ -z "${IMG}" ]; then \ @@ -226,6 +241,7 @@ $(LOCALBIN): KUSTOMIZE_VERSION ?= v5.4.3 CONTROLLER_TOOLS_VERSION ?= v0.18.0 GOLANGCI_LINT_VERSION ?= v2.1.0 +HELM_UNITTEST_VERSION ?= v1.0.3 CONTROLLER_GEN = $(LOCALBIN)/controller-gen controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. @@ -464,6 +480,11 @@ setup/ginkgo: @echo Installing gomega @go get github.com/onsi/gomega/... +.PHONY: setup/helm-unittest +setup/helm-unittest: + @helm plugin list 2>/dev/null | grep -q unittest || \ + helm plugin install https://github.com/helm-unittest/helm-unittest.git --version $(HELM_UNITTEST_VERSION) + .PHONY: build-installer build-installer: manifests generate kustomize mkdir -p dist diff --git a/api/v4/ingestorcluster_types.go b/api/v4/ingestorcluster_types.go index 4e206e76a..759c48818 100644 --- a/api/v4/ingestorcluster_types.go +++ b/api/v4/ingestorcluster_types.go @@ -73,7 +73,7 @@ type IngestorClusterStatus struct { // Telemetry App installation flag TelAppInstalled bool `json:"telAppInstalled"` - // Auxillary message describing CR status + // Auxiliary message describing CR status Message string `json:"message"` // Credential secret version to track changes to the secret and trigger rolling restart of indexer cluster peers when the secret is updated @@ -95,7 +95,7 @@ type IngestorClusterStatus struct { // +kubebuilder:printcolumn:name="Desired",type="integer",JSONPath=".status.replicas",description="Number of desired ingestor cluster pods" // +kubebuilder:printcolumn:name="Ready",type="integer",JSONPath=".status.readyReplicas",description="Current number of ready ingestor cluster pods" // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Age of ingestor cluster resource" -// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.message",description="Auxillary message describing CR status" +// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.message",description="Auxiliary message describing CR status" // +kubebuilder:storageversion // IngestorCluster is the Schema for the ingestorclusters API diff --git a/api/v4/objectstorage_types.go b/api/v4/objectstorage_types.go index f67f68c19..d79a93508 100644 --- a/api/v4/objectstorage_types.go +++ b/api/v4/objectstorage_types.go @@ -60,7 +60,7 @@ type ObjectStorageStatus struct { // Resource revision tracker ResourceRevMap map[string]string `json:"resourceRevMap"` - // Auxillary message describing CR status + // Auxiliary message describing CR status Message string `json:"message"` } @@ -73,7 +73,7 @@ type ObjectStorageStatus struct { // +kubebuilder:resource:path=objectstorages,scope=Namespaced,shortName=os // +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="Status of object storage" // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Age of object storage resource" -// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.message",description="Auxillary message describing CR status" +// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.message",description="Auxiliary message describing CR status" // +kubebuilder:storageversion // ObjectStorage is the Schema for the objectstorages API diff --git a/api/v4/queue_types.go b/api/v4/queue_types.go index 742e61acb..0cecf8f91 100644 --- a/api/v4/queue_types.go +++ b/api/v4/queue_types.go @@ -89,7 +89,7 @@ type QueueStatus struct { // Resource revision tracker ResourceRevMap map[string]string `json:"resourceRevMap"` - // Auxillary message describing CR status + // Auxiliary message describing CR status Message string `json:"message"` } @@ -102,7 +102,7 @@ type QueueStatus struct { // +kubebuilder:resource:path=queues,scope=Namespaced,shortName=queue // +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="Status of queue" // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Age of queue resource" -// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.message",description="Auxillary message describing CR status" +// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.message",description="Auxiliary message describing CR status" // +kubebuilder:storageversion // Queue is the Schema for the queues API diff --git a/bundle/manifests/enterprise.splunk.com_ingestorclusters.yaml b/bundle/manifests/enterprise.splunk.com_ingestorclusters.yaml index 0481e4a83..baded21b7 100644 --- a/bundle/manifests/enterprise.splunk.com_ingestorclusters.yaml +++ b/bundle/manifests/enterprise.splunk.com_ingestorclusters.yaml @@ -45,7 +45,7 @@ spec: jsonPath: .metadata.creationTimestamp name: Age type: date - - description: Auxillary message describing CR status + - description: Auxiliary message describing CR status jsonPath: .status.message name: Message type: string @@ -4630,7 +4630,7 @@ spec: is updated type: string message: - description: Auxillary message describing CR status + description: Auxiliary message describing CR status type: string phase: description: Phase of the ingestor pods diff --git a/bundle/manifests/enterprise.splunk.com_objectstorages.yaml b/bundle/manifests/enterprise.splunk.com_objectstorages.yaml index ed2e0d900..77dd3f20c 100644 --- a/bundle/manifests/enterprise.splunk.com_objectstorages.yaml +++ b/bundle/manifests/enterprise.splunk.com_objectstorages.yaml @@ -27,7 +27,7 @@ spec: jsonPath: .metadata.creationTimestamp name: Age type: date - - description: Auxillary message describing CR status + - description: Auxiliary message describing CR status jsonPath: .status.message name: Message type: string @@ -90,7 +90,7 @@ spec: description: ObjectStorageStatus defines the observed state of ObjectStorage. properties: message: - description: Auxillary message describing CR status + description: Auxiliary message describing CR status type: string phase: description: Phase of the object storage diff --git a/bundle/manifests/enterprise.splunk.com_queues.yaml b/bundle/manifests/enterprise.splunk.com_queues.yaml index 90dca1f99..02e319b12 100644 --- a/bundle/manifests/enterprise.splunk.com_queues.yaml +++ b/bundle/manifests/enterprise.splunk.com_queues.yaml @@ -27,7 +27,7 @@ spec: jsonPath: .metadata.creationTimestamp name: Age type: date - - description: Auxillary message describing CR status + - description: Auxiliary message describing CR status jsonPath: .status.message name: Message type: string @@ -139,7 +139,7 @@ spec: description: QueueStatus defines the observed state of Queue properties: message: - description: Auxillary message describing CR status + description: Auxiliary message describing CR status type: string phase: description: Phase of the queue diff --git a/cmd/main.go b/cmd/main.go index b8188608d..f1633446a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -25,6 +25,7 @@ import ( "path/filepath" "time" + "github.com/spf13/pflag" "sigs.k8s.io/controller-runtime/pkg/metrics/filters" intController "github.com/splunk/splunk-operator/internal/controller" @@ -89,24 +90,44 @@ func main() { // TLS certificate configuration for metrics var metricsCertPath, metricsCertName, metricsCertKey string - flag.StringVar(&logEncoder, "log-encoder", "json", "log encoding ('json' or 'console')") - flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") - flag.BoolVar(&enableLeaderElection, "leader-elect", false, + pflag.StringVar(&logEncoder, "log-encoder", "json", "log encoding ('json' or 'console')") + pflag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + pflag.BoolVar(&enableLeaderElection, "leader-elect", false, "Enable leader election for controller manager. "+ "Enabling this will ensure there is only one active controller manager.") - flag.BoolVar(&pprofActive, "pprof", true, "Enable pprof endpoint") - flag.IntVar(&logLevel, "log-level", int(zapcore.InfoLevel), "set log level") - flag.IntVar(&leaseDurationSecond, "lease-duration", leaseDurationSecond, "manager lease duration in seconds") - flag.IntVar(&renewDeadlineSecond, "renew-duration", renewDeadlineSecond, "manager renew duration in seconds") - flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metrics endpoint binds to. "+ + pflag.BoolVar(&pprofActive, "pprof", true, "Enable pprof endpoint") + pflag.IntVar(&logLevel, "log-level", int(zapcore.InfoLevel), "set log level") + pflag.IntVar(&leaseDurationSecond, "lease-duration", leaseDurationSecond, "manager lease duration in seconds") + pflag.IntVar(&renewDeadlineSecond, "renew-duration", renewDeadlineSecond, "manager renew duration in seconds") + pflag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metrics endpoint binds to. "+ "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") - flag.BoolVar(&secureMetrics, "metrics-secure", false, + pflag.BoolVar(&secureMetrics, "metrics-secure", false, "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.") // TLS certificate flags for metrics server - flag.StringVar(&metricsCertPath, "metrics-cert-path", "", "The directory that contains the metrics server certificate.") - flag.StringVar(&metricsCertName, "metrics-cert-name", "tls.crt", "The name of the metrics server certificate file.") - flag.StringVar(&metricsCertKey, "metrics-cert-key", "tls.key", "The name of the metrics server key file.") + pflag.StringVar(&metricsCertPath, "metrics-cert-path", "", "The directory that contains the metrics server certificate.") + pflag.StringVar(&metricsCertName, "metrics-cert-name", "tls.crt", "The name of the metrics server certificate file.") + pflag.StringVar(&metricsCertKey, "metrics-cert-key", "tls.key", "The name of the metrics server key file.") + + config.DefaultMutableFeatureGate.AddFlag(pflag.CommandLine) + + opts := zap.Options{ + Development: true, + TimeEncoder: zapcore.RFC3339NanoTimeEncoder, + } + opts.BindFlags(flag.CommandLine) + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + if allGates := config.DefaultMutableFeatureGate.GetAll(); len(allGates) > 0 { + effectiveStates := make(map[string]bool, len(allGates)) + for gate := range allGates { + effectiveStates[string(gate)] = config.DefaultMutableFeatureGate.Enabled(gate) + } + setupLog.Info("Feature gates initialized", "gates", effectiveStates) + } // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server. // More info: @@ -147,16 +168,6 @@ func main() { renewDeadline = time.Duration(renewDeadlineSecond) * time.Second } - opts := zap.Options{ - Development: true, - TimeEncoder: zapcore.RFC3339NanoTimeEncoder, - } - opts.BindFlags(flag.CommandLine) - flag.Parse() - - // Logging setup - ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) - // Configure metrics certificate watcher if metrics certs are provided var metricsCertWatcher *certwatcher.CertWatcher if len(metricsCertPath) > 0 { @@ -280,10 +291,11 @@ func main() { os.Exit(1) } - // Setup centralized validation webhook server (opt-in via ENABLE_VALIDATION_WEBHOOK env var, defaults to false) - enableWebhooks := os.Getenv("ENABLE_VALIDATION_WEBHOOK") - if enableWebhooks == "true" { - // Parse optional timeout configurations from environment + if _, ok := os.LookupEnv("ENABLE_VALIDATION_WEBHOOK"); ok { + setupLog.Info("DEPRECATED: ENABLE_VALIDATION_WEBHOOK env var is deprecated and will be removed in a future release; use --feature-gates=ValidationWebhook=true instead") + } + + if config.DefaultMutableFeatureGate.Enabled(config.ValidationWebhook) { readTimeout := 10 * time.Second if val := os.Getenv("WEBHOOK_READ_TIMEOUT"); val != "" { if d, err := time.ParseDuration(val); err == nil { @@ -306,16 +318,15 @@ func main() { Client: mgr.GetClient(), }) - // Add webhook server as a runnable to the manager if err := mgr.Add(manager.RunnableFunc(func(ctx context.Context) error { return webhookServer.Start(ctx) })); err != nil { setupLog.Error(err, "unable to add webhook server to manager") os.Exit(1) } - setupLog.Info("Validation webhook enabled via ENABLE_VALIDATION_WEBHOOK=true") + setupLog.Info("Validation webhook enabled") } else { - setupLog.Info("Validation webhook disabled (set ENABLE_VALIDATION_WEBHOOK=true to enable)") + setupLog.Info("Validation webhook disabled (set --feature-gates=ValidationWebhook=true to enable)") } //+kubebuilder:scaffold:builder diff --git a/config/crd/bases/enterprise.splunk.com_ingestorclusters.yaml b/config/crd/bases/enterprise.splunk.com_ingestorclusters.yaml index 44238ca7a..5ce5c63cf 100644 --- a/config/crd/bases/enterprise.splunk.com_ingestorclusters.yaml +++ b/config/crd/bases/enterprise.splunk.com_ingestorclusters.yaml @@ -33,7 +33,7 @@ spec: jsonPath: .metadata.creationTimestamp name: Age type: date - - description: Auxillary message describing CR status + - description: Auxiliary message describing CR status jsonPath: .status.message name: Message type: string @@ -4707,7 +4707,7 @@ spec: is updated type: string message: - description: Auxillary message describing CR status + description: Auxiliary message describing CR status type: string phase: description: Phase of the ingestor pods diff --git a/config/crd/bases/enterprise.splunk.com_objectstorages.yaml b/config/crd/bases/enterprise.splunk.com_objectstorages.yaml index b2ae90755..438752751 100644 --- a/config/crd/bases/enterprise.splunk.com_objectstorages.yaml +++ b/config/crd/bases/enterprise.splunk.com_objectstorages.yaml @@ -25,7 +25,7 @@ spec: jsonPath: .metadata.creationTimestamp name: Age type: date - - description: Auxillary message describing CR status + - description: Auxiliary message describing CR status jsonPath: .status.message name: Message type: string @@ -88,7 +88,7 @@ spec: description: ObjectStorageStatus defines the observed state of ObjectStorage. properties: message: - description: Auxillary message describing CR status + description: Auxiliary message describing CR status type: string phase: description: Phase of the object storage diff --git a/config/crd/bases/enterprise.splunk.com_queues.yaml b/config/crd/bases/enterprise.splunk.com_queues.yaml index ec848987a..875e679b4 100644 --- a/config/crd/bases/enterprise.splunk.com_queues.yaml +++ b/config/crd/bases/enterprise.splunk.com_queues.yaml @@ -25,7 +25,7 @@ spec: jsonPath: .metadata.creationTimestamp name: Age type: date - - description: Auxillary message describing CR status + - description: Auxiliary message describing CR status jsonPath: .status.message name: Message type: string @@ -123,7 +123,7 @@ spec: description: QueueStatus defines the observed state of Queue properties: message: - description: Auxillary message describing CR status + description: Auxiliary message describing CR status type: string phase: description: Phase of the queue diff --git a/config/default-with-webhook/kustomization-cluster.yaml b/config/default-with-webhook/kustomization-cluster.yaml index c596f0c68..f4ddabdb2 100644 --- a/config/default-with-webhook/kustomization-cluster.yaml +++ b/config/default-with-webhook/kustomization-cluster.yaml @@ -1,7 +1,7 @@ # Adds namespace to all resources. # Cluster-scoped deployment WITH webhook enabled (opt-in) # Requires cert-manager to be installed in the cluster -namespace: splunk-operator +namespace: splunk-operator # Value of this field is prepended to the # names of all resources, e.g. a deployment named @@ -115,7 +115,7 @@ patches: patch: |- - op: add path: /spec/template/spec/containers/0/env - value: + value: - name: WATCH_NAMESPACE value: WATCH_NAMESPACE_VALUE - name: RELATED_IMAGE_SPLUNK_ENTERPRISE @@ -124,12 +124,13 @@ patches: value: splunk-operator - name: SPLUNK_GENERAL_TERMS value: SPLUNK_GENERAL_TERMS_VALUE - - name: ENABLE_VALIDATION_WEBHOOK - value: "true" - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name + - op: add + path: /spec/template/spec/containers/0/args/- + value: --feature-gates=ValidationWebhook=true # [METRICS] The following patch will enable the metrics endpoint using HTTPS and the port :8443. # More info: https://book.kubebuilder.io/reference/metrics - path: manager_metrics_patch.yaml diff --git a/config/default-with-webhook/kustomization-namespace.yaml b/config/default-with-webhook/kustomization-namespace.yaml index 193791601..2bc1845c6 100644 --- a/config/default-with-webhook/kustomization-namespace.yaml +++ b/config/default-with-webhook/kustomization-namespace.yaml @@ -1,7 +1,7 @@ # Adds namespace to all resources. # Namespace-scoped deployment WITH webhook enabled (opt-in) # Requires cert-manager to be installed in the cluster -namespace: splunk-operator +namespace: splunk-operator # Value of this field is prepended to the # names of all resources, e.g. a deployment named @@ -115,7 +115,7 @@ patches: patch: |- - op: add path: /spec/template/spec/containers/0/env - value: + value: - name: WATCH_NAMESPACE valueFrom: fieldRef: @@ -126,12 +126,13 @@ patches: value: splunk-operator - name: SPLUNK_GENERAL_TERMS value: SPLUNK_GENERAL_TERMS_VALUE - - name: ENABLE_VALIDATION_WEBHOOK - value: "true" - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name + - op: add + path: /spec/template/spec/containers/0/args/- + value: --feature-gates=ValidationWebhook=true # [METRICS] The following patch will enable the metrics endpoint using HTTPS and the port :8443. # More info: https://book.kubebuilder.io/reference/metrics - path: manager_metrics_patch.yaml diff --git a/config/default-with-webhook/kustomization.yaml b/config/default-with-webhook/kustomization.yaml index 5ba87fec1..f4ddabdb2 100644 --- a/config/default-with-webhook/kustomization.yaml +++ b/config/default-with-webhook/kustomization.yaml @@ -1,7 +1,7 @@ # Adds namespace to all resources. # Cluster-scoped deployment WITH webhook enabled (opt-in) # Requires cert-manager to be installed in the cluster -namespace: splunk-operator +namespace: splunk-operator # Value of this field is prepended to the # names of all resources, e.g. a deployment named @@ -115,7 +115,7 @@ patches: patch: |- - op: add path: /spec/template/spec/containers/0/env - value: + value: - name: WATCH_NAMESPACE value: WATCH_NAMESPACE_VALUE - name: RELATED_IMAGE_SPLUNK_ENTERPRISE @@ -123,13 +123,14 @@ patches: - name: OPERATOR_NAME value: splunk-operator - name: SPLUNK_GENERAL_TERMS - value: WATCH_NAMESPACE_VALUE - - name: ENABLE_VALIDATION_WEBHOOK - value: "true" + value: SPLUNK_GENERAL_TERMS_VALUE - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name + - op: add + path: /spec/template/spec/containers/0/args/- + value: --feature-gates=ValidationWebhook=true # [METRICS] The following patch will enable the metrics endpoint using HTTPS and the port :8443. # More info: https://book.kubebuilder.io/reference/metrics - path: manager_metrics_patch.yaml diff --git a/docs/FeatureGates.md b/docs/FeatureGates.md new file mode 100644 index 000000000..f64b83b5f --- /dev/null +++ b/docs/FeatureGates.md @@ -0,0 +1,137 @@ +--- +title: Feature Gates +parent: Reference +nav_order: 7 +--- + +# Feature Gates + +The Splunk Operator uses the Kubernetes [FeatureGate](https://pkg.go.dev/k8s.io/component-base/featuregate) pattern to control rollout of new functionality. Feature gates allow new code to be merged to the main branch without activating in production, giving teams a safe, per-environment opt-in mechanism. + +## Usage + +### Helm Chart + +Set feature gates via the `splunkOperator.featureGates` map in your values file: + +```yaml +splunkOperator: + featureGates: + ValidationWebhook: true +``` + +Or pass them on the command line: + +```bash +helm install splunk-operator splunk/splunk-operator \ + --set splunkOperator.featureGates.ValidationWebhook=true +``` + +The chart formats the map into a single `--feature-gates=Key1=true,Key2=false` argument automatically. Adding a new gate requires no chart changes — just add an entry to the map. + +### Direct Binary + +When running the operator binary directly, pass feature gates at startup: + +```bash +/manager --feature-gates=ValidationWebhook=true +``` + +## Maturity Lifecycle + +| Stage | Default | Can Override | Next Step | +|-----------|---------|-------------|-----------------------------------------| +| **Alpha** | off | Yes | Promote to Beta after validation | +| **Beta** | on | Yes | Promote to GA after sustained stability | +| **GA** | on | No | Remove gate in a future release | + +## Current Feature Gates + +| Gate | Default | Stage | Since | Description | +|-----------------------|---------|-------|---------|----------------------------------------------------------| +| `ValidationWebhook` | `false` | Alpha | v3.2.0 | Centralized validation webhook server for CR admission | + +## Adding a New Feature Gate + +Follow these steps: + +### 1. Register the gate in `pkg/config/featuregates.go` + +Add a constant and an entry in `defaultFeatureGates`: + +```go +const ( + MyNewFeature featuregate.Feature = "MyNewFeature" +) + +var defaultFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{ + // existing gates … + MyNewFeature: {Default: false, PreRelease: featuregate.Alpha}, +} +``` + +### 2. Guard the code path + +Check the gate wherever the feature-specific logic runs: + +```go +if config.DefaultMutableFeatureGate.Enabled(config.MyNewFeature) { + // feature-specific logic +} +``` + +This can guard anything — a reconciler code path, a helper function, a webhook handler, an HTTP endpoint, etc. + +### Example: Gating a New Controller (CRD) + +When the feature gate introduces an entirely new CRD and controller, there are additional steps beyond the basic gate check. All three steps below are **mandatory** for any new CRD behind a feature gate. + +#### a. Gate controller registration in `cmd/main.go` + +Wrap the `SetupWithManager` call so the controller only starts when the gate is on: + +```go +if config.DefaultMutableFeatureGate.Enabled(config.MyNewFeature) { + if err = (&controller.MyNewReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "MyNew") + os.Exit(1) + } +} +``` + +#### b. Add a validating webhook for the gated CRD group + +A validating webhook **must** reject CR creation when the gate is off. Without this, users can create resources that no controller will reconcile, leading to silent failures: + +```go +func (v *MyNewValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + if !config.DefaultMutableFeatureGate.Enabled(config.MyNewFeature) { + return nil, fmt.Errorf( + "the MyNewFeature feature is not enabled; "+ + "set --feature-gates=MyNewFeature=true to activate") + } + return nil, nil +} +``` + +#### c. Label the CRD manifests + +Every gated CRD **must** carry maturity annotations and labels in `config/crd/bases/`. These signal to operators and tooling which gate controls the CRD and its current stability level: + +```yaml +metadata: + annotations: + splunk.com/feature-gate: MyNewFeature + splunk.com/feature-stage: Alpha + labels: + splunk.com/feature-stage: alpha +``` + +## Promoting a Gate + +- **Alpha → Beta**: Change `Default: false` to `Default: true` in `featuregates.go`; update the CRD label to `beta` +- **Beta → GA**: Set `LockToDefault: true` in the `FeatureSpec`; update the CRD label to `ga` +- **GA → Removed**: Delete the constant and `FeatureSpec` entry; remove the `if` guard in `cmd/main.go`; remove the CRD annotations/labels and the validating webhook diff --git a/docs/ValidationWebhook.md b/docs/ValidationWebhook.md index a3ae4c2de..92db9c0f5 100644 --- a/docs/ValidationWebhook.md +++ b/docs/ValidationWebhook.md @@ -83,27 +83,48 @@ If you prefer not to use cert-manager, you can provide your own TLS certificates ### Deployment Options -#### Option 1: Use the Webhook-Enabled Kustomize Overlay +#### Option 1: Enable via Helm Feature Gates -Deploy using the `config/default-with-webhook` overlay which includes all necessary webhook components: +If deploying with Helm, enable the feature gate through the `splunkOperator.featureGates` value: ```bash -# Build and apply the webhook-enabled configuration -kustomize build config/default-with-webhook | kubectl apply -f - +helm install splunk-operator splunk/splunk-operator \ + --set splunkOperator.featureGates.ValidationWebhook=true ``` -#### Option 2: Enable Webhook on Existing Deployment +Or in your values file: -If you already have the operator deployed, you can enable the webhook by setting the `ENABLE_VALIDATION_WEBHOOK` environment variable: +```yaml +splunkOperator: + featureGates: + ValidationWebhook: true +``` + +**Note:** This requires the webhook Kubernetes resources (Service, ValidatingWebhookConfiguration, TLS certificates) to be deployed separately. + +#### Option 2: Use the Webhook-Enabled Kustomize Overlay + +Deploy using the `config/default-with-webhook` overlay which includes all necessary webhook components and enables the `ValidationWebhook` feature gate automatically: ```bash -kubectl set env deployment/splunk-operator-controller-manager \ - ENABLE_VALIDATION_WEBHOOK=true -n splunk-operator +make deploy IMG= ENVIRONMENT=default-with-webhook \ + SPLUNK_GENERAL_TERMS="--accept-sgt-current-at-splunk-com" ``` -**Note:** This option also requires the webhook service, ValidatingWebhookConfiguration, and TLS certificates to be deployed. Use Option 1 for a complete deployment. +This uses the same `make deploy` target as the standard deployment, which substitutes the `WATCH_NAMESPACE`, `SPLUNK_ENTERPRISE_IMAGE`, and `SPLUNK_GENERAL_TERMS` placeholder values before running `kustomize build`. + +#### Option 3: Enable via Feature Gate on Existing Deployment + +If you already have the operator deployed with the webhook Kubernetes resources (Service, ValidatingWebhookConfiguration, TLS certificates), enable the feature gate by patching the container args: + +```bash +kubectl patch deployment splunk-operator-controller-manager -n splunk-operator \ + --type='json' -p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--feature-gates=ValidationWebhook=true"}]' +``` -#### Option 3: Modify Default Kustomization +**Note:** This requires the webhook service, ValidatingWebhookConfiguration, and TLS certificates to already be deployed. Use Option 1 for a complete deployment. + +#### Option 4: Modify Default Kustomization Edit `config/default/kustomization.yaml` to uncomment the webhook-related sections: @@ -119,6 +140,14 @@ Then deploy: make deploy IMG= SPLUNK_GENERAL_TERMS="--accept-sgt-current-at-splunk-com" ``` +### Legacy: ENABLE_VALIDATION_WEBHOOK Environment Variable + +> **Deprecated:** The `ENABLE_VALIDATION_WEBHOOK` environment variable is deprecated and will be removed in a future release. Use the `--feature-gates=ValidationWebhook=true` flag instead. + +For backwards compatibility, setting `ENABLE_VALIDATION_WEBHOOK=true` as an environment variable on the operator container will still enable the validation webhook. The operator logs a deprecation warning when this method is used. + +When both the `--feature-gates=ValidationWebhook=...` CLI flag and the `ENABLE_VALIDATION_WEBHOOK` env var are set, the **CLI flag takes precedence**. The env var is applied at startup before flag parsing, so the CLI value overwrites it. + ## Validated Fields The webhook validates the following spec fields: @@ -290,7 +319,7 @@ kubectl get validatingwebhookconfiguration splunk-operator-validating-webhook-co ```bash kubectl logs -n splunk-operator deployment/splunk-operator-controller-manager | grep -i webhook -# Look for: "Validation webhook enabled via ENABLE_VALIDATION_WEBHOOK=true" +# Look for: "Validation webhook enabled" # Look for: "Starting webhook server" {"port": 9443} ``` @@ -362,7 +391,7 @@ kubectl logs -n splunk-operator deployment/splunk-operator-controller-manager | If you see "Validation webhook disabled" in the logs, ensure: -1. The `ENABLE_VALIDATION_WEBHOOK` environment variable is set to `true` +1. The `--feature-gates=ValidationWebhook=true` flag is set on the operator container args (or the legacy `ENABLE_VALIDATION_WEBHOOK=true` env var is set) 2. You're using the correct kustomize overlay (`config/default-with-webhook`) ## Architecture @@ -457,7 +486,7 @@ var GVR = schema.GroupVersionResource{ // Add to DefaultValidators map var DefaultValidators = map[schema.GroupVersionResource]Validator{ // ... existing validators ... - + GVR: &GenericValidator[*enterpriseApi.]{ ValidateCreateFunc: ValidateCreate, ValidateUpdateFunc: ValidateUpdate, @@ -503,12 +532,7 @@ If your CRD doesn't need context-aware validation, you can omit `ValidateCreateW ## Disabling the Webhook -To disable the webhook after it has been enabled: - -```bash -kubectl set env deployment/splunk-operator-controller-manager \ - ENABLE_VALIDATION_WEBHOOK=false -n splunk-operator -``` +To disable the webhook after it has been enabled, remove the `--feature-gates=ValidationWebhook=true` flag from the container args (or remove the `ENABLE_VALIDATION_WEBHOOK` env var if using the legacy method). Or redeploy using the default kustomization (without webhook): diff --git a/docs/index.yaml b/docs/index.yaml index 47385faef..8b4f5919a 100644 --- a/docs/index.yaml +++ b/docs/index.yaml @@ -55,6 +55,34 @@ entries: urls: - https://splunk.github.io/splunk-operator/splunk-enterprise-3.1.0.tgz version: 3.1.0 + - apiVersion: v2 + appVersion: 3.0.0 + created: "2026-04-08T03:35:00Z" + dependencies: + - condition: splunk-operator.enabled + name: splunk-operator + repository: file://splunk-operator/helm-chart/splunk-operator + version: 3.0.0 + description: A Helm chart for Splunk Enterprise managed by the Splunk Operator + digest: ae82f6c8edee4d827817fe6c9c6447c422a03c59595a0f6e779cef847a83b611 + maintainers: + - email: vivekr@splunk.com + name: Vivek Reddy + - email: rlieberman@splunk.com + name: Raizel Lieberman + - email: patrykw@splunk.com + name: Patryk Wasielewski + - email: igorg@splunk.com + name: Igor Grzankowski + - email: kkoziol@splunk.com + name: Kasia Kozioł + - email: jbuczak@splunk.com + name: Jakub Buczak + name: splunk-enterprise + type: application + urls: + - https://splunk.github.io/splunk-operator/splunk-enterprise-3.0.0.tgz + version: 3.0.0 - apiVersion: v2 appVersion: 2.8.1 created: "2026-03-02T17:02:33.789329656Z" @@ -381,6 +409,29 @@ entries: urls: - https://splunk.github.io/splunk-operator/splunk-operator-3.1.0.tgz version: 3.1.0 + - apiVersion: v2 + appVersion: 3.0.0 + created: "2026-04-08T03:35:00Z" + description: A Helm chart for the Splunk Operator for Kubernetes + digest: bd318b1f4022421a3fd429b186ca344c61d04a3c2bbdd5cc535d960773558e44 + maintainers: + - email: vivekr@splunk.com + name: Vivek Reddy + - email: rlieberman@splunk.com + name: Raizel Lieberman + - email: patrykw@splunk.com + name: Patryk Wasielewski + - email: igorg@splunk.com + name: Igor Grzankowski + - email: kkoziol@splunk.com + name: Kasia Kozioł + - email: jbuczak@splunk.com + name: Jakub Buczak + name: splunk-operator + type: application + urls: + - https://splunk.github.io/splunk-operator/splunk-operator-3.0.0.tgz + version: 3.0.0 - apiVersion: v2 appVersion: 2.8.1 created: "2026-03-02T17:02:33.967789812Z" diff --git a/go.mod b/go.mod index 8b5adb30c..09bb99c70 100644 --- a/go.mod +++ b/go.mod @@ -1,17 +1,17 @@ module github.com/splunk/splunk-operator -go 1.25.8 +go 1.26.2 require ( cloud.google.com/go/storage v1.36.0 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1 - github.com/aws/aws-sdk-go-v2 v1.41.1 + github.com/aws/aws-sdk-go-v2 v1.41.5 github.com/aws/aws-sdk-go-v2/config v1.29.18 github.com/aws/aws-sdk-go-v2/credentials v1.17.71 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.85 - github.com/aws/aws-sdk-go-v2/service/s3 v1.84.1 + github.com/aws/aws-sdk-go-v2/service/s3 v1.99.0 github.com/aws/aws-sdk-go-v2/service/sqs v1.42.21 github.com/go-logr/logr v1.4.3 github.com/google/go-cmp v0.7.0 @@ -23,6 +23,7 @@ require ( github.com/onsi/gomega v1.39.1 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.22.0 + github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.11.1 github.com/wk8/go-ordered-map/v2 v2.1.7 go.uber.org/zap v1.27.0 @@ -31,6 +32,7 @@ require ( k8s.io/apiextensions-apiserver v0.33.0 k8s.io/apimachinery v0.33.0 k8s.io/client-go v0.33.0 + k8s.io/component-base v0.33.0 k8s.io/kubectl v0.26.2 sigs.k8s.io/controller-runtime v0.21.0 ) @@ -44,20 +46,20 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.33 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.37 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.5 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.18 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.18 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.25.6 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.4 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.34.1 // indirect - github.com/aws/smithy-go v1.24.0 // indirect + github.com/aws/smithy-go v1.24.2 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect @@ -100,7 +102,7 @@ require ( github.com/minio/md5-simd v1.1.0 // indirect github.com/minio/sha256-simd v0.1.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/moby/spdystream v0.5.0 // indirect + github.com/moby/spdystream v0.5.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect @@ -113,7 +115,6 @@ require ( github.com/rs/xid v1.2.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/cobra v1.8.1 // indirect - github.com/spf13/pflag v1.0.5 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/x448/float16 v0.8.4 // indirect @@ -121,12 +122,12 @@ require ( go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect - go.opentelemetry.io/otel v1.40.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 // indirect - go.opentelemetry.io/otel/metric v1.40.0 // indirect - go.opentelemetry.io/otel/sdk v1.40.0 // indirect - go.opentelemetry.io/otel/trace v1.40.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/sdk v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect @@ -136,7 +137,7 @@ require ( golang.org/x/net v0.49.0 // indirect golang.org/x/oauth2 v0.34.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.42.0 // indirect golang.org/x/term v0.39.0 // indirect golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.9.0 // indirect @@ -152,7 +153,6 @@ require ( gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiserver v0.33.0 // indirect - k8s.io/component-base v0.33.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect diff --git a/go.sum b/go.sum index a0d78e0ef..84e85db91 100644 --- a/go.sum +++ b/go.sum @@ -28,10 +28,10 @@ github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8 github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU= -github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 h1:12SpdwU8Djs+YGklkinSSlcrPyj3H4VifVsKf78KbwA= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11/go.mod h1:dd+Lkp6YmMryke+qxW/VnKyhMBDTYP41Q2Bb+6gNZgY= +github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY= +github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 h1:eBMB84YGghSocM7PsjmmPffTa+1FBUeNvGvFou6V/4o= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI= github.com/aws/aws-sdk-go-v2/config v1.29.18 h1:x4T1GRPnqKV8HMJOMtNktbpQMl3bIsfx8KbqmveUO2I= github.com/aws/aws-sdk-go-v2/config v1.29.18/go.mod h1:bvz8oXugIsH8K7HLhBv06vDqnFv3NsGDt2Znpk7zmOU= github.com/aws/aws-sdk-go-v2/credentials v1.17.71 h1:r2w4mQWnrTMJjOyIsZtGp3R3XGY3nqHn8C26C2lQWgA= @@ -40,24 +40,24 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.33 h1:D9ixiWSG4lyUBL2DDNK924 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.33/go.mod h1:caS/m4DI+cij2paz3rtProRBI4s/+TCiWoaWZuQ9010= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.85 h1:AfpstoiaenxGSCUheWiicgZE5XXS5Fi4CcQ4PA/x+Qw= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.85/go.mod h1:HxiF0Fd6WHWjdjOffLkCauq7JqzWqMMq0iUVLS7cPQc= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi9OnXWwcE0a2vGpbwmtICOsvcf4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 h1:PEgGVtPoB6NTpPrBgqSE5hE/o47Ij9qk/SEZFbUOe9A= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.37 h1:XTZZ0I3SZUHAtBLBU6395ad+VOblE0DwQP6MuaNeics= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.37/go.mod h1:Pi6ksbniAWVwu2S8pEzcYPyhUkAcLaufxN7PfAUQjBk= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.5 h1:M5/B8JUaCI8+9QD+u3S/f4YHpvqE9RpSkV3rf0Iks2w= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.5/go.mod h1:Bktzci1bwdbpuLiu3AOksiNPMl/LLKmX1TWmqp2xbvs= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.18 h1:vvbXsA2TVO80/KT7ZqCbx934dt6PY+vQ8hZpUZ/cpYg= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.18/go.mod h1:m2JJHledjBGNMsLOF1g9gbAxprzq3KjC8e4lxtn+eWg= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.18 h1:OS2e0SKqsU2LiJPqL8u9x41tKc6MMEHrWjLVLn3oysg= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.18/go.mod h1:+Yrk+MDGzlNGxCXieljNeWpoZTCQUQVL+Jk9hGGJ8qM= -github.com/aws/aws-sdk-go-v2/service/s3 v1.84.1 h1:RkHXU9jP0DptGy7qKI8CBGsUJruWz0v5IgwBa2DwWcU= -github.com/aws/aws-sdk-go-v2/service/s3 v1.84.1/go.mod h1:3xAOf7tdKF+qbb+XpU+EPhNXAdun3Lu1RcDrj8KC24I= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22 h1:rWyie/PxDRIdhNf4DzRk0lvjVOqFJuNnO8WwaIRVxzQ= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22/go.mod h1:zd/JsJ4P7oGfUhXn1VyLqaRZwPmZwg44Jf2dS84Dm3Y= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13 h1:JRaIgADQS/U6uXDqlPiefP32yXTda7Kqfx+LgspooZM= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13/go.mod h1:CEuVn5WqOMilYl+tbccq8+N2ieCy0gVn3OtRb0vBNNM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 h1:c31//R3xgIJMSC8S6hEVq+38DcvUlgFY0FM6mSI5oto= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21/go.mod h1:r6+pf23ouCB718FUxaqzZdbpYFyDtehyZcmP5KL9FkA= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21 h1:ZlvrNcHSFFWURB8avufQq9gFsheUgjVD9536obIknfM= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21/go.mod h1:cv3TNhVrssKR0O/xxLJVRfd2oazSnZnkUeTf6ctUwfQ= +github.com/aws/aws-sdk-go-v2/service/s3 v1.99.0 h1:hlSuz394kV0vhv9drL5lhuEFbEOEP1VyQpy15qWh1Pk= +github.com/aws/aws-sdk-go-v2/service/s3 v1.99.0/go.mod h1:uoA43SdFwacedBfSgfFSjjCvYe8aYBS7EnU5GZ/YKMM= github.com/aws/aws-sdk-go-v2/service/sqs v1.42.21 h1:Oa0IhwDLVrcBHDlNo1aosG4CxO4HyvzDV5xUWqWcBc0= github.com/aws/aws-sdk-go-v2/service/sqs v1.42.21/go.mod h1:t98Ssq+qtXKXl2SFtaSkuT6X42FSM//fnO6sfq5RqGM= github.com/aws/aws-sdk-go-v2/service/sso v1.25.6 h1:rGtWqkQbPk7Bkwuv3NzpE/scwwL9sC1Ul3tn9x83DUI= @@ -66,8 +66,8 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.4 h1:OV/pxyXh+eMA0TExHEC4jyWd github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.4/go.mod h1:8Mm5VGYwtm+r305FfPSuc+aFkrypeylGYhFim6XEPoc= github.com/aws/aws-sdk-go-v2/service/sts v1.34.1 h1:aUrLQwJfZtwv3/ZNG2xRtEen+NqI3iesuacjP51Mv1s= github.com/aws/aws-sdk-go-v2/service/sts v1.34.1/go.mod h1:3wFBZKoWnX3r+Sm7in79i54fBmNfwhdNdQuscCw7QIk= -github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= -github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= +github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng= +github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -246,8 +246,8 @@ github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKU github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= -github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/moby/spdystream v0.5.1 h1:9sNYeYZUcci9R6/w7KDaFWEWeV4LStVG78Mpyq/Zm/Y= +github.com/moby/spdystream v0.5.1/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -343,20 +343,20 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.5 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0/go.mod h1:HDBUsEjOuRC0EzKZ1bSaRGZWUBAzo+MhAcUUORSr4D0= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= -go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= -go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0/go.mod h1:EtekO9DEJb4/jRyN4v4Qjc2yA7AtfCBuz2FynRUWTXs= -go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= -go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= -go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= -go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= -go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= -go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= -go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= -go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -421,8 +421,8 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= diff --git a/helm-chart/splunk-enterprise/templates/enterprise_v4_ingestorcluster.yaml b/helm-chart/splunk-enterprise/templates/enterprise_v4_ingestorcluster.yaml index e5ab1258c..49a736523 100644 --- a/helm-chart/splunk-enterprise/templates/enterprise_v4_ingestorcluster.yaml +++ b/helm-chart/splunk-enterprise/templates/enterprise_v4_ingestorcluster.yaml @@ -1,3 +1,4 @@ +{{- if .Values.ingestorCluster }} {{- if .Values.ingestorCluster.enabled }} apiVersion: enterprise.splunk.com/v4 kind: IngestorCluster @@ -134,4 +135,5 @@ spec: {{- if .Values.ingestorCluster.defaultsUrlApps }} defaultsUrlApps: {{ .Values.ingestorCluster.defaultsUrlApps }} {{- end }} +{{- end }} {{- end }} \ No newline at end of file diff --git a/helm-chart/splunk-operator/templates/_helpers.tpl b/helm-chart/splunk-operator/templates/_helpers.tpl index ca59acf2e..9ab37b028 100644 --- a/helm-chart/splunk-operator/templates/_helpers.tpl +++ b/helm-chart/splunk-operator/templates/_helpers.tpl @@ -72,3 +72,15 @@ Define namespace of release and allow for namespace override {{- default .Release.Namespace .Values.namespaceOverride }} {{- end }} +{{/* +Format splunkOperator.featureGates map into a --feature-gates arg value. +Produces: Key1=true,Key2=false +*/}} +{{- define "splunk-operator.featureGates" -}} +{{- $pairs := list -}} +{{- range $gate, $enabled := .Values.splunkOperator.featureGates -}} +{{- $pairs = append $pairs (printf "%s=%t" $gate $enabled) -}} +{{- end -}} +{{- join "," $pairs -}} +{{- end }} + diff --git a/helm-chart/splunk-operator/templates/deployment.yaml b/helm-chart/splunk-operator/templates/deployment.yaml index 81b8afc33..ff177e71e 100644 --- a/helm-chart/splunk-operator/templates/deployment.yaml +++ b/helm-chart/splunk-operator/templates/deployment.yaml @@ -48,6 +48,9 @@ spec: args: - --leader-elect - --pprof +{{- if .Values.splunkOperator.featureGates }} + - --feature-gates={{ include "splunk-operator.featureGates" . }} +{{- end }} command: - /manager {{- with .Values.splunkOperator.livenessProbe }} @@ -78,7 +81,7 @@ spec: - name: SPLUNK_GENERAL_TERMS value: {{ .Values.splunkOperator.splunkGeneralTerms | default "" }} {{- with .Values.extraEnvs }} -{{- toYaml . | trim | nindent 10 }} +{{- toYaml . | trim | nindent 12 }} {{- end }} ports: {{- range .Values.splunkOperator.service.ports }} diff --git a/helm-chart/splunk-operator/tests/deployment_test.yaml b/helm-chart/splunk-operator/tests/deployment_test.yaml new file mode 100644 index 000000000..44c8bdb35 --- /dev/null +++ b/helm-chart/splunk-operator/tests/deployment_test.yaml @@ -0,0 +1,185 @@ +suite: deployment +templates: + - templates/deployment.yaml +tests: + - it: should be a Deployment + asserts: + - isKind: + of: Deployment + + - it: should set the correct name + asserts: + - equal: + path: metadata.name + value: splunk-operator-controller-manager + + - it: should use Recreate strategy + asserts: + - equal: + path: spec.strategy.type + value: Recreate + + - it: should include default args without feature-gates + asserts: + - equal: + path: spec.template.spec.containers[0].args + value: + - --leader-elect + - --pprof + + - it: should include feature-gates arg with a single gate + set: + splunkOperator.featureGates: + ValidationWebhook: true + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: --feature-gates=ValidationWebhook=true + + - it: should include feature-gates arg with multiple gates + set: + splunkOperator.featureGates: + ValidationWebhook: true + MyNewFeature: false + asserts: + - matchRegex: + path: spec.template.spec.containers[0].args[2] + pattern: "^--feature-gates=" + - matchRegex: + path: spec.template.spec.containers[0].args[2] + pattern: "ValidationWebhook=true" + - matchRegex: + path: spec.template.spec.containers[0].args[2] + pattern: "MyNewFeature=false" + + - it: should not include feature-gates arg when featureGates is empty + set: + splunkOperator.featureGates: {} + asserts: + - equal: + path: spec.template.spec.containers[0].args + value: + - --leader-elect + - --pprof + + - it: should always include --leader-elect and --pprof even with feature gates + set: + splunkOperator.featureGates: + ValidationWebhook: true + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: --leader-elect + - contains: + path: spec.template.spec.containers[0].args + content: --pprof + + - it: should set the command to /manager + asserts: + - equal: + path: spec.template.spec.containers[0].command + value: + - /manager + + - it: should use the configured image + set: + splunkOperator.image.repository: my-registry/splunk-operator:test + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: my-registry/splunk-operator:test + + - it: should set WATCH_NAMESPACE to watchNamespaces when clusterWideAccess is true + set: + splunkOperator.clusterWideAccess: true + splunkOperator.watchNamespaces: "ns1,ns2" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: WATCH_NAMESPACE + value: "ns1,ns2" + + - it: should set WATCH_NAMESPACE to release namespace when clusterWideAccess is false + release: + namespace: my-namespace + set: + splunkOperator.clusterWideAccess: false + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: WATCH_NAMESPACE + value: my-namespace + + - it: should add custom labels to deployment + set: + splunkOperator.labels: + custom-label: custom-value + asserts: + - equal: + path: metadata.labels.custom-label + value: custom-value + + - it: should add custom annotations to deployment + set: + splunkOperator.annotations: + custom-annotation: custom-value + asserts: + - equal: + path: metadata.annotations.custom-annotation + value: custom-value + + - it: should add pod labels + set: + splunkOperator.podLabels: + pod-label: pod-value + asserts: + - equal: + path: spec.template.metadata.labels.pod-label + value: pod-value + + - it: should add pod annotations + set: + splunkOperator.podAnnotations: + pod-annotation: pod-value + asserts: + - equal: + path: spec.template.metadata.annotations.pod-annotation + value: pod-value + + - it: should set security context defaults + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation + value: false + - equal: + path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem + value: true + - equal: + path: spec.template.spec.containers[0].securityContext.runAsNonRoot + value: true + + - it: should disable host namespaces by default + asserts: + - equal: + path: spec.template.spec.hostNetwork + value: false + - equal: + path: spec.template.spec.hostPID + value: false + - equal: + path: spec.template.spec.hostIPC + value: false + + - it: should set extra environment variables + set: + extraEnvs: + - name: MY_VAR + value: my-value + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: MY_VAR + value: my-value diff --git a/helm-chart/splunk-operator/tests/helpers_test.yaml b/helm-chart/splunk-operator/tests/helpers_test.yaml new file mode 100644 index 000000000..4be6f9036 --- /dev/null +++ b/helm-chart/splunk-operator/tests/helpers_test.yaml @@ -0,0 +1,57 @@ +suite: helpers +templates: + - templates/deployment.yaml +tests: + - it: should use default operator fullname + asserts: + - equal: + path: metadata.name + value: splunk-operator-controller-manager + + - it: should allow overriding operator name + set: + splunkOperator.nameOverride: my-operator + asserts: + - equal: + path: metadata.name + value: my-operator-controller-manager + + - it: should use default namespace from release + release: + namespace: test-ns + asserts: + - equal: + path: metadata.namespace + value: test-ns + + - it: should allow namespace override + release: + namespace: test-ns + set: + namespaceOverride: overridden-ns + asserts: + - equal: + path: metadata.namespace + value: overridden-ns + + - it: should include common labels + chart: + version: 1.2.3 + appVersion: 3.1.0 + release: + name: my-release + asserts: + - exists: + path: metadata.labels["helm.sh/chart"] + - equal: + path: metadata.labels["app.kubernetes.io/managed-by"] + value: Helm + - equal: + path: metadata.labels["app.kubernetes.io/version"] + value: "3.1.0" + + - it: should derive service account name from operator fullname + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: splunk-operator-controller-manager diff --git a/helm-chart/splunk-operator/values.yaml b/helm-chart/splunk-operator/values.yaml index 8fda5dc76..c9d571da8 100644 --- a/helm-chart/splunk-operator/values.yaml +++ b/helm-chart/splunk-operator/values.yaml @@ -146,6 +146,16 @@ splunkOperator: # Mandatory acknowledgment mechanism for the Splunk General Terms (SGT) splunkGeneralTerms: "" + # Feature gates to enable or disable on the operator. + # Each key is a gate name and the value is a boolean (true/false). + # The map is formatted into a single --feature-gates arg automatically. + # Adding a new gate requires no chart changes — just add an entry here. + # reference: https://splunk.github.io/splunk-operator/FeatureGates + featureGates: {} + # featureGates: + # ValidationWebhook: true + # MyNewFeature: false + # Array with extra yaml to deploy with the chart. Evaluated as a template extraManifests: [] # extraManifests: diff --git a/internal/controller/licensemanager_controller_test.go b/internal/controller/licensemanager_controller_test.go index 734e2f932..01380f363 100644 --- a/internal/controller/licensemanager_controller_test.go +++ b/internal/controller/licensemanager_controller_test.go @@ -95,7 +95,7 @@ var _ = Describe("LicenseManager Controller", func() { // econcile for the first time err is resource not found _, err := instance.Reconcile(ctx, request) Expect(err).ToNot(HaveOccurred()) - // create resource first adn then reconcile for the first time + // create resource first and then reconcile for the first time ssSpec := testutils.NewLicenseManager("test", namespace, "image") Expect(c.Create(ctx, ssSpec)).Should(Succeed()) // reconcile with updated annotations for pause diff --git a/pkg/config/featuregates.go b/pkg/config/featuregates.go new file mode 100644 index 000000000..934807511 --- /dev/null +++ b/pkg/config/featuregates.go @@ -0,0 +1,67 @@ +// Copyright (c) 2018-2026 Splunk Inc. All rights reserved. + +// +// 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 config + +import ( + "fmt" + "os" + + "k8s.io/component-base/featuregate" +) + +// Feature gate constants. Add new feature gates here following the checklist +// in docs/FeatureGates.md. +// +// Lifecycle: +// +// Alpha – off by default, opt-in via --feature-gates==true +// Beta – on by default, opt-out via --feature-gates==false +// GA – on, locked; remove the gate in a subsequent release +const ( + // ValidationWebhook gates the centralized validation webhook server. + // When enabled, the operator runs a validating webhook that enforces + // CR schema rules at admission time. + // Replaces the legacy ENABLE_VALIDATION_WEBHOOK env var. + ValidationWebhook featuregate.Feature = "ValidationWebhook" +) + +// defaultFeatureGates is the authoritative registry of all feature gates and +// their default state / maturity. Each entry here automatically becomes +// available via --feature-gates on the operator binary. +var defaultFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{ + ValidationWebhook: {Default: false, PreRelease: featuregate.Alpha}, +} + +var DefaultMutableFeatureGate featuregate.MutableFeatureGate = featuregate.NewFeatureGate() + +func init() { + if err := DefaultMutableFeatureGate.Add(defaultFeatureGates); err != nil { + panic(err) + } + applyLegacyValidationWebhookEnv(DefaultMutableFeatureGate) +} + +// applyLegacyValidationWebhookEnv preserves backwards compatibility for +// deployments using the ENABLE_VALIDATION_WEBHOOK env var instead of +// --feature-gates=ValidationWebhook=true. +// Remove once the ENABLE_VALIDATION_WEBHOOK deprecation period ends. +func applyLegacyValidationWebhookEnv(fg featuregate.MutableFeatureGate) { + if os.Getenv("ENABLE_VALIDATION_WEBHOOK") == "true" { + if err := fg.SetFromMap(map[string]bool{string(ValidationWebhook): true}); err != nil { + fmt.Fprintf(os.Stderr, "WARNING: failed to apply legacy env var ENABLE_VALIDATION_WEBHOOK: %v\n", err) + } + } +} diff --git a/pkg/config/featuregates_test.go b/pkg/config/featuregates_test.go new file mode 100644 index 000000000..03f9d9779 --- /dev/null +++ b/pkg/config/featuregates_test.go @@ -0,0 +1,91 @@ +// Copyright (c) 2018-2026 Splunk Inc. All rights reserved. + +// +// 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 config + +import ( + "os" + "testing" + + "k8s.io/component-base/featuregate" +) + +func TestValidationWebhookRegistered(t *testing.T) { + all := DefaultMutableFeatureGate.GetAll() + spec, ok := all[ValidationWebhook] + if !ok { + t.Fatal("ValidationWebhook gate not registered") + } + if spec.Default != false { + t.Errorf("ValidationWebhook default: got %v, want false", spec.Default) + } + if spec.PreRelease != featuregate.Alpha { + t.Errorf("ValidationWebhook prerelease: got %v, want Alpha", spec.PreRelease) + } +} + +func TestValidationWebhookOffByDefault(t *testing.T) { + if DefaultMutableFeatureGate.Enabled(ValidationWebhook) { + t.Error("ValidationWebhook should be disabled by default (Alpha)") + } +} + +func TestLegacyEnvVarEnablesGate(t *testing.T) { + fg := featuregate.NewFeatureGate() + if err := fg.Add(map[featuregate.Feature]featuregate.FeatureSpec{ + ValidationWebhook: {Default: false, PreRelease: featuregate.Alpha}, + }); err != nil { + t.Fatalf("Add: %v", err) + } + + t.Setenv("ENABLE_VALIDATION_WEBHOOK", "true") + applyLegacyValidationWebhookEnv(fg) + + if !fg.Enabled(ValidationWebhook) { + t.Error("ValidationWebhook should be enabled when ENABLE_VALIDATION_WEBHOOK=true") + } +} + +func TestLegacyEnvVarIgnoredWhenUnset(t *testing.T) { + fg := featuregate.NewFeatureGate() + if err := fg.Add(map[featuregate.Feature]featuregate.FeatureSpec{ + ValidationWebhook: {Default: false, PreRelease: featuregate.Alpha}, + }); err != nil { + t.Fatalf("Add: %v", err) + } + + os.Unsetenv("ENABLE_VALIDATION_WEBHOOK") + applyLegacyValidationWebhookEnv(fg) + + if fg.Enabled(ValidationWebhook) { + t.Error("ValidationWebhook should remain disabled when env var is not set") + } +} + +func TestLegacyEnvVarIgnoredWhenNotTrue(t *testing.T) { + fg := featuregate.NewFeatureGate() + if err := fg.Add(map[featuregate.Feature]featuregate.FeatureSpec{ + ValidationWebhook: {Default: false, PreRelease: featuregate.Alpha}, + }); err != nil { + t.Fatalf("Add: %v", err) + } + + t.Setenv("ENABLE_VALIDATION_WEBHOOK", "false") + applyLegacyValidationWebhookEnv(fg) + + if fg.Enabled(ValidationWebhook) { + t.Error("ValidationWebhook should remain disabled when ENABLE_VALIDATION_WEBHOOK=false") + } +} diff --git a/pkg/splunk/client/enterprise_test.go b/pkg/splunk/client/enterprise_test.go index 2c902d537..b605663cb 100644 --- a/pkg/splunk/client/enterprise_test.go +++ b/pkg/splunk/client/enterprise_test.go @@ -311,7 +311,7 @@ func TestGetclusterManagerInfo(t *testing.T) { } return nil } - body = splcommon.TestGetCMInfoEmpty + body = loadFixture(t, "get_cm_info_empty.json") splunkClientTester(t, "TestGetclusterManagerInfo", 200, body, wantRequest, test) // test error code @@ -331,7 +331,7 @@ func TestGetIndexerClusterPeerInfo(t *testing.T) { } return nil } - body := splcommon.TestGetIndexerClusterPeerInfo + body := loadFixture(t, "get_indexer_cluster_peer_info.json") splunkClientTester(t, "TestGetIndexerClusterPeerInfo", 200, body, wantRequest, test) // test body with no entries @@ -342,7 +342,7 @@ func TestGetIndexerClusterPeerInfo(t *testing.T) { } return nil } - body = splcommon.TestGetIndexerClusterPeerInfoEmpty + body = loadFixture(t, "get_indexer_cluster_peer_info_empty.json") splunkClientTester(t, "TestGetIndexerClusterPeerInfo", 200, body, wantRequest, test) // test error code @@ -383,7 +383,7 @@ func TestGetClusterManagerPeers(t *testing.T) { } return nil } - body := splcommon.TestGetCMPeers + body := loadFixture(t, "get_cm_peers.json") splunkClientTester(t, "TestGetClusterManagerPeers", 200, body, wantRequest, test) // test error response @@ -433,14 +433,14 @@ func TestAutomateMCApplyChanges(t *testing.T) { var wantRequests []*http.Request wantRequests = []*http.Request(append(wantRequests, request1, request2, request3, request4, request5, request6, request7, request8, request9, request10)) body := []string{ - `{"links":{},"origin":"https://localhost:8089/services/server/info","updated":"2020-09-24T06:38:53+00:00","generator":{"build":"a1a6394cc5ae","version":"8.0.5"},"entry":[{"name":"server-info","id":"https://localhost:8089/services/server/info/server-info","updated":"1970-01-01T00:00:00+00:00","links":{"alternate":"/services/server/info/server-info","list":"/services/server/info/server-info"},"author":"system","acl":{"app":"","can_list":true,"can_write":true,"modifiable":false,"owner":"system","perms":{"read":["*"],"write":[]},"removable":false,"sharing":"system"},"fields":{"required":[],"optional":[],"wildcard":[]},"content":{"activeLicenseGroup":"Trial","activeLicenseSubgroup":"Production","build":"a1a6394cc5ae","cluster_label":["idxc_label"],"cpu_arch":"x86_64","eai:acl":null,"fips_mode":false,"guid":"0F93F33C-4BDA-4A74-AD9F-3FCE26C6AFF0","health_info":"green","health_version":1,"host":"splunk-default-monitoring-console-86bc9b7c8c-d96x2","host_fqdn":"splunk-default-monitoring-console-86bc9b7c8c-d96x2","host_resolved":"splunk-default-monitoring-console-86bc9b7c8c-d96x2","isForwarding":true,"isFree":false,"isTrial":true,"kvStoreStatus":"ready","licenseKeys":["5C52DA5145AD67B8188604C49962D12F2C3B2CF1B82A6878E46F68CA2812807B"],"licenseSignature":"139bf73ec92c84121c79a9b8307a6724","licenseState":"OK","license_labels":["Splunk Enterprise Splunk Analytics for Hadoop Download Trial"],"master_guid":"0F93F33C-4BDA-4A74-AD9F-3FCE26C6AFF0","master_uri":"self","max_users":4294967295,"mode":"normal","numberOfCores":1,"numberOfVirtualCores":2,"os_build":"#1 SMP Thu Sep 3 19:04:44 UTC 2020","os_name":"Linux","os_name_extended":"Linux","os_version":"4.14.193-149.317.amzn2.x86_64","physicalMemoryMB":7764,"product_type":"enterprise","rtsearch_enabled":true,"serverName":"splunk-default-monitoring-console-86bc9b7c8c-d96x2","server_roles":["license_master","cluster_search_head","search_head"],"startup_time":1600928786,"staticAssetId":"CFE3D41EE2CCD1465E8C8453F83E4ECFFF540780B4490E84458DD4A3694CE4D1","version":"8.0.5"}}],"paging":{"total":1,"perPage":30,"offset":0},"messages":[]}`, - splcommon.TestMCApplyChanges, + loadFixture(t, "get_server_info.json"), + loadFixture(t, "mc_apply_changes.json"), "", "", "", - `{"links":{"create":"/servicesNS/nobody/splunk_monitoring_console/data/ui/nav/_new","_reload":"/servicesNS/nobody/splunk_monitoring_console/data/ui/nav/_reload","_acl":"/servicesNS/nobody/splunk_monitoring_console/data/ui/nav/_acl"},"origin":"https://localhost:8089/servicesNS/nobody/splunk_monitoring_console/data/ui/nav","updated":"2020-09-23T23:50:25+00:00","generator":{"build":"a1a6394cc5ae","version":"8.0.5"},"entry":[{"name":"default.distributed","id":"https://localhost:8089/servicesNS/nobody/splunk_monitoring_console/data/ui/nav/default.distributed","updated":"1970-01-01T00:00:00+00:00","links":{"alternate":"/servicesNS/nobody/splunk_monitoring_console/data/ui/nav/default.distributed","list":"/servicesNS/nobody/splunk_monitoring_console/data/ui/nav/default.distributed","_reload":"/servicesNS/nobody/splunk_monitoring_console/data/ui/nav/default.distributed/_reload","edit":"/servicesNS/nobody/splunk_monitoring_console/data/ui/nav/default.distributed"},"author":"nobody","acl":{"app":"splunk_monitoring_console","can_change_perms":true,"can_list":true,"can_share_app":true,"can_share_global":true,"can_share_user":false,"can_write":true,"modifiable":true,"owner":"nobody","perms":{"read":["admin"],"write":["admin"]},"removable":false,"sharing":"app"},"fields":{"required":["eai:data"],"optional":[],"wildcard":[]},"content":{"disabled":false,"eai:acl":null,"eai:appName":"splunk_monitoring_console","eai:data":"