Skip to content

microsoftexpert/tf-mod-databricks-sql-warehouse

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🧱 Databricks SQL Warehouse Terraform Module

Provisions what Databricks' product UI calls a "SQL Warehouse" (serverless or classic) β€” implemented via the Terraform resource databricks_sql_endpoint, against provider databricks/databricks ~> 1.117.0. databricks_sql_warehouse does not exist in this or any provider version; see "Schema notes that bite" below before you go looking for it.

Terraform Provider Module Type Resources Posture

🧩 Overview

  • 🏷️ Wraps databricks_sql_endpoint β€” Databricks' Terraform-level name for what its product UI calls a SQL Warehouse. There is no databricks_sql_warehouse resource to find in this provider.
  • πŸ–₯️ Creates one SQL warehouse, serverless or classic, sized via cluster_size.
  • πŸ›‘ Defaults to auto_stop_mins = 10 β€” this library's house secure default, overriding the Databricks API's own more permissive default, so idle compute doesn't bill indefinitely.
  • 🏷️ Accepts cost-attribution tags as a plain map(string) (var.custom_tags) and remaps them into the resource's real nested tags { custom_tags {... } } block shape internally.
  • 🚫 Never accepts a credential, host, or account ID.
  • 🌍 Workspace-plane only β€” this resource cannot be used with an account-level provider.

πŸ’‘ Why it matters: a SQL warehouse is billed compute the moment it's running. The auto-stop default in this module is the single highest-leverage cost control a caller can leave untouched.


❀️ Support this project

If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:

Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!


πŸ—ΊοΈ Where this fits

flowchart LR
 THIS["tf-mod-databricks-sql-warehouse"]
 style THIS fill:#FF3621,color:#fff,stroke:#1B3139,stroke-width:1px

 SQLQUERY["tf-mod-databricks-sql-query"]
 style SQLQUERY fill:#1B3139,color:#fff,stroke:#1B3139,stroke-width:1px

 PERMISSIONS["tf-mod-databricks-permissions"]
 style PERMISSIONS fill:#F2F2F2,color:#1B3139,stroke:#CCCCCC,stroke-width:1px

 THIS -->|"id becomes warehouse_id"| SQLQUERY
 THIS -->|"id becomes object_id for a CAN_USE grant"| PERMISSIONS
Loading

tf-mod-databricks-sql-query is this module's nearest sibling β€” its warehouse_id input consumes this module's id output directly. tf-mod-databricks-permissions is a light-neutral sibling that can attach workspace-object ACLs (CAN_USE, CAN_MANAGE) to this warehouse by its id.

ℹ️ tf-mod-databricks-sql-query is a seeded module name in this same catalog batch and has not yet been authored as of this README β€” the end-to-end composition example in the Example Library below reflects its planned contract, not a verified cross-module terraform plan.

🧬 What this builds

flowchart TB
 subgraph INPUTS["var.*"]
 CORE["name / cluster_size"]
 SIZE["auto_stop_mins / enable_serverless_compute / enable_photon"]
 SCALE["min_num_clusters / max_num_clusters / spot_instance_policy / warehouse_type"]
 MISC["instance_profile_arn / no_wait / custom_tags / channel"]
 end

 KEYSTONE["databricks_sql_endpoint.this"]
 style KEYSTONE fill:#1B3139,color:#fff,stroke:#1B3139,stroke-width:1px

 subgraph OUTPUTS["outputs"]
 ID["id / name"]
 JDBC["jdbc_url"]
 end

 CORE --> KEYSTONE
 SIZE --> KEYSTONE
 SCALE --> KEYSTONE
 MISC --> KEYSTONE

 KEYSTONE --> ID
 KEYSTONE --> JDBC
Loading

Resource inventory: one resource, databricks_sql_endpoint.this. No child collection.

βœ… Provider / Versions

Requirement Value
Terraform >= 1.12.0
databricks/databricks ~> 1.117.0
Provider block None β€” the caller's root module configures provider "databricks" {}
tags / custom_tags Supported, but as a nested block β€” see below, not a passthrough map
timeouts Supported by this resource's schema; not exposed as a v1.0.0 variable (no caller need identified yet)

Schema notes that bite:

  • The resource is databricks_sql_endpoint, not databricks_sql_warehouse. Databricks renamed the product-facing term to "SQL Warehouse" without renaming the underlying Terraform resource β€” the resource remains databricks_sql_endpoint as of provider ~> 1.117.0. Do not add a databricks_sql_warehouse resource block; it does not exist and terraform validate will fail with an unsupported resource type error if you do.
  • tags is a nested block, not a plain map(string). The live schema models it as tags { custom_tags { key = string, value = string } } (tags itself, nesting_mode = "list", max_items = 1; custom_tags unbounded within it, both key/value required strings) β€” a genuinely different shape from databricks_job/databricks_pipeline, whose tags argument is a flat map(string). This module's var.custom_tags is a map(string) at the variable-schema level for caller ergonomics; main.tf remaps it into the nested-block shape via dynamic "tags" wrapping a dynamic "custom_tags". A caller never authors the raw block shape.
  • name and cluster_size are both schema-Required β€” there is no platform default for either; every call must supply both explicitly.
  • data_source_id, jdbc_url, odbc_params, state, health, creator_name, num_active_sessions, and num_clusters are computed-only; none are settable inputs.
  • instance_profile_arn is AWS-specific resource configuration metadata (not module authentication) β€” leave it null on Azure/GCP workspaces.

πŸ”‘ Required Databricks Permissions & Scopes

  • Workspace-level SQL warehouse creation entitlement (workspace admin, or a user/group explicitly granted warehouse-creation permission by a workspace admin). This entitlement model is not enumerated as an argument in the machine-readable schema (schema.json carries no IAM metadata) β€” flagging this as house-standard guidance grounded in Databricks' documented entitlement model, not a schema-verified fact.
  • If instance_profile_arn is set: the applying identity must be permitted to attach that AWS instance profile.

Databricks Prerequisites

  • Workspace-level provider context (not account-level) β€” databricks_sql_endpoint is a workspace-plane resource.
  • If enable_serverless_compute = true, serverless SQL compute must already be enabled for the workspace by a workspace/account admin; this module cannot enable that feature flag itself.
  • If instance_profile_arn is set, the referenced AWS instance profile must already exist and be registered with the workspace.

πŸ“ Module Structure

tf-mod-databricks-sql-warehouse/
β”œβ”€β”€ providers.tf # required_providers only β€” no provider {} block
β”œβ”€β”€ variables.tf # name, cluster_size (both required), auto_stop_mins (default 10),...
β”œβ”€β”€ main.tf # databricks_sql_endpoint.this
β”œβ”€β”€ outputs.tf # id first, then name, then jdbc_url
β”œβ”€β”€ SCOPE.md # cross-module contract
β”œβ”€β”€ README.md # this file
└── examples/
 └── basic/
 └── main.tf # smallest real, runnable call

βš™οΈ Quick Start

module "adhoc_warehouse" {
  source = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-warehouse.git?ref=v1.0.0"

  name                      = "analytics-adhoc"
  cluster_size              = "2X-Small"
  enable_serverless_compute = true
  # auto_stop_mins left at the module's secure default (10 minutes)
}

The caller's root module configures provider "databricks" {} (host + auth) and passes it in implicitly, or explicitly via a providers = {} map β€” this module accepts neither.

πŸ”Œ Cross-Module Contract

Consumes: none β€” this is a standalone module with no cross-module inputs beyond optional resource-metadata fields (instance_profile_arn) that reference externally-managed AWS objects, not another module's output.

Emits:

Output Description Consumed by
id ID of the databricks_sql_endpoint resource tf-mod-databricks-sql-query (warehouse_id input), tf-mod-databricks-permissions (object ID for a grant)
name Display name of the warehouse Auditing / drift-detection tooling
jdbc_url JDBC connection URL (non-sensitive β€” a connection endpoint, not a credential) BI tool / client connection configuration

πŸ“š Example Library

1 Β· Minimal serverless warehouse (secure default left in place)
module "adhoc_warehouse" {
  source = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-warehouse.git?ref=v1.0.0"

  name                      = "analytics-adhoc"
  cluster_size              = "2X-Small"
  enable_serverless_compute = true
}

πŸ’‘ auto_stop_mins is omitted here, so it takes the module's house default of 10 β€” not the Databricks API's own more permissive default.

2 Β· Always-on warehouse (auto-stop disabled)
module "always_on_warehouse" {
  source = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-warehouse.git?ref=v1.0.0"

  name           = "bi-dashboards-prod"
  cluster_size   = "Medium"
  auto_stop_mins = 0
}

⚠️ auto_stop_mins = 0 leaves this warehouse's compute running indefinitely and billing continuously. Only set this for a warehouse serving latency-sensitive production BI traffic where cold-start time is unacceptable, and treat it as a deliberate, reviewed cost decision.

3 Β· Classic (non-serverless) cluster-size example
module "classic_warehouse" {
  source = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-warehouse.git?ref=v1.0.0"

  name                      = "legacy-classic"
  cluster_size              = "Small"
  enable_serverless_compute = false
  warehouse_type            = "CLASSIC"
}
4 Β· Min/max multi-cluster autoscaling
module "concurrent_bi_warehouse" {
  source = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-warehouse.git?ref=v1.0.0"

  name             = "bi-concurrent"
  cluster_size     = "Large"
  min_num_clusters = 1
  max_num_clusters = 4
}

ℹ️ Multi-cluster autoscaling lets the warehouse add clusters under concurrent query load rather than queueing β€” relevant mainly for classic compute; serverless scales differently under the hood.

5 Β· Photon-enabled warehouse
module "photon_warehouse" {
  source = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-warehouse.git?ref=v1.0.0"

  name          = "analytics-photon"
  cluster_size  = "Medium"
  enable_photon = true
}
6 Β· Spot-instance cost-optimized policy (classic compute)
module "cost_optimized_warehouse" {
  source = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-warehouse.git?ref=v1.0.0"

  name                      = "batch-sql-cost-optimized"
  cluster_size              = "Small"
  enable_serverless_compute = false
  spot_instance_policy      = "COST_OPTIMIZED"
}

ℹ️ spot_instance_policy only affects classic (non-serverless) compute β€” Databricks manages serverless compute's underlying infrastructure directly.

7 Β· Reliability-optimized spot policy
module "reliability_warehouse" {
  source = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-warehouse.git?ref=v1.0.0"

  name                      = "prod-sql-reliable"
  cluster_size              = "Large"
  enable_serverless_compute = false
  spot_instance_policy      = "RELIABILITY_OPTIMIZED"
}
8 Β· Release channel pinned to PREVIEW
module "preview_channel_warehouse" {
  source = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-warehouse.git?ref=v1.0.0"

  name         = "dbsql-preview-testing"
  cluster_size = "X-Small"

  channel = {
    name = "CHANNEL_NAME_PREVIEW"
  }
}

ℹ️ Use the PREVIEW channel only in a non-production warehouse used to validate upcoming DBSQL runtime changes before they reach CURRENT.

9 Β· Custom tags for cost attribution
module "tagged_warehouse" {
  source = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-warehouse.git?ref=v1.0.0"

  name         = "finance-reporting"
  cluster_size = "Small"

  custom_tags = {
    cost_center = "finance"
    environment = "prod"
    owner       = "data-platform-team"
  }
}

πŸ’‘ var.custom_tags is a plain map here β€” this module remaps it into the resource's real tags { custom_tags { key, value } } nested-block shape internally. See "Schema notes that bite."

10 Β· AWS instance-profile-attached warehouse
module "s3_access_warehouse" {
  source = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-warehouse.git?ref=v1.0.0"

  name                      = "s3-external-tables"
  cluster_size              = "Medium"
  enable_serverless_compute = false
  instance_profile_arn      = "arn:aws:iam::123456789012:instance-profile/databricks-sql-s3-reader"
}

ℹ️ AWS-only. Leave instance_profile_arn null on Azure/GCP workspaces.

11 Β· no_wait for faster apply cycles
module "fast_apply_warehouse" {
  source = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-warehouse.git?ref=v1.0.0"

  name         = "dev-sandbox"
  cluster_size = "2X-Small"
  no_wait      = true
}

ℹ️ no_wait = true returns control to Terraform once the API call is accepted, without waiting for the warehouse to reach a running state β€” useful in fast dev-loop applies, less useful when a caller needs the warehouse actually running before the next resource applies.

12 Β· Minimal least-privilege, lowest-cost baseline (recommended starting point)
module "baseline_warehouse" {
  source = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-warehouse.git?ref=v1.0.0"

  name         = "baseline-adhoc"
  cluster_size = "2X-Small"
  # auto_stop_mins left at the secure default: 10
}
13 Β· Multiple team warehouses via for_each at the caller level
locals {
  team_warehouses = {
    finance = "2X-Small"
    ml      = "Small"
    bi      = "Medium"
  }
}

module "team_warehouses" {
  for_each = local.team_warehouses
  source   = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-warehouse.git?ref=v1.0.0"

  name                      = "${each.key}-adhoc"
  cluster_size              = each.value
  enable_serverless_compute = true
}

ℹ️ for_each is applied at the caller's root-module level β€” this module itself has no child collection to iterate; each instance creates exactly one warehouse.

πŸ—οΈ 14 Β· End-to-end composition β€” warehouse β†’ query
module "analytics_warehouse" {
  source = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-warehouse.git?ref=v1.0.0"

  name                      = "analytics-adhoc"
  cluster_size              = "Small"
  enable_serverless_compute = true
}

module "daily_active_users_query" {
  source = "git::https://github.com/microsoftexpert/tf-mod-databricks-sql-query.git?ref=v1.0.0"

  display_name = "Daily Active Users"
  warehouse_id = module.analytics_warehouse.id
  query_text   = "SELECT event_date, COUNT(DISTINCT user_id) AS dau FROM analytics.events GROUP BY event_date"
}

ℹ️ tf-mod-databricks-sql-query has not yet been authored as of this README β€” this composition reflects its planned contract (per this library's catalog and recommended authoring order), not yet a verified cross-module terraform plan.

πŸ“₯ Inputs

Variable Type Default Notes
name string β€” (required)
cluster_size string β€” (required) Closed T-shirt-size enum
auto_stop_mins number 10 Secure default; 0 = always-on, ⚠️ cost risk
enable_serverless_compute bool null Requires workspace serverless entitlement
enable_photon bool null
min_num_clusters number null
max_num_clusters number null
spot_instance_policy string null COST_OPTIMIZED | RELIABILITY_OPTIMIZED
warehouse_type string null PRO | CLASSIC
instance_profile_arn string null AWS-only
no_wait bool null
custom_tags map(string) {} Remapped into nested tags { custom_tags {... } }
channel object({ name, dbsql_version }) null Both fields optional strings
Full variable declarations
variable "name" {
  type = string
}

variable "cluster_size" {
  type = string
  # validation: one of 2X-Small, X-Small, Small, Medium, Large, X-Large, 2X-Large, 3X-Large, 4X-Large
}

variable "auto_stop_mins" {
  type    = number
  default = 10
  # validation: >= 0
}

variable "enable_serverless_compute" {
  type    = bool
  default = null
}

variable "enable_photon" {
  type    = bool
  default = null
}

variable "min_num_clusters" {
  type    = number
  default = null
}

variable "max_num_clusters" {
  type    = number
  default = null
}

variable "spot_instance_policy" {
  type    = string
  default = null
  # validation: COST_OPTIMIZED | RELIABILITY_OPTIMIZED
}

variable "warehouse_type" {
  type    = string
  default = null
  # validation: PRO | CLASSIC
}

variable "instance_profile_arn" {
  type    = string
  default = null
}

variable "no_wait" {
  type    = bool
  default = null
}

variable "custom_tags" {
  type    = map(string)
  default = {}
}

variable "channel" {
  type = object({
    name          = optional(string)
    dbsql_version = optional(string)
  })
  default = null
}

🧾 Outputs

Output Description Sensitive?
id ID of the databricks_sql_endpoint resource No
name Display name of the warehouse No
jdbc_url JDBC connection URL β€” a connection endpoint, not a credential No

🧠 Architecture Notes

  • Naming discrepancy, restated for a reader who lands here first: this module's folder/product name is "sql-warehouse," but its keystone resource is databricks_sql_endpoint β€” databricks_sql_warehouse has never existed under that name in this provider. Every .tf file's comments and this README's tagline, Overview, "Schema notes that bite," and Troubleshooting all say this explicitly so a reader searching the registry for "sql_warehouse" isn't left confused.
  • tags is a nested block, remapped from a plain map. main.tf renders var.custom_tags (a map(string)) through a dynamic "tags" block wrapping a dynamic "custom_tags" block, so the keystone resource receives the tags { custom_tags { key, value } } shape the schema actually requires. A caller only ever writes an ordinary map literal.
  • auto_stop_mins = 10 is a house override, not a schema default. The Databricks API itself does not require a caller to set this at all (it is Optional in the schema); this module defaults it to 10 per this library's secure-by-default convention so a caller must type extra characters (auto_stop_mins = 0 or a higher value) to accept more cost exposure, rather than accidentally inheriting a more permissive platform default.
  • enable_serverless_compute/spot_instance_policy interaction is not enforced via validation {}. spot_instance_policy is only meaningful for classic (non-serverless) compute, but this module does not hard-fail a caller who sets both, consistent with the precedent set by tf-mod-databricks-cluster's autoscale/num_workers judgment call β€” over-constraining two fields whose real-world interaction depends on workspace entitlements risks rejecting a legitimate configuration.
  • No for_each, no child resources. Example breadth in this README comes from configuration variants (serverless vs. classic, autoscaling, channel, tags) and caller-level for_each, not from anything internal to this module.

🧱 Design Principles

Concern Secure default Opt-out (caller must set explicitly)
SQL warehouse auto-stop auto_stop_mins = 10 Caller sets a higher value or 0 (always-on) explicitly β€” this README's Example 2 carries the mandatory ⚠️ cost callout

This matches this library's secure-by-default convention for "SQL warehouse auto-stop" exactly. No other argument on this resource carries a house-mandated secure default in v1.0.0 β€” every other optional field defaults to null (accept the platform's own default) rather than an invented override, consistent with this library's rule against inventing defaults it doesn't otherwise specify.

πŸš€ Runbook

cd tf-mod-databricks-sql-warehouse
terraform init -backend=false
terraform validate
terraform fmt -check

Pin consumers to an immutable tag β€” ?ref=v1.0.0 β€” never a branch. This module is plan-only; a human applies from CI after review.

πŸ§ͺ Testing

terraform validate / terraform fmt -check catch: missing name/cluster_size, the cluster_size/spot_instance_policy/warehouse_type enum validations, malformed HCL, and β€” most importantly for this module β€” an accidental databricks_sql_warehouse resource block (unsupported resource type). They do not catch: whether the applying identity actually holds SQL warehouse creation entitlement, whether serverless SQL compute is actually enabled for the target workspace, whether a referenced instance_profile_arn actually exists and is attachable, or any other real Databricks API-side constraint. Those require an actual plan/apply against a live workspace, out of scope for this authoring process.

πŸ’¬ Example Output

$ terraform output
id = "abcdef1234567890"
jdbc_url = "jdbc:databricks://adb-1234567890123456.7.azuredatabricks.net:443/default;transportMode=http;ssl=1;httpPath=/sql/1.0/warehouses/abcdef1234567890;AuthMech=3"
name = "analytics-adhoc"

πŸ” Troubleshooting

Symptom Cause Fix
terraform validate fails with Unsupported resource type: databricks_sql_warehouse The resource was never renamed from databricks_sql_endpoint despite the product UI calling this a SQL Warehouse Use databricks_sql_endpoint; this module already does
Apply fails with a permissions error even though terraform validate passed Applying identity lacks SQL warehouse creation entitlement in the target workspace Confirm the identity holds the required workspace-level entitlement
enable_serverless_compute = true fails at apply time Serverless SQL compute is not enabled for the workspace Have a workspace/account admin enable serverless SQL compute, or set enable_serverless_compute = false
Apply fails referencing an invalid instance_profile_arn The instance profile does not exist or is not registered with the workspace Confirm the ARN and its registration with a workspace admin before reapplying
terraform plan shows an unexpected diff on every run for custom_tags A caller wrote the raw tags { custom_tags {... } } block shape directly against a fork of this module instead of using var.custom_tags Use var.custom_tags as documented; let main.tf's dynamic blocks render the nested shape
Warehouse never stops even though cost review expected it to auto_stop_mins was explicitly set to 0 (or a very high value) Confirm this was a deliberate, reviewed choice; otherwise reset to the secure default or an appropriate finite value

πŸ”— Related Docs

  • databricks_sql_endpoint provider resource β€” note the URL slug is sql_endpoint, not sql_warehouse, consistent with the naming discrepancy explained throughout this README.
  • tf-mod-databricks-sql-query (downstream, consumes this module's id as warehouse_id)
  • tf-mod-databricks-permissions (attaches workspace-object ACLs to this warehouse by id)
  • This module's SCOPE.md

πŸ’™ "Infrastructure as Code should be standardized, consistent, and secure."

Packages

 
 
 

Contributors

Languages