Skip to content

Add postgres_data_apis bundle resource - #7160

Merged
ruslantalpa merged 17 commits into
mainfrom
ruslantalpa/postgres-data-apis
Nov 5, 2026
Merged

ruslantalpa merged 17 commits into
mainfrom
ruslantalpa/postgres-data-apis

Conversation

@ruslantalpa

@ruslantalpa ruslantalpa commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Changes

Add the postgres_data_apis resource (Private Preview). It enables and configures the Data API (PostgREST) of a Lakebase Postgres database:

resources:
  postgres_data_apis:
    app:
      parent: ${resources.postgres_databases.app_db.name}
      db_schemas: [public]
      db_max_rows: 1000
      jwt_cache_max_lifetime: 300s
  • One Data API per database. Its ID is {parent}/data-api; changing parent recreates it. Removing the resource turns the Data API off; the database and its data are unaffected.
  • The serving URL is status.url; reference it as ${resources.postgres_data_apis.<key>.status.url}. It is a stable output field: it is built from the read-write endpoint host, the workspace and the database name, so an in-place update of the Data API cannot change it, and the reference resolves without planning a no-op update of the resources that use it.
  • Durations such as jwt_cache_max_lifetime use the protobuf seconds format, for example 300s.
  • Create, update and delete wait on long-running operations. Update sends the configured spec with update_mask=spec.
  • spec is INPUT_ONLY, so GET does not return it. DoRead fills the remote spec from status, which reports every setting in effect, so bundle plan detects out-of-band changes and bundle deployment bind applies the configured spec on the next deploy. The generated spec:input_only rules are dropped (apitypes.yml: postgres_data_apis: null) and every spec field is a hand-written backend_default, so a field the config omits is left to the server.
  • Status omits a bool that is false and was never set, so the bool fields are forced on the remote side.
  • A field removed from the config keeps its last value on the server: update_mask=spec merges, and per-field clearing is not used because clearing some fields currently leaves the Data API unable to serve requests. The removal plans one no-op update; the next plan is clean.
  • Labelled Private Preview to match the API's launch stage (the other postgres_* resources are Beta), so the JSON schema marks it doNotSuggest. Like its Beta siblings, it is not generated in PyDABs yet, which only covers GA and Public Preview resources.

Why

Lakebase users already manage projects, branches and databases with bundles and want to manage the Data API alongside them. The API is at Private Preview.
Notes for reviewers:

  • Like every other postgres_* resource, this one waits on its operation inline in create, update and delete, because the operation ID isn't persisted.
  • Registering the new type with the deployment metadata service is a separate server-side change. Until it is deployed, deploys with experimental.deployment_history enabled reject this resource type, so the DMS=true acceptance variants are excluded for this resource (as for features) and the test server's DMS fake does not accept the prefix yet. Both get re-enabled once the server change ships.
  • Cloud coverage: the resource acceptance tests run on cloud (AWS only, like the siblings); the invariant and bind tests are local-only, like the siblings. A manual live run against a dev workspace covered the full lifecycle.
  • jwt_role_claim_key and jwt_cache_max_lifetime are exposed because the API accepts them. Their runtime behaviour is still evolving at Private Preview; happy to hide them if you prefer.

Tests

  • Acceptance tests against the local test server: basic, update, recreate, out-of-band, bind, and url_reference (a job parameter that references status.url resolves on the first deploy, and an in-place update of the Data API plans no update of the job). The test server's Data API fake mirrors the real API's defaults, status.url, merge-on-update semantics, and error codes and messages.
  • Invariant config covering lists, an integer, bools (true and an explicit false), a duration and an enum: no drift, removal of every optional field converges, delete/destroy idempotent.
  • Unit tests for the status-to-spec mapping and the fake.
  • Manual run against a dev workspace with a CLI built from this branch: deploy, serving through the Data API URL with a service principal token, a job parameter referencing status.url resolved on the first deploy, update (row cap applied, job not updated, next plan clean), removed field (value kept), out-of-band change detected and reverted, bind of an existing Data API applied on deploy, destroy (Data API off, data intact).
    This pull request and its description were written by Isaac.

@github-actions github-actions Bot added the DABs DABs related issues label Oct 22, 2026
ruslantalpa added a commit that referenced this pull request Oct 22, 2026
Co-authored-by: Isaac <no-reply@databricks.com>
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Commit: ed7fa4ebf | Workflow run

Regression test report

Selected 11 changed tests (limit=20, 0 not selected)

15 tests: regression=10 unreleased=0 coverage=5 failing=0
test branch main (7adc80d) latest (v1.24.0)
TestAccept/bundle/deployment/bind/postgres_data_api/DMS= ✅ ❌ ❌
TestAccept/bundle/invariant/delete_idempotent/DMS=/INPUT_CONFIG=postgres_data_api.yml.tmpl/READPLAN= ✅ ✅ ✅
TestAccept/bundle/invariant/delete_idempotent/DMS=/INPUT_CONFIG=postgres_data_api.yml.tmpl/READPLAN=1 ✅ ✅ ✅
TestAccept/bundle/invariant/destroy_idempotent/DMS=/INPUT_CONFIG=postgres_data_api.yml.tmpl/READPLAN= ✅ ✅ ✅
TestAccept/bundle/invariant/destroy_idempotent/DMS=/INPUT_CONFIG=postgres_data_api.yml.tmpl/READPLAN=1 ✅ ✅ ✅
TestAccept/bundle/invariant/no_drift/DMS=/INPUT_CONFIG=postgres_data_api.yml.tmpl/READPLAN= ✅ ❌ ❌
TestAccept/bundle/invariant/no_drift/DMS=/INPUT_CONFIG=postgres_data_api.yml.tmpl/READPLAN=1 ✅ ✅ ✅
TestAccept/bundle/refschema/DMS= ✅ ❌ ❌
TestAccept/bundle/refschema/DMS=true ✅ ❌ ❌
TestAccept/bundle/resources/postgres_data_apis/basic/DMS= ✅ ❌ ❌
TestAccept/bundle/resources/postgres_data_apis/out-of-band/DMS= ✅ ❌ ❌
TestAccept/bundle/resources/postgres_data_apis/parent_only/DMS= ✅ ❌ ❌
TestAccept/bundle/resources/postgres_data_apis/recreate/DMS= ✅ ❌ ❌
TestAccept/bundle/resources/postgres_data_apis/update/DMS= ✅ ❌ ❌
TestAccept/bundle/resources/postgres_data_apis/url_reference/DMS= ✅ ❌ ❌
TestAccept/bundle/deployment/bind/postgres_data_api/DMS=: branch ✅ | main (7adc80d) ❌ | latest (v1.24.0) ❌

main (7adc80d):

acceptance_test.go:1345: Diff:
        --- bundle/deployment/bind/postgres_data_api/output.txt
        +++ /tmp/TestAcceptbundledeploymentbindpostgres_data_apiDMS=3757825515/002/output.txt
        @@ -2,93 +2,14 @@
         === Enable the Data API on a database outside the bundle
         === Deploy fails because the Data API is already enabled
         >>> musterr [CLI] bundle deploy
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
        -Error: cannot create resources.postgres_data_apis.data_api1: Data API is already enabled for this database (409 ALREADY_EXISTS)
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:5:3
         
        -Endpoint: POST [DATABRICKS_URL]/api/2.0/postgres/projects/test-project/branches/production/databases/test-database/data-api
        -HTTP Status: 409 Conflict
        -API error_code: ALREADY_EXISTS
        -API message: Data API is already enabled for this database
        -
        +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
         Files: 2 uploaded, 0 deleted
        +Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
         
        -=== Bind adopts the existing Data API
        ->>> [CLI] bundle deployment bind data_api1 projects/test-project/branches/production/databases/test-database/data-api --auto-approve
        -Successfully bound postgres_data_api with an id 'projects/test-project/branches/production/databases/test-database/data-api'
        -Run 'bundle deploy' to deploy changes to your workspace
        +Unexpected success
         
        ->>> [CLI] bundle summary
        -Name: test-bundle
        -Target: default
        -Workspace:
        -  User: [USERNAME]
        -  Path: /Workspace/Users/[USERNAME]/.bundle/test-bundle/default
        -Resources:
        -  Postgres Data APIs:
        -    data_api1:
        -      Name: projects/test-project/branches/production/databases/test-database/data-api
        -
        ->>> [CLI] bundle plan
        -update postgres_data_apis.data_api1
        -
        -Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged
        -
        ->>> [CLI] bundle deploy
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
        -Updated postgres_data_apis.data_api1
        -Files: 0 uploaded, 0 deleted
        -Resources: 0 created, 1 changed, 0 deleted, 0 unchanged
        -
        ->>> [CLI] postgres get-data-api projects/test-project/branches/production/databases/test-database/data-api
        -{
        -  "name": "projects/test-project/branches/production/databases/test-database/data-api",
        -  "status": {
        -    "db_schemas": [
        -      "public"
        -    ],
        -    "db_max_rows": 500
        -  }
        -}
        -
        ->>> [CLI] bundle plan
        -Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged
        -
        -=== Unbind leaves the Data API enabled
        ->>> [CLI] bundle deployment unbind data_api1
        -
        ->>> [CLI] bundle summary
        -Name: test-bundle
        -Target: default
        -Workspace:
        -  User: [USERNAME]
        -  Path: /Workspace/Users/[USERNAME]/.bundle/test-bundle/default
        -Resources:
        -  Postgres Data APIs:
        -    data_api1:
        -      Name: 
        -
        ->>> [CLI] postgres get-data-api projects/test-project/branches/production/databases/test-database/data-api
        -{
        -  "name": "projects/test-project/branches/production/databases/test-database/data-api"
        -}
        -
        -=== Bind again; destroy turns off the Data API
        ->>> [CLI] bundle deployment bind data_api1 projects/test-project/branches/production/databases/test-database/data-api --auto-approve
        -Successfully bound postgres_data_api with an id 'projects/test-project/branches/production/databases/test-database/data-api'
        -Run 'bundle deploy' to deploy changes to your workspace
        -
        ->>> [CLI] bundle destroy --auto-approve
        -The following resources will be deleted:
        -  delete resources.postgres_data_apis.data_api1
        -
        -All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bundle/default
        -
        -Destroy: 1 deleted
        -
        ->>> musterr [CLI] postgres get-data-api projects/test-project/branches/production/databases/test-database/data-api
        -Error: Data API is not enabled for this database
        -
        ->>> [CLI] postgres get-database projects/test-project/branches/production/databases/test-database
        -{
        -  "name": "projects/test-project/branches/production/databases/test-database"
        -}
        +Exit code: 1
        
    acceptance_test.go:1123: 
        LOG.setup: Warning: unknown field: postgres_data_apis
        LOG.setup:   at resources
        LOG.setup:   in databricks.yml:5:3
        LOG.setup: 
        LOG.setup: {
        LOG.setup:   "create_time": "2026-11-05T07:21:56.307774261Z",
        LOG.setup:   "name": "projects/test-project",
        LOG.setup:   "project_id": "test-project",
        LOG.setup:   "status": {
        LOG.setup:     "branch_logical_size_limit_bytes": 8796093022208,
        LOG.setup:     "default_branch": "projects/test-project/branches/production",
        LOG.setup:     "default_endpoint_settings": {
        LOG.setup:       "autoscaling_limit_max_cu": 1,
        LOG.setup:       "autoscaling_limit_min_cu": 1,
        LOG.setup:       "suspend_timeout_duration": "86400s"
        LOG.setup:     },
        LOG.setup:     "display_name": "Test Project",
        LOG.setup:     "enable_pg_native_login": false,
        LOG.setup:     "history_retention_duration": "604800s",
        LOG.setup:     "owner": "tester@databricks.com",
        LOG.setup:     "pg_version": 16,
        LOG.setup:     "project_id": "test-project",
        LOG.setup:     "synthetic_storage_size_bytes": 0
        LOG.setup:   },
        LOG.setup:   "uid": "7a0a1418-23dd-0efc-7a0a-141823dd1033",
        LOG.setup:   "update_time": "2026-11-05T07:21:56.307774261Z"
        LOG.setup: }
        LOG.setup: Warning: unknown field: postgres_data_apis
        LOG.setup:   at resources
        LOG.setup:   in databricks.yml:5:3
        LOG.setup: 
        LOG.setup: {
        LOG.setup:   "create_time": "2026-11-05T07:21:56.400608738Z",
        LOG.setup:   "database_id": "test-database",
        LOG.setup:   "name": "projects/test-project/branches/production/databases/test-database",
        LOG.setup:   "parent": "projects/test-project/branches/production",
        LOG.setup:   "status": {
        LOG.setup:     "database_id": "test-database",
        LOG.setup:     "postgres_database": "app_db",
        LOG.setup:     "role": "projects/test-project/branches/production/roles/owner"
        LOG.setup:   },
        LOG.setup:   "update_time": "2026-11-05T07:21:56.400608738Z"
        LOG.setup: }
        LOG.setup: Warning: unknown field: postgres_data_apis
        LOG.setup:   at resources
        LOG.setup:   in databricks.yml:5:3
        LOG.setup: 
        LOG.setup: {
        LOG.setup:   "create_time": "2026-11-05T07:21:56.488694835Z",
        LOG.setup:   "name": "projects/test-project/branches/production/databases/test-database/data-api",
        LOG.setup:   "parent": "projects/test-project/branches/production/databases/test-database",
        LOG.setup:   "status": {
        LOG.setup:     "available_schemas": [
        LOG.setup:       "public"
        LOG.setup:     ],
        LOG.setup:     "db_aggregates_enabled": true,
        LOG.setup:     "db_schemas": [
        LOG.setup:       "public"
        LOG.setup:     ],
        LOG.setup:     "jwt_role_claim_key": ".sub",
        LOG.setup:     "openapi_mode": "OPEN_API_MODE_DISABLED",
        LOG.setup:     "server_cors_allowed_origins": [
        LOG.setup:       "none"
        LOG.setup:     ],
        LOG.setup:     "url": "https://ep-7a0a1418-23dd-2ae2-7.database.us-east-1.cloud.databricks.com/api/2.0/workspace/900800700600/rest/app_db"
        LOG.setup:   },
        LOG.setup:   "update_time": "2026-11-05T07:21:56.488694835Z"
        LOG.setup: }

latest (v1.24.0):

