Skip to content

Commit 07e3362

Browse files
authored
Add support for Lakebase database instances (#3283)
## Changes <!-- Brief summary of your changes that is easy to understand --> Added support for creating Lakebase database instances in DABs ## Why <!-- Why are these changes needed? Provide the context that the reviewer might be missing. For example, were there any decisions behind the change that are not reflected in the code itself? --> This change allows users to define database instances as part of their assets bundle: ``` ... resources: ... database_instances: my_database_instance: name: my_database_instance capacity: CU_1 ``` ## Tests <!-- How have you tested the changes? --> Added acceptance tests for database instances deployments <!-- If your PR needs to be included in the release notes for next release, add a separate entry in NEXT_CHANGELOG.md as part of your PR. -->
1 parent 09a8f0c commit 07e3362

File tree

25 files changed

+922
-17
lines changed

25 files changed

+922
-17
lines changed

NEXT_CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@
99
### CLI
1010

1111
### Bundles
12+
* Add support for Lakebase database instances in DABs ([#3283](https://github.com/databricks/cli/pull/3283))
1213

1314
### API Changes
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
bundle:
2+
name: deploy-lakebase-single-instance-$UNIQUE_NAME
3+
4+
resources:
5+
database_instances:
6+
my_database:
7+
name: test-database-instance-$UNIQUE_NAME
8+
capacity: CU_1
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Local = true
2+
Cloud = true
3+
RequiresUnityCatalog = true
4+
5+
[CloudEnvs]
6+
gcp = false
7+
8+
[EnvMatrix]
9+
DATABRICKS_CLI_DEPLOYMENT = ["terraform", "direct-exp"]
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
2+
>>> [CLI] bundle validate
3+
Name: deploy-lakebase-single-instance-[UNIQUE_NAME]
4+
Target: default
5+
Workspace:
6+
User: [USERNAME]
7+
Path: /Workspace/Users/[USERNAME]/.bundle/deploy-lakebase-single-instance-[UNIQUE_NAME]/default
8+
9+
Validation OK!
10+
11+
>>> [CLI] bundle summary
12+
Name: deploy-lakebase-single-instance-[UNIQUE_NAME]
13+
Target: default
14+
Workspace:
15+
User: [USERNAME]
16+
Path: /Workspace/Users/[USERNAME]/.bundle/deploy-lakebase-single-instance-[UNIQUE_NAME]/default
17+
Resources:
18+
Database instances:
19+
my_database:
20+
Name: test-database-instance-[UNIQUE_NAME]
21+
URL: (not deployed)
22+
23+
>>> [CLI] bundle deploy
24+
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/deploy-lakebase-single-instance-[UNIQUE_NAME]/default/files...
25+
Deploying resources...
26+
Updating deployment state...
27+
Deployment complete!
28+
29+
>>> [CLI] database get-database-instance test-database-instance-[UNIQUE_NAME]
30+
{
31+
"capacity": "CU_1",
32+
"creation_time": "[TIMESTAMP]Z",
33+
"creator": "[USERNAME]",
34+
"effective_enable_readable_secondaries": false,
35+
"effective_node_count": 1,
36+
"effective_retention_window_in_days": 7,
37+
"effective_stopped": false,
38+
"name": "test-database-instance-[UNIQUE_NAME]",
39+
"pg_version": "PG_VERSION_16",
40+
"state": "AVAILABLE",
41+
"uid": "[UUID]"
42+
}
43+
44+
>>> [CLI] bundle summary
45+
Name: deploy-lakebase-single-instance-[UNIQUE_NAME]
46+
Target: default
47+
Workspace:
48+
User: [USERNAME]
49+
Path: /Workspace/Users/[USERNAME]/.bundle/deploy-lakebase-single-instance-[UNIQUE_NAME]/default
50+
Resources:
51+
Database instances:
52+
my_database:
53+
Name: test-database-instance-[UNIQUE_NAME]
54+
URL: [DATABRICKS_URL]/compute/database-instances/test-database-instance-[UNIQUE_NAME]
55+
56+
>>> [CLI] bundle destroy --auto-approve
57+
The following resources will be deleted:
58+
delete database_instance my_database
59+
60+
All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/deploy-lakebase-single-instance-[UNIQUE_NAME]/default
61+
62+
Deleting files...
63+
Destroy complete!
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
envsubst < databricks.yml.tmpl > databricks.yml
2+
3+
cleanup() {
4+
trace $CLI bundle destroy --auto-approve
5+
}
6+
trap cleanup EXIT
7+
8+
trace $CLI bundle validate
9+
10+
trace $CLI bundle summary
11+
12+
trace $CLI bundle deploy
13+
14+
# Poll for database instance to become available (max 10 attempts, 5s between attempts)
15+
for i in {1..10}; do
16+
state=$($CLI database get-database-instance "test-database-instance-${UNIQUE_NAME}" --output json 2>/dev/null | jq -r '.state')
17+
if [ "$state" = "AVAILABLE" ]; then
18+
break
19+
fi
20+
if [ $i -eq 30 ]; then
21+
echo "Database instance did not become AVAILABLE. Last polled state: ${state}"
22+
exit 1
23+
fi
24+
sleep 5
25+
done
26+
27+
# _dns fields are excluded since they differ between cloud envs
28+
trace $CLI database get-database-instance "test-database-instance-${UNIQUE_NAME}" | jq 'del(.read_only_dns, .read_write_dns)'
29+
30+
trace $CLI bundle summary
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Local = true
2+
Cloud = true
3+
4+
RecordRequests = false
5+
RequiresUnityCatalog = true
6+
CloudEnvs.gcp = false # lakebase is not available in GCP as of August 2025
7+
8+
Ignore = [
9+
"databricks.yml",
10+
]
11+
12+
[[Repls]]
13+
# clean up ?o=<num> suffix after URL since not all workspaces have that
14+
Old = '\?o=\[(NUMID|ALPHANUMID)\]'
15+
New = ''
16+
Order = 1000

acceptance/internal/handlers.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"strconv"
99

1010
"github.com/databricks/databricks-sdk-go/service/catalog"
11-
1211
"github.com/databricks/databricks-sdk-go/service/compute"
1312
"github.com/databricks/databricks-sdk-go/service/jobs"
1413

@@ -499,4 +498,20 @@ func addDefaultHandlers(server *testserver.Server) {
499498
}
500499
return testserver.Response{StatusCode: 404}
501500
})
501+
502+
server.Handle("POST", "/api/2.0/database/instances", func(req testserver.Request) any {
503+
return req.Workspace.DatabaseInstanceCreate(req)
504+
})
505+
506+
server.Handle("GET", "/api/2.0/database/instances/", func(req testserver.Request) any {
507+
return testserver.MapList(req.Workspace, req.Workspace.DatabaseInstances, "database_instances")
508+
})
509+
510+
server.Handle("GET", "/api/2.0/database/instances/{name}", func(req testserver.Request) any {
511+
return testserver.DatabaseInstanceMapGet(req.Workspace, req.Workspace.DatabaseInstances, req.Vars["name"])
512+
})
513+
514+
server.Handle("DELETE", "/api/2.0/database/instances/{name}", func(req testserver.Request) any {
515+
return testserver.DatabaseInstanceMapDelete(req)
516+
})
502517
}

