From bb583e3ccbc08a1a65afd3ca53c7429fd23bcd4e Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Sat, 25 Apr 2026 22:50:22 -0500 Subject: [PATCH] Fix HCL syntax errors in accounts and api Cloud Run definitions --- servers/gcp/cloud-run-accounts.tf | 207 +++++++++++++++++++++++------- servers/gcp/cloud-run-api.tf | 162 +++++++++++++++++------ 2 files changed, 282 insertions(+), 87 deletions(-) diff --git a/servers/gcp/cloud-run-accounts.tf b/servers/gcp/cloud-run-accounts.tf index b15dc45..257a8f7 100644 --- a/servers/gcp/cloud-run-accounts.tf +++ b/servers/gcp/cloud-run-accounts.tf @@ -1,9 +1,7 @@ # ── Accounts Service — Cloud Run ────────────────────────────────────────────── # Handles auth, billing, subscriptions, marketplace. # Connects to Cloud SQL via built-in Auth Proxy (Unix socket volume mount). -# Deployed in 3 regions for global latency; all regions share the same -# Cloud SQL instance (us-central1). Auth lookups are fast — cross-region -# latency acceptable until read replicas are warranted. +# All three regions share the same Cloud SQL instance (us-central1). locals { accounts_labels = { @@ -38,7 +36,7 @@ resource "google_cloud_run_v2_service" "accounts_us" { cpu = "1" memory = "512Mi" } - cpu_idle = true # accounts is bursty; don't pay for idle CPU + cpu_idle = true } env { @@ -50,7 +48,6 @@ resource "google_cloud_run_v2_service" "accounts_us" { value = "8080" } - # Database URL via Secret Manager (uses /cloudsql/ socket path) env { name = "ACCOUNTS_DATABASE_URL" value_source { @@ -60,8 +57,6 @@ resource "google_cloud_run_v2_service" "accounts_us" { } } } - - # JWT signing key (shared with API service) env { name = "JWT_SECRET" value_source { @@ -71,8 +66,6 @@ resource "google_cloud_run_v2_service" "accounts_us" { } } } - - # Stripe secrets (accounts handles purchase webhooks + subscription management) env { name = "STRIPE_SECRET_KEY" value_source { @@ -136,7 +129,6 @@ resource "google_cloud_run_v2_service" "accounts_us" { failure_threshold = 3 } - # Cloud SQL Auth Proxy socket mount volume_mounts { name = "cloudsql" mount_path = "/cloudsql" @@ -192,55 +184,114 @@ resource "google_cloud_run_v2_service" "accounts_eu" { cpu_idle = true } - env { name = "ENV"; value = "production" } - env { name = "PORT"; value = "8080" } + env { + name = "ENV" + value = "production" + } + env { + name = "PORT" + value = "8080" + } env { name = "ACCOUNTS_DATABASE_URL" - value_source { secret_key_ref { secret = google_secret_manager_secret.accounts_database_url.secret_id; version = "latest" } } + value_source { + secret_key_ref { + secret = google_secret_manager_secret.accounts_database_url.secret_id + version = "latest" + } + } } env { name = "JWT_SECRET" - value_source { secret_key_ref { secret = google_secret_manager_secret.jwt_secret.secret_id; version = "latest" } } + value_source { + secret_key_ref { + secret = google_secret_manager_secret.jwt_secret.secret_id + version = "latest" + } + } } env { name = "STRIPE_SECRET_KEY" - value_source { secret_key_ref { secret = "stripe-secret-key"; version = "latest" } } + value_source { + secret_key_ref { + secret = "stripe-secret-key" + version = "latest" + } + } } env { name = "STRIPE_WEBHOOK_SECRET" - value_source { secret_key_ref { secret = "stripe-webhook-secret"; version = "latest" } } + value_source { + secret_key_ref { + secret = "stripe-webhook-secret" + version = "latest" + } + } } env { name = "STRIPE_PRICE_PROFESSIONAL" - value_source { secret_key_ref { secret = "stripe-price-professional"; version = "latest" } } + value_source { + secret_key_ref { + secret = "stripe-price-professional" + version = "latest" + } + } } env { name = "STRIPE_PRICE_FOUNDING" - value_source { secret_key_ref { secret = "stripe-price-founding"; version = "latest" } } + value_source { + secret_key_ref { + secret = "stripe-price-founding" + version = "latest" + } + } } - ports { container_port = 8080; name = "http1" } + ports { + container_port = 8080 + name = "http1" + } startup_probe { - http_get { path = "/health"; port = 8080 } - initial_delay_seconds = 2; timeout_seconds = 5; period_seconds = 5; failure_threshold = 10 - } - liveness_probe { - http_get { path = "/health"; port = 8080 } - timeout_seconds = 5; period_seconds = 30; failure_threshold = 3 + http_get { + path = "/health" + port = 8080 + } + initial_delay_seconds = 2 + timeout_seconds = 5 + period_seconds = 5 + failure_threshold = 10 } - volume_mounts { name = "cloudsql"; mount_path = "/cloudsql" } + liveness_probe { + http_get { + path = "/health" + port = 8080 + } + timeout_seconds = 5 + period_seconds = 30 + failure_threshold = 3 + } + + volume_mounts { + name = "cloudsql" + mount_path = "/cloudsql" + } } volumes { name = "cloudsql" - cloud_sql_instance { instances = [local.sql_instance] } + cloud_sql_instance { + instances = [local.sql_instance] + } } } - traffic { type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST"; percent = 100 } + traffic { + type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST" + percent = 100 + } depends_on = [ google_project_iam_member.accounts_secret_accessor, @@ -269,59 +320,121 @@ resource "google_cloud_run_v2_service" "accounts_apac" { image = local.accounts_image resources { - limits = { cpu = "1"; memory = "512Mi" } + limits = { + cpu = "1" + memory = "512Mi" + } cpu_idle = true } - env { name = "ENV"; value = "production" } - env { name = "PORT"; value = "8080" } + env { + name = "ENV" + value = "production" + } + env { + name = "PORT" + value = "8080" + } env { name = "ACCOUNTS_DATABASE_URL" - value_source { secret_key_ref { secret = google_secret_manager_secret.accounts_database_url.secret_id; version = "latest" } } + value_source { + secret_key_ref { + secret = google_secret_manager_secret.accounts_database_url.secret_id + version = "latest" + } + } } env { name = "JWT_SECRET" - value_source { secret_key_ref { secret = google_secret_manager_secret.jwt_secret.secret_id; version = "latest" } } + value_source { + secret_key_ref { + secret = google_secret_manager_secret.jwt_secret.secret_id + version = "latest" + } + } } env { name = "STRIPE_SECRET_KEY" - value_source { secret_key_ref { secret = "stripe-secret-key"; version = "latest" } } + value_source { + secret_key_ref { + secret = "stripe-secret-key" + version = "latest" + } + } } env { name = "STRIPE_WEBHOOK_SECRET" - value_source { secret_key_ref { secret = "stripe-webhook-secret"; version = "latest" } } + value_source { + secret_key_ref { + secret = "stripe-webhook-secret" + version = "latest" + } + } } env { name = "STRIPE_PRICE_PROFESSIONAL" - value_source { secret_key_ref { secret = "stripe-price-professional"; version = "latest" } } + value_source { + secret_key_ref { + secret = "stripe-price-professional" + version = "latest" + } + } } env { name = "STRIPE_PRICE_FOUNDING" - value_source { secret_key_ref { secret = "stripe-price-founding"; version = "latest" } } + value_source { + secret_key_ref { + secret = "stripe-price-founding" + version = "latest" + } + } } - ports { container_port = 8080; name = "http1" } + ports { + container_port = 8080 + name = "http1" + } startup_probe { - http_get { path = "/health"; port = 8080 } - initial_delay_seconds = 2; timeout_seconds = 5; period_seconds = 5; failure_threshold = 10 - } - liveness_probe { - http_get { path = "/health"; port = 8080 } - timeout_seconds = 5; period_seconds = 30; failure_threshold = 3 + http_get { + path = "/health" + port = 8080 + } + initial_delay_seconds = 2 + timeout_seconds = 5 + period_seconds = 5 + failure_threshold = 10 } - volume_mounts { name = "cloudsql"; mount_path = "/cloudsql" } + liveness_probe { + http_get { + path = "/health" + port = 8080 + } + timeout_seconds = 5 + period_seconds = 30 + failure_threshold = 3 + } + + volume_mounts { + name = "cloudsql" + mount_path = "/cloudsql" + } } volumes { name = "cloudsql" - cloud_sql_instance { instances = [local.sql_instance] } + cloud_sql_instance { + instances = [local.sql_instance] + } } } - traffic { type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST"; percent = 100 } + traffic { + type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST" + percent = 100 + } depends_on = [ google_project_iam_member.accounts_secret_accessor, diff --git a/servers/gcp/cloud-run-api.tf b/servers/gcp/cloud-run-api.tf index f6e79ad..d956916 100644 --- a/servers/gcp/cloud-run-api.tf +++ b/servers/gcp/cloud-run-api.tf @@ -1,8 +1,7 @@ # ── REST API (neuron-rest) — Cloud Run ──────────────────────────────────────── -# Stateless API layer. Validates JWTs issued by the accounts service. -# Does NOT connect to Cloud SQL directly — reads from accounts service for -# user context; maintains its own in-process state only. -# No Cloud SQL volume needed here. +# Stateless API layer. Validates JWTs from accounts service. +# No database connection — reads user context from accounts service. +# cpu_idle=false: always-hot, no cold-start latency for API calls. locals { api_labels = { @@ -36,13 +35,22 @@ resource "google_cloud_run_v2_service" "api_us" { cpu = "2" memory = "1Gi" } - cpu_idle = false # API needs to be always-hot; no cold starts + cpu_idle = false } - env { name = "ENV"; value = "production" } - env { name = "PORT"; value = "8080" } + env { + name = "ENV" + value = "production" + } + env { + name = "PORT" + value = "8080" + } + env { + name = "ACCOUNTS_SERVICE_URL" + value = "https://accounts.neurontechnologies.ai" + } - # JWT key — shared with accounts service for token validation env { name = "JWT_SECRET" value_source { @@ -52,8 +60,6 @@ resource "google_cloud_run_v2_service" "api_us" { } } } - - # License admin token — for neuron-mcp license checks env { name = "LICENSE_ADMIN_TOKEN" value_source { @@ -64,12 +70,6 @@ resource "google_cloud_run_v2_service" "api_us" { } } - # Accounts service URL — for JWT validation and user lookups - env { - name = "ACCOUNTS_SERVICE_URL" - value = "https://accounts.neurontechnologies.ai" - } - ports { container_port = 8080 name = "http1" @@ -132,39 +132,80 @@ resource "google_cloud_run_v2_service" "api_eu" { image = local.api_image resources { - limits = { cpu = "2"; memory = "1Gi" } + limits = { + cpu = "2" + memory = "1Gi" + } cpu_idle = false } - env { name = "ENV"; value = "production" } - env { name = "PORT"; value = "8080" } + env { + name = "ENV" + value = "production" + } + env { + name = "PORT" + value = "8080" + } + env { + name = "ACCOUNTS_SERVICE_URL" + value = "https://accounts.neurontechnologies.ai" + } env { name = "JWT_SECRET" - value_source { secret_key_ref { secret = google_secret_manager_secret.jwt_secret.secret_id; version = "latest" } } + value_source { + secret_key_ref { + secret = google_secret_manager_secret.jwt_secret.secret_id + version = "latest" + } + } } env { name = "LICENSE_ADMIN_TOKEN" - value_source { secret_key_ref { secret = google_secret_manager_secret.license_admin_token.secret_id; version = "latest" } } + value_source { + secret_key_ref { + secret = google_secret_manager_secret.license_admin_token.secret_id + version = "latest" + } + } } - env { name = "ACCOUNTS_SERVICE_URL"; value = "https://accounts.neurontechnologies.ai" } - ports { container_port = 8080; name = "http1" } + ports { + container_port = 8080 + name = "http1" + } startup_probe { - http_get { path = "/health"; port = 8080 } - initial_delay_seconds = 2; timeout_seconds = 5; period_seconds = 5; failure_threshold = 6 + http_get { + path = "/health" + port = 8080 + } + initial_delay_seconds = 2 + timeout_seconds = 5 + period_seconds = 5 + failure_threshold = 6 } + liveness_probe { - http_get { path = "/health"; port = 8080 } - timeout_seconds = 5; period_seconds = 30; failure_threshold = 3 + http_get { + path = "/health" + port = 8080 + } + timeout_seconds = 5 + period_seconds = 30 + failure_threshold = 3 } } max_instance_request_concurrency = 1000 } - traffic { type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST"; percent = 100 } + traffic { + type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST" + percent = 100 + } + depends_on = [google_project_iam_member.api_secret_accessor] } @@ -189,38 +230,79 @@ resource "google_cloud_run_v2_service" "api_apac" { image = local.api_image resources { - limits = { cpu = "2"; memory = "1Gi" } + limits = { + cpu = "2" + memory = "1Gi" + } cpu_idle = false } - env { name = "ENV"; value = "production" } - env { name = "PORT"; value = "8080" } + env { + name = "ENV" + value = "production" + } + env { + name = "PORT" + value = "8080" + } + env { + name = "ACCOUNTS_SERVICE_URL" + value = "https://accounts.neurontechnologies.ai" + } env { name = "JWT_SECRET" - value_source { secret_key_ref { secret = google_secret_manager_secret.jwt_secret.secret_id; version = "latest" } } + value_source { + secret_key_ref { + secret = google_secret_manager_secret.jwt_secret.secret_id + version = "latest" + } + } } env { name = "LICENSE_ADMIN_TOKEN" - value_source { secret_key_ref { secret = google_secret_manager_secret.license_admin_token.secret_id; version = "latest" } } + value_source { + secret_key_ref { + secret = google_secret_manager_secret.license_admin_token.secret_id + version = "latest" + } + } } - env { name = "ACCOUNTS_SERVICE_URL"; value = "https://accounts.neurontechnologies.ai" } - ports { container_port = 8080; name = "http1" } + ports { + container_port = 8080 + name = "http1" + } startup_probe { - http_get { path = "/health"; port = 8080 } - initial_delay_seconds = 2; timeout_seconds = 5; period_seconds = 5; failure_threshold = 6 + http_get { + path = "/health" + port = 8080 + } + initial_delay_seconds = 2 + timeout_seconds = 5 + period_seconds = 5 + failure_threshold = 6 } + liveness_probe { - http_get { path = "/health"; port = 8080 } - timeout_seconds = 5; period_seconds = 30; failure_threshold = 3 + http_get { + path = "/health" + port = 8080 + } + timeout_seconds = 5 + period_seconds = 30 + failure_threshold = 3 } } max_instance_request_concurrency = 1000 } - traffic { type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST"; percent = 100 } + traffic { + type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST" + percent = 100 + } + depends_on = [google_project_iam_member.api_secret_accessor] }