variable "project" {
  description = "Project ID."
  type        = string
}

variable "region" {
  description = "Region."
  type        = string
}

variable "service_cloudkms" {
  description = "cloudkms service."
}

variable "private_network_id" {
  description = "Private network id."
  type        = string
}

variable "private_subnetwork_id" {
  description = "Private subnetwork id."
  type        = string
}

variable "machine_type" {
  description = "Machine type for GKE nodes."
  type        = string
  # Default is very cheap but low ram. Good for simple testing but not for production. Try e2-standard-2 if you need more ram.
  default = "e2-medium"
}

output "gke_connect_command" {
  description = "Command to run to connect to the kubernetes cluster."
  value       = "gcloud container clusters get-credentials ${google_container_cluster.primary.name} --region ${var.region} --project ${var.project}"
}

data "google_project" "project" {
  project_id = var.project
}

#################### KMS ##################################

resource "random_id" "gke_db" {
  byte_length = 4
}

resource "google_kms_key_ring" "gke_db" {
  project  = var.project
  name     = "gke-db-${random_id.gke_db.hex}"
  location = var.region

  lifecycle {
    #prevent_destroy = true
  }

  depends_on = [
    var.service_cloudkms
  ]
}

resource "google_kms_key_ring_iam_policy" "gke_db" {
  key_ring_id = google_kms_key_ring.gke_db.id
  policy_data = data.google_iam_policy.gke_db.policy_data

  depends_on = [
    var.service_cloudkms
  ]
}

resource "google_kms_crypto_key" "gke_db" {
  name     = "gke-db-key"
  key_ring = google_kms_key_ring.gke_db.id

  lifecycle {
    #prevent_destroy = true
  }

  depends_on = [
    google_project_service.container
  ]
}

data "google_iam_policy" "gke_db" {
  binding {
    role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"

    members = [
      "serviceAccount:service-${data.google_project.project.number}@container-engine-robot.iam.gserviceaccount.com"
    ]
  }
}

#################### GKE ##################################

resource "google_project_service" "container" {
  project                    = var.project
  service                    = "container.googleapis.com"
  disable_dependent_services = true
}

resource "google_project_service" "containerregistry" {
  project                    = var.project
  service                    = "containerregistry.googleapis.com"
  disable_dependent_services = true
}

resource "google_service_account" "gke" {
  project      = var.project
  account_id   = "gke-service-account"
  display_name = "GKE Service Account"
}

# Allow GKE to access custom docker images in GCR
resource "google_storage_bucket_iam_member" "gke_gcr" {
  bucket = "artifacts.${google_service_account.gke.project}.appspot.com"
  role   = "roles/storage.objectViewer"
  member = "serviceAccount:${google_service_account.gke.email}"

  depends_on = [
    google_project_service.containerregistry
  ]
}

resource "google_container_cluster" "primary" {
  project    = var.project
  name       = "gke-cluster"
  location   = var.region
  network    = var.private_network_id
  subnetwork = var.private_subnetwork_id

  remove_default_node_pool = true
  initial_node_count       = 1
  enable_shielded_nodes    = true
  min_master_version       = "1.19.10-gke.1000"

  database_encryption {
    state    = "ENCRYPTED"
    key_name = google_kms_crypto_key.gke_db.self_link
  }

  maintenance_policy {
    daily_maintenance_window {
      start_time = "03:00"
    }
  }

  workload_identity_config {
    identity_namespace = "${data.google_project.project.project_id}.svc.id.goog"
  }

  release_channel {
    channel = "STABLE"
  }

  master_auth {
    username = ""
    password = ""
  }

  ip_allocation_policy {
    cluster_ipv4_cidr_block  = "/16"
    services_ipv4_cidr_block = "/20"
  }

  lifecycle {
    #prevent_destroy = true
  }

  depends_on = [
    google_project_service.container,
    google_kms_key_ring_iam_policy.gke_db
  ]
}

resource "google_container_node_pool" "primary" {
  project            = google_container_cluster.primary.project
  name_prefix        = "node-pool"
  location           = var.region
  cluster            = google_container_cluster.primary.name
  initial_node_count = 1

  autoscaling {
    min_node_count = 0
    max_node_count = 20
  }

  node_config {
    preemptible  = true
    machine_type = var.machine_type

    service_account = google_service_account.gke.email
    oauth_scopes = [
      "https://www.googleapis.com/auth/cloud-platform"
    ]

    metadata = {
      disable-legacy-endpoints = "true"
    }

    tags = []

    shielded_instance_config {
      enable_secure_boot          = true
      enable_integrity_monitoring = true
    }
  }

  lifecycle {
    ignore_changes = [
      node_count
    ]
  }

  depends_on = [
    google_project_service.container
  ]
}