diff --git a/.gitignore b/.gitignore index a248d4ca..8d8384b8 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,8 @@ # Ignored vscode files .vscode/ -.idea/ \ No newline at end of file +.idea/ + +# Claude Code +.claude/ +CLAUDE.md \ No newline at end of file diff --git a/examples/gcp-with-psc-exfiltration-protection/terraform.tf b/examples/gcp-with-psc-exfiltration-protection/terraform.tf index 791cc0c9..6d4a5f43 100644 --- a/examples/gcp-with-psc-exfiltration-protection/terraform.tf +++ b/examples/gcp-with-psc-exfiltration-protection/terraform.tf @@ -1,12 +1,12 @@ terraform { + required_version = ">= 1.9.0" + required_providers { databricks = { - source = "databricks/databricks" - version = ">=1.81.1" + source = "databricks/databricks" } google = { - source = "hashicorp/google" - version = "6.17.0" + source = "hashicorp/google" } random = { source = "hashicorp/random" diff --git a/examples/gcp-with-psc-exfiltration-protection/variables.tf b/examples/gcp-with-psc-exfiltration-protection/variables.tf index 15365ccf..9fdc89e6 100644 --- a/examples/gcp-with-psc-exfiltration-protection/variables.tf +++ b/examples/gcp-with-psc-exfiltration-protection/variables.tf @@ -1,13 +1,33 @@ +# Account variable "databricks_account_id" { type = string description = "Databricks Account ID" + + validation { + condition = can(regex("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", var.databricks_account_id)) + error_message = "databricks_account_id must be a valid UUID (e.g., 12345678-1234-1234-1234-123456789012)." + } } +# Region variable "google_region" { type = string description = "Google Cloud region where the resources will be created" + + validation { + condition = contains([ + "asia-northeast1", "asia-south1", "asia-southeast1", + "australia-southeast1", + "europe-west1", "europe-west2", "europe-west3", + "northamerica-northeast1", + "southamerica-east1", + "us-central1", "us-east1", "us-east4", "us-west1", "us-west4" + ], var.google_region) + error_message = "google_region must be a GCP region that supports Databricks PSC endpoints." + } } +# Projects variable "workspace_google_project" { type = string description = "Google Cloud project ID related to Databricks workspace" @@ -23,45 +43,73 @@ variable "hub_vpc_google_project" { description = "Google Cloud project ID related to Hub VPC" } +# Network variable "is_spoke_vpc_shared" { type = bool description = "Whether the Spoke VPC is a Shared or a dedicated VPC" } -variable "prefix" { +variable "hub_vpc_cidr" { type = string - description = "Prefix to use in generated resources name" + description = "CIDR for Hub VPC" + + validation { + condition = can(cidrhost(var.hub_vpc_cidr, 0)) + error_message = "hub_vpc_cidr must be a valid CIDR block (e.g., 10.0.0.0/24)." + } } -# For the value of the regional Hive Metastore IP, refer to the Databricks documentation -# Here - https://docs.gcp.databricks.com/en/resources/ip-domain-region.html#addresses-for-default-metastore -variable "hive_metastore_ip" { +variable "spoke_vpc_cidr" { type = string - description = "Value of regional default Hive Metastore IP" + description = "CIDR for Spoke VPC" + + validation { + condition = can(cidrhost(var.spoke_vpc_cidr, 0)) + error_message = "spoke_vpc_cidr must be a valid CIDR block (e.g., 10.1.0.0/24)." + } } -variable "hub_vpc_cidr" { +variable "psc_subnet_cidr" { type = string - description = "CIDR for Hub VPC" + description = "CIDR for PSC subnet within the Spoke VPC" + + validation { + condition = can(cidrhost(var.psc_subnet_cidr, 0)) + error_message = "psc_subnet_cidr must be a valid CIDR block (e.g., 10.1.1.0/24)." + } } -variable "spoke_vpc_cidr" { +# Naming +variable "prefix" { type = string - description = "CIDR for Spoke VPC" + description = "Prefix to use in generated resource names" + + validation { + condition = can(regex("^[a-z][a-z0-9-]{1,20}$", var.prefix)) + error_message = "prefix must start with a lowercase letter, contain only lowercase letters, numbers, and hyphens, and be 2-21 characters long." + } } -variable "psc_subnet_cidr" { +# For the value of the regional Hive Metastore IP, refer to the Databricks documentation +# Here - https://docs.gcp.databricks.com/en/resources/ip-domain-region.html#addresses-for-default-metastore +variable "hive_metastore_ip" { type = string - description = "CIDR for Spoke VPC" + description = "IP address of the regional default Hive Metastore" + + validation { + condition = can(regex("^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$", var.hive_metastore_ip)) + error_message = "hive_metastore_ip must be a valid IPv4 address." + } } +# Tags variable "tags" { type = map(string) description = "Map of tags to add to all resources" - - default = {} + default = {} } +# Unity Catalog variable "metastore_name" { type = string description = "Name to assign to regional metastore" @@ -70,4 +118,4 @@ variable "metastore_name" { variable "catalog_name" { type = string description = "Name to assign to default catalog" -} \ No newline at end of file +} diff --git a/modules/gcp-with-psc-exfiltration-protection/outputs.tf b/modules/gcp-with-psc-exfiltration-protection/outputs.tf index 27983846..7d504577 100644 --- a/modules/gcp-with-psc-exfiltration-protection/outputs.tf +++ b/modules/gcp-with-psc-exfiltration-protection/outputs.tf @@ -1,10 +1,52 @@ - +# Workspace output "workspace_url" { - value = databricks_mws_workspaces.databricks_workspace.workspace_url description = "The workspace URL which is of the format '{workspaceId}.{random}.gcp.databricks.com'" + value = databricks_mws_workspaces.databricks_workspace.workspace_url } output "workspace_id" { description = "The Databricks workspace ID" value = databricks_mws_workspaces.databricks_workspace.workspace_id -} \ No newline at end of file +} + +# Network +output "spoke_vpc_id" { + description = "The ID of the Spoke VPC network" + value = google_compute_network.spoke_vpc.id +} + +output "hub_vpc_id" { + description = "The ID of the Hub VPC network" + value = google_compute_network.hub_vpc.id +} + +output "spoke_subnetwork_id" { + description = "The ID of the primary Spoke subnet" + value = google_compute_subnetwork.spoke_subnetwork.id +} + +output "psc_subnetwork_id" { + description = "The ID of the PSC subnet within the Spoke VPC" + value = google_compute_subnetwork.psc_subnetwork.id +} + +output "network_id" { + description = "The Databricks MWS network configuration ID" + value = databricks_mws_networks.databricks_network.network_id +} + +# PSC Endpoints +output "backend_psc_endpoint_ip" { + description = "The IP address of the backend (SCC) PSC endpoint" + value = google_compute_address.backend_pe_ip_address.address +} + +output "spoke_frontend_psc_endpoint_ip" { + description = "The IP address of the workspace frontend PSC endpoint in the Spoke VPC" + value = google_compute_address.spoke_frontend_pe_ip_address.address +} + +output "hub_frontend_psc_endpoint_ip" { + description = "The IP address of the workspace frontend PSC endpoint in the Hub VPC" + value = google_compute_address.hub_frontend_pe_ip_address.address +} diff --git a/modules/gcp-with-psc-exfiltration-protection/terraform.tf b/modules/gcp-with-psc-exfiltration-protection/terraform.tf index 688f0fbd..6d4a5f43 100644 --- a/modules/gcp-with-psc-exfiltration-protection/terraform.tf +++ b/modules/gcp-with-psc-exfiltration-protection/terraform.tf @@ -1,4 +1,6 @@ terraform { + required_version = ">= 1.9.0" + required_providers { databricks = { source = "databricks/databricks" diff --git a/modules/gcp-with-psc-exfiltration-protection/variables.tf b/modules/gcp-with-psc-exfiltration-protection/variables.tf index cd96e520..40bc3b36 100644 --- a/modules/gcp-with-psc-exfiltration-protection/variables.tf +++ b/modules/gcp-with-psc-exfiltration-protection/variables.tf @@ -1,13 +1,33 @@ +# Account variable "databricks_account_id" { type = string description = "Databricks Account ID" + + validation { + condition = can(regex("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", var.databricks_account_id)) + error_message = "databricks_account_id must be a valid UUID (e.g., 12345678-1234-1234-1234-123456789012)." + } } +# Region variable "google_region" { type = string description = "Google Cloud region where the resources will be created" + + validation { + condition = contains([ + "asia-northeast1", "asia-south1", "asia-southeast1", + "australia-southeast1", + "europe-west1", "europe-west2", "europe-west3", + "northamerica-northeast1", + "southamerica-east1", + "us-central1", "us-east1", "us-east4", "us-west1", "us-west4" + ], var.google_region) + error_message = "google_region must be a GCP region that supports Databricks PSC endpoints." + } } +# Projects variable "workspace_google_project" { type = string description = "Google Cloud project ID related to Databricks workspace" @@ -23,40 +43,67 @@ variable "hub_vpc_google_project" { description = "Google Cloud project ID related to Hub VPC" } +# Network variable "is_spoke_vpc_shared" { type = bool description = "Whether the Spoke VPC is a Shared or a dedicated VPC" } -variable "prefix" { +variable "hub_vpc_cidr" { type = string - description = "Prefix to use in generated resources name" + description = "CIDR for Hub VPC" + + validation { + condition = can(cidrhost(var.hub_vpc_cidr, 0)) + error_message = "hub_vpc_cidr must be a valid CIDR block (e.g., 10.0.0.0/24)." + } } -# For the value of the regional Hive Metastore IP, refer to the Databricks documentation -# Here - https://docs.gcp.databricks.com/en/resources/ip-domain-region.html#addresses-for-default-metastore -variable "hive_metastore_ip" { +variable "spoke_vpc_cidr" { type = string - description = "Value of regional default Hive Metastore IP" + description = "CIDR for Spoke VPC" + + validation { + condition = can(cidrhost(var.spoke_vpc_cidr, 0)) + error_message = "spoke_vpc_cidr must be a valid CIDR block (e.g., 10.1.0.0/24)." + } } -variable "hub_vpc_cidr" { +variable "psc_subnet_cidr" { type = string - description = "CIDR for Hub VPC" + description = "CIDR for PSC subnet within the Spoke VPC" + + validation { + condition = can(cidrhost(var.psc_subnet_cidr, 0)) + error_message = "psc_subnet_cidr must be a valid CIDR block (e.g., 10.1.1.0/24)." + } } -variable "spoke_vpc_cidr" { +# Naming +variable "prefix" { type = string - description = "CIDR for Spoke VPC" + description = "Prefix to use in generated resource names" + + validation { + condition = can(regex("^[a-z][a-z0-9-]{1,20}$", var.prefix)) + error_message = "prefix must start with a lowercase letter, contain only lowercase letters, numbers, and hyphens, and be 2-21 characters long." + } } -variable "psc_subnet_cidr" { +# For the value of the regional Hive Metastore IP, refer to the Databricks documentation +# Here - https://docs.gcp.databricks.com/en/resources/ip-domain-region.html#addresses-for-default-metastore +variable "hive_metastore_ip" { type = string - description = "CIDR for Spoke VPC" + description = "IP address of the regional default Hive Metastore" + + validation { + condition = can(regex("^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$", var.hive_metastore_ip)) + error_message = "hive_metastore_ip must be a valid IPv4 address." + } } +# Tags variable "tags" { - description = "Map of tags to add to all resources" type = map(string) + description = "Map of tags to add to all resources" } -