Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add analytics hub module #2087

Merged
merged 7 commits into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 166 additions & 0 deletions modules/analytics-hub/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# BigQuery Analytics Hub

This module allows managing [Analytics Hub](https://cloud.google.com/bigquery/docs/analytics-hub-introduction) Exchange and Listing resources.

## Examples

### Exchange

```hcl
module "analytics-hub" {
source = "./fabric/modules/analytics-hub"
project_id = "project-id"
region = "us-central1"
prefix = "test"
name = "exchange"
primary_contact = "[email protected]"
documentation = "documentation"
}
# tftest modules=1 resources=1
```

### Listings

```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}"
restricted_export_config = {
enabled = true
restrict_query_result = true
}
description = "(Optional) Short description of the listing."
primary_contact = "(Optional) Email or URL of the primary point of contact of the listing."
documentation = "(Optional) Documentation describing the listing."
request_access = "(Optional) Email or URL of the request access of the listing. Subscribers can use this reference to request access."
categories = []
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 dlisting publisher."
primary_contact = "(Optional) Email or URL of the listing publisher."
}
}
}
}
# 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) for IAM roles that can be granted on exchange and listings.

IAM bindings created by this module are authoritative for each given role.

```hcl
module "analytics-hub" {
source = "./fabric/modules/analytics-hub"
project_id = "project-id"
region = "us-central1"
name = "exchange"
iam = {
"roles/analyticshub.viewer" = [
"group:[email protected]"
],
}
listings = {
"listing_id" = {
bigquery_dataset = "projects/{project}/datasets/{dataset}"
iam = {
"roles/analyticshub.subscriber" = [
"group:[email protected]"
],
"roles/analyticshub.subscriptionOwner" = [
"group:[email protected]"
],
}
}
}
}
# tftest modules=1 resources=5
```

### 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}
restricted_export_config:
enabled: true
description: "(Optional) Short description of the listing."
primary_contact: "(Optional) Email or URL of the primary point of contact of the listing."
documentation: "(Optional) Documentation describing the listing."
request_access: "(Optional) Email or URL of the request access of the listing. Subscribers can use this reference to request access."
categories: []
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 dlisting publisher."
primary_contact: "(Optional) Email or URL of the listing publisher."
iam:
roles/analyticshub.subscriber:
- group:[email protected]
roles/analyticshub.subscriptionOwner:
- group:[email protected]
```
<!-- BEGIN TFDOC -->
## Variables

| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
| [name](variables.tf#L78) | 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#L95) | The ID of the project where the Analytics Hub Exchange will be created. | <code>string</code> | ✓ | |
| [region](variables.tf#L100) | 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.tf#L38) | Authoritative IAM bindings for the data exchange in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [icon](variables.tf#L45) | Base64 encoded image representing the data exchange. | <code>string</code> | | <code>null</code> |
| [listings](variables.tf#L51) | 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; description &#61; optional&#40;string&#41;&#10; bigquery_dataset &#61; string&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;&#41;&#10; primary_contact &#61; optional&#40;string&#41;&#10; documentation &#61; optional&#40;string&#41;&#10; icon &#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; publisher &#61; optional&#40;object&#40;&#123;&#10; name &#61; string&#10; primary_contact &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; categories &#61; optional&#40;list&#40;string&#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#L83) | Optional prefix for Analytics Hub Exchange ID. | <code>string</code> | | <code>null</code> |
| [primary_contact](variables.tf#L89) | 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#L26) | Data listings and corresponding configs. | |
<!-- END TFDOC -->
50 changes: 50 additions & 0 deletions modules/analytics-hub/iam.tf
Original file line number Diff line number Diff line change
@@ -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.
*/

locals {
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 = var.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_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 = each.value.listing_id
role = each.value.role
members = each.value.members
depends_on = [google_bigquery_analytics_hub_listing.listing]
ludoo marked this conversation as resolved.
Show resolved Hide resolved
}
64 changes: 64 additions & 0 deletions modules/analytics-hub/main.tf
Original file line number Diff line number Diff line change
@@ -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)
}
}

}
33 changes: 33 additions & 0 deletions modules/analytics-hub/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* 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
]
}

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
]
}
Loading
Loading