Skip to content
Open
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
3 changes: 2 additions & 1 deletion .agent/skills/pr-checklist/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ Before submitting a PR, run these commands to match what CI checks. CI uses the
# 3. Tests (CI runs with both deployment engines)
./task test

# 4. If you changed bundle config structs or schema-related code:
# 4. If you changed bundle config structs, schema, or direct-engine resource code:
./task generate-schema
./task generate-direct

# 5. If you changed files in python/:
./task pydabs-codegen pydabs-test pydabs-lint pydabs-docs
Expand Down
1 change: 1 addition & 0 deletions NEXT_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,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.
* Add `postgres_catalogs` resource to bind a Unity Catalog catalog to a Postgres database on a Lakebase Autoscaling branch ([#5265](https://github.com/databricks/cli/pull/5265)).

### Dependency updates
15 changes: 15 additions & 0 deletions acceptance/bundle/invariant/configs/postgres_catalog.yml.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
bundle:
name: test-bundle-$UNIQUE_NAME

resources:
postgres_projects:
project:
project_id: test-pg-project-$UNIQUE_NAME
display_name: Test Postgres Project

postgres_catalogs:
catalog:
catalog_id: test_pg_catalog_$UNIQUE_NAME
branch: ${resources.postgres_projects.project.name}/branches/production
postgres_database: appdb
create_database_if_missing: true
1 change: 1 addition & 0 deletions acceptance/bundle/invariant/continue_293/out.test.toml

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

1 change: 1 addition & 0 deletions acceptance/bundle/invariant/migrate/out.test.toml

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

1 change: 1 addition & 0 deletions acceptance/bundle/invariant/no_drift/out.test.toml

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

2 changes: 2 additions & 0 deletions acceptance/bundle/invariant/test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ EnvMatrix.INPUT_CONFIG = [
"pipeline.yml.tmpl",
"pipeline_config_dots.yml.tmpl",
"postgres_branch.yml.tmpl",
"postgres_catalog.yml.tmpl",
"postgres_endpoint.yml.tmpl",
"postgres_project.yml.tmpl",
"registered_model.yml.tmpl",
Expand All @@ -67,6 +68,7 @@ no_alert_on_cloud = ["CONFIG_Cloud=true", "INPUT_CONFIG=alert.yml.tmpl"]
no_postgres_project_on_cloud = ["CONFIG_Cloud=true", "INPUT_CONFIG=postgres_project.yml.tmpl"]
no_postgres_branch_on_cloud = ["CONFIG_Cloud=true", "INPUT_CONFIG=postgres_branch.yml.tmpl"]
no_postgres_endpoint_on_cloud = ["CONFIG_Cloud=true", "INPUT_CONFIG=postgres_endpoint.yml.tmpl"]
no_postgres_catalog_on_cloud = ["CONFIG_Cloud=true", "INPUT_CONFIG=postgres_catalog.yml.tmpl"]

# External locations require actual storage credentials with cloud IAM setup
# which are environment-specific, so we only test locally with the mock server
Expand Down
18 changes: 18 additions & 0 deletions acceptance/bundle/refschema/out.fields.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2734,6 +2734,24 @@ resources.postgres_branches.*.ttl *duration.Duration INPUT STATE
resources.postgres_branches.*.uid string REMOTE
resources.postgres_branches.*.update_time *time.Time REMOTE
resources.postgres_branches.*.url string INPUT
resources.postgres_catalogs.*.branch string ALL
resources.postgres_catalogs.*.catalog_id string ALL
resources.postgres_catalogs.*.create_database_if_missing bool ALL
resources.postgres_catalogs.*.create_time *time.Time REMOTE
resources.postgres_catalogs.*.id string INPUT
resources.postgres_catalogs.*.lifecycle resources.Lifecycle INPUT
resources.postgres_catalogs.*.lifecycle.prevent_destroy bool INPUT
resources.postgres_catalogs.*.modified_status string INPUT
resources.postgres_catalogs.*.name string REMOTE
resources.postgres_catalogs.*.postgres_database string ALL
resources.postgres_catalogs.*.status *postgres.CatalogCatalogStatus REMOTE
resources.postgres_catalogs.*.status.branch string REMOTE
resources.postgres_catalogs.*.status.catalog_id string REMOTE
resources.postgres_catalogs.*.status.postgres_database string REMOTE
resources.postgres_catalogs.*.status.project string REMOTE
resources.postgres_catalogs.*.uid string REMOTE
resources.postgres_catalogs.*.update_time *time.Time REMOTE
resources.postgres_catalogs.*.url string INPUT
resources.postgres_endpoints.*.autoscaling_limit_max_cu float64 INPUT STATE
resources.postgres_endpoints.*.autoscaling_limit_min_cu float64 INPUT STATE
resources.postgres_endpoints.*.create_time *time.Time REMOTE
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
bundle:
name: deploy-postgres-catalog-$UNIQUE_NAME

sync:
paths: []

resources:
postgres_projects:
my_project:
project_id: test-pg-proj-$UNIQUE_NAME
display_name: "Test Project for Catalog"
pg_version: 16

postgres_catalogs:
my_catalog:
catalog_id: lakebase_test_$UNIQUE_NAME
branch: ${resources.postgres_projects.my_project.id}/branches/production
postgres_database: appdb
create_database_if_missing: true
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": "Test Project for Catalog",
"pg_version": 16
}
}
}
{
"method": "POST",
"path": "/api/2.0/postgres/catalogs",
"q": {
"catalog_id": "lakebase_test_[UNIQUE_NAME]"
},
"body": {
"spec": {
"branch": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production",
"create_database_if_missing": true,
"postgres_database": "appdb"
}
}
}
{
"method": "GET",
"path": "/api/2.0/postgres/catalogs/lakebase_test_[UNIQUE_NAME]"
}

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

74 changes: 74 additions & 0 deletions acceptance/bundle/resources/postgres_catalogs/basic/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@

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

Validation OK!

>>> [CLI] bundle summary
Name: deploy-postgres-catalog-[UNIQUE_NAME]
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/deploy-postgres-catalog-[UNIQUE_NAME]/default
Resources:
Postgres catalogs:
my_catalog:
Name: lakebase_test_[UNIQUE_NAME]
URL: [DATABRICKS_URL]/explore/data/lakebase_test_[UNIQUE_NAME]
Postgres projects:
my_project:
Name: Test Project for Catalog
URL: (not deployed)

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

>>> [CLI] postgres get-catalog catalogs/lakebase_test_[UNIQUE_NAME]
{
"name": "catalogs/lakebase_test_[UNIQUE_NAME]",
"status": {
"branch": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production",
"catalog_id": "lakebase_test_[UNIQUE_NAME]",
"postgres_database": "appdb",
"project": "projects/test-pg-proj-[UNIQUE_NAME]"
}
}

>>> [CLI] bundle summary
Name: deploy-postgres-catalog-[UNIQUE_NAME]
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/deploy-postgres-catalog-[UNIQUE_NAME]/default
Resources:
Postgres catalogs:
my_catalog:
Name: lakebase_test_[UNIQUE_NAME]
URL: [DATABRICKS_URL]/explore/data/lakebase_test_[UNIQUE_NAME]
Postgres projects:
my_project:
Name: Test Project for Catalog
URL: (not deployed)

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

>>> [CLI] bundle destroy --auto-approve
The following resources will be deleted:
delete resources.postgres_catalogs.my_catalog
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

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

Deleting files...
Destroy complete!
23 changes: 23 additions & 0 deletions acceptance/bundle/resources/postgres_catalogs/basic/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
envsubst < databricks.yml.tmpl > databricks.yml

cleanup() {
trace $CLI bundle destroy --auto-approve
rm -f out.requests.txt
}
trap cleanup EXIT

trace $CLI bundle validate

trace $CLI bundle summary

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

# Get catalog details. Hide volatile fields so cloud and local match.
catalog_name="catalogs/lakebase_test_${UNIQUE_NAME}"
trace $CLI postgres get-catalog "${catalog_name}" | jq 'del(.create_time, .update_time, .uid)'

trace $CLI bundle summary

# Filter requests to only show postgres operations (exclude workspace, telemetry, and operation polling).
trace print_requests.py --keep --get '//postgres' '^//workspace-files/' '^//workspace/' '^//telemetry-ext' '^//operations/' > out.requests.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
bundle:
name: recreate-postgres-catalog-$UNIQUE_NAME

sync:
paths: []

resources:
postgres_projects:
my_project:
project_id: test-pg-proj-$UNIQUE_NAME
display_name: "Test Project for Catalog Recreate"
pg_version: 16

postgres_catalogs:
my_catalog:
catalog_id: lakebase_test_$UNIQUE_NAME
branch: ${resources.postgres_projects.my_project.id}/branches/production
postgres_database: $POSTGRES_DATABASE
create_database_if_missing: true

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

31 changes: 31 additions & 0 deletions acceptance/bundle/resources/postgres_catalogs/recreate/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

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

>>> [CLI] bundle plan
recreate postgres_catalogs.my_catalog

Plan: 1 to add, 0 to change, 1 to delete, 1 unchanged

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

>>> [CLI] bundle destroy --auto-approve
The following resources will be deleted:
delete resources.postgres_catalogs.my_catalog
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

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

Deleting files...
Destroy complete!
16 changes: 16 additions & 0 deletions acceptance/bundle/resources/postgres_catalogs/recreate/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
cleanup() {
trace $CLI bundle destroy --auto-approve
rm -f out.requests.txt
}
trap cleanup EXIT

export POSTGRES_DATABASE=appdb
envsubst < databricks.yml.tmpl > databricks.yml
trace $CLI bundle deploy

# Toggle a recreate-on-change field; plan must show delete + create.
export POSTGRES_DATABASE=otherdb
envsubst < databricks.yml.tmpl > databricks.yml
trace $CLI bundle plan | contains.py "Plan: 1 to add, 0 to change, 1 to delete, 1 unchanged"

trace $CLI bundle deploy
26 changes: 26 additions & 0 deletions acceptance/bundle/resources/postgres_catalogs/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Local = true
Cloud = true
RequiresUnityCatalog = true

# Lakebase v2 (postgres) is only available in AWS as of January 2026
CloudEnvs.gcp = false
CloudEnvs.azure = false

EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct", "terraform"]

Ignore = [
"databricks.yml",
".databricks",
]

[[Repls]]
# Clean up ?o=<num> suffix after URL since not all workspaces have that
Old = '\?o=\[(NUMID|ALPHANUMID)\]'
New = ''
Order = 1000

[[Repls]]
# Normalize postgres operation IDs (unique per operation).
Old = '/operations/[A-Za-z0-9+/=-]+'
New = '/operations/[OPERATION_ID]'
Order = 2000
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var unsupportedResources = []string{
"synced_database_tables",
"postgres_branches",
"postgres_endpoints",
"postgres_catalogs",
}

func TestApplyBundlePermissions(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,13 @@ func mockBundle(mode config.Mode) *bundle.Bundle {
},
},
},
PostgresCatalogs: map[string]*resources.PostgresCatalog{
"postgres_catalog1": {
PostgresCatalogConfig: resources.PostgresCatalogConfig{
CatalogId: "postgres_catalog_1",
},
},
},
VectorSearchEndpoints: map[string]*resources.VectorSearchEndpoint{
"vs_endpoint1": {
CreateEndpoint: vectorsearch.CreateEndpoint{
Expand Down Expand Up @@ -441,6 +448,7 @@ func TestAppropriateResourcesAreRenamed(t *testing.T) {
"PostgresProjects",
"PostgresBranches",
"PostgresEndpoints",
"PostgresCatalogs",
}

diags := bundle.ApplySeq(t.Context(), b, ApplyTargetMode(), ApplyPresets())
Expand Down
Loading
Loading