acceptance_test.go:1345: Diff:
        --- bundle/deployment/bind/postgres_data_api/output.txt
        +++ /tmp/TestAcceptbundledeploymentbindpostgres_data_apiDMS=403657056/002/output.txt
        @@ -2,93 +2,14 @@
         === Enable the Data API on a database outside the bundle
         === Deploy fails because the Data API is already enabled
         >>> musterr [CLI] bundle deploy
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
        -Error: cannot create resources.postgres_data_apis.data_api1: Data API is already enabled for this database (409 ALREADY_EXISTS)
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:5:3
         
        -Endpoint: POST [DATABRICKS_URL]/api/2.0/postgres/projects/test-project/branches/production/databases/test-database/data-api
        -HTTP Status: 409 Conflict
        -API error_code: ALREADY_EXISTS
        -API message: Data API is already enabled for this database
        -
        +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
         Files: 2 uploaded, 0 deleted
        +Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
         
        -=== Bind adopts the existing Data API
        ->>> [CLI] bundle deployment bind data_api1 projects/test-project/branches/production/databases/test-database/data-api --auto-approve
        -Successfully bound postgres_data_api with an id 'projects/test-project/branches/production/databases/test-database/data-api'
        -Run 'bundle deploy' to deploy changes to your workspace
        +Unexpected success
         
        ->>> [CLI] bundle summary
        -Name: test-bundle
        -Target: default
        -Workspace:
        -  User: [USERNAME]
        -  Path: /Workspace/Users/[USERNAME]/.bundle/test-bundle/default
        -Resources:
        -  Postgres Data APIs:
        -    data_api1:
        -      Name: projects/test-project/branches/production/databases/test-database/data-api
        -
        ->>> [CLI] bundle plan
        -update postgres_data_apis.data_api1
        -
        -Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged
        -
        ->>> [CLI] bundle deploy
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
        -Updated postgres_data_apis.data_api1
        -Files: 0 uploaded, 0 deleted
        -Resources: 0 created, 1 changed, 0 deleted, 0 unchanged
        -
        ->>> [CLI] postgres get-data-api projects/test-project/branches/production/databases/test-database/data-api
        -{
        -  "name": "projects/test-project/branches/production/databases/test-database/data-api",
        -  "status": {
        -    "db_schemas": [
        -      "public"
        -    ],
        -    "db_max_rows": 500
        -  }
        -}
        -
        ->>> [CLI] bundle plan
        -Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged
        -
        -=== Unbind leaves the Data API enabled
        ->>> [CLI] bundle deployment unbind data_api1
        -
        ->>> [CLI] bundle summary
        -Name: test-bundle
        -Target: default
        -Workspace:
        -  User: [USERNAME]
        -  Path: /Workspace/Users/[USERNAME]/.bundle/test-bundle/default
        -Resources:
        -  Postgres Data APIs:
        -    data_api1:
        -      Name: 
        -
        ->>> [CLI] postgres get-data-api projects/test-project/branches/production/databases/test-database/data-api
        -{
        -  "name": "projects/test-project/branches/production/databases/test-database/data-api"
        -}
        -
        -=== Bind again; destroy turns off the Data API
        ->>> [CLI] bundle deployment bind data_api1 projects/test-project/branches/production/databases/test-database/data-api --auto-approve
        -Successfully bound postgres_data_api with an id 'projects/test-project/branches/production/databases/test-database/data-api'
        -Run 'bundle deploy' to deploy changes to your workspace
        -
        ->>> [CLI] bundle destroy --auto-approve
        -The following resources will be deleted:
        -  delete resources.postgres_data_apis.data_api1
        -
        -All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bundle/default
        -
        -Destroy: 1 deleted
        -
        ->>> musterr [CLI] postgres get-data-api projects/test-project/branches/production/databases/test-database/data-api
        -Error: Data API is not enabled for this database
        -
        ->>> [CLI] postgres get-database projects/test-project/branches/production/databases/test-database
        -{
        -  "name": "projects/test-project/branches/production/databases/test-database"
        -}
        +Exit code: 1
        
    acceptance_test.go:1123: 
        LOG.setup: Warning: unknown field: postgres_data_apis
        LOG.setup:   at resources
        LOG.setup:   in databricks.yml:5:3
        LOG.setup: 
        LOG.setup: {
        LOG.setup:   "create_time": "2026-11-05T07:22:04.786884918Z",
        LOG.setup:   "name": "projects/test-project",
        LOG.setup:   "project_id": "test-project",
        LOG.setup:   "status": {
        LOG.setup:     "branch_logical_size_limit_bytes": 8796093022208,
        LOG.setup:     "default_branch": "projects/test-project/branches/production",
        LOG.setup:     "default_endpoint_settings": {
        LOG.setup:       "autoscaling_limit_max_cu": 1,
        LOG.setup:       "autoscaling_limit_min_cu": 1,
        LOG.setup:       "suspend_timeout_duration": "86400s"
        LOG.setup:     },
        LOG.setup:     "display_name": "Test Project",
        LOG.setup:     "enable_pg_native_login": false,
        LOG.setup:     "history_retention_duration": "604800s",
        LOG.setup:     "owner": "tester@databricks.com",
        LOG.setup:     "pg_version": 16,
        LOG.setup:     "project_id": "test-project",
        LOG.setup:     "synthetic_storage_size_bytes": 0
        LOG.setup:   },
        LOG.setup:   "uid": "7a0a141a-1d42-039f-7a0a-141a1d4204b9",
        LOG.setup:   "update_time": "2026-11-05T07:22:04.786884918Z"
        LOG.setup: }
        LOG.setup: Warning: unknown field: postgres_data_apis
        LOG.setup:   at resources
        LOG.setup:   in databricks.yml:5:3
        LOG.setup: 
        LOG.setup: {
        LOG.setup:   "create_time": "2026-11-05T07:22:04.904451324Z",
        LOG.setup:   "database_id": "test-database",
        LOG.setup:   "name": "projects/test-project/branches/production/databases/test-database",
        LOG.setup:   "parent": "projects/test-project/branches/production",
        LOG.setup:   "status": {
        LOG.setup:     "database_id": "test-database",
        LOG.setup:     "postgres_database": "app_db",
        LOG.setup:     "role": "projects/test-project/branches/production/roles/owner"
        LOG.setup:   },
        LOG.setup:   "update_time": "2026-11-05T07:22:04.904451324Z"
        LOG.setup: }
        LOG.setup: Warning: unknown field: postgres_data_apis
        LOG.setup:   at resources
        LOG.setup:   in databricks.yml:5:3
        LOG.setup: 
        LOG.setup: {
        LOG.setup:   "create_time": "2026-11-05T07:22:05.079321272Z",
        LOG.setup:   "name": "projects/test-project/branches/production/databases/test-database/data-api",
        LOG.setup:   "parent": "projects/test-project/branches/production/databases/test-database",
        LOG.setup:   "status": {
        LOG.setup:     "available_schemas": [
        LOG.setup:       "public"
        LOG.setup:     ],
        LOG.setup:     "db_aggregates_enabled": true,
        LOG.setup:     "db_schemas": [
        LOG.setup:       "public"
        LOG.setup:     ],
        LOG.setup:     "jwt_role_claim_key": ".sub",
        LOG.setup:     "openapi_mode": "OPEN_API_MODE_DISABLED",
        LOG.setup:     "server_cors_allowed_origins": [
        LOG.setup:       "none"
        LOG.setup:     ],
        LOG.setup:     "url": "https://ep-7a0a141a-1d42-1b0e-7.database.us-east-1.cloud.databricks.com/api/2.0/workspace/900800700600/rest/app_db"
        LOG.setup:   },
        LOG.setup:   "update_time": "2026-11-05T07:22:05.079321272Z"
        LOG.setup: }
TestAccept/bundle/invariant/no_drift/DMS=/INPUT_CONFIG=postgres_data_api.yml.tmpl/READPLAN=: branch ✅ | main (7adc80d) ❌ | latest (v1.24.0) ❌

main (7adc80d):

