patch

package
v0.1.0-alpha.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 12, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

README

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.

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)
# Target a specific resource by kind and name
[deployment.myapp.spec]
replicas = 3

[deployment.myapp.spec.template.spec.containers.0]
image = "${app.image}:${app.tag}"
resources.requests.cpu = "200m"
resources.requests.memory = "256Mi"

# Append to a list with .-
[deployment.myapp.spec.template.spec.containers.-]
name = "sidecar"
image = "envoy:latest"
YAML Format
target:
  kind: Deployment
  name: myapp
patches:
  - path: spec.replicas
    value: 3
  - path: spec.template.spec.containers[0].image
    value: "nginx:latest"

Quick Start

import "github.com/go-kure/kure/pkg/patch"

// Load patches from file
file, _ := os.Open("patches/customize.kpatch")
specs, err := patch.LoadPatchFile(file)

// Create patchable set with resources and patches
patchSet, err := patch.NewPatchableAppSet(resources, specs)

// Resolve targets and apply
resolved, err := patchSet.Resolve()
for _, r := range resolved {
    err := r.Apply()
}

// Write patched output
err = patchSet.WriteToFile("output.yaml")

Key Features

Variable Substitution

Patches support variable references that resolve against a parameter context:

[deployment.myapp.spec.template.spec.containers.0]
image = "${registry}/${image}:${tag}"
replicas = "${replicas}"
varCtx := &patch.VariableContext{
    Variables: map[string]interface{}{
        "registry": "docker.io",
        "image":    "myapp",
        "tag":      "v1.0.0",
        "replicas": 3,
    },
}
specs, err := patch.LoadPatchFileWithVariables(file, varCtx)
List Selectors

Target specific items in lists using selectors:

# By index
[deployment.myapp.spec.template.spec.containers.0]
image = "updated:latest"

# Append to list
[deployment.myapp.spec.template.spec.containers.-]
name = "new-container"

# By field value (name selector)
[deployment.myapp.spec.template.spec.containers.{name=myapp}]
image = "updated:latest"
Structure Preservation

When using NewPatchableAppSetWithStructure, the original YAML document structure is preserved through patching, maintaining comments, key ordering, and formatting.

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
  • launcher - Uses patches in kurel package system
  • io - YAML parsing for patch targets

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

Core Types

PatchableAppSet - Manages resources and their patches
PatchOp         - Individual patch operation
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

Constants

This section is empty.

Variables

View Source
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 GenerateOutputFilename

func GenerateOutputFilename(originalPath, patchPath, outputDir string) string

GenerateOutputFilename creates the output filename based on the pattern <outputDir>/<originalname>-patch-<patchname>.yaml

func InferPatchOp

func InferPatchOp(path string) string

InferPatchOp infers a patch operation based on the path syntax.

func IsTOMLFormat

func IsTOMLFormat(content string) bool

IsTOMLFormat detects if the content appears to be TOML-style patch format

func LoadResourcesFromMultiYAML

func LoadResourcesFromMultiYAML(r io.Reader) ([]*unstructured.Unstructured, error)

func SubstituteVariables

func SubstituteVariables(value string, ctx *VariableContext) (interface{}, error)

SubstituteVariables replaces ${values.key} and ${features.flag} patterns with actual values

Types

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

func ParsePatchLine(key string, value interface{}) (PatchOp, error)

ParsePatchLine converts a YAML patch line of form "path[selector]" into a PatchOp.

func (*PatchOp) NormalizePath

func (p *PatchOp) NormalizePath() error

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
}

PatchSpec ties a parsed PatchOp to an optional explicit target.

func LoadPatchFile

func LoadPatchFile(r io.Reader) ([]PatchSpec, error)

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
	Patches     []struct {
		Target string
		Patch  PatchOp
	}
}

PatchableAppSet represents a collection of resources together with the patches that should be applied to them.

func LoadPatchableAppSet

func LoadPatchableAppSet(resourceReaders []io.Reader, patchReader io.Reader) (*PatchableAppSet, error)

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) WritePatchedFiles

func (s *PatchableAppSet) WritePatchedFiles(originalPath string, patchFiles []string, outputDir string) error

WritePatchedFiles writes separate files for each patch set applied

func (*PatchableAppSet) WriteToFile

func (s *PatchableAppSet) WriteToFile(filename string) error

WriteToFile writes the patched resources to a file while preserving structure

type PathPart

type PathPart struct {
	Field      string
	MatchType  string // "", "index", or "key"
	MatchValue string
}

PathPart represents one segment of a parsed patch path.

func ParsePatchPath

func ParsePatchPath(path string) ([]PathPart, error)

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
}

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.

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 TOMLHeader

type TOMLHeader struct {
	Kind     string
	Name     string
	Sections []string
	Selector *Selector
}

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 TargetedPatch struct {
	Target string                 `yaml:"target"`
	Patch  map[string]interface{} `yaml:"patch"`
}

type VariableContext

type VariableContext struct {
	Values   map[string]interface{}
	Features map[string]bool
}

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) 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) 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

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL