Skip to content

Conversation

@patrykw-splunk
Copy link
Collaborator

@patrykw-splunk patrykw-splunk commented Feb 2, 2026

Description

Implements an opt-in validation webhook for Splunk Enterprise CRDs that validates spec fields on CREATE and UPDATE operations, providing immediate feedback when invalid configurations are submitted.

The webhook is disabled by default and can be enabled by setting ENABLE_WEBHOOKS=true or using the config/default-with-webhook kustomize overlay.

Key Changes

New Validation Package (pkg/splunk/enterprise/validation/)

  • Validator framework - Generic type-safe validator using Go generics
  • Webhook server - HTTP server with TLS support on port 9443
  • CRD validators - Standalone, IndexerCluster, SearchHeadCluster, ClusterManager, LicenseManager, MonitoringConsole

Validated Fields

Field Rule
spec.replicas ≥ 0 (Standalone), ≥ 3 (IndexerCluster, SearchHeadCluster)
spec.imagePullPolicy Must be Always, Never, or IfNotPresent
spec.livenessInitialDelaySeconds ≥ 3
spec.readinessInitialDelaySeconds ≥ 3
spec.etcVolumeStorageConfig.storageCapacity Format ^[0-9]+Gi$
spec.varVolumeStorageConfig.storageCapacity Format ^[0-9]+Gi$
spec.smartstore Volume/index name validation (conditional)
spec.appRepo App source name/location validation (conditional)

Webhook Infrastructure

  • config/webhook/ - Service and ValidatingWebhookConfiguration
  • config/certmanager/ - TLS certificate via cert-manager
  • config/default-with-webhook/ - Opt-in kustomize overlay

Documentation

  • docs/ValidationWebhook.md

Testing and Verification

Comprehensive unit tests (~95% coverage)
Server and HTTP handler tests

Related Issues

N/A

PR Checklist

  • Code changes adhere to the project's coding standards.
  • Relevant unit and integration tests are included.
  • Documentation has been updated accordingly.
  • All tests pass locally.
  • The PR description follows the project's guidelines.

patrykw-splunk and others added 4 commits February 2, 2026 16:24
* implementation of dummy validation webhook

---------

Co-authored-by: Patryk Wasielewski <pwasiele@splunk.com>
Implement Validation Webhook logic + unit tests + mux server for webhook

---------

Co-authored-by: Patryk Wasielewski <pwasiele@splunk.com>
@github-actions
Copy link
Contributor

github-actions bot commented Feb 2, 2026

CLA Assistant Lite bot:
Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.


I have read the CLA Document and I hereby sign the CLA


0 out of 2 committers have signed the CLA.
@patrykw-splunk
@patryk Wasielewski
Patryk Wasielewski seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You can retrigger this bot by commenting recheck in this Pull Request

@coveralls
Copy link
Collaborator

coveralls commented Feb 2, 2026

Pull Request Test Coverage Report for Build 21636244635

Details

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.02%) to 86.242%

Totals Coverage Status
Change from base Build 21471999380: 0.02%
Covered Lines: 10763
Relevant Lines: 12480

💛 - Coveralls


The webhook validates the following Custom Resource Definitions:

- Standalone
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add here bias language CRDs

- indexerclusters
- searchheadclusters
- clustermanagers
- clustermasters
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are doing it only for v4, then I guess any references to ClusterMaster or LicenseMaster in this file and others could be removed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is slightly inconsistent across different files, so we have to decide on the approach.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the difference is that here it's necessary to list here all resources for validation sake

func ValidateClusterManagerUpdate(obj, oldObj *enterpriseApi.ClusterManager) field.ErrorList {
var allErrs field.ErrorList
allErrs = append(allErrs, ValidateClusterManagerCreate(obj)...)
return allErrs
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could it be just a one line instead of three?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment applies to all such functions

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a topic for discussion. One liner could fit here ideally if we would know that this function won't be extended. The problem is that if we want to add i.e immutable fields (and we're planning to) this will look like it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

example

`// ValidateClusterManagerUpdate validates a ClusterManager on UPDATE
func ValidateClusterManagerUpdate(obj, oldObj *enterpriseApi.ClusterManager) field.ErrorList {
allErrs := ValidateClusterManagerCreate(obj)

// Example: Check immutable fields

// Example 1: Prevent changing ClusterManagerRef (if it was set)
if oldObj.Spec.ClusterManagerRef.Name != "" && 
   obj.Spec.ClusterManagerRef.Name != oldObj.Spec.ClusterManagerRef.Name {
    allErrs = append(allErrs, field.Forbidden(
        field.NewPath("spec").Child("clusterManagerRef").Child("name"),
        "field is immutable once set"))
}

`

Copy link
Collaborator

@kasiakoziol kasiakoziol Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And what if not? 😄 I get your point.

func GetClusterManagerWarningsOnCreate(obj *enterpriseApi.ClusterManager) []string {
var warnings []string
warnings = append(warnings, getCommonWarnings(&obj.Spec.CommonSplunkSpec)...)
return warnings
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here


warnings := GetClusterManagerWarningsOnCreate(obj)
if len(warnings) != 0 {
t.Errorf("GetClusterManagerWarningsOnCreate() returned %d warnings, expected 0", len(warnings))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we just use assertions?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It applies to all tests

func getCommonWarnings(spec *enterpriseApi.CommonSplunkSpec) []string {
var warnings []string

// Warn about deprecated fields or configurations
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's for the future sake, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exactly

name: "invalid indexer cluster - zero replicas",
obj: &enterpriseApi.IndexerCluster{
Spec: enterpriseApi.IndexerClusterSpec{
Replicas: 0,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we are setting up replicas to 3 if not provided (in the controller code), so maybe we should add default value at the spec level if we are introducing webhooks to make sure we are backward compatible in case someone didn't provide the value.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It applies to all such cases

@patrykw-splunk
Copy link
Collaborator Author

I have read the Code of Conduct and I hereby accept the Terms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants