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 NEXT_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@

### Bundles
* Make sure warnings asking for approval are understood by agents ([#5239](https://github.com/databricks/cli/pull/5239))
* Support `replace_existing: true` on `postgres_branches` and `postgres_endpoints` so bundles can manage the implicitly-created production branch and primary read-write endpoint of a Lakebase project.

### Dependency updates
2 changes: 2 additions & 0 deletions acceptance/bundle/refschema/out.fields.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2706,6 +2706,7 @@ resources.postgres_branches.*.modified_status string INPUT
resources.postgres_branches.*.name string REMOTE
resources.postgres_branches.*.no_expiry bool INPUT STATE
resources.postgres_branches.*.parent string ALL
resources.postgres_branches.*.replace_existing bool INPUT STATE
resources.postgres_branches.*.source_branch string INPUT STATE
resources.postgres_branches.*.source_branch_lsn string INPUT STATE
resources.postgres_branches.*.source_branch_time *time.Time INPUT STATE
Expand Down Expand Up @@ -2750,6 +2751,7 @@ resources.postgres_endpoints.*.modified_status string INPUT
resources.postgres_endpoints.*.name string REMOTE
resources.postgres_endpoints.*.no_suspension bool INPUT STATE
resources.postgres_endpoints.*.parent string ALL
resources.postgres_endpoints.*.replace_existing bool INPUT STATE
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is create-only field, right? In that case, why do we need to track it in STATE?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no way to pass it into DoCreate without putting it in the state type.

I couldn't find precedent for this in other resources.

Hypothetically if we were to add a create-only side channel, I'm not sure the added complexity is worth it.

resources.postgres_endpoints.*.settings *postgres.EndpointSettings INPUT STATE
resources.postgres_endpoints.*.settings.pg_settings map[string]string INPUT STATE
resources.postgres_endpoints.*.settings.pg_settings.* string INPUT STATE
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
bundle:
name: deploy-postgres-replace-branch-$UNIQUE_NAME

sync:
paths: []

resources:
postgres_projects:
my_project:
project_id: test-pg-proj-$UNIQUE_NAME
display_name: "Replace existing branch test"
pg_version: 16
history_retention_duration: "604800s"

# Take over the implicitly-created production branch with replace_existing
# and apply a non-default spec (no_expiry: true). The field is input-only
# and not surfaced in get-branch, but it is visible in the recorded
# request body so the diff confirms it was sent.
postgres_branches:
production:
parent: ${resources.postgres_projects.my_project.id}
branch_id: production
replace_existing: true
no_expiry: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
The following resources will be deleted:
delete resources.postgres_branches.production
delete resources.postgres_projects.my_project

This action will result in the deletion of the following Lakebase projects along with
all their branches, databases, and endpoints. All data stored in them will be permanently lost:
delete resources.postgres_projects.my_project

This action will result in the deletion of the following Lakebase branches.
All data stored in them will be permanently lost:
delete resources.postgres_branches.production

All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/deploy-postgres-replace-branch-[UNIQUE_NAME]/default

Deleting files...
Destroy complete!
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
The following resources will be deleted:
delete resources.postgres_branches.production
delete resources.postgres_projects.my_project

This action will result in the deletion of the following Lakebase projects along with
all their branches, databases, and endpoints. All data stored in them will be permanently lost:
delete resources.postgres_projects.my_project

This action will result in the deletion of the following Lakebase branches.
All data stored in them will be permanently lost:
delete resources.postgres_branches.production

All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/deploy-postgres-replace-branch-[UNIQUE_NAME]/default

Deleting files...
Destroy complete!
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"method": "POST",
"path": "/api/2.0/postgres/projects",
"q": {
"project_id": "test-pg-proj-[UNIQUE_NAME]"
},
"body": {
"spec": {
"display_name": "Replace existing branch test",
"history_retention_duration": "604800s",
"pg_version": 16
}
}
}
{
"method": "POST",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches",
"q": {
"branch_id": "production",
"replace_existing": "true"
},
"body": {
"spec": {
"no_expiry": true
}
}
}
{
"method": "GET",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"method": "POST",
"path": "/api/2.0/postgres/projects",
"q": {
"project_id": "test-pg-proj-[UNIQUE_NAME]"
},
"body": {
"spec": {
"display_name": "Replace existing branch test",
"history_retention_duration": "604800s",
"pg_version": 16
}
}
}
{
"method": "POST",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches",
"q": {
"branch_id": "production",
"replace_existing": "true"
},
"body": {
"parent": "projects/test-pg-proj-[UNIQUE_NAME]",
"spec": {
"no_expiry": true
}
}
}
{
"method": "GET",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"method": "POST",
"path": "/api/2.0/postgres/projects",
"q": {
"project_id": "test-pg-proj-[UNIQUE_NAME]"
},
"body": {
"spec": {
"display_name": "Replace existing branch test",
"history_retention_duration": "604800s",
"pg_version": 16
}
}
}
{
"method": "POST",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches",
"q": {
"branch_id": "production",
"replace_existing": "true"
},
"body": {
"spec": {
"no_expiry": true
}
}
}
{
"method": "GET",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
}
{
"method": "GET",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
}
{
"method": "GET",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]"
}
{
"method": "DELETE",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
}
{
"method": "DELETE",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"method": "POST",
"path": "/api/2.0/postgres/projects",
"q": {
"project_id": "test-pg-proj-[UNIQUE_NAME]"
},
"body": {
"spec": {
"display_name": "Replace existing branch test",
"history_retention_duration": "604800s",
"pg_version": 16
}
}
}
{
"method": "POST",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches",
"q": {
"branch_id": "production",
"replace_existing": "true"
},
"body": {
"parent": "projects/test-pg-proj-[UNIQUE_NAME]",
"spec": {
"no_expiry": true
}
}
}
{
"method": "GET",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
}
{
"method": "GET",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]"
}
{
"method": "GET",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
}
{
"method": "DELETE",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
}
{
"method": "DELETE",
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]"
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

>>> [CLI] bundle validate
Name: deploy-postgres-replace-branch-[UNIQUE_NAME]
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/deploy-postgres-replace-branch-[UNIQUE_NAME]/default

Validation OK!

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/deploy-postgres-replace-branch-[UNIQUE_NAME]/default/files...
Deploying resources...
Updating deployment state...
Deployment complete!

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

>>> print_requests.py --keep --get //postgres ^//workspace-files/ ^//workspace/ ^//telemetry-ext ^//operations/

=== bundle destroy
>>> print_requests.py --keep --get //postgres ^//workspace-files/ ^//workspace/ ^//telemetry-ext ^//operations/
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
envsubst < databricks.yml.tmpl > databricks.yml

cleanup() {
# Belt-and-braces in case bundle destroy was skipped or partially failed.
$CLI postgres delete-project "projects/test-pg-proj-${UNIQUE_NAME}" 2>/dev/null || true
rm -f out.requests.txt
}
trap cleanup EXIT

trace $CLI bundle validate

rm -f out.requests.txt
trace $CLI bundle deploy

# Confirm the implicit production branch is now under management.
trace $CLI postgres get-branch "projects/test-pg-proj-${UNIQUE_NAME}/branches/production" | jq 'del(.create_time, .update_time, .status.logical_size_bytes)'

trace print_requests.py --keep --get '//postgres' '^//workspace-files/' '^//workspace/' '^//telemetry-ext' '^//operations/' > out.requests.deploy.$DATABRICKS_BUNDLE_ENGINE.json

# bundle destroy: the backend rejects independent deletion of the root
# branch with a MANAGED_BY_PARENT marker; both engines disregard that
# error and let the project delete cascade-clean the branch. Per-engine
# output is captured so regressions in either engine's destroy flow show
# up in the diff.
title "bundle destroy"
$CLI bundle destroy --auto-approve > out.destroy.$DATABRICKS_BUNDLE_ENGINE.txt 2>&1 || true

trace print_requests.py --keep --get '//postgres' '^//workspace-files/' '^//workspace/' '^//telemetry-ext' '^//operations/' > out.requests.destroy.$DATABRICKS_BUNDLE_ENGINE.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# All configuration inherited from parent test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
bundle:
name: deploy-postgres-replace-endpoint-$UNIQUE_NAME

sync:
paths: []

resources:
# The project's default_endpoint_settings are inherited by every implicit
# primary endpoint. We set suspend_timeout_duration to 300s here so the
# primary endpoint of the "develop" branch below would otherwise come up
# with 300s.
postgres_projects:
my_project:
project_id: test-pg-proj-$UNIQUE_NAME
display_name: "Replace existing endpoint test"
pg_version: 16
history_retention_duration: "604800s"
default_endpoint_settings:
autoscaling_limit_min_cu: 0.5
autoscaling_limit_max_cu: 4
suspend_timeout_duration: "300s"

# Non-default branch managed normally — the server auto-provisions its
# primary read-write endpoint with the project defaults above.
postgres_branches:
develop:
parent: ${resources.postgres_projects.my_project.id}
branch_id: develop
no_expiry: true

# Take over the implicitly-created primary endpoint of the develop branch
# and override the inherited suspend_timeout_duration (300s) with 600s. A
# successful deploy with 600s reflected in get-endpoint proves
# replace_existing applied the spec.
postgres_endpoints:
primary:
parent: ${resources.postgres_branches.develop.id}
endpoint_id: primary
replace_existing: true
endpoint_type: ENDPOINT_TYPE_READ_WRITE
autoscaling_limit_min_cu: 0.5
autoscaling_limit_max_cu: 4
suspend_timeout_duration: "600s"
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
The following resources will be deleted:
delete resources.postgres_branches.develop
delete resources.postgres_endpoints.primary
delete resources.postgres_projects.my_project

This action will result in the deletion of the following Lakebase projects along with
all their branches, databases, and endpoints. All data stored in them will be permanently lost:
delete resources.postgres_projects.my_project

This action will result in the deletion of the following Lakebase branches.
All data stored in them will be permanently lost:
delete resources.postgres_branches.develop

All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/deploy-postgres-replace-endpoint-[UNIQUE_NAME]/default

Deleting files...
Destroy complete!
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
The following resources will be deleted:
delete resources.postgres_branches.develop
delete resources.postgres_endpoints.primary
delete resources.postgres_projects.my_project

This action will result in the deletion of the following Lakebase projects along with
all their branches, databases, and endpoints. All data stored in them will be permanently lost:
delete resources.postgres_projects.my_project

This action will result in the deletion of the following Lakebase branches.
All data stored in them will be permanently lost:
delete resources.postgres_branches.develop

All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/deploy-postgres-replace-endpoint-[UNIQUE_NAME]/default

Deleting files...
Destroy complete!
Loading
Loading