add analytics hub module (#2087)

This commit is contained in:
Thinh Ha 2024-02-19 15:55:00 +00:00 committed by GitHub
parent a45741d5d0
commit 82f11e7ca5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 691 additions and 0 deletions

View File

@ -0,0 +1,216 @@
# BigQuery Analytics Hub
This module allows managing [Analytics Hub](https://cloud.google.com/bigquery/docs/analytics-hub-introduction) Exchange and Listing resources.
## Examples
### Exchange
Exchange argument references can be found in: https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/bigquery_analytics_hub_data_exchange
```hcl
module "analytics-hub" {
source = "./fabric/modules/analytics-hub"
project_id = "project-id"
region = "us-central1"
prefix = "test"
name = "exchange"
primary_contact = "exchange-owner-group@domain.com"
documentation = "documentation"
}
# tftest modules=1 resources=1
```
### Listings
Listing definitions can be provided in the form {LISTING_ID => LISTING_CONFIGS}. Listing argument references can be found in: https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/bigquery_analytics_hub_listing
```hcl
module "analytics-hub" {
source = "./fabric/modules/analytics-hub"
project_id = "project-id"
region = "us-central1"
name = "exchange"
listings = {
"listing_id" = {
bigquery_dataset = "projects/{project}/datasets/{dataset}"
},
"listing_id_2" = {
bigquery_dataset = "projects/{project}/datasets/{dataset}"
description = "(Optional) Short description of the listing."
documentation = "(Optional) Documentation describing the listing."
categories = []
primary_contact = "(Optional) Email or URL of the primary point of contact of the listing."
icon = "(Optional) Base64 encoded image representing the listing."
request_access = "(Optional) Email or URL of the request access of the listing. Subscribers can use this reference to request access."
data_provider = {
name = "(Required) Name of the data provider."
primary_contact = "(Optional) Email or URL of the data provider."
}
publisher = {
name = "(Required) Name of the listing publisher."
primary_contact = "(Optional) Email or URL of the listing publisher."
}
restricted_export_config = {
enabled = true
restrict_query_result = true
}
}
}
}
# tftest modules=1 resources=3
```
### IAM
This module supports setting IAM permissions on both the exchange and listing resources. IAM permissions on the exchange is inherited on the listings.
See [this page](https://cloud.google.com/bigquery/docs/analytics-hub-grant-roles) to see IAM roles that can be granted on exchange and listings.
#### Exchange
Input to variables `iam`, `iam_bindings`, and `iam_by_principals` will be merged, and are [authoritative for the given role](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/bigquery_analytics_hub_data_exchange_iam#google_bigquery_analytics_hub_data_exchange_iam_binding). Inputs to variable `iam_bindings_additive` are [additive](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/bigquery_analytics_hub_data_exchange_iam#google_bigquery_analytics_hub_data_exchange_iam_member).
In practice, you should only need to use either `iam` or `iam_bindings`.
```hcl
module "analytics-hub" {
source = "./fabric/modules/analytics-hub"
project_id = "project-id"
region = "us-central1"
name = "exchange"
iam = {
"roles/analyticshub.viewer" = [
"group:viewer@domain.com"
],
}
iam_bindings = {
"viewers" = {
role = "roles/analyticshub.viewer"
members = ["user:user@domain.com"]
}
}
iam_by_principals = {
"user:user@domain.com" = [
"roles/analyticshub.viewer"
]
}
iam_bindings_additive = {
"subscribers" = {
role = "roles/analyticshub.subscriber"
member = "user:user@domain.com"
}
}
}
# tftest modules=1 resources=3 inventory=iam_exchange.yaml
```
#### Listings
The listings variable block support the `iam` input which are [authoritative for the given role](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/bigquery_analytics_hub_listing_iam#google_bigquery_analytics_hub_listing_iam_binding).
```hcl
module "analytics-hub" {
source = "./fabric/modules/analytics-hub"
project_id = "project-id"
region = "us-central1"
name = "exchange"
iam = {
"roles/analyticshub.viewer" = [
"group:viewer@domain.com"
],
}
listings = {
"listing_id" = {
bigquery_dataset = "projects/{project}/datasets/{dataset}"
iam = {
"roles/analyticshub.subscriber" = [
"group:subscriber@domain.com"
],
"roles/analyticshub.subscriptionOwner" = [
"group:subscription-owner@domain.com"
],
}
}
}
}
# tftest modules=1 resources=5 inventory=iam_listing.yaml
```
### Factory
Similarly to other modules, a rules factory (see [Resource Factories](../../blueprints/factories/)) is also included here to allow managing listings inside the same exchange via descriptive configuration files.
Factory configuration is via one optional attributes in the `factory_config_path` variable specifying the path where tags files are stored.
Factory tags are merged with rules declared in code, with the latter taking precedence where both use the same key.
This is an example of a simple factory:
```hcl
module "analytics-hub" {
source = "./fabric/modules/analytics-hub"
project_id = "project-id"
region = "us-central1"
name = "exchange"
listings = {
"listing_id" = {
bigquery_dataset = "projects/{project}/datasets/{dataset}"
},
}
factories_config = {
listings = "listings"
}
}
# tftest modules=1 resources=5 files=yaml
```
```yaml
# tftest-file id=yaml path=listings/listing_1.yaml
bigquery_dataset: projects/{project}/datasets/{dataset}
description: "(Optional) Short description of the listing."
documentation: "(Optional) Documentation describing the listing."
categories: []
icon: "(Optional) Base64 encoded image representing the listing."
primary_contact: "(Optional) Email or URL of the primary point of contact of the listing."
request_access: "(Optional) Email or URL of the request access of the listing. Subscribers can use this reference to request access."
data_provider:
name: "(Required) Name of the data provider."
primary_contact: "(Optional) Email or URL of the data provider."
iam:
roles/analyticshub.subscriber:
- group:subscriber@domain.com
roles/analyticshub.subscriptionOwner:
- group:subscription-owner@domain.com
publisher:
name: "(Required) Name of the listing publisher."
primary_contact: "(Optional) Email or URL of the listing publisher."
restricted_export_config:
enabled: true
restrict_query_result: true
```
<!-- BEGIN TFDOC -->
## Variables
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
| [name](variables.tf#L71) | The ID of the data exchange. Must contain only Unicode letters, numbers (0-9), underscores (_). Should not use characters that require URL-escaping or characters outside of ASCII spaces. | <code>string</code> | ✓ | |
| [project_id](variables.tf#L88) | The ID of the project where the data exchange will be created. | <code>string</code> | ✓ | |
| [region](variables.tf#L93) | Region for the data exchange. | <code>string</code> | ✓ | |
| [description](variables.tf#L17) | Resource description for data exchange. | <code>string</code> | | <code>null</code> |
| [documentation](variables.tf#L23) | Documentation describing the data exchange. | <code>string</code> | | <code>null</code> |
| [factories_config](variables.tf#L29) | Paths to data files and folders that enable factory functionality. | <code title="object&#40;&#123;&#10; listings &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam](variables-iam.tf#L17) | Authoritative IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_bindings](variables-iam.tf#L24) | Authoritative IAM bindings in {KEY => {role = ROLE, members = []}}. Keys are arbitrary. | <code title="map&#40;object&#40;&#123;&#10; members &#61; list&#40;string&#41;&#10; role &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_bindings_additive](variables-iam.tf#L34) | Individual additive IAM bindings. Keys are arbitrary. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_by_principals](variables-iam.tf#L44) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [icon](variables.tf#L38) | Base64 encoded image representing the data exchange. | <code>string</code> | | <code>null</code> |
| [listings](variables.tf#L44) | Listings definitions in the form {LISTING_ID => LISTING_CONFIGS}. LISTING_ID must contain only Unicode letters, numbers (0-9), underscores (_). Should not use characters that require URL-escaping or characters outside of ASCII spaces. | <code title="map&#40;object&#40;&#123;&#10; bigquery_dataset &#61; string&#10; description &#61; optional&#40;string&#41;&#10; documentation &#61; optional&#40;string&#41;&#10; categories &#61; optional&#40;list&#40;string&#41;&#41;&#10; icon &#61; optional&#40;string&#41;&#10; primary_contact &#61; optional&#40;string&#41;&#10; request_access &#61; optional&#40;string&#41;&#10; data_provider &#61; optional&#40;object&#40;&#123;&#10; name &#61; string&#10; primary_contact &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;&#41;&#10; publisher &#61; optional&#40;object&#40;&#123;&#10; name &#61; string&#10; primary_contact &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; restricted_export_config &#61; optional&#40;object&#40;&#123;&#10; enabled &#61; optional&#40;bool&#41;&#10; restrict_query_result &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [prefix](variables.tf#L76) | Optional prefix for data exchange ID. | <code>string</code> | | <code>null</code> |
| [primary_contact](variables.tf#L82) | Email or URL of the primary point of contact of the data exchange. | <code>string</code> | | <code>null</code> |
## Outputs
| name | description | sensitive |
|---|---|:---:|
| [data_exchange_id](outputs.tf#L17) | Data exchange id. | |
| [data_listings](outputs.tf#L27) | Data listings and corresponding configs. | |
<!-- END TFDOC -->

View File

@ -0,0 +1,78 @@
/**
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
locals {
_exchange_iam_principal_roles = distinct(flatten(values(var.iam_by_principals)))
_exchange_iam_principals = {
for r in local._exchange_iam_principal_roles : r => [
for k, v in var.iam_by_principals :
k if try(index(v, r), null) != null
]
}
_exchange_iam_bindings = {
for key, iam_bindings in var.iam_bindings :
iam_bindings.role => iam_bindings.members
}
exchange_iam = {
for role in distinct(concat(keys(var.iam), keys(local._exchange_iam_principals), keys(local._exchange_iam_bindings))) :
role => concat(
try(var.iam[role], []),
try(local._exchange_iam_principals[role], []),
try(local._exchange_iam_bindings[role], []),
)
}
listing_iam = flatten([
for listing_id, listing_configs in local.factory_listings : [
for role, members in coalesce(listing_configs.iam, tomap({})) : {
listing_id = listing_id
role = role
members = members
}
]
])
}
resource "google_bigquery_analytics_hub_data_exchange_iam_binding" "exchange_iam_bindings" {
for_each = local.exchange_iam
project = google_bigquery_analytics_hub_data_exchange.data_exchange.project
location = google_bigquery_analytics_hub_data_exchange.data_exchange.location
data_exchange_id = google_bigquery_analytics_hub_data_exchange.data_exchange.data_exchange_id
role = each.key
members = each.value
}
resource "google_bigquery_analytics_hub_data_exchange_iam_member" "exchange_iam_members" {
for_each = var.iam_bindings_additive
project = google_bigquery_analytics_hub_data_exchange.data_exchange.project
location = google_bigquery_analytics_hub_data_exchange.data_exchange.location
data_exchange_id = google_bigquery_analytics_hub_data_exchange.data_exchange.data_exchange_id
role = each.value.role
member = each.value.member
}
resource "google_bigquery_analytics_hub_listing_iam_binding" "listing_iam_bindings" {
for_each = {
for index, listing_iam in local.listing_iam :
"${listing_iam.listing_id}-${listing_iam.role}" => listing_iam
}
project = google_bigquery_analytics_hub_data_exchange.data_exchange.project
location = google_bigquery_analytics_hub_data_exchange.data_exchange.location
data_exchange_id = google_bigquery_analytics_hub_data_exchange.data_exchange.data_exchange_id
listing_id = google_bigquery_analytics_hub_listing.listing[each.value.listing_id].id
role = each.value.role
members = each.value.members
}

View File

@ -0,0 +1,64 @@
/**
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
locals {
prefix = var.prefix == null || var.prefix == "" ? "" : "${var.prefix}_"
_factory_listings = {
for f in try(fileset(var.factories_config.listings, "*.yaml"), []) :
trimsuffix(f, ".yaml") => yamldecode(file("${var.factories_config.listings}/${f}"))
}
factory_listings = merge(local._factory_listings, var.listings)
}
resource "google_bigquery_analytics_hub_data_exchange" "data_exchange" {
project = var.project_id
location = var.region
data_exchange_id = "${local.prefix}${var.name}"
display_name = "${local.prefix}${var.name}"
description = var.description
primary_contact = var.primary_contact
documentation = var.documentation
icon = var.icon
}
resource "google_bigquery_analytics_hub_listing" "listing" {
for_each = local.factory_listings
project = var.project_id
location = var.region
data_exchange_id = google_bigquery_analytics_hub_data_exchange.data_exchange.data_exchange_id
listing_id = each.key
display_name = each.key
description = try(each.value.description, null)
primary_contact = try(each.value.primary_contact, null)
documentation = try(each.value.documentation, null)
icon = try(each.value.icon, null)
request_access = try(each.value.request_access, null)
categories = try(each.value.categories, null)
bigquery_dataset {
dataset = each.value.bigquery_dataset
}
dynamic "restricted_export_config" {
for_each = each.value.restricted_export_config != null ? [""] : []
content {
enabled = try(each.value.restricted_export_config.enabled, null)
restrict_query_result = try(each.value.restricted_export_config.restrict_query_result, null)
}
}
}

View File

@ -0,0 +1,34 @@
/**
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
output "data_exchange_id" {
description = "Data exchange id."
value = google_bigquery_analytics_hub_data_exchange.data_exchange.data_exchange_id
depends_on = [
google_bigquery_analytics_hub_data_exchange.data_exchange,
google_bigquery_analytics_hub_data_exchange_iam_binding.exchange_iam_bindings,
google_bigquery_analytics_hub_data_exchange_iam_member.exchange_iam_members
]
}
output "data_listings" {
description = "Data listings and corresponding configs."
value = { for k, v in google_bigquery_analytics_hub_listing.listing : k => v.bigquery_dataset }
depends_on = [
google_bigquery_analytics_hub_listing.listing,
google_bigquery_analytics_hub_listing_iam_binding.listing_iam_bindings
]
}

View File

@ -0,0 +1,49 @@
/**
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
variable "iam" {
description = "Authoritative IAM bindings in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
nullable = false
}
variable "iam_bindings" {
description = "Authoritative IAM bindings in {KEY => {role = ROLE, members = []}}. Keys are arbitrary."
type = map(object({
members = list(string)
role = string
}))
nullable = false
default = {}
}
variable "iam_bindings_additive" {
description = "Individual additive IAM bindings. Keys are arbitrary."
type = map(object({
member = string
role = string
}))
nullable = false
default = {}
}
variable "iam_by_principals" {
description = "Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable."
type = map(list(string))
default = {}
nullable = false
}

View File

@ -0,0 +1,96 @@
/**
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
variable "description" {
description = "Resource description for data exchange."
default = null
type = string
}
variable "documentation" {
description = "Documentation describing the data exchange."
default = null
type = string
}
variable "factories_config" {
description = "Paths to data files and folders that enable factory functionality."
type = object({
listings = optional(string)
})
nullable = false
default = {}
}
variable "icon" {
description = "Base64 encoded image representing the data exchange."
default = null
type = string
}
variable "listings" {
description = "Listings definitions in the form {LISTING_ID => LISTING_CONFIGS}. LISTING_ID must contain only Unicode letters, numbers (0-9), underscores (_). Should not use characters that require URL-escaping or characters outside of ASCII spaces."
type = map(object({
bigquery_dataset = string
description = optional(string)
documentation = optional(string)
categories = optional(list(string))
icon = optional(string)
primary_contact = optional(string)
request_access = optional(string)
data_provider = optional(object({
name = string
primary_contact = optional(string)
}))
iam = optional(map(list(string)))
publisher = optional(object({
name = string
primary_contact = optional(string)
}))
restricted_export_config = optional(object({
enabled = optional(bool)
restrict_query_result = optional(bool)
}))
}))
default = {}
}
variable "name" {
description = "The ID of the data exchange. Must contain only Unicode letters, numbers (0-9), underscores (_). Should not use characters that require URL-escaping or characters outside of ASCII spaces."
type = string
}
variable "prefix" {
description = "Optional prefix for data exchange ID."
type = string
default = null
}
variable "primary_contact" {
description = "Email or URL of the primary point of contact of the data exchange."
type = string
default = null
}
variable "project_id" {
description = "The ID of the project where the data exchange will be created."
type = string
}
variable "region" {
description = "Region for the data exchange."
type = string
}

View 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.0"
required_providers {
google = {
source = "hashicorp/google"
version = ">= 5.11.0, < 6.0.0" # tftest
}
google-beta = {
source = "hashicorp/google-beta"
version = ">= 5.11.0, < 6.0.0" # tftest
}
}
}

View File

@ -0,0 +1,50 @@
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
values:
module.analytics-hub.google_bigquery_analytics_hub_data_exchange.data_exchange:
data_exchange_id: exchange
description: null
display_name: exchange
documentation: null
icon: null
location: us-central1
primary_contact: null
project: project-id
timeouts: null
? module.analytics-hub.google_bigquery_analytics_hub_data_exchange_iam_binding.exchange_iam_bindings["roles/analyticshub.viewer"]
: condition: []
data_exchange_id: exchange
location: us-central1
members:
- group:viewer@domain.com
- user:user@domain.com
project: project-id
role: roles/analyticshub.viewer
module.analytics-hub.google_bigquery_analytics_hub_data_exchange_iam_member.exchange_iam_members["subscribers"]:
condition: []
data_exchange_id: exchange
location: us-central1
member: user:user@domain.com
project: project-id
role: roles/analyticshub.subscriber
counts:
google_bigquery_analytics_hub_data_exchange: 1
google_bigquery_analytics_hub_data_exchange_iam_binding: 1
google_bigquery_analytics_hub_data_exchange_iam_member: 1
modules: 1
resources: 3
outputs: {}

View File

@ -0,0 +1,77 @@
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
values:
module.analytics-hub.google_bigquery_analytics_hub_data_exchange.data_exchange:
data_exchange_id: exchange
description: null
display_name: exchange
documentation: null
icon: null
location: us-central1
primary_contact: null
project: project-id
timeouts: null
? module.analytics-hub.google_bigquery_analytics_hub_data_exchange_iam_binding.exchange_iam_bindings["roles/analyticshub.viewer"]
: condition: []
data_exchange_id: exchange
location: us-central1
members:
- group:viewer@domain.com
project: project-id
role: roles/analyticshub.viewer
module.analytics-hub.google_bigquery_analytics_hub_listing.listing["listing_id"]:
bigquery_dataset:
- dataset: projects/{project}/datasets/{dataset}
categories: null
data_exchange_id: exchange
data_provider: []
description: null
display_name: listing_id
documentation: null
icon: null
listing_id: listing_id
location: us-central1
primary_contact: null
project: project-id
publisher: []
request_access: null
restricted_export_config: []
timeouts: null
? module.analytics-hub.google_bigquery_analytics_hub_listing_iam_binding.listing_iam_bindings["listing_id-roles/analyticshub.subscriber"]
: condition: []
data_exchange_id: exchange
location: us-central1
members:
- group:subscriber@domain.com
project: project-id
role: roles/analyticshub.subscriber
? module.analytics-hub.google_bigquery_analytics_hub_listing_iam_binding.listing_iam_bindings["listing_id-roles/analyticshub.subscriptionOwner"]
: condition: []
data_exchange_id: exchange
location: us-central1
members:
- group:subscription-owner@domain.com
project: project-id
role: roles/analyticshub.subscriptionOwner
counts:
google_bigquery_analytics_hub_data_exchange: 1
google_bigquery_analytics_hub_data_exchange_iam_binding: 1
google_bigquery_analytics_hub_listing: 1
google_bigquery_analytics_hub_listing_iam_binding: 2
modules: 1
resources: 5
outputs: {}