From b2cef1cff2720f0a91fc859e4c497d1686eee454 Mon Sep 17 00:00:00 2001 From: Ryan C Koch Date: Mon, 30 Jul 2018 16:57:20 -0500 Subject: [PATCH] Adding new App Engine support (#4) * adding new app engine support * add test to verify app engine app created * don't delete default app engine service account * rename variable to REGION and set to us-east4 * better app_engine tests --- README.md | 1 + examples/app_engine/README.md | 13 +++++ examples/app_engine/main.tf | 46 ++++++++++++++++++ examples/app_engine/outputs.tf | 30 ++++++++++++ examples/app_engine/variables.tf | 27 +++++++++++ main.tf | 8 ++++ outputs.tf | 5 ++ test/integration/gcloud/integration.bats | 60 +++++++++++++++++------- test/integration/gcloud/run.sh | 10 ++++ test/integration/gcloud/sample.sh | 1 + variables.tf | 6 +++ 11 files changed, 191 insertions(+), 16 deletions(-) create mode 100755 examples/app_engine/README.md create mode 100755 examples/app_engine/main.tf create mode 100755 examples/app_engine/outputs.tf create mode 100755 examples/app_engine/variables.tf diff --git a/README.md b/README.md index 7e1ad405..5c85888f 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ In order to operate with the Service Account you must activate the following API - Cloud Billing API - cloudbilling.googleapis.com - Identity and Access Management API - iam.googleapis.com - Admin SDK - admin.googleapis.com +- Google App Engine Admin API - appengine.googleapis.com ### GSuite #### Admin diff --git a/examples/app_engine/README.md b/examples/app_engine/README.md new file mode 100755 index 00000000..1794fa3b --- /dev/null +++ b/examples/app_engine/README.md @@ -0,0 +1,13 @@ +# App Engine Project + +This example illustrates how to create a simple project with App Engine enabled. + +It will do the following: +- Create a project +- Active the Google App Engine Admin API on the new project +- Create a new App Engine app + +Expected variables: +- `admin_email` +- `organization_id` +- `billing_account` diff --git a/examples/app_engine/main.tf b/examples/app_engine/main.tf new file mode 100755 index 00000000..3959ce0c --- /dev/null +++ b/examples/app_engine/main.tf @@ -0,0 +1,46 @@ +/** + * Copyright 2018 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. + */ + +locals { + credentials_file_path = "${path.module}/sa-key.json" +} + +/****************************************** + Provider configuration + *****************************************/ +provider "gsuite" { + credentials = "${file(local.credentials_file_path)}" + impersonated_user_email = "${var.admin_email}" +} + +module "project-factory" { + source = "../../" + random_project_id = "true" + name = "appeng-sample" + org_id = "${var.organization_id}" + billing_account = "${var.billing_account}" + credentials_path = "${local.credentials_file_path}" + + app_engine { + location_id = "us-central" + + feature_settings = [ + { + split_health_checks = true + }, + ] + } +} diff --git a/examples/app_engine/outputs.tf b/examples/app_engine/outputs.tf new file mode 100755 index 00000000..5cc8dede --- /dev/null +++ b/examples/app_engine/outputs.tf @@ -0,0 +1,30 @@ +/** + * Copyright 2018 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. + */ + +output "project_info_example" { + value = "${module.project-factory.project_id}" + description = "The ID of the created project" +} + +output "domain_example" { + value = "${module.project-factory.domain}" + description = "The organization's domain" +} + +output "app_engine_enabled_example" { + value = "${module.project-factory.app_engine_enabled}" + description = "Whether app engine is enabled" +} diff --git a/examples/app_engine/variables.tf b/examples/app_engine/variables.tf new file mode 100755 index 00000000..9abe8149 --- /dev/null +++ b/examples/app_engine/variables.tf @@ -0,0 +1,27 @@ +/** + * Copyright 2018 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. + */ + +variable "admin_email" { + description = "Admin user email on Gsuite" +} + +variable "organization_id" { + description = "The organization id for the associated services" +} + +variable "billing_account" { + description = "The ID of the billing account to associate this project with" +} diff --git a/main.tf b/main.tf index 3f4d7c3c..498e3f08 100755 --- a/main.tf +++ b/main.tf @@ -37,6 +37,12 @@ locals { project_bucket_name = "${var.bucket_name != "" ? var.bucket_name : format("%s-state", var.name)}" create_bucket = "${var.bucket_project != "" ? "true" : "false"}" gsuite_group = "${var.group_name != "" || var.create_group}" + app_engine_enabled = "${length(keys(var.app_engine)) > 0 ? true : false}" + + app_engine_config = { + enabled = "${list(var.app_engine)}" + disabled = "${list()}" + } } /****************************************** @@ -76,6 +82,8 @@ resource "google_project" "project" { auto_create_network = "${var.auto_create_network}" labels = "${var.labels}" + + app_engine = "${local.app_engine_config["${local.app_engine_enabled ? "enabled" : "disabled"}"]}" } /****************************************** diff --git a/outputs.tf b/outputs.tf index 374bcc8e..f8742375 100755 --- a/outputs.tf +++ b/outputs.tf @@ -62,3 +62,8 @@ output "project_bucket_url" { value = "${google_storage_bucket.project_bucket.*.url}" description = "Project's bucket url" } + +output "app_engine_enabled" { + value = "${local.app_engine_enabled}" + description = "Whether app engine is enabled" +} diff --git a/test/integration/gcloud/integration.bats b/test/integration/gcloud/integration.bats index 50dde830..6d4ebf07 100755 --- a/test/integration/gcloud/integration.bats +++ b/test/integration/gcloud/integration.bats @@ -34,6 +34,24 @@ [[ "$output" =~ 0\ destroyed ]] } +@test "Terraform plan setting of App Engine settings" { + + run terraform plan + [ "$status" -eq 0 ] + [[ "$output" =~ 0\ to\ add ]] + [[ "$output" =~ 1\ to\ change ]] + [[ "$output" =~ 0\ to\ destroy ]] +} + +@test "Terraform apply" { + + run terraform apply -auto-approve + [ "$status" -eq 0 ] + [[ "$output" =~ 0\ added ]] + [[ "$output" =~ 1\ changed ]] + [[ "$output" =~ 0\ destroyed ]] +} + # #################################### # # gcloud tests # # #################################### # @@ -49,14 +67,18 @@ [[ "${lines[5]}" = "projectId: $PROJECT_ID" ]] } -@test "Test the compute api must be activated" { +@test "Test the correct apis are activated" { export PROJECT_ID="$(terraform output project_info_example)" export GROUP_EMAIL="$(terraform output group_email_example)" run gcloud services list [ "$status" -eq 0 ] - [[ "${lines[1]}" = *"compute.googleapis.com"* ]] + [[ "${lines[2]}" = *"compute.googleapis.com"* ]] + + run gcloud services list + [ "$status" -eq 0 ] + [[ "${lines[1]}" = *"appengine.googleapis.com"* ]] } @test "Test that project has the shared vpc associated (host project)" { @@ -69,25 +91,16 @@ [[ "${lines[1]}" = "$SHARED_VPC" ]] } -@test "Test project has the service account created" { - - export PROJECT_ID="$(terraform output project_info_example)" - export GROUP_EMAIL="$(terraform output group_email_example)" - - run gcloud iam service-accounts list --format=list - [ "$status" -eq 0 ] - [[ "${lines[1]}" = " email: project-service-account@$PROJECT_ID.iam.gserviceaccount.com" ]] -} - -@test "Test project has not the default service account" { +@test "Test project has only the expected service accounts" { export PROJECT_ID="$(terraform output project_info_example)" export GROUP_EMAIL="$(terraform output group_email_example)" - run gcloud iam service-accounts list + run gcloud iam service-accounts list --format="get(email)" [ "$status" -eq 0 ] - [[ "${lines[1]}" =~ project-service-account@$PROJECT_ID.iam.gserviceaccount.com ]] - [[ "${lines[2]}" = "" ]] + [[ "${lines[0]}" = "$PROJECT_ID@appspot.gserviceaccount.com" ]] + [[ "${lines[1]}" = "project-service-account@$PROJECT_ID.iam.gserviceaccount.com" ]] + [[ "${lines[3]}" = "" ]] } @test "Test Gsuite group $GROUP_EMAIL has role:$GROUP_ROLE on project" { @@ -132,6 +145,21 @@ [[ "$output" = *"{u'role': u'roles/compute.networkUser', u'members': [u'group:$GROUP_EMAIL', u'serviceAccount:project-service-account@$PROJECT_ID.iam.gserviceaccount.com']}"* ]] } +@test "Test App Engine app created with the correct settings" { + + PROJECT_ID="$(terraform output project_info_example)" + AUTH_DOMAIN="$(echo $GSUITE_ADMIN_ACCOUNT | cut -d '@' -f2)" + + run gcloud --project=${PROJECT_ID} app describe + [ "$status" -eq 0 ] + [[ "${lines[0]}" = "authDomain: $AUTH_DOMAIN" ]] + [[ "${lines[4]}" = "featureSettings: {}" ]] + [[ "${lines[6]}" = "id: $PROJECT_ID}" ]] + [[ "${lines[7]}" = "name: apps/$PROJECT_ID" ]] + [[ "${lines[8]}" = "locationId: $REGION" ]] + [[ "${lines[9]}" = "servingStatus: SERVING" ]] +} + # #################################### # # Terraform destroy test # # #################################### # diff --git a/test/integration/gcloud/run.sh b/test/integration/gcloud/run.sh index 65384884..07500b31 100755 --- a/test/integration/gcloud/run.sh +++ b/test/integration/gcloud/run.sh @@ -72,6 +72,16 @@ module "project-factory" { sa_group = "$SA_GROUP" folder_id = "$FOLDER_ID" credentials_path = "\${local.credentials_file_path}" + app_engine { + location_id = "$REGION" + auth_domain = "$(echo $GSUITE_ADMIN_ACCOUNT | cut -d '@' -f2)" + + feature_settings = [ + { + split_health_checks = false + }, + ] + } } EOF } diff --git a/test/integration/gcloud/sample.sh b/test/integration/gcloud/sample.sh index 2acab054..8eb9d57f 100644 --- a/test/integration/gcloud/sample.sh +++ b/test/integration/gcloud/sample.sh @@ -35,4 +35,5 @@ export GROUP_NAME="test-group$RANDOM" export CREATE_GROUP="true" export FOLDER_ID="" export GROUP_ROLE="roles/editor" +export REGION="us-east4" export CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE=$CREDENTIALS_PATH diff --git a/variables.tf b/variables.tf index 0271e7d7..6ff6cf70 100755 --- a/variables.tf +++ b/variables.tf @@ -112,3 +112,9 @@ variable "auto_create_network" { description = "Create the default network" default = "false" } + +variable "app_engine" { + description = "A map for app engine configuration" + type = "map" + default = {} +}