Documentation
¶
Index ¶
- Constants
- func AllValidatorNames() []string
- func RunValidationTestsSync(ctx context.Context, cfg *coreconfig.Config, bootstrap TypeBootstrapper, ...) (configtest.Result, error)
- func SuiteRunBudget(testCount int) time.Duration
- func SuiteValidationEnvelope(testCount int) time.Duration
- func ValidateIncrementalActivationPaths(cfg *coreconfig.Config) []string
- type BaseValidator
- type BasicValidator
- type JSONPathValidator
- type SchemaAcquisitionError
- type SyncFailures
- type TemplateValidator
- type TypeBootstrapper
- type ValidationHandler
- type ValidationTestsValidator
- type Verdict
Constants ¶
const ( // ValidatorNameBasic is the name for the basic structure validator. ValidatorNameBasic = "basic" // ValidatorNameTemplate is the name for the template syntax validator. ValidatorNameTemplate = "template" // ValidatorNameJSONPath is the name for the JSONPath expression validator. ValidatorNameJSONPath = "jsonpath" // ValidatorNameValidationTests is the name for the validator that runs the // config's embedded validationTests (the same suite the `controller validate` // CLI runs) before a config is accepted, so the daemon never loads a config // whose tests fail. ValidatorNameValidationTests = "validationtests" )
Validator names used in the scatter-gather validation pattern.
These constants ensure consistency between: - Validator responder names (in ConfigValidationResponse) - Expected responders list (in ConfigChangeHandler)
Using constants prevents typos and silent failures where the scatter-gather pattern would timeout waiting for a validator that uses a different name.
const EventBufferSize = busevents.LowVolumeSubscriberBuffer
EventBufferSize is the size of the event subscription buffer. Low-volume component (~1 validation request per reconciliation).
Variables ¶
This section is empty.
Functions ¶
func AllValidatorNames ¶
func AllValidatorNames() []string
AllValidatorNames returns a slice of all validator names. Use this when registering validators in the ConfigChangeHandler.
func RunValidationTestsSync ¶
func RunValidationTestsSync(ctx context.Context, cfg *coreconfig.Config, bootstrap TypeBootstrapper, runTimeout time.Duration, logger *slog.Logger) (configtest.Result, error)
RunValidationTestsSync resolves typed schemas, builds a throwaway engine, and runs the config's embedded validationTests via the shared configtest helper (the same one the admission webhook uses, so the gates can't drift). It is the shared core behind both the live scatter-gather gate (the validator's HandleRequest) and the startup load gate (controller.runIteration) — so a config's tests are bootstrapped, compiled, and executed identically whether they run on a live change or at controller load.
A config with no validationTests is a zero-cost pass. A runTimeout <= 0 uses the default suite budget (validationTestsRunTimeout). Any setup error is returned so the caller can fail validation with a clear reason rather than silently skipping the gate.
func SuiteRunBudget ¶
SuiteRunBudget returns the live-gate test-execution budget for a suite of the given size: the validationTestsRunTimeout floor PLUS suitePerTestBudget per test. A fixed 25s cap rejected the chart's all-passing 362-test suite on contended CI nodes (issue #77: 362/362 passed in 27.8s, cancelled at 25s, config rejected as "partially-validated"). Scaling with suite size keeps small suites on a tight bound while a legitimately large suite gets time proportional to its work. Exported so configchange can derive its scatter-gather envelope from the SAME formula — the envelope must stay strictly larger than this budget (see SuiteValidationEnvelope).
The floor is ADDED, not max()'d. Taking the larger of the two pinned every suite below 250 tests to exactly 25s, so the floor — chosen as headroom for a *small* suite on a cold node — silently became the whole budget for a suite doing ten times the work. That reintroduced #77's false rejection at the crossover: the chart's ~249-test effective suite (post-`requires` stripping on a cluster without Gateway CRDs) needed 27.3s against a budget that computed to 24.9s and therefore clamped to the 25s floor, and a perfectly good default config was rejected as partially-validated. Adding the floor is also what the doc comment on suitePerTestBudget and the shipped changelog ("25s floor + ~100ms per test") always described.
func SuiteValidationEnvelope ¶
SuiteValidationEnvelope returns the scatter-gather timeout for validating a config with the given suite size. Every component that grows with the suite (run budget, engine compile) scales, so the envelope is strictly larger than the validator's worst-case wall time for every testCount and the validationtests validator always self-reports (pass, or "did not complete") before the coordinator declares it a missing responder.
func ValidateIncrementalActivationPaths ¶
func ValidateIncrementalActivationPaths(cfg *coreconfig.Config) []string
ValidateIncrementalActivationPaths validates component activation paths.
Types ¶
type BaseValidator ¶
BaseValidator owns request decoding and response publishing for a ValidationHandler. A panic produces a rejection so the scatter-gather coordinator can finish.
func NewBaseValidator ¶
func NewBaseValidator( eventBus *busevents.EventBus, logger *slog.Logger, name string, handler ValidationHandler, ) *BaseValidator
NewBaseValidator subscribes the handler to config validation requests.
func (*BaseValidator) HandleEvent ¶
func (v *BaseValidator) HandleEvent(event busevents.Event)
HandleEvent implements component.EventHandler.
func (*BaseValidator) HandlePanic ¶
func (v *BaseValidator) HandlePanic(recovered any, event busevents.Event)
HandlePanic rejects the request so scatter-gather does not wait for a lost response.
func (*BaseValidator) HandleRequest ¶
func (v *BaseValidator) HandleRequest(req *events.ConfigValidationRequest)
HandleRequest owns config decoding and the single response for each validation.
type BasicValidator ¶
type BasicValidator struct {
*BaseValidator
}
BasicValidator validates basic structural configuration requirements.
This component subscribes to ConfigValidationRequest events and validates basic structural requirements such as: - Required fields are present - Field types and values are correct - Port numbers are in valid ranges - Non-empty slices where required
This validator uses the existing config.ValidateStructure() function and does NOT validate template syntax or JSONPath expressions (handled by specialized validators).
This component is part of the scatter-gather validation pattern and publishes ConfigValidationResponse events with validation results.
func NewBasicValidator ¶
func NewBasicValidator(eventBus *busevents.EventBus, logger *slog.Logger) *BasicValidator
NewBasicValidator creates a new basic validator component.
func (*BasicValidator) Validate ¶
func (v *BasicValidator) Validate(_ context.Context, cfg *coreconfig.Config, version string) Verdict
Validate implements ValidationHandler.
type JSONPathValidator ¶
type JSONPathValidator struct {
*BaseValidator
}
JSONPathValidator validates JSONPath expressions in configuration.
This component subscribes to ConfigValidationRequest events and validates all JSONPath expressions in the configuration using the k8s indexer package.
Validated fields: - WatchedResourcesIgnoreFields (all expressions) - WatchedResources[*].IndexBy (all expressions) - WatchedResources[*].FieldSelector (field.path=value format)
This component is part of the scatter-gather validation pattern and publishes ConfigValidationResponse events with validation results.
func NewJSONPathValidator ¶
func NewJSONPathValidator(eventBus *busevents.EventBus, logger *slog.Logger) *JSONPathValidator
NewJSONPathValidator creates a new JSONPath validator component.
func (*JSONPathValidator) Validate ¶
func (v *JSONPathValidator) Validate(_ context.Context, cfg *coreconfig.Config, version string) Verdict
Validate implements ValidationHandler.
type SchemaAcquisitionError ¶
type SchemaAcquisitionError struct {
// Subject names what could not be validated without the schemas.
Subject string
Err error
}
SchemaAcquisitionError reports that watched-resource schemas could not be acquired, so typed template access cannot be checked.
func (*SchemaAcquisitionError) Error ¶
func (e *SchemaAcquisitionError) Error() string
func (*SchemaAcquisitionError) Transient ¶
func (e *SchemaAcquisitionError) Transient() bool
Transient reports whether the failure says nothing about the config: the apiserver was slow, overloaded, or unreachable.
func (*SchemaAcquisitionError) Unwrap ¶
func (e *SchemaAcquisitionError) Unwrap() error
type SyncFailures ¶
SyncFailures contains the complete config-validator verdict by validator.
func ValidateConfigSync ¶
func ValidateConfigSync( ctx context.Context, cfg *coreconfig.Config, bootstrap TypeBootstrapper, runTimeout time.Duration, logger *slog.Logger, ) SyncFailures
ValidateConfigSync applies the same four validators as the live scatter-gather before an iteration adopts a re-resolved config.
func (SyncFailures) Error ¶
func (f SyncFailures) Error() string
Error returns a deterministic summary suitable for the startup error.
func (SyncFailures) Flat ¶
func (f SyncFailures) Flat() []string
Flat returns the deterministic messages written to config status.
type TemplateValidator ¶
type TemplateValidator struct {
*BaseValidator
// contains filtered or unexported fields
}
TemplateValidator validates template syntax in configuration.
This component subscribes to ConfigValidationRequest events and validates all templates together as a complete set. It uses helpers.ExtractTemplatesFromConfig to ensure validation matches production behavior exactly (DRY principle).
Templates are validated together, not in isolation, so snippets that reference each other via render, import, or inherit_context work correctly.
This component is part of the scatter-gather validation pattern and publishes ConfigValidationResponse events with validation results.
func NewTemplateValidator ¶
func NewTemplateValidator(eventBus *busevents.EventBus, logger *slog.Logger, bootstrap TypeBootstrapper) *TemplateValidator
NewTemplateValidator creates a new template validator component.
Parameters:
- eventBus: the EventBus to subscribe to and publish on
- logger: structured logger for diagnostics
- bootstrap: resolver for typed reflect.Types per watched resource. MUST be non-nil — without real types the engine compile would degrade to envelope-only declarations and false-positively reject any chart that uses typed Spec / Status access. Tests pass a stub returning an in-memory Result; production passes a closure around controller.runTypeBootstrap.
func (*TemplateValidator) Validate ¶
func (v *TemplateValidator) Validate(ctx context.Context, cfg *coreconfig.Config, version string) Verdict
Validate implements ValidationHandler.
type TypeBootstrapper ¶
type TypeBootstrapper func(ctx context.Context, cfg *coreconfig.Config) (*typebootstrap.Result, error)
TypeBootstrapper runs the schema-acquisition pipeline for a candidate config and returns the resolved typed reflect.Types for each watched resource. Used by TemplateValidator so its engine compile sees the same typed globals the Stage-5 production engine will see — without this, a chart that uses typed Spec/Status access (e.g. `gw.Spec.Listeners`) would be false-positively rejected at Stage 1 against an envelope-only declaration set.
Production wiring binds this to controller.runTypeBootstrap with the iteration's K8s client captured in the closure; tests pass a stub that returns a Result built from in-memory schemas.
type ValidationHandler ¶
type ValidationHandler interface {
Validate(ctx context.Context, cfg *coreconfig.Config, version string) Verdict
}
ValidationHandler validates a typed config without owning event responses.
type ValidationTestsValidator ¶
type ValidationTestsValidator struct {
*BaseValidator
// contains filtered or unexported fields
}
ValidationTestsValidator runs the config's embedded validationTests — the exact suite the `controller validate` CLI runs — as a scatter-gather validator. It guards live config changes: when a CRD update's tests fail the aggregation publishes ConfigInvalidEvent and the last-good config keeps serving.
The load path invokes the complete synchronous validator contract, which shares RunValidationTestsSync with this adapter.
It builds a throwaway engine from the candidate config (using the same live-schema TypeBootstrapper the TemplateValidator uses, so typed access in tests compiles identically to production) plus a temporary HAProxy validation tree for `haproxy_valid` assertions, runs the suite, and reports the outcome. This runs only on config load/change — never on the resource reconciliation hot path.
func NewValidationTestsValidator ¶
func NewValidationTestsValidator(eventBus *busevents.EventBus, logger *slog.Logger, bootstrap TypeBootstrapper) *ValidationTestsValidator
NewValidationTestsValidator creates the validationTests validator.
bootstrap MUST be non-nil — without real typed reflect.Types the engine compile (and therefore any test exercising typed Spec/Status access) would false-positively fail. Production passes a closure around controller.runTypeBootstrap; tests pass a stub returning an in-memory Result.
func (*ValidationTestsValidator) Validate ¶
func (v *ValidationTestsValidator) Validate(ctx context.Context, cfg *coreconfig.Config, version string) Verdict
Validate implements ValidationHandler.