diff options
Diffstat (limited to 'main.tf')
| -rw-r--r-- | main.tf | 443 |
1 files changed, 443 insertions, 0 deletions
@@ -0,0 +1,443 @@ +# VARIABLES + +locals { + deploy_ui_cf_name = "deploy-ui-gcs" + deploy_ui_topic = "deploy-ui-gcs" + artifact_bucket_name = "gh-artifacts" + ui_name = "ui" + runner_api_name = "runner-api" + example_api_name = "example-api" + example_db_name = "example-db" +} + +variable "project" { + type = string +} +variable "region" { + type = string +} +variable "zone" { + type = string +} +variable "credentials" { + type = string +} +variable "cloud_run_location" { + type = string +} +variable "gcs_location" { + type = string +} +variable "gh_deploy_sa" { + type = string +} +variable "runner_api_image" { + type = string +} +variable "example_api_image" { + type = string +} +variable "ui_build_revision" { + type = string +} +variable "ui_dns_name" { + type = string +} +variable "example_db_api_user_password" { + type = string + sensitive = true +} +variable "nr_license_key" { + type = string + sensitive = true +} + +# TF BACKEND + +terraform { + backend "gcs" { + bucket = "slam-lang-tf-state" + prefix = "terraform/state" + credentials = "sa.json" + } +} + +provider "google" { + project = var.project + region = var.region + zone = var.zone + credentials = var.credentials +} + +# DEPLOYMENT INFRA + +resource "google_storage_bucket" "gh-artifacts" { + name = "${var.project}-${local.artifact_bucket_name}" + location = var.gcs_location + force_destroy = true + + uniform_bucket_level_access = true +} + +resource "google_pubsub_schema" "deploy-ui-gcs" { + name = "${local.deploy_ui_topic}-schema" + type = "AVRO" + definition = <<-EOT + { + "type": "record", + "name": "Avro", + "fields": [ + { + "name": "revision", + "type": "string" + } + ] + } + EOT +} + +resource "google_pubsub_topic" "deploy-ui-gcs" { + name = local.deploy_ui_topic + + depends_on = [google_pubsub_schema.deploy-ui-gcs] + schema_settings { + schema = "projects/${var.project}/schemas/${google_pubsub_schema.deploy-ui-gcs.name}" + encoding = "JSON" + } +} + +resource "google_pubsub_schema" "deploy-ui-gcs-result" { + name = "${local.deploy_ui_topic}-result-schema" + type = "AVRO" + definition = <<-EOT + { + "type": "record", + "name": "Avro", + "fields": [ + { + "name": "revision", + "type": "string" + }, + { + "name": "ok", + "type": "boolean" + } + ] + } + EOT +} + +resource "google_pubsub_topic" "deploy-ui-gcs-result" { + name = "${local.deploy_ui_topic}-result" + + depends_on = [google_pubsub_schema.deploy-ui-gcs-result] + schema_settings { + schema = "projects/${var.project}/schemas/${google_pubsub_schema.deploy-ui-gcs-result.name}" + encoding = "JSON" + } +} + +resource "google_pubsub_subscription" "deploy-ui-gcs-result" { + name = "${local.deploy_ui_topic}-result-sub" + topic = google_pubsub_topic.deploy-ui-gcs-result.name + + message_retention_duration = "604800s" # 7 days + retain_acked_messages = false + + ack_deadline_seconds = 20 + + expiration_policy { + ttl = "" + } + retry_policy { + minimum_backoff = "10s" + } + + enable_message_ordering = false +} + +resource "null_resource" "cloud-function-deploy-ui-gcs" { + triggers = { + version = jsondecode(file("deploy-ui-gcs/package.json")).version + name = local.deploy_ui_cf_name + region = var.cloud_run_location + topic = local.deploy_ui_topic + service-account = var.gh_deploy_sa + } + + depends_on = [ + google_storage_bucket.gh-artifacts, + google_pubsub_topic.deploy-ui-gcs, + google_pubsub_subscription.deploy-ui-gcs-result, + ] + + provisioner "local-exec" { + command = <<-EOT + cd deploy-ui-gcs + gcloud functions deploy ${self.triggers.name} \ + --region ${self.triggers.region} \ + --trigger-topic ${self.triggers.topic} \ + --service-account=${self.triggers.service-account} \ + --runtime=nodejs16 + EOT + } + + provisioner "local-exec" { + when = destroy + command = <<-EOT + cd deploy-ui-gcs + gcloud functions delete ${self.triggers.name} \ + --region ${self.triggers.region} \ + EOT + } +} + +# FRONTEND UI + +resource "google_storage_bucket" "ui" { + name = "${var.project}-${local.ui_name}" + location = var.gcs_location + force_destroy = true + + uniform_bucket_level_access = true + + website { + main_page_suffix = "index.html" + } + cors { + origin = ["*"] + method = ["GET", "HEAD", "PUT", "POST", "DELETE"] + response_header = ["*"] + max_age_seconds = 3600 + } +} + +data "google_iam_policy" "gcs_allUsers_viewer" { + binding { + role = "roles/storage.objectViewer" + members = [ + "allUsers", + ] + } +} + +resource "google_storage_bucket_iam_policy" "ui" { + bucket = google_storage_bucket.ui.name + policy_data = data.google_iam_policy.gcs_allUsers_viewer.policy_data +} + +resource "null_resource" "ui-content" { + triggers = { + ui_build_revision = var.ui_build_revision + } + + depends_on = [ + null_resource.cloud-function-deploy-ui-gcs, + ] + + provisioner "local-exec" { + command = <<-EOT + which npm + cd deploy-ui-gcs + npm run deploy "${var.ui_build_revision}" + EOT + } +} + +resource "google_compute_backend_bucket" "ui" { + name = local.ui_name + description = "" + bucket_name = google_storage_bucket.ui.name + enable_cdn = false +} + +resource "google_compute_url_map" "ui" { + name = local.ui_name + project = var.project + provider = google-beta + default_service = google_compute_backend_bucket.ui.id +} + +resource "google_compute_managed_ssl_certificate" "ui" { + name = local.ui_name + + managed { + domains = [var.ui_dns_name] + } +} + +resource "google_compute_target_https_proxy" "ui" { + name = local.ui_name + project = var.project + url_map = google_compute_url_map.ui.id + ssl_certificates = [google_compute_managed_ssl_certificate.ui.id] +} + +resource "google_compute_global_address" "ui" { + provider = google-beta + project = var.project + name = local.ui_name +} + +resource "google_compute_global_forwarding_rule" "ui" { + name = local.ui_name + project = var.project + provider = google-beta + ip_protocol = "TCP" + load_balancing_scheme = "EXTERNAL" + port_range = "443" + target = google_compute_target_https_proxy.ui.id + ip_address = google_compute_global_address.ui.id +} + +output "ui-ip" { + value = google_compute_global_address.ui.address +} + +output "ui-url" { + value = "https://${var.ui_dns_name}" +} + +# RUNNER API + +resource "google_cloud_run_service" "runner-api" { + name = local.runner_api_name + project = var.project + location = var.cloud_run_location + + template { + spec { + containers { + image = var.runner_api_image + env { + name = "NEWRELIC_LICENSE_KEY" + value = var.nr_license_key + } + } + timeout_seconds = 7 # interpreter timeout = 5 + } + + metadata { + annotations = { + "autoscaling.knative.dev/maxScale" = 3 + } + } + } + + traffic { + percent = 100 + latest_revision = true + } +} + +data "google_iam_policy" "cloud_run_allUsers_invoker" { + binding { + role = "roles/run.invoker" + members = [ + "allUsers", + ] + } +} + +resource "google_cloud_run_service_iam_policy" "runner-api" { + location = google_cloud_run_service.runner-api.location + project = google_cloud_run_service.runner-api.project + service = google_cloud_run_service.runner-api.name + + policy_data = data.google_iam_policy.cloud_run_allUsers_invoker.policy_data +} + +# EXAMPLE API + +resource "google_cloud_run_service" "example-api" { + name = local.example_api_name + project = var.project + location = var.cloud_run_location + + template { + spec { + containers { + image = var.example_api_image + env { + name = "PGHOST" + value = "/cloudsql/${google_sql_database_instance.example-db.connection_name}" + } + env { + name = "PGDATABASE" + value = google_sql_database.example-db.name + } + env { + name = "PGUSER" + value = local.example_api_name + } + env { + name = "PGPASSWORD" + value = var.example_db_api_user_password + } + env { + name = "NEWRELIC_LICENSE_KEY" + value = var.nr_license_key + } + } + timeout_seconds = 5 + } + + metadata { + annotations = { + "autoscaling.knative.dev/maxScale" = 3 + "run.googleapis.com/cloudsql-instances" = google_sql_database_instance.example-db.connection_name + } + } + } + + traffic { + percent = 100 + latest_revision = true + } + + depends_on = [ + google_sql_user.example-db + ] +} + +resource "google_cloud_run_service_iam_policy" "example-api" { + location = google_cloud_run_service.example-api.location + project = google_cloud_run_service.example-api.project + service = google_cloud_run_service.example-api.name + + policy_data = data.google_iam_policy.cloud_run_allUsers_invoker.policy_data +} + +# EXAMPLE DB + +resource "google_sql_database_instance" "example-db" { + name = local.example_db_name + database_version = "POSTGRES_14" + region = var.region + + settings { + tier = "db-f1-micro" + availability_type = "ZONAL" + location_preference { + zone = var.zone + } + disk_size = 10 + backup_configuration { + enabled = false + } + ip_configuration { + ipv4_enabled = true + } + } +} + +resource "google_sql_database" "example-db" { + name = local.example_db_name + instance = google_sql_database_instance.example-db.name +} + +resource "google_sql_user" "example-db" { + name = local.example_api_name + instance = google_sql_database_instance.example-db.name + password = var.example_db_api_user_password +} |
