Repository navigation
Conversation
Signed-off-by: Christopher Haar <christopher.haar@upbound.io>
Signed-off-by: Christopher Haar <christopher.haar@upbound.io>
| Examples: | ||
|
|
||
| # Preview what applying resources.yaml would do. | ||
| crossplane resource simulate -f resources.yaml | ||
|
|
||
| # Preview against a specific provider version instead of the installed one. | ||
| crossplane resource simulate -f resources.yaml --provider-images xpkg.upbound.io/upbound/provider-aws-ec2:v2.9.0 | ||
|
|
||
| # Keep diff servers running for faster subsequent runs. | ||
| crossplane resource simulate -f resources.yaml --keep-diff-servers | ||
|
|
||
| # Emit machine-readable results for CI gating. | ||
| crossplane resource simulate -f resources.yaml -o json |
There was a problem hiding this comment.
Nit: we should format these to match what we have in other commands:
| Examples: | |
| # Preview what applying resources.yaml would do. | |
| crossplane resource simulate -f resources.yaml | |
| # Preview against a specific provider version instead of the installed one. | |
| crossplane resource simulate -f resources.yaml --provider-images xpkg.upbound.io/upbound/provider-aws-ec2:v2.9.0 | |
| # Keep diff servers running for faster subsequent runs. | |
| crossplane resource simulate -f resources.yaml --keep-diff-servers | |
| # Emit machine-readable results for CI gating. | |
| crossplane resource simulate -f resources.yaml -o json | |
| ## Examples | |
| Preview what applying resources.yaml would do: | |
| ```shell | |
| crossplane resource simulate -f resources.yaml | |
| ``` | |
| Preview against a specific provider version instead of the installed one: | |
| ```shell | |
| crossplane resource simulate -f resources.yaml --provider-images xpkg.upbound.io/upbound/provider-aws-ec2:v2.9.0 | |
| ``` | |
| Keep diff servers running for faster subsequent runs: | |
| ```shell | |
| crossplane resource simulate -f resources.yaml --keep-diff-servers | |
| ``` | |
| Emit machine-readable results for CI gating: | |
| ```shell | |
| crossplane resource simulate -f resources.yaml -o json | |
| ``` |
|
|
||
| images := c.ProviderImages | ||
| if len(images) == 0 { | ||
| if images, err = installedProviderImages(ctx, kubeClient); err != nil { |
There was a problem hiding this comment.
Rather than defaulting to all the installed providers, could we find only the providers that are relevant to the resources? I believe we can do that by finding the relevant CRDs in the cluster and following their owner refs.
| // The provider config lives in the provider family's group, one label | ||
| // above the resource's group: ec2.aws.m.upbound.io -> aws.m.upbound.io. |
There was a problem hiding this comment.
This isn't true for all providers (e.g., provider-kubernetes). But, I'm not sure how we can reliably determine the right group, aside from asking the provider.
| for _, p := range providers.Items { | ||
| img := p.Status.CurrentIdentifier | ||
| if img == "" { | ||
| img = p.Spec.Package |
There was a problem hiding this comment.
I wonder if we will want a way to apply ImageConfig rewrites to these images. For crossplane project simulate obviously we can use what's in the project metadata. For resource simluate maybe we should have a flag. Another option would be to use the p.Status.ResolvedPackage, but that assumes the same rewrites used in the cluster make sense locally, which I expect is often not true.
| if kubeconfig.QPS == 0 { | ||
| kubeconfig.QPS = 20 | ||
| } | ||
| if kubeconfig.Burst == 0 { | ||
| kubeconfig.Burst = 30 | ||
| } |
There was a problem hiding this comment.
Might be worth a comment explaining why we set these values.
| id, err = m.rt.StartContainer(ctx, name, image, | ||
| // --debug precedes the subcommand: it is the provider's global flag. | ||
| docker.StartWithCommand([]string{"--debug", "internal", "diff-server", "--address", fmt.Sprintf(":%d", containerPort)}), | ||
| docker.StartWithPublishedPort(netip.MustParseAddr("127.0.0.1"), containerPort), |
There was a problem hiding this comment.
We might need a way to override this, like we have in render with the runtime-docker-publish-address annotation. Fine to leave it hard-coded for the first version, but given the esoteric Docker setups we see from users I expect it's something we'll have to figure out.
Description of your changes
Implements
crossplane resource simulateper the accepted design(design/one-pager-cli-simulate.md): given YAML for one or more managed resources (-f), preview what applying them would do, provider-computed, end to end.For each input resource the CLI fetches the live MR from the current kubeconfig context, runs the providers own package image locally as a diff server (the gRPC
PlanServiceupjet providers now serve viainternal diff-server,merged in crossplane/upjet#765, crossplane/upjet#769, crossplane/upjet#778), and renders the providers verdict: create, update, no-op or the replace nobody spotted in review, with the unsynced-until-replaced warning. Replaces are counted separately in the summary and never presented as destroy-and-recreate.
Resources without a diff server (no
DiffServercapability, no route, or the server refuses the resource) degrade to an honest client-side diff marked[?]with the approximate warning and nothing fails the run, nothing silently dropsout.
The design one-pager predated the merged upjet protocol
internal diff-serverand the package capability isDiffServer(spec.capabilities); the gRPC service remainsPlanService(proto/diff/v1alpha1).GetInfowas dropped: routing is built client-side from the CRDs inside each provider package, by group and kind, and the capability is checked before any container starts.Planrequest.FAILED_PRECONDITION/DIFF_COMPUTATION_NOT_SUPPORTEDmapping to the[?]fallback.kubernetes_object_storecarries the referenced ProviderConfig, fetched with the user's own kubeconfig and RBAC (the server is offline and sees only what travels in the request; credentials Secrets deliberately stay out today and the server plans with placeholder, but we need this as some providers e.g. gcp uses fields like projectIds).Groundwork for project simulate (#367)
This PR deliberately builds the shared pieces
project simulatemust reuse, so the two commands converge on one implementation and we need to sync in a followup PR:internal/planthe typed per-resource result (actions, field changes with sensitive/known-after-apply/unresolved markers, replace paths), the diff server client, and the output renderers (-o plan|json|yaml, versioned JSON/YAML envelope with a top-levelerroredgate for CI).internal/plan.Fallbacktheclient-side diff ([?]path). Schema-less by design; expected to be subsumed by crossplane-diff's calculator when its machinery moves in with Addcrossplane project simulate#367.-o diffis intentionally not implemented here: crossplane-diff renders real full-manifest unified diffs today, and that renderer is what-o diffshould become, not a lower-fidelity imitation.internal/diffservercapability gate, CRD-based routing table, container lifecycle with deterministic digest-derived names and--keep-diff-serversreuse eg. feat(render): label docker containers and networks created by render #407Implementation notes
resource simulateenters the tree as alpha; provider images come from the providers installed on the cluster by default,--provider-imagesoverrides.internal/dockergains a published-port option + host-port lookup, the same mechanism render's function runtime uses, lifted from its private code into the shared helpers.Fixes #368
Implements the
resource simulatehalf of #369 (project simulate planning,--allprovider upgrade preview, and--skip-plancan followup with a new PRI have:
./nix.sh flake checkto ensure this PR is ready for review.backport release-x.ylabels to auto-backport this PR.Need help with this checklist? See the cheat sheet.
Tested