acceptance_test.go:1345: Diff:
        --- bundle/invariant/no_drift/output.txt
        +++ /tmp/TestAcceptbundleinvariantno_driftDMS=INPUT_CONFIG=postgres_4205872967/002/output.txt
        @@ -1 +1,161 @@
         INPUT_CONFIG_OK
        +Expected at least one update action, found none
        +{
        +  "plan_version": [PLAN_VERSION],
        +  "cli_version": "[CLI_VERSION]",
        +  "lineage": "[UUID]",
        +  "serial": 1,
        +  "plan": {
        +    "resources.postgres_branches.production": {
        +      "depends_on": [
        +        {
        +          "node": "resources.postgres_projects.project",
        +          "label": "${resources.postgres_projects.project.name}"
        +        }
        +      ],
        +      "action": "skip",
        +      "remote_state": {
        +        "branch_id": "production",
        +        "create_time": "[TIMESTAMP]",
        +        "name": "projects/test-pg-project-[UNIQUE_NAME]/branches/production",
        +        "parent": "projects/test-pg-project-[UNIQUE_NAME]",
        +        "status": {
        +          "branch_id": "production",
        +          "current_state": "READY",
        +          "default": true,
        +          "is_protected": false,
        +          "logical_size_bytes": 0,
        +          "state_change_time": "[TIMESTAMP]"
        +        },
        +        "uid": "br-7a0a1418-9dd6-613a-7",
        +        "update_time": "[TIMESTAMP]"
        +      },
        +      "changes": {
        +        "no_expiry": {
        +          "action": "skip",
        +          "reason": "spec:input_only",
        +          "old": true,
        +          "new": true
        +        },
        +        "replace_existing": {
        +          "action": "skip",
        +          "reason": "missing_in_remote",
        +          "old": true,
        +          "new": true
        +        }
        +      }
        +    },
        +    "resources.postgres_databases.database": {
        +      "depends_on": [
        +        {
        +          "node": "resources.postgres_branches.production",
        +          "label": "${resources.postgres_branches.production.name}"
        +        },
        +        {
        +          "node": "resources.postgres_roles.owner",
        +          "label": "${resources.postgres_roles.owner.name}"
        +        }
        +      ],
        +      "action": "skip",
        +      "remote_state": {
        +        "create_time": "[TIMESTAMP]",
        +        "database_id": "test-database-[UNIQUE_NAME]",
        +        "name": "projects/test-pg-project-[UNIQUE_NAME]/branches/production/databases/test-database-[UNIQUE_NAME]",
        +        "parent": "projects/test-pg-project-[UNIQUE_NAME]/branches/production",
        +        "role": "",
        +        "status": {
        +          "database_id": "test-database-[UNIQUE_NAME]",
        +          "postgres_database": "app_db",
        +          "role": "projects/test-pg-project-[UNIQUE_NAME]/branches/production/roles/test-role-[UNIQUE_NAME]"
        +        },
        +        "update_time": "[TIMESTAMP]"
        +      },
        +      "changes": {
        +        "postgres_database": {
        +          "action": "skip",
        +          "reason": "spec:input_only",
        +          "old": "app_db",
        +          "new": "app_db"
        +        },
        +        "role": {
        +          "action": "skip",
        +          "reason": "spec:input_only",
        +          "old": "projects/test-pg-project-[UNIQUE_NAME]/branches/production/roles/test-role-[UNIQUE_NAME]",
        +          "new": "projects/test-pg-project-[UNIQUE_NAME]/branches/production/roles/test-role-[UNIQUE_NAME]",
        +          "remote": ""
        +        }
        +      }
        +    },
        +    "resources.postgres_projects.project": {
        +      "action": "skip",
        +      "remote_state": {
        +        "create_time": "[TIMESTAMP]",
        +        "name": "projects/test-pg-project-[UNIQUE_NAME]",
        +        "project_id": "test-pg-project-[UNIQUE_NAME]",
        +        "status": {
        +          "branch_logical_size_limit_bytes": 8796093022208,
        +          "default_branch": "projects/test-pg-project-[UNIQUE_NAME]/branches/production",
        +          "default_endpoint_settings": {
        +            "autoscaling_limit_max_cu": 1,
        +            "autoscaling_limit_min_cu": 1,
        +            "suspend_timeout_duration": "86400s"
        +          },
        +          "display_name": "Test Postgres Project",
        +          "enable_pg_native_login": false,
        +          "history_retention_duration": "604800s",
        +          "owner": "[USERNAME]",
        +          "project_id": "test-pg-project-[UNIQUE_NAME]",
        +          "synthetic_storage_size_bytes": 0
        +        },
        +        "uid": "[UUID]",
        +        "update_time": "[TIMESTAMP]"
        +      },
        +      "changes": {
        +        "display_name": {
        +          "action": "skip",
        +          "reason": "spec:input_only",
        +          "old": "Test Postgres Project",
        +          "new": "Test Postgres Project"
        +        }
        +      }
        +    },
        +    "resources.postgres_roles.owner": {
        +      "depends_on": [
        +        {
        +          "node": "resources.postgres_branches.production",
        +          "label": "${resources.postgres_branches.production.name}"
        +        }
        +      ],
        +      "action": "skip",
        +      "remote_state": {
        +        "create_time": "[TIMESTAMP]",
        +        "name": "projects/test-pg-project-[UNIQUE_NAME]/branches/production/roles/test-role-[UNIQUE_NAME]",
        +        "parent": "projects/test-pg-project-[UNIQUE_NAME]/branches/production",
        +        "role_id": "test-role-[UNIQUE_NAME]",
        +        "status": {
        +          "attributes": {
        +            "bypassrls": false,
        +            "createdb": false,
        +            "createrole": false
        +          },
        +          "auth_method": "PG_PASSWORD_SCRAM_SHA_256",
        +          "identity_type": "IDENTITY_TYPE_UNSPECIFIED",
        +          "postgres_role": "app_role",
        +          "role_id": "test-role-[UNIQUE_NAME]"
        +        },
        +        "update_time": "[TIMESTAMP]"
        +      },
        +      "changes": {
        +        "postgres_role": {
        +          "action": "skip",
        +          "reason": "spec:input_only",
        +          "old": "app_role",
        +          "new": "app_role"
        +        }
        +      }
        +    }
        +  }
        +}
        +
        +
        +Exit code: 10
        
    acceptance_test.go:1123: 
        LOG.config: bundle:
        LOG.config:   name: test-bundle-bbbuh5qtnjbujgwtir3lig2oje
        LOG.config: 
        LOG.config: resources:
        LOG.config:   postgres_projects:
        LOG.config:     project:
        LOG.config:       project_id: test-pg-project-bbbuh5qtnjbujgwtir3lig2oje
        LOG.config:       display_name: Test Postgres Project
        LOG.config: 
        LOG.config:   # The Data API needs a read-write endpoint on the branch. Take over the
        LOG.config:   # "production" branch created with the project, which comes with one.
        LOG.config:   postgres_branches:
        LOG.config:     production:
        LOG.config:       parent: ${resources.postgres_projects.project.name}
        LOG.config:       branch_id: production
        LOG.config:       replace_existing: true
        LOG.config:       no_expiry: true
        LOG.config: 
        LOG.config:   postgres_roles:
        LOG.config:     owner:
        LOG.config:       parent: ${resources.postgres_branches.production.name}
        LOG.config:       role_id: test-role-bbbuh5qtnjbujgwtir3lig2oje
        LOG.config:       postgres_role: app_role
        LOG.config: 
        LOG.config:   postgres_databases:
        LOG.config:     database:
        LOG.config:       parent: ${resources.postgres_branches.production.name}
        LOG.config:       database_id: test-database-bbbuh5qtnjbujgwtir3lig2oje
        LOG.config:       postgres_database: app_db
        LOG.config:       role: ${resources.postgres_roles.owner.name}
        LOG.config: 
        LOG.config:   postgres_data_apis:
        LOG.config:     foo:
... (196 more lines truncated, raise DATABRICKS_CLI_TEST_MAX_LOG to see more)

latest (v1.24.0):

