diffprocessor

package
v0.5.0-rc1 Latest Latest
Warning

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

Go to latest
Published: Dec 9, 2025 License: Apache-2.0 Imports: 39 Imported by: 0

Documentation

Overview

Package diffprocessor contains the logic to calculate and render diffs.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CachedFunctionProvider

type CachedFunctionProvider struct {
	// contains filtered or unexported fields
}

CachedFunctionProvider lazy-loads and caches functions with reuse annotations. This is appropriate for the comp command where many XRs use the same composition, allowing Docker containers to be reused across renders.

func (*CachedFunctionProvider) Cleanup

func (p *CachedFunctionProvider) Cleanup(ctx context.Context) error

Cleanup stops and removes Docker containers created during function execution.

func (*CachedFunctionProvider) GetFunctionsForComposition

func (p *CachedFunctionProvider) GetFunctionsForComposition(comp *apiextensionsv1.Composition) ([]pkgv1.Function, error)

GetFunctionsForComposition fetches and caches functions on first call per composition.

type CompDiffProcessor added in v0.2.0

type CompDiffProcessor interface {
	DiffComposition(ctx context.Context, stdout io.Writer, compositions []*un.Unstructured, namespace string) error
	Initialize(ctx context.Context) error
}

CompDiffProcessor defines the interface for composition diffing.

func NewCompDiffProcessor added in v0.2.0

func NewCompDiffProcessor(xrProc DiffProcessor, compositionClient xp.CompositionClient, opts ...ProcessorOption) CompDiffProcessor

NewCompDiffProcessor creates a new DefaultCompDiffProcessor.

type ComponentFactories

type ComponentFactories struct {
	// ResourceManager creates a ResourceManager
	ResourceManager func(client k8.ResourceClient, defClient xp.DefinitionClient, treeClient xp.ResourceTreeClient, logger logging.Logger) ResourceManager

	// SchemaValidator creates a SchemaValidator
	SchemaValidator func(schema k8.SchemaClient, def xp.DefinitionClient, logger logging.Logger) SchemaValidator

	// DiffCalculator creates a DiffCalculator
	DiffCalculator func(apply k8.ApplyClient, tree xp.ResourceTreeClient, resourceManager ResourceManager, logger logging.Logger, diffOptions renderer.DiffOptions) DiffCalculator

	// DiffRenderer creates a DiffRenderer
	DiffRenderer func(logger logging.Logger, diffOptions renderer.DiffOptions) renderer.DiffRenderer

	// RequirementsProvider creates an ExtraResourceProvider
	RequirementsProvider func(res k8.ResourceClient, def xp.EnvironmentClient, renderFunc RenderFunc, logger logging.Logger) *RequirementsProvider

	// FunctionProvider creates a FunctionProvider
	FunctionProvider func(fnClient xp.FunctionClient, logger logging.Logger) FunctionProvider
}

ComponentFactories contains factory functions for creating processor components.

type DefaultCompDiffProcessor added in v0.2.0

type DefaultCompDiffProcessor struct {
	// contains filtered or unexported fields
}

DefaultCompDiffProcessor implements CompDiffProcessor.

func (*DefaultCompDiffProcessor) DiffComposition added in v0.2.0

func (p *DefaultCompDiffProcessor) DiffComposition(ctx context.Context, stdout io.Writer, compositions []*un.Unstructured, namespace string) error

DiffComposition processes composition changes and shows impact on existing XRs.

func (*DefaultCompDiffProcessor) Initialize added in v0.2.0

func (p *DefaultCompDiffProcessor) Initialize(ctx context.Context) error

Initialize loads required resources.

type DefaultDiffCalculator

type DefaultDiffCalculator struct {
	// contains filtered or unexported fields
}

DefaultDiffCalculator implements the DiffCalculator interface.

func (*DefaultDiffCalculator) CalculateDiff

func (c *DefaultDiffCalculator) CalculateDiff(ctx context.Context, composite *un.Unstructured, desired *un.Unstructured) (*dt.ResourceDiff, error)

CalculateDiff calculates the diff for a single resource.

func (*DefaultDiffCalculator) CalculateDiffs

func (c *DefaultDiffCalculator) CalculateDiffs(ctx context.Context, xr *cmp.Unstructured, desired render.Outputs) (map[string]*dt.ResourceDiff, error)

CalculateDiffs computes all diffs including removals for the rendered resources. This is the primary method that most code should use.

func (*DefaultDiffCalculator) CalculateNonRemovalDiffs

func (c *DefaultDiffCalculator) CalculateNonRemovalDiffs(ctx context.Context, xr *cmp.Unstructured, parentComposite *un.Unstructured, desired render.Outputs) (map[string]*dt.ResourceDiff, map[string]bool, error)

CalculateNonRemovalDiffs computes diffs for modified/added resources and returns the set of rendered resource keys for removal detection.

TWO-PHASE DIFF ALGORITHM: This method implements Phase 1 of our two-phase diff calculation. The two-phase approach is necessary to correctly handle nested XRs (Composite Resources that themselves create other Composite Resources).

WHY TWO PHASES? When processing nested XRs, we must:

  1. Phase 1 (this method): Calculate diffs for all rendered resources (adds/modifications) and build a set of "rendered resource keys" that tracks what was generated
  2. Phase 2 (CalculateRemovedResourceDiffs): Compare cluster state against rendered resources to identify removals

The separation is critical because:

  • Nested XRs are processed recursively BETWEEN these phases
  • Nested XRs generate additional composed resources that must be added to the "rendered resources" set before removal detection
  • If we detected removals too early, we'd falsely identify nested XR resources as "to be removed" before they've been processed

EXAMPLE SCENARIO:

Parent XR renders: [Resource-A, NestedXR-B]
NestedXR-B renders: [Resource-C, Resource-D]

Without two phases:
  - We'd see cluster has [Resource-A, Resource-C, Resource-D] from prior render
  - We'd see new render has [Resource-A, NestedXR-B]
  - We'd INCORRECTLY mark Resource-C and Resource-D as removed

With two phases:
  Phase 1: Calculate diffs for [Resource-A, NestedXR-B], track as rendered
  Process nested: Recurse into NestedXR-B, add Resource-C and Resource-D to rendered set
  Phase 2: Now see [Resource-A, NestedXR-B, Resource-C, Resource-D] as rendered
           No false removal detection!

Returns: (diffs map, rendered resource keys, error).

func (*DefaultDiffCalculator) CalculateRemovedResourceDiffs

func (c *DefaultDiffCalculator) CalculateRemovedResourceDiffs(ctx context.Context, xr *un.Unstructured, renderedResources map[string]bool) (map[string]*dt.ResourceDiff, error)

CalculateRemovedResourceDiffs identifies resources that would be removed and calculates their diffs.

func (*DefaultDiffCalculator) SetDiffOptions

func (c *DefaultDiffCalculator) SetDiffOptions(options renderer.DiffOptions)

SetDiffOptions updates the diff options used by the calculator.

type DefaultDiffProcessor

type DefaultDiffProcessor struct {
	// contains filtered or unexported fields
}

DefaultDiffProcessor implements DiffProcessor with modular components.

func (*DefaultDiffProcessor) DiffSingleResource

func (p *DefaultDiffProcessor) DiffSingleResource(ctx context.Context, res *un.Unstructured, compositionProvider types.CompositionProvider) (map[string]*dt.ResourceDiff, error)

DiffSingleResource handles one resource at a time and returns its diffs. The compositionProvider function is called to obtain the composition to use for rendering. This is the public method for top-level XR diffing, which enables removal detection.

func (*DefaultDiffProcessor) Initialize

func (p *DefaultDiffProcessor) Initialize(ctx context.Context) error

Initialize loads required resources like CRDs and environment configs.

func (*DefaultDiffProcessor) PerformDiff

func (p *DefaultDiffProcessor) PerformDiff(ctx context.Context, stdout io.Writer, resources []*un.Unstructured, compositionProvider types.CompositionProvider) error

PerformDiff processes resources using a composition provider function.

func (*DefaultDiffProcessor) ProcessNestedXRs added in v0.3.0

func (p *DefaultDiffProcessor) ProcessNestedXRs(
	ctx context.Context,
	composedResources []cpd.Unstructured,
	compositionProvider types.CompositionProvider,
	parentResourceID string,
	parentXR *cmp.Unstructured,
	observedResources []cpd.Unstructured,
	depth int,
) (map[string]*dt.ResourceDiff, map[string]bool, error)

ProcessNestedXRs recursively processes composed resources that are themselves XRs. It checks each composed resource to see if it's an XR, and if so, processes it through its own composition pipeline to get the full tree of diffs. It preserves the identity of existing nested XRs to ensure accurate diff calculation. observedResources should contain the observed resources from the parent XR's resource tree.

func (*DefaultDiffProcessor) RenderWithRequirements

func (p *DefaultDiffProcessor) RenderWithRequirements(
	ctx context.Context,
	xr *cmp.Unstructured,
	comp *apiextensionsv1.Composition,
	fns []pkgv1.Function,
	resourceID string,
	observedResources []cpd.Unstructured,
) (render.Outputs, error)

RenderWithRequirements performs an iterative rendering process that discovers and fulfills requirements.

func (*DefaultDiffProcessor) SanitizeXR

func (p *DefaultDiffProcessor) SanitizeXR(res *un.Unstructured, resourceID string) (*cmp.Unstructured, bool, error)

SanitizeXR makes an XR into a valid unstructured object that we can use in a dry-run apply.

type DefaultFunctionProvider

type DefaultFunctionProvider struct {
	// contains filtered or unexported fields
}

DefaultFunctionProvider fetches functions from the cluster on each call. This is appropriate for the xr command where each XR is processed independently.

func (*DefaultFunctionProvider) Cleanup

Cleanup is a no-op for DefaultFunctionProvider as it doesn't create any resources.

func (*DefaultFunctionProvider) GetFunctionsForComposition

func (p *DefaultFunctionProvider) GetFunctionsForComposition(comp *apiextensionsv1.Composition) ([]pkgv1.Function, error)

GetFunctionsForComposition fetches functions from the cluster.

type DefaultResourceManager

type DefaultResourceManager struct {
	// contains filtered or unexported fields
}

DefaultResourceManager implements ResourceManager interface.

func (*DefaultResourceManager) FetchCurrentObject

func (m *DefaultResourceManager) FetchCurrentObject(ctx context.Context, composite *un.Unstructured, desired *un.Unstructured) (*un.Unstructured, bool, error)

FetchCurrentObject retrieves the current state of the object from the cluster It returns the current object, a boolean indicating if it's a new object, and any error.

func (*DefaultResourceManager) FetchObservedResources

func (m *DefaultResourceManager) FetchObservedResources(ctx context.Context, xr *cmp.Unstructured) ([]cpd.Unstructured, error)

FetchObservedResources fetches the observed composed resources for the given XR. Returns a flat slice of composed resources suitable for render.Inputs.ObservedResources.

func (*DefaultResourceManager) UpdateOwnerRefs

func (m *DefaultResourceManager) UpdateOwnerRefs(ctx context.Context, parent *un.Unstructured, child *un.Unstructured)

UpdateOwnerRefs ensures all OwnerReferences have valid UIDs. It handles Claims and XRs differently according to Crossplane's ownership model: - Claims should never be controller owners of composed resources. - XRs should be controller owners and use their UID for matching references.

type DefaultSchemaValidator

type DefaultSchemaValidator struct {
	// contains filtered or unexported fields
}

DefaultSchemaValidator implements SchemaValidator interface.

func (*DefaultSchemaValidator) EnsureComposedResourceCRDs

func (v *DefaultSchemaValidator) EnsureComposedResourceCRDs(ctx context.Context, resources []*un.Unstructured) error

EnsureComposedResourceCRDs checks if we have all the CRDs needed for the cpd resources and fetches any missing ones from the cluster.

func (*DefaultSchemaValidator) GetCRDs

GetCRDs returns the current CRDs.

