├── .gitignore ├── assets └── architecture.png ├── .github ├── renovate.json ├── release-please.yml ├── conventional-commit-lint.yaml ├── trusted-contribution.yml └── workflows │ ├── stale.yml │ ├── lint.yaml │ └── periodic-reporter.yaml ├── SECURITY.md ├── infra ├── modules │ ├── firestore │ │ ├── README.md │ │ ├── outputs.tf │ │ ├── versions.tf │ │ ├── variables.tf │ │ ├── main.tf │ │ ├── metadata.display.yaml │ │ └── metadata.yaml │ ├── storage │ │ ├── README.md │ │ ├── outputs.tf │ │ ├── versions.tf │ │ ├── main.tf │ │ ├── variables.tf │ │ ├── metadata.display.yaml │ │ └── metadata.yaml │ ├── networking │ │ ├── README.md │ │ ├── versions.tf │ │ ├── variables.tf │ │ ├── outputs.tf │ │ ├── metadata.display.yaml │ │ ├── main.tf │ │ └── metadata.yaml │ ├── cloudrun │ │ ├── outputs.tf │ │ ├── versions.tf │ │ ├── README.md │ │ ├── metadata.display.yaml │ │ ├── main.tf │ │ ├── variables.tf │ │ └── metadata.yaml │ └── load-balancer │ │ ├── versions.tf │ │ ├── README.md │ │ ├── outputs.tf │ │ ├── variables.tf │ │ ├── metadata.display.yaml │ │ ├── main.tf │ │ └── metadata.yaml ├── examples │ └── simple_example │ │ ├── README.md │ │ ├── main.tf │ │ ├── variables.tf │ │ └── outputs.tf ├── test │ ├── setup │ │ ├── versions.tf │ │ ├── outputs.tf │ │ ├── variables.tf │ │ ├── main.tf │ │ └── iam.tf │ └── integration │ │ ├── discover_test.go │ │ ├── go.mod │ │ └── simple_example │ │ └── simple_example_test.go ├── provider.tf ├── outputs.tf ├── metadata.display.yaml ├── Makefile ├── variables.tf ├── README.md ├── postdeployment.tf ├── metadata.yaml ├── main.tf └── files │ ├── lds_cdn_dashboard.tftpl │ └── lds_cloudrun_dashboard.tftpl ├── CODEOWNERS ├── tools └── prepare_services.sh ├── CONTRIBUTING.md ├── README.md ├── CHANGELOG.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | **/terraform.tfstate* 2 | **/.terraform* 3 | **/backend.tf 4 | **/terraform.tfplan 5 | **/values-*.yaml 6 | credentials.json 7 | -------------------------------------------------------------------------------- /assets/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/HEAD/assets/architecture.png -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["github>GoogleCloudPlatform/cloud-foundation-toolkit//infra/terraform/test-org/github/resources/renovate"] 4 | } 5 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | To report a security issue, please use [https://g.co/vulnz](https://g.co/vulnz). 2 | We use g.co/vulnz for our intake, and do coordination and disclosure here on 3 | GitHub (including using GitHub Security Advisory). The Google Security Team will 4 | respond within 5 working days of your report on g.co/vulnz. 5 | -------------------------------------------------------------------------------- /infra/modules/firestore/README.md: -------------------------------------------------------------------------------- 1 | # firestore module 2 | 3 | 4 | ## Inputs 5 | 6 | | Name | Description | Type | Default | Required | 7 | |------|-------------|------|---------|:--------:| 8 | | collection\_fields | collection id with respect to its fields | `map(any)` | n/a | yes | 9 | | firestore\_db\_name | firestore database name | `string` | n/a | yes | 10 | | project\_id | GCP project ID. | `string` | n/a | yes | 11 | 12 | ## Outputs 13 | 14 | | Name | Description | 15 | |------|-------------| 16 | | db\_name | Firestore database name | 17 | 18 | 19 | -------------------------------------------------------------------------------- /infra/modules/storage/README.md: -------------------------------------------------------------------------------- 1 | # storage module 2 | 3 | 4 | ## Inputs 5 | 6 | | Name | Description | Type | Default | Required | 7 | |------|-------------|------|---------|:--------:| 8 | | labels | A map of key/value label pairs to assign to the bucket. | `map(string)` | `{}` | no | 9 | | location | Bucket location | `string` | n/a | yes | 10 | | name | Bucket name | `string` | n/a | yes | 11 | | project\_id | GCP project ID. | `string` | n/a | yes | 12 | 13 | ## Outputs 14 | 15 | | Name | Description | 16 | |------|-------------| 17 | | bucket\_name | Bucket name | 18 | 19 | 20 | -------------------------------------------------------------------------------- /infra/modules/networking/README.md: -------------------------------------------------------------------------------- 1 | # networking module 2 | 3 | 4 | ## Inputs 5 | 6 | | Name | Description | Type | Default | Required | 7 | |------|-------------|------|---------|:--------:| 8 | | project\_id | GCP project ID. | `string` | n/a | yes | 9 | | region | Google cloud region where the resource will be created. | `string` | n/a | yes | 10 | 11 | ## Outputs 12 | 13 | | Name | Description | 14 | |------|-------------| 15 | | netowrk\_self\_link | Network self link | 16 | | subnet\_netowrk\_self\_link | Subnet netowrk self link | 17 | | vpc\_access\_connector\_id | VPC access connector id | 18 | 19 | 20 | -------------------------------------------------------------------------------- /infra/examples/simple_example/README.md: -------------------------------------------------------------------------------- 1 | # Simple Example 2 | 3 | 4 | ## Inputs 5 | 6 | | Name | Description | Type | Default | Required | 7 | |------|-------------|------|---------|:--------:| 8 | | project\_id | GCP project for provisioning cloud resources. | `any` | n/a | yes | 9 | 10 | ## Outputs 11 | 12 | | Name | Description | 13 | |------|-------------| 14 | | backend\_bucket\_name | The name of the backend bucket used for Cloud CDN | 15 | | cdn\_bucket\_name | The bucket name for cdn | 16 | | db\_name | The Firestore database name | 17 | | lb\_global\_ip | Frontend IP address of the load balancer | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/release-please.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | releaseType: terraform-module 16 | handleGHRelease: true 17 | primaryBranch: main 18 | bumpMinorPreMajor: true 19 | -------------------------------------------------------------------------------- /infra/examples/simple_example/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | module "simple" { 18 | source = "../../" 19 | project_id = var.project_id 20 | } 21 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # NOTE: This file is automatically generated from values at: 2 | # https://github.com/GoogleCloudPlatform/cloud-foundation-toolkit/blob/master/infra/terraform/test-org/org/locals.tf 3 | 4 | * @GoogleCloudPlatform/blueprint-solutions @GoogleCloudPlatform/torus-dpe @GoogleCloudPlatform/dee-platform-ops @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/jump-start-solutions-admins 5 | 6 | # NOTE: GitHub CODEOWNERS locations: 7 | # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners#codeowners-and-branch-protection 8 | 9 | CODEOWNERS @GoogleCloudPlatform/blueprint-solutions 10 | .github/CODEOWNERS @GoogleCloudPlatform/blueprint-solutions 11 | docs/CODEOWNERS @GoogleCloudPlatform/blueprint-solutions 12 | 13 | -------------------------------------------------------------------------------- /infra/examples/simple_example/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | variable "project_id" { 18 | description = "GCP project for provisioning cloud resources." 19 | } 20 | -------------------------------------------------------------------------------- /infra/modules/storage/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | output "bucket_name" { 18 | description = "Bucket name" 19 | value = google_storage_bucket.main.name 20 | } 21 | -------------------------------------------------------------------------------- /infra/modules/cloudrun/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | output "cloud_run" { 18 | description = "Cloud Run service" 19 | value = google_cloud_run_v2_service.main 20 | } 21 | -------------------------------------------------------------------------------- /infra/modules/firestore/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | output "db_name" { 18 | description = "Firestore database name" 19 | value = google_firestore_database.default.name 20 | } 21 | -------------------------------------------------------------------------------- /tools/prepare_services.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | PROJECT_ID=$(gcloud config get-value project) 18 | 19 | gcloud config set project "$PROJECT_ID" 20 | 21 | gcloud services enable cloudresourcemanager.googleapis.com 22 | -------------------------------------------------------------------------------- /infra/test/setup/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | terraform { 18 | required_version = ">= 0.13" 19 | required_providers { 20 | google = { 21 | source = "hashicorp/google" 22 | version = "~> 4.57" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /infra/modules/cloudrun/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | terraform { 18 | required_version = ">= 0.13" 19 | required_providers { 20 | google = { 21 | source = "hashicorp/google" 22 | version = "~> 4.57" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /infra/modules/networking/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | terraform { 18 | required_version = ">= 0.13" 19 | required_providers { 20 | google = { 21 | source = "hashicorp/google" 22 | version = "~> 4.57" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /infra/modules/storage/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | terraform { 18 | required_version = ">= 0.13" 19 | required_providers { 20 | google = { 21 | source = "hashicorp/google" 22 | version = "~> 4.57" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.github/conventional-commit-lint.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022-2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # NOTE: This file is automatically generated from: 16 | # https://github.com/GoogleCloudPlatform/cloud-foundation-toolkit/blob/master/infra/terraform/test-org/github 17 | 18 | enabled: true 19 | always_check_pr_title: true 20 | -------------------------------------------------------------------------------- /infra/modules/load-balancer/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | terraform { 18 | required_version = ">= 0.13" 19 | required_providers { 20 | google = { 21 | source = "hashicorp/google" 22 | version = "~> 4.57" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /infra/modules/firestore/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | terraform { 18 | required_version = ">= 0.13" 19 | required_providers { 20 | google = { 21 | source = "hashicorp/google" 22 | version = ">= 4.57, <= 4.84, != 4.75.0" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /infra/test/integration/discover_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package test 16 | 17 | import ( 18 | "testing" 19 | 20 | "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/tft" 21 | ) 22 | 23 | func TestAll(t *testing.T) { 24 | tft.AutoDiscoverAndTest(t) 25 | } 26 | -------------------------------------------------------------------------------- /infra/modules/networking/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | variable "project_id" { 18 | description = "GCP project ID." 19 | type = string 20 | } 21 | 22 | variable "region" { 23 | description = "Google cloud region where the resource will be created." 24 | type = string 25 | } 26 | -------------------------------------------------------------------------------- /infra/test/setup/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | output "project_id" { 18 | value = module.project.project_id 19 | } 20 | 21 | output "sa_key" { 22 | value = google_service_account_key.int_test.private_key 23 | sensitive = true 24 | } 25 | 26 | output "delete_contents_on_destroy" { 27 | value = true 28 | } 29 | -------------------------------------------------------------------------------- /infra/modules/load-balancer/README.md: -------------------------------------------------------------------------------- 1 | # load-balancer module 2 | 3 | 4 | ## Inputs 5 | 6 | | Name | Description | Type | Default | Required | 7 | |------|-------------|------|---------|:--------:| 8 | | bucket\_name | Bucket name | `string` | n/a | yes | 9 | | client\_service\_name | Frontend service name | `string` | n/a | yes | 10 | | labels | A map of key/value label pairs to assign to the bucket. | `map(string)` | n/a | yes | 11 | | project\_id | GCP project ID. | `string` | n/a | yes | 12 | | region | Google cloud region where the resource will be created. | `string` | n/a | yes | 13 | | resource\_path | Resource folder path | `string` | n/a | yes | 14 | 15 | ## Outputs 16 | 17 | | Name | Description | 18 | |------|-------------| 19 | | backend\_bucket\_name | The name of the backend bucket used for Cloud CDN | 20 | | lb\_external\_ip | Frontend IP address of the load balancer | 21 | 22 | 23 | -------------------------------------------------------------------------------- /infra/test/setup/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | variable "org_id" { 18 | description = "The numeric organization id" 19 | } 20 | 21 | variable "folder_id" { 22 | description = "The folder to deploy in" 23 | } 24 | 25 | variable "billing_account" { 26 | description = "The billing account id associated with the project, e.g. XXXXXX-YYYYYY-ZZZZZZ" 27 | } 28 | -------------------------------------------------------------------------------- /.github/trusted-contribution.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # NOTE: This file is automatically generated from: 16 | # https://github.com/GoogleCloudPlatform/cloud-foundation-toolkit/blob/master/infra/terraform/test-org/github 17 | 18 | annotations: 19 | - type: comment 20 | text: "/gcbrun" 21 | trustedContributors: 22 | - release-please[bot] 23 | - renovate[bot] 24 | - renovate-bot 25 | - forking-renovate[bot] 26 | - dependabot[bot] 27 | -------------------------------------------------------------------------------- /infra/modules/load-balancer/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | output "lb_external_ip" { 18 | description = "Frontend IP address of the load balancer" 19 | value = google_compute_global_forwarding_rule.lds.ip_address 20 | } 21 | 22 | output "backend_bucket_name" { 23 | description = "The name of the backend bucket used for Cloud CDN" 24 | value = google_compute_backend_bucket.cdn.name 25 | } 26 | -------------------------------------------------------------------------------- /infra/modules/firestore/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | variable "project_id" { 18 | description = "GCP project ID." 19 | type = string 20 | } 21 | 22 | variable "collection_fields" { 23 | description = "collection id with respect to its fields" 24 | type = map(any) 25 | } 26 | 27 | variable "firestore_db_name" { 28 | description = "firestore database name" 29 | type = string 30 | } 31 | -------------------------------------------------------------------------------- /infra/provider.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | terraform { 18 | required_version = ">= 0.13" 19 | required_providers { 20 | google = { 21 | source = "hashicorp/google" 22 | version = "<= 4.84, != 4.75.0" 23 | } 24 | random = { 25 | source = "hashicorp/random" 26 | version = "~> 3.4" 27 | } 28 | } 29 | } 30 | 31 | provider "google" { 32 | project = var.project_id 33 | region = var.region 34 | } 35 | -------------------------------------------------------------------------------- /infra/modules/storage/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | resource "google_storage_bucket" "main" { 18 | project = var.project_id 19 | name = var.name 20 | location = var.location 21 | labels = var.labels 22 | force_destroy = true 23 | } 24 | 25 | resource "google_storage_default_object_acl" "policy" { 26 | bucket = google_storage_bucket.main.name 27 | role_entity = [ 28 | "READER:allUsers", 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /infra/modules/networking/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | output "netowrk_self_link" { 18 | description = "Network self link" 19 | value = google_compute_network.main.self_link 20 | } 21 | 22 | output "subnet_netowrk_self_link" { 23 | description = "Subnet netowrk self link" 24 | value = google_compute_subnetwork.main.self_link 25 | } 26 | 27 | output "vpc_access_connector_id" { 28 | description = "VPC access connector id" 29 | value = google_vpc_access_connector.main.id 30 | } 31 | -------------------------------------------------------------------------------- /infra/modules/storage/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | variable "project_id" { 18 | description = "GCP project ID." 19 | type = string 20 | } 21 | 22 | variable "name" { 23 | description = "Bucket name" 24 | type = string 25 | } 26 | 27 | variable "location" { 28 | description = "Bucket location" 29 | type = string 30 | } 31 | 32 | variable "labels" { 33 | type = map(string) 34 | description = "A map of key/value label pairs to assign to the bucket." 35 | default = {} 36 | } 37 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. 4 | 5 | ## Before you begin 6 | 7 | ### Sign our Contributor License Agreement 8 | 9 | Contributions to this project must be accompanied by a 10 | [Contributor License Agreement](https://cla.developers.google.com/about) (CLA). 11 | You (or your employer) retain the copyright to your contribution; this simply 12 | gives us permission to use and redistribute your contributions as part of the 13 | project. 14 | 15 | If you or your current employer have already signed the Google CLA (even if it 16 | was for a different project), you probably don't need to do it again. 17 | 18 | Visit to see your current agreements or to 19 | sign a new one. 20 | 21 | ### Review our Community Guidelines 22 | 23 | This project follows 24 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/). 25 | 26 | ## Contribution process 27 | 28 | ### Code Reviews 29 | 30 | All submissions, including submissions by project members, require review. We 31 | use GitHub pull requests for this purpose. Consult 32 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 33 | information on using pull requests. 34 | -------------------------------------------------------------------------------- /infra/examples/simple_example/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | output "lb_global_ip" { 18 | description = "Frontend IP address of the load balancer" 19 | value = module.simple.lb_external_ip 20 | } 21 | 22 | output "backend_bucket_name" { 23 | description = "The name of the backend bucket used for Cloud CDN" 24 | value = module.simple.backend_bucket_name 25 | } 26 | 27 | output "cdn_bucket_name" { 28 | description = "The bucket name for cdn" 29 | value = module.simple.bucket_name 30 | } 31 | 32 | output "db_name" { 33 | description = "The Firestore database name" 34 | value = module.simple.db_name 35 | } 36 | -------------------------------------------------------------------------------- /infra/modules/networking/metadata.display.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: blueprints.cloud.google.com/v1alpha1 16 | kind: BlueprintMetadata 17 | metadata: 18 | name: terraform-large-data-sharing-golang-webapp-networking-display 19 | annotations: 20 | config.kubernetes.io/local-config: "true" 21 | spec: 22 | info: 23 | title: networking module 24 | source: 25 | repo: https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp.git 26 | sourceType: git 27 | dir: /infra/modules/networking 28 | ui: 29 | input: 30 | variables: 31 | project_id: 32 | name: project_id 33 | title: Project Id 34 | region: 35 | name: region 36 | title: Region 37 | -------------------------------------------------------------------------------- /infra/modules/firestore/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | resource "google_firestore_database" "default" { 18 | project = var.project_id 19 | name = var.firestore_db_name 20 | location_id = "nam5" //US 21 | type = "FIRESTORE_NATIVE" 22 | } 23 | 24 | resource "google_firestore_index" "meta" { 25 | 26 | for_each = var.collection_fields 27 | collection = each.key 28 | database = google_firestore_database.default.name 29 | dynamic "fields" { 30 | for_each = each.value 31 | iterator = field 32 | content { 33 | field_path = lookup(field.value, "field_path", null) 34 | order = lookup(field.value, "order", null) 35 | array_config = lookup(field.value, "array_config", null) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /infra/modules/load-balancer/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | variable "project_id" { 18 | description = "GCP project ID." 19 | type = string 20 | } 21 | 22 | variable "region" { 23 | description = "Google cloud region where the resource will be created." 24 | type = string 25 | } 26 | 27 | variable "bucket_name" { 28 | description = "Bucket name" 29 | type = string 30 | } 31 | 32 | variable "client_service_name" { 33 | description = "Frontend service name" 34 | type = string 35 | } 36 | 37 | variable "resource_path" { 38 | description = "Resource folder path" 39 | type = string 40 | } 41 | 42 | variable "labels" { 43 | description = "A map of key/value label pairs to assign to the bucket." 44 | type = map(string) 45 | } 46 | -------------------------------------------------------------------------------- /infra/test/setup/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | module "project" { 18 | source = "terraform-google-modules/project-factory/google" 19 | version = "~> 14.0" 20 | 21 | name = "ci-lds" 22 | random_project_id = "true" 23 | org_id = var.org_id 24 | folder_id = var.folder_id 25 | billing_account = var.billing_account 26 | default_service_account = "keep" 27 | 28 | activate_apis = [ 29 | "cloudresourcemanager.googleapis.com", 30 | "compute.googleapis.com", 31 | "run.googleapis.com", 32 | "iam.googleapis.com", 33 | "firestore.googleapis.com", 34 | "vpcaccess.googleapis.com", 35 | "serviceusage.googleapis.com", 36 | "monitoring.googleapis.com", 37 | "cloudtrace.googleapis.com" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /infra/modules/firestore/metadata.display.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: blueprints.cloud.google.com/v1alpha1 16 | kind: BlueprintMetadata 17 | metadata: 18 | name: terraform-large-data-sharing-golang-webapp-firestore-display 19 | annotations: 20 | config.kubernetes.io/local-config: "true" 21 | spec: 22 | info: 23 | title: firestore module 24 | source: 25 | repo: https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp.git 26 | sourceType: git 27 | dir: /infra/modules/firestore 28 | ui: 29 | input: 30 | variables: 31 | collection_fields: 32 | name: collection_fields 33 | title: Collection Fields 34 | init: 35 | name: init 36 | title: Init 37 | project_id: 38 | name: project_id 39 | title: Project Id 40 | -------------------------------------------------------------------------------- /infra/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | output "lb_external_ip" { 18 | description = "Frontend IP address of the load balancer" 19 | value = module.load_balancer.lb_external_ip 20 | } 21 | 22 | output "backend_bucket_name" { 23 | description = "The name of the backend bucket used for Cloud CDN" 24 | value = module.load_balancer.backend_bucket_name 25 | } 26 | 27 | output "bucket_name" { 28 | description = "Bucket name" 29 | value = module.storage.bucket_name 30 | } 31 | 32 | output "db_name" { 33 | description = "Firestore database name" 34 | value = module.firestore.db_name 35 | } 36 | 37 | output "neos_walkthrough_url" { 38 | description = "Neos Tutorial URL" 39 | value = "https://console.cloud.google.com/products/solutions/deployments?walkthrough_id=panels--sic--large-data-sharing-golang_toc" 40 | } 41 | -------------------------------------------------------------------------------- /infra/modules/networking/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | resource "google_compute_network" "main" { 18 | project = var.project_id 19 | name = "lds-network-golang" 20 | auto_create_subnetworks = true 21 | } 22 | 23 | resource "google_compute_subnetwork" "main" { 24 | region = var.region 25 | network = google_compute_network.main.id 26 | name = "lds-vpc-connector-subnetwork-golang" 27 | private_ip_google_access = true 28 | 29 | # Subnets used for VPC connectors must have a netmask of 28. 30 | ip_cidr_range = "10.2.0.0/28" 31 | } 32 | 33 | resource "google_vpc_access_connector" "main" { 34 | project = var.project_id 35 | region = var.region 36 | name = "lds-vpc-connector-golang" 37 | subnet { 38 | name = google_compute_subnetwork.main.name 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /infra/modules/storage/metadata.display.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: blueprints.cloud.google.com/v1alpha1 16 | kind: BlueprintMetadata 17 | metadata: 18 | name: terraform-large-data-sharing-golang-webapp-storage-display 19 | annotations: 20 | config.kubernetes.io/local-config: "true" 21 | spec: 22 | info: 23 | title: storage module 24 | source: 25 | repo: https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp.git 26 | sourceType: git 27 | dir: /infra/modules/storage 28 | ui: 29 | input: 30 | variables: 31 | labels: 32 | name: labels 33 | title: Labels 34 | location: 35 | name: location 36 | title: Location 37 | name: 38 | name: name 39 | title: Name 40 | project_id: 41 | name: project_id 42 | title: Project Id 43 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022-2024 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # NOTE: This file is automatically generated from: 16 | # https://github.com/GoogleCloudPlatform/cloud-foundation-toolkit/blob/master/infra/terraform/test-org/github 17 | 18 | name: "Close stale issues" 19 | on: 20 | schedule: 21 | - cron: "0 23 * * *" 22 | 23 | jobs: 24 | stale: 25 | if: github.repository_owner == 'GoogleCloudPlatform' || github.repository_owner == 'terraform-google-modules' 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: actions/stale@v9 29 | with: 30 | repo-token: ${{ secrets.GITHUB_TOKEN }} 31 | stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days' 32 | stale-pr-message: 'This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days' 33 | exempt-issue-labels: 'triaged' 34 | exempt-pr-labels: 'dependencies,autorelease: pending' 35 | -------------------------------------------------------------------------------- /infra/test/setup/iam.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | locals { 18 | int_required_roles = [ 19 | "roles/storage.admin", 20 | "roles/datastore.owner", 21 | "roles/appengine.appAdmin", 22 | "roles/compute.admin", 23 | "roles/compute.networkAdmin", 24 | "roles/cloudtrace.admin", 25 | "roles/iam.serviceAccountAdmin", 26 | "roles/iam.serviceAccountUser", 27 | "roles/resourcemanager.projectIamAdmin", 28 | "roles/run.admin", 29 | "roles/monitoring.admin", 30 | "roles/vpcaccess.admin", 31 | ] 32 | } 33 | 34 | resource "google_service_account" "int_test" { 35 | project = module.project.project_id 36 | account_id = "ci-jss" 37 | display_name = "ci-jss" 38 | } 39 | 40 | resource "google_project_iam_member" "int_test" { 41 | for_each = toset(local.int_required_roles) 42 | 43 | project = module.project.project_id 44 | role = each.value 45 | member = "serviceAccount:${google_service_account.int_test.email}" 46 | } 47 | 48 | resource "google_service_account_key" "int_test" { 49 | service_account_id = google_service_account.int_test.id 50 | } 51 | -------------------------------------------------------------------------------- /infra/modules/load-balancer/metadata.display.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: blueprints.cloud.google.com/v1alpha1 16 | kind: BlueprintMetadata 17 | metadata: 18 | name: terraform-large-data-sharing-golang-webapp-load-balancer-display 19 | annotations: 20 | config.kubernetes.io/local-config: "true" 21 | spec: 22 | info: 23 | title: load-balancer module 24 | source: 25 | repo: https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp.git 26 | sourceType: git 27 | dir: /infra/modules/load-balancer 28 | ui: 29 | input: 30 | variables: 31 | bucket_name: 32 | name: bucket_name 33 | title: Bucket Name 34 | client_service_name: 35 | name: client_service_name 36 | title: Client Service Name 37 | labels: 38 | name: labels 39 | title: Labels 40 | project_id: 41 | name: project_id 42 | title: Project Id 43 | region: 44 | name: region 45 | title: Region 46 | resource_path: 47 | name: resource_path 48 | title: Resource Path 49 | -------------------------------------------------------------------------------- /infra/modules/cloudrun/README.md: -------------------------------------------------------------------------------- 1 | # cloudrun module 2 | 3 | 4 | ## Inputs 5 | 6 | | Name | Description | Type | Default | Required | 7 | |------|-------------|------|---------|:--------:| 8 | | cloud\_run\_image | Docker image for Cloud Run | `string` | n/a | yes | 9 | | cloud\_run\_name | Name of Cloud Run | `string` | n/a | yes | 10 | | container\_port | Container port | `string` | n/a | yes | 11 | | env\_vars | Environment variables |
list(object({
value = string
name = string
}))
| `[]` | no | 12 | | ingress | Ingress of Cloud Run | `string` | n/a | yes | 13 | | labels | A map of key/value label pairs to assign to the bucket | `map(string)` | n/a | yes | 14 | | limits | Resource limits to the container | `map(string)` | n/a | yes | 15 | | liveness\_probe | helth check |
object(
{
initial_delay_seconds = number,
timeout_seconds = number,
period_seconds = number,
failure_threshold = number,
http_get = object(
{
path = string
}
)
}
)
|
{
"failure_threshold": 3,
"http_get": {
"path": "/"
},
"initial_delay_seconds": 600,
"period_seconds": 300,
"timeout_seconds": 60
}
| no | 16 | | location | Google cloud location where the resource will be created | `string` | n/a | yes | 17 | | project\_id | GCP project ID | `string` | n/a | yes | 18 | | service\_account\_email | cloud run service account email | `string` | n/a | yes | 19 | | vpc\_access\_connector\_id | VPC access connector id | `string` | n/a | yes | 20 | | vpc\_egress | VPC access egress | `string` | n/a | yes | 21 | 22 | ## Outputs 23 | 24 | | Name | Description | 25 | |------|-------------| 26 | | cloud\_run | Cloud Run service | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # NOTE: This file is automatically generated from values at: 16 | # https://github.com/GoogleCloudPlatform/cloud-foundation-toolkit/blob/master/infra/terraform/test-org/org/locals.tf 17 | 18 | name: 'lint' 19 | 20 | on: 21 | workflow_dispatch: 22 | pull_request: 23 | branches: 24 | - main 25 | 26 | concurrency: 27 | group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}' 28 | cancel-in-progress: true 29 | 30 | jobs: 31 | lint: 32 | name: 'lint' 33 | runs-on: 'ubuntu-latest' 34 | steps: 35 | - uses: 'actions/checkout@v4' 36 | - id: variables 37 | run: | 38 | MAKEFILE=$(find . -name Makefile -print -quit) 39 | if [ -z "$MAKEFILE" ]; then 40 | echo dev-tools=gcr.io/cloud-foundation-cicd/cft/developer-tools:1 >> "$GITHUB_OUTPUT" 41 | else 42 | VERSION=$(grep "DOCKER_TAG_VERSION_DEVELOPER_TOOLS := " $MAKEFILE | cut -d\ -f3) 43 | IMAGE=$(grep "DOCKER_IMAGE_DEVELOPER_TOOLS := " $MAKEFILE | cut -d\ -f3) 44 | REGISTRY=$(grep "REGISTRY_URL := " $MAKEFILE | cut -d\ -f3) 45 | echo dev-tools=${REGISTRY}/${IMAGE}:${VERSION} >> "$GITHUB_OUTPUT" 46 | fi 47 | - run: docker run --rm -e ENABLE_BPMETADATA -v ${{ github.workspace }}:/workspace ${{ steps.variables.outputs.dev-tools }} module-swapper 48 | env: 49 | ENABLE_BPMETADATA: 1 50 | 51 | - run: docker run --rm -e ENABLE_BPMETADATA -v ${{ github.workspace }}:/workspace ${{ steps.variables.outputs.dev-tools }} /usr/local/bin/test_lint.sh 52 | env: 53 | ENABLE_BPMETADATA: 1 54 | 55 | -------------------------------------------------------------------------------- /infra/modules/cloudrun/metadata.display.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: blueprints.cloud.google.com/v1alpha1 16 | kind: BlueprintMetadata 17 | metadata: 18 | name: terraform-large-data-sharing-golang-webapp-cloudrun-display 19 | annotations: 20 | config.kubernetes.io/local-config: "true" 21 | spec: 22 | info: 23 | title: cloudrun module 24 | source: 25 | repo: https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp.git 26 | sourceType: git 27 | dir: /infra/modules/cloudrun 28 | ui: 29 | input: 30 | variables: 31 | cloud_run_image: 32 | name: cloud_run_image 33 | title: Cloud Run Image 34 | cloud_run_name: 35 | name: cloud_run_name 36 | title: Cloud Run Name 37 | container_port: 38 | name: container_port 39 | title: Container Port 40 | env_vars: 41 | name: env_vars 42 | title: Env Vars 43 | ingress: 44 | name: ingress 45 | title: Ingress 46 | labels: 47 | name: labels 48 | title: Labels 49 | limits: 50 | name: limits 51 | title: Limits 52 | liveness_probe: 53 | name: liveness_probe 54 | title: Liveness Probe 55 | location: 56 | name: location 57 | title: Location 58 | project_id: 59 | name: project_id 60 | title: Project Id 61 | service_account_email: 62 | name: service_account_email 63 | title: Service Account Email 64 | vpc_access_connector_id: 65 | name: vpc_access_connector_id 66 | title: Vpc Access Connector Id 67 | vpc_egress: 68 | name: vpc_egress 69 | title: Vpc Egress 70 | -------------------------------------------------------------------------------- /infra/modules/cloudrun/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | resource "google_cloud_run_v2_service" "main" { 18 | name = var.cloud_run_name 19 | location = var.location 20 | ingress = var.ingress 21 | template { 22 | service_account = var.service_account_email 23 | scaling { 24 | max_instance_count = 4 25 | } 26 | containers { 27 | image = var.cloud_run_image 28 | liveness_probe { 29 | initial_delay_seconds = lookup(var.liveness_probe, "initial_delay_seconds", null) 30 | timeout_seconds = lookup(var.liveness_probe, "timeout_seconds", null) 31 | period_seconds = lookup(var.liveness_probe, "period_seconds", null) 32 | failure_threshold = lookup(var.liveness_probe, "failure_threshold", null) 33 | http_get { 34 | path = lookup(var.liveness_probe.http_get, "path", null) 35 | } 36 | } 37 | resources { 38 | limits = var.limits 39 | cpu_idle = true 40 | } 41 | dynamic "env" { 42 | for_each = var.env_vars 43 | content { 44 | name = env.value["name"] 45 | value = env.value["value"] 46 | } 47 | } 48 | ports { 49 | container_port = var.container_port 50 | } 51 | } 52 | vpc_access { 53 | connector = var.vpc_access_connector_id 54 | egress = var.vpc_egress 55 | } 56 | } 57 | labels = var.labels 58 | } 59 | 60 | resource "google_cloud_run_service_iam_policy" "policy" { 61 | project = var.project_id 62 | location = var.location 63 | service = google_cloud_run_v2_service.main.name 64 | policy_data = data.google_iam_policy.cloud_run.policy_data 65 | } 66 | 67 | data "google_iam_policy" "cloud_run" { 68 | binding { 69 | role = "roles/run.invoker" 70 | members = [ 71 | "allUsers" 72 | ] 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /infra/modules/firestore/metadata.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: blueprints.cloud.google.com/v1alpha1 16 | kind: BlueprintMetadata 17 | metadata: 18 | name: terraform-large-data-sharing-golang-webapp-firestore 19 | annotations: 20 | config.kubernetes.io/local-config: "true" 21 | spec: 22 | info: 23 | title: firestore module 24 | source: 25 | repo: https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp.git 26 | sourceType: git 27 | dir: /infra/modules/firestore 28 | actuationTool: 29 | flavor: Terraform 30 | version: '>= 0.13' 31 | description: {} 32 | content: 33 | examples: 34 | - name: simple_example 35 | location: examples/simple_example 36 | interfaces: 37 | variables: 38 | - name: collection_fields 39 | description: collection id with respect to its fields 40 | varType: map(any) 41 | required: true 42 | - name: init 43 | description: Initialize resource or not 44 | varType: bool 45 | required: true 46 | - name: project_id 47 | description: GCP project ID. 48 | varType: string 49 | required: true 50 | requirements: 51 | roles: 52 | - level: Project 53 | roles: 54 | - roles/storage.admin 55 | - roles/datastore.owner 56 | - roles/appengine.appAdmin 57 | - roles/compute.admin 58 | - roles/compute.networkAdmin 59 | - roles/cloudtrace.admin 60 | - roles/iam.serviceAccountAdmin 61 | - roles/iam.serviceAccountUser 62 | - roles/resourcemanager.projectIamAdmin 63 | - roles/run.admin 64 | - roles/monitoring.admin 65 | - roles/vpcaccess.admin 66 | services: 67 | - cloudresourcemanager.googleapis.com 68 | - compute.googleapis.com 69 | - run.googleapis.com 70 | - iam.googleapis.com 71 | - firestore.googleapis.com 72 | - vpcaccess.googleapis.com 73 | - serviceusage.googleapis.com 74 | - monitoring.googleapis.com 75 | - cloudtrace.googleapis.com 76 | -------------------------------------------------------------------------------- /infra/modules/networking/metadata.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: blueprints.cloud.google.com/v1alpha1 16 | kind: BlueprintMetadata 17 | metadata: 18 | name: terraform-large-data-sharing-golang-webapp-networking 19 | annotations: 20 | config.kubernetes.io/local-config: "true" 21 | spec: 22 | info: 23 | title: networking module 24 | source: 25 | repo: https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp.git 26 | sourceType: git 27 | dir: /infra/modules/networking 28 | actuationTool: 29 | flavor: Terraform 30 | version: '>= 0.13' 31 | description: {} 32 | content: 33 | examples: 34 | - name: simple_example 35 | location: examples/simple_example 36 | interfaces: 37 | variables: 38 | - name: project_id 39 | description: GCP project ID. 40 | varType: string 41 | required: true 42 | - name: region 43 | description: Google cloud region where the resource will be created. 44 | varType: string 45 | required: true 46 | outputs: 47 | - name: netowrk_self_link 48 | description: Network self link 49 | - name: subnet_netowrk_self_link 50 | description: Subnet netowrk self link 51 | - name: vpc_access_connector_id 52 | description: VPC access connector id 53 | requirements: 54 | roles: 55 | - level: Project 56 | roles: 57 | - roles/storage.admin 58 | - roles/datastore.owner 59 | - roles/appengine.appAdmin 60 | - roles/compute.admin 61 | - roles/compute.networkAdmin 62 | - roles/cloudtrace.admin 63 | - roles/iam.serviceAccountAdmin 64 | - roles/iam.serviceAccountUser 65 | - roles/resourcemanager.projectIamAdmin 66 | - roles/run.admin 67 | - roles/monitoring.admin 68 | - roles/vpcaccess.admin 69 | services: 70 | - cloudresourcemanager.googleapis.com 71 | - compute.googleapis.com 72 | - run.googleapis.com 73 | - iam.googleapis.com 74 | - firestore.googleapis.com 75 | - vpcaccess.googleapis.com 76 | - serviceusage.googleapis.com 77 | - monitoring.googleapis.com 78 | - cloudtrace.googleapis.com 79 | -------------------------------------------------------------------------------- /infra/modules/storage/metadata.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: blueprints.cloud.google.com/v1alpha1 16 | kind: BlueprintMetadata 17 | metadata: 18 | name: terraform-large-data-sharing-golang-webapp-storage 19 | annotations: 20 | config.kubernetes.io/local-config: "true" 21 | spec: 22 | info: 23 | title: storage module 24 | source: 25 | repo: https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp.git 26 | sourceType: git 27 | dir: /infra/modules/storage 28 | actuationTool: 29 | flavor: Terraform 30 | version: '>= 0.13' 31 | description: {} 32 | content: 33 | examples: 34 | - name: simple_example 35 | location: examples/simple_example 36 | interfaces: 37 | variables: 38 | - name: labels 39 | description: A map of key/value label pairs to assign to the bucket. 40 | varType: map(string) 41 | defaultValue: {} 42 | - name: location 43 | description: Bucket location 44 | varType: string 45 | required: true 46 | - name: name 47 | description: Bucket name 48 | varType: string 49 | required: true 50 | - name: project_id 51 | description: GCP project ID. 52 | varType: string 53 | required: true 54 | outputs: 55 | - name: bucket_name 56 | description: Bucket name 57 | requirements: 58 | roles: 59 | - level: Project 60 | roles: 61 | - roles/storage.admin 62 | - roles/datastore.owner 63 | - roles/appengine.appAdmin 64 | - roles/compute.admin 65 | - roles/compute.networkAdmin 66 | - roles/cloudtrace.admin 67 | - roles/iam.serviceAccountAdmin 68 | - roles/iam.serviceAccountUser 69 | - roles/resourcemanager.projectIamAdmin 70 | - roles/run.admin 71 | - roles/monitoring.admin 72 | - roles/vpcaccess.admin 73 | services: 74 | - cloudresourcemanager.googleapis.com 75 | - compute.googleapis.com 76 | - run.googleapis.com 77 | - iam.googleapis.com 78 | - firestore.googleapis.com 79 | - vpcaccess.googleapis.com 80 | - serviceusage.googleapis.com 81 | - monitoring.googleapis.com 82 | - cloudtrace.googleapis.com 83 | -------------------------------------------------------------------------------- /infra/metadata.display.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: blueprints.cloud.google.com/v1alpha1 16 | kind: BlueprintMetadata 17 | metadata: 18 | name: terraform-large-data-sharing-golang-webapp-display 19 | annotations: 20 | config.kubernetes.io/local-config: "true" 21 | spec: 22 | info: 23 | title: Large Data Sharing Golang Web App 24 | source: 25 | repo: https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp.git 26 | sourceType: git 27 | dir: /infra 28 | ui: 29 | input: 30 | variables: 31 | bucket_location: 32 | name: bucket_location 33 | title: Bucket Location 34 | disable_services_on_destroy: 35 | name: disable_services_on_destroy 36 | title: Disable Services On Destroy 37 | init: 38 | name: init 39 | title: Init 40 | labels: 41 | name: labels 42 | title: Labels 43 | lds_client_image: 44 | name: lds_client_image 45 | title: Lds Client Image 46 | lds_firestore: 47 | name: lds_firestore 48 | title: Lds Firestore 49 | lds_firestore_field_name: 50 | name: lds_firestore_field_name 51 | title: Lds Firestore Field Name 52 | lds_firestore_field_orderNo: 53 | name: lds_firestore_field_orderNo 54 | title: Lds Firestore Field OrderNo 55 | lds_firestore_field_path: 56 | name: lds_firestore_field_path 57 | title: Lds Firestore Field Path 58 | lds_firestore_field_size: 59 | name: lds_firestore_field_size 60 | title: Lds Firestore Field Size 61 | lds_firestore_field_tags: 62 | name: lds_firestore_field_tags 63 | title: Lds Firestore Field Tags 64 | lds_initialization_archive_file_name: 65 | name: lds_initialization_archive_file_name 66 | title: Lds Initialization Archive File Name 67 | lds_initialization_bucket_name: 68 | name: lds_initialization_bucket_name 69 | title: Lds Initialization Bucket Name 70 | lds_server_image: 71 | name: lds_server_image 72 | title: Lds Server Image 73 | project_id: 74 | name: project_id 75 | title: Project Id 76 | region: 77 | name: region 78 | title: Region 79 | -------------------------------------------------------------------------------- /infra/modules/cloudrun/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | variable "project_id" { 18 | description = "GCP project ID" 19 | type = string 20 | } 21 | 22 | variable "location" { 23 | description = "Google cloud location where the resource will be created" 24 | type = string 25 | } 26 | 27 | variable "cloud_run_name" { 28 | description = "Name of Cloud Run" 29 | type = string 30 | } 31 | 32 | variable "cloud_run_image" { 33 | description = "Docker image for Cloud Run" 34 | type = string 35 | } 36 | 37 | # cpu = (core count * 1000)m 38 | # memory = (size) Mi/Gi 39 | variable "limits" { 40 | type = map(string) 41 | description = "Resource limits to the container" 42 | } 43 | 44 | variable "container_port" { 45 | description = "Container port" 46 | type = string 47 | } 48 | 49 | variable "env_vars" { 50 | description = "Environment variables" 51 | type = list(object({ 52 | value = string 53 | name = string 54 | })) 55 | default = [] 56 | } 57 | 58 | variable "ingress" { 59 | description = "Ingress of Cloud Run" 60 | type = string 61 | } 62 | 63 | variable "vpc_access_connector_id" { 64 | description = "VPC access connector id" 65 | type = string 66 | } 67 | 68 | variable "vpc_egress" { 69 | description = "VPC access egress" 70 | type = string 71 | } 72 | 73 | variable "service_account_email" { 74 | description = "cloud run service account email" 75 | type = string 76 | } 77 | 78 | variable "liveness_probe" { 79 | description = "helth check" 80 | type = object( 81 | { 82 | initial_delay_seconds = number, 83 | timeout_seconds = number, 84 | period_seconds = number, 85 | failure_threshold = number, 86 | http_get = object( 87 | { 88 | path = string 89 | } 90 | ) 91 | } 92 | ) 93 | default = { 94 | initial_delay_seconds = 600, 95 | timeout_seconds = 60, 96 | period_seconds = 300, 97 | failure_threshold = 3, 98 | http_get = { 99 | path = "/" 100 | } 101 | } 102 | } 103 | 104 | variable "labels" { 105 | description = "A map of key/value label pairs to assign to the bucket" 106 | type = map(string) 107 | } 108 | -------------------------------------------------------------------------------- /infra/modules/load-balancer/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | resource "google_compute_backend_bucket" "cdn" { 18 | project = var.project_id 19 | name = "lds-cdn-golang" 20 | bucket_name = var.bucket_name 21 | enable_cdn = true 22 | cdn_policy { 23 | cache_mode = "CACHE_ALL_STATIC" 24 | client_ttl = 3600 25 | default_ttl = 3600 26 | max_ttl = 86400 27 | negative_caching = true 28 | serve_while_stale = 86400 29 | } 30 | custom_response_headers = [ 31 | "X-Cache-ID: {cdn_cache_id}", 32 | "X-Cache-Hit: {cdn_cache_status}", 33 | "X-Client-Location: {client_region_subdivision}, {client_city}", 34 | "X-Client-IP-Address: {client_ip_address}" 35 | ] 36 | } 37 | 38 | resource "google_compute_region_network_endpoint_group" "client" { 39 | name = "lds-client-golang" 40 | network_endpoint_type = "SERVERLESS" 41 | region = var.region 42 | cloud_run { 43 | service = var.client_service_name 44 | } 45 | } 46 | 47 | resource "google_compute_backend_service" "lds" { 48 | name = "lds-golang" 49 | load_balancing_scheme = "EXTERNAL" 50 | backend { 51 | group = google_compute_region_network_endpoint_group.client.id 52 | } 53 | } 54 | 55 | resource "google_compute_url_map" "lds" { 56 | project = var.project_id 57 | name = "lds-lb-golang" 58 | default_service = google_compute_backend_bucket.cdn.id 59 | host_rule { 60 | path_matcher = "client" 61 | hosts = [ 62 | "*", 63 | ] 64 | } 65 | path_matcher { 66 | name = "client" 67 | default_service = google_compute_backend_service.lds.id 68 | path_rule { 69 | paths = [ 70 | "/${var.resource_path}/*", 71 | ] 72 | service = google_compute_backend_bucket.cdn.id 73 | } 74 | } 75 | } 76 | 77 | resource "google_compute_target_http_proxy" "lds" { 78 | project = var.project_id 79 | name = "lds-proxy-golang" 80 | url_map = google_compute_url_map.lds.self_link 81 | } 82 | 83 | resource "google_compute_global_forwarding_rule" "lds" { 84 | project = var.project_id 85 | labels = var.labels 86 | name = "lds-frontend-golang" 87 | target = google_compute_target_http_proxy.lds.self_link 88 | ip_address = google_compute_global_address.lds.address 89 | port_range = "80" 90 | } 91 | 92 | resource "google_compute_global_address" "lds" { 93 | project = var.project_id 94 | name = "lds-external-ip-golang" 95 | ip_version = "IPV4" 96 | address_type = "EXTERNAL" 97 | } 98 | -------------------------------------------------------------------------------- /infra/modules/load-balancer/metadata.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: blueprints.cloud.google.com/v1alpha1 16 | kind: BlueprintMetadata 17 | metadata: 18 | name: terraform-large-data-sharing-golang-webapp-load-balancer 19 | annotations: 20 | config.kubernetes.io/local-config: "true" 21 | spec: 22 | info: 23 | title: load-balancer module 24 | source: 25 | repo: https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp.git 26 | sourceType: git 27 | dir: /infra/modules/load-balancer 28 | actuationTool: 29 | flavor: Terraform 30 | version: '>= 0.13' 31 | description: {} 32 | content: 33 | examples: 34 | - name: simple_example 35 | location: examples/simple_example 36 | interfaces: 37 | variables: 38 | - name: bucket_name 39 | description: Bucket name 40 | varType: string 41 | required: true 42 | - name: client_service_name 43 | description: Frontend service name 44 | varType: string 45 | required: true 46 | - name: labels 47 | description: A map of key/value label pairs to assign to the bucket. 48 | varType: map(string) 49 | required: true 50 | - name: project_id 51 | description: GCP project ID. 52 | varType: string 53 | required: true 54 | - name: region 55 | description: Google cloud region where the resource will be created. 56 | varType: string 57 | required: true 58 | - name: resource_path 59 | description: Resource folder path 60 | varType: string 61 | required: true 62 | outputs: 63 | - name: backend_bucket_name 64 | description: The name of the backend bucket used for Cloud CDN 65 | - name: lb_external_ip 66 | description: Frontend IP address of the load balancer 67 | requirements: 68 | roles: 69 | - level: Project 70 | roles: 71 | - roles/storage.admin 72 | - roles/datastore.owner 73 | - roles/appengine.appAdmin 74 | - roles/compute.admin 75 | - roles/compute.networkAdmin 76 | - roles/cloudtrace.admin 77 | - roles/iam.serviceAccountAdmin 78 | - roles/iam.serviceAccountUser 79 | - roles/resourcemanager.projectIamAdmin 80 | - roles/run.admin 81 | - roles/monitoring.admin 82 | - roles/vpcaccess.admin 83 | services: 84 | - cloudresourcemanager.googleapis.com 85 | - compute.googleapis.com 86 | - run.googleapis.com 87 | - iam.googleapis.com 88 | - firestore.googleapis.com 89 | - vpcaccess.googleapis.com 90 | - serviceusage.googleapis.com 91 | - monitoring.googleapis.com 92 | - cloudtrace.googleapis.com 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Large data sharing Go web app 2 | 3 | ## Description 4 | 5 | ### Tagline 6 | 7 | Create a web app to share large quantities of files to users across the globe 8 | 9 | ### Detailed 10 | 11 | This solution quickly and securely deploys a three-tiered web app with a Javascript front end, a Go back end, and a Firestore database on GCP. The goal of this solution is to utilize Google's Cloud CDN to serve large quantities of files (e.g., images, videos, documents) to users across the globe. 12 | 13 | The resources/services/activations/deletions that this module will create/trigger are: 14 | 15 | - Cloud Load Balancing 16 | - Cloud Storage 17 | - Cloud CDN 18 | - Cloud Run 19 | - Firestore 20 | 21 | 22 | ## Inputs 23 | 24 | | Name | Description | Type | Default | Required | 25 | |------|-------------|------|---------|:--------:| 26 | | bucket\_location | Bucket location. https://cloud.google.com/storage/docs/locations | `string` | `"US"` | no | 27 | | disable\_services\_on\_destroy | Whether project services will be disabled when the resources are destroyed. | `bool` | `false` | no | 28 | | init | Initialize resource or not | `bool` | `true` | no | 29 | | labels | A map of key/value label pairs to assign to the resources. | `map(string)` |
{
"app": "large-data-sharing"
}
| no | 30 | | lds\_client\_image | Docker image for frontend | `string` | `"gcr.io/hsa-resources-public/hsa-lds-golang-frontend:latest"` | no | 31 | | lds\_initialization\_archive\_file\_name | Archive file's name in lds-initialization bucket | `string` | `"initialization.tar.gz"` | no | 32 | | lds\_initialization\_bucket\_name | Bucket for cloud run job | `string` | `"jss-resources"` | no | 33 | | lds\_server\_image | Docker image for backend | `string` | `"gcr.io/hsa-resources-public/hsa-lds-golang-backend:latest"` | no | 34 | | project\_id | GCP project ID. | `string` | n/a | yes | 35 | | region | Google cloud region where the resource will be created. | `string` | `"us-west1"` | no | 36 | | firestore_collection_id | Firestore collection id. | `string` | `"fileMetadata"` | no | 37 | 38 | ## Outputs 39 | 40 | | Name | Description | 41 | |------|-------------| 42 | | bucket\_name | Bucket name | 43 | | lb\_external\_ip | Frontend IP address of the load balancer | 44 | | neos\_walkthrough\_url | Neos Tutorial URL | 45 | 46 | 47 | 48 | ## Requirements 49 | 50 | These sections describe requirements for using this module. 51 | 52 | ### Software 53 | 54 | The following dependencies must be available: 55 | 56 | - [Terraform](https://developer.hashicorp.com/terraform/downloads) v0.13 57 | - [Terraform Provider for GCP](https://registry.terraform.io/providers/hashicorp/google/latest/docs) plugin v4.57 58 | 59 | ### Service Account 60 | 61 | - roles/storage.objectAdmin 62 | - roles/datastore.user 63 | - roles/compute.networkUser 64 | 65 | A service account with the following roles must be used to provision 66 | the resources of this module: 67 | 68 | ### APIs 69 | 70 | A project with the following APIs enabled must be used to host the 71 | resources of this module: 72 | 73 | - compute.googleapis.com 74 | - run.googleapis.com 75 | - iam.googleapis.com 76 | - firestore.googleapis.com 77 | - vpcaccess.googleapis.com 78 | - monitoring.googleapis.com 79 | - cloudtrace.googleapis.com 80 | -------------------------------------------------------------------------------- /infra/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Please note that this file was generated from [terraform-google-module-template](https://github.com/terraform-google-modules/terraform-google-module-template). 16 | # Please make sure to contribute relevant changes upstream! 17 | 18 | # Make will use bash instead of sh 19 | SHELL := /usr/bin/env bash 20 | 21 | DOCKER_TAG_VERSION_DEVELOPER_TOOLS := 1 22 | DOCKER_IMAGE_DEVELOPER_TOOLS := cft/developer-tools 23 | REGISTRY_URL := gcr.io/cloud-foundation-cicd 24 | ENABLE_BPMETADATA := 1 25 | export ENABLE_BPMETADATA 26 | 27 | # Enter docker container for local development 28 | .PHONY: docker_run 29 | docker_run: 30 | docker run --rm -it \ 31 | -e SERVICE_ACCOUNT_JSON \ 32 | -v "$(CURDIR)":/workspace \ 33 | $(REGISTRY_URL)/${DOCKER_IMAGE_DEVELOPER_TOOLS}:${DOCKER_TAG_VERSION_DEVELOPER_TOOLS} \ 34 | /bin/bash 35 | 36 | # Execute prepare tests within the docker container 37 | .PHONY: docker_test_prepare 38 | docker_test_prepare: 39 | docker run --rm -it \ 40 | -e SERVICE_ACCOUNT_JSON \ 41 | -e TF_VAR_org_id \ 42 | -e TF_VAR_folder_id \ 43 | -e TF_VAR_billing_account \ 44 | -v "$(CURDIR)":/workspace \ 45 | $(REGISTRY_URL)/${DOCKER_IMAGE_DEVELOPER_TOOLS}:${DOCKER_TAG_VERSION_DEVELOPER_TOOLS} \ 46 | /usr/local/bin/execute_with_credentials.sh prepare_environment 47 | 48 | # Clean up test environment within the docker container 49 | .PHONY: docker_test_cleanup 50 | docker_test_cleanup: 51 | docker run --rm -it \ 52 | -e SERVICE_ACCOUNT_JSON \ 53 | -e TF_VAR_org_id \ 54 | -e TF_VAR_folder_id \ 55 | -e TF_VAR_billing_account \ 56 | -v "$(CURDIR)":/workspace \ 57 | $(REGISTRY_URL)/${DOCKER_IMAGE_DEVELOPER_TOOLS}:${DOCKER_TAG_VERSION_DEVELOPER_TOOLS} \ 58 | /usr/local/bin/execute_with_credentials.sh cleanup_environment 59 | 60 | # Execute lint tests within the docker container 61 | .PHONY: docker_test_lint 62 | docker_test_lint: 63 | docker run --rm -it \ 64 | -e ENABLE_BPMETADATA \ 65 | -e EXCLUDE_LINT_DIRS \ 66 | -v "$(CURDIR)":/workspace \ 67 | $(REGISTRY_URL)/${DOCKER_IMAGE_DEVELOPER_TOOLS}:${DOCKER_TAG_VERSION_DEVELOPER_TOOLS} \ 68 | /usr/local/bin/test_lint.sh 69 | 70 | # Execute lint tests non tty within the docker container 71 | .PHONY: docker_test_lint_gha 72 | docker_test_lint_gha: 73 | docker run --rm \ 74 | -e EXCLUDE_LINT_DIRS \ 75 | -v "$(CURDIR)":/workspace \ 76 | $(REGISTRY_URL)/${DOCKER_IMAGE_DEVELOPER_TOOLS}:${DOCKER_TAG_VERSION_DEVELOPER_TOOLS} \ 77 | /usr/local/bin/test_lint.sh 78 | 79 | # Generate documentation 80 | .PHONY: docker_generate_docs 81 | docker_generate_docs: 82 | docker run --rm -it \ 83 | -e ENABLE_BPMETADATA \ 84 | -v "$(dir ${CURDIR})":/workspace \ 85 | $(REGISTRY_URL)/${DOCKER_IMAGE_DEVELOPER_TOOLS}:${DOCKER_TAG_VERSION_DEVELOPER_TOOLS} \ 86 | /bin/bash -c 'source /usr/local/bin/task_helper_functions.sh && generate_docs "-d -p infra"' 87 | 88 | # Alias for backwards compatibility 89 | .PHONY: generate_docs 90 | generate_docs: docker_generate_docs 91 | -------------------------------------------------------------------------------- /infra/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | variable "project_id" { 18 | description = "GCP project ID." 19 | type = string 20 | validation { 21 | condition = var.project_id != "" 22 | error_message = "Error: project_id is required" 23 | } 24 | } 25 | 26 | variable "region" { 27 | description = "Google cloud region where the resource will be created." 28 | type = string 29 | default = "us-west1" 30 | } 31 | 32 | variable "disable_services_on_destroy" { 33 | description = "Whether project services will be disabled when the resources are destroyed." 34 | type = bool 35 | default = false 36 | } 37 | 38 | variable "bucket_location" { 39 | description = "Bucket location. https://cloud.google.com/storage/docs/locations" 40 | type = string 41 | default = "US" 42 | 43 | validation { 44 | condition = contains(["ASIA", "EU", "US"], var.bucket_location) 45 | error_message = "Allowed values for type are \"ASIA\", \"EU\", \"US\"." 46 | } 47 | } 48 | 49 | variable "lds_server_image" { 50 | description = "Docker image for backend" 51 | type = string 52 | default = "gcr.io/hsa-public/hsa-lds-golang-backend:firestore-db" 53 | } 54 | 55 | variable "lds_client_image" { 56 | description = "Docker image for frontend" 57 | type = string 58 | default = "gcr.io/hsa-resources-public/hsa-lds-golang-frontend:latest" 59 | } 60 | 61 | variable "lds_initialization_bucket_name" { 62 | description = "Bucket for cloud run job" 63 | type = string 64 | default = "jss-resources" 65 | } 66 | 67 | variable "lds_initialization_archive_file_name" { 68 | description = "Archive file's name in lds-initialization bucket" 69 | type = string 70 | default = "initialization.tar.gz" 71 | } 72 | 73 | variable "labels" { 74 | type = map(string) 75 | description = "A map of key/value label pairs to assign to the resources." 76 | default = { 77 | app = "large-data-sharing-golang" 78 | } 79 | } 80 | 81 | variable "lds_firestore" { 82 | description = "Firestore collection id" 83 | type = string 84 | default = "fileMetadata-cdn" 85 | } 86 | 87 | variable "lds_firestore_field_path" { 88 | description = "Firestore field: path" 89 | type = string 90 | default = "path" 91 | } 92 | 93 | variable "lds_firestore_field_name" { 94 | description = "Firestore field: name" 95 | type = string 96 | default = "name" 97 | } 98 | 99 | variable "lds_firestore_field_size" { 100 | description = "Firestore field: size" 101 | type = string 102 | default = "size" 103 | } 104 | 105 | variable "lds_firestore_field_tags" { 106 | description = "Firestore field: tags" 107 | type = string 108 | default = "tags" 109 | } 110 | 111 | variable "lds_firestore_field_orderNo" { 112 | description = "Firestore field: orderNo" 113 | type = string 114 | default = "orderNo" 115 | } 116 | -------------------------------------------------------------------------------- /infra/README.md: -------------------------------------------------------------------------------- 1 | # Large Data Sharing Golang Web App 2 | 3 | ## Description 4 | 5 | ### Tagline 6 | 7 | Create a web app to share large quantities of files to users across the globe 8 | 9 | ### Detailed 10 | 11 | This solution provides an end-to-end demonstration on how a developer would architect an application that can handle large quantities of files operations on GCP. The goal of this solution is to utilize Google Cloud CDN to serve large quantities of files. 12 | 13 | The resources/services/activations/deletions that this module will create/trigger are: 14 | 15 | - Cloud Load Balancing 16 | - Cloud Storage 17 | - Cloud CDN 18 | - Cloud Run 19 | - Firestore 20 | 21 | 22 | ## Inputs 23 | 24 | | Name | Description | Type | Default | Required | 25 | |------|-------------|------|---------|:--------:| 26 | | bucket\_location | Bucket location. https://cloud.google.com/storage/docs/locations | `string` | `"US"` | no | 27 | | disable\_services\_on\_destroy | Whether project services will be disabled when the resources are destroyed. | `bool` | `false` | no | 28 | | labels | A map of key/value label pairs to assign to the resources. | `map(string)` |
{
"app": "large-data-sharing-golang"
}
| no | 29 | | lds\_client\_image | Docker image for frontend | `string` | `"gcr.io/hsa-resources-public/hsa-lds-golang-frontend:latest"` | no | 30 | | lds\_firestore | Firestore collection id | `string` | `"fileMetadata-cdn"` | no | 31 | | lds\_firestore\_field\_name | Firestore field: name | `string` | `"name"` | no | 32 | | lds\_firestore\_field\_orderNo | Firestore field: orderNo | `string` | `"orderNo"` | no | 33 | | lds\_firestore\_field\_path | Firestore field: path | `string` | `"path"` | no | 34 | | lds\_firestore\_field\_size | Firestore field: size | `string` | `"size"` | no | 35 | | lds\_firestore\_field\_tags | Firestore field: tags | `string` | `"tags"` | no | 36 | | lds\_initialization\_archive\_file\_name | Archive file's name in lds-initialization bucket | `string` | `"initialization.tar.gz"` | no | 37 | | lds\_initialization\_bucket\_name | Bucket for cloud run job | `string` | `"jss-resources"` | no | 38 | | lds\_server\_image | Docker image for backend | `string` | `"gcr.io/hsa-public/hsa-lds-golang-backend:firestore-db"` | no | 39 | | project\_id | GCP project ID. | `string` | n/a | yes | 40 | | region | Google cloud region where the resource will be created. | `string` | `"us-west1"` | no | 41 | 42 | ## Outputs 43 | 44 | | Name | Description | 45 | |------|-------------| 46 | | backend\_bucket\_name | The name of the backend bucket used for Cloud CDN | 47 | | bucket\_name | Bucket name | 48 | | db\_name | Firestore database name | 49 | | lb\_external\_ip | Frontend IP address of the load balancer | 50 | | neos\_walkthrough\_url | Neos Tutorial URL | 51 | 52 | 53 | 54 | ## Requirements 55 | 56 | These sections describe requirements for using this module. 57 | 58 | ### Software 59 | 60 | The following dependencies must be available: 61 | 62 | - [Terraform](https://developer.hashicorp.com/terraform/downloads) v0.13 63 | - [Terraform Provider for GCP](https://registry.terraform.io/providers/hashicorp/google/latest/docs) plugin v4.57 64 | 65 | ### Service Account 66 | 67 | - roles/storage.objectAdmin 68 | - roles/datastore.user 69 | - roles/compute.networkUser 70 | 71 | A service account with the following roles must be used to provision 72 | the resources of this module: 73 | 74 | ### APIs 75 | 76 | A project with the following APIs enabled must be used to host the 77 | resources of this module: 78 | 79 | - compute.googleapis.com 80 | - run.googleapis.com 81 | - iam.googleapis.com 82 | - firestore.googleapis.com 83 | - vpcaccess.googleapis.com 84 | - monitoring.googleapis.com 85 | -------------------------------------------------------------------------------- /infra/postdeployment.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | locals { 18 | migrate_data_commands = [ 19 | "gsutil cp gs://${var.lds_initialization_bucket_name}/execution.sh .", 20 | "gsutil cp gs://${var.lds_initialization_bucket_name}/upload.sh .", 21 | "bash execution.sh ${var.lds_initialization_bucket_name} ${var.lds_initialization_archive_file_name} ${module.cloud_run_client.cloud_run.uri}", 22 | ] 23 | } 24 | 25 | resource "google_cloud_run_v2_job" "migrate_data" { 26 | depends_on = [ 27 | module.project_services, 28 | ] 29 | name = "migration-data-job-golang" 30 | location = var.region 31 | launch_stage = "BETA" 32 | template { 33 | template { 34 | service_account = google_service_account.cloudrun.email 35 | containers { 36 | image = "gcr.io/google.com/cloudsdktool/cloud-sdk" 37 | command = ["/bin/bash"] 38 | args = [ 39 | "-c", 40 | join(" && ", local.migrate_data_commands) 41 | ] 42 | } 43 | vpc_access { 44 | connector = module.networking.vpc_access_connector_id 45 | egress = "ALL_TRAFFIC" 46 | } 47 | } 48 | } 49 | labels = var.labels 50 | } 51 | 52 | resource "google_cloud_run_v2_job" "reset_data" { 53 | depends_on = [ 54 | module.project_services, 55 | ] 56 | name = "reset-data-job-golang" 57 | location = var.region 58 | launch_stage = "BETA" 59 | template { 60 | template { 61 | service_account = google_service_account.cloudrun.email 62 | containers { 63 | image = "curlimages/curl" 64 | command = ["/bin/sh"] 65 | args = [ 66 | "-c", 67 | "curl -X DELETE ${module.cloud_run_server.cloud_run.uri}/api/reset" 68 | ] 69 | } 70 | vpc_access { 71 | connector = module.networking.vpc_access_connector_id 72 | egress = "ALL_TRAFFIC" 73 | } 74 | } 75 | } 76 | labels = var.labels 77 | } 78 | 79 | data "google_compute_zones" "available" { 80 | depends_on = [ 81 | module.project_services, 82 | ] 83 | project = var.project_id 84 | region = var.region 85 | } 86 | 87 | resource "google_compute_instance" "initialization" { 88 | depends_on = [ 89 | module.project_services, 90 | module.cloud_run_server, 91 | module.cloud_run_client, 92 | ] 93 | 94 | name = "lds-initialization-golang" 95 | machine_type = "n1-standard-1" 96 | zone = data.google_compute_zones.available.names[0] 97 | 98 | boot_disk { 99 | initialize_params { 100 | image = "debian-cloud/debian-11" 101 | } 102 | } 103 | 104 | network_interface { 105 | network = module.networking.netowrk_self_link 106 | subnetwork = module.networking.subnet_netowrk_self_link 107 | } 108 | 109 | service_account { 110 | email = "${data.google_project.project.number}-compute@developer.gserviceaccount.com" 111 | scopes = [ 112 | "cloud-platform" 113 | ] 114 | } 115 | 116 | metadata_startup_script = <= 0.13' 31 | description: {} 32 | content: 33 | examples: 34 | - name: simple_example 35 | location: examples/simple_example 36 | interfaces: 37 | variables: 38 | - name: cloud_run_image 39 | description: Docker image for Cloud Run 40 | varType: string 41 | required: true 42 | - name: cloud_run_name 43 | description: Name of Cloud Run 44 | varType: string 45 | required: true 46 | - name: container_port 47 | description: Container port 48 | varType: string 49 | required: true 50 | - name: env_vars 51 | description: Environment variables 52 | varType: |- 53 | list(object({ 54 | value = string 55 | name = string 56 | })) 57 | defaultValue: [] 58 | - name: ingress 59 | description: Ingress of Cloud Run 60 | varType: string 61 | required: true 62 | - name: labels 63 | description: A map of key/value label pairs to assign to the bucket 64 | varType: map(string) 65 | required: true 66 | - name: limits 67 | description: Resource limits to the container 68 | varType: map(string) 69 | required: true 70 | - name: liveness_probe 71 | description: helth check 72 | varType: |- 73 | object( 74 | { 75 | initial_delay_seconds = number, 76 | timeout_seconds = number, 77 | period_seconds = number, 78 | failure_threshold = number, 79 | http_get = object( 80 | { 81 | path = string 82 | } 83 | ) 84 | } 85 | ) 86 | defaultValue: 87 | failure_threshold: 3 88 | http_get: 89 | path: / 90 | initial_delay_seconds: 600 91 | period_seconds: 300 92 | timeout_seconds: 60 93 | - name: location 94 | description: Google cloud location where the resource will be created 95 | varType: string 96 | required: true 97 | - name: project_id 98 | description: GCP project ID 99 | varType: string 100 | required: true 101 | - name: service_account_email 102 | description: cloud run service account email 103 | varType: string 104 | required: true 105 | - name: vpc_access_connector_id 106 | description: VPC access connector id 107 | varType: string 108 | required: true 109 | - name: vpc_egress 110 | description: VPC access egress 111 | varType: string 112 | required: true 113 | outputs: 114 | - name: cloud_run 115 | description: Cloud Run service 116 | requirements: 117 | roles: 118 | - level: Project 119 | roles: 120 | - roles/storage.admin 121 | - roles/datastore.owner 122 | - roles/appengine.appAdmin 123 | - roles/compute.admin 124 | - roles/compute.networkAdmin 125 | - roles/cloudtrace.admin 126 | - roles/iam.serviceAccountAdmin 127 | - roles/iam.serviceAccountUser 128 | - roles/resourcemanager.projectIamAdmin 129 | - roles/run.admin 130 | - roles/monitoring.admin 131 | - roles/vpcaccess.admin 132 | services: 133 | - cloudresourcemanager.googleapis.com 134 | - compute.googleapis.com 135 | - run.googleapis.com 136 | - iam.googleapis.com 137 | - firestore.googleapis.com 138 | - vpcaccess.googleapis.com 139 | - serviceusage.googleapis.com 140 | - monitoring.googleapis.com 141 | - cloudtrace.googleapis.com 142 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.1.3](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/compare/v0.1.2...v0.1.3) (2023-07-26) 4 | 5 | 6 | ### Bug Fixes 7 | 8 | * pinning google provider < 4.75.0 ([#38](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/issues/38)) ([8161493](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/8161493a9b265defaeac19bd4d0e51b8a40f3ecb)) 9 | 10 | ## [0.1.2](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/compare/v0.1.1...v0.1.2) (2023-06-30) 11 | 12 | 13 | ### Bug Fixes 14 | 15 | * **deps:** update module github.com/googlecloudplatform/cloud-foundation-toolkit/infra/blueprint-test to v0.6.1 ([#33](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/issues/33)) ([9473e18](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/9473e188e2e5833e6446b6531d72d63473d6457c)) 16 | 17 | ## [0.1.1](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/compare/v0.1.0...v0.1.1) (2023-06-30) 18 | 19 | 20 | ### Bug Fixes 21 | 22 | * changed TF actuation perms for CFT tests ([#29](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/issues/29)) ([add6af9](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/add6af97f3d4f4bf1169661b0fc5f29b148b60a4)) 23 | * **deps:** update module github.com/googlecloudplatform/cloud-foundation-toolkit/infra/blueprint-test to v0.6.0 ([#30](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/issues/30)) ([6e337fd](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/6e337fdf9e830950f9a81ea6784c9998f3629485)) 24 | * **deps:** update module github.com/stretchr/testify to v1.8.4 ([#24](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/issues/24)) ([e6b045b](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/e6b045bb111641851d8679c76464d48427062d3f)) 25 | * made core metadata compliant with the schema ([fc2e8b1](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/fc2e8b1d3ffc8e11f3c3d527a8241744b8ba3136)) 26 | * Update int.cloudbuild.yaml to use LR billing ([#27](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/issues/27)) ([3d77373](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/3d7737342a4f430475ca1556af0cc644737cfd5d)) 27 | * update metadata ([#22](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/issues/22)) ([1edab3f](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/1edab3fdf7928476bc069e6440572da855e602f6)) 28 | * update neos toc url ([#32](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/issues/32)) ([3a7bf72](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/3a7bf7211999a3c6c71dd66bbfbbc11a9059f887)) 29 | 30 | ## 0.1.0 (2023-05-19) 31 | 32 | 33 | ### Bug Fixes 34 | 35 | * added CFT cases and fixed build and naming conflicts ([#13](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/issues/13)) ([3feb32f](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/3feb32f8342419b4adfc3bbc923d35d8168b3edd)) 36 | * check cloud run jobs status in CFT test ([#19](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/issues/19)) ([b5b7a09](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/b5b7a097ee07e28e4a7950b3c055af125eb3f1ee)) 37 | * **deps:** update go modules ([#16](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/issues/16)) ([8aabf89](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/8aabf8921fabc20a72f9307d12211e8337ff4bee)) 38 | * **deps:** update module github.com/googlecloudplatform/cloud-foundation-toolkit/infra/blueprint-test to v0.5.2 ([#17](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/issues/17)) ([4cd4599](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/4cd4599a6c02526cf8341d49e688f42301de5e89)) 39 | * **deps:** update module github.com/stretchr/testify to v1.8.3 ([#20](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/issues/20)) ([f94728a](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/f94728a54af0bee6fce2d3fc8d60a34ccc9def5f)) 40 | * remove invalid characters in output.tf ([#14](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/issues/14)) ([57cc42d](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/57cc42d04ae45d0031578fd9cb65754585b75b5a)) 41 | * Update outputs.tf to output neos url ([0941642](https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp/commit/09416421af570c9c0f531cdf4bce01b36afe0c91)) 42 | -------------------------------------------------------------------------------- /infra/metadata.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: blueprints.cloud.google.com/v1alpha1 16 | kind: BlueprintMetadata 17 | metadata: 18 | name: terraform-large-data-sharing-golang-webapp 19 | annotations: 20 | config.kubernetes.io/local-config: "true" 21 | spec: 22 | info: 23 | title: Large Data Sharing Golang Web App 24 | source: 25 | repo: https://github.com/GoogleCloudPlatform/terraform-large-data-sharing-golang-webapp.git 26 | sourceType: git 27 | dir: /infra 28 | description: 29 | tagline: Create a web app to share large quantities of files to users across the globe 30 | detailed: This solution provides an end-to-end demonstration on how a developer would architect an application that can handle large quantities of files operations on GCP. The goal of this solution is to utilize Google Cloud CDN to serve large quantities of files. 31 | deploymentDuration: 32 | configurationSecs: 60 33 | deploymentSecs: 300 34 | costEstimate: 35 | description: cost details 36 | url: https://cloud.google.com/products/calculator#id=d2ad2fa1-53ea-4ea4-bbfb-490f69611e0a 37 | cloudProducts: 38 | - productId: SERVERLESS_SECTION 39 | pageUrl: run 40 | label: Cloud Run 41 | - productId: LOAD_BALANCING_SECTION 42 | pageUrl: net-services/loadbalancing 43 | label: Cloud LoadBalancer 44 | - productId: search_FILESTORE_SECTION 45 | pageUrl: filestore 46 | label: Filestore 47 | - productId: STORAGE_SECTION 48 | pageUrl: storage 49 | label: Cloud Storage 50 | - productId: LOAD_BALANCING_SECTION 51 | pageUrl: net-services/cdn 52 | content: 53 | architecture: 54 | diagramUrl: www.gstatic.com/pantheon/images/solutions/large_data_sharing_golang_webapp_architecture_v1.svg 55 | description: 56 | - User requests to upload files are routed to the front end using a load balancer. 57 | - The frontend routes these requests to the backend, which uses Cloud Run. 58 | - The backend stores the files (i.e., data) in Cloud Storage and the metadata in Firestore. 59 | - User requests to view a file are routed to the Cloud CDN if there is a CDN cache hit. 60 | - User requests to view a file are routed to the Cloud Storage if there is a CDN cache miss. 61 | documentation: 62 | - title: Large Data Sharing Golang Web App 63 | url: https://cloud.google.com/architecture/big-data-analytics/large-data-sharing-go 64 | - title: Tutorial Walkthrough ID 65 | url: solutions-in-console--large-data-sharing--large-data-sharing-golang_tour 66 | subBlueprints: 67 | - name: cloudrun 68 | location: modules/cloudrun 69 | - name: firestore 70 | location: modules/firestore 71 | - name: load-balancer 72 | location: modules/load-balancer 73 | - name: networking 74 | location: modules/networking 75 | - name: storage 76 | location: modules/storage 77 | examples: 78 | - name: simple_example 79 | location: examples/simple_example 80 | interfaces: 81 | variables: 82 | - name: bucket_location 83 | description: Bucket location. https://cloud.google.com/storage/docs/locations 84 | varType: string 85 | defaultValue: US 86 | - name: disable_services_on_destroy 87 | description: Whether project services will be disabled when the resources are destroyed. 88 | varType: bool 89 | defaultValue: false 90 | - name: init 91 | description: Initialize resource or not 92 | varType: bool 93 | defaultValue: true 94 | - name: labels 95 | description: A map of key/value label pairs to assign to the resources. 96 | varType: map(string) 97 | defaultValue: 98 | app: large-data-sharing-golang 99 | - name: lds_client_image 100 | description: Docker image for frontend 101 | varType: string 102 | defaultValue: gcr.io/hsa-resources-public/hsa-lds-golang-frontend:latest 103 | - name: lds_firestore 104 | description: Firestore collection id 105 | varType: string 106 | defaultValue: fileMetadata-cdn 107 | - name: lds_firestore_field_name 108 | description: 'Firestore field: name' 109 | varType: string 110 | defaultValue: name 111 | - name: lds_firestore_field_orderNo 112 | description: 'Firestore field: orderNo' 113 | varType: string 114 | defaultValue: orderNo 115 | - name: lds_firestore_field_path 116 | description: 'Firestore field: path' 117 | varType: string 118 | defaultValue: path 119 | - name: lds_firestore_field_size 120 | description: 'Firestore field: size' 121 | varType: string 122 | defaultValue: size 123 | - name: lds_firestore_field_tags 124 | description: 'Firestore field: tags' 125 | varType: string 126 | defaultValue: tags 127 | - name: lds_initialization_archive_file_name 128 | description: Archive file's name in lds-initialization bucket 129 | varType: string 130 | defaultValue: initialization.tar.gz 131 | - name: lds_initialization_bucket_name 132 | description: Bucket for cloud run job 133 | varType: string 134 | defaultValue: jss-resources 135 | - name: lds_server_image 136 | description: Docker image for backend 137 | varType: string 138 | defaultValue: gcr.io/hsa-resources-public/hsa-lds-golang-backend:latest 139 | - name: project_id 140 | description: GCP project ID. 141 | varType: string 142 | required: true 143 | - name: region 144 | description: Google cloud region where the resource will be created. 145 | varType: string 146 | defaultValue: us-west1 147 | outputs: 148 | - name: backend_bucket_name 149 | description: The name of the backend bucket used for Cloud CDN 150 | - name: bucket_name 151 | description: Bucket name 152 | - name: lb_external_ip 153 | description: Frontend IP address of the load balancer 154 | - name: neos_walkthrough_url 155 | description: Neos Tutorial URL 156 | requirements: 157 | roles: 158 | - level: Project 159 | roles: 160 | - roles/storage.admin 161 | - roles/datastore.owner 162 | - roles/appengine.appAdmin 163 | - roles/compute.admin 164 | - roles/compute.networkAdmin 165 | - roles/cloudtrace.admin 166 | - roles/iam.serviceAccountAdmin 167 | - roles/iam.serviceAccountUser 168 | - roles/resourcemanager.projectIamAdmin 169 | - roles/run.admin 170 | - roles/monitoring.admin 171 | - roles/vpcaccess.admin 172 | services: 173 | - cloudresourcemanager.googleapis.com 174 | - compute.googleapis.com 175 | - run.googleapis.com 176 | - iam.googleapis.com 177 | - firestore.googleapis.com 178 | - vpcaccess.googleapis.com 179 | - serviceusage.googleapis.com 180 | - monitoring.googleapis.com 181 | - cloudtrace.googleapis.com 182 | -------------------------------------------------------------------------------- /.github/workflows/periodic-reporter.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023-2024 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # NOTE: This file is automatically generated from: 16 | # https://github.com/GoogleCloudPlatform/cloud-foundation-toolkit/blob/master/infra/terraform/modules/workflow_files/periodic-reporter.yaml 17 | 18 | name: 'reporter' 19 | 20 | on: 21 | schedule: 22 | # 2 hours after scheduled periodic and once again in the evening 23 | - cron: '0 5,17 * * *' 24 | workflow_dispatch: 25 | 26 | jobs: 27 | report: 28 | if: github.repository_owner == 'GoogleCloudPlatform' || github.repository_owner == 'terraform-google-modules' 29 | 30 | permissions: 31 | issues: 'write' 32 | 33 | runs-on: 'ubuntu-latest' 34 | 35 | steps: 36 | - uses: 'actions/github-script@v7' 37 | with: 38 | script: |- 39 | // label for all issues opened by reporter 40 | const periodicLabel = 'periodic-failure'; 41 | 42 | // check if any reporter opened any issues previously 43 | const prevIssues = await github.paginate(github.rest.issues.listForRepo, { 44 | ...context.repo, 45 | state: 'open', 46 | creator: 'github-actions[bot]', 47 | labels: [periodicLabel] 48 | }); 49 | // createOrCommentIssue creates a new issue or comments on an existing issue. 50 | const createOrCommentIssue = async function (title, txt) { 51 | if (prevIssues.length < 1) { 52 | console.log('no previous issues found, creating one'); 53 | await github.rest.issues.create({ 54 | ...context.repo, 55 | title: title, 56 | body: txt, 57 | labels: [periodicLabel] 58 | }); 59 | return; 60 | } 61 | if (prevIssues.length > 1) { 62 | console.warn( 63 | `found ${prevIssues.length} issues but only adding comment to ${prevIssues[0].html_url}` 64 | ); 65 | } 66 | console.log( 67 | `found previous issue ${prevIssues[0].html_url}, adding comment` 68 | ); 69 | await github.rest.issues.createComment({ 70 | ...context.repo, 71 | issue_number: prevIssues[0].number, 72 | body: txt 73 | }); 74 | }; 75 | 76 | // updateAndCloseIssues comments on any existing issues and closes them. No-op if no issue exists. 77 | const updateAndCloseIssues = async function (txt) { 78 | if (prevIssues.length < 1) { 79 | console.log('no previous issues found, skipping close'); 80 | return; 81 | } 82 | for (const prevIssue of prevIssues) { 83 | console.log(`found previous issue ${prevIssue.html_url}, adding comment`); 84 | await github.rest.issues.createComment({ 85 | ...context.repo, 86 | issue_number: prevIssue.number, 87 | body: txt 88 | }); 89 | console.log(`closing ${prevIssue.html_url}`); 90 | await github.rest.issues.update({ 91 | ...context.repo, 92 | issue_number: prevIssue.number, 93 | body: txt, 94 | state: 'closed' 95 | }); 96 | } 97 | }; 98 | 99 | // Find status of check runs. 100 | // We will find check runs for each commit and then filter for the periodic. 101 | // Checks API only allows for ref and if we use main there could be edge cases where 102 | // the check run happened on a SHA that is different from head. 103 | const commits = await github.paginate(github.rest.repos.listCommits, { 104 | ...context.repo 105 | }); 106 | 107 | var foundCheck = false; 108 | let periodicCheck = {}; 109 | 110 | for (const commit of commits) { 111 | console.log( 112 | `checking runs at ${commit.html_url}: ${commit.commit.message}` 113 | ); 114 | const checks = await github.rest.checks.listForRef({ 115 | ...context.repo, 116 | ref: commit.sha 117 | }); 118 | // find runs for this commit 119 | for (const check of checks.data.check_runs) { 120 | console.log(`found run ${check.name} for ${commit.html_url}`); 121 | if (check.name.includes('periodic-int-trigger')) { 122 | foundCheck = true; 123 | periodicCheck = check; 124 | break; 125 | } 126 | } 127 | 128 | if (foundCheck) { 129 | if ( 130 | periodicCheck.status === 'completed' && 131 | periodicCheck.conclusion === 'success' 132 | ) { 133 | updateAndCloseIssues( 134 | `[Passing periodic](${periodicCheck.html_url}) at ${commit.html_url}. Closing this issue.` 135 | ); 136 | } else if (periodicCheck.status === 'in_progress') { 137 | console.log( 138 | `Check is pending ${periodicCheck.html_url} for ${commit.html_url}. Retry again later.` 139 | ); 140 | } 141 | // error case 142 | else { 143 | createOrCommentIssue( 144 | 'Failing periodic', 145 | `[Failing periodic](${periodicCheck.html_url}) at ${commit.html_url}.` 146 | ); 147 | } 148 | // exit early as check was found 149 | return; 150 | } 151 | } 152 | 153 | // no periodic-int-trigger checks found across all commits, report it 154 | createOrCommentIssue( 155 | 'Missing periodic', 156 | `Periodic test has not run in the past 24hrs. Last checked from ${ 157 | commits[0].html_url 158 | } to ${commits[commits.length - 1].html_url}.` 159 | ); 160 | -------------------------------------------------------------------------------- /infra/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | module "project_services" { 18 | source = "terraform-google-modules/project-factory/google//modules/project_services" 19 | version = "~> 14.0" 20 | disable_services_on_destroy = var.disable_services_on_destroy 21 | project_id = var.project_id 22 | 23 | activate_apis = [ 24 | "compute.googleapis.com", 25 | "run.googleapis.com", 26 | "iam.googleapis.com", 27 | "cloudresourcemanager.googleapis.com", 28 | "firestore.googleapis.com", 29 | "vpcaccess.googleapis.com", 30 | "monitoring.googleapis.com", 31 | "cloudtrace.googleapis.com", 32 | ] 33 | } 34 | 35 | data "google_project" "project" { 36 | depends_on = [ 37 | module.project_services, 38 | ] 39 | } 40 | 41 | locals { 42 | resource_path = "resource" 43 | firestore = length(var.lds_firestore) == 0 ? "fileMetadata-cdn-golang" : var.lds_firestore 44 | firestore_db_name = "large-data-sharing-${random_id.random_code.hex}" 45 | firestore_field_path = length(var.lds_firestore_field_path) == 0 ? "path" : var.lds_firestore_field_path 46 | firestore_field_name = length(var.lds_firestore_field_name) == 0 ? "name" : var.lds_firestore_field_name 47 | firestore_field_size = length(var.lds_firestore_field_size) == 0 ? "size" : var.lds_firestore_field_size 48 | firestore_field_tags = length(var.lds_firestore_field_tags) == 0 ? "tags" : var.lds_firestore_field_tags 49 | firestore_field_orderNo = length(var.lds_firestore_field_orderNo) == 0 ? "orderNo" : var.lds_firestore_field_orderNo 50 | collection_fields = { 51 | (var.lds_firestore) = [ 52 | { 53 | field_path = local.firestore_field_tags 54 | array_config = "CONTAINS" 55 | }, 56 | { 57 | field_path = local.firestore_field_orderNo 58 | order = "DESCENDING" 59 | }, 60 | ] 61 | } 62 | } 63 | 64 | module "storage" { 65 | depends_on = [ 66 | module.project_services, 67 | ] 68 | source = "./modules/storage" 69 | 70 | project_id = var.project_id 71 | location = var.bucket_location 72 | labels = var.labels 73 | name = "lds-resource-${data.google_project.project.number}-golang" 74 | } 75 | 76 | module "networking" { 77 | depends_on = [ 78 | module.project_services, 79 | ] 80 | source = "./modules/networking" 81 | 82 | project_id = var.project_id 83 | region = var.region 84 | } 85 | 86 | module "firestore" { 87 | depends_on = [ 88 | module.project_services 89 | ] 90 | source = "./modules/firestore" 91 | 92 | project_id = var.project_id 93 | collection_fields = local.collection_fields 94 | firestore_db_name = local.firestore_db_name 95 | } 96 | 97 | resource "random_id" "random_code" { 98 | byte_length = 4 99 | } 100 | 101 | resource "google_service_account" "cloudrun" { 102 | depends_on = [ 103 | module.project_services, 104 | ] 105 | 106 | account_id = "cloudrun-${random_id.random_code.hex}-golang" 107 | } 108 | 109 | resource "google_project_iam_member" "cloudrun" { 110 | for_each = toset([ 111 | "roles/storage.objectAdmin", 112 | "roles/datastore.user", 113 | "roles/compute.networkUser", 114 | "roles/cloudtrace.agent", 115 | ]) 116 | project = var.project_id 117 | role = each.key 118 | member = "serviceAccount:${google_service_account.cloudrun.email}" 119 | } 120 | 121 | module "cloud_run_server" { 122 | depends_on = [ 123 | module.project_services, 124 | ] 125 | source = "./modules/cloudrun" 126 | 127 | project_id = var.project_id 128 | location = var.region 129 | cloud_run_name = "lds-server-golang" 130 | cloud_run_image = var.lds_server_image 131 | limits = { 132 | cpu = "2000m" 133 | memory = "2Gi" 134 | } 135 | container_port = "8000" 136 | liveness_probe = { 137 | initial_delay_seconds = 300 138 | timeout_seconds = 10 139 | period_seconds = 60 140 | failure_threshold = 1 141 | http_get = { 142 | path = "/api/healthchecker" 143 | } 144 | } 145 | env_vars = [ 146 | { 147 | name = "LDS_REST_PORT" 148 | value = "8000" 149 | }, 150 | { 151 | name = "LDS_PROJECT" 152 | value = var.project_id 153 | }, 154 | { 155 | name = "LDS_BUCKET" 156 | value = module.storage.bucket_name 157 | }, 158 | { 159 | name = "LDS_RESOURCE_PATH" 160 | value = "/${local.resource_path}" 161 | }, 162 | { 163 | name = "LDS_FIRESTORE_COLLECTION" 164 | value = local.firestore 165 | }, 166 | { 167 | name = "LDS_FIRESTORE_DATABASE" 168 | value = local.firestore_db_name 169 | }, 170 | { 171 | name = "LDS_FIRESTORE_FIELD_PATH" 172 | value = local.firestore_field_path 173 | }, 174 | { 175 | name = "LDS_FIRESTORE_FIELD_NAME" 176 | value = local.firestore_field_name 177 | }, 178 | { 179 | name = "LDS_FIRESTORE_FIELD_SIZE" 180 | value = local.firestore_field_size 181 | }, 182 | { 183 | name = "LDS_FIRESTORE_FIELD_TAGS" 184 | value = local.firestore_field_tags 185 | }, 186 | { 187 | name = "LDS_FIRESTORE_FIELD_ORDER_NO" 188 | value = local.firestore_field_orderNo 189 | }, 190 | ] 191 | ingress = "INGRESS_TRAFFIC_INTERNAL_ONLY" 192 | vpc_access_connector_id = module.networking.vpc_access_connector_id 193 | vpc_egress = "PRIVATE_RANGES_ONLY" 194 | service_account_email = google_service_account.cloudrun.email 195 | labels = var.labels 196 | } 197 | 198 | module "cloud_run_client" { 199 | depends_on = [ 200 | module.project_services, 201 | ] 202 | source = "./modules/cloudrun" 203 | 204 | project_id = var.project_id 205 | location = var.region 206 | cloud_run_name = "lds-client-golang" 207 | cloud_run_image = var.lds_client_image 208 | limits = { 209 | cpu = "1000m" 210 | memory = "512Mi" 211 | } 212 | container_port = "80" 213 | liveness_probe = { 214 | initial_delay_seconds = 30 215 | timeout_seconds = 5 216 | period_seconds = 60 217 | failure_threshold = 1 218 | http_get = { 219 | path = "/" 220 | } 221 | } 222 | env_vars = [ 223 | { 224 | name = "LDS_REST_URL" 225 | value = module.cloud_run_server.cloud_run.uri 226 | }, 227 | ] 228 | ingress = "INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER" 229 | vpc_access_connector_id = module.networking.vpc_access_connector_id 230 | vpc_egress = "ALL_TRAFFIC" 231 | service_account_email = google_service_account.cloudrun.email 232 | labels = var.labels 233 | } 234 | 235 | module "load_balancer" { 236 | depends_on = [ 237 | module.project_services, 238 | ] 239 | source = "./modules/load-balancer" 240 | 241 | project_id = var.project_id 242 | region = var.region 243 | bucket_name = module.storage.bucket_name 244 | client_service_name = module.cloud_run_client.cloud_run.name 245 | resource_path = local.resource_path 246 | labels = var.labels 247 | } 248 | 249 | resource "google_monitoring_dashboard" "lds" { 250 | depends_on = [ 251 | module.project_services, 252 | ] 253 | 254 | for_each = { 255 | "lds_cloudrun_dashboard.tftpl" = { 256 | PROJECT_ID = var.project_id, 257 | } 258 | "lds_cdn_dashboard.tftpl" = { 259 | 260 | } 261 | } 262 | 263 | dashboard_json = templatefile("${path.module}/files/${each.key}", each.value) 264 | } 265 | -------------------------------------------------------------------------------- /infra/files/lds_cdn_dashboard.tftpl: -------------------------------------------------------------------------------- 1 | { 2 | "displayName": "Cloud CDN - Large Data Sharing Golang", 3 | "mosaicLayout": { 4 | "columns": 12, 5 | "tiles": [ 6 | { 7 | "height": 4, 8 | "widget": { 9 | "title": "Request Count by Continent", 10 | "xyChart": { 11 | "chartOptions": { 12 | "mode": "COLOR" 13 | }, 14 | "dataSets": [ 15 | { 16 | "plotType": "STACKED_AREA", 17 | "timeSeriesQuery": { 18 | "timeSeriesQueryLanguage": "fetch https_lb_rule\n| metric 'loadbalancing.googleapis.com/https/request_count'\n| align rate(1m)\n| every 1m\n| group_by [metric.proxy_continent],\n [row_count: row_count()]" 19 | } 20 | } 21 | ], 22 | "timeshiftDuration": "0s", 23 | "yAxis": { 24 | "scale": "LINEAR" 25 | } 26 | } 27 | }, 28 | "width": 6, 29 | "yPos": 8 30 | }, 31 | { 32 | "height": 4, 33 | "widget": { 34 | "title": "Cache Hit Response Bytes by Continent", 35 | "xyChart": { 36 | "chartOptions": { 37 | "mode": "COLOR" 38 | }, 39 | "dataSets": [ 40 | { 41 | "plotType": "STACKED_BAR", 42 | "timeSeriesQuery": { 43 | "timeSeriesQueryLanguage": "fetch https_lb_rule\n| metric 'loadbalancing.googleapis.com/https/response_bytes_count'\n| filter (metric.cache_result = 'HIT')\n| align rate(1m)\n| every 1m\n| group_by [metric.proxy_continent],\n [value_response_bytes_count_aggregate:\n aggregate(value.response_bytes_count)]" 44 | } 45 | } 46 | ], 47 | "timeshiftDuration": "0s", 48 | "yAxis": { 49 | "scale": "LINEAR" 50 | } 51 | } 52 | }, 53 | "width": 6, 54 | "xPos": 6, 55 | "yPos": 4 56 | }, 57 | { 58 | "height": 4, 59 | "widget": { 60 | "title": "Cache Status by Count", 61 | "xyChart": { 62 | "chartOptions": { 63 | "mode": "COLOR" 64 | }, 65 | "dataSets": [ 66 | { 67 | "plotType": "LINE", 68 | "timeSeriesQuery": { 69 | "timeSeriesQueryLanguage": "fetch https_lb_rule\n| metric 'loadbalancing.googleapis.com/https/request_count'\n| align rate(1m)\n| every 1m\n| group_by [metric.cache_result],\n [row_count: row_count()]\n" 70 | } 71 | } 72 | ], 73 | "timeshiftDuration": "0s", 74 | "yAxis": { 75 | "scale": "LINEAR" 76 | } 77 | } 78 | }, 79 | "width": 6, 80 | "yPos": 4 81 | }, 82 | { 83 | "height": 4, 84 | "widget": { 85 | "title": "Response Egress by Cache Status", 86 | "xyChart": { 87 | "chartOptions": { 88 | "mode": "COLOR" 89 | }, 90 | "dataSets": [ 91 | { 92 | "plotType": "STACKED_AREA", 93 | "timeSeriesQuery": { 94 | "timeSeriesQueryLanguage": "fetch https_lb_rule\n| metric 'loadbalancing.googleapis.com/https/response_bytes_count'\n| align rate(1m)\n| every 1m\n| group_by [metric.cache_result],\n [value_response_bytes_count_aggregate:\n aggregate(value.response_bytes_count)]" 95 | } 96 | } 97 | ], 98 | "timeshiftDuration": "0s", 99 | "yAxis": { 100 | "scale": "LINEAR" 101 | } 102 | } 103 | }, 104 | "width": 6, 105 | "xPos": 6 106 | }, 107 | { 108 | "height": 4, 109 | "widget": { 110 | "title": "Latency by Continent 95%", 111 | "xyChart": { 112 | "chartOptions": { 113 | "mode": "COLOR" 114 | }, 115 | "dataSets": [ 116 | { 117 | "plotType": "LINE", 118 | "timeSeriesQuery": { 119 | "timeSeriesQueryLanguage": "fetch https_lb_rule\n| metric 'loadbalancing.googleapis.com/https/frontend_tcp_rtt'\n| group_by 1m,\n [value_frontend_tcp_rtt_aggregate: aggregate(value.frontend_tcp_rtt)]\n| every 1m\n| group_by [metric.proxy_continent],\n [value_frontend_tcp_rtt_aggregate_percentile:\n percentile(value_frontend_tcp_rtt_aggregate, 95)]" 120 | } 121 | } 122 | ], 123 | "timeshiftDuration": "0s", 124 | "yAxis": { 125 | "scale": "LINEAR" 126 | } 127 | } 128 | }, 129 | "width": 6, 130 | "yPos": 12 131 | }, 132 | { 133 | "height": 4, 134 | "widget": { 135 | "title": "Client Response Code", 136 | "xyChart": { 137 | "chartOptions": { 138 | "mode": "COLOR" 139 | }, 140 | "dataSets": [ 141 | { 142 | "plotType": "STACKED_AREA", 143 | "timeSeriesQuery": { 144 | "timeSeriesQueryLanguage": "fetch https_lb_rule\n| metric 'loadbalancing.googleapis.com/https/request_count'\n| group_by 1h, [row_count: row_count()]\n| every 1h\n| group_by [metric.response_code_class],\n [row_count_aggregate: aggregate(row_count)]" 145 | } 146 | } 147 | ], 148 | "timeshiftDuration": "0s", 149 | "yAxis": { 150 | "scale": "LINEAR" 151 | } 152 | } 153 | }, 154 | "width": 6, 155 | "xPos": 6, 156 | "yPos": 8 157 | }, 158 | { 159 | "height": 4, 160 | "widget": { 161 | "title": "Non 2xx Error Codes", 162 | "xyChart": { 163 | "chartOptions": { 164 | "mode": "COLOR" 165 | }, 166 | "dataSets": [ 167 | { 168 | "plotType": "STACKED_AREA", 169 | "timeSeriesQuery": { 170 | "timeSeriesQueryLanguage": "fetch https_lb_rule\n| metric 'loadbalancing.googleapis.com/https/request_count'\n| filter (metric.response_code_class != 200)\n| group_by 1h, [row_count: row_count()]\n| every 1h\n| group_by [metric.response_code_class],\n [row_count_aggregate: aggregate(row_count)]" 171 | } 172 | } 173 | ], 174 | "timeshiftDuration": "0s", 175 | "yAxis": { 176 | "scale": "LINEAR" 177 | } 178 | } 179 | }, 180 | "width": 6, 181 | "xPos": 6, 182 | "yPos": 12 183 | }, 184 | { 185 | "height": 2, 186 | "widget": { 187 | "scorecard": { 188 | "timeSeriesQuery": { 189 | "timeSeriesFilter": { 190 | "aggregation": { 191 | "alignmentPeriod": "60s", 192 | "crossSeriesReducer": "REDUCE_SUM", 193 | "perSeriesAligner": "ALIGN_SUM" 194 | }, 195 | "filter": "metric.type=\"loadbalancing.googleapis.com/https/request_count\" resource.type=\"https_lb_rule\"" 196 | } 197 | } 198 | }, 199 | "title": "Total Requests" 200 | }, 201 | "width": 3 202 | }, 203 | { 204 | "height": 2, 205 | "widget": { 206 | "scorecard": { 207 | "timeSeriesQuery": { 208 | "timeSeriesFilter": { 209 | "aggregation": { 210 | "alignmentPeriod": "60s", 211 | "crossSeriesReducer": "REDUCE_SUM", 212 | "perSeriesAligner": "ALIGN_SUM" 213 | }, 214 | "filter": "metric.type=\"loadbalancing.googleapis.com/https/response_bytes_count\" resource.type=\"https_lb_rule\"" 215 | } 216 | } 217 | }, 218 | "title": "Total Egress" 219 | }, 220 | "width": 3, 221 | "xPos": 3 222 | }, 223 | { 224 | "height": 2, 225 | "widget": { 226 | "scorecard": { 227 | "timeSeriesQuery": { 228 | "timeSeriesFilter": { 229 | "aggregation": { 230 | "alignmentPeriod": "60s", 231 | "crossSeriesReducer": "REDUCE_SUM", 232 | "perSeriesAligner": "ALIGN_SUM" 233 | }, 234 | "filter": "metric.type=\"loadbalancing.googleapis.com/https/response_bytes_count\" resource.type=\"https_lb_rule\" metric.label.\"cache_result\"=\"HIT\"" 235 | } 236 | } 237 | }, 238 | "title": "Cache Hit Egress" 239 | }, 240 | "width": 3, 241 | "yPos": 2 242 | }, 243 | { 244 | "height": 2, 245 | "widget": { 246 | "scorecard": { 247 | "timeSeriesQuery": { 248 | "timeSeriesFilter": { 249 | "aggregation": { 250 | "alignmentPeriod": "60s", 251 | "crossSeriesReducer": "REDUCE_SUM", 252 | "perSeriesAligner": "ALIGN_SUM" 253 | }, 254 | "filter": "metric.type=\"loadbalancing.googleapis.com/https/response_bytes_count\" resource.type=\"https_lb_rule\" metric.label.\"cache_result\"=\"MISS\"" 255 | } 256 | } 257 | }, 258 | "title": "Cache Miss Egress" 259 | }, 260 | "width": 3, 261 | "xPos": 3, 262 | "yPos": 2 263 | }, 264 | { 265 | "height": 4, 266 | "widget": { 267 | "title": "Request Count by Country", 268 | "xyChart": { 269 | "chartOptions": { 270 | "mode": "COLOR" 271 | }, 272 | "dataSets": [ 273 | { 274 | "minAlignmentPeriod": "60s", 275 | "plotType": "STACKED_AREA", 276 | "timeSeriesQuery": { 277 | "timeSeriesFilter": { 278 | "aggregation": { 279 | "alignmentPeriod": "60s", 280 | "perSeriesAligner": "ALIGN_RATE" 281 | }, 282 | "filter": "metric.type=\"loadbalancing.googleapis.com/https/request_count\" resource.type=\"https_lb_rule\"", 283 | "secondaryAggregation": { 284 | "alignmentPeriod": "60s", 285 | "crossSeriesReducer": "REDUCE_SUM", 286 | "groupByFields": [ 287 | "metric.label.\"client_country\"" 288 | ], 289 | "perSeriesAligner": "ALIGN_SUM" 290 | } 291 | } 292 | } 293 | } 294 | ], 295 | "timeshiftDuration": "0s", 296 | "yAxis": { 297 | "scale": "LINEAR" 298 | } 299 | } 300 | }, 301 | "width": 6, 302 | "yPos": 16 303 | } 304 | ] 305 | } 306 | } 307 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /infra/files/lds_cloudrun_dashboard.tftpl: -------------------------------------------------------------------------------- 1 | { 2 | "category": "CUSTOM", 3 | "dashboardFilters": [], 4 | "displayName": "Cloud Run Dashboard - Large Data Sharing Golang", 5 | "labels": {}, 6 | "mosaicLayout": { 7 | "columns": 12, 8 | "tiles": [ 9 | { 10 | "height": 4, 11 | "widget": { 12 | "title": "Average Request Latency", 13 | "xyChart": { 14 | "chartOptions": { 15 | "mode": "COLOR" 16 | }, 17 | "dataSets": [ 18 | { 19 | "minAlignmentPeriod": "60s", 20 | "plotType": "LINE", 21 | "targetAxis": "Y1", 22 | "timeSeriesQuery": { 23 | "apiSource": "DEFAULT_CLOUD", 24 | "timeSeriesFilter": { 25 | "aggregation": { 26 | "alignmentPeriod": "60s", 27 | "crossSeriesReducer": "REDUCE_MEAN", 28 | "groupByFields": [ 29 | "resource.label.\"service_name\"", 30 | "resource.label.\"location\"" 31 | ], 32 | "perSeriesAligner": "ALIGN_DELTA" 33 | }, 34 | "filter": "metric.type=\"run.googleapis.com/request_latencies\" resource.type=\"cloud_run_revision\" resource.label.\"project_id\"=\"${PROJECT_ID}\"", 35 | "secondaryAggregation": { 36 | "alignmentPeriod": "60s", 37 | "crossSeriesReducer": "REDUCE_NONE", 38 | "perSeriesAligner": "ALIGN_NONE" 39 | } 40 | } 41 | } 42 | } 43 | ], 44 | "thresholds": [], 45 | "timeshiftDuration": "0s", 46 | "yAxis": { 47 | "label": "", 48 | "scale": "LINEAR" 49 | } 50 | } 51 | }, 52 | "width": 6, 53 | "xPos": 6, 54 | "yPos": 0 55 | }, 56 | { 57 | "height": 4, 58 | "widget": { 59 | "title": "HTTP Request Count", 60 | "xyChart": { 61 | "chartOptions": { 62 | "mode": "COLOR" 63 | }, 64 | "dataSets": [ 65 | { 66 | "minAlignmentPeriod": "60s", 67 | "plotType": "LINE", 68 | "targetAxis": "Y1", 69 | "timeSeriesQuery": { 70 | "apiSource": "DEFAULT_CLOUD", 71 | "timeSeriesFilter": { 72 | "aggregation": { 73 | "alignmentPeriod": "60s", 74 | "crossSeriesReducer": "REDUCE_NONE", 75 | "perSeriesAligner": "ALIGN_RATE" 76 | }, 77 | "filter": "metric.type=\"run.googleapis.com/request_count\" resource.type=\"cloud_run_revision\" resource.label.\"project_id\"=\"${PROJECT_ID}\"", 78 | "secondaryAggregation": { 79 | "alignmentPeriod": "60s", 80 | "crossSeriesReducer": "REDUCE_SUM", 81 | "groupByFields": [ 82 | "resource.label.\"service_name\"", 83 | "resource.label.\"location\"" 84 | ], 85 | "perSeriesAligner": "ALIGN_NONE" 86 | } 87 | } 88 | } 89 | } 90 | ], 91 | "thresholds": [], 92 | "timeshiftDuration": "0s", 93 | "yAxis": { 94 | "label": "", 95 | "scale": "LINEAR" 96 | } 97 | } 98 | }, 99 | "width": 6, 100 | "xPos": 0, 101 | "yPos": 0 102 | }, 103 | { 104 | "height": 4, 105 | "widget": { 106 | "title": "Active Container Instance Count", 107 | "xyChart": { 108 | "chartOptions": { 109 | "mode": "COLOR" 110 | }, 111 | "dataSets": [ 112 | { 113 | "minAlignmentPeriod": "60s", 114 | "plotType": "LINE", 115 | "targetAxis": "Y1", 116 | "timeSeriesQuery": { 117 | "apiSource": "DEFAULT_CLOUD", 118 | "timeSeriesFilter": { 119 | "aggregation": { 120 | "alignmentPeriod": "60s", 121 | "crossSeriesReducer": "REDUCE_SUM", 122 | "groupByFields": [ 123 | "metric.label.\"state\"", 124 | "resource.label.\"service_name\"", 125 | "resource.label.\"location\"" 126 | ], 127 | "perSeriesAligner": "ALIGN_MEAN" 128 | }, 129 | "filter": "metric.type=\"run.googleapis.com/container/instance_count\" resource.type=\"cloud_run_revision\" resource.label.\"project_id\"=\"${PROJECT_ID}\" metric.label.\"state\"=\"active\"", 130 | "secondaryAggregation": { 131 | "alignmentPeriod": "60s", 132 | "crossSeriesReducer": "REDUCE_NONE", 133 | "perSeriesAligner": "ALIGN_NONE" 134 | } 135 | } 136 | } 137 | } 138 | ], 139 | "thresholds": [], 140 | "timeshiftDuration": "0s", 141 | "yAxis": { 142 | "label": "", 143 | "scale": "LINEAR" 144 | } 145 | } 146 | }, 147 | "width": 6, 148 | "xPos": 0, 149 | "yPos": 4 150 | }, 151 | { 152 | "height": 4, 153 | "widget": { 154 | "title": "Idle Container Instance Count", 155 | "xyChart": { 156 | "chartOptions": { 157 | "mode": "COLOR" 158 | }, 159 | "dataSets": [ 160 | { 161 | "minAlignmentPeriod": "60s", 162 | "plotType": "LINE", 163 | "targetAxis": "Y1", 164 | "timeSeriesQuery": { 165 | "apiSource": "DEFAULT_CLOUD", 166 | "timeSeriesFilter": { 167 | "aggregation": { 168 | "alignmentPeriod": "60s", 169 | "crossSeriesReducer": "REDUCE_SUM", 170 | "groupByFields": [ 171 | "metric.label.\"state\"", 172 | "resource.label.\"service_name\"", 173 | "resource.label.\"location\"" 174 | ], 175 | "perSeriesAligner": "ALIGN_MEAN" 176 | }, 177 | "filter": "metric.type=\"run.googleapis.com/container/instance_count\" resource.type=\"cloud_run_revision\" resource.label.\"project_id\"=\"${PROJECT_ID}\" metric.label.\"state\"=\"idle\"", 178 | "secondaryAggregation": { 179 | "alignmentPeriod": "60s", 180 | "crossSeriesReducer": "REDUCE_NONE", 181 | "perSeriesAligner": "ALIGN_NONE" 182 | } 183 | } 184 | } 185 | } 186 | ], 187 | "thresholds": [], 188 | "timeshiftDuration": "0s", 189 | "yAxis": { 190 | "label": "", 191 | "scale": "LINEAR" 192 | } 193 | } 194 | }, 195 | "width": 6, 196 | "xPos": 6, 197 | "yPos": 4 198 | }, 199 | { 200 | "height": 4, 201 | "widget": { 202 | "title": "Container CPU Allocation", 203 | "xyChart": { 204 | "chartOptions": { 205 | "mode": "COLOR" 206 | }, 207 | "dataSets": [ 208 | { 209 | "minAlignmentPeriod": "60s", 210 | "plotType": "LINE", 211 | "targetAxis": "Y1", 212 | "timeSeriesQuery": { 213 | "apiSource": "DEFAULT_CLOUD", 214 | "timeSeriesFilter": { 215 | "aggregation": { 216 | "alignmentPeriod": "60s", 217 | "crossSeriesReducer": "REDUCE_SUM", 218 | "groupByFields": [ 219 | "resource.label.\"service_name\"", 220 | "resource.label.\"location\"" 221 | ], 222 | "perSeriesAligner": "ALIGN_RATE" 223 | }, 224 | "filter": "metric.type=\"run.googleapis.com/container/cpu/allocation_time\" resource.type=\"cloud_run_revision\" resource.label.\"project_id\"=\"${PROJECT_ID}\"", 225 | "secondaryAggregation": { 226 | "alignmentPeriod": "60s", 227 | "crossSeriesReducer": "REDUCE_NONE", 228 | "perSeriesAligner": "ALIGN_NONE" 229 | } 230 | } 231 | } 232 | } 233 | ], 234 | "thresholds": [], 235 | "timeshiftDuration": "0s", 236 | "yAxis": { 237 | "label": "", 238 | "scale": "LINEAR" 239 | } 240 | } 241 | }, 242 | "width": 6, 243 | "xPos": 6, 244 | "yPos": 8 245 | }, 246 | { 247 | "height": 4, 248 | "widget": { 249 | "title": "Container Memory Allocation", 250 | "xyChart": { 251 | "chartOptions": { 252 | "mode": "COLOR" 253 | }, 254 | "dataSets": [ 255 | { 256 | "minAlignmentPeriod": "60s", 257 | "plotType": "LINE", 258 | "targetAxis": "Y1", 259 | "timeSeriesQuery": { 260 | "apiSource": "DEFAULT_CLOUD", 261 | "timeSeriesFilter": { 262 | "aggregation": { 263 | "alignmentPeriod": "60s", 264 | "crossSeriesReducer": "REDUCE_SUM", 265 | "groupByFields": [ 266 | "resource.label.\"service_name\"", 267 | "resource.label.\"location\"" 268 | ], 269 | "perSeriesAligner": "ALIGN_RATE" 270 | }, 271 | "filter": "metric.type=\"run.googleapis.com/container/memory/allocation_time\" resource.type=\"cloud_run_revision\" resource.label.\"project_id\"=\"${PROJECT_ID}\"", 272 | "secondaryAggregation": { 273 | "alignmentPeriod": "60s", 274 | "crossSeriesReducer": "REDUCE_NONE", 275 | "perSeriesAligner": "ALIGN_NONE" 276 | } 277 | } 278 | } 279 | } 280 | ], 281 | "thresholds": [], 282 | "timeshiftDuration": "0s", 283 | "yAxis": { 284 | "label": "", 285 | "scale": "LINEAR" 286 | } 287 | } 288 | }, 289 | "width": 6, 290 | "xPos": 6, 291 | "yPos": 12 292 | }, 293 | { 294 | "height": 4, 295 | "widget": { 296 | "title": "Container CPU Utilization", 297 | "xyChart": { 298 | "chartOptions": { 299 | "mode": "COLOR" 300 | }, 301 | "dataSets": [ 302 | { 303 | "minAlignmentPeriod": "60s", 304 | "plotType": "LINE", 305 | "targetAxis": "Y1", 306 | "timeSeriesQuery": { 307 | "apiSource": "DEFAULT_CLOUD", 308 | "timeSeriesFilter": { 309 | "aggregation": { 310 | "alignmentPeriod": "60s", 311 | "crossSeriesReducer": "REDUCE_PERCENTILE_99", 312 | "groupByFields": [ 313 | "resource.label.\"service_name\"", 314 | "resource.label.\"location\"" 315 | ], 316 | "perSeriesAligner": "ALIGN_DELTA" 317 | }, 318 | "filter": "metric.type=\"run.googleapis.com/container/cpu/utilizations\" resource.type=\"cloud_run_revision\" resource.label.\"project_id\"=\"${PROJECT_ID}\"", 319 | "secondaryAggregation": { 320 | "alignmentPeriod": "60s", 321 | "crossSeriesReducer": "REDUCE_NONE", 322 | "perSeriesAligner": "ALIGN_NONE" 323 | } 324 | } 325 | } 326 | } 327 | ], 328 | "thresholds": [], 329 | "timeshiftDuration": "0s", 330 | "yAxis": { 331 | "label": "", 332 | "scale": "LINEAR" 333 | } 334 | } 335 | }, 336 | "width": 6, 337 | "xPos": 0, 338 | "yPos": 8 339 | }, 340 | { 341 | "height": 4, 342 | "widget": { 343 | "title": "Container Memory Utilization", 344 | "xyChart": { 345 | "chartOptions": { 346 | "mode": "COLOR" 347 | }, 348 | "dataSets": [ 349 | { 350 | "minAlignmentPeriod": "60s", 351 | "plotType": "LINE", 352 | "targetAxis": "Y1", 353 | "timeSeriesQuery": { 354 | "apiSource": "DEFAULT_CLOUD", 355 | "timeSeriesFilter": { 356 | "aggregation": { 357 | "alignmentPeriod": "60s", 358 | "crossSeriesReducer": "REDUCE_PERCENTILE_99", 359 | "groupByFields": [ 360 | "resource.label.\"service_name\"", 361 | "resource.label.\"location\"" 362 | ], 363 | "perSeriesAligner": "ALIGN_DELTA" 364 | }, 365 | "filter": "metric.type=\"run.googleapis.com/container/memory/utilizations\" resource.type=\"cloud_run_revision\" resource.label.\"project_id\"=\"${PROJECT_ID}\"", 366 | "secondaryAggregation": { 367 | "alignmentPeriod": "60s", 368 | "crossSeriesReducer": "REDUCE_NONE", 369 | "perSeriesAligner": "ALIGN_NONE" 370 | } 371 | } 372 | } 373 | } 374 | ], 375 | "thresholds": [], 376 | "timeshiftDuration": "0s", 377 | "yAxis": { 378 | "label": "", 379 | "scale": "LINEAR" 380 | } 381 | } 382 | }, 383 | "width": 6, 384 | "xPos": 0, 385 | "yPos": 12 386 | }, 387 | { 388 | "height": 4, 389 | "widget": { 390 | "title": "Received Bytes", 391 | "xyChart": { 392 | "chartOptions": { 393 | "mode": "COLOR" 394 | }, 395 | "dataSets": [ 396 | { 397 | "minAlignmentPeriod": "60s", 398 | "plotType": "LINE", 399 | "targetAxis": "Y1", 400 | "timeSeriesQuery": { 401 | "apiSource": "DEFAULT_CLOUD", 402 | "timeSeriesFilter": { 403 | "aggregation": { 404 | "alignmentPeriod": "60s", 405 | "crossSeriesReducer": "REDUCE_SUM", 406 | "groupByFields": [ 407 | "resource.label.\"service_name\"", 408 | "resource.label.\"location\"" 409 | ], 410 | "perSeriesAligner": "ALIGN_RATE" 411 | }, 412 | "filter": "metric.type=\"run.googleapis.com/container/network/received_bytes_count\" resource.type=\"cloud_run_revision\" resource.label.\"project_id\"=\"${PROJECT_ID}\"", 413 | "secondaryAggregation": { 414 | "alignmentPeriod": "60s", 415 | "crossSeriesReducer": "REDUCE_NONE", 416 | "perSeriesAligner": "ALIGN_NONE" 417 | } 418 | } 419 | } 420 | } 421 | ], 422 | "thresholds": [], 423 | "timeshiftDuration": "0s", 424 | "yAxis": { 425 | "label": "", 426 | "scale": "LINEAR" 427 | } 428 | } 429 | }, 430 | "width": 6, 431 | "xPos": 0, 432 | "yPos": 16 433 | }, 434 | { 435 | "height": 4, 436 | "widget": { 437 | "title": "Sent Bytes", 438 | "xyChart": { 439 | "chartOptions": { 440 | "mode": "COLOR" 441 | }, 442 | "dataSets": [ 443 | { 444 | "minAlignmentPeriod": "60s", 445 | "plotType": "LINE", 446 | "targetAxis": "Y1", 447 | "timeSeriesQuery": { 448 | "apiSource": "DEFAULT_CLOUD", 449 | "timeSeriesFilter": { 450 | "aggregation": { 451 | "alignmentPeriod": "60s", 452 | "crossSeriesReducer": "REDUCE_SUM", 453 | "groupByFields": [ 454 | "resource.label.\"service_name\"", 455 | "resource.label.\"location\"" 456 | ], 457 | "perSeriesAligner": "ALIGN_RATE" 458 | }, 459 | "filter": "metric.type=\"run.googleapis.com/container/network/sent_bytes_count\" resource.type=\"cloud_run_revision\" resource.label.\"project_id\"=\"${PROJECT_ID}\"", 460 | "secondaryAggregation": { 461 | "alignmentPeriod": "60s", 462 | "crossSeriesReducer": "REDUCE_NONE", 463 | "perSeriesAligner": "ALIGN_NONE" 464 | } 465 | } 466 | } 467 | } 468 | ], 469 | "thresholds": [], 470 | "timeshiftDuration": "0s", 471 | "yAxis": { 472 | "label": "", 473 | "scale": "LINEAR" 474 | } 475 | } 476 | }, 477 | "width": 6, 478 | "xPos": 6, 479 | "yPos": 16 480 | }, 481 | { 482 | "height": 4, 483 | "widget": { 484 | "title": "Container Startup Latency", 485 | "xyChart": { 486 | "chartOptions": { 487 | "mode": "COLOR" 488 | }, 489 | "dataSets": [ 490 | { 491 | "minAlignmentPeriod": "60s", 492 | "plotType": "STACKED_BAR", 493 | "targetAxis": "Y1", 494 | "timeSeriesQuery": { 495 | "apiSource": "DEFAULT_CLOUD", 496 | "timeSeriesFilter": { 497 | "aggregation": { 498 | "alignmentPeriod": "60s", 499 | "crossSeriesReducer": "REDUCE_MEAN", 500 | "groupByFields": [ 501 | "resource.label.\"service_name\"", 502 | "resource.label.\"location\"" 503 | ], 504 | "perSeriesAligner": "ALIGN_PERCENTILE_99" 505 | }, 506 | "filter": "metric.type=\"run.googleapis.com/container/startup_latencies\" resource.type=\"cloud_run_revision\" resource.label.\"project_id\"=\"${PROJECT_ID}\"", 507 | "secondaryAggregation": { 508 | "alignmentPeriod": "60s", 509 | "crossSeriesReducer": "REDUCE_NONE", 510 | "perSeriesAligner": "ALIGN_NONE" 511 | } 512 | } 513 | } 514 | } 515 | ], 516 | "thresholds": [], 517 | "timeshiftDuration": "0s", 518 | "yAxis": { 519 | "label": "", 520 | "scale": "LINEAR" 521 | } 522 | } 523 | }, 524 | "width": 6, 525 | "xPos": 0, 526 | "yPos": 20 527 | } 528 | ] 529 | } 530 | } 531 | --------------------------------------------------------------------------------