acceptance_test.go:1345: Diff:
        --- bundle/invariant/no_drift/output.txt
        +++ /tmp/TestAcceptbundleinvariantno_driftDMS=INPUT_CONFIG=postgres_1763553154/002/output.txt
        @@ -1 +1,161 @@
         INPUT_CONFIG_OK
        +Expected at least one update action, found none
        +{
        +  "plan_version": [PLAN_VERSION],
        +  "cli_version": "[CLI_VERSION]",
        +  "lineage": "[UUID]",
        +  "serial": 1,
        +  "plan": {
        +    "resources.postgres_branches.production": {
        +      "depends_on": [
        +        {
        +          "node": "resources.postgres_projects.project",
        +          "label": "${resources.postgres_projects.project.name}"
        +        }
        +      ],
        +      "action": "skip",
        +      "remote_state": {
        +        "branch_id": "production",
        +        "create_time": "[TIMESTAMP]",
        +        "name": "projects/test-pg-project-[UNIQUE_NAME]/branches/production",
        +        "parent": "projects/test-pg-project-[UNIQUE_NAME]",
        +        "status": {
        +          "branch_id": "production",
        +          "current_state": "READY",
        +          "default": true,
        +          "is_protected": false,
        +          "logical_size_bytes": 0,
        +          "state_change_time": "[TIMESTAMP]"
        +        },
        +        "uid": "br-7a0a141a-85df-6315-7",
        +        "update_time": "[TIMESTAMP]"
        +      },
        +      "changes": {
        +        "no_expiry": {
        +          "action": "skip",
        +          "reason": "spec:input_only",
        +          "old": true,
        +          "new": true
        +        },
        +        "replace_existing": {
        +          "action": "skip",
        +          "reason": "missing_in_remote",
        +          "old": true,
        +          "new": true
        +        }
        +      }
        +    },
        +    "resources.postgres_databases.database": {
        +      "depends_on": [
        +        {
        +          "node": "resources.postgres_branches.production",
        +          "label": "${resources.postgres_branches.production.name}"
        +        },
        +        {
        +          "node": "resources.postgres_roles.owner",
        +          "label": "${resources.postgres_roles.owner.name}"
        +        }
        +      ],
        +      "action": "skip",
        +      "remote_state": {
        +        "create_time": "[TIMESTAMP]",
        +        "database_id": "test-database-[UNIQUE_NAME]",
        +        "name": "projects/test-pg-project-[UNIQUE_NAME]/branches/production/databases/test-database-[UNIQUE_NAME]",
        +        "parent": "projects/test-pg-project-[UNIQUE_NAME]/branches/production",
        +        "role": "",
        +        "status": {
        +          "database_id": "test-database-[UNIQUE_NAME]",
        +          "postgres_database": "app_db",
        +          "role": "projects/test-pg-project-[UNIQUE_NAME]/branches/production/roles/test-role-[UNIQUE_NAME]"
        +        },
        +        "update_time": "[TIMESTAMP]"
        +      },
        +      "changes": {
        +        "postgres_database": {
        +          "action": "skip",
        +          "reason": "spec:input_only",
        +          "old": "app_db",
        +          "new": "app_db"
        +        },
        +        "role": {
        +          "action": "skip",
        +          "reason": "spec:input_only",
        +          "old": "projects/test-pg-project-[UNIQUE_NAME]/branches/production/roles/test-role-[UNIQUE_NAME]",
        +          "new": "projects/test-pg-project-[UNIQUE_NAME]/branches/production/roles/test-role-[UNIQUE_NAME]",
        +          "remote": ""
        +        }
        +      }
        +    },
        +    "resources.postgres_projects.project": {
        +      "action": "skip",
        +      "remote_state": {
        +        "create_time": "[TIMESTAMP]",
        +        "name": "projects/test-pg-project-[UNIQUE_NAME]",
        +        "project_id": "test-pg-project-[UNIQUE_NAME]",
        +        "status": {
        +          "branch_logical_size_limit_bytes": 8796093022208,
        +          "default_branch": "projects/test-pg-project-[UNIQUE_NAME]/branches/production",
        +          "default_endpoint_settings": {
        +            "autoscaling_limit_max_cu": 1,
        +            "autoscaling_limit_min_cu": 1,
        +            "suspend_timeout_duration": "86400s"
        +          },
        +          "display_name": "Test Postgres Project",
        +          "enable_pg_native_login": false,
        +          "history_retention_duration": "604800s",
        +          "owner": "[USERNAME]",
        +          "project_id": "test-pg-project-[UNIQUE_NAME]",
        +          "synthetic_storage_size_bytes": 0
        +        },
        +        "uid": "[UUID]",
        +        "update_time": "[TIMESTAMP]"
        +      },
        +      "changes": {
        +        "display_name": {
        +          "action": "skip",
        +          "reason": "spec:input_only",
        +          "old": "Test Postgres Project",
        +          "new": "Test Postgres Project"
        +        }
        +      }
        +    },
        +    "resources.postgres_roles.owner": {
        +      "depends_on": [
        +        {
        +          "node": "resources.postgres_branches.production",
        +          "label": "${resources.postgres_branches.production.name}"
        +        }
        +      ],
        +      "action": "skip",
        +      "remote_state": {
        +        "create_time": "[TIMESTAMP]",
        +        "name": "projects/test-pg-project-[UNIQUE_NAME]/branches/production/roles/test-role-[UNIQUE_NAME]",
        +        "parent": "projects/test-pg-project-[UNIQUE_NAME]/branches/production",
        +        "role_id": "test-role-[UNIQUE_NAME]",
        +        "status": {
        +          "attributes": {
        +            "bypassrls": false,
        +            "createdb": false,
        +            "createrole": false
        +          },
        +          "auth_method": "PG_PASSWORD_SCRAM_SHA_256",
        +          "identity_type": "IDENTITY_TYPE_UNSPECIFIED",
        +          "postgres_role": "app_role",
        +          "role_id": "test-role-[UNIQUE_NAME]"
        +        },
        +        "update_time": "[TIMESTAMP]"
        +      },
        +      "changes": {
        +        "postgres_role": {
        +          "action": "skip",
        +          "reason": "spec:input_only",
        +          "old": "app_role",
        +          "new": "app_role"
        +        }
        +      }
        +    }
        +  }
        +}
        +
        +
        +Exit code: 10
        
    acceptance_test.go:1123: 
        LOG.config: bundle:
        LOG.config:   name: test-bundle-7rje7nf4bbas5anjyvsinkfopa
        LOG.config: 
        LOG.config: resources:
        LOG.config:   postgres_projects:
        LOG.config:     project:
        LOG.config:       project_id: test-pg-project-7rje7nf4bbas5anjyvsinkfopa
        LOG.config:       display_name: Test Postgres Project
        LOG.config: 
        LOG.config:   # The Data API needs a read-write endpoint on the branch. Take over the
        LOG.config:   # "production" branch created with the project, which comes with one.
        LOG.config:   postgres_branches:
        LOG.config:     production:
        LOG.config:       parent: ${resources.postgres_projects.project.name}
        LOG.config:       branch_id: production
        LOG.config:       replace_existing: true
        LOG.config:       no_expiry: true
        LOG.config: 
        LOG.config:   postgres_roles:
        LOG.config:     owner:
        LOG.config:       parent: ${resources.postgres_branches.production.name}
        LOG.config:       role_id: test-role-7rje7nf4bbas5anjyvsinkfopa
        LOG.config:       postgres_role: app_role
        LOG.config: 
        LOG.config:   postgres_databases:
        LOG.config:     database:
        LOG.config:       parent: ${resources.postgres_branches.production.name}
        LOG.config:       database_id: test-database-7rje7nf4bbas5anjyvsinkfopa
        LOG.config:       postgres_database: app_db
        LOG.config:       role: ${resources.postgres_roles.owner.name}
        LOG.config: 
        LOG.config:   postgres_data_apis:
        LOG.config:     foo:
... (196 more lines truncated, raise DATABRICKS_CLI_TEST_MAX_LOG to see more)
TestAccept/bundle/refschema/DMS=: branch ✅ | main (7adc80d) ❌ | latest (v1.24.0) ❌

main (7adc80d):

acceptance_test.go:1316: Missing output file: output/postgres_data_apis.txt

latest (v1.24.0): same output as main (7adc80d)

TestAccept/bundle/refschema/DMS=true: branch ✅ | main (7adc80d) ❌ | latest (v1.24.0) ❌

main (7adc80d):

acceptance_test.go:1316: Missing output file: output/postgres_data_apis.txt

latest (v1.24.0): same output as main (7adc80d)

TestAccept/bundle/resources/postgres_data_apis/basic/DMS=: branch ✅ | main (7adc80d) ❌ | latest (v1.24.0) ❌

main (7adc80d):

acceptance_test.go:1345: Diff:
        --- bundle/resources/postgres_data_apis/basic/output.txt
        +++ /tmp/TestAcceptbundleresourcespostgres_data_apisbasicDMS=1160923048/002/output.txt
        @@ -1,23 +1,28 @@
         
         >>> [CLI] bundle validate
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:36:3
        +
         Name: deploy-pg-data-api-[UNIQUE_NAME]
         Target: default
         Workspace:
           User: [USERNAME]
           Path: /Workspace/Users/[USERNAME]/.bundle/deploy-pg-data-api-[UNIQUE_NAME]/default
         
        -Validation OK!
        +Found 1 warning
         
         >>> [CLI] bundle summary
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:36:3
        +
         Name: deploy-pg-data-api-[UNIQUE_NAME]
         Target: default
         Workspace:
           User: [USERNAME]
           Path: /Workspace/Users/[USERNAME]/.bundle/deploy-pg-data-api-[UNIQUE_NAME]/default
         Resources:
        -  Postgres Data APIs:
        -    my_data_api:
        -      Name: 
           Postgres branches:
             production:
               Name: 
        @@ -32,88 +23,43 @@
               Name: 
         
         >>> [CLI] bundle plan
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:36:3
        +
         create postgres_branches.production
        -create postgres_data_apis.my_data_api
         create postgres_databases.my_database
         create postgres_projects.my_project
         create postgres_roles.owner
         
        -Plan: 5 to add, 0 to change, 0 to delete, 0 unchanged
        +Plan: 4 to add, 0 to change, 0 to delete, 0 unchanged
         
         === Deploy enables the Data API
         >>> [CLI] bundle deploy
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:36:3
        +
         Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/deploy-pg-data-api-[UNIQUE_NAME]/default/files...
         Created postgres_branches.production
        -Created postgres_data_apis.my_data_api
         Created postgres_databases.my_database
         Created postgres_projects.my_project
         Created postgres_roles.owner
         Files: 0 uploaded, 0 deleted
        -Resources: 5 created, 0 changed, 0 deleted, 0 unchanged
        +Resources: 4 created, 0 changed, 0 deleted, 0 unchanged
         
         >>> [CLI] postgres get-data-api projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api
        -{
        -  "name": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api",
        -  "parent": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database",
        -  "status": {
        -    "db_schemas": [
        -      "public"
        -    ],
        -    "db_max_rows": 100,
        -    "server_cors_allowed_origins": [
        -      "none"
        -    ]
        -  }
        -}
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:36:3
         
        ->>> [CLI] bundle summary
        -Name: deploy-pg-data-api-[UNIQUE_NAME]
        -Target: default
        -Workspace:
        -  User: [USERNAME]
        -  Path: /Workspace/Users/[USERNAME]/.bundle/deploy-pg-data-api-[UNIQUE_NAME]/default
        -Resources:
        -  Postgres Data APIs:
        -    my_data_api:
        -      Name: projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api
        -  Postgres branches:
        -    production:
        -      Name: projects/test-pg-proj-[UNIQUE_NAME]/branches/production
        -  Postgres databases:
        -    my_database:
        -      Name: projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database
        -  Postgres projects:
        -    my_project:
        -      Name: Test Project for Data API
        -  Postgres roles:
        -    owner:
        -      Name: projects/test-pg-proj-[UNIQUE_NAME]/branches/production/roles/app-owner
        -
        -=== Plan after deploy shows no changes
        ->>> [CLI] bundle plan
        -Plan: 0 to add, 0 to change, 0 to delete, 5 unchanged
        -
        -=== Removing the resource turns off the Data API but keeps the database
        ->>> [CLI] bundle plan
        -delete postgres_data_apis.my_data_api
        -
        -Plan: 0 to add, 0 to change, 1 to delete, 4 unchanged
        -
        ->>> [CLI] bundle deploy --auto-approve
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/deploy-pg-data-api-[UNIQUE_NAME]/default/files...
        -Deleted postgres_data_apis.my_data_api
        -Files: 0 uploaded, 0 deleted
        -Resources: 0 created, 0 changed, 1 deleted, 4 unchanged
        -
        ->>> musterr [CLI] postgres get-data-api projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api
         Error: Data API is not enabled for this database
         
        ->>> [CLI] postgres get-database projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database
        -{
        -  "name": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database"
        -}
        -
         >>> [CLI] bundle destroy --auto-approve
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:36:3
        +
         The following resources will be deleted:
           delete resources.postgres_branches.production
           delete resources.postgres_databases.my_database
        @@ -135,3 +61,5 @@
         All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/deploy-pg-data-api-[UNIQUE_NAME]/default
         
         Destroy: 4 deleted
        +
        +Exit code: 1
        
    acceptance_test.go:1345: Diff:
        --- bundle/resources/postgres_data_apis/basic/out.requests.deploy.json
        +++ /tmp/TestAcceptbundleresourcespostgres_data_apisbasicDMS=1160923048/001/out.requests.deploy.json
        @@ -49,15 +49,3 @@
             }
           }
         }
        -{
        -  "method": "POST",
        -  "path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api",
        -  "body": {
        -    "spec": {
        -      "db_max_rows": 100,
        -      "db_schemas": [
        -        "public"
        -      ]
        -    }
        -  }
        -}
        
    acceptance_test.go:1316: Missing output file: out.requests.remove.json

latest (v1.24.0):

acceptance_test.go:1345: Diff:
        --- bundle/resources/postgres_data_apis/basic/output.txt
        +++ /tmp/TestAcceptbundleresourcespostgres_data_apisbasicDMS=2650671977/002/output.txt
        @@ -1,23 +1,28 @@
         
         >>> [CLI] bundle validate
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:36:3
        +
         Name: deploy-pg-data-api-[UNIQUE_NAME]
         Target: default
         Workspace:
           User: [USERNAME]
           Path: /Workspace/Users/[USERNAME]/.bundle/deploy-pg-data-api-[UNIQUE_NAME]/default
         
        -Validation OK!
        +Found 1 warning
         
         >>> [CLI] bundle summary
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:36:3
        +
         Name: deploy-pg-data-api-[UNIQUE_NAME]
         Target: default
         Workspace:
           User: [USERNAME]
           Path: /Workspace/Users/[USERNAME]/.bundle/deploy-pg-data-api-[UNIQUE_NAME]/default
         Resources:
        -  Postgres Data APIs:
        -    my_data_api:
        -      Name: 
           Postgres branches:
             production:
               Name: 
        @@ -32,88 +23,43 @@
               Name: 
         
         >>> [CLI] bundle plan
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:36:3
        +
         create postgres_branches.production
        -create postgres_data_apis.my_data_api
         create postgres_databases.my_database
         create postgres_projects.my_project
         create postgres_roles.owner
         
        -Plan: 5 to add, 0 to change, 0 to delete, 0 unchanged
        +Plan: 4 to add, 0 to change, 0 to delete, 0 unchanged
         
         === Deploy enables the Data API
         >>> [CLI] bundle deploy
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:36:3
        +
         Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/deploy-pg-data-api-[UNIQUE_NAME]/default/files...
         Created postgres_branches.production
        -Created postgres_data_apis.my_data_api
         Created postgres_databases.my_database
         Created postgres_projects.my_project
         Created postgres_roles.owner
         Files: 0 uploaded, 0 deleted
        -Resources: 5 created, 0 changed, 0 deleted, 0 unchanged
        +Resources: 4 created, 0 changed, 0 deleted, 0 unchanged
         
         >>> [CLI] postgres get-data-api projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api
        -{
        -  "name": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api",
        -  "parent": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database",
        -  "status": {
        -    "db_schemas": [
        -      "public"
        -    ],
        -    "db_max_rows": 100,
        -    "server_cors_allowed_origins": [
        -      "none"
        -    ]
        -  }
        -}
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:36:3
         
        ->>> [CLI] bundle summary
        -Name: deploy-pg-data-api-[UNIQUE_NAME]
        -Target: default
        -Workspace:
        -  User: [USERNAME]
        -  Path: /Workspace/Users/[USERNAME]/.bundle/deploy-pg-data-api-[UNIQUE_NAME]/default
        -Resources:
        -  Postgres Data APIs:
        -    my_data_api:
        -      Name: projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api
        -  Postgres branches:
        -    production:
        -      Name: projects/test-pg-proj-[UNIQUE_NAME]/branches/production
        -  Postgres databases:
        -    my_database:
        -      Name: projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database
        -  Postgres projects:
        -    my_project:
        -      Name: Test Project for Data API
        -  Postgres roles:
        -    owner:
        -      Name: projects/test-pg-proj-[UNIQUE_NAME]/branches/production/roles/app-owner
        -
        -=== Plan after deploy shows no changes
        ->>> [CLI] bundle plan
        -Plan: 0 to add, 0 to change, 0 to delete, 5 unchanged
        -
        -=== Removing the resource turns off the Data API but keeps the database
        ->>> [CLI] bundle plan
        -delete postgres_data_apis.my_data_api
        -
        -Plan: 0 to add, 0 to change, 1 to delete, 4 unchanged
        -
        ->>> [CLI] bundle deploy --auto-approve
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/deploy-pg-data-api-[UNIQUE_NAME]/default/files...
        -Deleted postgres_data_apis.my_data_api
        -Files: 0 uploaded, 0 deleted
        -Resources: 0 created, 0 changed, 1 deleted, 4 unchanged
        -
        ->>> musterr [CLI] postgres get-data-api projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api
         Error: Data API is not enabled for this database
         
        ->>> [CLI] postgres get-database projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database
        -{
        -  "name": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database"
        -}
        -
         >>> [CLI] bundle destroy --auto-approve
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:36:3
        +
         The following resources will be deleted:
           delete resources.postgres_branches.production
           delete resources.postgres_databases.my_database
        @@ -135,3 +61,5 @@
         All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/deploy-pg-data-api-[UNIQUE_NAME]/default
         
         Destroy: 4 deleted
        +
        +Exit code: 1
        
    acceptance_test.go:1316: Missing output file: out.requests.remove.json
    acceptance_test.go:1345: Diff:
        --- bundle/resources/postgres_data_apis/basic/out.requests.deploy.json
        +++ /tmp/TestAcceptbundleresourcespostgres_data_apisbasicDMS=2650671977/001/out.requests.deploy.json
        @@ -49,15 +49,3 @@
             }
           }
         }
        -{
        -  "method": "POST",
        -  "path": "/api/2.0/postgres/projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api",
        -  "body": {
        -    "spec": {
        -      "db_max_rows": 100,
        -      "db_schemas": [
        -        "public"
        -      ]
        -    }
        -  }
        -}
TestAccept/bundle/resources/postgres_data_apis/out-of-band/DMS=: branch ✅ | main (7adc80d) ❌ | latest (v1.24.0) ❌

main (7adc80d):

