Factories refactor (#1843)
* factories refactor doc * Adds file schema and filesystem organization * Update 20231106-factories.md * move factories out of blueprints and create new factories README * align factory in billing-account module * align factory in dataplex-datascan module * align factory in billing-account module * align factory in net-firewall-policy module * align factory in dns-response-policy module * align factory in net-vpc-firewall module * align factory in net-vpc module * align factory variable names in FAST * remove decentralized firewall blueprint * bump terraform version * bump module versions * update top-level READMEs * move project factory to modules * fix variable names and tests * tfdoc * remove changelog link * add project factory to top-level README * fix cludrun eventarc diff * fix README * fix cludrun eventarc diff --------- Co-authored-by: Simone Ruffilli <sruffilli@google.com>
This commit is contained in:
committed by
GitHub
parent
8e86f0e108
commit
6941313c7d
89
modules/__experimental_deprecated/alloydb-instance/README.md
Normal file
89
modules/__experimental_deprecated/alloydb-instance/README.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# AlloyDB cluster and instance with read replicas
|
||||
|
||||
This module manages the creation of AlloyDB cluster and configuration with/without automated backup policy, Primary node instance and Read Node Pools.
|
||||
|
||||
|
||||
## Simple example
|
||||
|
||||
This example shows how to create Alloydb cluster and instance with multiple read pools in GCP project.
|
||||
|
||||
```hcl
|
||||
module "alloydb" {
|
||||
source = "./fabric/modules/alloydb-instance"
|
||||
project_id = "myproject"
|
||||
cluster_id = "alloydb-cluster-all"
|
||||
location = "europe-west2"
|
||||
labels = {}
|
||||
display_name = ""
|
||||
initial_user = {
|
||||
user = "alloydb-cluster-full",
|
||||
password = "alloydb-cluster-password"
|
||||
}
|
||||
network_self_link = "projects/myproject/global/networks/default"
|
||||
|
||||
automated_backup_policy = null
|
||||
|
||||
primary_instance_config = {
|
||||
instance_id = "primary-instance-1",
|
||||
instance_type = "PRIMARY",
|
||||
machine_cpu_count = 2,
|
||||
database_flags = {},
|
||||
display_name = "alloydb-primary-instance"
|
||||
}
|
||||
read_pool_instance = [
|
||||
{
|
||||
instance_id = "read-instance-1",
|
||||
display_name = "read-instance-1",
|
||||
instance_type = "READ_POOL",
|
||||
node_count = 1,
|
||||
database_flags = {},
|
||||
machine_cpu_count = 1
|
||||
},
|
||||
{
|
||||
instance_id = "read-instance-2",
|
||||
display_name = "read-instance-2",
|
||||
instance_type = "READ_POOL",
|
||||
node_count = 1,
|
||||
database_flags = {},
|
||||
machine_cpu_count = 1
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
# tftest skip
|
||||
```
|
||||
## TODO
|
||||
- [ ] Add IAM support
|
||||
- [ ] support password in output
|
||||
<!-- BEGIN TFDOC -->
|
||||
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [cluster_id](variables.tf#L35) | The ID of the alloydb cluster. | <code>string</code> | ✓ | |
|
||||
| [network_self_link](variables.tf#L83) | Network ID where the AlloyDb cluster will be deployed. | <code>string</code> | ✓ | |
|
||||
| [primary_instance_config](variables.tf#L88) | Primary cluster configuration that supports read and write operations. | <code title="object({ instance_id = string, display_name = optional(string), database_flags = optional(map(string)) labels = optional(map(string)) annotations = optional(map(string)) gce_zone = optional(string) availability_type = optional(string) machine_cpu_count = optional(number, 2), })">object({…})</code> | ✓ | |
|
||||
| [project_id](variables.tf#L110) | The ID of the project in which to provision resources. | <code>string</code> | ✓ | |
|
||||
| [automated_backup_policy](variables.tf#L17) | The automated backup policy for this cluster. | <code title="object({ location = optional(string) backup_window = optional(string) enabled = optional(bool) weekly_schedule = optional(object({ days_of_week = optional(list(string)) start_times = list(string) })), quantity_based_retention_count = optional(number) time_based_retention_count = optional(string) labels = optional(map(string)) backup_encryption_key_name = optional(string) })">object({…})</code> | | <code>null</code> |
|
||||
| [display_name](variables.tf#L44) | Human readable display name for the Alloy DB Cluster. | <code>string</code> | | <code>null</code> |
|
||||
| [encryption_key_name](variables.tf#L50) | The fully-qualified resource name of the KMS key for cluster encryption. | <code>string</code> | | <code>null</code> |
|
||||
| [initial_user](variables.tf#L56) | Alloy DB Cluster Initial User Credentials. | <code title="object({ user = optional(string), password = string })">object({…})</code> | | <code>null</code> |
|
||||
| [labels](variables.tf#L65) | User-defined labels for the alloydb cluster. | <code>map(string)</code> | | <code>{}</code> |
|
||||
| [location](variables.tf#L71) | Location where AlloyDb cluster will be deployed. | <code>string</code> | | <code>"europe-west2"</code> |
|
||||
| [network_name](variables.tf#L77) | The network name of the project in which to provision resources. | <code>string</code> | | <code>"multiple-readpool"</code> |
|
||||
| [read_pool_instance](variables.tf#L115) | List of Read Pool Instances to be created. | <code title="list(object({ instance_id = string display_name = string node_count = optional(number, 1) database_flags = optional(map(string)) availability_type = optional(string) gce_zone = optional(string) machine_cpu_count = optional(number, 2) }))">list(object({…}))</code> | | <code>[]</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
| name | description | sensitive |
|
||||
|---|---|:---:|
|
||||
| [cluster](outputs.tf#L17) | Cluster created. | ✓ |
|
||||
| [cluster_id](outputs.tf#L23) | ID of the Alloy DB Cluster created. | |
|
||||
| [primary_instance](outputs.tf#L28) | Primary instance created. | |
|
||||
| [primary_instance_id](outputs.tf#L33) | ID of the primary instance created. | |
|
||||
| [read_pool_instance_ids](outputs.tf#L38) | IDs of the read instances created. | |
|
||||
|
||||
<!-- END TFDOC -->
|
||||
|
||||
160
modules/__experimental_deprecated/alloydb-instance/main.tf
Normal file
160
modules/__experimental_deprecated/alloydb-instance/main.tf
Normal file
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
locals {
|
||||
quantity_based_retention_count = (
|
||||
var.automated_backup_policy != null ? (var.automated_backup_policy.quantity_based_retention_count != null ? [var.automated_backup_policy.quantity_based_retention_count] : []) : []
|
||||
)
|
||||
read_pool_instance = (
|
||||
var.read_pool_instance != null ?
|
||||
{ for read_pool_instances in var.read_pool_instance : read_pool_instances.instance_id => read_pool_instances } : {}
|
||||
)
|
||||
time_based_retention_count = (
|
||||
var.automated_backup_policy != null ? (var.automated_backup_policy.time_based_retention_count != null ? [var.automated_backup_policy.time_based_retention_count] : []) : []
|
||||
)
|
||||
}
|
||||
|
||||
resource "google_alloydb_cluster" "default" {
|
||||
cluster_id = var.cluster_id
|
||||
location = var.location
|
||||
network = var.network_self_link
|
||||
display_name = var.display_name
|
||||
project = var.project_id
|
||||
labels = var.labels
|
||||
|
||||
dynamic "automated_backup_policy" {
|
||||
for_each = var.automated_backup_policy == null ? [] : [""]
|
||||
content {
|
||||
location = var.automated_backup_policy.location
|
||||
backup_window = var.automated_backup_policy.backup_window
|
||||
enabled = var.automated_backup_policy.enabled
|
||||
labels = var.automated_backup_policy.labels
|
||||
|
||||
|
||||
weekly_schedule {
|
||||
days_of_week = automated_backup_policy.value.weekly_schedule.days_of_week
|
||||
dynamic "start_times" {
|
||||
for_each = { for i, time in automated_backup_policy.value.weekly_schedule.start_times : i => {
|
||||
hours = tonumber(split(":", time)[0])
|
||||
minutes = tonumber(split(":", time)[1])
|
||||
seconds = tonumber(split(":", time)[2])
|
||||
nanos = tonumber(split(":", time)[3])
|
||||
}
|
||||
}
|
||||
content {
|
||||
hours = start_times.value.hours
|
||||
minutes = start_times.value.minutes
|
||||
seconds = start_times.value.seconds
|
||||
nanos = start_times.value.nanos
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "quantity_based_retention" {
|
||||
for_each = local.quantity_based_retention_count
|
||||
content {
|
||||
count = quantity_based_retention.value
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "time_based_retention" {
|
||||
for_each = local.time_based_retention_count
|
||||
content {
|
||||
retention_period = time_based_retention.value
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "encryption_config" {
|
||||
for_each = automated_backup_policy.value.backup_encryption_key_name == null ? [] : ["encryption_config"]
|
||||
content {
|
||||
kms_key_name = automated_backup_policy.value.backup_encryption_key_name
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dynamic "initial_user" {
|
||||
for_each = var.initial_user == null ? [] : ["initial_user"]
|
||||
content {
|
||||
user = var.initial_user.user
|
||||
password = var.initial_user.password
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "encryption_config" {
|
||||
for_each = var.encryption_key_name == null ? [] : ["encryption_config"]
|
||||
content {
|
||||
kms_key_name = var.encryption_key_name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_alloydb_instance" "primary" {
|
||||
cluster = google_alloydb_cluster.default.name
|
||||
instance_id = var.primary_instance_config.instance_id
|
||||
instance_type = "PRIMARY"
|
||||
display_name = var.primary_instance_config.display_name
|
||||
database_flags = var.primary_instance_config.database_flags
|
||||
labels = var.primary_instance_config.labels
|
||||
annotations = var.primary_instance_config.annotations
|
||||
gce_zone = var.primary_instance_config.availability_type == "ZONAL" ? var.primary_instance_config.gce_zone : null
|
||||
availability_type = var.primary_instance_config.availability_type
|
||||
|
||||
machine_config {
|
||||
cpu_count = var.primary_instance_config.machine_cpu_count
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
resource "google_alloydb_instance" "read_pool" {
|
||||
for_each = local.read_pool_instance
|
||||
cluster = google_alloydb_cluster.default.name
|
||||
instance_id = each.key
|
||||
instance_type = "READ_POOL"
|
||||
availability_type = each.value.availability_type
|
||||
gce_zone = each.value.availability_type == "ZONAL" ? each.value.availability_type.gce_zone : null
|
||||
|
||||
read_pool_config {
|
||||
node_count = each.value.node_count
|
||||
}
|
||||
|
||||
database_flags = each.value.database_flags
|
||||
machine_config {
|
||||
cpu_count = each.value.machine_cpu_count
|
||||
}
|
||||
|
||||
depends_on = [google_alloydb_instance.primary, google_compute_network.default, google_compute_global_address.private_ip_alloc, google_service_networking_connection.vpc_connection]
|
||||
}
|
||||
|
||||
resource "google_compute_network" "default" {
|
||||
name = var.network_name
|
||||
}
|
||||
|
||||
resource "google_compute_global_address" "private_ip_alloc" {
|
||||
name = "adb-all"
|
||||
address_type = "INTERNAL"
|
||||
purpose = "VPC_PEERING"
|
||||
prefix_length = 16
|
||||
network = google_compute_network.default.id
|
||||
}
|
||||
|
||||
resource "google_service_networking_connection" "vpc_connection" {
|
||||
network = google_compute_network.default.id
|
||||
service = "servicenetworking.googleapis.com"
|
||||
reserved_peering_ranges = [google_compute_global_address.private_ip_alloc.name]
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
output "cluster" {
|
||||
description = "Cluster created."
|
||||
value = resource.google_alloydb_cluster.default.display_name
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
output "cluster_id" {
|
||||
description = "ID of the Alloy DB Cluster created."
|
||||
value = google_alloydb_cluster.default.cluster_id
|
||||
}
|
||||
|
||||
output "primary_instance" {
|
||||
description = "Primary instance created."
|
||||
value = resource.google_alloydb_instance.primary.display_name
|
||||
}
|
||||
|
||||
output "primary_instance_id" {
|
||||
description = "ID of the primary instance created."
|
||||
value = google_alloydb_instance.primary.instance_id
|
||||
}
|
||||
|
||||
output "read_pool_instance_ids" {
|
||||
description = "IDs of the read instances created."
|
||||
value = [
|
||||
for rd, details in google_alloydb_instance.read_pool : details.instance_id
|
||||
]
|
||||
}
|
||||
127
modules/__experimental_deprecated/alloydb-instance/variables.tf
Normal file
127
modules/__experimental_deprecated/alloydb-instance/variables.tf
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
variable "automated_backup_policy" {
|
||||
description = "The automated backup policy for this cluster."
|
||||
type = object({
|
||||
location = optional(string)
|
||||
backup_window = optional(string)
|
||||
enabled = optional(bool)
|
||||
weekly_schedule = optional(object({
|
||||
days_of_week = optional(list(string))
|
||||
start_times = list(string)
|
||||
})),
|
||||
quantity_based_retention_count = optional(number)
|
||||
time_based_retention_count = optional(string)
|
||||
labels = optional(map(string))
|
||||
backup_encryption_key_name = optional(string)
|
||||
})
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "cluster_id" {
|
||||
description = "The ID of the alloydb cluster."
|
||||
type = string
|
||||
validation {
|
||||
condition = can(regex("^[a-z0-9-]+$", var.cluster_id))
|
||||
error_message = "ERROR: Cluster ID must contain only Letters(lowercase), number, and hyphen."
|
||||
}
|
||||
}
|
||||
|
||||
variable "display_name" {
|
||||
description = "Human readable display name for the Alloy DB Cluster."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "encryption_key_name" {
|
||||
description = "The fully-qualified resource name of the KMS key for cluster encryption."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "initial_user" {
|
||||
description = "Alloy DB Cluster Initial User Credentials."
|
||||
type = object({
|
||||
user = optional(string),
|
||||
password = string
|
||||
})
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "labels" {
|
||||
description = "User-defined labels for the alloydb cluster."
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "location" {
|
||||
description = "Location where AlloyDb cluster will be deployed."
|
||||
type = string
|
||||
default = "europe-west2"
|
||||
}
|
||||
|
||||
variable "network_name" {
|
||||
description = "The network name of the project in which to provision resources."
|
||||
type = string
|
||||
default = "multiple-readpool"
|
||||
}
|
||||
|
||||
variable "network_self_link" {
|
||||
description = "Network ID where the AlloyDb cluster will be deployed."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "primary_instance_config" {
|
||||
description = "Primary cluster configuration that supports read and write operations."
|
||||
type = object({
|
||||
instance_id = string,
|
||||
display_name = optional(string),
|
||||
database_flags = optional(map(string))
|
||||
labels = optional(map(string))
|
||||
annotations = optional(map(string))
|
||||
gce_zone = optional(string)
|
||||
availability_type = optional(string)
|
||||
machine_cpu_count = optional(number, 2),
|
||||
})
|
||||
validation {
|
||||
condition = can(regex("^(2|4|8|16|32|64)$", var.primary_instance_config.machine_cpu_count))
|
||||
error_message = "cpu count must be one of [2 4 8 16 32 64]."
|
||||
}
|
||||
validation {
|
||||
condition = can(regex("^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$", var.primary_instance_config.instance_id))
|
||||
error_message = "Primary Instance ID should satisfy the following pattern ^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$."
|
||||
}
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
description = "The ID of the project in which to provision resources."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "read_pool_instance" {
|
||||
description = "List of Read Pool Instances to be created."
|
||||
type = list(object({
|
||||
instance_id = string
|
||||
display_name = string
|
||||
node_count = optional(number, 1)
|
||||
database_flags = optional(map(string))
|
||||
availability_type = optional(string)
|
||||
gce_zone = optional(string)
|
||||
machine_cpu_count = optional(number, 2)
|
||||
}))
|
||||
default = []
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
# Copyright 2024 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
terraform {
|
||||
required_version = ">= 1.7.4"
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = ">= 5.12.0, < 6.0.0" # tftest
|
||||
}
|
||||
google-beta = {
|
||||
source = "hashicorp/google-beta"
|
||||
version = ">= 5.12.0, < 6.0.0" # tftest
|
||||
}
|
||||
}
|
||||
}
|
||||
79
modules/__experimental_deprecated/bigquery-factory/README.md
Normal file
79
modules/__experimental_deprecated/bigquery-factory/README.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Google Cloud BQ Factory
|
||||
|
||||
This module allows creation and management of BigQuery datasets tables and views by defining them in well-formatted YAML files. YAML abstraction for BQ can simplify users onboarding and also makes creation of tables easier compared to HCL.
|
||||
|
||||
This factory is based on the [BQ dataset module](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/tree/master/modules/bigquery-dataset) which currently only supports tables and views. As soon as external table and materialized view support is added, this factory will be enhanced accordingly.
|
||||
|
||||
You can create as many files as you like, the code will loop through it and create everything accordingly.
|
||||
|
||||
## Example
|
||||
|
||||
### Terraform code
|
||||
|
||||
In this section we show how to create tables and views from a file structure similar to the one shown below.
|
||||
|
||||
```bash
|
||||
bigquery
|
||||
│
|
||||
├── tables
|
||||
│ ├── table_a.yaml
|
||||
│ ├── table_b.yaml
|
||||
├── views
|
||||
│ ├── view_a.yaml
|
||||
│ ├── view_b.yaml
|
||||
```
|
||||
|
||||
First we create the table definition in `bigquery/tables/countries.yaml`.
|
||||
|
||||
```yaml
|
||||
# tftest-file id=table path=bigquery/tables/countries.yaml
|
||||
dataset: my_dataset
|
||||
table: countries
|
||||
deletion_protection: true
|
||||
labels:
|
||||
env: prod
|
||||
schema:
|
||||
- name: country
|
||||
type: STRING
|
||||
- name: population
|
||||
type: INT64
|
||||
```
|
||||
|
||||
And a view in `bigquery/views/population.yaml`.
|
||||
|
||||
```yaml
|
||||
# tftest-file id=view path=bigquery/views/population.yaml
|
||||
dataset: my_dataset
|
||||
view: department
|
||||
query: SELECT SUM(population) from my_dataset.countries
|
||||
labels:
|
||||
env: prod
|
||||
```
|
||||
|
||||
With this file structure, we can use the factory as follows:
|
||||
|
||||
```hcl
|
||||
module "bq" {
|
||||
source = "./fabric/modules/__experimental_deprecated/bigquery-factory"
|
||||
project_id = var.project_id
|
||||
tables_path = "bigquery/tables"
|
||||
views_path = "bigquery/views"
|
||||
}
|
||||
# tftest modules=2 resources=3 files=table,view
|
||||
```
|
||||
<!-- BEGIN TFDOC -->
|
||||
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [project_id](variables.tf#L17) | Project ID. | <code>string</code> | ✓ | |
|
||||
| [tables_path](variables.tf#L22) | Relative path for the folder storing table data. | <code>string</code> | ✓ | |
|
||||
| [views_path](variables.tf#L27) | Relative path for the folder storing view data. | <code>string</code> | ✓ | |
|
||||
|
||||
<!-- END TFDOC -->
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] add external table support
|
||||
- [ ] add materialized view support
|
||||
71
modules/__experimental_deprecated/bigquery-factory/main.tf
Normal file
71
modules/__experimental_deprecated/bigquery-factory/main.tf
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
locals {
|
||||
views = {
|
||||
for f in fileset(var.views_path, "**/*.yaml") :
|
||||
trimsuffix(f, ".yaml") => yamldecode(file("${var.views_path}/${f}"))
|
||||
}
|
||||
|
||||
tables = {
|
||||
for f in fileset(var.tables_path, "**/*.yaml") :
|
||||
trimsuffix(f, ".yaml") => yamldecode(file("${var.tables_path}/${f}"))
|
||||
}
|
||||
|
||||
all_datasets = distinct(concat(
|
||||
[for x in values(local.tables) : x.dataset],
|
||||
[for x in values(local.views) : x.dataset]
|
||||
))
|
||||
|
||||
datasets = {
|
||||
for dataset in local.all_datasets :
|
||||
dataset => {
|
||||
"views" = {
|
||||
for k, v in local.views :
|
||||
v.view => {
|
||||
friendly_name = v.view
|
||||
labels = try(v.labels, null)
|
||||
query = v.query
|
||||
use_legacy_sql = try(v.use_legacy_sql, false)
|
||||
deletion_protection = try(v.deletion_protection, false)
|
||||
}
|
||||
if v.dataset == dataset
|
||||
},
|
||||
"tables" = {
|
||||
for k, v in local.tables :
|
||||
v.table => {
|
||||
friendly_name = v.table
|
||||
labels = try(v.labels, null)
|
||||
options = try(v.options, null)
|
||||
partitioning = try(v.partitioning, null)
|
||||
schema = jsonencode(v.schema)
|
||||
use_legacy_sql = try(v.use_legacy_sql, false)
|
||||
deletion_protection = try(v.deletion_protection, false)
|
||||
}
|
||||
if v.dataset == dataset
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module "bq" {
|
||||
source = "../../../modules/bigquery-dataset"
|
||||
for_each = local.datasets
|
||||
project_id = var.project_id
|
||||
id = each.key
|
||||
views = try(each.value.views, null)
|
||||
tables = try(each.value.tables, null)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
variable "project_id" {
|
||||
description = "Project ID."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "tables_path" {
|
||||
description = "Relative path for the folder storing table data."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "views_path" {
|
||||
description = "Relative path for the folder storing view data."
|
||||
type = string
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
# Google Cloud Identity Group Factory
|
||||
|
||||
This module allows creation and management of Cloud Identity Groups by defining them in well formatted `yaml` files.
|
||||
|
||||
Yaml abstraction for Groups can simplify groups creation and members management. Yaml can be simpler and clearer comparing to HCL.
|
||||
|
||||
## Example
|
||||
|
||||
### Terraform code
|
||||
|
||||
```hcl
|
||||
module "groups" {
|
||||
source = "./fabric/modules/__experimental_deprecated/cloud-identity-group-factory"
|
||||
customer_id = "customers/C0xxxxxxx"
|
||||
data_dir = "data"
|
||||
}
|
||||
# tftest modules=2 resources=3 files=group1
|
||||
```
|
||||
|
||||
```yaml
|
||||
# tftest-file id=group1 path=data/group1@example.com.yaml
|
||||
display_name: Group 1
|
||||
description: Group 1
|
||||
members:
|
||||
- user1@example.com
|
||||
managers:
|
||||
- user2@example.com
|
||||
```
|
||||
|
||||
### Configuration Structure
|
||||
|
||||
Groups configuration should be placed in a set of yaml files. The name of the file identify the name of the group.
|
||||
|
||||
```bash
|
||||
├── data
|
||||
├── group1@domain.com.yaml
|
||||
├── group2@domain.com.yaml
|
||||
|
||||
```
|
||||
|
||||
### Group definition format and structure
|
||||
|
||||
Within each file, the group entry structure is following:
|
||||
|
||||
```yaml
|
||||
display_name: Group 1 # Group display name.
|
||||
description: Group 1 description # Group description.
|
||||
members: # List of group members.
|
||||
- user_1@example.com
|
||||
- user_2@example.com
|
||||
managers: # List of group managers.
|
||||
- manager_1@example.com
|
||||
```
|
||||
<!-- BEGIN TFDOC -->
|
||||
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [customer_id](variables.tf#L17) | Directory customer ID in the form customers/C0xxxxxxx. | <code>string</code> | ✓ | |
|
||||
| [data_dir](variables.tf#L22) | Relative path for the folder storing configuration data. | <code>string</code> | ✓ | |
|
||||
|
||||
## Outputs
|
||||
|
||||
| name | description | sensitive |
|
||||
|---|---|:---:|
|
||||
| [group_id](outputs.tf#L17) | Group name => Group ID mapping. | |
|
||||
|
||||
<!-- END TFDOC -->
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
locals {
|
||||
groups = {
|
||||
for f in fileset("${var.data_dir}", "**/*.yaml") :
|
||||
trimsuffix(f, ".yaml") => yamldecode(file("${var.data_dir}/${f}"))
|
||||
}
|
||||
}
|
||||
|
||||
module "group" {
|
||||
source = "../../../modules/cloud-identity-group"
|
||||
for_each = local.groups
|
||||
customer_id = var.customer_id
|
||||
name = each.key
|
||||
display_name = try(each.value.display_name, null)
|
||||
description = try(each.value.description, null)
|
||||
members = try(each.value.members, [])
|
||||
managers = try(each.value.managers, [])
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
output "group_id" {
|
||||
description = "Group name => Group ID mapping."
|
||||
value = {
|
||||
for k in module.group :
|
||||
k.name => k.id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
variable "customer_id" {
|
||||
description = "Directory customer ID in the form customers/C0xxxxxxx."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "data_dir" {
|
||||
description = "Relative path for the folder storing configuration data."
|
||||
type = string
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# Google Cloud DNS Inbound Policy Addresses
|
||||
|
||||
This module allows discovering the addresses reserved in subnets when [DNS Inbound Policies](https://cloud.google.com/dns/docs/policies) are configured.
|
||||
|
||||
Since it's currently impossible to fetch those addresses using a GCP data source (see [this issue](https://github.com/hashicorp/terraform-provider-google/issues/3753) for more details), the workaround used here is to derive the authorization token from the Google provider, and do a direct HTTP call to the Compute API.
|
||||
|
||||
## Examples
|
||||
|
||||
```hcl
|
||||
module "dns-policy-addresses" {
|
||||
source = "./fabric/modules/__experimental/net-dns-policy-addresses"
|
||||
project_id = "myproject"
|
||||
regions = ["europe-west1", "europe-west3"]
|
||||
}
|
||||
# tftest skip (uses data sources)
|
||||
```
|
||||
|
||||
The output is a map with lists of addresses of type `DNS_RESOLVER` for each region specified in variables.
|
||||
|
||||
<!-- BEGIN TFDOC -->
|
||||
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [project_id](variables.tf#L17) | Project id. | <code>string</code> | ✓ | |
|
||||
| [regions](variables.tf#L22) | Regions to fetch addresses from. | <code>list(string)</code> | | <code>["europe-west1"]</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
| name | description | sensitive |
|
||||
|---|---|:---:|
|
||||
| [addresses](outputs.tf#L24) | DNS inbound policy addresses per region. | |
|
||||
|
||||
<!-- END TFDOC -->
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
locals {
|
||||
url = format(
|
||||
"https://content-compute.googleapis.com/compute/v1/projects/%s",
|
||||
var.project_id
|
||||
)
|
||||
}
|
||||
|
||||
data "google_client_config" "current" {}
|
||||
|
||||
data "http" "addresses" {
|
||||
for_each = toset(var.regions)
|
||||
url = "${local.url}/regions/${each.key}/addresses?filter=purpose%20%3D%20%22DNS_RESOLVER%22"
|
||||
request_headers = {
|
||||
Authorization = "Bearer ${data.google_client_config.current.access_token}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
locals {
|
||||
region_addresses = {
|
||||
for k, v in data.http.addresses : k => try(jsondecode(v.body), {})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
output "addresses" {
|
||||
description = "DNS inbound policy addresses per region."
|
||||
value = {
|
||||
for k, v in local.region_addresses : k => [
|
||||
for i in try(v.items, []) : i.address
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
variable "project_id" {
|
||||
description = "Project id."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "regions" {
|
||||
description = "Regions to fetch addresses from."
|
||||
nullable = false
|
||||
type = list(string)
|
||||
default = ["europe-west1"]
|
||||
}
|
||||
48
modules/__experimental_deprecated/net-neg/README.md
Normal file
48
modules/__experimental_deprecated/net-neg/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Network Endpoint Group Module
|
||||
|
||||
This modules allows creating zonal network endpoint groups.
|
||||
|
||||
Note: this module will integrated into a general-purpose load balancing module in the future.
|
||||
|
||||
## Example
|
||||
```hcl
|
||||
module "neg" {
|
||||
source = "./fabric/modules/__experimental/net-neg/"
|
||||
project_id = "myproject"
|
||||
name = "myneg"
|
||||
network = var.vpc.self_link
|
||||
subnetwork = var.subnet.self_link
|
||||
zone = "europe-west1-b"
|
||||
endpoints = [
|
||||
for instance in module.vm.instances :
|
||||
{
|
||||
instance = instance.name
|
||||
port = 80
|
||||
ip_address = instance.network_interface[0].network_ip
|
||||
}
|
||||
]
|
||||
}
|
||||
# tftest skip
|
||||
```
|
||||
<!-- BEGIN TFDOC -->
|
||||
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [endpoints](variables.tf#L17) | List of (instance, port, address) of the NEG. | <code title="list(object({ instance = string port = number ip_address = string }))">list(object({…}))</code> | ✓ | |
|
||||
| [name](variables.tf#L26) | NEG name. | <code>string</code> | ✓ | |
|
||||
| [network](variables.tf#L31) | Name or self link of the VPC used for the NEG. Use the self link for Shared VPC. | <code>string</code> | ✓ | |
|
||||
| [project_id](variables.tf#L36) | NEG project id. | <code>string</code> | ✓ | |
|
||||
| [subnetwork](variables.tf#L41) | VPC subnetwork name or self link. | <code>string</code> | ✓ | |
|
||||
| [zone](variables.tf#L46) | NEG zone. | <code>string</code> | ✓ | |
|
||||
|
||||
## Outputs
|
||||
|
||||
| name | description | sensitive |
|
||||
|---|---|:---:|
|
||||
| [id](outputs.tf#L17) | Network endpoint group ID. | |
|
||||
| [self_lnk](outputs.tf#L22) | Network endpoint group self link. | |
|
||||
| [size](outputs.tf#L27) | Size of the network endpoint group. | |
|
||||
|
||||
<!-- END TFDOC -->
|
||||
33
modules/__experimental_deprecated/net-neg/main.tf
Normal file
33
modules/__experimental_deprecated/net-neg/main.tf
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
resource "google_compute_network_endpoint_group" "group" {
|
||||
project = var.project_id
|
||||
name = var.name
|
||||
network = var.network
|
||||
subnetwork = var.subnetwork
|
||||
zone = var.zone
|
||||
}
|
||||
|
||||
resource "google_compute_network_endpoint" "endpoint" {
|
||||
for_each = { for endpoint in var.endpoints : endpoint.instance => endpoint }
|
||||
project = var.project_id
|
||||
network_endpoint_group = google_compute_network_endpoint_group.group.name
|
||||
instance = each.value.instance
|
||||
port = each.value.port
|
||||
ip_address = each.value.ip_address
|
||||
zone = var.zone
|
||||
}
|
||||
30
modules/__experimental_deprecated/net-neg/outputs.tf
Normal file
30
modules/__experimental_deprecated/net-neg/outputs.tf
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
output "id" {
|
||||
description = "Network endpoint group ID."
|
||||
value = google_compute_network_endpoint_group.group.name
|
||||
}
|
||||
|
||||
output "self_lnk" {
|
||||
description = "Network endpoint group self link."
|
||||
value = google_compute_network_endpoint_group.group.self_link
|
||||
}
|
||||
|
||||
output "size" {
|
||||
description = "Size of the network endpoint group."
|
||||
value = google_compute_network_endpoint_group.group.size
|
||||
}
|
||||
49
modules/__experimental_deprecated/net-neg/variables.tf
Normal file
49
modules/__experimental_deprecated/net-neg/variables.tf
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
variable "endpoints" {
|
||||
description = "List of (instance, port, address) of the NEG."
|
||||
type = list(object({
|
||||
instance = string
|
||||
port = number
|
||||
ip_address = string
|
||||
}))
|
||||
}
|
||||
|
||||
variable "name" {
|
||||
description = "NEG name."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "network" {
|
||||
description = "Name or self link of the VPC used for the NEG. Use the self link for Shared VPC."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
description = "NEG project id."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "subnetwork" {
|
||||
description = "VPC subnetwork name or self link."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "zone" {
|
||||
description = "NEG zone."
|
||||
type = string
|
||||
}
|
||||
27
modules/__experimental_deprecated/net-neg/versions.tf
Normal file
27
modules/__experimental_deprecated/net-neg/versions.tf
Normal file
@@ -0,0 +1,27 @@
|
||||
# Copyright 2024 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
terraform {
|
||||
required_version = ">= 1.7.4"
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = ">= 5.12.0, < 6.0.0" # tftest
|
||||
}
|
||||
google-beta = {
|
||||
source = "hashicorp/google-beta"
|
||||
version = ">= 5.12.0, < 6.0.0" # tftest
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
# Copyright 2024 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
terraform {
|
||||
required_version = ">= 1.7.4"
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = ">= 5.12.0, < 6.0.0" # tftest
|
||||
}
|
||||
google-beta = {
|
||||
source = "hashicorp/google-beta"
|
||||
version = ">= 5.12.0, < 6.0.0" # tftest
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user