terraform/translation/gcc/main.tf (329 lines of code) (raw):
# Copyright 2021 Google LLC.
# This software is provided as-is, without warranty or representation for any use or purpose.
# Your use of it is subject to your agreement with Google.
#/************************* DMT END-TO-END MIGRATION INFRASTRUCTURE*************************
/*****************************************
Cloud Composer Deployment
*****************************************/
data "google_project" "project" {
project_id = var.project_id
}
locals {
/* Check if network topology is host-service (shared VPC) */
network_project_id = var.network_project_id != "" ? var.network_project_id : var.project_id
subnetwork_region = var.subnetwork_region != "" ? var.subnetwork_region : var.location
/* Check if master authorized network has been set */
master_authorized_networks_config = length(var.master_authorized_networks) == 0 ? [] : [{
cidr_blocks : var.master_authorized_networks
}]
/* Set sizing for Airflow components based on user values, or other environment sizing presets - Small, Medium, Large. */
scheduler_presets = {
"ENVIRONMENT_SIZE_SMALL" = {
"cpu" = 0.5
"memory_gb" = 2,
"storage_gb" = 1,
"count" = 1,
},
"ENVIRONMENT_SIZE_MEDIUM" = {
"cpu" = startswith(var.image_version, "composer-3") ? 1 : 2,
"memory_gb" = startswith(var.image_version, "composer-3") ? 4 : 7.5,
"storage_gb" = 5,
"count" = 2,
},
"ENVIRONMENT_SIZE_LARGE" = {
"cpu" = startswith(var.image_version, "composer-3") ? 1 : 4,
"memory_gb" = startswith(var.image_version, "composer-3") ? 4 : 15,
"storage_gb" = 10,
"count" = 2,
} }
scheduler_config = var.scheduler != null ? var.scheduler : local.scheduler_presets[var.environment_size]
triggerer_presets = {
"ENVIRONMENT_SIZE_SMALL" = {
"cpu" = 0.5,
"memory_gb" = 1,
"count" = 1,
},
"ENVIRONMENT_SIZE_MEDIUM" = {
"cpu" = 0.5,
"memory_gb" = 1,
"count" = 1,
},
"ENVIRONMENT_SIZE_LARGE" = {
"cpu" = 0.5,
"memory_gb" = 1,
"count" = 1,
} }
triggerer_config = var.triggerer != null ? var.triggerer : local.triggerer_presets[var.environment_size]
web_server_presets = {
"ENVIRONMENT_SIZE_SMALL" = {
"cpu" = 1,
"memory_gb" = 2,
"storage_gb" = 1,
},
"ENVIRONMENT_SIZE_MEDIUM" = {
"cpu" = 2,
"memory_gb" = 7.5,
"storage_gb" = 5,
},
"ENVIRONMENT_SIZE_LARGE" = {
"cpu" = 2,
"memory_gb" = 7.5,
"storage_gb" = 10,
} }
web_server_config = var.web_server != null ? var.web_server : local.web_server_presets[var.environment_size]
worker_presets = {
"ENVIRONMENT_SIZE_SMALL" = {
"cpu" = 0.5,
"memory_gb" = 2,
"storage_gb" = startswith(var.image_version, "composer-3") ? 10 : 1,
"min_count" = 1,
"max_count" = 3,
},
"ENVIRONMENT_SIZE_MEDIUM" = {
"cpu" = 2,
"memory_gb" = 7.5,
"storage_gb" = startswith(var.image_version, "composer-3") ? 20 : 5,
"min_count" = 2,
"max_count" = 6,
},
"ENVIRONMENT_SIZE_LARGE" = {
"cpu" = 4,
"memory_gb" = 15,
"storage_gb" = startswith(var.image_version, "composer-3") ? 50 : 10,
"min_count" = 3,
"max_count" = 12,
} }
worker_config = var.worker != null ? var.worker : local.worker_presets[var.environment_size]
dag_processor_presets = {
"ENVIRONMENT_SIZE_SMALL" = {
"cpu" = 1,
"memory_gb" = 4,
"storage_gb" = 1,
"count" = 1,
},
"ENVIRONMENT_SIZE_MEDIUM" = {
"cpu" = 2,
"memory_gb" = 7.5,
"storage_gb" = 5,
"count" = 1,
},
"ENVIRONMENT_SIZE_LARGE" = {
"cpu" = 4,
"memory_gb" = 15,
"storage_gb" = 10,
"count" = 2,
} }
dag_processor_config = var.dag_processor != null ? var.dag_processor : local.dag_processor_presets[var.environment_size]
}
resource "google_project_service_identity" "composer_service_agent_identity" {
provider = google-beta
project = data.google_project.project.project_id
service = "composer.googleapis.com"
}
resource "google_project_iam_member" "composer_service_agent_roles" {
depends_on = [google_project_service_identity.composer_service_agent_identity]
project = data.google_project.project.project_id
for_each = toset([
"roles/composer.serviceAgent",
"roles/composer.ServiceAgentV2Ext",
])
role = each.key
member = google_project_service_identity.composer_service_agent_identity.member
}
/* Cloud Composer Service Account creation that will be attached to the Composer */
resource "google_service_account" "composer_service_account" {
project = var.project_id
account_id = var.service_account_gcc
display_name = "Service Account for Cloud Composer"
}
/* Provide Composer Worker IAM role and Composer Admin IAM role */
resource "google_project_iam_member" "composer_worker" {
depends_on = [google_service_account.composer_service_account]
project = var.project_id
for_each = toset(var.composer_roles)
role = each.value
member = google_service_account.composer_service_account.member
}
/* Provide Object Admin authorization for Service Account to the created GCS buckets */
resource "google_storage_bucket_iam_member" "storage_object_admin" {
depends_on = [google_service_account.composer_service_account]
for_each = toset(var.bucket_names)
bucket = "${each.value}-${var.customer_name}"
role = "roles/storage.objectAdmin"
member = google_service_account.composer_service_account.member
}
/* Properties of Composer Environment*/
resource "google_composer_environment" "composer_env" {
depends_on = [google_project_iam_member.composer_service_agent_roles, google_storage_bucket_iam_member.storage_object_admin, google_project_iam_member.composer_worker]
project = var.project_id
provider = google-beta
name = "${var.composer_env_name}-${var.customer_name}"
region = var.location
labels = var.labels
config {
node_config {
/* Picks up VPC network and subnet name based on Choice of Shared VPC project or not */
network = "projects/${local.network_project_id}/global/networks/${var.network}"
subnetwork = "projects/${local.network_project_id}/regions/${local.subnetwork_region}/subnetworks/${var.subnetwork}"
service_account = google_service_account.composer_service_account.email
dynamic "ip_allocation_policy" {
for_each = (startswith(var.image_version, "composer-2") && (var.pod_ip_allocation_range_name != null || var.service_ip_allocation_range_name != null)) ? [1] : []
content {
cluster_secondary_range_name = var.pod_ip_allocation_range_name
services_secondary_range_name = var.service_ip_allocation_range_name
}
}
}
software_config {
airflow_config_overrides = {
"api-auth_backends" = "airflow.composer.api.backend.composer_auth",
"core-dags_are_paused_at_creation" = "True",
"webserver-dag_orientation" = "TB",
"secrets-backend" = "airflow.providers.google.cloud.secrets.secret_manager.CloudSecretManagerBackend",
"secrets-backend_kwargs" = jsonencode({ "connections_prefix" : "composer-connections", "variables_prefix" : "secret", "sep" : "-" })
"core-max_map_length" = var.max_map_length
}
image_version = var.image_version
pypi_packages = {
# Add any extra depedencies here
oracledb = ""
redshift-connector = ""
openpyxl = ""
}
env_variables = {
"GCP_PROJECT_ID" = var.project_id
"REGION" = var.location
"COMPOSER_ENV" = "${var.composer_env_name}-${var.customer_name}"
"COMPOSER_SA" = var.service_account_gcc
"TRANSLATION_REPORT_FILENAME" = "batch_translation_report.csv"
"CUSTOMER_NAME" = var.customer_name
"CONFIG_BUCKET_NAME" = "${var.config_bucket}-${var.customer_name}"
"DVT_IMAGE" = var.dvt_image
/* Adding this env variable for Data Transfer use later */
"CONTROLLER_TOPIC" = "${var.dtsagent_controller_topic_name}-${var.customer_name}"
}
}
/* Check if Private IP is enabled for Cloud Composer Networking Type */
enable_private_environment = var.use_private_environment && startswith(var.image_version, "composer-3") ? true : null
dynamic "private_environment_config" {
for_each = var.use_private_environment && startswith(var.image_version, "composer-2") ? [
{
enable_private_endpoint = var.enable_private_endpoint
cloud_composer_connection_subnetwork = var.composer_private_service_connect_connectivity == true ? (var.cloud_composer_connection_subnetwork_name == null ? "projects/${local.network_project_id}/regions/${local.subnetwork_region}/subnetworks/${var.subnetwork}" : "projects/${local.network_project_id}/regions/${local.subnetwork_region}/subnetworks/${var.cloud_composer_connection_subnetwork_name}") : null
master_ipv4_cidr_block = var.composer_private_service_connect_connectivity == false ? var.master_ipv4_cidr : null
cloud_sql_ipv4_cidr_block = var.composer_private_service_connect_connectivity == false ? var.cloud_sql_ipv4_cidr : null
web_server_ipv4_cidr_block = var.composer_private_service_connect_connectivity == false ? var.web_server_ipv4_cidr : null
cloud_composer_network_ipv4_cidr_block = var.composer_private_service_connect_connectivity == false ? var.cloud_composer_network_ipv4_cidr_block : null
}] : []
content {
enable_private_endpoint = private_environment_config.value["enable_private_endpoint"]
cloud_composer_connection_subnetwork = private_environment_config.value["cloud_composer_connection_subnetwork"]
master_ipv4_cidr_block = private_environment_config.value["master_ipv4_cidr_block"]
cloud_sql_ipv4_cidr_block = private_environment_config.value["cloud_sql_ipv4_cidr_block"]
web_server_ipv4_cidr_block = private_environment_config.value["web_server_ipv4_cidr_block"]
cloud_composer_network_ipv4_cidr_block = private_environment_config.value["cloud_composer_network_ipv4_cidr_block"]
}
}
/* Allow only authorized networks to connect to Cluster Endpoints */
dynamic "master_authorized_networks_config" {
for_each = startswith(var.image_version, "composer-2") ? local.master_authorized_networks_config : []
content {
enabled = length(var.master_authorized_networks) > 0
dynamic "cidr_blocks" {
for_each = master_authorized_networks_config.value["cidr_blocks"]
content {
cidr_block = cidr_blocks.value.cidr_block
display_name = cidr_blocks.value.display_name
}
}
}
}
dynamic "web_server_network_access_control" {
for_each = var.web_server_allowed_ip_ranges != null ? [1] : []
content {
dynamic "allowed_ip_range" {
for_each = var.web_server_allowed_ip_ranges
content {
value = allowed_ip_range.value.value
description = allowed_ip_range.value.description
}
}
}
}
/* Composer Environment Resource Configuration */
workloads_config {
scheduler {
cpu = local.scheduler_config.cpu
memory_gb = local.scheduler_config.memory_gb
storage_gb = local.scheduler_config.storage_gb
count = local.scheduler_config.count
}
triggerer {
cpu = local.triggerer_config.cpu
memory_gb = local.triggerer_config.memory_gb
count = local.triggerer_config.count
}
web_server {
cpu = local.web_server_config.cpu
memory_gb = local.web_server_config.memory_gb
storage_gb = local.web_server_config.storage_gb
}
worker {
cpu = local.worker_config.cpu
memory_gb = local.worker_config.memory_gb
storage_gb = local.worker_config.storage_gb
min_count = local.worker_config.min_count
max_count = local.worker_config.max_count
}
dynamic "dag_processor" {
for_each = startswith(var.image_version, "composer-3") ? [1] : []
content {
cpu = local.dag_processor_config.cpu
memory_gb = local.dag_processor_config.memory_gb
storage_gb = local.dag_processor_config.storage_gb
count = local.dag_processor_config.count
}
}
}
environment_size = var.environment_size
}
}
/* Copy translation DAGs to Composer bucket */
resource "null_resource" "upload_translation_dags" {
depends_on = [google_composer_environment.composer_env]
triggers = {
translation_dag_hashes = jsonencode({
for fn in fileset(var.translation_dag_source_path, "**") :
fn => filesha256("${var.translation_dag_source_path}/${fn}")
})
}
provisioner "local-exec" {
command = "gsutil -o \"GSUtil:parallel_process_count=1\" -m cp -r ${var.translation_dag_source_path}/* ${google_composer_environment.composer_env.config.0.dag_gcs_prefix}/"
}
}
/* Copy common_utils/ to Composer bucket */
resource "null_resource" "upload_common_utils" {
depends_on = [google_composer_environment.composer_env]
triggers = {
common_util_hashes = jsonencode({
for fn in fileset(var.common_utils, "**") :
fn => filesha256("${var.common_utils}/${fn}")
})
}
provisioner "local-exec" {
command = "gsutil -o \"GSUtil:parallel_process_count=1\" -m cp -r ${var.common_utils} ${google_composer_environment.composer_env.config.0.dag_gcs_prefix}/"
}
}
/* Composer 2: Set up firewall rule to allow Composer GKE cluster pods (KubernetesPodOperator) to reach the rest of the VPC network. */
data "google_container_cluster" "composer_gke_cluster" {
count = startswith(var.image_version, "composer-2") ? 1 : 0
name = split("/", google_composer_environment.composer_env.config.0.gke_cluster)[5]
location = split("/", google_composer_environment.composer_env.config.0.gke_cluster)[3]
}
resource "google_compute_firewall" "dmt-pod-operator" {
count = startswith(var.image_version, "composer-2") ? 1 : 0
name = "dmt-allow-composer-gke-pods"
network = google_composer_environment.composer_env.config.0.node_config.0.network
description = "Allows Composer cluster GKE pods to reach the default VPC range."
priority = 1001
direction = "INGRESS"
source_ranges = [data.google_container_cluster.composer_gke_cluster[0].ip_allocation_policy.0.cluster_ipv4_cidr_block]
allow {
protocol = "all"
}
}