acceptance_test.go:1345: Diff:
        --- bundle/resources/postgres_data_apis/out-of-band/output.txt
        +++ /tmp/TestAcceptbundleresourcespostgres_data_apisout-of-bandDMS=1650556314/002/output.txt
        @@ -1,110 +1,32 @@
         
         === Deploy enables the Data API
         >>> [CLI] bundle deploy
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:36:3
        +
         Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/oob-pg-data-api-[UNIQUE_NAME]/default/files...
         Created postgres_branches.production
        -Created postgres_data_apis.my_data_api
         Created postgres_databases.my_database
         Created postgres_projects.my_project
         Created postgres_roles.owner
         Files: 0 uploaded, 0 deleted
        -Resources: 5 created, 0 changed, 0 deleted, 0 unchanged
        +Resources: 4 created, 0 changed, 0 deleted, 0 unchanged
         
         >>> [CLI] postgres get-data-api projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api
        -{
        -  "name": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api",
        -  "parent": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database",
        -  "status": {
        -    "db_schemas": [
        -      "public"
        -    ],
        -    "db_max_rows": 100,
        -    "server_cors_allowed_origins": [
        -      "none"
        -    ]
        -  }
        -}
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:36:3
         
        -=== Change the spec out of band
        ->>> [CLI] postgres update-data-api projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api spec --json {"spec": {"db_schemas": ["public"], "db_max_rows": 7}}
        -{
        -  "name": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api",
        -  "parent": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database",
        -  "status": {
        -    "db_schemas": [
        -      "public"
        -    ],
        -    "db_max_rows": 7,
        -    "server_cors_allowed_origins": [
        -      "none"
        -    ]
        -  }
        -}
        +Error: Data API is not enabled for this database
         
        -=== Plan detects the change from status, and deploy restores the config
        ->>> [CLI] bundle plan
        -update postgres_data_apis.my_data_api
        -
        -Plan: 0 to add, 1 to change, 0 to delete, 4 unchanged
        -
        ->>> [CLI] bundle deploy
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/oob-pg-data-api-[UNIQUE_NAME]/default/files...
        -Updated postgres_data_apis.my_data_api
        -Files: 0 uploaded, 0 deleted
        -Resources: 0 created, 1 changed, 0 deleted, 4 unchanged
        -
        ->>> [CLI] postgres get-data-api projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api
        -{
        -  "name": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api",
        -  "parent": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database",
        -  "status": {
        -    "db_schemas": [
        -      "public"
        -    ],
        -    "db_max_rows": 100,
        -    "server_cors_allowed_origins": [
        -      "none"
        -    ]
        -  }
        -}
        -
        ->>> [CLI] bundle plan
        -Plan: 0 to add, 0 to change, 0 to delete, 5 unchanged
        -
        -=== Disable the Data API out of band
        ->>> [CLI] postgres delete-data-api projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api
        -
        -=== Plan detects the Data API is gone and re-creates it
        ->>> [CLI] bundle plan
        -create postgres_data_apis.my_data_api
        -
        -Plan: 1 to add, 0 to change, 0 to delete, 4 unchanged
        -
        ->>> [CLI] bundle deploy
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/oob-pg-data-api-[UNIQUE_NAME]/default/files...
        -Created postgres_data_apis.my_data_api
        -Files: 0 uploaded, 0 deleted
        -Resources: 1 created, 0 changed, 0 deleted, 4 unchanged
        -
        ->>> [CLI] postgres get-data-api projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api
        -{
        -  "name": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database/data-api",
        -  "parent": "projects/test-pg-proj-[UNIQUE_NAME]/branches/production/databases/my-database",
        -  "status": {
        -    "db_schemas": [
        -      "public"
        -    ],
        -    "db_max_rows": 100,
        -    "server_cors_allowed_origins": [
        -      "none"
        -    ]
        -  }
        -}
        -
         >>> [CLI] bundle destroy --auto-approve
        +Warning: unknown field: postgres_data_apis
        +  at resources
        +  in databricks.yml:36:3
        +
         The following resources will be deleted:
           delete resources.postgres_branches.production
        -  delete resources.postgres_data_apis.my_data_api
           delete resources.postgres_databases.my_database
           delete resources.postgres_projects.my_project
           delete resources.postgres_roles.owner
        @@ -123,4 +32,6 @@
         
         All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/oob-pg-data-api-[UNIQUE_NAME]/default
         
        -Destroy: 5 deleted
        +Destroy: 4 deleted
        +
        +Exit code: 1

latest (v1.24.0): same output as main (7adc80d)

TestAccept/bundle/resources/postgres_data_apis/parent_only/DMS=: branch ✅ | main (7adc80d) ❌ | latest (v1.24.0) ❌

main (7adc80d):

acceptance_test.go:1345: 
        	Error Trace:	/home/runner/work/cli/cli/libs/testdiff/testdiff.go:22
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:1345
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:1086
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:660
        	Error:      	Not equal: 
        	            	expected: "\n=== Validate rejects a Data API that sets only parent\n>>> musterr [CLI] bundle validate\nError: postgres_data_apis.my_data_api: at least one Data API setting besides parent is required, for example db_schemas\n  at resources.postgres_data_apis.my_data_api\n  in databricks.yml:7:7\n\nName: parent-only-pg-data-api\nTarget: default\nWorkspace:\n  User: [USERNAME]\n  Path: /Workspace/Users/[USERNAME]/.bundle/parent-only-pg-data-api/default\n\nFound 1 error\n\n=== Deploy fails the same way before anything is created\n>>> musterr [CLI] bundle deploy\nError: postgres_data_apis.my_data_api: at least one Data API setting besides parent is required, for example db_schemas\n  at resources.postgres_data_apis.my_data_api\n  in databricks.yml:7:7\n\n"
        	            	actual  : "\n=== Validate rejects a Data API that sets only parent\n>>> musterr [CLI] bundle validate\nWarning: unknown field: postgres_data_apis\n  at resources\n  in databricks.yml:5:3\n\nName: parent-only-pg-data-api\nTarget: default\nWorkspace:\n  User: [USERNAME]\n  Path: /Workspace/Users/[USERNAME]/.bundle/parent-only-pg-data-api/default\n\nFound 1 warning\n\nUnexpected success\n\nExit code: 1\n"
        	            	
        	            	Diff:
        	            	--- Expected
        	            	+++ Actual
        	            	@@ -3,5 +3,5 @@
        	            	 >>> musterr [CLI] bundle validate
        	            	-Error: postgres_data_apis.my_data_api: at least one Data API setting besides parent is required, for example db_schemas
        	            	-  at resources.postgres_data_apis.my_data_api
        	            	-  in databricks.yml:7:7
        	            	+Warning: unknown field: postgres_data_apis
        	            	+  at resources
        	            	+  in databricks.yml:5:3
        	            	 
        	            	@@ -13,10 +13,7 @@
        	            	 
        	            	-Found 1 error
        	            	+Found 1 warning
        	            	 
        	            	-=== Deploy fails the same way before anything is created
        	            	->>> musterr [CLI] bundle deploy
        	            	-Error: postgres_data_apis.my_data_api: at least one Data API setting besides parent is required, for example db_schemas
        	            	-  at resources.postgres_data_apis.my_data_api
        	            	-  in databricks.yml:7:7
        	            	+Unexpected success
        	            	 
        	            	+Exit code: 1
        	            	 
        	Test:       	TestAccept/bundle/resources/postgres_data_apis/parent_only/DMS=
        	Messages:   	bundle/resources/postgres_data_apis/parent_only/output.txt vs /tmp/TestAcceptbundleresourcespostgres_data_apisparent_onlyDMS=2354082818/002/output.txt

latest (v1.24.0): same output as main (7adc80d)

3 more failure details omitted, see the full report in the run.

ruslantalpa added a commit that referenced this pull request Oct 22, 2026
Co-authored-by: Isaac <no-reply@databricks.com>
@ruslantalpa
ruslantalpa force-pushed the ruslantalpa/postgres-data-apis branch from 3be15c5 to 1a763c3 Compare October 22, 2026 11:14
@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: ed7fa4e

Run: 41985912941

Env ✅​pass 🙈​skip Time
✅​ aws linux-2core-8gb 281 21 4:59
✅​ aws-windows-latest-4core-16gb 283 19 8:48
✅​ azure linux-2core-8gb 270 26 3:54
✅​ azure-windows-latest-4core-16gb 272 24 7:16
✅​ gcp linux-2core-8gb 271 26 3:58
✅​ gcp-windows-latest-4core-16gb 273 24 6:15
Top 3 slowest tests (at least 2 minutes):
duration env testname
7:10 azure-windows-latest-4core-16gb TestAccept
7:02 aws-windows-latest-4core-16gb TestAccept
6:09 gcp-windows-latest-4core-16gb TestAccept

