From 7a4298783a6c343ac2fa15dcccd83f8a68cbf8a2 Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Thu, 15 Sep 2022 16:47:18 +0200 Subject: [PATCH] Removed old and unused modules --- CHANGELOG.md | 2 +- README.md | 2 +- modules/README.md | 1 - modules/folders-unit/README.md | 57 ------- modules/folders-unit/locals.tf | 58 ------- modules/folders-unit/main.tf | 109 ------------- modules/folders-unit/outputs.tf | 59 ------- modules/folders-unit/variables.tf | 116 -------------- modules/folders-unit/versions.tf | 29 ---- modules/iot-core/README.md | 145 ------------------ modules/iot-core/diagram.png | Bin 481113 -> 0 bytes modules/iot-core/diagram_iot.png | Bin 53046 -> 0 bytes modules/iot-core/main.tf | 95 ------------ modules/iot-core/outputs.tf | 20 --- modules/iot-core/variables.tf | 67 -------- modules/naming-convention/README.md | 89 ----------- modules/naming-convention/main.tf | 46 ------ modules/naming-convention/outputs.tf | 25 --- modules/naming-convention/variables.tf | 60 -------- modules/naming-convention/versions.tf | 29 ---- tests/modules/naming_convention/__init__.py | 13 -- .../modules/naming_convention/fixture/main.tf | 65 -------- tests/modules/naming_convention/test_plan.py | 47 ------ 23 files changed, 2 insertions(+), 1132 deletions(-) delete mode 100644 modules/folders-unit/README.md delete mode 100644 modules/folders-unit/locals.tf delete mode 100644 modules/folders-unit/main.tf delete mode 100644 modules/folders-unit/outputs.tf delete mode 100644 modules/folders-unit/variables.tf delete mode 100644 modules/folders-unit/versions.tf delete mode 100644 modules/iot-core/README.md delete mode 100644 modules/iot-core/diagram.png delete mode 100644 modules/iot-core/diagram_iot.png delete mode 100644 modules/iot-core/main.tf delete mode 100644 modules/iot-core/outputs.tf delete mode 100644 modules/iot-core/variables.tf delete mode 100644 modules/naming-convention/README.md delete mode 100644 modules/naming-convention/main.tf delete mode 100644 modules/naming-convention/outputs.tf delete mode 100644 modules/naming-convention/variables.tf delete mode 100644 modules/naming-convention/versions.tf delete mode 100644 tests/modules/naming_convention/__init__.py delete mode 100644 tests/modules/naming_convention/fixture/main.tf delete mode 100644 tests/modules/naming_convention/test_plan.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 244af3025..dcb1d9317 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -183,7 +183,7 @@ All notable changes to this project will be documented in this file. - **incompatible change** removed `iam` key from logging sink configuration in the `project` and `organization` modules - remove GCS to BQ with Dataflow example, replace by GCS to BQ with least privileges - the `net-vpc` and `project` modules now use the beta provider for shared VPC-related resources -- new [iot-core](modules/iot-core) module +- new iot-core module - **incompatible change** the variables for host and service Shared VPCs have changed in the project module - **incompatible change** the variable for service identities IAM has changed in the project factory - add `data-catalog-policy-tag` module diff --git a/README.md b/README.md index b4711da73..bdb17b658 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ The current list of modules supports most of the core foundational and networkin Currently available modules: -- **foundational** - [folder](./modules/folder), [organization](./modules/organization), [project](./modules/project), [service accounts](./modules/iam-service-account), [logging bucket](./modules/logging-bucket), [billing budget](./modules/billing-budget), [naming convention](./modules/naming-convention), [projects-data-source](./modules/projects-data-source), [organization-policy](./modules/organization-policy) +- **foundational** - [folder](./modules/folder), [organization](./modules/organization), [project](./modules/project), [service accounts](./modules/iam-service-account), [logging bucket](./modules/logging-bucket), [billing budget](./modules/billing-budget), [projects-data-source](./modules/projects-data-source), [organization-policy](./modules/organization-policy) - **networking** - [VPC](./modules/net-vpc), [VPC firewall](./modules/net-vpc-firewall), [VPC peering](./modules/net-vpc-peering), [VPN static](./modules/net-vpn-static), [VPN dynamic](./modules/net-vpn-dynamic), [HA VPN](./modules/net-vpn-ha), [NAT](./modules/net-cloudnat), [address reservation](./modules/net-address), [DNS](./modules/dns), [L4 ILB](./modules/net-ilb), [L7 ILB](./modules/net-ilb-l7), [Service Directory](./modules/service-directory), [Cloud Endpoints](./modules/endpoints) - **compute** - [VM/VM group](./modules/compute-vm), [MIG](./modules/compute-mig), [GKE cluster](./modules/gke-cluster), [GKE nodepool](./modules/gke-nodepool), [GKE hub](./modules/gke-hub), [COS container](./modules/cloud-config-container/cos-generic-metadata/) (coredns, mysql, onprem, squid) - **data** - [GCS](./modules/gcs), [BigQuery dataset](./modules/bigquery-dataset), [Pub/Sub](./modules/pubsub), [Datafusion](./modules/datafusion), [Bigtable instance](./modules/bigtable-instance), [Cloud SQL instance](./modules/cloudsql-instance), [Data Catalog Policy Tag](./modules/data-catalog-policy-tag) diff --git a/modules/README.md b/modules/README.md index 3280a6828..281b2fda8 100644 --- a/modules/README.md +++ b/modules/README.md @@ -32,7 +32,6 @@ These modules are used in the examples included in this repository. If you are u - [billing budget](./billing-budget) - [folder](./folder) - [logging bucket](./logging-bucket) -- [naming convention](./naming-convention) - [organization](./organization) - [project](./project) - [projects-data-source](./projects-data-source) diff --git a/modules/folders-unit/README.md b/modules/folders-unit/README.md deleted file mode 100644 index e84a962b8..000000000 --- a/modules/folders-unit/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# Google Cloud Unit Folders Module - -This module allows creation and management of an organizational hierarchy "unit" composed of a parent folder (usually mapped to a business unit or team), and a set of child folders (usually mapped to environments) each with a corresponding set of service accounts, IAM bindings and GCS buckets. - -## Example - -```hcl -module "folders-unit" { - source = "./fabric/modules/folders-unit" - name = "Business Intelligence" - short_name = "bi" - automation_project_id = "automation-project-394yr923811" - billing_account_id = "015617-16GHBC-AF02D9" - organization_id = "506128240800" - root_node = "folders/93469270123701" - prefix = "unique-prefix" - environments = { - dev = "Development", - test = "Testing", - prod = "Production" - } - service_account_keys = true -} -# tftest modules=1 resources=37 -``` - - -## Variables - -| name | description | type | required | default | -|---|---|:---:|:---:|:---:| -| [automation_project_id](variables.tf#L17) | Project id used for automation service accounts. | string | ✓ | | -| [billing_account_id](variables.tf#L22) | Country billing account account. | string | ✓ | | -| [name](variables.tf#L86) | Top folder name. | string | ✓ | | -| [organization_id](variables.tf#L91) | Organization id in organizations/nnnnnn format. | string | ✓ | | -| [root_node](variables.tf#L102) | Root node in folders/folder_id or organizations/org_id format. | string | ✓ | | -| [short_name](variables.tf#L113) | Short name used as GCS bucket and service account prefixes, do not use capital letters or spaces. | string | ✓ | | -| [environments](variables.tf#L27) | Unit environments short names. | map(string) | | {…} | -| [gcs_defaults](variables.tf#L36) | Defaults use for the state GCS buckets. | map(string) | | {…} | -| [iam](variables.tf#L45) | IAM bindings for the top-level folder in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | -| [iam_billing_config](variables.tf#L51) | Grant billing user role to service accounts, defaults to granting on the billing account. | object({…}) | | {…} | -| [iam_enviroment_roles](variables.tf#L63) | IAM roles granted to the environment service account on the environment sub-folder. | list(string) | | […] | -| [iam_xpn_config](variables.tf#L74) | Grant Shared VPC creation roles to service accounts, defaults to granting at folder level. | object({…}) | | {…} | -| [prefix](variables.tf#L96) | Optional prefix used for GCS bucket names to ensure uniqueness. | string | | null | -| [service_account_keys](variables.tf#L107) | Generate and store service account keys in the state file. | bool | | false | - -## Outputs - -| name | description | sensitive | -|---|---|:---:| -| [env_folders](outputs.tf#L17) | Unit environments folders. | | -| [env_gcs_buckets](outputs.tf#L28) | Unit environments tfstate gcs buckets. | | -| [env_sa_keys](outputs.tf#L36) | Unit environments service account keys. | ✓ | -| [env_service_accounts](outputs.tf#L45) | Unit environments service accounts. | | -| [unit_folder](outputs.tf#L53) | Unit top level folder. | | - - diff --git a/modules/folders-unit/locals.tf b/modules/folders-unit/locals.tf deleted file mode 100644 index bd5135092..000000000 --- a/modules/folders-unit/locals.tf +++ /dev/null @@ -1,58 +0,0 @@ -/** - * 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 { - folder_roles = concat(var.iam_enviroment_roles, local.sa_xpn_folder_roles) - iam = var.iam == null ? {} : var.iam - folder_iam_service_account_bindings = { - for pair in setproduct(keys(var.environments), local.folder_roles) : - "${pair.0}-${pair.1}" => { environment = pair.0, role = pair.1 } - } - org_iam_service_account_bindings = { - for pair in setproduct(keys(var.environments), concat( - local.sa_xpn_org_roles, - local.sa_billing_org_roles, - local.sa_billing_org_roles)) : - "${pair.0}-${pair.1}" => { environment = pair.0, role = pair.1 } - } - billing_iam_service_account_bindings = { - for pair in setproduct(keys(var.environments), local.sa_billing_account_roles) : - "${pair.0}-${pair.1}" => { environment = pair.0, role = pair.1 } - } - service_accounts = { - for key, sa in google_service_account.environment : - key => "serviceAccount:${sa.email}" - } - sa_billing_account_roles = ( - var.iam_billing_config.target_org ? [] : ["roles/billing.user"] - ) - sa_billing_org_roles = ( - !var.iam_billing_config.target_org ? [] : ["roles/billing.user"] - ) - sa_xpn_folder_roles = ( - local.sa_xpn_target_org ? [] : ["roles/compute.xpnAdmin"] - ) - sa_xpn_org_roles = ( - local.sa_xpn_target_org - ? ["roles/compute.xpnAdmin", "roles/resourcemanager.organizationViewer"] - : ["roles/resourcemanager.organizationViewer"] - ) - sa_xpn_target_org = ( - var.iam_xpn_config.target_org - || - substr(var.root_node, 0, 13) == "organizations" - ) -} diff --git a/modules/folders-unit/main.tf b/modules/folders-unit/main.tf deleted file mode 100644 index f609fffc1..000000000 --- a/modules/folders-unit/main.tf +++ /dev/null @@ -1,109 +0,0 @@ -/** - * 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 { - organization_id = element(split("/", var.organization_id), 1) -} - -############################################################################### -# Folders and folder IAM # -############################################################################### - -resource "google_folder" "unit" { - display_name = var.name - parent = var.root_node -} - -resource "google_folder" "environment" { - for_each = var.environments - display_name = each.value - parent = google_folder.unit.name -} - -resource "google_folder_iam_binding" "unit" { - for_each = var.iam - folder = google_folder.unit.name - role = each.key - members = each.value -} - -resource "google_folder_iam_binding" "environment" { - for_each = local.folder_iam_service_account_bindings - folder = google_folder.environment[each.value.environment].name - role = each.value.role - members = [local.service_accounts[each.value.environment]] -} - -############################################################################### -# Billing account and org IAM # -############################################################################### - -resource "google_organization_iam_member" "org_iam_member" { - for_each = local.org_iam_service_account_bindings - org_id = local.organization_id - role = each.value.role - member = local.service_accounts[each.value.environment] -} - -resource "google_billing_account_iam_member" "billing_iam_member" { - for_each = var.iam_billing_config.grant ? local.billing_iam_service_account_bindings : {} - billing_account_id = var.billing_account_id - role = each.value.role - member = local.service_accounts[each.value.environment] -} - -################################################################################ -# Service Accounts # -################################################################################ - -resource "google_service_account" "environment" { - for_each = var.environments - project = var.automation_project_id - account_id = "${var.short_name}-${each.key}" - display_name = "${var.short_name} ${each.key} (Terraform managed)." -} - -resource "google_service_account_key" "keys" { - for_each = var.service_account_keys ? var.environments : {} - service_account_id = google_service_account.environment[each.key].email -} - -################################################################################ -# GCS and GCS IAM # -################################################################################ - -resource "google_storage_bucket" "tfstate" { - for_each = var.environments - project = var.automation_project_id - name = join("", [ - var.prefix == null ? "" : "${var.prefix}-", - "${var.short_name}-${each.key}-tf" - ]) - location = var.gcs_defaults.location - storage_class = var.gcs_defaults.storage_class - force_destroy = false - uniform_bucket_level_access = true - versioning { - enabled = true - } -} - -resource "google_storage_bucket_iam_binding" "bindings" { - for_each = var.environments - bucket = google_storage_bucket.tfstate[each.key].name - role = "roles/storage.objectAdmin" - members = [local.service_accounts[each.key]] -} diff --git a/modules/folders-unit/outputs.tf b/modules/folders-unit/outputs.tf deleted file mode 100644 index 8e4d1066f..000000000 --- a/modules/folders-unit/outputs.tf +++ /dev/null @@ -1,59 +0,0 @@ -/** - * 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 "env_folders" { - description = "Unit environments folders." - value = { - for key, folder in google_folder.environment - : key => { - id = folder.name, - name = folder.display_name - } - } -} - -output "env_gcs_buckets" { - description = "Unit environments tfstate gcs buckets." - value = { - for key, bucket in google_storage_bucket.tfstate - : key => bucket.name - } -} - -output "env_sa_keys" { - description = "Unit environments service account keys." - sensitive = true - value = { - for key, sa_key in google_service_account_key.keys : - key => sa_key.private_key - } -} - -output "env_service_accounts" { - description = "Unit environments service accounts." - value = { - for key, sa in google_service_account.environment - : key => sa.email - } -} - -output "unit_folder" { - description = "Unit top level folder." - value = { - id = google_folder.unit.name, - name = google_folder.unit.display_name - } -} diff --git a/modules/folders-unit/variables.tf b/modules/folders-unit/variables.tf deleted file mode 100644 index 10a167d47..000000000 --- a/modules/folders-unit/variables.tf +++ /dev/null @@ -1,116 +0,0 @@ -/** - * 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 "automation_project_id" { - description = "Project id used for automation service accounts." - type = string -} - -variable "billing_account_id" { - description = "Country billing account account." - type = string -} - -variable "environments" { - description = "Unit environments short names." - type = map(string) - default = { - non-prod = "Non production" - prod = "Production" - } -} - -variable "gcs_defaults" { - description = "Defaults use for the state GCS buckets." - type = map(string) - default = { - location = "EU" - storage_class = "MULTI_REGIONAL" - } -} - -variable "iam" { - description = "IAM bindings for the top-level folder in {ROLE => [MEMBERS]} format." - type = map(list(string)) - default = {} -} - -variable "iam_billing_config" { - description = "Grant billing user role to service accounts, defaults to granting on the billing account." - type = object({ - grant = bool - target_org = bool - }) - default = { - grant = true - target_org = false - } -} - -variable "iam_enviroment_roles" { - description = "IAM roles granted to the environment service account on the environment sub-folder." - type = list(string) - default = [ - "roles/compute.networkAdmin", - "roles/owner", - "roles/resourcemanager.folderAdmin", - "roles/resourcemanager.projectCreator", - ] -} - -variable "iam_xpn_config" { - description = "Grant Shared VPC creation roles to service accounts, defaults to granting at folder level." - type = object({ - grant = bool - target_org = bool - }) - default = { - grant = true - target_org = false - } -} - -variable "name" { - description = "Top folder name." - type = string -} - -variable "organization_id" { - description = "Organization id in organizations/nnnnnn format." - type = string -} - -variable "prefix" { - description = "Optional prefix used for GCS bucket names to ensure uniqueness." - type = string - default = null -} - -variable "root_node" { - description = "Root node in folders/folder_id or organizations/org_id format." - type = string -} - -variable "service_account_keys" { - description = "Generate and store service account keys in the state file." - type = bool - default = false -} - -variable "short_name" { - description = "Short name used as GCS bucket and service account prefixes, do not use capital letters or spaces." - type = string -} diff --git a/modules/folders-unit/versions.tf b/modules/folders-unit/versions.tf deleted file mode 100644 index 4278054b1..000000000 --- a/modules/folders-unit/versions.tf +++ /dev/null @@ -1,29 +0,0 @@ -# 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 -# -# 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.1.0" - required_providers { - google = { - source = "hashicorp/google" - version = ">= 4.32.0" # tftest - } - google-beta = { - source = "hashicorp/google-beta" - version = ">= 4.32.0" # tftest - } - } -} - - diff --git a/modules/iot-core/README.md b/modules/iot-core/README.md deleted file mode 100644 index 18579d506..000000000 --- a/modules/iot-core/README.md +++ /dev/null @@ -1,145 +0,0 @@ -# Google Cloud IoT Core Module - -This module sets up Cloud IoT Core Registry, registers IoT Devices and configures Pub/Sub topics required in Cloud IoT Core. - -To use this module, ensure the following APIs are enabled: -* pubsub.googleapis.com -* cloudiot.googleapis.com - -## Simple Example - -Basic example showing how to create an IoT Platform (IoT Core), connected to a set of given Pub/Sub topics and provision IoT devices. - -Devices certificates must exist before calling this module. You can generate these certificates using the following command - -``` -openssl req -x509 -newkey rsa:2048 -keyout rsa_private.pem -nodes -out rsa_cert.pem -subj "/CN=unused" -``` - -And then provision public certificate path, together with the rest of device configuration in a devices yaml file following the following format -```yaml -device_id: # id of your IoT Device - is_blocked: # false to allow device connection with IoT Registry - is_gateway: # true to indicate the device connecting acts as a gateway for other IoT Devices - log_level: # device logs level - certificate_file: # public certificate path, generated as explained in the previous step - certificate_format: # Certificates format values are RSA_PEM, RSA_X509_PEM, ES256_PEM, and ES256_X509_PEM -``` - -Example Device config yaml configuration -```yaml -device_1: - is_blocked: false - is_gateway: false - log_level: INFO - certificate_file: device_certs/rsa_cert5.pem - certificate_format: RSA_X509_PEM -device_2: - is_blocked: true - is_gateway: false - log_level: INFO - certificate_file: device_certs/rsa_cert5.pem - certificate_format: RSA_X509_PEM -``` - -```hcl -module "iot-platform" { - source = "./fabric/modules/iot-core" - project_id = "my_project_id" - region = "europe-west1" - telemetry_pubsub_topic_id = "telemetry_topic_id" - status_pubsub_topic_id = "status_topic_id" - protocols = { - http = false, - mqtt = true - } - devices_config_directory = "./devices_config_folder" -} -# tftest:skip - -``` - -Now, we can test sending telemetry messages from devices to our IoT Platform, for example using the MQTT demo client at https://github.com/googleapis/nodejs-iot/tree/main/samples/mqtt_example - -## Example with specific PubSub topics for custom MQTT topics - -If you need to match specific MQTT topics (eg, /temperature) into specific PubSub topics, you can use extra_telemetry_pubsub_topic_ids for that, as in the following example: - -```hcl -module "iot-platform" { - source = "./fabric/modules/iot-core" - project_id = "my_project_id" - region = "europe-west1" - telemetry_pubsub_topic_id = "telemetry_topic_id" - status_pubsub_topic_id = "status_topic_id" - extra_telemetry_pubsub_topic_ids = { - "temperature" = "temp_topic_id", - "humidity" = "hum_topic_id" - } - protocols = { - http = false, - mqtt = true - } - devices_config_directory = "./devices_config_folder" -} -# tftest:skip - -``` - -## Example integrated with Data Foundation Platform -In this example, we will show how to extend the **[Data Foundations Platform](../../blueprints/data-solutions/data-platform-foundations/)** to include IoT Platform as a new source of data. - -![Target architecture](./diagram_iot.png) - -1. First, we will setup Environment following instructions in **[Environment Setup](../../blueprints/data-solutions/data-platform-foundations/)** to setup projects and SAs required. Get output variable project_ids.landing as will be used later - -1. Second, execute instructions in **[Environment Setup](../../blueprints/data-solutions/data-platform-foundations/)** to provision PubSub, DataFlow, BQ,... Get variable landing-pubsub as will be used later to create IoT Registry - -1. Now it is time to provision IoT Platform. Modify landing-project-id and landing_pubsub_topic_id with output variables obtained before. Create device certificates as shown in the Simple Example and register them in devices.yaml file together with deviceids. - -```hcl -module "iot-platform" { - source = "./fabric/modules/iot-core" - project_id = "landing-project-id" - region = "europe-west1" - telemetry_pubsub_topic_id = "landing_pubsub_topic_id" - status_pubsub_topic_id = "status_pubsub_topic_id" - protocols = { - http = false, - mqtt = true - } - devices_config_directory = "./devices_config_folder" -} -# tftest:skip -``` -1. After that, we can setup the pipeline "PubSub to BigQuery" shown at **[Pipeline Setup](../../blueprints/data-solutions/data-platform-foundations/)** - -1. Finally, instead of testing the pipeline by sending messages to PubSub, we can now test sending telemetry messages from simulated IoT devices to our IoT Platform, for example using the MQTT demo client at https://github.com/googleapis/nodejs-iot/tree/main/samples/mqtt_example . We shall edit the client script cloudiot_mqtt_example_nodejs.js to send messages following the pipeline message format, so they are processed by DataFlow job and inserted in the BigQuery table. -``` -const payload = '{"name": "device4", "surname": "NA", "timestamp":"'+Math.floor(Date.now()/1000)+'"}'; -``` - -Or even better, create a new BigQuery table with our IoT sensors data columns and modify the DataFlow job to push data to it. - - -## Variables - -| name | description | type | required | default | -|---|---|:---:|:---:|:---:| -| [devices_config_directory](variables.tf#L17) | Path to folder where devices configs are stored in yaml format. Folder may include subfolders with configuration files. Files suffix must be `.yaml`. | string | ✓ | | -| [project_id](variables.tf#L34) | Project were resources will be deployed | string | ✓ | | -| [region](variables.tf#L48) | Region were resources will be deployed | string | ✓ | | -| [status_pubsub_topic_id](variables.tf#L59) | pub sub topic for status messages (GCP-->Device) | string | ✓ | | -| [telemetry_pubsub_topic_id](variables.tf#L64) | pub sub topic for telemetry messages (Device-->GCP) | string | ✓ | | -| [extra_telemetry_pubsub_topic_ids](variables.tf#L22) | additional pubsub topics linked to adhoc MQTT topics (Device-->GCP) in the format MQTT_TOPIC: PUBSUB_TOPIC_ID | map(string) | | {} | -| [log_level](variables.tf#L28) | IoT Registry Log level | string | | "INFO" | -| [protocols](variables.tf#L39) | IoT protocols (HTTP / MQTT) activation | object({…}) | | { http = true, mqtt = true } | -| [registry_name](variables.tf#L53) | Name for the IoT Core Registry | string | | "cloudiot-registry" | - -## Outputs - -| name | description | sensitive | -|---|---|:---:| -| [iot_registry](outputs.tf#L17) | Cloud IoT Core Registry | | - - diff --git a/modules/iot-core/diagram.png b/modules/iot-core/diagram.png deleted file mode 100644 index 7a3393212d03a5331d898729b29fc87ec7d8d24a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 481113 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