Repository navigation
Conversation
9dff52a to
881e787
Compare
The renderers wrote every OutputError to stderr as "ERROR: Kind/name: ...", and the processors also returned the failure, which main printed again as "Error: ...". A failing run reported each error twice in two formats. Stop the renderers printing errors and drop OutputError.FormatError. Structured output keeps errors[] unchanged, and warnings still go to stderr when raised. main prints every returned error, schema-validation ones included, since the renderers no longer print them. DiffComposition now names each failing resource in its returned error, as PerformDiff already did. The integration harness prints a returned error as main does so stderr assertions see what a user sees. Backport of crossplane/cli#436 (19817b2). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
The renderers wrote every OutputError to stderr as "ERROR: Kind/name: ...", and the processors also returned the failure, which main printed again as "Error: ...". A failing run reported each error twice in two formats. Stop the renderers printing errors and drop OutputError.FormatError. Structured output keeps errors[] unchanged, and warnings still go to stderr when raised. main prints every returned error, schema-validation ones included, since the renderers no longer print them. DiffComposition now names each failing resource in its returned error, as PerformDiff already did. The integration harness prints a returned error as main does so stderr assertions see what a user sees. Backport of crossplane/cli#436 (19817b2). Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com> Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Callers can now detect a backend that predates `crossplane internal render` with errors.Is instead of matching stderr text. The user-visible message is unchanged. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Verbatim copy of cmd/diff/{renderer,renderer/types,types,testutils} from
crossplane-contrib/crossplane-diff at 9fa7d31 with import paths rewritten,
gci import grouping, and named constants for repeated literals in
testutils/mock_builder.go (goconst). Adds gopsutil/v4 (used by the envtest
reaper) and bumps go.yaml.in/yaml/v3 to v3.0.5 and golang.org/x/sys to
v0.48.0, which it requires.
TestCRDsForXRD needs Crossplane's CRDs and fails until a CRD fetch exists.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Fetch Crossplane's cluster/crds at v2.4.1 (the apis/v2 version go.mod pins) as a fixed-output derivation and expose it to the test check and the test app as CROSSPLANE_CRDS_DIR. PinnedCrossplaneCRDsDir now reads that variable instead of an Earthly-populated cluster/gomod/crds. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Verbatim copy of cmd/diff/{ref,dockerrun,client/core} from
crossplane-contrib/crossplane-diff at 11e6fc3 with import paths rewritten.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Upstream replaced Info-level advisory logging with a dt.Advisories channel; resync renderer, renderer/types, testutils and dockerrun. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Verbatim copy of cmd/diff/client/kubernetes from crossplane-contrib/crossplane-diff at 9fa7d31 with import paths rewritten and gci import grouping. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Verbatim copy of cmd/diff/client/crossplane from crossplane-contrib/crossplane-diff at 9fa7d31 with import paths rewritten and gci import grouping. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Verbatim copy of cmd/diff/diffprocessor from crossplane-contrib/crossplane-diff at 9fa7d31 with import paths rewritten and gci import grouping. Adds github.com/Masterminds/semver v1.5.0, which crossplane-diff's render_version.go imports, and refreshes the nix vendor hash. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
The cli's docker and local render engines now mark a backend that lacks `crossplane internal render` as render.ErrStaleRenderBackend, so the diff render engine checks that sentinel instead of defining its own and matching the error text. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Port crossplane-diff's AppContext as internal/diff/client.New and share resource simulate's rest.Config construction via kube.RESTConfig. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Lift render xr's loadFunctionsFromProject into project.LoadFunctions with no behavior change. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
When spec.paths.apis is "/", project build walks the whole project and should skip the examples, functions and operations directories. Walk paths are rooted at "/" but the default excludes are relative, so the prefix check never matched and those directories were packaged. Anchor each exclude at "/" and match the directory itself or anything beneath it, so "examples" no longer matches "examples-foo" either. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Add LoadCompositions, which returns the Compositions under a project's APIs path using the same walk and excludes as project build. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Add ProjectFunctionProvider, a FunctionProvider that resolves pipeline steps naming a project function to that function and asks the wrapped (cluster) provider only for the remaining steps, so an embedded function that is not installed in the cluster no longer fails the lookup and an installed one no longer runs the stale cluster version. Returned functions are per-call copies, as CachedFunctionProvider's are. Overlaid functions carry no pull-policy annotation, so the docker runtime keeps its IfNotPresent default and daemon-loaded images run without a registry pull. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Add `crossplane project simulate`, which previews how a project's Compositions would change the composite resources in the user's current Kubernetes context. It builds the project's functions, overlays them on the cluster's functions by name, and runs the diff engine's composition diff, printing the result with the engine's own renderers (-o diff|json|yaml). Exit status is 0 on success, 1 on a tool error, 2 when only schema validation failed, and 130 when interrupted. The timeout bounds the whole simulation because the engine has no per-composite deadline yet. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Add --exit-code to `crossplane project simulate`. With it, a simulation that succeeds and finds changes exits with status 3, so CI can gate on it, as with git diff --exit-code. Without it, changes still exit 0, because finding them is what a simulation is for. Tool, schema-validation and interrupt statuses take precedence either way. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
…harness Port TestDiffIntegration and TestCompDiffIntegration from crossplane-diff origin/main 6a140b6 (cmd/diff/diff_integration_test.go, diff_it_utils_test.go, main_test.go and the ~350-file testdata tree) into internal/diff/integration, verbatim case tables included. Every case is CLI args plus an expected exit code and output, funneled through one runSimulate harness function that wires this repo's ported engine the way crossplane-diff's comp and xr commands do; when crossplane project simulate grows this surface, the harness swaps to the real command in a single-function change. Cases the simulate surface cannot express yet are ported in full and skipped with greppable gap:/env: reasons rather than dropped. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Auto-fix gci/tagalign/prealloc; preallocate the harness's option slice; mark the five builders carried verbatim from crossplane-diff whose cases are gap-skipped as nolint:unused with the reason. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
The gap/env guards sat after startIntegrationCluster, so a skipped case still booted envtest before skipping; move them ahead of cluster startup and thread the case's timeout in, since the args they inspect are built before the cluster too. Also skip when CROSSPLANE_CRDS_DIR is unset, so plain go test skips rather than fatals, and document the package in a README. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
TestDiffSingleResourceConcurrent starts its own envtest cluster, so it needs the same Docker/envtest/CRDS guards the runner applies; without them nix run .#test died in envtest.Start instead of skipping. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
The flag-parity branch is merged, so --no-color, --ignore-paths, --function-credentials, --eventual-state, --analyze-on, --analyze-unchanged (deprecated; simulate's --analyze-on=always) and --dry-run-on all exist on project simulate. Remove the gap guard and wire --function-credentials through the harness, loading its Secrets at parse time the way both crossplane-diff's kong MapperValue and simulate's own flag do. 41 of 142 subtests now run and pass (was 23); the remaining skips are the xr-mode and repeated --resource gaps plus crossplane-diff's own upstream skip reasons. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Package the envtest control-plane binaries (kube-apiserver, etcd, kubectl) from the controller-tools envtest v1.30.3 release, the version crossplane-diff's Earthfile targets. Wire KUBEBUILDER_ASSETS into the sandboxed test check, where the render-engine cases still skip on the missing Docker daemon but the envtest cluster cases can run, and add an unsandboxed integration-test app plus a CI job that runs it on a runner's host Docker daemon. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
… error Use the kubeconfig context's namespace for namespaced resources without one, as resource simulate does. Join a Composition render failure with the simulation's error instead of replacing it, by sharing one renderReport helper between the XR and Composition paths. Remove the unused DiffOptions.Format switch. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Parse --name once in Validate, drop the redundant WithoutCancel, inline selectServers, and make ref.Parse errors flag-neutral (wrapped as invalid --name by the caller). Delete the unused ref.ParseAll. Tighten RenderErrorKeepsDiffError and fix stale TestSimulateDiffOptions cases. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
…pendency manager Add project.NewXpkgClient and use it from render xr, render op, project build, run and simulate instead of five inline copies. Replace LoadFunctions/LoadFunctionsWithDigests with one LoadFunctions that takes the parsed project, the dependency manager and an options struct. Project simulate now parses the project once and builds one client and one manager (with schema generators) for both function and provider dependencies, so --image-configs, when set, replaces the project's ImageConfigs for both. The help says so. BuildWithMaxConcurrency clamps 0 to 1. Before, 0 made an unbuffered semaphore and render xr/op hung with --max-concurrency=0. Simulate's Validate check and the max() in build and run are no longer needed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
LoadFunctions always computed embedded function digests, which go through a strict configuration tag. render xr, which discards them, then failed for a project repository without an explicit registry and did index work for nothing. Add LoadFunctionsOptions.Digests; only simulate sets it. Log the project file path at the callers again, say what nil Generators means, and note that --image-configs doesn't change schema generation images. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
…via ImageConfigs Simulate takes the render engine flags as render does, including --crossplane-binary and --crossplane-docker-network (falling back to CROSSPLANE_DIFF_DOCKER_NETWORK). --function-registry-override is gone: function images, except the project's embedded functions, are rewritten by the effective ImageConfigs, which --image-configs replaces and which may now be used with --skip-plan. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
EngineFlags' --session-id help now takes a kong variable, so simulate describes the diff-server label it actually sets, while render keeps its text. Pin that ImageConfig rewrites keep a digest, leave the ImageConfig out of the rewrite error when none was selected, drop the test-only NewProjectFunctionProviderFactory, and move --image-configs out of the provider-plan section of the help, noting the binary and docker-network xor and that an unparseable project file in the cwd is an error. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Shorten flag help to one sentence and move the details to help.md. Take --function-credentials as a plain path and load it in Validate with render.LoadCredentials, keeping only v1 Secrets. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Check each document's TypeMeta before decoding it as a Secret, so other kinds such as a ConfigMap with plain-text data are ignored, not rejected. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
plan.Result, plan.Summary and plan.Renderer go back to their shape on main, so resource simulate's -o json|yaml no longer carries project fields or summary.deferred, and its format version resets to 0.1. Project simulate's result moves to simulate.ProjectResult, which embeds plan.Result and holds the composites, compositions, errors, warnings and notes. ProjectSummary.Deferred is now counted from the composites in NewProjectResult instead of being set by whoever builds them. The project renderer reuses plan.RenderPlan, RenderSummaryLine and RenderSummaryWarnings. Drop Verification.Performed: a Verification is present only for a dry run that was not performed. Fix the Pinned doc to match deferred composites, which are pinned too. plan no longer imports internal/diff/compare: cleanView strips status, server-managed metadata, last-applied-configuration and composed resource references itself. BREAKING CHANGE: project simulate's JSON drops dryRun.performed and reports formatVersion 0.1. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
ProjectResult embedded plan.Result, so encoding/json wrote the embedded plans ahead of the outer summary, composites and compositions. A MarshalJSON now writes the keys in their previous order: formatVersion, errored, summary, composites, compositions, plans, errors, warnings, notes. YAML goes through it too. The summary has one source: Result.Summary holds the plan counts, and Deferred() counts deferred composites, joined only when serialized. ProjectSummary is gone. cleanView's doc now says it deliberately skips the engine's synthetic-name rule, and a test pins that a generateName-shaped name and an empty spec.crossplane are kept. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
…paths Change paths are now crossplane-runtime fieldpath strings, the syntax --ignore-paths reads. Drop JoinKey, isIdent, PathSegments and simtest's parsePath in favour of fieldpath.Segments/Parse. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
…dpath Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Replace common.ExitStatus and project simulate's exitError with one common.ExitError (a kong.ExitCoder); a nil Err exits silently, which main honours. resource simulate now exits 3 when a plan would change anything, and its --cache-dir follows the CLI convention (CROSSPLANE_XPKG_CACHE, dependency.DefaultCacheDir()). Flags that do nothing for the inputs warn; misleading scope flags with XR files exit 80. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
…lags resource simulate exits 1 after rendering when any plan errored, as project simulate does. --providers and --session-id with --skip-plan now warn instead of exiting 80. Add common.ExitCodeChanges and ExitCodeSchemaValidation, pinned to the engine's codes, and exit silently only for an unwrapped ExitError value via common.SilentExit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
kong's Context.Run returns errors.Join(runErr, hookErr), so an unwrapped type assertion never matched and changes found printed an empty error and exited 1. Match with errors.As, and require an empty message so a wrapping or joined error is still printed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
… flags Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Use "cluster diff" and "provider plan" throughout, print one no-diff-server message (stderr only for -o diff, Notes otherwise), drop crossplane-diff from the help, and trim help internals. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
…splane-diff from messages Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Load -f inputs with ld.WithoutPipelineInputs() so the loader never returns Composition step inputs as manifests, and delete pipelineInputs, which dropped any real resource identical to a step input. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
…ommand Move internal/diff/integration into cmd/crossplane/project behind the integration build tag, so internal/ no longer imports cmd/ from tests, and unexport the simulate test hooks. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
| // provider diff servers as the engine finishes rendering it, so an XR whose | ||
| // plans fail is reported as an error, whole, like a failed render. | ||
| // | ||
| // It keeps one plan per diff key: when two XRs produce the same key, the |
There was a problem hiding this comment.
what happen if two XRs render the same composed resource differently, XR B report is merged with a provider plan computed from XR A desired object. Please key by (XR, diff key), or flag the conflict?!
| } | ||
| } | ||
|
|
||
| plans := PlanDiffs(ctx, x.planner, x.keep, diffs) |
There was a problem hiding this comment.
Keys that are already collected are still planned over gRPC, and the result is thrown away; if that call fails, XR B fails for nothing. Please skip keys you already have.
| keep func(*unstructured.Unstructured) bool | ||
| ensure EnsureServers | ||
|
|
||
| mu sync.Mutex |
There was a problem hiding this comment.
The mutex only covers half of the contract, while the comment says the engine is sequential. Either drop it and document not safe for concurrent use, or lock all of AfterXRDiff
| for _, r := range resources { | ||
| gvk := r.GroupVersionKind() | ||
| gk := gvk.GroupKind() | ||
| img, ok := cache.images[gk] |
There was a problem hiding this comment.
There are three caches with three failure policies. crdDefaults refuses to cache transient errors, but RelevantProviderImages caches "" on any error and ProviderManaged caches false silently, which drops provider-found drift. Please use one rule: never cache non-definite answers.
| // A lookup that fails answers false, so the resource keeps the engine's | ||
| // verdict alone. XRs are never provider-managed: their CRDs are controlled by | ||
| // their CompositeResourceDefinition. | ||
| func ProviderManaged(ctx context.Context, kubeClient client.Client, rmapper meta.RESTMapper) func(*unstructured.Unstructured) bool { |
There was a problem hiding this comment.
nit: the same CRD is fetched by multiple code paths:
ProviderManaged, RelevantProviderImages and default.go, on top of the engines own SchemaClient CRD cache. Please use one per-run CRD lookup and derive the answers from it
| } | ||
| } | ||
|
|
||
| // RenderImage returns the fully-resolved render image reference the engine will |
There was a problem hiding this comment.
resolveRenderImage is a copy of render.crossplaneImageFromFlags. Please export the render helper and delete this one. RenderImage() is used only in tests...
|
|
||
| switch { | ||
| case bySelector == 0 && byDeletion == 0: | ||
| return fmt.Sprintf("All %d XR(s) using composition %s have Manual update policy (use --include-manual to see them)", |
There was a problem hiding this comment.
The user-facing text says "use --include-manual", but the flag here is --include-pinned - think in the design doc we usinging include-manual right ?
| ) | ||
|
|
||
| // EnvironmentClient handles environment configurations. | ||
| type EnvironmentClient interface { |
There was a problem hiding this comment.
is this every used ? feels death code here
| limitations under the License. | ||
| */ | ||
|
|
||
| // Package dockerrun ties the Docker resources a crossplane-diff run creates — function containers, the |
There was a problem hiding this comment.
This is a third container cleanup scheme next to internal/containerruntime and internal/diffserver, which use other labels and are never reaped. One command now has two cleanup strategies. Please either move lease/reap into containerruntime for everything, or drop it from this PR.
| @@ -0,0 +1,82 @@ | |||
| /* | |||
There was a problem hiding this comment.
Per run we now build two Kubernetes client stacks with two discovery caches (client/core + client/kubernetes vs simulate.NewKubeClient) and two CRD-default caches (diffprocessor/defaulter.go vs internal/simulate/defaults.go). Please share one.
…ssplane-simulate Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
…tials Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Description of your changes
Adds an alpha
crossplane project simulate(#367) built on thecrossplane diffengine, ported from crossplane-diff intointernal/diff. It previews how a project's changed Compositions and embedded functions affect the XRs on a live cluster. Provider diff servers then plan each composed managed resource.Builds on #429 (
resource simulate, merged).Engine port (
internal/diff/**): the renderer, types, ref, dockerrun, the core/kubernetes/crossplane clients and the diffprocessor, ported from crossplane-diff (import rewrites and gci grouping only), plus a client bundleclient.New. It tracks upstream through crossplane-diff#591, #593, #594, #595, #597 and #598:internal/diff/compare.XRReport,CompDiffOutput), and the command renders them.internal/diff/result.CLI-only engine additions, written to be upstreamable: an opt-in per-XR budget (
WithXRTimeout), whose clock pauses while shared work runs (OutsideXRDeadline), and an after-XR hook (WithAfterXRDiff).Integration tests (
internal/diff/integration): every case from crossplane-diff'sTestDiffIntegrationandTestCompDiffIntegration, run against envtest with the real Docker render engine. OnerunSimulatefunction translates each case's crossplane-diff arguments and runs the realproject simulatecommand through kong. Structured assertions checkplan.Result.simtest.Expect()/AssertStructured), since every mode emits the sameplan.Result. Each mode keeps its own matching rules, so no check got weaker or stricter.TestProjectSimulateIntegrationruns the command on real project files: malformed and empty projects, a project mixed with other inputs, a plain project that must match Composition mode's result, an embedded function that must win over a same-named cluster Function, and a provider dependency that must decide which diff server is used (through a test-onlySimulateHooks.Servers).CrossNamespaceResourceCollision,AddedResourceRetainsCompositionAuthoredStatus). Nogap:skips remain.nix run .#integration-test, or./nix.sh run .#integration-testin a container).Project glue:
project.LoadFunctions(lifted fromrender xr),project.LoadCompositionsandproject.LoadProviderDependencies.FunctionProviderthat serves project functions by name and falls back to the cluster's.project push.kube.RESTConfig, now shared withresource simulate.project simulatecommand (alpha).-f/--inputis repeatable and picks the mode from what it's given:comp. XRs are found on the cluster, and the cluster's functions run.xr. Compositions and functions come from the cluster.compandxrdo.-f: commas are part of the path; repeat-ffor more inputs.--name,-n,--max-concurrency,--max-iterations,--timeout) fail during parsing, before any function build or server start.-c/--context, impersonation,-n,--name(repeatable, comma-separated, acceptsns/name),--include-pinned,--max-iterations,--timeout,--max-concurrency,--cache-dir,-o plan|diff|json|yaml, the render-backend version flags, and crossplane-diff's other common flags (--ignore-paths,--function-credentials,--dry-run-on,--analyze-on, ...).Provider plans: each composed managed resource is planned by its provider's diff server, with
resource simulate'sPlanner, now shared ininternal/simulate. Unchanged provider-managed resources are planned too, so cloud drift shows.--skip-plan,--providers,--image-configsand--session-id. Planning is on by default.--providersoverrides. Otherwise project mode uses the project's provider dependencies, and Composition and XR modes start the cluster's providers on demand for the kinds actually rendered. A failed lookup for a kind skips that kind with one warning.approximate.Output:
-o planis the default terraform-style view.-o json|yamlemitplan.Result(formatVersion0.3) through one mapper (internal/simulate.FromXRReportandFromCompReport).-o diffis crossplane-diff's diff, plus inline# forces replacement,(known after apply)and a(requires replacement)header and summary count, but only when provider plans ran. Without them it is byte-identical to crossplane-diff.plan.Result: each plan carriesbefore(live) andafter(rendered), the cleaned objects the diff compares, with Secret values redacted. It also carries composite grouping, typed errors with validation failures, warnings, revision impact for each Composition, dry-run verification, a deferred count, and notes. The notes say when the provider layer was skipped or no diff server served the resources.resource simulateshares the model, so its JSON gainsbefore/afterand the same stripping.Render: a typed
render.ErrStaleRenderBackend, so the engine can tell a stale render backend apart from other errors.Pinned XRs: an XR on a Manual policy whose pinned revision calls a changed embedded function is rendered against that revision, with the project's functions, and reported with
pinned: trueand adetailnaming the revision. Otherwise pinned XRs are deferred, still withpinned: true.Nix and CI: pinned Crossplane v2.4.1 CRDs and envtest v1.30.3 assets (Linux and macOS, amd64 and arm64) for the tests. The integration tests need Docker for the render engine, and the Nix sandbox has none.
integrationbuild tag, the same way the existingcompilegatetests do, and lint still covers them.nix run .#integration-testapp andintegration-testsCI job, outside the sandbox. Unit tests andflake checkare unchanged. The app keeps the host PATH (nix inputs first) so Docker's credential helpers resolve.-coverpkg=./...profile to codecov under theintegrationflag, and codecov merges it with theunittestsupload for the same commit.Still to do for #367:
crossplane project simulateandcrossplane resource simulatedocs#1162, after this PR passes review.Decisions to review (hard to reverse, even under alpha):
project simulatewrites into the project. In project mode, simulate builds the embedded functions the same wayproject buildandrender xrdo. That generates language schemas into the project'sschemas/directory as a side effect. For a preview command, that may be unexpected: running it in CI or on a clean checkout leaves a modified working tree. Should simulate generate schemas into a temporary directory instead, leaving the project untouched? Or is writing them acceptable, sincerender xralready does it and the schemas are needed to build the functions anyway? If we change it, shouldrender xrchange with it?-o planis the default,-o json|yamlemitplan.Result, and crossplane-diff's v1/v2 JSON schemas are gone.plan.Resultfield shapes: every summary count is always present (deferredincluded); a composite'sreasonis a camelCase enum (manualPolicy,revisionSelectorMismatch,deleting,unknown), mapped explicitly from the engine's values so an upstream rename can't silently change the contract; an error's resource iserrors[].ref;pinnedis true for every XR on a Manual policy. Every input mode emits this one shape, butcompositionsandcompositesareomitempty, so an XR-mode result has nocompositionskey rather than[]. Do reviewers agree, or should both always be present so consumers see the same keys whatever-fis given?before/afterinplan.Result: they follow terraform'sshow -jsonand are null for a create or delete respectively. A resource whose only change is provider-side drift has no objects.plan.Result:pathis one string. Plain keys join with., list indexes are[N], and any other key is quoted terraform-style as["key"], e.g.metadata.annotations["crossplane.io/composite"]. This lets annotation and label keys round-trip, but json/yaml consumers must parse the grammar to split a path. An additivesegmentslist is an option if that's a burden. Paths from upjet's diff servers don't quote dotted TF map keys (e.g. atagskeya.b), which needs an upjet change.common.ExitStatusthatmainexits with after a run that returns no error. Errors still exit through kong'sFatalIfErrorf.--timeout(default 2m, must be > 0) is a per-XR budget covering the XR's render and its resources' provider plans.-f/--input,--name,--include-pinned,-c/--context,--skip-plan,--providers,--image-configs,--session-id.-fclassification: a single file that isn't a project file and holds no Compositions is treated as XRs. Each one is checked against the cluster's XRDs, as a claim and then as an XR. Anything else (a Configuration, a Provider, a ConfigMap) is rejected with its kind, name and what-faccepts.ERROR: Kind/name: .... kong prints the returned error once, ascrossplane: error: ..., and that error names each failing resource. Structured output'serrors[]is unchanged.Also worth a look:
fix(project):project buildwithspec.paths.apis: "/"no longer packages XRDs and Compositions fromexamples,functionsandoperations. It's a separate commit, easy to cherry-pick on its own.resource simulatechanges:internal/simulate, including fix(simulate): stop planning server-defaulted and late-initialized fields as removals in the approximate diff #441's CRD defaulting and Simulate development runtime #443's Development runtime, soproject simulate's provider plans get both.--timeout 0means no per-plan limit.go.yaml.in/yaml/v3v3.0.5,golang.org/x/sysv0.48.0. The port's semver use moved to Masterminds v3.-f -) hasn't been tested end to end.I have:
./nix.sh flake checkto ensure this PR is ready for review.crossplane project simulateandcrossplane resource simulatedocs#1162.Addedbackport release-x.ylabels to auto-backport this PR.🤖 Generated with Claude Code