@ruslantalpa
ruslantalpa marked this pull request as ready for review October 23, 2026 13:26
@ruslantalpa
ruslantalpa requested review from a team as code owners October 23, 2026 13:26
ruslantalpa added a commit that referenced this pull request Nov 2, 2026
Co-authored-by: Isaac <no-reply@databricks.com>
@ruslantalpa
ruslantalpa force-pushed the ruslantalpa/postgres-data-apis branch from 300f4d8 to b83bc7f Compare November 2, 2026 14:06
@ruslantalpa
ruslantalpa added this pull request to the merge queue Nov 3, 2026
@ruslantalpa
ruslantalpa removed this pull request from the merge queue due to a manual request Nov 3, 2026
@ruslantalpa
ruslantalpa requested review from pietern and removed request for chrisst and shreyas-goenka November 4, 2026 07:20
ruslantalpa and others added 10 commits November 5, 2026 07:03
Add the `postgres_data_apis` resource, which enables and configures the
Data API (PostgREST) of a Lakebase Postgres database.

The Data API is a per-database singleton with no ID of its own: its
resource name is "{parent}/data-api", and `parent` is a provided id
field, so changing it recreates. Create, update, and delete are
long-running operations. Updates send the full spec with
update_mask=spec, so a field removed from the config resets to its
server default.

spec is INPUT_ONLY in the API, so GET does not return it and remote
spec changes are not detected (ignore_remote_changes spec:input_only,
generated). Deleting the resource turns the Data API off; the database
and its data are unaffected.

The resource is labelled Private Preview, matching the API's launch
stage, rather than the Beta its postgres_* siblings are pinned to.

Co-authored-by: Isaac <no-reply@databricks.com>
Observed against a real workspace:

- status reports the configuration in effect, server defaults included:
  db_aggregates_enabled=true, db_schemas=["public"],
  jwt_role_claim_key=".sub", openapi_mode=OPEN_API_MODE_DISABLED and
  server_cors_allowed_origins=["none"]. A bool that was never set and is
  false is omitted; once set it is reported, false included.
- update_mask=spec keeps the current value of a field the request omits;
  it does not reset it to the default.
- Errors: 400 INVALID_PARAMETER_VALUE "Field 'data_api' is required and
  must contain at least one subfield with a non-default value!" for an
  empty spec, 409 ALREADY_EXISTS "Data API is already enabled for this
  database", and 404 NOT_FOUND "Data API is not enabled for this
  database" for get, update and delete when it is not enabled.

The acceptance tests now also print server_cors_allowed_origins, and the
update test shows that a field removed from the config keeps its value.

Co-authored-by: Isaac <no-reply@databricks.com>
GET does not return spec (it is INPUT_ONLY), so the plan could not see a
remote spec change, and a bound Data API kept its old configuration until
the bundle config changed. status reports every spec field in effect, so
DoRead now fills the remote spec from it.

The generated spec:input_only rules no longer apply, so apitypes.yml drops
the type for postgres_data_apis and the field rules are hand-written:
every spec field is a backend_default with no allowed values. A field the
config omits is left to the server: create applies the server default, and
update_mask=spec keeps the current value of an omitted field, so a field
removed from the config keeps its last value. Leaf update masks would reset
it, but resetting db_max_rows or jwt_role_claim_key that way leaves the
Data API unable to serve requests, so the mask stays at spec.

Status omits a false bool that was never set, so the remote spec forces
db_aggregates_enabled and server_timing_enabled: an explicit false in the
config compares against false, not against an unknown value.

With this, binding an existing Data API plans an update that applies the
configured spec, and an out-of-band spec change shows up in the plan.

Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
The real API reports the serving URL in status.url:
https://{read-write endpoint host}/api/2.0/workspace/{workspace_id}/rest/{postgres_database}.
The fake now fills it in GET and in the create and update operation
responses, from the branch's read-write endpoint host, the fake
workspace ID and the database's Postgres name.

The new url_reference acceptance test has a job parameter that references
${resources.postgres_data_apis.<key>.status.url} and shows it resolves on
the first deploy. It also records that an in-place update of the Data API
currently plans an update of the job too.

Co-authored-by: Isaac <no-reply@databricks.com>
status.url is built from the read-write endpoint host, the workspace and
the database's Postgres name. An update of the Data API changes none of
them, but without this the reference resolver delays any
${resources.postgres_data_apis.<key>.status.url} reference during an
in-place update, so every dependent got a no-op update planned too.

The url_reference acceptance test now shows that changing db_max_rows
plans an update of the Data API only, and the next plan is clean.

Co-authored-by: Isaac <no-reply@databricks.com>
The invariant config now also sets db_aggregates_enabled: false,
server_timing_enabled: true, jwt_cache_max_lifetime: 300s and
openapi_mode: OPEN_API_MODE_IGNORE_PRIVILEGES, so no_drift checks the
status readback for a forced false bool, a true bool, a duration and an
enum.

Every optional field is tagged CAN_REMOVE, the bools included. Removing
either bool on its own plans an update and converges: the server keeps
the last value, status reports it, and the field is a backend default.

Co-authored-by: Isaac <no-reply@databricks.com>
The resource's schema description was inherited from the embedded SDK
spec type ("Desired PostgREST configuration (input)."). Override it to
say what the resource is, that a database has at most one Data API,
where the serving URL is (status.url) and how durations are written
(300s).

Also override the postgres.OpenApiMode description, which mentioned a
value that may be added later, with what the two supported values do.

Co-authored-by: Isaac <no-reply@databricks.com>
The comment above the PostgresDataApi entry split gofmt's alignment
block, which re-indented the unrelated PostgresBranch and
PostgresCatalog lines. Make it a trailing comment, so the diff against
main is only the added entry.

Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
ruslantalpa and others added 7 commits November 5, 2026 07:03
Co-authored-by: Isaac <no-reply@databricks.com>
The Integration Tests failed on AWS for every postgres_data_apis test in the
DMS=true variant. Deployment history rejects the new resource-key prefix:

  failed to create deployment version: operations.resource_key must have a
  known resource type prefix (e.g. 'jobs.', 'pipelines.'):
  postgres_data_apis.my_data_api (400 INVALID_PARAMETER_VALUE)

The testserver's dmsResourceTypes is meant to mirror the real service, so
listing postgres_data_apis there hid the failure locally. Remove it, so the
fake rejects the prefix the same way the real service does, and exclude
DMS=true for the postgres_data_apis resource tests and the invariant config.
This matches how the features resource handles the same gap.

Co-authored-by: Isaac <no-reply@databricks.com>
Main split the refschema output per resource type and added
lifecycle.depends_on, so add output/postgres_data_apis.txt and the
lifecycle.depends_on required field for postgres_data_apis.

Co-authored-by: Isaac <no-reply@databricks.com>
Main dropped the bind-wide DMS=[""] matrix now that bind works with
deployment history, so the bind test started running with DMS=true.
Deployment history does not accept the postgres_data_apis prefix yet,
so exclude DMS=true here as the resource tests already do.

Co-authored-by: Isaac <no-reply@databricks.com>
The roles and databases used to hard-code `.../branches/production`, an
implicit dependency on the branch the project creates. Take over that branch
with `replace_existing: true` (as in postgres_branches/replace_existing) in
every Data API acceptance test and in the invariant config, and reference it
from the role and database parents.

The bind test is unchanged: its parent is a literal created by the setup
script, so there is no bundle dependency.

Co-authored-by: Isaac <no-reply@databricks.com>
The Data API create call requires at least one setting with a non-default
value, so a config with only `parent` passed `bundle validate` and then
failed at deploy. Add a validate-time check that rejects such an entry
before anything is deployed, and say in the schema description that a
setting besides `parent` is required.

The check reads the dynamic config, so a setting given as a `${...}`
reference counts as set and `lifecycle` does not. The new local-only
`parent_only` acceptance test shows the error for validate and deploy.

Co-authored-by: Isaac <no-reply@databricks.com>
Add a Badness note to the update acceptance test: removing a previously
set field plans an update, but update_mask=spec merges, so the server
keeps the last value and the next plan is clean.

Reword the status.url stable_output_fields comment: the URL is stable
only with respect to the Data API's own updates. Renaming the database's
postgres_database changes it, and a reference resolved in that same
deploy keeps the old URL until the next deploy.

Co-authored-by: Isaac <no-reply@databricks.com>
@ruslantalpa
ruslantalpa force-pushed the ruslantalpa/postgres-data-apis branch from ab7d1a8 to ed7fa4e Compare November 5, 2026 07:14
@ruslantalpa
ruslantalpa added this pull request to the merge queue Nov 5, 2026
Merged via the queue into main with commit 5c0ab45 Nov 5, 2026
29 checks passed
@ruslantalpa
ruslantalpa deleted the ruslantalpa/postgres-data-apis branch November 5, 2026 11:34
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.

4 participants