Skip to content

Generated controllers never set WithDeterministicExternalName, blocking recovery from external-create-pending #681

Description

@polds

What happened?

Generated controllers build the reconciler options in pkg/pipeline/templates/controller.go.tmpl without managed.WithDeterministicExternalName, so deterministicExternalName is false for every upjet resource.

When a create is interrupted after crossplane.io/external-create-pending is set but before -succeeded/-failed is recorded (for example the provider pod restarts during an async create), crossplane-runtime treats the create as incomplete. With deterministicExternalName false it refuses to retry, and the MR is stuck indefinitely on:

cannot determine creation result - remove the crossplane.io/external-create-pending annotation if it is safe to proceed

crossplane-runtime already handles the safe case: when deterministicExternalName is true it logs "proceeding due to deterministic external name" and continues. Resources with a user-supplied external name (everything except config.IdentifierFromProvider) are deterministic, so the retry is safe and would not leak a resource. Because upjet never opts in, the only recovery is deleting the annotation by hand, which is not viable for GitOps-managed clusters.

How can we reproduce it?

  1. Pick a resource with a user-supplied external name (config.NameAsIdentifier or config.TemplatedStringAsIdentifier).
  2. Create an instance, then restart the provider pod while the async create is in flight, so external-create-pending ends up as the newest of the three external-create-* annotations.
  3. The MR stays Synced=False with "cannot determine creation result" and never retries until the annotation is removed manually.

Suggested fix

Add managed.WithDeterministicExternalName(deterministic) to the opts in controller.go.tmpl, with deterministic derived from the resource config: false for config.IdentifierFromProvider (provider-assigned id), true for user-supplied external names.

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