Skip to content

direct: don't treat an explicit scalar zero as an empty no-op change - #6825

Open
arloc wants to merge 1 commit into
databricks:mainfrom
arloc:main
Open

arloc wants to merge 1 commit into
databricks:mainfrom
arloc:main

Conversation

@arloc

@arloc arloc commented Sep 24, 2026

Copy link
Copy Markdown

direct: don't treat an explicit scalar zero as an empty no-op change

Changes

  • Replace the allEmpty(ch.Old, ch.New, ch.Remote) call in addPerFieldActions with allEmptyChange(ch): Old/Remote keep the permissive isEmpty (a zero-ish backend echo for a field nobody asked to change still counts as empty), but New is checked strictly — a concrete scalar zero/false there already survived structdiff's ForceSendFields-aware nil substitution, so it is a real, explicitly force-sent value and must not be classified as empty.
  • Add three regression tests in bundle_plan_test.go:
    • TestScalarZeroIsNotEmpty: the fix itself, gcp_attributes.local_ssd_count set to 0 for the first time is detected as an update.
    • TestUnsetScalarWithBackendEchoIsStillEmpty: no-regression guard, an unrelated field the config never sets (e.g. timeout_seconds) whose
      remote echoes a scalar zero stays a no-op.
    • TestRemovingManagedOverrideMatchingRemoteIsEmpty: documents intentional behavior - removing a managed override when remote already matches the last explicit value stays a no-op (gcp_attributes is ignore_remote_changes: managed, so the tool never actively resets it).
  • Add a Cloud=false acceptance test under acceptance/bundle/resources/clusters/deploy/local_ssd_count_update covering the update path; the existing local_ssd_count test only covers create.

Why

Direct-engine bundle plan silently dropped an update that explicitly forces gcp_attributes.local_ssd_count: 0 on a cluster/job previously deployed without the field. isEmpty()'s blanket IsZero() -> true shortcut conflated a real, force-sent 0 with an unset field, so the change was classified ReasonEmpty before ever reaching the ignore_remote_changes: managed rule for gcp_attributes. GCP doesn't reliably echo local_ssd_count back on GET, so the field never converged even across repeated deploys. Reported against a real GCP workspace; see databricks/terraform-provider-databricks#4089 for the same underlying backend quirk in Terraform.

Tests

  • go test ./bundle/direct/...
  • go test ./bundle/... ./libs/structs/...
  • New acceptance test (generated output.txt/out.test.toml)
  • Manually verified against a real GCP workspace: setting the field, unrelated fields (disabled, timeout_seconds), and removing the override all now behave correctly.

- Replace the `allEmpty(ch.Old, ch.New, ch.Remote)` call in
  `addPerFieldActions` with `allEmptyChange(ch)`: `Old`/`Remote` keep the
  permissive `isEmpty` (a zero-ish backend echo for a field nobody asked
  to change still counts as empty), but `New` is checked strictly — a
  concrete scalar zero/false there already survived structdiff's
  ForceSendFields-aware nil substitution, so it is a real, explicitly
  force-sent value and must not be classified as empty.
- Add three regression tests in bundle_plan_test.go:
  - TestScalarZeroIsNotEmpty: the fix itself, gcp_attributes.local_ssd_count
    set to 0 for the first time is detected as an update.
  - TestUnsetScalarWithBackendEchoIsStillEmpty: no-regression guard, an
    unrelated field the config never sets (e.g. timeout_seconds) whose
    remote echoes a scalar zero stays a no-op.
  - TestRemovingManagedOverrideMatchingRemoteIsEmpty: documents intentional
    behavior - removing a managed override when remote already matches
    the last explicit value stays a no-op (gcp_attributes is
    ignore_remote_changes: managed, so the tool never actively resets it).
- Add a Cloud=false acceptance test under
  acceptance/bundle/resources/clusters/deploy/local_ssd_count_update
  covering the update path; the existing local_ssd_count test only
  covers create.

Direct-engine `bundle plan` silently dropped an update that explicitly
forces `gcp_attributes.local_ssd_count: 0` on a cluster/job previously
deployed without the field. `isEmpty()`'s blanket `IsZero() -> true`
shortcut conflated a real, force-sent `0` with an unset field, so the
change was classified `ReasonEmpty` before ever reaching the
`ignore_remote_changes: managed` rule for gcp_attributes. GCP doesn't
reliably echo local_ssd_count back on GET, so the field never converged
even across repeated deploys. Reported against a real GCP workspace;
see databricks/terraform-provider-databricks#4089 for the same
underlying backend quirk in Terraform.

- `go test ./bundle/direct/...`
- `go test ./bundle/... ./libs/structs/...`
- New acceptance test (generated output.txt/out.test.toml)
- Manually verified against a real GCP workspace: setting the field,
  unrelated fields (disabled, timeout_seconds), and removing the
  override all now behave correctly.
@arloc
arloc requested review from a team as code owners September 24, 2026 00:35
@github-actions

Copy link
Copy Markdown
Contributor

An authorized user can trigger integration tests manually by following the instructions below:

Trigger:
go/deco-tests-run/cli

Inputs:

  • PR number: 6825
  • Commit SHA: 99a29e4b61dc0034e222c20b138039b8acf929f9

Checks will be approved automatically on success.

@github-actions github-actions Bot added the DABs DABs related issues label Sep 24, 2026

This branch has not been deployed

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

Labels

DABs DABs related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant