Skip to content

Support optional DoDelete in the direct engine - #6647

Draft
denik wants to merge 1 commit into
mainfrom
denik/optional-delete
Draft

Support optional DoDelete in the direct engine#6647
denik wants to merge 1 commit into
mainfrom
denik/optional-delete

Conversation

@denik

@denik denik commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Resources whose deletion has no backend effect — grants, permissions, secret_scope_acls — previously implemented a no-op DoDelete (return nil). This makes DoDelete optional: omitting it declares the same intent, and lets the engine treat a planned Delete for such a resource as a state-only cleanup.

Optimizations unlocked

Knowing a resource's delete is a no-op lets the engine do less and say less:

  • Skip the remote read at plan time. For a Delete on such a resource the planner no longer calls DoRead — its only purpose was detecting an already-gone resource so apply could skip the delete call, which is pointless when there is no delete call. Fewer API round-trips, and no spurious read errors: e.g. destroy_without_mgmtperms no longer emits a "does not have Manage permissions" warning.
  • Skip the delete scaffolding at apply. There was never a backend delete for these resources (that is the whole point), so the entry is now dropped straight from state via the same path as Gone, instead of running the full delete path (loading the persisted state and dispatching the no-op DoDelete/WaitAfterDelete).
  • Omit from human output. These deletes are dropped from the textual plan, the deploy/destroy summaries, and the destructive-action prompt. They are excluded from the resource counts entirely (neither deleted — nothing was — nor unchanged — the state entry was removed), so the Resources:/Plan: tally only reflects real backend actions.
  • prevent_destroy becomes inert for these resources — there is nothing to destroy.
  • Kept in the JSON plan (action: delete, state_only: true), so machine consumers still see the state transition.

Technical changes

  • dresources/adapter.go: DoDelete is now an optional bound caller; HasDoDelete() reports it; the wrapper is a nil-guarded no-op and its state-type validation is conditional. The three no-op DoDelete bodies are removed (rationale kept as comments).
  • deployplan (plan.go, action.go): new PlanEntry.StateOnly flag (serialized state_only), a sibling to Gone. Unlike Gone (a property of remote state) it is a property of the resource type. CountActions leaves StateOnly deletes out of the tally.
  • bundle_plan.go: on a Delete for a resource with no DoDelete, skip the remote read and set StateOnly.
  • bundle_apply.go: a StateOnly delete removes the state entry without running the delete path (shares the existing Gone branch).
  • phases/deploy.go, phases/destroy.go, cmd/bundle/plan.go: exclude StateOnly deletes from approval, summaries, and the textual plan.
  • deploy/terraform/showplanfile.go: the terraform plan reader marks the same permissions/grants/secret_acls deletes StateOnly, so both engines' human-facing output stays identical. This changes only what is shown, not what terraform applies.

Tests

  • Unit tests updated/green: bundle/direct/..., bundle/deployplan/..., bundle/deploy/terraform/..., bundle/phases/..., cmd/bundle/....
  • Acceptance goldens regenerated (12 files under permissions/, secret_scopes/).

This pull request and its description were written by Isaac.

@eng-dev-ecosystem-bot

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: ba38843

Run: 34613474728

Env 💚​RECOVERED ✅​pass 🙈​skip Time
💚​ aws linux 1 283 18 14:05
💚​ aws windows 1 285 16 8:08
💚​ azure linux 1 278 19 9:38
💚​ azure windows 1 280 17 5:21
💚​ gcp linux 1 279 19 11:04
💚​ gcp windows 1 281 17 7:19
Test Name aws linux aws windows azure linux azure windows gcp linux gcp windows
💚​ TestAccept 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
Top 10 slowest tests (at least 2 minutes):
duration env testname
4:53 gcp windows TestAccept
3:27 azure windows TestAccept
3:26 aws windows TestAccept
2:57 aws linux TestAccept/bundle/resources/secret_scopes/delete_scope/DATABRICKS_BUNDLE_ENGINE=terraform/DMS=
2:52 aws linux TestFilerWorkspaceFilesExtensionsReadDir
2:18 aws windows TestAccept/bundle/resources/secret_scopes/delete_scope/DATABRICKS_BUNDLE_ENGINE=terraform/DMS=
2:14 aws windows TestAccept/bundle/resources/secret_scopes/delete_scope/DATABRICKS_BUNDLE_ENGINE=direct/DMS=true
2:03 aws linux TestAccept/bundle/resources/secret_scopes/delete_scope/DATABRICKS_BUNDLE_ENGINE=direct/DMS=
2:02 aws linux TestImportDirWithOverwriteFlag
2:02 gcp linux TestAccept/bundle/resources/secret_scopes/delete_scope/DATABRICKS_BUNDLE_ENGINE=direct/DMS=true

@denik
denik force-pushed the denik/optional-delete branch from ba38843 to e1a2487 Compare September 11, 2026 16:14
Resources whose deletion has no backend effect (grants, permissions,
secret_scope_acls) can now omit DoDelete instead of implementing a no-op.
The engine treats a planned Delete for such a resource as a state-only
cleanup (new PlanEntry.StateOnly flag):

- adapter.go: DoDelete is optional; HasDoDelete() reports it.
- Direct planner skips the remote read for the Delete (only used to detect
  already-gone resources, pointless when there is no delete call) and marks
  the entry StateOnly; apply removes the state entry without a delete call.
- Shared rendering/counts (bundle plan text, deploy summary, destroy list,
  approval, CountActions) treat StateOnly as non-destructive/unchanged; the
  Delete stays in the JSON plan.
- Terraform plan reader marks the same groups StateOnly so both engines'
  human output stays consistent (no change to what terraform applies).

Co-authored-by: Isaac <no-reply@databricks.com>
@denik
denik force-pushed the denik/optional-delete branch from e1a2487 to 8d344c9 Compare September 11, 2026 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants