terraform/lab1/main.tf (107 lines of code) (raw):
/**
* Copyright 2021 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.
*/
provider "google" {
project = var.project_id
region = var.region
}
locals {
service_src = "image-analysis"
service_name = "picture-uploaded"
bucket_name = "uploaded-pictures-${var.project_id}"
}
# List of services to enable
variable "gcp_services" {
type = list(string)
default = [
"appengine.googleapis.com",
"cloudbuild.googleapis.com",
"cloudfunctions.googleapis.com",
"firestore.googleapis.com",
"vision.googleapis.com"
]
}
# Enable services
resource "google_project_service" "services" {
for_each = toset(var.gcp_services)
service = each.value
disable_on_destroy = false
}
# Create a multi-region bucket with uniform bucket level access
resource "google_storage_bucket" "bucket" {
name = local.bucket_name
location = var.bucket_location
force_destroy = true
uniform_bucket_level_access = true
}
# Make the bucket public
resource "google_storage_bucket_iam_member" "member" {
bucket = google_storage_bucket.bucket.name
role = "roles/storage.objectViewer"
member = "allUsers"
}
# Create an App Engine app (requirement for Firestore) and Firestore
resource "google_app_engine_application" "default" {
project = var.project_id
location_id = var.region
database_type = "CLOUD_FIRESTORE"
depends_on = [
google_project_service.services
]
}
# Create Firestore index
resource "google_firestore_index" "default" {
collection = "pictures"
fields {
field_path = "thumbnail"
order = "DESCENDING"
}
fields {
field_path = "created"
order = "DESCENDING"
}
depends_on = [
google_project_service.services,
# Not depending on App Engine as it's only created
# once and subsequent creations will fail
#google_app_engine_application.default
]
}
# Zip the source code
data "archive_file" "default" {
type = "zip"
source_dir = "${path.module}/../../functions/${local.service_src}/nodejs/"
output_path = "tmp/${local.service_src}.zip"
excludes = [ "node_modules", "package-lock.json" ]
}
# Create a storage bucket for the source
resource "google_storage_bucket" "source" {
name = "source-${local.service_src}-${var.project_id}"
}
# Upload the zip to the bucket. The archive in Cloud Stoage uses the md5 of the zip file.
# This ensures the function is redeployed only when the source is changed.
resource "google_storage_bucket_object" "default" {
name = "${local.service_src}_${data.archive_file.default.output_md5}.zip"
bucket = google_storage_bucket.source.name
source = data.archive_file.default.output_path
depends_on = [data.archive_file.default, google_storage_bucket.source]
}
# Deploy the Cloud Function
## Node.js
resource "google_cloudfunctions_function" "default" {
name = local.service_name
region = var.region
source_archive_bucket = google_storage_bucket.source.name
source_archive_object = google_storage_bucket_object.default.name
runtime = "nodejs10"
entry_point = "vision_analysis"
event_trigger {
resource = local.bucket_name
event_type = "google.storage.object.finalize"
}
depends_on = [
google_project_service.services
]
}
# Make the function public
resource "google_cloudfunctions_function_iam_member" "invoker" {
cloud_function = google_cloudfunctions_function.default.name
role = "roles/cloudfunctions.invoker"
member = "allUsers"
}