Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .nextchanges/bundles/postgres-oneof-update-mask.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
direct: Fix deploying an update to `expire_time`, `ttl` or `suspend_timeout_duration` on Lakebase resources ([#6443](https://github.com/databricks/cli/pull/6443)).

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"method": "PATCH",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/dev-branch",
"q": {
"update_mask": "spec.expire_time"
"update_mask": "spec.expiration"
},
"body": {
"spec": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Resources: 2 created, 0 changed, 0 deleted, 0 unchanged
"uid": "[BRANCH_UID]"
}

=== Change expire_time: both engines plan it, only terraform applies it
=== Change expire_time and re-deploy
>>> update_file.py databricks.yml [EXPIRE_TIME_BEFORE] [EXPIRE_TIME_AFTER]

>>> [CLI] bundle plan
Expand All @@ -36,9 +36,32 @@ Plan: 0 to add, 1 to change, 0 to delete, 1 unchanged

>>> [CLI] bundle plan -o json

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/update-postgres-branch-expire-[UNIQUE_NAME]/default/files...
Updated postgres_branches.dev_branch
Files: 0 uploaded, 0 deleted
Resources: 0 created, 1 changed, 0 deleted, 1 unchanged

>>> print_requests.py --del-body project_id,branch_id --sort //postgres ^//workspace-files/ ^//workspace/ ^//telemetry-ext ^//operations/

>>> [CLI] postgres get-branch projects/test-pg-proj-[UNIQUE_NAME]/branches/dev-branch
{
"branch_id": "dev-branch",
"name": "projects/test-pg-proj-[UNIQUE_NAME]/branches/dev-branch",
"parent": "projects/test-pg-proj-[UNIQUE_NAME]",
"status": {
"branch_id": "dev-branch",
"current_state": "READY",
"default": false,
"expire_time": "[EXPIRE_TIME_AFTER]",
"is_protected": false,
"source_branch": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production",
"source_branch_lsn": "[LSN]",
"source_branch_time": "[TIMESTAMP]",
"state_change_time": "[TIMESTAMP]"
},
"uid": "[BRANCH_UID]"
}

>>> [CLI] bundle destroy --auto-approve
The following resources will be deleted:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ trace $CLI bundle deploy
rm -f out.requests.txt
trace $CLI postgres get-branch "${branch_name}" | branch_fields

title "Change expire_time: both engines plan it, only terraform applies it"
title "Change expire_time and re-deploy"
trace update_file.py databricks.yml "2030-01-01T00:00:00Z" "2031-06-15T12:00:00Z"

# Only terraform applies it: expire_time is a member of the
# expiration oneof, and the direct engine masks it under its own name. See test.toml.
trace $CLI bundle plan
trace $CLI bundle plan -o json | jq '.plan."resources.postgres_branches.dev_branch" | {action, changes}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json
rm -f out.requests.txt
errcode $CLI bundle deploy &> out.deploy.$DATABRICKS_BUNDLE_ENGINE.txt
trace $CLI bundle deploy
trace print_requests.py --del-body project_id,branch_id --sort '//postgres' '^//workspace-files/' '^//workspace/' '^//telemetry-ext' '^//operations/' > out.requests.$DATABRICKS_BUNDLE_ENGINE.json
trace $CLI postgres get-branch "${branch_name}" | branch_fields > out.branch.$DATABRICKS_BUNDLE_ENGINE.txt
trace $CLI postgres get-branch "${branch_name}" | branch_fields
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
# expire_time, ttl and no_expiry are three sides of one oneof. The API masks them
# together under spec.expiration and rejects each field name on its own, so the
# direct engine's update_mask=spec.expire_time is answered with
# 400 INVALID_PARAMETER_VALUE. Same bug as postgres_endpoints/update_suspend_timeout,
# and a separate fix from the diffing this test covers.
Badness = "Direct engine cannot apply an expire_time change: it masks the field under its own name, but the API only accepts the oneof group name spec.expiration"
# expire_time, ttl and no_expiry are three sides of one oneof, and the API accepts them
# in update_mask only under the group name spec.expiration. Both engines apply the change;
# out.requests.direct.json records the group mask the direct engine now sends.


# Local only: a real workspace caps how far ahead a branch may expire and answers
# these literal timestamps with 400 "expiration time exceeds the maximum
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"method": "PATCH",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/dev-branch",
"q": {
"update_mask": "spec.ttl"
"update_mask": "spec.expiration"
},
"body": {
"spec": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Created postgres_projects.my_project
Files: 0 uploaded, 0 deleted
Resources: 2 created, 0 changed, 0 deleted, 0 unchanged

=== Change ttl: both engines plan it, only terraform applies it
=== Change ttl and re-deploy
>>> update_file.py databricks.yml ttl: 604800s ttl: 259200s

>>> [CLI] bundle plan
Expand All @@ -17,6 +17,12 @@ Plan: 0 to add, 1 to change, 0 to delete, 1 unchanged

>>> [CLI] bundle plan -o json

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/update-postgres-branch-ttl-[UNIQUE_NAME]/default/files...
Updated postgres_branches.dev_branch
Files: 0 uploaded, 0 deleted
Resources: 0 created, 1 changed, 0 deleted, 1 unchanged

>>> print_requests.py --del-body project_id,branch_id --sort //postgres ^//workspace-files/ ^//workspace/ ^//telemetry-ext ^//operations/

>>> [CLI] bundle destroy --auto-approve
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# ttl, expire_time and no_expiry are three sides of one oneof, and the API accepts them in
# update_mask only under the group name spec.expiration. This is the cloud-covered case of
# that oneof; update_expire_time is local only.

envsubst < databricks.yml.tmpl > databricks.yml

cleanup() {
Expand All @@ -10,7 +14,7 @@ title "Initial deployment"
trace $CLI bundle deploy
rm -f out.requests.txt

title "Change ttl: both engines plan it, only terraform applies it"
title "Change ttl and re-deploy"
trace update_file.py databricks.yml "ttl: 604800s" "ttl: 259200s"

# Only terraform applies it: ttl is a member of the
Expand All @@ -22,5 +26,5 @@ trace update_file.py databricks.yml "ttl: 604800s" "ttl: 259200s"
trace $CLI bundle plan
trace $CLI bundle plan -o json | jq '.plan."resources.postgres_branches.dev_branch" | {action, changes}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json
rm -f out.requests.txt
errcode $CLI bundle deploy &> out.deploy.$DATABRICKS_BUNDLE_ENGINE.txt
trace $CLI bundle deploy
trace print_requests.py --del-body project_id,branch_id --sort '//postgres' '^//workspace-files/' '^//workspace/' '^//telemetry-ext' '^//operations/' > out.requests.$DATABRICKS_BUNDLE_ENGINE.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/remove-postgres-endpoint-suspend-[UNIQUE_NAME]/default/files...
Error: cannot update resources.postgres_endpoints.my_endpoint: updating id=projects/test-pg-proj-[UNIQUE_NAME]/branches/main/endpoints/my-endpoint: Unknown field path in update_mask: 'spec.suspend_timeout_duration' (400 INVALID_PARAMETER_VALUE)
Error: cannot update resources.postgres_endpoints.my_endpoint: updating id=projects/test-pg-proj-[UNIQUE_NAME]/branches/main/endpoints/my-endpoint: Field 'spec.suspension' is in update_mask but not provided in request (400 INVALID_PARAMETER_VALUE)

Endpoint: PATCH [DATABRICKS_URL]/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/main/endpoints/my-endpoint?update_mask=spec.suspend_timeout_duration
Endpoint: PATCH [DATABRICKS_URL]/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/main/endpoints/my-endpoint?update_mask=spec.suspension
HTTP Status: 400 Bad Request
API error_code: INVALID_PARAMETER_VALUE
API message: Unknown field path in update_mask: 'spec.suspend_timeout_duration'
API message: Field 'spec.suspension' is in update_mask but not provided in request

Files: 0 uploaded, 0 deleted

Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"method": "PATCH",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/main/endpoints/my-endpoint",
"q": {
"update_mask": "spec.suspend_timeout_duration"
"update_mask": "spec.suspension"
},
"body": {
"spec": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Resources: 3 created, 0 changed, 0 deleted, 0 unchanged
}
}

=== Remove suspend_timeout_duration: both engines plan it, only terraform applies it
=== Remove suspend_timeout_duration: neither engine can apply it
>>> update_file.py databricks.yml suspend_timeout_duration: 300s

>>> [CLI] bundle plan
Expand All @@ -36,6 +36,19 @@ Plan: 0 to add, 1 to change, 0 to delete, 2 unchanged
>>> print_requests.py --del-body project_id,branch_id,endpoint_id --sort //postgres ^//workspace-files/ ^//workspace/ ^//telemetry-ext ^//operations/

>>> [CLI] postgres get-endpoint projects/test-pg-proj-[UNIQUE_NAME]/branches/main/endpoints/my-endpoint
{
"endpoint_id": "my-endpoint",
"name": "projects/test-pg-proj-[UNIQUE_NAME]/branches/main/endpoints/my-endpoint",
"parent": "projects/test-pg-proj-[UNIQUE_NAME]/branches/main",
"uid": "[ENDPOINT_UID]",
"status": {
"endpoint_id": "my-endpoint",
"endpoint_type": "ENDPOINT_TYPE_READ_ONLY",
"autoscaling_limit_min_cu": 0.5,
"autoscaling_limit_max_cu": 8,
"suspend_timeout_duration": "300s"
}
}

>>> [CLI] bundle plan -o json

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ trace $CLI bundle deploy
rm -f out.requests.txt
trace $CLI postgres get-endpoint "${endpoint_name}" | endpoint_fields

title "Remove suspend_timeout_duration: both engines plan it, only terraform applies it"
title "Remove suspend_timeout_duration: neither engine can apply it"
trace update_file.py databricks.yml " suspend_timeout_duration: 300s" ""

# Both engines plan the removal, so the plan stays in output.txt. They diverge from
# the deploy on: the direct engine masks the field under its own name, which the API
# rejects because it is a member of the suspension oneof. See test.toml.
# Both engines plan the removal and neither applies it, but they fail differently, so the
# deploy and the drift it leaves stay in per-engine files. The direct engine masks
# spec.suspension with no member of that oneof in the body and the API rejects it; the
# Terraform provider masks the whole spec, which the API accepts and then ignores. See
# test.toml.
trace $CLI bundle plan
trace $CLI bundle plan -o json | jq '.plan."resources.postgres_endpoints.my_endpoint" | {action, changes}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json
rm -f out.requests.txt
Expand All @@ -28,6 +30,6 @@ trace print_requests.py --del-body project_id,branch_id,endpoint_id --sort '//po
# Read the endpoint back to see whether the removal reached it, then plan again to
# record the drift it leaves behind: direct still has the removal pending and will
# fail again on every deploy, terraform applied it and is clean.
trace $CLI postgres get-endpoint "${endpoint_name}" | endpoint_fields > out.endpoint.$DATABRICKS_BUNDLE_ENGINE.txt
trace $CLI postgres get-endpoint "${endpoint_name}" | endpoint_fields
trace $CLI bundle plan &> out.plan.drift.$DATABRICKS_BUNDLE_ENGINE.txt
trace $CLI bundle plan -o json | jq '.plan."resources.postgres_endpoints.my_endpoint" | {action, changes}' > out.plan.drift.$DATABRICKS_BUNDLE_ENGINE.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# suspend_timeout_duration and no_suspension are two sides of one oneof. The API
# masks them together under spec.suspension and rejects either field name, so
# removing the field is answered with 400 INVALID_PARAMETER_VALUE just like changing
# it (postgres_endpoints/update_suspend_timeout). Separate fix from the diffing this
# test covers.
#
# out.plan.drift.direct.* records what the failed removal leaves behind: the old
# value stays in state, so every later deploy plans the removal again and fails again.
Badness = "Direct engine cannot remove suspend_timeout_duration: it masks the field under its own name, but the API only accepts the oneof group name spec.suspension, so the removal fails on every deploy"
# The mask is now correct: suspend_timeout_duration is masked under its oneof group name
# spec.suspension. The removal still cannot be applied, and that is a property of the API
# rather than of the mask: a masked field has to be populated in the request body, so
# dropping it from the bundle leaves nothing to send. Probed against a real workspace on
# 2026-08-31 -- an absent value and an explicit null are both answered with "is in
# update_mask but not provided in request". The only way to stop an endpoint suspending is
# to set the other member of the oneof, no_suspension: true.
Badness = "Removing suspend_timeout_duration cannot be applied: the API requires a masked field to be populated, so the removal fails on every deploy. Setting no_suspension: true instead is the supported way to express it"

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"method": "PATCH",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/main/endpoints/my-endpoint",
"q": {
"update_mask": "spec.suspend_timeout_duration"
"update_mask": "spec.suspension"
},
"body": {
"spec": {
Expand Down
Loading
Loading