Documentation
¶
Overview ¶
Package diffprocessor contains the logic to calculate and render diffs.
Index ¶
- Constants
- Variables
- func CleanupDetached(ctx context.Context, c Cleaner, logger logging.Logger)
- func CopyLabels(source, target *un.Unstructured, keys ...string)
- func DetermineExitCode(err error, hasDiffs bool) int
- func Interrupted(ctx context.Context) bool
- func IsSchemaValidationError(err error) bool
- func NewOutputError(resourceID string, err error) dt.OutputError
- func NormalizeRenderVersion(version string) string
- func UncomparableRenderImageWarning(image string) string
- func ValidateMinRenderImage(image string) error
- func ValidateMinRenderVersion(version string) error
- type AnalyzeOn
- type CRDDefaulter
- type CachedFunctionProvider
- type ChangeScope
- type Cleaner
- type CompDiffProcessor
- type ComponentFactories
- type CompositeResolver
- type DefaultCompDiffProcessor
- type DefaultDiffCalculator
- func (c *DefaultDiffCalculator) CalculateDiff(ctx context.Context, composite *un.Unstructured, desired *un.Unstructured) (*dt.ResourceDiff, error)
- func (c *DefaultDiffCalculator) CalculateDiffs(ctx context.Context, xr *cmp.Unstructured, desired render.CompositionOutputs) (map[string]*dt.ResourceDiff, error)
- func (c *DefaultDiffCalculator) CalculateNonRemovalDiffs(ctx context.Context, xr *cmp.Unstructured, desired render.CompositionOutputs) (map[string]*dt.ResourceDiff, dtypes.RenderedResources, error)
- func (c *DefaultDiffCalculator) CalculateRemovedResourceDiffs(ctx context.Context, xr *un.Unstructured, rendered dtypes.RenderedResources) (map[string]*dt.ResourceDiff, error)
- func (c *DefaultDiffCalculator) SetDiffOptions(options renderer.DiffOptions)
- type DefaultDiffProcessor
- func (p *DefaultDiffProcessor) Cleanup(ctx context.Context) error
- func (p *DefaultDiffProcessor) DiffSingleResource(ctx context.Context, res *un.Unstructured, ...) (map[string]*dt.ResourceDiff, error)
- func (p *DefaultDiffProcessor) Initialize(ctx context.Context) error
- func (p *DefaultDiffProcessor) PerformDiff(ctx context.Context, resources []*un.Unstructured, ...) (bool, error)
- func (p *DefaultDiffProcessor) ProcessNestedXRs(ctx context.Context, composedResources []cpd.Unstructured, ...) (map[string]*dt.ResourceDiff, types.RenderedResources, error)
- func (p *DefaultDiffProcessor) RenderToStableState(ctx context.Context, xr *cmp.Unstructured, comp *apiextensionsv1.Composition, ...) (render.CompositionOutputs, error)
- func (p *DefaultDiffProcessor) SanitizeXR(res *un.Unstructured, resourceID string) (*cmp.Unstructured, bool, error)
- type DefaultFunctionProvider
- type DefaultResourceManager
- func (m *DefaultResourceManager) FetchCurrentObject(ctx context.Context, composite *un.Unstructured, desired *un.Unstructured) (*un.Unstructured, bool, error)
- func (m *DefaultResourceManager) FetchObservedResources(ctx context.Context, xr *cmp.Unstructured) ([]cpd.Unstructured, error)
- func (m *DefaultResourceManager) UpdateOwnerRefs(ctx context.Context, parent *un.Unstructured, child *un.Unstructured)
- type DefaultSchemaValidator
- func (v *DefaultSchemaValidator) EnsureComposedResourceCRDs(ctx context.Context, resources []*un.Unstructured) error
- func (v *DefaultSchemaValidator) GetCRDs() []*extv1.CustomResourceDefinition
- func (v *DefaultSchemaValidator) LoadCRDs(ctx context.Context) error
- func (v *DefaultSchemaValidator) ValidateResources(ctx context.Context, xr *un.Unstructured, composed []cpd.Unstructured) error
- func (v *DefaultSchemaValidator) ValidateScopeConstraints(ctx context.Context, resource *un.Unstructured, expectedNamespace string, ...) error
- type Defaulter
- type DefaultingPolicy
- type DiffCalculator
- type DiffProcessor
- type DryRunOn
- type EffectiveComposite
- type EngineRenderFn
- type EnvInjectingFunctionProvider
- type FunctionProvider
- func NewCachedFunctionProvider(fnClient xp.FunctionClient, logger logging.Logger) FunctionProvider
- func NewDefaultFunctionProvider(fnClient xp.FunctionClient, logger logging.Logger) FunctionProvider
- func NewEnvInjectingFunctionProvider(inner FunctionProvider, envs map[string]string, logger logging.Logger) FunctionProvider
- func NewRegistryOverrideFunctionProvider(inner FunctionProvider, registry string, logger logging.Logger) FunctionProvider
- type InputValidator
- type InputValidatorFactory
- type ProcessorConfig
- type ProcessorOption
- func WithAnalyzeOn(analyzeOn AnalyzeOn) ProcessorOption
- func WithColorize(colorize bool) ProcessorOption
- func WithCompact(compact bool) ProcessorOption
- func WithCrossplaneImage(image string) ProcessorOption
- func WithCrossplaneRenderBinary(path string) ProcessorOption
- func WithCrossplaneVersion(version string) ProcessorOption
- func WithDefaulterFactory(factory func(k8.SchemaClient, xp.DefinitionClient, DefaultingPolicy) Defaulter) ProcessorOption
- func WithDiffCalculatorFactory(...) ProcessorOption
- func WithDiffRendererFactory(factory func(logging.Logger, renderer.DiffOptions) renderer.DiffRenderer) ProcessorOption
- func WithDryRunOn(dryRunOn DryRunOn) ProcessorOption
- func WithEventualState(enabled bool) ProcessorOption
- func WithFunctionCredentials(creds []corev1.Secret) ProcessorOption
- func WithFunctionProviderFactory(factory func(xp.FunctionClient, logging.Logger) FunctionProvider) ProcessorOption
- func WithFunctionRegistryOverride(registry string) ProcessorOption
- func WithIgnorePaths(ignorePaths []string) ProcessorOption
- func WithIncludeManual(includeManual bool) ProcessorOption
- func WithInputValidatorFactory(factory InputValidatorFactory) ProcessorOption
- func WithLogger(logger logging.Logger) ProcessorOption
- func WithMaxNestedDepth(depth int) ProcessorOption
- func WithMaxRecvMessageSize(mb int) ProcessorOption
- func WithMaxRenderIterations(maxIterations int) ProcessorOption
- func WithMinimizeComposition(minimize bool) ProcessorOption
- func WithOutputFormat(format renderer.OutputFormat) ProcessorOption
- func WithOutputVersion(version renderer.OutputVersion) ProcessorOption
- func WithRenderFunc(renderFn RenderFn) ProcessorOption
- func WithRequirementsProviderFactory(...) ProcessorOption
- func WithResourceManagerFactory(...) ProcessorOption
- func WithSchemaValidatorFactory(...) ProcessorOption
- func WithStderr(w io.Writer) ProcessorOption
- func WithStdout(w io.Writer) ProcessorOption
- func WithWarnings(warnings *WarningLogger) ProcessorOption
- type RegistryOverrideFunctionProvider
- type RenderFn
- type RenderInputs
- type RequirementsProvider
- type ResourceManager
- type SchemaValidationError
- func (e *SchemaValidationError) Error() string
- func (e *SchemaValidationError) Unwrap() error
- func (e *SchemaValidationError) WithFailures(failures []dt.ResourceValidationFailure) *SchemaValidationError
- func (e *SchemaValidationError) WithResult(result *pkgvalidate.ValidationResult) *SchemaValidationError
- type SchemaValidator
- type WarningLogger
- type XRDiffResult
Constants ¶
const ( // ExitCodeSuccess indicates no diff and no errors. ExitCodeSuccess = 0 // ExitCodeToolError indicates a tool execution error (e.g., kube access, internal failure). ExitCodeToolError = 1 // ExitCodeSchemaValidation indicates a schema validation error. ExitCodeSchemaValidation = 2 // ExitCodeDiffDetected indicates that differences were detected. ExitCodeDiffDetected = 3 // ExitCodeInterrupted indicates the run was cancelled by SIGINT (Ctrl+C) or SIGTERM. It is 130 by // the shell convention for SIGINT (128 + 2); the signal handler does not report which signal // arrived, so SIGTERM uses the same code. ExitCodeInterrupted = 130 )
Exit codes for crossplane-diff CLI.
const ( // LabelComposite identifies the root composite resource that owns a composed resource. LabelComposite = "crossplane.io/composite" // LabelClaimName identifies the claim that triggered creation of the composite. LabelClaimName = "crossplane.io/claim-name" // LabelClaimNamespace identifies the namespace of the claim. LabelClaimNamespace = "crossplane.io/claim-namespace" )
Crossplane label keys used for resource identity and ownership.
const CleanupTimeout = 30 * time.Second
CleanupTimeout bounds how long releasing the processor's Docker resources may take. Cleanup is attempted on a context detached from the run's cancellation (see CleanupDetached), so this is what stops a slow or hung Docker daemon from blocking a run indefinitely.
const DefaultMaxRenderIterations = 20
DefaultMaxRenderIterations is the default maximum render iterations.
const EnvDockerNetwork = "CROSSPLANE_DIFF_DOCKER_NETWORK"
EnvDockerNetwork is the environment variable that specifies which Docker network the crossplane-render container and function containers should join. NewEngineRenderFn reads this once and routes the value through render.EngineFlags.CrossplaneDockerNetwork; the upstream docker engine then both runs the render container on that network and annotates fns to join it at Setup time. This is needed when crossplane-diff runs inside a Docker container (e.g. a GitHub Actions container job).
const EnvMaxRecvMessageSize = "MAX_RECV_MESSAGE_SIZE"
EnvMaxRecvMessageSize is the container env var crossplane-diff injects to raise a function's gRPC max receive size. It is intentionally unprefixed and function-agnostic, mirroring the SDK-wide TLS_SERVER_CERTS_DIR convention shared by crossplane composition functions: functions that bind it honor it, functions that don't simply ignore it.
const FieldErrorTypeAdmission = "admission"
FieldErrorTypeAdmission is the FieldValidationError.Type for a rejection issued by the apiserver's admission chain rather than by local schema validation. It deliberately sits alongside upstream's "schema" / "cel" / "unknownField" / "defaulting" values in the same field, because to a consumer asking "why won't the cluster accept this?" it is the same kind of answer.
const MinCrossplaneRenderVersion = "v2.3.4"
MinCrossplaneRenderVersion is the minimum crossplane render version that crossplane-diff supports. Renders against older versions silently drop cluster-observed composed resources (their controller-ref UIDs no longer match the XR the way this tool assembles them), producing incorrect diffs — see crossplane-contrib/crossplane-diff#399. The value corresponds to the upstream release that preserves a non-empty input XR UID and validates observed resources (crossplane/crossplane#7544).
Variables ¶
var ErrInterrupted = errors.New("run interrupted by signal; results are incomplete")
ErrInterrupted is the error an interrupted run reports, in errors[] and on stderr, in place of the cancelled calls the interruption caused.
Functions ¶
func CleanupDetached ¶ added in v0.11.0
CleanupDetached releases c's resources on a context derived from ctx that keeps ctx's values but not its cancellation or deadline, bounded instead by CleanupTimeout. Cleanup must still run when the run's own context has expired (--timeout), since Docker calls on a dead context fail and leave containers running; and it must not hang on a slow or wedged Docker daemon. A failure is logged, not returned: releasing resources is best-effort and must not change the run's result.
This is also what lets cleanup finish after Ctrl+C or SIGTERM: the first signal cancels the run's context (see the command layer's run context) rather than killing the process. A second signal exits immediately and may leave containers behind, which the next run reclaims (see dockerrun).
func CopyLabels ¶ added in v0.5.0
func CopyLabels(source, target *un.Unstructured, keys ...string)
CopyLabels copies specified labels from source to target if they exist in source. This is a no-op if source has no labels or if none of the specified keys exist.
func DetermineExitCode ¶ added in v0.6.0
DetermineExitCode determines the appropriate exit code based on the error and diff status. Priority: interrupted (130) > tool error (1) > schema validation error (2) > diff detected (3) > success (0). An interruption outranks everything because the other errors of an interrupted run are mostly the cancelled calls it caused.
func Interrupted ¶ added in v0.11.0
Interrupted reports whether the run context ctx was cancelled by a signal. The run context is a timeout context on the signal context, so an expired --timeout yields context.DeadlineExceeded and a signal yields context.Canceled. The run's own cancel also yields Canceled, but only fires once the run is over, so callers must evaluate this before it.
func IsSchemaValidationError ¶ added in v0.6.0
IsSchemaValidationError checks if any error in the chain is a schema validation error.
func NewOutputError ¶ added in v0.8.0
func NewOutputError(resourceID string, err error) dt.OutputError
NewOutputError builds a structured-output entry for err, tagged with resourceID. When err contains a *SchemaValidationError that carries either a pkgvalidate.ValidationResult or pre-built Failures, the returned OutputError also exposes a typed per-resource breakdown via ValidationFailures so machine consumers don't need to parse Message. Non-validation errors return an OutputError with only ResourceID and Message populated.
Explicit Failures win over Result. The two are never both set in practice — one comes from pkg/validate, the other from an apiserver rejection — but preferring the explicit list means a caller that sets it cannot have it silently dropped.
func NormalizeRenderVersion ¶ added in v0.11.0
NormalizeRenderVersion returns version with a leading "v" when it parses as a semantic version without one, and version unchanged otherwise.
ValidateMinRenderVersion deliberately accepts a bare "2.3.4", but upstream formats the pinned version into the image tag verbatim (…/crossplane:<version>) and publishes only v-prefixed tags, so without this the bare form validates and then dies at pull time as an unpullable image. The original string is prefixed rather than reformatted from the parsed value, so prerelease and build metadata survive byte-for-byte. Tags that are not semantic versions ("stable", "main") are real, pullable tags and are left alone.
func UncomparableRenderImageWarning ¶ added in v0.11.0
UncomparableRenderImageWarning returns advisory text when image is a reference whose version cannot be compared against MinCrossplaneRenderVersion, or "" for an empty image (no override was requested) or one that ValidateMinRenderImage could check. Rendering with an image below the minimum silently drops cluster-observed composed resources, which shrinks the rendered set and surfaces as spurious removals, so an unverifiable reference is worth saying out loud even though it cannot be rejected.
func ValidateMinRenderImage ¶ added in v0.11.0
ValidateMinRenderImage returns an error if the tag of a full crossplane render image reference parses as a semantic version older than MinCrossplaneRenderVersion.
A reference whose version is not comparable — pinned by digest, tagged with a floating name like "stable", or carrying no tag at all — is accepted: refusing it would break the mirrored and air-gapped registries --crossplane-image exists to serve, and a digest is opaque by construction. Those references are reported by UncomparableRenderImageWarning instead, so the floor stays visible without becoming a false positive.
func ValidateMinRenderVersion ¶ added in v0.9.0
ValidateMinRenderVersion returns an error if version parses to a semantic version older than MinCrossplaneRenderVersion, or if it cannot be parsed as a semantic version at all. A leading "v" is accepted (and optional — see NormalizeRenderVersion, which is what makes the bare form usable rather than merely accepted). It is intended for validating an explicitly pinned --crossplane-version; a full --crossplane-image reference goes through ValidateMinRenderImage instead, and the floating :stable default carries no comparable version at all.
Types ¶
type AnalyzeOn ¶ added in v0.11.0
type AnalyzeOn string
AnalyzeOn names the smallest composition change that triggers per-composite impact analysis. The values are ordered from least to most eager.
const ( // AnalyzeOnSpecChange evaluates composites only when the composition's spec changes. The // cheapest setting, and a deliberate user judgement: a metadata-only change still produces a new // CompositionRevision, whose identity a composition template can observe through the XR's // compositionRevisionRef, so choosing this asserts that none of your compositions do that. AnalyzeOnSpecChange AnalyzeOn = "spec-change" // AnalyzeOnAnyChange evaluates composites whenever anything Crossplane hashes into the // composition's identity differs — labels and annotations as well as spec. The default, because // whether a metadata-only change reaches rendered output can only be settled by rendering. AnalyzeOnAnyChange AnalyzeOn = "any-change" // AnalyzeOnAlways evaluates composites even when the composition is identical, which creates no // revision and so cannot change anything. Useful as a pre-edit "is my cluster converged?" // baseline; note that any delta it reports is by construction not caused by this composition. AnalyzeOnAlways AnalyzeOn = "always" )
type CRDDefaulter ¶ added in v0.11.0
type CRDDefaulter struct {
// contains filtered or unexported fields
}
CRDDefaulter implements Defaulter from the CRDs a SchemaClient knows.
func (*CRDDefaulter) Default ¶ added in v0.11.0
func (d *CRDDefaulter) Default(ctx context.Context, obj *un.Unstructured) (*un.Unstructured, string, error)
Default returns a copy of obj with its CRD's defaults applied, and the CRD's storage version when it is not obj's. What happens when no CRD can be found depends on the policy. A CRD that is found but does not define obj's apiVersion is an error under either policy: there is nothing to predict from, and returning obj as though defaulted would hide it.
type CachedFunctionProvider ¶ added in v0.5.0
type CachedFunctionProvider struct {
// contains filtered or unexported fields
}
CachedFunctionProvider lazy-loads functions and caches them by composition name. This is appropriate for the comp command, where many XRs use the same composition: the cluster is asked for a composition's functions once, however many XRs render it. The function containers themselves are started, reused across renders and removed by the render engine, which names them for the run that owns them (see EngineRenderFn).
func (*CachedFunctionProvider) Cleanup ¶ added in v0.5.0
func (p *CachedFunctionProvider) Cleanup(_ context.Context) error
Cleanup is a no-op for CachedFunctionProvider: the render engine owns the containers.
func (*CachedFunctionProvider) GetFunctionsForComposition ¶ added in v0.5.0
func (p *CachedFunctionProvider) GetFunctionsForComposition(comp *apiextensionsv1.Composition) ([]pkgv1.Function, error)
GetFunctionsForComposition fetches and caches functions on first call per composition.
type ChangeScope ¶ added in v0.11.0
type ChangeScope string
ChangeScope is how much of a composition differs from its in-cluster version, in terms of what Crossplane hashes into the composition's identity (see Composition.Hash()).
const ( // ChangeScopeNone means nothing Crossplane hashes differs. No CompositionRevision is created, so // nothing can adopt anything. ChangeScopeNone ChangeScope = "none" // ChangeScopeMetadata means the labels or annotations differ but the spec does not. A new // CompositionRevision is still created, carrying an identical spec. ChangeScopeMetadata ChangeScope = "metadata" // ChangeScopeSpec means the spec differs. ChangeScopeSpec ChangeScope = "spec" )
type Cleaner ¶ added in v0.11.0
Cleaner is anything holding resources that CleanupDetached can release. DiffProcessor, CompDiffProcessor and FunctionProvider all embed it.
type CompDiffProcessor ¶ added in v0.2.0
type CompDiffProcessor interface {
// DiffComposition processes composition changes and shows impact on existing XRs.
// Returns (hasDiffs, error) where hasDiffs indicates if any differences were detected.
// When `resources` is non-empty, impact analysis is restricted to the named composites:
// each ref is resolved against every supplied composition's (XR GVK, claim GVK) pair via a
// preflight pass. If any ref is relevant to no supplied composition, the call fails before
// rendering any diffs (CLI input error). When `resources` is empty, behavior is unchanged.
DiffComposition(ctx context.Context, compositions []*un.Unstructured, namespace string, resources []k8stypes.NamespacedName) (bool, error)
Initialize(ctx context.Context) error
// Cleaner releases any resources held by the processor (e.g., Docker containers).
Cleaner
}
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, resource k8.ResourceClient, def xp.DefinitionClient, logger logging.Logger) SchemaValidator
// Defaulter creates a Defaulter with the given policy. The processor makes two: a strict one for the
// XR it renders, and a lenient one the DiffCalculator uses to predict additions.
Defaulter func(schema k8.SchemaClient, def xp.DefinitionClient, policy DefaultingPolicy) Defaulter
// DiffCalculator creates a DiffCalculator
DiffCalculator func(apply k8.ApplyClient, access k8.AccessChecker, tree xp.ResourceTreeClient, resourceManager ResourceManager, logger logging.Logger, diffOptions renderer.DiffOptions, dryRunOn DryRunOn, predictor Defaulter) DiffCalculator
// DiffRenderer creates a DiffRenderer
DiffRenderer func(logger logging.Logger, diffOptions renderer.DiffOptions) renderer.DiffRenderer
// CompDiffRenderer creates a CompDiffRenderer for composition diffs
CompDiffRenderer func(logger logging.Logger, diffRenderer renderer.DiffRenderer, opts renderer.DiffOptions) renderer.CompDiffRenderer
// RequirementsProvider creates an ExtraResourceProvider
RequirementsProvider func(res k8.ResourceClient, def xp.EnvironmentClient, logger logging.Logger) *RequirementsProvider
// FunctionProvider creates a FunctionProvider
FunctionProvider func(fnClient xp.FunctionClient, logger logging.Logger) FunctionProvider
// InputValidator creates the InputValidator for one PerformDiff run
InputValidator InputValidatorFactory
}
ComponentFactories contains factory functions for creating processor components.
type CompositeResolver ¶ added in v0.11.0
type CompositeResolver struct {
// contains filtered or unexported fields
}
CompositeResolver computes the effective composite: what Crossplane would actually reconcile for a composite as supplied, given what the cluster already holds. It is computed once per composite, before the composition is resolved, so that composition resolution and render agree on which revision, composition and update policy apply.
func NewCompositeResolver ¶ added in v0.11.0
func NewCompositeResolver(resources ResourceManager, defs xp.DefinitionClient, logger logging.Logger) *CompositeResolver
NewCompositeResolver creates a CompositeResolver.
func (*CompositeResolver) Resolve ¶ added in v0.11.0
func (r *CompositeResolver) Resolve(ctx context.Context, authored *cmp.Unstructured, existing *un.Unstructured) (EffectiveComposite, error)
Resolve computes the effective composite for authored. existing is authored's cluster copy when the caller already has it (a nested XR, found among its parent's observed resources); otherwise it is nil and Resolve fetches it.
Fetch errors are fatal: a composite resolved without the cluster state it depends on would be rendered against the wrong revision, composition or observed resources, and the diff would be silently wrong.
type DefaultCompDiffProcessor ¶ added in v0.2.0
type DefaultCompDiffProcessor struct {
// contains filtered or unexported fields
}
DefaultCompDiffProcessor implements CompDiffProcessor.
func (*DefaultCompDiffProcessor) Cleanup ¶ added in v0.7.0
func (p *DefaultCompDiffProcessor) Cleanup(ctx context.Context) error
Cleanup releases any resources held by the processor. Delegates to the underlying XR processor for cleanup.
func (*DefaultCompDiffProcessor) DiffComposition ¶ added in v0.2.0
func (p *DefaultCompDiffProcessor) DiffComposition(ctx context.Context, compositions []*un.Unstructured, namespace string, resources []k8stypes.NamespacedName) (bool, error)
DiffComposition processes composition changes and shows impact on existing XRs. Returns (hasDiffs, error) where hasDiffs indicates if any differences were detected.
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.CompositionOutputs) (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 ¶ added in v0.5.0
func (c *DefaultDiffCalculator) CalculateNonRemovalDiffs(ctx context.Context, xr *cmp.Unstructured, desired render.CompositionOutputs) (map[string]*dt.ResourceDiff, dtypes.RenderedResources, 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:
- 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
- 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!
What it records as rendered is keyed for both of its consumers; see dtypes.RenderedResources. Each composed resource is recorded as desired by desired.CompositeResource, the composite render consumed (for a claim, its backing XR, not the claim xr is), because that is the composite that composes it.
Returns: (diffs map, rendered resources, error).
func (*DefaultDiffCalculator) CalculateRemovedResourceDiffs ¶
func (c *DefaultDiffCalculator) CalculateRemovedResourceDiffs(ctx context.Context, xr *un.Unstructured, rendered dtypes.RenderedResources) (map[string]*dt.ResourceDiff, error)
CalculateRemovedResourceDiffs identifies the composed resources Crossplane would garbage collect, and calculates their removal diffs.
It applies Crossplane's own rule (crossplane v2.4.2, internal/controller/apiextensions/composite/ composition_functions.go). ExistingComposedResourceObserver.ObserveComposedResources observes each resource in a composite's resourceRefs, keyed by its composition resource name, except one another controller owns. DeletingComposedResourceGarbageCollector.GarbageCollectComposedResources then deletes each observed resource whose name is not among the names the composite's render desired, unless it has no controller reference. Matching is by composition resource name within the composite, never by API version or object name: a resource rendered at a new apiVersion is updated in place (#552).
The walk covers nested XRs' resources too, each matched against the composite it hangs from in the tree, which is the one that composed it. A composite that was not rendered, such as a nested XR being removed, desires nothing, so what it composed is removed with it.
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) Cleanup ¶ added in v0.7.0
func (p *DefaultDiffProcessor) Cleanup(ctx context.Context) error
Cleanup releases any resources held by the processor. This includes stopping and removing any Docker containers created for function execution.
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, resources []*un.Unstructured, compositionProvider types.CompositionProvider) (bool, error)
PerformDiff processes resources using a composition provider function. Returns (hasDiffs, error) where hasDiffs indicates if any differences were detected.
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, types.RenderedResources, 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. depth is the nesting depth of composedResources themselves: 1 for the resources composed by the XR the user named, 2 for their children, and so on. MaxNestedDepth is therefore the number of levels of nesting permitted below the root, and descending past it is an error rather than a silent truncation of the tree.
func (*DefaultDiffProcessor) RenderToStableState ¶ added in v0.7.0
func (p *DefaultDiffProcessor) RenderToStableState( ctx context.Context, xr *cmp.Unstructured, comp *apiextensionsv1.Composition, fns []pkgv1.Function, resourceID string, observedResources []cpd.Unstructured, synthesizeReady bool, ) (render.CompositionOutputs, error)
RenderToStableState performs iterative rendering until stable state is reached. It handles requirements resolution (environment configs, etc.) and optionally synthesizes Ready status on composed resources between iterations.
When synthesizeReady is false (normal mode), the loop terminates once requirements are resolved. When synthesizeReady is true (eventual-state mode), the loop continues until every rendered composed resource is observed Ready and no new requirements appear, synthesizing Ready=True on the observed state between iterations to reveal stages gated on readiness (function-sequencer). Synthesized Ready reaches only the next render's observed state: observedResources itself, and the cluster state the diff is later computed against, are never modified.
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 ¶ added in v0.5.0
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 ¶ added in v0.5.0
func (p *DefaultFunctionProvider) Cleanup(_ context.Context) error
Cleanup is a no-op for DefaultFunctionProvider as it doesn't create any resources.
func (*DefaultFunctionProvider) GetFunctionsForComposition ¶ added in v0.5.0
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 ¶ added in v0.5.0
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 RenderInputs.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 ¶
func (v *DefaultSchemaValidator) GetCRDs() []*extv1.CustomResourceDefinition
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 Defaulter ¶ added in v0.11.0
type Defaulter interface {
// Default returns a copy of obj with its CRD's defaults applied, and the version that CRD stores
// obj at when that is not obj's own version. The version is empty when there is no other: for a
// built-in type, a resource whose CRD is not found, a single-version CRD, or a resource at its
// CRD's storage version. obj itself is never modified.
Default(ctx context.Context, obj *un.Unstructured) (defaulted *un.Unstructured, storageVersion string, err error)
}
Defaulter predicts the defaults the apiserver would apply to a resource from its CRD's schema.
Nothing it returns may be sent to the apiserver. Under server-side apply every field in a request claims ownership of that field, so a locally defaulted field would take a value away from whichever manager set it in the cluster and report a change that applying the manifest would not make (#503). It has exactly two uses: the XR that composition and render consume, which must carry the spec Crossplane would see (StrictDefaulting); and the predicted result of an addition that has no apiserver result (LenientDefaulting).
The prediction covers CRD `default:` values only. Mutating admission and admission plugins are not modelled at all. Nor is a multi-version CRD's storage version: the prediction defaults against the requested version only, while the cluster may also apply the storage version's defaults and convert the resource through it. That one cannot be predicted without the conversion, but it can be named, so Default reports the storage version whenever it differs from the requested one, and the unverified addition's warning says the diff may omit its defaults and conversion (#528). Nor does it prune fields the schema does not declare, as the apiserver would, but that never shows: schema validation rejects an undeclared field as an unknownField error before any prediction runs.
func NewDefaulter ¶ added in v0.11.0
func NewDefaulter(sc k8.SchemaClient, dc xp.DefinitionClient, policy DefaultingPolicy) Defaulter
NewDefaulter creates a CRDDefaulter with the given policy.
type DefaultingPolicy ¶ added in v0.11.0
type DefaultingPolicy int
DefaultingPolicy says what a Defaulter does with a resource it finds no CRD for.
const ( // StrictDefaulting fails for a resource it finds no CRD for. It is the policy for the XR that render // consumes: rendering without the defaults Crossplane would see could produce a wrong diff, so a // missing XRD or CRD must not be passed over. StrictDefaulting DefaultingPolicy = iota // LenientDefaulting returns a resource it finds no CRD for as an unchanged copy: a built-in type, // which has no CRD, or a resource whose CRD cannot be found. It is the policy for predicting an // addition the apiserver did not see, which is best effort by nature; the schema validator, not // the Defaulter, is the gate on missing CRDs. LenientDefaulting )
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.CompositionOutputs) (map[string]*dt.ResourceDiff, error)
// CalculateNonRemovalDiffs computes diffs for modified/added resources and returns
// what was rendered. This is used by nested XR processing.
// Returns: (diffs map, rendered resources, error)
CalculateNonRemovalDiffs(ctx context.Context, xr *cmp.Unstructured, desired render.CompositionOutputs) (map[string]*dt.ResourceDiff, dtypes.RenderedResources, error)
// CalculateRemovedResourceDiffs identifies the composed resources in the cluster that Crossplane
// would garbage collect, given what was rendered. This is called after nested XR processing is
// complete.
CalculateRemovedResourceDiffs(ctx context.Context, xr *un.Unstructured, rendered dtypes.RenderedResources) (map[string]*dt.ResourceDiff, error)
}
DiffCalculator calculates differences between resources.
func NewDiffCalculator ¶
func NewDiffCalculator(apply k8.ApplyClient, access k8.AccessChecker, tree xp.ResourceTreeClient, resourceManager ResourceManager, logger logging.Logger, diffOptions renderer.DiffOptions, dryRunOn DryRunOn, predictor Defaulter) DiffCalculator
NewDiffCalculator creates a new DefaultDiffCalculator. predictor predicts CRD defaults for the additions that get no apiserver result; see dryRunCreateAddition. It should be lenient (LenientDefaulting): a prediction is best effort, and must not fail an addition for want of a CRD.
type DiffProcessor ¶
type DiffProcessor interface {
// PerformDiff processes resources using a composition provider function.
// Returns (hasDiffs, error) where hasDiffs indicates if any differences were detected.
PerformDiff(ctx context.Context, resources []*un.Unstructured, compositionProvider types.CompositionProvider) (bool, 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
// Cleaner releases any resources held by the processor (e.g., Docker containers).
// Should be called when the processor is no longer needed.
Cleaner
}
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 DryRunOn ¶ added in v0.11.0
type DryRunOn string
DryRunOn selects which resources are round-tripped through the apiserver to compute their post-apply form. Like AnalyzeOn it is a depth/cost knob: every resource dry-run costs one apiserver round-trip and requires a permission, and a resource left un-dry-run is marked with a DryRunInfo so "we did not check" stays distinguishable from "we checked and it matches".
const ( // DryRunOnExisting dry-runs only resources that already exist in the cluster, leaving additions // as the render pipeline produced them plus locally predicted CRD defaults (see Defaulter). This // was the only behaviour before crossplane-diff#334. It needs no create permission, and costs one // round-trip fewer per added resource. DryRunOnExisting DryRunOn = "existing" // DryRunOnAll additionally dry-run creates added resources, so their diffs pick up // apiserver-side defaulting and mutating admission — neither of which the local Defaulter can // predict for a built-in type, and neither of which it can predict at all for admission. The // default. Where the create is not permitted, the resource degrades to rendered output plus // locally predicted CRD defaults, and says so rather than failing the run. DryRunOnAll DryRunOn = "all" )
type EffectiveComposite ¶ added in v0.11.0
type EffectiveComposite struct {
// Authored is the composite as supplied (see DefaultDiffProcessor.SanitizeXR). It is never
// modified, because it is what gets validated and dry-run applied: under server-side apply every
// field in a payload claims ownership of that field (#503). For a claim it is the claim, which is
// defaulted only with its own CRD (by the apiserver, or by the lenient Defaulter for a predicted
// addition), never its XR's: the two differ (crossplane-runtime pkg/xcrd schemas.go:75 and :209),
// since only the XR's defaults compositionUpdatePolicy and only the claim's compositeDeletePolicy.
Authored *cmp.Unstructured
// Cluster is the cluster's copy of Authored, or nil if the cluster has none. For a claim it is the
// claim.
Cluster *un.Unstructured
// Backing is the cluster's copy of a claim's backing XR. It is nil for an XR, and for a claim whose
// backing XR does not exist yet.
Backing *un.Unstructured
// Effective is the XR Crossplane would compose, before CRD defaulting. For an XR, that is Authored
// plus the fields Crossplane writes that Authored leaves out, taken from Cluster. For a claim it is
// the backing XR (Backing, or one synthesized from the claim) with the claim's spec synced into it
// the way Crossplane's claim syncer does. It is a fresh object the caller may modify.
Effective *un.Unstructured
// IsClaim reports whether Authored is a claim.
IsClaim bool
}
EffectiveComposite is one composite seen the ways a diff needs it.
func (EffectiveComposite) Composed ¶ added in v0.11.0
func (c EffectiveComposite) Composed() *un.Unstructured
Composed returns the cluster object whose composed resources Effective observes: Backing for a claim, Cluster for an XR. It is nil when that object does not exist yet.
type EngineRenderFn ¶ added in v0.8.0
type EngineRenderFn struct {
// contains filtered or unexported fields
}
EngineRenderFn is the default RenderFn implementation. It lazily starts function runtimes on first use, reuses them across subsequent calls, and serializes concurrent renders with an internal mutex.
A single `xr` invocation can render against XRs from multiple compositions whose function pipelines overlap but aren't identical. Engine.Setup (crossplane/cli#159) accepts being called once per batch: the call that creates a new environment — if any — returns a real cleanup; calls that integrate fns into an environment that already exists (because a prior Setup call established it, or because the engine was pre-configured to use an externally-managed environment via --crossplane-docker-network) return a no-op cleanup, as do calls on engines with nothing to clean up (the local engine). We accumulate every returned cleanup in a slice and call them in LIFO order on Cleanup without coordinating which one is real, per the caller contract in the upstream Engine.Setup docstring.
func NewEngineRenderFn ¶ added in v0.8.0
func NewEngineRenderFn(log logging.Logger, binaryPath, version, image string) *EngineRenderFn
NewEngineRenderFn constructs an EngineRenderFn.
binaryPath, version, and image select the render backend via render.EngineFlags (they are mutually exclusive upstream, grouped under the "crossplane-selector" xor):
- binaryPath (CrossplaneBinary): drives the upstream localRenderEngine against a local `crossplane` binary.
- version (CrossplaneVersion): the docker engine pulls xpkg.crossplane.io/crossplane/crossplane:<version>.
- image (CrossplaneImage): the docker engine pulls that full image ref.
When all three are empty the docker engine pulls xpkg.crossplane.io/crossplane/crossplane:stable. Both engines now capture stderr into the returned error and honour exit code 3 (partial-output-on- fatal — crossplane/crossplane#7455) per crossplane/cli#91, so we no longer wrap them. Our EngineRenderFn.Render still expects (rsp != nil, err != nil) on pipeline fatal and surfaces both — see the comment there.
The docker engine renders on a Docker network: by default one it creates in its first Setup and removes in that Setup's cleanup, labelled with the run's session. CROSSPLANE_DIFF_DOCKER_NETWORK, read once here, names the user's network instead, passed as render.EngineFlags.CrossplaneDockerNetwork (crossplane/cli#65): the engine then runs the crossplane-render container on it AND annotates each fn at Setup time so its container joins it too — closing both halves of the "crossplane-diff inside a container" case (crossplane/cli#75). The engine never creates or removes that network, and neither does the run: it carries no session label.
func (*EngineRenderFn) Cleanup ¶ added in v0.8.0
func (e *EngineRenderFn) Cleanup(ctx context.Context) error
Cleanup stops every function runtime started across the engine's lifetime, then has the run remove every container labelled with its session, run the cleanups accumulated from each engine.Setup call in LIFO order (removing the network the engine created, now that nothing is attached), and remove any of its networks still left. The run's own sweep also catches what upstream fails to remove. Idempotent and safe to call when Render was never invoked.
func (*EngineRenderFn) Render ¶ added in v0.8.0
func (e *EngineRenderFn) Render(ctx context.Context, log logging.Logger, in RenderInputs) (render.CompositionOutputs, error)
Render performs one render. It is safe for concurrent use — calls are serialized internally. Setup runs only on invocations that introduce previously-unseen functions; renders whose fns are all already running skip straight to building the request. See the EngineRenderFn docstring for the per-batch Setup contract this relies on.
func (*EngineRenderFn) RenderImage ¶ added in v0.11.0
func (e *EngineRenderFn) RenderImage() string
RenderImage returns the fully-resolved render image reference the engine will pull, or "" when a local crossplane binary was selected instead. It exists so callers — and tests — can observe which backend a processor actually ended up with; the upstream Engine interface exposes no accessor for it, so before this the selector arguments vanished at the boundary and dropping them entirely was undetectable (crossplane-diff#488).
type EnvInjectingFunctionProvider ¶ added in v0.11.0
type EnvInjectingFunctionProvider struct {
// contains filtered or unexported fields
}
EnvInjectingFunctionProvider wraps another FunctionProvider and upserts a set of env pairs into each function's runtime-docker-env annotation before returning them. Used to raise the function gRPC max-recv-message-size so large XRs don't trip the function-sdk-go 4MB default under `crossplane render` (which, unlike the in-cluster runtime, does not apply DeploymentRuntimeConfig).
func (*EnvInjectingFunctionProvider) Cleanup ¶ added in v0.11.0
func (p *EnvInjectingFunctionProvider) Cleanup(ctx context.Context) error
Cleanup delegates to the wrapped provider.
func (*EnvInjectingFunctionProvider) GetFunctionsForComposition ¶ added in v0.11.0
func (p *EnvInjectingFunctionProvider) GetFunctionsForComposition(comp *apiextensionsv1.Composition) ([]pkgv1.Function, error)
GetFunctionsForComposition delegates to the wrapped provider and upserts the configured env pairs into each function's runtime-docker-env annotation. The upsert is idempotent so repeated calls over a caching inner provider don't duplicate pairs.
type FunctionProvider ¶ added in v0.5.0
type FunctionProvider interface {
// GetFunctionsForComposition returns the functions needed to render a composition.
GetFunctionsForComposition(comp *apiextensionsv1.Composition) ([]pkgv1.Function, error)
// Cleaner stops and removes any resources created during function execution.
// For providers that don't create resources (like DefaultFunctionProvider), this is a no-op.
Cleaner
}
FunctionProvider provides functions for rendering compositions. Different implementations can fetch functions on-demand or return cached functions.
func NewCachedFunctionProvider ¶ added in v0.5.0
func NewCachedFunctionProvider(fnClient xp.FunctionClient, logger logging.Logger) FunctionProvider
NewCachedFunctionProvider creates a new CachedFunctionProvider.
func NewDefaultFunctionProvider ¶ added in v0.5.0
func NewDefaultFunctionProvider(fnClient xp.FunctionClient, logger logging.Logger) FunctionProvider
NewDefaultFunctionProvider creates a new DefaultFunctionProvider.
func NewEnvInjectingFunctionProvider ¶ added in v0.11.0
func NewEnvInjectingFunctionProvider(inner FunctionProvider, envs map[string]string, logger logging.Logger) FunctionProvider
NewEnvInjectingFunctionProvider wraps inner, upserting the given env pairs into each returned function's runtime-docker-env annotation.
func NewRegistryOverrideFunctionProvider ¶ added in v0.8.0
func NewRegistryOverrideFunctionProvider(inner FunctionProvider, registry string, logger logging.Logger) FunctionProvider
NewRegistryOverrideFunctionProvider wraps inner, replacing the registry portion of every function package ref with the given registry.
type InputValidator ¶ added in v0.11.0
type InputValidator interface {
// ToRender returns the inputs to render, in input order, with duplicates already dropped.
// An input with a non-nil Err was rejected before rendering and must not be rendered.
ToRender() []types.ValidatedInput
// RecordRender records the render of ToRender()[i]: every resource key it produced
// (including unchanged ones) and its error, if any.
RecordRender(i int, rendered map[string]bool, err error)
// Verdicts returns the final error for each group (indexed like ToRender()), or nil.
// It applies stage 2 and the precedence rule: a managed-input verdict replaces that
// group's own render failure.
Verdicts(groups []dt.XRDiffGroup) []error
// RenderOverlaps returns the stage-3 errors.
RenderOverlaps(groups []dt.XRDiffGroup) []error
}
InputValidator validates one PerformDiff run's input set. It is created per run by an InputValidatorFactory, because it carries that run's state between stages.
func NewBundleInputValidator ¶ added in v0.11.0
func NewBundleInputValidator(logger logging.Logger, inputs []*un.Unstructured) InputValidator
NewBundleInputValidator returns the default InputValidator for one run over inputs. It has the InputValidatorFactory signature. Stage 1 (checkInputs) runs here, so duplicates are logged once.
type InputValidatorFactory ¶ added in v0.11.0
type InputValidatorFactory func(logger logging.Logger, inputs []*un.Unstructured) InputValidator
InputValidatorFactory creates the InputValidator for one run.
type ProcessorConfig ¶
type ProcessorConfig struct {
// Colorize determines whether to use colors in the diff output
Colorize bool
// Compact determines whether to show a compact diff format
Compact bool
// OutputFormat specifies the output format for diffs (diff, json, yaml)
OutputFormat renderer.OutputFormat
// OutputVersion specifies the schema version of structured (json, yaml) output
OutputVersion renderer.OutputVersion
// 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
// MinimizeComposition collapses composition changes to a single marker line per
// composition, omitting the full YAML diff body. Human renderer only; structured
// output always includes full compositionChanges.
MinimizeComposition bool
// Warnings is the source of non-fatal advisories to include in structured output. It is the same
// *WarningLogger that Logger is set to when the CLI wires one up; keeping a typed handle avoids
// type-asserting the Logger back to its concrete type at drain time. Nil is valid and means no
// warnings are collected — the human-visible stderr line is emitted by the WarningLogger itself,
// so leaving this unset only affects structured output.
Warnings *WarningLogger
// AnalyzeOn is the smallest composition change that triggers per-composite impact analysis.
// Evaluating a composite costs one function render, so this is a cost knob — it never suppresses
// a reported consequence. RevisionImpact is populated at every setting, and composites left
// unevaluated are marked ImpactAnalysisSkipped so "we did not look" stays distinguishable from
// "we looked and found nothing".
//
// Zero value means AnalyzeOnAnyChange, matching the CLI default.
AnalyzeOn AnalyzeOn
// DryRunOn selects which resources are verified against the apiserver. Zero value means
// DryRunOnAll, matching the CLI default.
DryRunOn DryRunOn
// EventualState enables iterative simulation to show eventual state after all reconciliation
// cycles complete. Useful with function-sequencer which hides later stage resources.
EventualState bool
// MaxRenderIterations is the maximum number of render iterations when resolving requirements
// or simulating eventual state. Higher values may be needed for complex pipelines.
MaxRenderIterations int
// IgnorePaths is a list of paths to ignore when calculating diffs
IgnorePaths []string
// FunctionCredentials holds Secret credentials to pass to Functions during rendering
FunctionCredentials []corev1.Secret
// FunctionRegistryOverride overrides the registry in all function package refs.
FunctionRegistryOverride string
// MaxRecvMessageSize is the max gRPC message size (MB) for render function
// containers. Zero leaves the function's own default (function-sdk-go uses
// 4MB). When >0 it is injected as the appropriate container env var,
// so large XRs don't trip the default limit under render.
MaxRecvMessageSize int
// Stdout is the writer for diff output (defaults to os.Stdout)
Stdout io.Writer
// Stderr is the writer for error output (defaults to os.Stderr)
Stderr io.Writer
// Logger is the logger to use
Logger logging.Logger
// RenderFunc is the function to use for rendering resources. If left nil,
// processors construct a default engine-backed RenderFn on initialization.
RenderFunc RenderFn
// CrossplaneRenderBinary, when non-empty, causes the default
// engine-backed RenderFn to invoke a local `crossplane` binary at the
// supplied path instead of the upstream docker engine. This is a test
// affordance that gives integration tests a fast in-process render path;
// production users should leave it empty so the docker engine pulls
// xpkg.crossplane.io/crossplane/crossplane:stable. Ignored when
// RenderFunc is set explicitly.
CrossplaneRenderBinary string
// CrossplaneVersion, when non-empty, causes the default engine-backed
// RenderFn's docker engine to pull
// xpkg.crossplane.io/crossplane/crossplane:<version> instead of :stable.
// Mutually exclusive with CrossplaneImage and CrossplaneRenderBinary.
// Ignored when RenderFunc is set explicitly.
CrossplaneVersion string
// CrossplaneImage, when non-empty, causes the default engine-backed
// RenderFn's docker engine to pull this full image reference instead of
// the default xpkg.crossplane.io/crossplane/crossplane:stable. Mutually
// exclusive with CrossplaneVersion and CrossplaneRenderBinary. Ignored
// when RenderFunc is set explicitly.
CrossplaneImage string
// 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 WithAnalyzeOn ¶ added in v0.11.0
func WithAnalyzeOn(analyzeOn AnalyzeOn) ProcessorOption
WithAnalyzeOn sets the smallest composition change that triggers per-composite impact analysis (see ProcessorConfig.AnalyzeOn). An empty value leaves the default in place.
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 WithCrossplaneImage ¶ added in v0.9.0
func WithCrossplaneImage(image string) ProcessorOption
WithCrossplaneImage pins the full crossplane render image reference the default engine-backed RenderFn's docker engine pulls. See ProcessorConfig.CrossplaneImage. Mutually exclusive with WithCrossplaneVersion and WithCrossplaneRenderBinary.
func WithCrossplaneRenderBinary ¶ added in v0.8.0
func WithCrossplaneRenderBinary(path string) ProcessorOption
WithCrossplaneRenderBinary points the default engine-backed RenderFn at a local `crossplane` binary instead of the upstream docker engine. See ProcessorConfig.CrossplaneRenderBinary for the semantics — production callers should not use this; it exists for fast integration-test iteration.
func WithCrossplaneVersion ¶ added in v0.9.0
func WithCrossplaneVersion(version string) ProcessorOption
WithCrossplaneVersion pins the crossplane render version the default engine-backed RenderFn's docker engine pulls (…/crossplane:<version>). See ProcessorConfig.CrossplaneVersion. Mutually exclusive with WithCrossplaneImage and WithCrossplaneRenderBinary.
func WithDefaulterFactory ¶ added in v0.11.0
func WithDefaulterFactory(factory func(k8.SchemaClient, xp.DefinitionClient, DefaultingPolicy) Defaulter) ProcessorOption
WithDefaulterFactory sets the Defaulter factory function.
func WithDiffCalculatorFactory ¶
func WithDiffCalculatorFactory(factory func(k8.ApplyClient, k8.AccessChecker, xp.ResourceTreeClient, ResourceManager, logging.Logger, renderer.DiffOptions, DryRunOn, Defaulter) DiffCalculator) ProcessorOption
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 WithDryRunOn ¶ added in v0.11.0
func WithDryRunOn(dryRunOn DryRunOn) ProcessorOption
WithDryRunOn sets which resources are round-tripped through the apiserver. An empty value leaves the config's default in place, matching WithAnalyzeOn.
func WithEventualState ¶ added in v0.7.0
func WithEventualState(enabled bool) ProcessorOption
WithEventualState sets whether to show eventual state after all reconciliation cycles complete. When enabled, the processor runs an iterative simulation that synthesizes Ready status on rendered resources until no new resources appear. This is useful with function-sequencer which hides later stage resources until earlier stages become Ready.
func WithFunctionCredentials ¶ added in v0.6.0
func WithFunctionCredentials(creds []corev1.Secret) ProcessorOption
WithFunctionCredentials sets the credentials to pass to Functions during rendering.
func WithFunctionProviderFactory ¶ added in v0.5.0
func WithFunctionProviderFactory(factory func(xp.FunctionClient, logging.Logger) FunctionProvider) ProcessorOption
WithFunctionProviderFactory sets the FunctionProvider factory function.
func WithFunctionRegistryOverride ¶ added in v0.8.0
func WithFunctionRegistryOverride(registry string) ProcessorOption
WithFunctionRegistryOverride overrides the registry in all function package refs.
func WithIgnorePaths ¶ added in v0.5.0
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 WithInputValidatorFactory ¶ added in v0.11.0
func WithInputValidatorFactory(factory InputValidatorFactory) ProcessorOption
WithInputValidatorFactory sets the InputValidator factory function, called once per PerformDiff run.
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 WithMaxRecvMessageSize ¶ added in v0.11.0
func WithMaxRecvMessageSize(mb int) ProcessorOption
WithMaxRecvMessageSize sets the max gRPC message size (MB) injected into render function containers.
func WithMaxRenderIterations ¶ added in v0.7.0
func WithMaxRenderIterations(maxIterations int) ProcessorOption
WithMaxRenderIterations sets the maximum number of render iterations when resolving requirements or simulating eventual state.
func WithMinimizeComposition ¶ added in v0.9.0
func WithMinimizeComposition(minimize bool) ProcessorOption
WithMinimizeComposition sets whether to collapse composition changes to a single marker line.
func WithOutputFormat ¶ added in v0.6.0
func WithOutputFormat(format renderer.OutputFormat) ProcessorOption
WithOutputFormat sets the output format for diffs.
func WithOutputVersion ¶ added in v0.11.0
func WithOutputVersion(version renderer.OutputVersion) ProcessorOption
WithOutputVersion sets the schema version of structured output.
func WithRenderFunc ¶
func WithRenderFunc(renderFn RenderFn) ProcessorOption
WithRenderFunc sets the render function for the processor.
func WithRequirementsProviderFactory ¶
func WithRequirementsProviderFactory(factory func(k8.ResourceClient, xp.EnvironmentClient, logging.Logger) *RequirementsProvider) ProcessorOption
WithRequirementsProviderFactory sets the RequirementsProvider factory function.
func WithResourceManagerFactory ¶
func WithResourceManagerFactory(factory func(k8.ResourceClient, xp.DefinitionClient, xp.ResourceTreeClient, logging.Logger) ResourceManager) ProcessorOption
WithResourceManagerFactory sets the ResourceManager factory function.
func WithSchemaValidatorFactory ¶
func WithSchemaValidatorFactory(factory func(k8.SchemaClient, k8.ResourceClient, xp.DefinitionClient, logging.Logger) SchemaValidator) ProcessorOption
WithSchemaValidatorFactory sets the SchemaValidator factory function.
func WithStderr ¶ added in v0.7.0
func WithStderr(w io.Writer) ProcessorOption
WithStderr sets the writer for error output.
func WithStdout ¶ added in v0.7.1
func WithStdout(w io.Writer) ProcessorOption
WithStdout sets the writer for diff output.
func WithWarnings ¶ added in v0.11.0
func WithWarnings(warnings *WarningLogger) ProcessorOption
WithWarnings sets the collector whose warnings are included in structured output. Pass the same *WarningLogger that was supplied to WithLogger.
type RegistryOverrideFunctionProvider ¶ added in v0.8.0
type RegistryOverrideFunctionProvider struct {
// contains filtered or unexported fields
}
RegistryOverrideFunctionProvider wraps another FunctionProvider and replaces the registry in each function's package reference before returning them.
func (*RegistryOverrideFunctionProvider) Cleanup ¶ added in v0.8.0
func (p *RegistryOverrideFunctionProvider) Cleanup(ctx context.Context) error
Cleanup delegates to the wrapped provider.
func (*RegistryOverrideFunctionProvider) GetFunctionsForComposition ¶ added in v0.8.0
func (p *RegistryOverrideFunctionProvider) GetFunctionsForComposition(comp *apiextensionsv1.Composition) ([]pkgv1.Function, error)
GetFunctionsForComposition delegates to the wrapped provider and rewrites the registry portion of each returned function's package ref.
type RenderFn ¶ added in v0.8.0
type RenderFn func(ctx context.Context, log logging.Logger, in RenderInputs) (render.CompositionOutputs, error)
RenderFn is the render abstraction injected into diff processors. Callers provide the Function CRs they already have; the implementation owns the engine and FunctionAddresses lifecycle.
type RenderInputs ¶ added in v0.8.0
type RenderInputs struct {
CompositeResource *ucomposite.Unstructured
Composition *apiextensionsv1.Composition
Functions []pkgv1.Function
FunctionCredentials []corev1.Secret
ObservedResources []composed.Unstructured
RequiredResources []kunstructured.Unstructured
RequiredSchemas []spec3.OpenAPI
// XRD is the CompositeResourceDefinition the binary should consider
// when rendering. Set by RenderToStableState based on a defClient lookup
// so the binary can pick the right composite.Schema (Legacy vs Modern)
// for the input XR's GVK. The renderer then writes canonical fields at
// the path the cluster CRD declares (spec.* for v1, spec.crossplane.*
// for v2), making dry-run apply succeed and the rendered desired
// comparable against cluster state. Optional; when nil the binary
// falls back to SchemaModern.
XRD *kunstructured.Unstructured
}
RenderInputs carries what the diff processor already holds. It deliberately omits FunctionAddrs — that's engine state, not caller state.
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, 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) ResolveSelectors ¶ added in v0.8.0
func (p *RequirementsProvider) ResolveSelectors(ctx context.Context, selectors []*v1.ResourceSelector, xrNamespace string) ([]*un.Unstructured, error)
ResolveSelectors resolves a flat list of ResourceSelector entries into their backing resources. Checks the cache first; on a miss it defers to the per-selector fetcher and caches the result.
Matches the render.CompositionOutputs.RequiredResources shape introduced in upstream crossplane PR #7339.
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 SchemaValidationError ¶ added in v0.6.0
type SchemaValidationError struct {
ResourceID string
Message string
Err error
Result *pkgvalidate.ValidationResult
Failures []dt.ResourceValidationFailure
}
SchemaValidationError indicates schema validation failed. Used to distinguish validation errors from other tool errors for exit code handling.
Result, when non-nil, carries the structured per-resource validation outcome that produced this error. Output renderers use it to surface typed FieldValidationError records under OutputError.ValidationFailures in JSON / YAML output. It is left nil for paths that fail validation without a *pkgvalidate.ValidationResult in hand — for example scope-validation errors raised after schema validation succeeded — so the absence of structured detail is observable rather than fabricated.
Failures is the same information for rejections that did not come from pkg/validate at all — specifically, a resource the apiserver itself refused during a dry-run (a validating admission webhook, a ResourceQuota, a missing namespace). Those are the same kind of fact as a schema rejection ("the cluster will not accept this resource"), just detected by the apiserver instead of locally, so they belong in the same exit-code tier and the same output field. They are carried separately rather than synthesised into a pkgvalidate.ValidationResult because that would mean inventing a FieldErrorType value upstream does not define; ResourceValidationFailure is explicitly ours to populate (see its doc in renderer/types).
func NewAdmissionRejectionError ¶ added in v0.11.0
func NewAdmissionRejectionError(rejectedDesc string, obj *un.Unstructured, err error) *SchemaValidationError
NewAdmissionRejectionError wraps an apiserver dry-run rejection of obj as a SchemaValidationError, so it lands in the same exit-code tier and the same structured-output field as a local schema rejection.
This is used for BOTH new and existing resources on purpose. Before this existed, a webhook rejection of an existing resource surfaced as a plain tool error (exit 1) while the identical rejection of an addition would have been a validation error (exit 2) — reporting the same cluster fact under two different exit codes depending only on whether the resource happened to exist already. See crossplane-diff#334.
rejectedDesc describes the REJECTED resource (the calculator's per-resource id, e.g. "Bucket/my-bucket"), not the input XR. It is folded into the message because OutputError.ResourceID identifies the input the user supplied, which for a composed resource is the XR — without this, a human would be told their XR was rejected with no way to tell which composed resource the cluster actually refused.
The inner SchemaValidationError deliberately gets an empty ResourceID: its Error() would otherwise prefix "schema validation error for <id>: ", which both duplicates the id that OutputError.FormatError already prints and mislabels an admission rejection as a schema problem.
func NewSchemaValidationError ¶ added in v0.6.0
func NewSchemaValidationError(resourceID, message string, err error) *SchemaValidationError
NewSchemaValidationError creates a new SchemaValidationError without a structured Result. Use WithResult on the returned value to attach one when the failure originated from pkg/validate.SchemaValidate.
func (*SchemaValidationError) Error ¶ added in v0.6.0
func (e *SchemaValidationError) Error() string
Error implements the error interface.
func (*SchemaValidationError) Unwrap ¶ added in v0.6.0
func (e *SchemaValidationError) Unwrap() error
Unwrap returns the wrapped error for errors.Is/As compatibility.
func (*SchemaValidationError) WithFailures ¶ added in v0.11.0
func (e *SchemaValidationError) WithFailures(failures []dt.ResourceValidationFailure) *SchemaValidationError
WithFailures attaches already-built per-resource failures for a rejection that did not originate from pkg/validate — an apiserver dry-run refusal. It is the sibling of WithResult; see the Failures field for why the two are separate. Returns the receiver for fluent chaining.
func (*SchemaValidationError) WithResult ¶ added in v0.8.0
func (e *SchemaValidationError) WithResult(result *pkgvalidate.ValidationResult) *SchemaValidationError
WithResult attaches the structured *pkgvalidate.ValidationResult that produced this error so downstream renderers can emit typed per-resource failures alongside the human-readable Message. Returns the receiver for fluent chaining.
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, rClient k8.ResourceClient, dClient xp.DefinitionClient, logger logging.Logger) SchemaValidator
NewSchemaValidator creates a new DefaultSchemaValidator.
type WarningLogger ¶ added in v0.11.0
type WarningLogger struct {
// contains filtered or unexported fields
}
WarningLogger is the advisory channel: a logging.Logger decorator that treats every Info call as a user-facing warning, writing it to stderr immediately and collecting it for structured output. Debug calls are forwarded to the wrapped logger unchanged.
Why the logger, and why Info ¶
A warning has to be raisable from wherever it is discovered — a client, a resource manager, the render loop. The logging.Logger is the only cross-cutting dependency already threaded to all of those; every component factory in ProcessorConfig takes exactly one (a client, a converter, and a Logger), so a parallel "warning sink" parameter would mean churning every constructor, every factory signature, and every With*Factory option for no semantic gain.
There is no Warn to reach for: crossplane-runtime's logging.Logger has exactly two levels by design ("Crossplane prefers not to use go-logr because it desires a simpler API with only two levels ... Info and Debug"), and it defines Info as "messages that Crossplane operators are very likely to be concerned with when running Crossplane" against Debug's "when debugging Crossplane". So treating Info as the advisory level is not a convention invented here — it is the interface's documented meaning, which this type implements by giving those messages somewhere to go. What it does add is the second sink: the same message also lands in structured output.
The user-facing label is deliberately WARNING rather than INFO. An operator reading "INFO: applying this diff will assume ownership" would under-weight it; the upstream *level* and the word shown to a human are answering different questions.
Why it writes to stderr itself ¶
Raising the wrapped logger's verbosity would surface warnings for humans, but in zap's development-mode format (timestamp, level, caller) and still nowhere in structured output. Owning the human rendering here means one mechanism produces both views — the same dual-emission contract OutputError follows — and the text stays fit for a CLI. Info is therefore NOT forwarded to the wrapped logger; otherwise a --verbose run would print every warning twice, once in each format.
Why identical warnings are collapsed ¶
A warning is raised where the condition is discovered, and several of those sites sit inside loops the caller chose — resolveFunctionCredentials runs once per XR, so a single unfetchable secret on a composition affecting thirty XRs would otherwise produce thirty byte-identical WARNING lines and thirty identical warnings[] entries. A repeat that is identical in BOTH message and context carries no information the user has not already been given, so the sink keeps only the first. Warnings whose context differs in any pair are distinct occurrences and every one of them is kept: the ownership-theft advisory in resource_manager.go names the composed resource in its context and must fire once per resource. The consequence for a warning site is therefore a simple rule — put what distinguishes one occurrence from another in the context, which it should be doing regardless, since context is what a machine consumer reads.
A zero WarningLogger is not usable; construct one with NewWarningLogger.
func NewWarningLogger ¶ added in v0.11.0
func NewWarningLogger(logger logging.Logger, stderr io.Writer) *WarningLogger
NewWarningLogger wraps logger so that Info calls become user-facing warnings written to stderr and collected for structured output. Debug calls pass through to logger unchanged.
func (*WarningLogger) Debug ¶ added in v0.11.0
func (l *WarningLogger) Debug(msg string, keysAndValues ...any)
Debug forwards to the wrapped logger. Tracing is not advisory output.
func (*WarningLogger) Info ¶ added in v0.11.0
func (l *WarningLogger) Info(msg string, keysAndValues ...any)
Info records msg as a user-facing warning: written to stderr now, and collected for structured output. A warning identical to one already raised — same message and same context — is dropped from both channels; see the type comment. It is deliberately not forwarded to the wrapped logger.
func (*WarningLogger) Warnings ¶ added in v0.11.0
func (l *WarningLogger) Warnings() []dt.OutputWarning
Warnings returns the warnings collected so far, in emission order. The returned slice is a copy, so callers may retain it while more warnings are raised.
func (*WarningLogger) WithValues ¶ added in v0.11.0
func (l *WarningLogger) WithValues(keysAndValues ...any) logging.Logger
WithValues returns a logger that carries the supplied pairs, sharing this logger's collection point so derived loggers do not each accumulate their own separate warning list.
type XRDiffResult ¶ added in v0.5.0
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 ¶ added in v0.5.0
func (r *XRDiffResult) HasChanges() bool
HasChanges returns true if this XR has downstream resource changes.
func (*XRDiffResult) HasError ¶ added in v0.5.0
func (r *XRDiffResult) HasError() bool
HasError returns true if this XR encountered a processing error.