Patch Engine
Patch - Declarative Resource Patching
The patch package provides a JSONPath-based system for declaratively modifying Kubernetes resources. It supports both TOML and YAML patch file formats with structure-preserving modifications and variable substitution.
Scope and Status
pkg/patch is a supported, standalone library. It is not invoked by kurel build — that
pipeline is closed through explicit registration (author-declared ${var} parameters plus
registered component, trait, and lowering-rule handlers), not universally typed: a handler may
declare a PropertySchema for an out-of-process validator to consume, but launcher’s own authored
document path does not check property shape against it — see pkg/oam/validate.go and
pkg/oam/property_validate.go’s scope note. No implicit patch step is planned. pkg/patch is the
designated implementation for explicit, user-invoked patching (e.g. interactive patch mode), used
directly by callers that want to modify Kubernetes resources outside the kurel build path.
Overview
Patches allow you to modify Kubernetes manifests without rewriting them. The system uses JSONPath expressions to target specific fields and applies changes while preserving the original YAML structure (comments, ordering, formatting).
Patch File Formats
TOML Format (.kpatch)
YAML Format
Quick Start
Key Features
Variable Substitution
Patches support variable references that resolve against a parameter context:
List Selectors
Target specific items in lists using selectors:
Structure Preservation
When using NewPatchableAppSetWithStructure, the original YAML document structure is preserved through patching, maintaining comments, key ordering, and formatting.
Strategic Merge Patch
For broad document-level changes, strategic merge patch (SMP) deep-merges a partial YAML document into the target resource. Known Kubernetes kinds merge lists by key (e.g. containers by name); unknown kinds fall back to JSON merge patch (RFC 7386).
SMP patches are applied before field-level patches. See DESIGN.md for full specification.
API Reference
Loading Patches
| Function | Description |
|---|---|
LoadPatchFile(r) | Load with automatic format detection |
LoadPatchFileWithVariables(r, ctx) | Load with variable substitution |
LoadTOMLPatchFile(r, ctx) | Load TOML-format patches |
LoadYAMLPatchFile(r, ctx) | Load YAML-format patches |
Applying Patches
| Function | Description |
|---|---|
NewPatchableAppSet(resources, patches) | Create patchable set |
NewPatchableAppSetWithStructure(docSet, patches) | Create with structure preservation |
ParsePatchLine(path, value) | Parse a single patch operation |
Strategic Merge Patch
| Function | Description |
|---|---|
ApplyStrategicMergePatch(resource, patch, lookup) | Apply SMP to a single resource |
DefaultKindLookup() | Create a KindLookup from the built-in scheme |
DetectSMPConflicts(patches, lookup, gvk) | Check pairwise conflicts among patches |
ResolveWithConflictCheck() | Resolve patches with conflict detection |
DetectSMPConflicts compares every patch pair exactly once (O(n²) in the
number of patches targeting one resource) rather than sampling, so it stays
accurate; a resource’s authored patch list is expected to stay small, which is
what keeps the quadratic cost unnoticeable in practice.
Error Handling
Individual patch operation failures (op.go — replace, delete, insert, and the other
per-line ops applied to a document) and patch-target resolution failures are returned as
*errors.PatchError
(github.com/go-kure/launcher/pkg/errors), carrying the failed operation, target path, resource
name, and the underlying cause where one exists:
errors.As(err, &pe) also matches failures from PatchableAppSet.Resolve()’s target-lookup check
and ResourceWithPatches.Apply() (both build on the same NewPatchError calls above) even where a
caller in set.go wraps them again with fmt.Errorf("...: %w", err) — %w preserves the chain.
Two call paths never produce a *errors.PatchError, so errors.As(err, &pe) will not match them:
direct use of ApplyStrategicMergePatch (and its applyJSONMergePatch/applyTypedSMP helpers in
strategic.go), and the YAML-structure-preserving document mutation helpers
(YAMLDocument.ApplyPatchesToDocument / ApplyStrategicPatchesToDocument in yaml_preserve.go,
reached via PatchableAppSet.WriteToFile’s per-document apply loop, and
UpdateDocumentFromResource). Those return plain wrapped errors (errors.Wrap/fmt.Errorf). Do
not assume every error out of this package is a *errors.PatchError — check the call path.
Related Packages
- pkg/oam - the
kurel buildpipeline; independent of this package (see Scope and Status above) - pkg/errors - structured error types, including
PatchError - kure pkg/io - YAML parsing for patch targets