Skip to content

Commit

Permalink
feat: initial commit of Snowflake Shared Database module
Browse files Browse the repository at this point in the history
  • Loading branch information
dgniewek committed Sep 19, 2024
1 parent dc177e6 commit 5363024
Show file tree
Hide file tree
Showing 24 changed files with 622 additions and 151 deletions.
99 changes: 59 additions & 40 deletions README.md

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions examples/complete/.env.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
SNOWFLAKE_USER=
SNOWFLAKE_ACCOUNT=
SNOWFLAKE_ROLE="ACCOUNTADMIN"

# Login using RSA key
# SNOWFLAKE_PRIVATE_KEY_PATH=
# SNOWFLAKE_AUTHENTICATOR="JWT"

# Login using password
# SNOWFLAKE_PASSWORD=
77 changes: 65 additions & 12 deletions examples/complete/README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,71 @@
# Complete Example

```terraform
module "terraform_module_template" {
source = "../../"
context = module.this.context
example_var = "This is a example value."
sub_resource = {
example_var = "This is a example value of sub resource."
module "snowflake_shared_database" {
source = "../.."
name = "SHARED_DATABASE"
context = module.this.context
from_share = var.from_share
descriptor_name = "snowflake-database"
comment = "Sample shared Database"
replace_invalid_characters = true
default_ddl_collation = "UTF8"
log_level = "INFO"
trace_level = "ON_EVENT"
suspend_task_after_num_failures = 1
task_auto_retry_attempts = 1
user_task_managed_initial_warehouse_size = "X-Small"
user_task_minimum_trigger_interval_in_seconds = 300
user_task_timeout_ms = 200
quoted_identifiers_ignore_case = true
enable_console_output = true
create_default_roles = true
roles = {
readonly = {
comment = "Read-only role"
granted_roles = [resource.snowflake_account_role.this.name]
granted_to_users = [resource.snowflake_user.this.name]
}
}
}
```

## Usage

1. Configure private sharing on producer Snowflake Account (remember that both producer and consumer accounts have to be deployed on the same Cloud Provider for. ex. AWS and in the same region for. ex. `eu-west-1`)

This step can be done manually using Snowsight UI or by running [create_share.sql](./create-share.sql) script on producer Snowflake account.

When using the script, please remember to properly define consumer account details in the last line:

```sql
ALTER SHARE sample_share ADD ACCOUNT="<orgname.accountname>";
```

2. With share configured in step 1., run terraform on consumer account using below commands

```shell
terraform init
terraform plan -var-file fixtures.tfvars -out tfplan
terraform apply tfplan
```

**Please remember to pass share details (from step 1.) to `from_share` variable.**

```shell
$ terraform plan
var.from_share
A fully qualified path to a share from which the database will be created. A fully qualified path follows the format of `<organization_name>.<account_name>.<share_name>`

Enter a value: <orgname.accountname.sharename>
```

<!-- BEGIN_TF_DOCS -->