func (*DefaultSchemaValidator) LoadCRDs

func (v *DefaultSchemaValidator) LoadCRDs(ctx context.Context) error

LoadCRDs loads CRDs from the cluster.

func (*DefaultSchemaValidator) ValidateResources

func (v *DefaultSchemaValidator) ValidateResources(ctx context.Context, xr *un.Unstructured, composed []cpd.Unstructured) error

ValidateResources validates resources using schema validation.

func (*DefaultSchemaValidator) ValidateScopeConstraints

func (v *DefaultSchemaValidator) ValidateScopeConstraints(ctx context.Context, resource *un.Unstructured, expectedNamespace string, isClaimRoot bool) error

ValidateScopeConstraints validates that a resource has the appropriate namespace for its scope and that namespaced resources match the expected namespace (no cross-namespace refs).

type DiffCalculator

type DiffCalculator interface {
	// CalculateDiff computes the diff for a single resource
	CalculateDiff(ctx context.Context, composite *un.Unstructured, desired *un.Unstructured) (*dt.ResourceDiff, error)

	// CalculateDiffs computes all diffs including removals for the rendered resources.
	// This is the primary method that most code should use.
	CalculateDiffs(ctx context.Context, xr *cmp.Unstructured, desired render.Outputs) (map[string]*dt.ResourceDiff, error)

	// CalculateNonRemovalDiffs computes diffs for modified/added resources and returns
	// the set of rendered resource keys. This is used by nested XR processing.
	// parentComposite should be nil for root XRs, and the parent XR for nested XRs.
	// Returns: (diffs map, rendered resource keys, error)
	CalculateNonRemovalDiffs(ctx context.Context, xr *cmp.Unstructured, parentComposite *un.Unstructured, desired render.Outputs) (map[string]*dt.ResourceDiff, map[string]bool, error)

	// CalculateRemovedResourceDiffs identifies resources that exist in the cluster but are not
	// in the rendered set. This is called after nested XR processing is complete.
	CalculateRemovedResourceDiffs(ctx context.Context, xr *un.Unstructured, renderedResources map[string]bool) (map[string]*dt.ResourceDiff, error)
}

DiffCalculator calculates differences between resources.

func NewDiffCalculator

func NewDiffCalculator(apply k8.ApplyClient, tree xp.ResourceTreeClient, resourceManager ResourceManager, logger logging.Logger, diffOptions renderer.DiffOptions) DiffCalculator

NewDiffCalculator creates a new DefaultDiffCalculator.

type DiffProcessor

type DiffProcessor interface {
	// PerformDiff processes resources using a composition provider function
	PerformDiff(ctx context.Context, stdout io.Writer, resources []*un.Unstructured, compositionProvider types.CompositionProvider) error

	// DiffSingleResource processes a single resource and returns its diffs
	DiffSingleResource(ctx context.Context, res *un.Unstructured, compositionProvider types.CompositionProvider) (map[string]*dt.ResourceDiff, error)

	// Initialize loads required resources like CRDs and environment configs
	Initialize(ctx context.Context) error
}

DiffProcessor interface for processing resources.

func NewDiffProcessor

func NewDiffProcessor(k8cs k8.Clients, xpcs xp.Clients, opts ...ProcessorOption) DiffProcessor

NewDiffProcessor creates a new DefaultDiffProcessor with the provided options.

type FunctionProvider

type FunctionProvider interface {
	// GetFunctionsForComposition returns the functions needed to render a composition.
	GetFunctionsForComposition(comp *apiextensionsv1.Composition) ([]pkgv1.Function, error)

	// Cleanup stops and removes any resources created during function execution.
	// For providers that don't create resources (like DefaultFunctionProvider), this is a no-op.
	Cleanup(ctx context.Context) error
}

FunctionProvider provides functions for rendering compositions. Different implementations can fetch functions on-demand or return cached functions.

func NewCachedFunctionProvider

func NewCachedFunctionProvider(fnClient xp.FunctionClient, logger logging.Logger) FunctionProvider

