Documentation
¶
Overview ¶
Package patch provides declarative patching of Kubernetes resources using a simple, structured syntax without templates or overlays.
This package enables tools to modify Kubernetes manifests through patches that target specific fields and list items using dot-notation paths with smart selectors.
Quick Start ¶
Load resources and apply patches:
// Load base Kubernetes resources
resources, err := patch.LoadResourcesFromMultiYAML(resourceFile)
if err != nil {
return err
}
// Load patch specifications
patches, err := patch.LoadPatchFile(patchFile)
if err != nil {
return err
}
// Create patchable set and apply
set, err := patch.NewPatchableAppSet(resources, patches)
if err != nil {
return err
}
resolved, err := set.Resolve()
if err != nil {
return err
}
for _, r := range resolved {
if err := r.Apply(); err != nil {
return err
}
}
Patch Syntax ¶
Both YAML and TOML patch formats are supported with automatic detection:
# YAML format
spec.replicas: 3
spec.containers[name=main].image: nginx:latest
spec.ports[+name=https]: {name: https, port: 443}
# TOML format
[deployment.app]
spec.replicas: 3
[deployment.app.containers.name=main]
image: nginx:latest
resources.requests.cpu: 100m
Strategic Merge Patch ¶
In addition to field-level patches, this package supports Kubernetes strategic merge patch (SMP) semantics. SMP patches are partial YAML documents that are deep-merged into target resources. For known Kubernetes kinds, list items are merged by key (e.g. containers by name). For unknown kinds (CRDs), the package falls back to RFC 7386 JSON merge patch.
SMP patches are specified in YAML with type: strategic:
patches:
- target: deployment.my-app
type: strategic
patch:
spec:
template:
spec:
containers:
- name: main
resources:
limits:
cpu: "500m"
SMP patches are applied before field-level patches (SMP sets the broad document shape; field patches make precise tweaks on top).
Use PatchableAppSet.ResolveWithConflictCheck to detect conflicting SMP patches targeting the same resource before applying them.
Core Types ¶
PatchableAppSet - Manages resources and their patches PatchOp - Individual field-level patch operation StrategicPatch - Strategic merge patch document KindLookup - GVK-to-struct resolution for SMP ConflictReport - SMP conflict detection results PathPart - Structured path component TOMLHeader - Parsed TOML section header
Detailed Documentation ¶
For comprehensive information, see the markdown documentation:
- DESIGN.md - Complete syntax reference and examples
- PATCH_ENGINE_DESIGN.md - Architecture and implementation details
- PATH_RESOLUTION.md - Advanced path resolution and type inference
- ERROR_HANDLING.md - Error handling patterns and debugging
Debugging ¶
Enable detailed logging:
export KURE_DEBUG=1
Index ¶
- Variables
- func ApplyPatch(basePath, patchPath string) ([]*unstructured.Unstructured, error)
- func ApplyStrategicMergePatch(resource *unstructured.Unstructured, patch map[string]interface{}, ...) error
- func CanonicalResourceKey(r *unstructured.Unstructured) string
- func GenerateOutputFilename(originalPath, patchPath, outputDir string) string
- func InferPatchOp(path string) string
- func IsTOMLFormat(content string) bool
- func LoadResourcesFromMultiYAML(r io.Reader) ([]*unstructured.Unstructured, error)
- func ResolveTargetKey(resources []*unstructured.Unstructured, target string) (string, error)
- func SubstituteVariables(value string, ctx *VariableContext) (interface{}, error)
- type ConflictReport
- type KindLookup
- type PatchConflict
- type PatchOp
- type PatchSpec
- func LoadPatchFile(r io.Reader) ([]PatchSpec, error)
- func LoadPatchFileWithVariables(r io.Reader, varCtx *VariableContext) ([]PatchSpec, error)
- func LoadTOMLPatchFile(r io.Reader, varCtx *VariableContext) ([]PatchSpec, error)
- func LoadYAMLPatchFile(r io.Reader, varCtx *VariableContext) ([]PatchSpec, error)
- type PatchableAppSet
- func LoadPatchableAppSet(resourceReaders []io.Reader, patchReader io.Reader) (*PatchableAppSet, error)
- func NewPatchableAppSet(resources []*unstructured.Unstructured, patches []PatchSpec) (*PatchableAppSet, error)
- func NewPatchableAppSetWithStructure(documentSet *YAMLDocumentSet, patches []PatchSpec) (*PatchableAppSet, error)
- func (s *PatchableAppSet) Resolve() ([]*ResourceWithPatches, error)
- func (s *PatchableAppSet) ResolveWithConflictCheck() ([]*ResourceWithPatches, []*ConflictReport, error)
- func (s *PatchableAppSet) WritePatchedFiles(originalPath string, patchFiles []string, outputDir string) error
- func (s *PatchableAppSet) WritePatchedFilesWithOptions(originalPath string, patchFiles []string, outputDir string, debug bool) error
- func (s *PatchableAppSet) WriteToFile(filename string) error
- type PathPart
- type RawPatchMap
- type ResourceWithPatches
- type SchemeKindLookup
- type Selector
- type StrategicPatch
- type TOMLHeader
- type TargetedPatch
- type VariableContext
- type YAMLDocument
- type YAMLDocumentSet
- func (set *YAMLDocumentSet) Copy() (*YAMLDocumentSet, error)
- func (set *YAMLDocumentSet) FindDocumentByKindAndName(kind, name string) *YAMLDocument
- func (set *YAMLDocumentSet) FindDocumentByKindNameAndNamespace(kind, name, namespace string) *YAMLDocument
- func (set *YAMLDocumentSet) FindDocumentByName(name string) *YAMLDocument
- func (set *YAMLDocumentSet) GetResources() []*unstructured.Unstructured
- func (set *YAMLDocumentSet) WriteToFile(filename string) error
Constants ¶
This section is empty.
Variables ¶
var Debug = os.Getenv("KURE_DEBUG") == "1"
Functions ¶
func ApplyPatch ¶
func ApplyPatch(basePath, patchPath string) ([]*unstructured.Unstructured, error)
ApplyPatch loads resources and patch instructions from the provided file paths and returns the patched resources.
func ApplyStrategicMergePatch ¶
func ApplyStrategicMergePatch( resource *unstructured.Unstructured, patch map[string]interface{}, lookup KindLookup, ) error
ApplyStrategicMergePatch applies a strategic merge patch to a resource. For known Kubernetes kinds (registered in the lookup scheme), it uses StrategicMergeMapPatch with typed struct tags to enable list-merge-by-key semantics (e.g. containers merged by name). For unknown kinds (CRDs), it falls back to RFC 7386 JSON merge patch. If lookup is nil, fallback is always used.
func CanonicalResourceKey ¶
func CanonicalResourceKey(r *unstructured.Unstructured) string
CanonicalResourceKey returns the unique key for a resource. For namespaced resources: "namespace/kind.name" For cluster-scoped resources: "kind.name"
func GenerateOutputFilename ¶
GenerateOutputFilename creates the output filename based on the pattern <outputDir>/<originalname>-patch-<patchname>.yaml
func InferPatchOp ¶
InferPatchOp infers a patch operation based on the path syntax.
func IsTOMLFormat ¶
IsTOMLFormat detects if the content appears to be TOML-style patch format
func LoadResourcesFromMultiYAML ¶
func LoadResourcesFromMultiYAML(r io.Reader) ([]*unstructured.Unstructured, error)
func ResolveTargetKey ¶
func ResolveTargetKey(resources []*unstructured.Unstructured, target string) (string, error)
ResolveTargetKey resolves a patch target to its canonical resource key. Accepts short names ("my-app"), kind-qualified names ("deployment.my-app"), and namespace-qualified names ("staging/deployment.my-app"). Returns an error if the target matches no resource or is ambiguous.
func SubstituteVariables ¶
func SubstituteVariables(value string, ctx *VariableContext) (interface{}, error)
SubstituteVariables replaces ${values.key} and ${features.flag} patterns with actual values
Types ¶
type ConflictReport ¶
type ConflictReport struct {
ResourceName string
ResourceKind string
Conflicts []PatchConflict
}
ConflictReport describes conflicts detected among strategic merge patches targeting the same resource.
func DetectSMPConflicts ¶
func DetectSMPConflicts( patches []map[string]interface{}, lookup KindLookup, gvk schema.GroupVersionKind, ) (*ConflictReport, error)
DetectSMPConflicts checks pairwise conflicts among strategic merge patches targeting the same resource. For known kinds, it uses MergingMapsHaveConflicts with PatchMetaFromStruct. For unknown kinds, it performs a simple key-overlap check.
func (*ConflictReport) HasConflicts ¶
func (r *ConflictReport) HasConflicts() bool
HasConflicts returns true if any conflicts were detected.
type KindLookup ¶
type KindLookup interface {
LookupKind(gvk schema.GroupVersionKind) (runtime.Object, bool)
}
KindLookup resolves a GroupVersionKind to a typed Go struct, enabling strategic merge patch to read struct tags for merge strategy metadata.
func DefaultKindLookup ¶
func DefaultKindLookup() (KindLookup, error)
DefaultKindLookup returns a KindLookup backed by pkg/kubernetes.Scheme, which has all core Kubernetes and registered CRD types.
type PatchConflict ¶
PatchConflict describes a single conflict between two patches.
type PatchOp ¶
type PatchOp struct {
Op string `json:"op"`
Path string `json:"path"`
ParsedPath []PathPart `json:"patsedpath,omitempty"`
Selector string `json:"selector,omitempty"`
Value interface{} `json:"value"`
}
PatchOp represents a single patch operation to apply to an object.
func ParsePatchLine ¶
ParsePatchLine converts a YAML patch line of form "path[selector]" into a PatchOp.
func (*PatchOp) NormalizePath ¶
NormalizePath parses the Path field and stores the result in ParsedPath.
func (*PatchOp) ValidateAgainst ¶
func (p *PatchOp) ValidateAgainst(obj *unstructured.Unstructured) error
ValidateAgainst checks that the patch operation is valid for the given object.
type PatchSpec ¶
type PatchSpec struct {
Target string
Patch PatchOp // field-level patch (zero value when Strategic is set)
Strategic *StrategicPatch // non-nil for strategic merge patches
}
PatchSpec ties a parsed PatchOp to an optional explicit target. For strategic merge patches, Strategic is non-nil and Patch is zero-value.
func LoadPatchFileWithVariables ¶
func LoadPatchFileWithVariables(r io.Reader, varCtx *VariableContext) ([]PatchSpec, error)
func LoadTOMLPatchFile ¶
func LoadTOMLPatchFile(r io.Reader, varCtx *VariableContext) ([]PatchSpec, error)
func LoadYAMLPatchFile ¶
func LoadYAMLPatchFile(r io.Reader, varCtx *VariableContext) ([]PatchSpec, error)
type PatchableAppSet ¶
type PatchableAppSet struct {
Resources []*unstructured.Unstructured
DocumentSet *YAMLDocumentSet // Preserves original YAML structure
KindLookup KindLookup // Used for strategic merge patches (may be nil)
Patches []struct {
Target string
Patch PatchOp
Strategic *StrategicPatch
}
}
PatchableAppSet represents a collection of resources together with the patches that should be applied to them.
func LoadPatchableAppSet ¶
func NewPatchableAppSet ¶
func NewPatchableAppSet(resources []*unstructured.Unstructured, patches []PatchSpec) (*PatchableAppSet, error)
NewPatchableAppSet constructs a PatchableAppSet from already loaded resources and parsed patch specifications.
func NewPatchableAppSetWithStructure ¶
func NewPatchableAppSetWithStructure(documentSet *YAMLDocumentSet, patches []PatchSpec) (*PatchableAppSet, error)
NewPatchableAppSetWithStructure constructs a PatchableAppSet with YAML structure preservation.
func (*PatchableAppSet) Resolve ¶
func (s *PatchableAppSet) Resolve() ([]*ResourceWithPatches, error)
Resolve groups patches by their target resource and returns them as ResourceWithPatches objects.
func (*PatchableAppSet) ResolveWithConflictCheck ¶
func (s *PatchableAppSet) ResolveWithConflictCheck() ([]*ResourceWithPatches, []*ConflictReport, error)
ResolveWithConflictCheck resolves patches and additionally checks for conflicts among strategic merge patches targeting the same resource.
func (*PatchableAppSet) WritePatchedFiles ¶
func (s *PatchableAppSet) WritePatchedFiles(originalPath string, patchFiles []string, outputDir string) error
WritePatchedFiles writes separate files for each patch set applied. Debug output is enabled based on the current value of the Debug flag.
func (*PatchableAppSet) WritePatchedFilesWithOptions ¶
func (s *PatchableAppSet) WritePatchedFilesWithOptions(originalPath string, patchFiles []string, outputDir string, debug bool) error
WritePatchedFilesWithOptions writes separate files for each patch set applied with explicit debug control, avoiding mutation of the global Debug flag.
func (*PatchableAppSet) WriteToFile ¶
func (s *PatchableAppSet) WriteToFile(filename string) error
WriteToFile writes the patched resources to a file while preserving structure
type PathPart ¶
PathPart represents one segment of a parsed patch path.
func ParsePatchPath ¶
ParsePatchPath parses a patch path with selectors into structured parts.
type RawPatchMap ¶
type RawPatchMap map[string]interface{}
type ResourceWithPatches ¶
type ResourceWithPatches struct {
Name string
Base *unstructured.Unstructured
Patches []PatchOp
StrategicPatches []StrategicPatch // applied before field-level patches
KindLookup KindLookup // may be nil; used for strategic merge
}
ResourceWithPatches ties a base object with the patches that should be applied to it.
func (*ResourceWithPatches) Apply ¶
func (r *ResourceWithPatches) Apply() error
Apply executes all patches on the base object. Strategic merge patches are applied first (setting broad document shape), then field-level patches make precise tweaks on top.
type SchemeKindLookup ¶
SchemeKindLookup implements KindLookup using a runtime.Scheme.
func NewSchemeKindLookup ¶
func NewSchemeKindLookup(scheme *runtime.Scheme) *SchemeKindLookup
NewSchemeKindLookup returns a KindLookup backed by the given scheme.
func (*SchemeKindLookup) LookupKind ¶
func (s *SchemeKindLookup) LookupKind(gvk schema.GroupVersionKind) (runtime.Object, bool)
LookupKind returns a zero-value typed object for the given GVK, or false if the GVK is not registered in the scheme.
type Selector ¶
type Selector struct {
Type string // "index", "key-value", "bracketed"
Index *int
Key string
Value string
Bracketed string
}
Selector represents different types of selectors in TOML headers
type StrategicPatch ¶
type StrategicPatch struct {
Patch map[string]interface{}
}
StrategicPatch represents a partial YAML document for deep merge using Kubernetes strategic merge patch semantics.
type TOMLHeader ¶
TOMLHeader represents a parsed TOML-style header like [kind.name.section.selector]
func ParseTOMLHeader ¶
func ParseTOMLHeader(header string) (*TOMLHeader, error)
ParseTOMLHeader parses a TOML-style header into structured components Examples:
[deployment.app] → Kind: deployment, Name: app
[deployment.app.containers.name=main] → Kind: deployment, Name: app, Sections: [containers], Selector: {Key: name, Value: main}
[deployment.app.ports.0] → Kind: deployment, Name: app, Sections: [ports], Selector: {Index: 0}
[deployment.app.containers[image.name=main]] → Kind: deployment, Name: app, Sections: [containers], Selector: {Bracketed: image.name=main}
func (*TOMLHeader) ResolveTOMLPath ¶
func (h *TOMLHeader) ResolveTOMLPath() (resourceTarget, fieldPath string, err error)
ResolveTOMLPath converts a TOML header to resource target and field path
func (*TOMLHeader) String ¶
func (h *TOMLHeader) String() string
String returns a string representation of the TOML header
type TargetedPatch ¶
type VariableContext ¶
VariableContext holds variables for substitution
type YAMLDocument ¶
type YAMLDocument struct {
Node *yaml.Node
Resource *unstructured.Unstructured
Original string // Original YAML content with comments
Order int // Original position in file
}
YAMLDocument represents a single YAML document with preserved structure
func (*YAMLDocument) ApplyPatchesToDocument ¶
func (doc *YAMLDocument) ApplyPatchesToDocument(patches []PatchOp) error
ApplyPatchesToDocument applies patches to a YAML document while preserving structure
func (*YAMLDocument) ApplyStrategicPatchesToDocument ¶
func (doc *YAMLDocument) ApplyStrategicPatchesToDocument(patches []StrategicPatch, lookup KindLookup) error
ApplyStrategicPatchesToDocument applies strategic merge patches to a YAML document while preserving structure. The resource is mutated in place via ApplyStrategicMergePatch, then the YAML node is updated to reflect the new state while preserving comments.
func (*YAMLDocument) UpdateDocumentFromResource ¶
func (doc *YAMLDocument) UpdateDocumentFromResource() error
UpdateDocumentFromResource updates a document's YAML node from its resource
type YAMLDocumentSet ¶
type YAMLDocumentSet struct {
Documents []*YAMLDocument
Separator string // Document separator (usually "---")
}
YAMLDocumentSet holds multiple YAML documents with preserved order and comments
func LoadResourcesWithStructure ¶
func LoadResourcesWithStructure(r io.Reader) (*YAMLDocumentSet, error)
LoadResourcesWithStructure loads YAML resources while preserving comments and order
func (*YAMLDocumentSet) Copy ¶
func (set *YAMLDocumentSet) Copy() (*YAMLDocumentSet, error)
Copy creates a deep copy of the YAMLDocumentSet
func (*YAMLDocumentSet) FindDocumentByKindAndName ¶
func (set *YAMLDocumentSet) FindDocumentByKindAndName(kind, name string) *YAMLDocument
FindDocumentByKindAndName finds a document by resource kind and name
func (*YAMLDocumentSet) FindDocumentByKindNameAndNamespace ¶
func (set *YAMLDocumentSet) FindDocumentByKindNameAndNamespace(kind, name, namespace string) *YAMLDocument
FindDocumentByKindNameAndNamespace finds a document by kind, name, and namespace. All three must match for a result.
func (*YAMLDocumentSet) FindDocumentByName ¶
func (set *YAMLDocumentSet) FindDocumentByName(name string) *YAMLDocument
FindDocumentByName finds a document by resource name
func (*YAMLDocumentSet) GetResources ¶
func (set *YAMLDocumentSet) GetResources() []*unstructured.Unstructured
GetResources returns the unstructured resources in order
func (*YAMLDocumentSet) WriteToFile ¶
func (set *YAMLDocumentSet) WriteToFile(filename string) error
WriteToFile writes the document set to a file with preserved structure