Skip to content

Commit

Permalink
feat: Add MySQL support (#138)
Browse files Browse the repository at this point in the history
Co-authored-by: Akash Gangil <[email protected]>
Co-authored-by: Nim Jayawardena <[email protected]>
  • Loading branch information
3 people authored Sep 16, 2024
1 parent b4fef3c commit ab8330c
Show file tree
Hide file tree
Showing 12 changed files with 274 additions and 77 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Functional examples are included in the

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| database\_type | Cloud SQL Database flavor, mysql or postgresql | `string` | `"postgresql"` | no |
| deployment\_name | The name of this particular deployment, will get added as a prefix to most resources. | `string` | `"three-tier-app"` | no |
| enable\_apis | Whether or not to enable underlying apis in this solution. . | `string` | `true` | no |
| labels | A map of labels to apply to contained resources. | `map(string)` | <pre>{<br> "three-tier-app": true<br>}</pre> | no |
Expand Down
70 changes: 58 additions & 12 deletions build/int.cloudbuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,79 @@
# 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.

timeout: 5400s

steps:
- id: swap-module-refs
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['module-swapper']

- id: prepare
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && prepare_environment']
env:
- 'TF_VAR_org_id=$_ORG_ID'
- 'TF_VAR_folder_id=$_FOLDER_ID'
- 'TF_VAR_billing_account=$_LR_BILLING_ACCOUNT'

# Initialize all tests
- id: init-all
name: gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS
args: ['/bin/bash', '-c', 'cft test run all --stage init --verbose']

# Test the "simple example" deployment (which uses PostgreSQL)
- id: simple-example-init
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'cft test run TestSimpleExample --stage init --verbose']
name: gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS
waitFor: ['init-all']
script: |
#!/bin/bash -e
cft test run TestSimpleExample --stage init --verbose
- id: simple-example-apply
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'cft test run TestSimpleExample --stage apply --verbose']
name: gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS
waitFor: ['simple-example-init']
script: |
#!/bin/bash -e
cft test run TestSimpleExample --stage apply --verbose
- id: simple-example-verify
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'cft test run TestSimpleExample --stage verify --verbose']
- id: simple-example-teardown
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'cft test run TestSimpleExample --stage teardown --verbose']
- id: multiple-deploy
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'cft test run TestMultipleDeploy --verbose']
name: gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS
waitFor: ['simple-example-apply']
script: |
#!/bin/bash -e
cft test run TestSimpleExample --stage verify --verbose
- id: simple-example-destroy
name: gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS
waitFor: ['simple-example-verify']
script: |
#!/bin/bash -e
cft test run TestSimpleExample --stage destroy --verbose
# Test a deployment with MySQL
- id: mysql-init
name: gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS
waitFor: ['init-all']
script: |
#!/bin/bash -e
cft test run TestMysql --stage init --verbose
- id: mysql-apply
name: gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS
waitFor: ['mysql-init']
script: |
#!/bin/bash -e
cft test run TestMysql --stage apply --verbose
- id: mysql-verify
name: gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS
waitFor: ['mysql-apply']
script: |
#!/bin/bash -e
cft test run TestMysql --stage verify --verbose
- id: mysql-destroy
name: gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS
waitFor: ['mysql-verify']
script: |
#!/bin/bash -e
cft test run TestMysql --stage destroy --verbose
tags:
- 'ci'
- 'integration'
Expand Down
25 changes: 25 additions & 0 deletions examples/mysql/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# MySQL Example

This example illustrates how to use the `three-tier-app` module using Cloud SQL MySQL.

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| project\_id | The ID of the project in which to provision resources. | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| endpoint | The url of the front end which we want to surface to the user |
| sqlservername | The name of the database that we randomly generated. |

<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

To provision this example, run the following from within this directory:
- `terraform init` to get the plugins
- `terraform plan` to see the infrastructure plan
- `terraform apply` to apply the infrastructure build
- `terraform destroy` to destroy the built infrastructure
26 changes: 26 additions & 0 deletions examples/mysql/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Copyright 2024 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.
*/

module "three_tier_app" {
source = "GoogleCloudPlatform/three-tier-web-app/google"
version = "~> 0.1"

project_id = var.project_id
database_type = "mysql"
deployment_name = "three-tier-mysql"
region = "us-central1"
zone = "us-central1-a"
}
25 changes: 25 additions & 0 deletions examples/mysql/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Copyright 2024 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 "endpoint" {
value = module.three_tier_app.endpoint
description = "The url of the front end which we want to surface to the user"
}

output "sqlservername" {
value = module.three_tier_app.sqlservername
description = "The name of the database that we randomly generated."
}
20 changes: 20 additions & 0 deletions examples/mysql/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright 2024 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 "project_id" {
description = "The ID of the project in which to provision resources."
type = string
}
25 changes: 25 additions & 0 deletions examples/mysql/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Copyright 2024 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.
*/

terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 4.0"
}
}
required_version = ">= 0.13"
}
66 changes: 35 additions & 31 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,26 @@ data "google_project" "project" {
}

locals {
api_image = "gcr.io/sic-container-repo/todo-api-postgres:latest"
api_image = (var.database_type == "mysql" ? "gcr.io/sic-container-repo/todo-api" : "gcr.io/sic-container-repo/todo-api-postgres:latest")
fe_image = "gcr.io/sic-container-repo/todo-fe"

api_env_vars_postgresql = {
redis_host = google_redis_instance.main.host
db_host = google_sql_database_instance.main.ip_address[0].ip_address
db_user = google_service_account.runsa.email
db_conn = google_sql_database_instance.main.connection_name
db_name = "todo"
redis_port = "6379"
}

api_env_vars_mysql = {
REDISHOST = google_redis_instance.main.host
todo_host = google_sql_database_instance.main.ip_address[0].ip_address
todo_user = "foo"
todo_pass = "bar"
todo_name = "todo"
REDISPORT = "6379"
}
}

module "project-services" {
Expand Down Expand Up @@ -117,7 +135,7 @@ resource "random_id" "id" {
# Handle Database
resource "google_sql_database_instance" "main" {
name = "${var.deployment_name}-db-${random_id.id.hex}"
database_version = "POSTGRES_14"
database_version = (var.database_type == "mysql" ? "MYSQL_8_0" : "POSTGRES_14")
region = var.region
project = var.project_id

Expand All @@ -135,9 +153,12 @@ resource "google_sql_database_instance" "main" {
location_preference {
zone = var.zone
}
database_flags {
name = "cloudsql.iam_authentication"
value = "on"
dynamic "database_flags" {
for_each = var.database_type == "postgresql" ? [1] : []
content {
name = "cloudsql.iam_authentication"
value = "on"
}
}
}
deletion_protection = false
Expand All @@ -150,10 +171,11 @@ resource "google_sql_database_instance" "main" {

resource "google_sql_user" "main" {
project = var.project_id
name = "${google_service_account.runsa.account_id}@${var.project_id}.iam"
type = "CLOUD_IAM_SERVICE_ACCOUNT"
instance = google_sql_database_instance.main.name
deletion_policy = "ABANDON"
name = var.database_type == "postgresql" ? "${google_service_account.runsa.account_id}@${var.project_id}.iam" : "foo"
type = var.database_type == "postgresql" ? "CLOUD_IAM_SERVICE_ACCOUNT" : null
password = var.database_type == "mysql" ? "bar" : null
}

resource "google_sql_database" "database" {
Expand All @@ -174,31 +196,13 @@ resource "google_cloud_run_service" "api" {
service_account_name = google_service_account.runsa.email
containers {
image = local.api_image
env {
name = "redis_host"
value = google_redis_instance.main.host
}
env {
name = "db_host"
value = google_sql_database_instance.main.ip_address[0].ip_address
dynamic "env" {
for_each = var.database_type == "postgresql" ? local.api_env_vars_postgresql : local.api_env_vars_mysql
content {
name = env.key
value = env.value
}
}
env {
name = "db_user"
value = google_service_account.runsa.email
}
env {
name = "db_conn"
value = google_sql_database_instance.main.connection_name
}
env {
name = "db_name"
value = "todo"
}
env {
name = "redis_port"
value = "6379"
}

}
}

Expand Down
8 changes: 7 additions & 1 deletion metadata.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2023 Google LLC
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -44,10 +44,16 @@ spec:
- title: Architecture Diagram
url: assets/three_tier_web_app_v4.svg
examples:
- name: mysql
location: examples/mysql
- name: simple_example
location: examples/simple_example
interfaces:
variables:
- name: database_type
description: Cloud SQL Database flavor, mysql or postgresql
varType: string
defaultValue: postgresql
- name: deployment_name
description: The name of this particular deployment, will get added as a prefix to most resources.
varType: string
Expand Down
42 changes: 42 additions & 0 deletions test/integration/mysql/mysql_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2024 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.

package mysql

import (
"testing"
"time"

"github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/tft"
"github.com/stretchr/testify/assert"
)

// Retry if these errors are encountered.
var retryErrors = map[string]string{
// Error for Cloud SQL not deleting databases.
".*is being accessed by other users.*": "Database will eventually let you delete it",
".*SERVICE_DISABLED.*": "Service enablement is eventually consistent",
}

func TestMysql(t *testing.T) {
blueprintTest := tft.NewTFBlueprintTest(t, tft.WithRetryableTerraformErrors(retryErrors, 10, time.Minute))

blueprintTest.DefineVerify(func(assert *assert.Assertions) {
// DefaultVerify asserts no resource changes exist after apply.
// It helps ensure that a second "terraform apply" wouldn't result in resource deletions/replacements.
blueprintTest.DefaultVerify(assert)
})

blueprintTest.Test()
}
Loading

0 comments on commit ab8330c

Please sign in to comment.