main.tf (247 lines of code) (raw):

# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Random suffix tied to project -- used on resources with global naming data "google_project" "project" { project_id = var.project_id } resource "random_id" "suffix" { byte_length = 2 } data "google_storage_project_service_account" "gcs_account" { project = var.project_id } locals { # mediaedge doesn't yet support google_project_service_identity mediaedgefill_email = "service-${data.google_project.project.number}@gcp-sa-mediaedgefill.iam.gserviceaccount.com" index_html = templatefile("${path.module}/source/index.html.tftpl", { test_video_name = google_storage_bucket_object.test_video.name, test_video_name_short = trimsuffix(google_storage_bucket_object.test_video.name, ".mp4"), vod_upload_bucket = google_storage_bucket.vod_upload.name, vod_upload_bucket_urlenc = urlencode(google_storage_bucket.vod_upload.name), vod_serving_bucket = google_storage_bucket.vod_serving.name, vod_serving_bucket_urlenc = urlencode(google_storage_bucket.vod_serving.name), project_id_urlenc = urlencode(var.project_id), media_cdn_ipv4 = google_network_services_edge_cache_service.default.ipv4_addresses[0], }) } module "project_services" { source = "terraform-google-modules/project-factory/google//modules/project_services" version = "~> 13.0" disable_services_on_destroy = false project_id = var.project_id enable_apis = var.enable_apis activate_apis = [ "artifactregistry.googleapis.com", "cloudbuild.googleapis.com", "cloudfunctions.googleapis.com", "compute.googleapis.com", "edgecache.googleapis.com", "eventarc.googleapis.com", "iam.googleapis.com", "networkservices.googleapis.com", "pubsub.googleapis.com", "run.googleapis.com", "storage-api.googleapis.com", "storage.googleapis.com", "transcoder.googleapis.com", ] } resource "google_project_service_identity" "service_identities" { provider = google-beta project = module.project_services.project_id for_each = toset([ "transcoder.googleapis.com", ]) service = each.value } resource "google_storage_bucket" "gcf_source" { name = "gcf-source-${random_id.suffix.hex}" project = module.project_services.project_id location = var.region force_destroy = false uniform_bucket_level_access = true labels = var.labels } resource "google_storage_bucket" "vod_upload" { name = "vod-upload-${random_id.suffix.hex}" project = module.project_services.project_id location = var.region force_destroy = false uniform_bucket_level_access = true labels = var.labels } resource "google_storage_bucket" "vod_serving" { name = "vod-serving-${random_id.suffix.hex}" project = module.project_services.project_id location = var.region force_destroy = true uniform_bucket_level_access = true labels = var.labels cors { origin = ["https://shaka-player-demo.appspot.com/"] response_header = ["Content-Type", "Range"] method = ["GET", "HEAD"] max_age_seconds = 3600 } } resource "google_network_services_edge_cache_origin" "default" { name = "vod-origin-${random_id.suffix.hex}" project = module.project_services.project_id origin_address = google_storage_bucket.vod_serving.url max_attempts = 2 labels = var.labels timeout { connect_timeout = "10s" } } resource "google_network_services_edge_cache_service" "default" { name = "vod-service-${random_id.suffix.hex}" project = module.project_services.project_id labels = var.labels edge_security_policy = google_compute_security_policy.edgepolicy.name routing { host_rule { hosts = ["*"] path_matcher = "routes" } path_matcher { name = "routes" route_rule { priority = 1 match_rule { prefix_match = "/" } origin = google_network_services_edge_cache_origin.default.name route_action { cdn_policy { cache_mode = "FORCE_CACHE_ALL" default_ttl = "3600s" } } header_action { response_header_to_add { header_name = "x-cache-status" header_value = "{cdn_cache_status}" } } } } } } resource "google_storage_bucket_iam_member" "media_edge" { bucket = google_storage_bucket.vod_serving.name role = "roles/storage.objectViewer" member = "serviceAccount:${local.mediaedgefill_email}" } # Allow the google storage service account to publish to Eventarc pubsub resource "google_project_iam_member" "gcs-pubsub-publishing" { project = module.project_services.project_id role = "roles/pubsub.publisher" member = "serviceAccount:${data.google_storage_project_service_account.gcs_account.email_address}" } resource "google_service_account" "transcode_sa" { account_id = "transcode-sa-${random_id.suffix.hex}" project = module.project_services.project_id display_name = <<-EOT Service account used by both the Transcode Cloud Function and Eventarc trigger EOT } resource "google_project_iam_member" "invoking" { project = module.project_services.project_id role = "roles/run.invoker" member = "serviceAccount:${google_service_account.transcode_sa.email}" } resource "google_project_iam_member" "event-receiving" { project = module.project_services.project_id role = "roles/eventarc.eventReceiver" member = "serviceAccount:${google_service_account.transcode_sa.email}" } resource "google_project_iam_member" "artifactregistry-reader" { project = module.project_services.project_id role = "roles/artifactregistry.reader" member = "serviceAccount:${google_service_account.transcode_sa.email}" } resource "google_project_iam_member" "transcoder" { project = module.project_services.project_id role = "roles/transcoder.admin" member = "serviceAccount:${google_service_account.transcode_sa.email}" } data "archive_file" "ingestion" { type = "zip" source_dir = "${path.module}/source/ingestion" output_path = "${path.module}/build/ingestion.zip" } # upload the ingestion function source zipfile to cloud storage resource "google_storage_bucket_object" "ingestion_source" { name = "ingestion.zip" source = data.archive_file.ingestion.output_path bucket = google_storage_bucket.gcf_source.name } resource "google_storage_bucket_object" "test_video" { name = "smpte.mp4" bucket = google_storage_bucket.vod_upload.name source = "smpte.mp4" content_type = "video/mp4" depends_on = [ google_cloudfunctions2_function.vod_ingestion, ] } resource "google_storage_bucket_object" "index_html" { name = "index.html" bucket = google_storage_bucket.vod_serving.name content = local.index_html content_type = "text/html" } resource "google_cloudfunctions2_function" "vod_ingestion" { provider = google-beta project = module.project_services.project_id location = var.region name = "vod-ingestion-${random_id.suffix.hex}" description = <<-EOT Cloud function that invokes a Transcode API job on objects added to vod_upload bucket EOT labels = var.labels build_config { runtime = "python310" entry_point = "vod_ingestion" source { storage_source { bucket = google_storage_bucket.gcf_source.name object = google_storage_bucket_object.ingestion_source.output_name } } } service_config { max_instance_count = 3 min_instance_count = 0 available_memory = "256M" timeout_seconds = 60 environment_variables = { TRANSCODE_PROJECT_ID = var.project_id TRANSCODE_REGION = var.region TRANSCODE_SERVING_BUCKET = google_storage_bucket.vod_serving.name } ingress_settings = "ALLOW_INTERNAL_ONLY" all_traffic_on_latest_revision = true service_account_email = google_service_account.transcode_sa.email } event_trigger { trigger_region = var.region event_type = "google.cloud.storage.object.v1.finalized" retry_policy = "RETRY_POLICY_RETRY" service_account_email = google_service_account.transcode_sa.email event_filters { attribute = "bucket" value = google_storage_bucket.vod_upload.name } } depends_on = [ google_project_iam_member.event-receiving, google_project_iam_member.artifactregistry-reader, ] } resource "google_storage_bucket_iam_member" "transcoder-read" { bucket = google_storage_bucket.vod_upload.name role = "roles/storage.objectViewer" member = "serviceAccount:${google_project_service_identity.service_identities["transcoder.googleapis.com"].email}" } resource "google_storage_bucket_iam_member" "transcoder-write" { bucket = google_storage_bucket.vod_serving.name role = "roles/storage.objectAdmin" member = "serviceAccount:${google_project_service_identity.service_identities["transcoder.googleapis.com"].email}" }