Skip to content

Commit 75586fd

Browse files
authored
postgres: Support replace_existing on branches and endpoints (#5264)
## Summary Adds support for `replace_existing` on Lakebase `postgres_branches` and `postgres_endpoints` so users can bring the implicitly-created production branch and primary read-write endpoint under bundle management — previously these always returned 409 ALREADY_EXISTS on deploy. Also closes the destroy-side gap: the backend signals lifecycle-owned-by-parent via `details[].ErrorInfo.metadata.declarative_context: MANAGED_BY_PARENT`. The Terraform provider already honors this; this PR adds the equivalent suppression in the direct engine. The acceptance testserver is taught the same payload shape. Two focused acceptance tests cover the override-implicit-resource flow on both engines: - `postgres_branches/replace_existing`: takes over the production branch, applies a non-default `no_expiry: true`. - `postgres_endpoints/replace_existing`: takes over the primary endpoint of a user-created branch, overrides the project-inherited `suspend_timeout_duration` (300s → 600s). ## Depends on Built on top of #5263 (testproxy: forward raw error body and headers from upstream) — without that fix, the acceptance test proxy strips `details[]` from upstream errors before they reach the engines, so the suppression in TF and the direct engine never fires when tests run against cloud. ## Test plan - [x] Manually ran both acceptance tests against a real workspace — full deploy + destroy on both engines. This pull request and its description were written by Isaac.
1 parent d72afae commit 75586fd

40 files changed

Lines changed: 1055 additions & 109 deletions

NEXT_CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@
1111

1212
### Bundles
1313
* Make sure warnings asking for approval are understood by agents ([#5239](https://github.com/databricks/cli/pull/5239))
14+
* 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.
1415

1516
### Dependency updates

acceptance/bundle/refschema/out.fields.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2706,6 +2706,7 @@ resources.postgres_branches.*.modified_status string INPUT
27062706
resources.postgres_branches.*.name string REMOTE
27072707
resources.postgres_branches.*.no_expiry bool INPUT STATE
27082708
resources.postgres_branches.*.parent string ALL
2709+
resources.postgres_branches.*.replace_existing bool INPUT STATE
27092710
resources.postgres_branches.*.source_branch string INPUT STATE
27102711
resources.postgres_branches.*.source_branch_lsn string INPUT STATE
27112712
resources.postgres_branches.*.source_branch_time *time.Time INPUT STATE
@@ -2750,6 +2751,7 @@ resources.postgres_endpoints.*.modified_status string INPUT
27502751
resources.postgres_endpoints.*.name string REMOTE
27512752
resources.postgres_endpoints.*.no_suspension bool INPUT STATE
27522753
resources.postgres_endpoints.*.parent string ALL
2754+
resources.postgres_endpoints.*.replace_existing bool INPUT STATE
27532755
resources.postgres_endpoints.*.settings *postgres.EndpointSettings INPUT STATE
27542756
resources.postgres_endpoints.*.settings.pg_settings map[string]string INPUT STATE
27552757
resources.postgres_endpoints.*.settings.pg_settings.* string INPUT STATE
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
bundle:
2+
name: deploy-postgres-replace-branch-$UNIQUE_NAME
3+
4+
sync:
5+
paths: []
6+
7+
resources:
8+
postgres_projects:
9+
my_project:
10+
project_id: test-pg-proj-$UNIQUE_NAME
11+
display_name: "Replace existing branch test"
12+
pg_version: 16
13+
history_retention_duration: "604800s"
14+
15+
# Take over the implicitly-created production branch with replace_existing
16+
# and apply a non-default spec (no_expiry: true). The field is input-only
17+
# and not surfaced in get-branch, but it is visible in the recorded
18+
# request body so the diff confirms it was sent.
19+
postgres_branches:
20+
production:
21+
parent: ${resources.postgres_projects.my_project.id}
22+
branch_id: production
23+
replace_existing: true
24+
no_expiry: true
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
The following resources will be deleted:
2+
delete resources.postgres_branches.production
3+
delete resources.postgres_projects.my_project
4+
5+
This action will result in the deletion of the following Lakebase projects along with
6+
all their branches, databases, and endpoints. All data stored in them will be permanently lost:
7+
delete resources.postgres_projects.my_project
8+
9+
This action will result in the deletion of the following Lakebase branches.
10+
All data stored in them will be permanently lost:
11+
delete resources.postgres_branches.production
12+
13+
All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/deploy-postgres-replace-branch-[UNIQUE_NAME]/default
14+
15+
Deleting files...
16+
Destroy complete!
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
The following resources will be deleted:
2+
delete resources.postgres_branches.production
3+
delete resources.postgres_projects.my_project
4+
5+
This action will result in the deletion of the following Lakebase projects along with
6+
all their branches, databases, and endpoints. All data stored in them will be permanently lost:
7+
delete resources.postgres_projects.my_project
8+
9+
This action will result in the deletion of the following Lakebase branches.
10+
All data stored in them will be permanently lost:
11+
delete resources.postgres_branches.production
12+
13+
All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/deploy-postgres-replace-branch-[UNIQUE_NAME]/default
14+
15+
Deleting files...
16+
Destroy complete!
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"method": "POST",
3+
"path": "/api/2.0/postgres/projects",
4+
"q": {
5+
"project_id": "test-pg-proj-[UNIQUE_NAME]"
6+
},
7+
"body": {
8+
"spec": {
9+
"display_name": "Replace existing branch test",
10+
"history_retention_duration": "604800s",
11+
"pg_version": 16
12+
}
13+
}
14+
}
15+
{
16+
"method": "POST",
17+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches",
18+
"q": {
19+
"branch_id": "production",
20+
"replace_existing": "true"
21+
},
22+
"body": {
23+
"spec": {
24+
"no_expiry": true
25+
}
26+
}
27+
}
28+
{
29+
"method": "GET",
30+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
31+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"method": "POST",
3+
"path": "/api/2.0/postgres/projects",
4+
"q": {
5+
"project_id": "test-pg-proj-[UNIQUE_NAME]"
6+
},
7+
"body": {
8+
"spec": {
9+
"display_name": "Replace existing branch test",
10+
"history_retention_duration": "604800s",
11+
"pg_version": 16
12+
}
13+
}
14+
}
15+
{
16+
"method": "POST",
17+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches",
18+
"q": {
19+
"branch_id": "production",
20+
"replace_existing": "true"
21+
},
22+
"body": {
23+
"parent": "projects/test-pg-proj-[UNIQUE_NAME]",
24+
"spec": {
25+
"no_expiry": true
26+
}
27+
}
28+
}
29+
{
30+
"method": "GET",
31+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
32+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"method": "POST",
3+
"path": "/api/2.0/postgres/projects",
4+
"q": {
5+
"project_id": "test-pg-proj-[UNIQUE_NAME]"
6+
},
7+
"body": {
8+
"spec": {
9+
"display_name": "Replace existing branch test",
10+
"history_retention_duration": "604800s",
11+
"pg_version": 16
12+
}
13+
}
14+
}
15+
{
16+
"method": "POST",
17+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches",
18+
"q": {
19+
"branch_id": "production",
20+
"replace_existing": "true"
21+
},
22+
"body": {
23+
"spec": {
24+
"no_expiry": true
25+
}
26+
}
27+
}
28+
{
29+
"method": "GET",
30+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
31+
}
32+
{
33+
"method": "GET",
34+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
35+
}
36+
{
37+
"method": "GET",
38+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]"
39+
}
40+
{
41+
"method": "DELETE",
42+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
43+
}
44+
{
45+
"method": "DELETE",
46+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]"
47+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"method": "POST",
3+
"path": "/api/2.0/postgres/projects",
4+
"q": {
5+
"project_id": "test-pg-proj-[UNIQUE_NAME]"
6+
},
7+
"body": {
8+
"spec": {
9+
"display_name": "Replace existing branch test",
10+
"history_retention_duration": "604800s",
11+
"pg_version": 16
12+
}
13+
}
14+
}
15+
{
16+
"method": "POST",
17+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches",
18+
"q": {
19+
"branch_id": "production",
20+
"replace_existing": "true"
21+
},
22+
"body": {
23+
"parent": "projects/test-pg-proj-[UNIQUE_NAME]",
24+
"spec": {
25+
"no_expiry": true
26+
}
27+
}
28+
}
29+
{
30+
"method": "GET",
31+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
32+
}
33+
{
34+
"method": "GET",
35+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]"
36+
}
37+
{
38+
"method": "GET",
39+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
40+
}
41+
{
42+
"method": "DELETE",
43+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production"
44+
}
45+
{
46+
"method": "DELETE",
47+
"path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]"
48+
}

acceptance/bundle/resources/postgres_branches/replace_existing/out.test.toml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)