NewCachedFunctionProvider creates a new CachedFunctionProvider.

func NewDefaultFunctionProvider

func NewDefaultFunctionProvider(fnClient xp.FunctionClient, logger logging.Logger) FunctionProvider

NewDefaultFunctionProvider creates a new DefaultFunctionProvider.

type ProcessorConfig

type ProcessorConfig struct {
	// Namespace is the namespace to use for resources
	Namespace string

	// Colorize determines whether to use colors in the diff output
	Colorize bool

	// Compact determines whether to show a compact diff format
	Compact bool

	// MaxNestedDepth is the maximum depth for recursive nested XR processing
	MaxNestedDepth int

	// IncludeManual determines whether to include XRs with Manual update policy in composition diffs
	IncludeManual bool

	// IgnorePaths is a list of paths to ignore when calculating diffs
	IgnorePaths []string

	// Logger is the logger to use
	Logger logging.Logger

	// RenderFunc is the function to use for rendering resources
	RenderFunc RenderFunc

	// RenderMutex is the mutex used to serialize render operations (for internal use)
	RenderMutex *sync.Mutex

	// Factories provide factory functions for creating components
	Factories ComponentFactories
}

ProcessorConfig contains configuration for the DiffProcessor.

func (*ProcessorConfig) GetDiffOptions

func (c *ProcessorConfig) GetDiffOptions() renderer.DiffOptions

GetDiffOptions returns DiffOptions based on the ProcessorConfig.

func (*ProcessorConfig) SetDefaultFactories

func (c *ProcessorConfig) SetDefaultFactories()

SetDefaultFactories sets default component factory functions if not already set.

type ProcessorOption

type ProcessorOption func(*ProcessorConfig)

ProcessorOption defines a function that can modify a ProcessorConfig.

func WithColorize

func WithColorize(colorize bool) ProcessorOption

WithColorize sets whether to use colors in diff output.

func WithCompact

func WithCompact(compact bool) ProcessorOption

WithCompact sets whether to use compact diff format.

func WithDiffCalculatorFactory

WithDiffCalculatorFactory sets the DiffCalculator factory function.

func WithDiffRendererFactory

func WithDiffRendererFactory(factory func(logging.Logger, renderer.DiffOptions) renderer.DiffRenderer) ProcessorOption

WithDiffRendererFactory sets the DiffRenderer factory function.

func WithFunctionProviderFactory

func WithFunctionProviderFactory(factory func(xp.FunctionClient, logging.Logger) FunctionProvider) ProcessorOption

WithFunctionProviderFactory sets the FunctionProvider factory function.

func WithIgnorePaths

func WithIgnorePaths(ignorePaths []string) ProcessorOption

WithIgnorePaths sets the paths to ignore when calculating diffs.

func WithIncludeManual added in v0.3.0

func WithIncludeManual(includeManual bool) ProcessorOption

WithIncludeManual sets whether to include XRs with Manual update policy in composition diffs.

func WithLogger

func WithLogger(logger logging.Logger) ProcessorOption

WithLogger sets the logger for the processor.

func WithMaxNestedDepth added in v0.3.0

func WithMaxNestedDepth(depth int) ProcessorOption

WithMaxNestedDepth sets the maximum depth for recursive nested XR processing.

func WithNamespace

func WithNamespace(namespace string) ProcessorOption

WithNamespace sets the namespace for the processor.

func WithRenderFunc

func WithRenderFunc(renderFn RenderFunc) ProcessorOption

WithRenderFunc sets the render function for the processor.

func WithRenderMutex added in v0.2.1

func WithRenderMutex(mu *sync.Mutex) ProcessorOption

WithRenderMutex sets the mutex for serializing render operations.

func WithRequirementsProviderFactory

func WithRequirementsProviderFactory(factory func(k8.ResourceClient, xp.EnvironmentClient, RenderFunc, logging.Logger) *RequirementsProvider) ProcessorOption

WithRequirementsProviderFactory sets the RequirementsProvider factory function.

func WithResourceManagerFactory

WithResourceManagerFactory sets the ResourceManager factory function.

func WithSchemaValidatorFactory

func WithSchemaValidatorFactory(factory func(k8.SchemaClient, xp.DefinitionClient, logging.Logger) SchemaValidator) ProcessorOption

WithSchemaValidatorFactory sets the SchemaValidator factory function.

type RenderFunc

type RenderFunc func(ctx context.Context, log logging.Logger, in render.Inputs) (render.Outputs, error)

RenderFunc defines the signature of a function that can render resources.

type RequirementsProvider

type RequirementsProvider struct {
	// contains filtered or unexported fields
}

RequirementsProvider consolidates requirement processing with caching.

func NewRequirementsProvider

func NewRequirementsProvider(res k8.ResourceClient, env xp.EnvironmentClient, renderFn RenderFunc, logger logging.Logger) *RequirementsProvider

NewRequirementsProvider creates a new provider with caching.

func (*RequirementsProvider) ClearCache

func (p *RequirementsProvider) ClearCache()

ClearCache clears all cached resources.

func (*RequirementsProvider) Initialize

func (p *RequirementsProvider) Initialize(ctx context.Context) error

Initialize pre-fetches resources like environment configs.

func (*RequirementsProvider) ProvideRequirements

func (p *RequirementsProvider) ProvideRequirements(ctx context.Context, requirements map[string]v1.Requirements, xrNamespace string) ([]*un.Unstructured, error)

ProvideRequirements provides requirements, checking cache first.

type ResourceManager

type ResourceManager interface {
	// FetchCurrentObject retrieves the current state of an object from the cluster
	FetchCurrentObject(ctx context.Context, composite *un.Unstructured, desired *un.Unstructured) (*un.Unstructured, bool, error)

	// UpdateOwnerRefs ensures all OwnerReferences have valid UIDs
	UpdateOwnerRefs(ctx context.Context, parent *un.Unstructured, child *un.Unstructured)

	// FetchObservedResources fetches the observed composed resources for the given XR
	FetchObservedResources(ctx context.Context, xr *cmp.Unstructured) ([]cpd.Unstructured, error)
}

ResourceManager handles resource-related operations like fetching, updating owner refs, and identifying resources to be removed.

func NewResourceManager

func NewResourceManager(client k8.ResourceClient, defClient xp.DefinitionClient, treeClient xp.ResourceTreeClient, logger logging.Logger) ResourceManager

NewResourceManager creates a new DefaultResourceManager.

type SchemaValidator

type SchemaValidator interface {
	// ValidateResources validates resources using schema validation
	ValidateResources(ctx context.Context, xr *un.Unstructured, composed []cpd.Unstructured) error

	// EnsureComposedResourceCRDs ensures we have all required CRDs for validation
	EnsureComposedResourceCRDs(ctx context.Context, resources []*un.Unstructured) error

	// ValidateScopeConstraints validates that a resource has the appropriate namespace for its scope
	// and that namespaced resources match the expected namespace (no cross-namespace refs)
	ValidateScopeConstraints(ctx context.Context, resource *un.Unstructured, expectedNamespace string, isClaimRoot bool) error
}

SchemaValidator handles validation of resources against CRD schemas.

func NewSchemaValidator

func NewSchemaValidator(sClient k8.SchemaClient, dClient xp.DefinitionClient, logger logging.Logger) SchemaValidator

NewSchemaValidator creates a new DefaultSchemaValidator.

type XRDiffResult

type XRDiffResult struct {
	// Diffs contains the downstream resource diffs for this XR (keyed by resource ID).
	// Empty map means no changes detected.
	Diffs map[string]*dt.ResourceDiff
	// Error contains any error that occurred while processing this XR.
	// nil means processing was successful.
	Error error
}

XRDiffResult captures the result of processing a single XR against a composition.

func (*XRDiffResult) HasChanges

func (r *XRDiffResult) HasChanges() bool

HasChanges returns true if this XR has downstream resource changes.

func (*XRDiffResult) HasError

func (r *XRDiffResult) HasError() bool

HasError returns true if this XR encountered a processing error.

Jump to

Keyboard shortcuts

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