Skip to content

Surface an UpToDate condition showing would-be changes for observed Objects #523

Description

@jcogilvie

What problem are you facing?

When adopting an existing Kubernetes resource into Crossplane, we run the Object in Observe-only mode first, to prove the import is a no-op before granting the provider write access. The goal is a "zero-diff import": Crossplane should not want to change anything about the resource (beyond, in the AWS-provider analogy, tags) before we consider it safe to manage.

Today an observe-only Object gives us no visibility into what Crossplane would change if we switched it to update mode. spec.forProvider vs status.atProvider comparison is manual and, in observe mode, the provider owns no fields so there is nothing meaningful to compare. To actually flush out would-be changes we currently have to perform a convoluted state-machine step: flip the management policy from observe to update while simultaneously swapping the ProviderConfig to a permissions-restricted (e.g. tag-only) role, so that any attempted change beyond the allowed set is rejected with a 403, and then trace the 403 back to the offending field. That is slow, error-prone, and requires a credential-rotation dance.

We would like a first-class signal, available while the resource is still observe-only and untouched, that answers: "when I switch this Object to update mode, what actually changes on the live resource?"

How could Crossplane help solve your problem?

crossplane-runtime is adding an UpToDate status condition to the managed reconciler (see crossplane/crossplane-runtime#945, tracking crossplane/crossplane-runtime#939). It reflects the Observe result as a condition with reasons ObserveMatched (True), and UpdateRestricted / UpdateRequested / UpdateFailed (False), plus ReconcilePaused (Unknown), and carries a diff message on the False states.

provider-kubernetes can implement this so that, for an Object:

  • In sync (an update would change nothing) → UpToDate: True / ObserveMatched.
  • Would change (an update would modify the live resource) → UpToDate: False / UpdateRestricted, with a field-level diff in the condition message describing exactly what would change — and, in observe mode, without mutating the resource.

The important property for the import use case is that the diff answers "what would update mode change?" independent of current field ownership. Concretely, the provider (on the server-side-apply path) can dry-run applying the manifest as the provider field owner with ForceOwnership — exactly what an update would do — and diff the result against the live object. This shows precisely the fields the manifest would change, even for a resource currently owned entirely by another actor (the import scenario), while leaving fields the manifest does not mention untouched.

This collapses the observe → tag-only-ProviderConfig → 403-hunting detour into simply reading the UpToDate condition on an observe-only Object.

Notes / scope

  • Depends on the crossplane-runtime UpToDate work (crossplane/crossplane-runtime#945); provider-kubernetes needs to populate ExternalObservation.Diff and derive up-to-date-ness meaningfully in observe mode.
  • Applies to both the cluster-scoped (v1alpha2) and namespaced (v1alpha1) Object controllers.
  • Open design questions worth discussing on the PR: whether connection details should be published for observe-only resources, diff-message truncation for large diffs, and human-friendly rendering of the diff.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions