Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 65 additions & 33 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,18 @@ import (
"crypto/tls"
"flag"
"fmt"
"log/slog"
"os"
"path/filepath"
"time"

"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
"github.com/spf13/pflag"

intController "github.com/splunk/splunk-operator/internal/controller"
"github.com/splunk/splunk-operator/internal/controller/debug"
"github.com/splunk/splunk-operator/pkg/config"
"github.com/splunk/splunk-operator/pkg/logging"
"github.com/splunk/splunk-operator/pkg/splunk/enterprise/validation"
"sigs.k8s.io/controller-runtime/pkg/certwatcher"

// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them.
Expand All @@ -45,14 +46,15 @@ import (
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"

enterpriseApiV3 "github.com/splunk/splunk-operator/api/v3"
enterpriseApi "github.com/splunk/splunk-operator/api/v4"
"github.com/splunk/splunk-operator/internal/controller"
//+kubebuilder:scaffold:imports
//extapi "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
)
Expand All @@ -76,8 +78,11 @@ func main() {
var enableLeaderElection bool
var probeAddr string
var pprofActive bool
var logEncoder string
var logLevel int

// Structured logging flags
var logLevel string
var logFormat string
var logAddSource bool

var leaseDuration time.Duration
var renewDeadline time.Duration
Expand All @@ -86,27 +91,49 @@ func main() {

var tlsOpts []func(*tls.Config)

// 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(&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")

// Structured logging flags (can also be set via LOG_LEVEL, LOG_FORMAT, LOG_ADD_SOURCE env vars)
pflag.StringVar(&logLevel, "log-level", "", "log level: debug, info, warn, error (overrides LOG_LEVEL env var)")
pflag.StringVar(&logFormat, "log-format", "", "log output format: json, text (overrides LOG_FORMAT env var)")
pflag.BoolVar(&logAddSource, "log-add-source", false, "add source file:line to log output (overrides LOG_ADD_SOURCE env var)")
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:
Expand Down Expand Up @@ -147,15 +174,20 @@ func main() {
renewDeadline = time.Duration(renewDeadlineSecond) * time.Second
}

opts := zap.Options{
Development: true,
TimeEncoder: zapcore.RFC3339NanoTimeEncoder,
// Initialize structured logging infrastructure
// Flags take precedence over environment variables
var addSourcePtr *bool
if logAddSource {
addSourcePtr = &logAddSource
}
opts.BindFlags(flag.CommandLine)
flag.Parse()
logCfg := logging.LoadConfigWithFlags(logLevel, logFormat, addSourcePtr)
_ = logging.SetupLogger(logCfg)

// Logging setup
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
// Log startup information using slog
slog.Info("splunk Operator starting",
slog.String("log_level", logging.LevelToString(logCfg.Level)),
slog.String("log_format", logCfg.Format),
slog.Bool("log_add_source", logCfg.AddSource))

// Configure metrics certificate watcher if metrics certs are provided
var metricsCertWatcher *certwatcher.CertWatcher
Expand Down Expand Up @@ -264,7 +296,7 @@ func main() {
setupLog.Error(err, "unable to create controller", "controller", "Standalone")
os.Exit(1)
}
if err := (&controller.IngestorClusterReconciler{
if err := (&intController.IngestorClusterReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("ingestorcluster-controller"),
Expand All @@ -280,10 +312,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 {
Expand All @@ -306,16 +339,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

Expand Down
9 changes: 5 additions & 4 deletions config/default-with-webhook/kustomization-cluster.yaml
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
9 changes: 5 additions & 4 deletions config/default-with-webhook/kustomization-namespace.yaml
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -115,7 +115,7 @@ patches:
patch: |-
- op: add
path: /spec/template/spec/containers/0/env
value:
value:
- name: WATCH_NAMESPACE
valueFrom:
fieldRef:
Expand All @@ -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
Expand Down
11 changes: 6 additions & 5 deletions config/default-with-webhook/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -115,21 +115,22 @@ 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
value: SPLUNK_ENTERPRISE_IMAGE
- 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
Expand Down
Loading
Loading