bundle/config/mutator/resourcemutator/apply_bundle_permissions.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ var (
6060
permissions.CAN_VIEW: "CAN_VIEW",
6161
permissions.CAN_RUN: "CAN_MONITOR",
6262
},
63+
"database_instances": {
64+
permissions.CAN_MANAGE: "CAN_MANAGE",
65+
permissions.CAN_VIEW: "CAN_USE",
66+
},
6367
}
6468
)
6569

bundle/config/mutator/resourcemutator/apply_target_mode_test.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"slices"
77
"testing"
88

9+
"github.com/databricks/databricks-sdk-go/service/database"
10+
911
"github.com/databricks/cli/bundle"
1012
"github.com/databricks/cli/bundle/config"
1113
"github.com/databricks/cli/bundle/config/resources"
@@ -167,6 +169,13 @@ func mockBundle(mode config.Mode) *bundle.Bundle {
167169
},
168170
},
169171
},
172+
DatabaseInstances: map[string]*resources.DatabaseInstance{
173+
"database_instance1": {
174+
DatabaseInstance: database.DatabaseInstance{
175+
Name: "database_instance1",
176+
},
177+
},
178+
},
170179
},
171180
},
172181
SyncRoot: vfs.MustNew("/Users/[email protected]"),
@@ -335,7 +344,7 @@ func TestAllNonUcResourcesAreRenamed(t *testing.T) {
335344
resourceType := resources.Type().Field(i).Name
336345

337346
// Skip resources that are not renamed
338-
if resourceType == "Apps" || resourceType == "SecretScopes" {
347+
if resourceType == "Apps" || resourceType == "SecretScopes" || resourceType == "DatabaseInstances" {
339348
continue
340349
}
341350

bundle/config/mutator/resourcemutator/run_as_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func allResourceTypes(t *testing.T) []string {
3535
"apps",
3636
"clusters",
3737
"dashboards",
38+
"database_instances",
3839
"experiments",
3940
"jobs",
4041
"model_serving_endpoints",
@@ -139,6 +140,7 @@ func TestRunAsWorksForAllowedResources(t *testing.T) {
139140
// they are not on the allow list below.
140141
var allowList = []string{
141142
"clusters",
143+
"database_instances",
142144
"jobs",
143145
"models",
144146
"registered_models",

0 commit comments

Comments
 (0)