Expand All @@ -35,6 +82,7 @@ terraform apply tfplan
| <a name="input_descriptor_formats"></a> [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.<br>Map of maps. Keys are names of descriptors. Values are maps of the form<br>`{<br> format = string<br> labels = list(string)<br>}`<br>(Type is `any` so the map values can later be enhanced to provide additional options.)<br>`format` is a Terraform format string to be passed to the `format()` function.<br>`labels` is a list of labels, in order, to pass to `format()` function.<br>Label values will be normalized before being passed to `format()` so they will be<br>identical to how they appear in `id`.<br>Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no |
| <a name="input_enabled"></a> [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no |
| <a name="input_environment"></a> [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no |
| <a name="input_from_share"></a> [from\_share](#input\_from\_share) | A fully qualified path to a share from which the database will be created. A fully qualified path follows the format of `<organization_name>.<account_name>.<share_name>` | `string` | n/a | yes |
| <a name="input_id_length_limit"></a> [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).<br>Set to `0` for unlimited length.<br>Set to `null` for keep the existing setting, which defaults to `0`.<br>Does not affect `id_full`. | `number` | `null` | no |
| <a name="input_label_key_case"></a> [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.<br>Does not affect keys of tags passed in via the `tags` input.<br>Possible values: `lower`, `title`, `upper`.<br>Default value: `title`. | `string` | `null` | no |
| <a name="input_label_order"></a> [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.<br>Defaults to ["namespace", "environment", "stage", "name", "attributes"].<br>You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no |
Expand All @@ -51,7 +99,7 @@ terraform apply tfplan

| Name | Source | Version |
|------|--------|---------|
| <a name="module_terraform_module_template"></a> [terraform\_module\_template](#module\_terraform\_module\_template) | ../../ | n/a |
| <a name="module_snowflake_shared_database"></a> [snowflake\_shared\_database](#module\_snowflake\_shared\_database) | ../.. | n/a |
| <a name="module_this"></a> [this](#module\_this) | cloudposse/label/null | 0.25.0 |

## Outputs
Expand All @@ -62,16 +110,21 @@ terraform apply tfplan

## Providers

No providers.
| Name | Version |
|------|---------|
| <a name="provider_snowflake"></a> [snowflake](#provider\_snowflake) | >= 0.95 |

## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3.0 |
| <a name="requirement_null"></a> [null](#requirement\_null) | 3.1.1 |
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3 |
| <a name="requirement_snowflake"></a> [snowflake](#requirement\_snowflake) | >= 0.95 |

## Resources

No resources.
| Name | Type |
|------|------|
| [snowflake_account_role.this](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/resources/account_role) | resource |
| [snowflake_user.this](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/resources/user) | resource |
<!-- END_TF_DOCS -->
23 changes: 23 additions & 0 deletions examples/complete/create-share.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
CREATE DATABASE sample_shared_db;

CREATE SCHEMA sample_shared_db.shared_schema;

CREATE TABLE sample_shared_db.shared_schema.sample_table (
ID NUMBER,
VALUE TEXT
);

INSERT INTO sample_shared_db.shared_schema.sample_table
VALUES
(1, 'TEST VALUE'),
(2, 'ANOTHER TEST VALUE');

CREATE SHARE sample_share COMMENT = 'Test Share';

GRANT USAGE ON DATABASE sample_shared_db TO SHARE sample_share;

GRANT USAGE ON SCHEMA sample_shared_db.shared_schema TO SHARE sample_share;

GRANT SELECT ON ALL TABLES IN SCHEMA sample_shared_db.shared_schema TO SHARE sample_share;

ALTER SHARE sample_share ADD ACCOUNT="<orgname.accountname>";
17 changes: 12 additions & 5 deletions examples/complete/fixtures.tfvars
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
descriptor_formats = {

}
namespace = "gid"
#stage = "example"
#environment = "dev"

tags = {
Terraform = "True"
descriptor_formats = {
snowflake-role = {
labels = ["attributes", "name"]
format = "%v_%v"
}
snowflake-database = {
labels = ["environment", "stage", "name", "attributes"]
format = "%v_%v_%v_%v"
}
}
43 changes: 37 additions & 6 deletions examples/complete/main.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,40 @@
module "terraform_module_template" {
source = "../../"
context = module.this.context
resource "snowflake_user" "this" {
name = "SAMPLE_USER"
}

resource "snowflake_account_role" "this" {
name = "SAMPLE_ROLE"
}

module "snowflake_shared_database" {
source = "../.."

name = "SHARED_DATABASE"
context = module.this.context
from_share = var.from_share

descriptor_name = "snowflake-database"
comment = "Sample shared Database"
replace_invalid_characters = true
default_ddl_collation = "UTF8"
log_level = "INFO"
trace_level = "ON_EVENT"

suspend_task_after_num_failures = 1
task_auto_retry_attempts = 1
user_task_managed_initial_warehouse_size = "X-Small"
user_task_minimum_trigger_interval_in_seconds = 300
user_task_timeout_ms = 200
quoted_identifiers_ignore_case = true
enable_console_output = true

create_default_roles = true

example_var = "This is a example value."
sub_resource = {
example_var = "This is a example value of sub resource."
roles = {
readonly = {
comment = "Read-only role"
granted_roles = [resource.snowflake_account_role.this.name]
granted_to_users = [resource.snowflake_user.this.name]
}
}
}
2 changes: 1 addition & 1 deletion examples/complete/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
output "example_output" {
description = "Example output of the module"
value = module.terraform_module_template
value = module.snowflake_shared_database
}
4 changes: 1 addition & 3 deletions examples/complete/providers.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
provider "null" {
# Configuration options
}
provider "snowflake" {}
4 changes: 4 additions & 0 deletions examples/complete/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
variable "from_share" {
description = "A fully qualified path to a share from which the database will be created. A fully qualified path follows the format of `<organization_name>.<account_name>.<share_name>`"
type = string
}
9 changes: 4 additions & 5 deletions examples/complete/versions.tf
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
terraform {
required_version = ">= 1.3.0"

required_version = ">= 1.3"
required_providers {
null = {
source = "hashicorp/null"
version = "3.1.1"
snowflake = {
source = "Snowflake-Labs/snowflake"
version = ">= 0.95"
}
}
}
10 changes: 10 additions & 0 deletions examples/simple/.env.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
SNOWFLAKE_USER=
SNOWFLAKE_ACCOUNT=
SNOWFLAKE_ROLE="ACCOUNTADMIN"

# Login using RSA key
# SNOWFLAKE_PRIVATE_KEY_PATH=
# SNOWFLAKE_AUTHENTICATOR="JWT"

# Login using password
# SNOWFLAKE_PASSWORD=
2 changes: 1 addition & 1 deletion examples/simple/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ apply:
terraform apply tfplan

destroy:
terraform destroy
terraform destroy
44 changes: 34 additions & 10 deletions examples/simple/README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,61 @@
# Simple Example

```terraform
module "terraform_module_template" {
source = "../../"
module "snowflake_shared_database" {
source = "../.."
example_var = "This is a example value."
sub_resource = {
example_var = "This is a example value of sub resource."
}
name = "SHARED_DATABASE"
from_share = var.from_share
}
```

## Usage

1. Configure private sharing on producer Snowflake Account (remember that both producer and consumer accounts have to be deployed on the same Cloud Provider for. ex. AWS and in the same region for. ex. `eu-west-1`)

This step can be done manually using Snowsight UI or by running [create_share.sql](./create-share.sql) script on producer Snowflake account.

When using the script, please remember to properly define consumer account details in the last line:

```sql
ALTER SHARE sample_share ADD ACCOUNT="<orgname.accountname>";
```

2. With share configured in step 1., run terraform on consumer account using below commands

```shell
terraform init
terraform plan -out tfplan
terraform apply tfplan
```

**Please remember to pass share details (from step 1.) to `from_share` variable.**

```shell
$ terraform plan
var.from_share
A fully qualified path to a share from which the database will be created. A fully qualified path follows the format of `<organization_name>.<account_name>.<share_name>`

Enter a value: <orgname.accountname.sharename>
```

<!-- BEGIN_TF_DOCS -->




## Inputs

No inputs.
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_from_share"></a> [from\_share](#input\_from\_share) | A fully qualified path to a share from which the database will be created. A fully qualified path follows the format of `<organization_name>.<account_name>.<share_name>` | `string` | n/a | yes |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_terraform_module_template"></a> [terraform\_module\_template](#module\_terraform\_module\_template) | ../../ | n/a |
| <a name="module_snowflake_shared_database"></a> [snowflake\_shared\_database](#module\_snowflake\_shared\_database) | ../.. | n/a |

## Outputs

Expand All @@ -47,8 +71,8 @@ No providers.

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3.0 |
| <a name="requirement_null"></a> [null](#requirement\_null) | 3.1.1 |
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3 |
| <a name="requirement_snowflake"></a> [snowflake](#requirement\_snowflake) | >= 0.95 |

## Resources

Expand Down
23 changes: 23 additions & 0 deletions examples/simple/create-share.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
CREATE DATABASE sample_shared_db;

CREATE SCHEMA sample_shared_db.shared_schema;

CREATE TABLE sample_shared_db.shared_schema.sample_table (
ID NUMBER,
VALUE TEXT
);

INSERT INTO sample_shared_db.shared_schema.sample_table
VALUES
(1, 'TEST VALUE'),
(2, 'ANOTHER TEST VALUE');

CREATE SHARE sample_share COMMENT = 'Test Share';

GRANT USAGE ON DATABASE sample_shared_db TO SHARE sample_share;

GRANT USAGE ON SCHEMA sample_shared_db.shared_schema TO SHARE sample_share;

GRANT SELECT ON ALL TABLES IN SCHEMA sample_shared_db.shared_schema TO SHARE sample_share;

ALTER SHARE sample_share ADD ACCOUNT="<orgname.accountname>";
11 changes: 4 additions & 7 deletions examples/simple/main.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
module "terraform_module_template" {
source = "../../"
module "snowflake_shared_database" {
source = "../.."

example_var = "This is a example value."

sub_resource = {
example_var = "This is a example value of sub resource."
}
name = "SHARED_DATABASE"
from_share = var.from_share
}
2 changes: 1 addition & 1 deletion examples/simple/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
output "example_output" {
description = "Example output of the module"
value = module.terraform_module_template
value = module.snowflake_shared_database
}
Loading

0 comments on commit 5363024

Please sign in to comment.