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

feat: Tag association v1 readiness #3210

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
78 changes: 74 additions & 4 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,77 @@ across different versions.

> [!TIP]
> We highly recommend upgrading the versions one by one instead of bulk upgrades.


## v0.99.0 ➞ v0.100.0

### snowflake_tag_association resource changes
#### *(behavior change)* new id format
In order to provide more functionality for tagging objects, we have changed the resource id from `"TAG_DATABASE"."TAG_SCHEMA"."TAG_NAME"` to `"TAG_DATABASE"."TAG_SCHEMA"."TAG_NAME"|TAG_VALUE|OBJECT_TYPE`. This allows to group tags associations per tag ID, tag value and object type in one resource.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so it means that if I want to add the same tag, same value to the same object type, then I have to put all of them in one resource, right? (here it would mean that changing silver to gold in the second resource is not permitted because both these resources would have the same id)

If I understand this correctly, then I think it would be good to add this info, directly to the resource docs, and here too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, added more explanation.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the operation deterministic if done in one go? I mean it's possible that value will be first added in the first resource and later removed as part of second resource removal, right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(because unset does not take the value)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, true. Added more instructions here and in the resource docs.

```
resource "snowflake_tag_association" "gold_warehouses" {
object_identifiers = [snowflake_warehouse.w1.fully_qualified_name, snowflake_warehouse.w2.fully_qualified_name]
object_type = "WAREHOUSE"
tag_id = snowflake_tag.tier.fully_qualified_name
tag_value = "gold"
}
resource "snowflake_tag_association" "silver_warehouses" {
object_identifiers = [snowflake_warehouse.w3.fully_qualified_name]
object_type = "WAREHOUSE"
tag_id = snowflake_tag.tier.fully_qualified_name
tag_value = "silver"
}
resource "snowflake_tag_association" "silver_databases" {
object_identifiers = [snowflake_database.d1.fully_qualified_name]
object_type = "DATABASE"
tag_id = snowflake_tag.tier.fully_qualified_name
tag_value = "silver"
}
```

Note that if you want to promote silver instances to gold, you can not simply change `tag_value` in `silver_warehouses`. Instead, you should first remove `object_identifiers` from `silver_warehouses`, run `terraform apply`, and then add the relevant `object_identifiers` in `gold_warehouses`, like this (note that `silver_warehouses` resource was deleted):
```
resource "snowflake_tag_association" "gold_warehouses" {
object_identifiers = [snowflake_warehouse.w1.fully_qualified_name, snowflake_warehouse.w2.fully_qualified_name, snowflake_warehouse.w3.fully_qualified_name]
object_type = "WAREHOUSE"
tag_id = snowflake_tag.tier.fully_qualified_name
tag_value = "gold"
}
```
and run `terraform apply` again.

Note that the order of operations is not deterministic in this case, and if you do these operations in one step, it is possible that the tag value will be changed first, and unset later because of removing the resource with old value.

The state is migrated automatically. There is no need to adjust configuration files, unless you use resource id `snowflake_tag_association.example.id` as a reference in other resources.

#### *(behavior change)* changed fields
Behavior of some fields was changed:
- `object_identifier` was renamed to `object_identifiers` and it is now a set of fully qualified names. Change your configurations from
```
resource "snowflake_tag_association" "table_association" {
object_identifier {
name = snowflake_table.test.name
database = snowflake_database.test.name
schema = snowflake_schema.test.name
}
object_type = "TABLE"
tag_id = snowflake_tag.test.fully_qualified_name
tag_value = "engineering"
}
```
to
```
resource "snowflake_tag_association" "table_association" {
object_identifiers = [snowflake_table.test.fully_qualified_name]
object_type = "TABLE"
tag_id = snowflake_tag.test.fully_qualified_name
tag_value = "engineering"
}
```
- `tag_id` has now suppressed identifier quoting to prevent issues with Terraform showing permament differences, like [this one](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2982)
- `object_type` and `tag_id` are now marked as ForceNew

The state is migrated automatically. Please adjust your configuration files.

## v0.98.0 ➞ v0.99.0

### snowflake_tasks data source changes
Expand Down Expand Up @@ -39,7 +109,7 @@ data "snowflake_tasks" "new_tasks" {
in {
# for IN SCHEMA specify:
schema = "<database_name>.<schema_name>"

# for IN DATABASE specify:
database = "<database_name>"
}
Expand All @@ -65,7 +135,7 @@ New fields:
- `config` - enables to specify JSON-formatted metadata that can be retrieved in the `sql_statement` by using [SYSTEM$GET_TASK_GRAPH_CONFIG](https://docs.snowflake.com/en/sql-reference/functions/system_get_task_graph_config).
- `show_output` and `parameters` fields added for holding SHOW and SHOW PARAMETERS output (see [raw Snowflake output](./v1-preparations/CHANGES_BEFORE_V1.md#raw-snowflake-output)).
- Added support for finalizer tasks with `finalize` field. It conflicts with `after` and `schedule` (see [finalizer tasks](https://docs.snowflake.com/en/user-guide/tasks-graphs#release-and-cleanup-of-task-graphs)).

Changes:
- `enabled` field changed to `started` and type changed to string with only boolean values available (see ["empty" values](./v1-preparations/CHANGES_BEFORE_V1.md#empty-values)). It is also now required field, so make sure it's explicitly set (previously it was optional with the default value set to `false`).
- `allow_overlapping_execution` type was changed to string with only boolean values available (see ["empty" values](./v1-preparations/CHANGES_BEFORE_V1.md#empty-values)). Previously, it had the default set to `false` which will be migrated. If nothing will be set the provider will plan the change to `default` value. If you want to make sure it's turned off, set it explicitly to `false`.
Expand Down Expand Up @@ -132,7 +202,7 @@ resource "snowflake_task" "example" {
```

- `after` field type was changed from `list` to `set` and the values were changed from names to fully qualified names.

Before:
```terraform
resource "snowflake_task" "example" {
Expand Down
76 changes: 34 additions & 42 deletions docs/resources/tag_association.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,20 @@
page_title: "snowflake_tag_association Resource - terraform-provider-snowflake"
subcategory: ""
description: |-

Resource used to manage tag associations. For more information, check object tagging documentation https://docs.snowflake.com/en/user-guide/object-tagging.
---

# snowflake_tag_association (Resource)
!> **V1 release candidate** This resource was reworked and is a release candidate for the V1. We do not expect significant changes in it before the V1. We will welcome any feedback and adjust the resource if needed. Any errors reported will be resolved with a higher priority. We encourage checking this resource out before the V1 release. Please follow the [migration guide](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/MIGRATION_GUIDE.md#v0980--v0990) to use it.

-> **Note** For `ACCOUNT` object type, only identifiers with organization name are supported. See [account identifier docs](https://docs.snowflake.com/en/user-guide/admin-account-identifier#format-1-preferred-account-name-in-your-organization) for more details.

-> **Note** Tag association resource ID has the following format: `"TAG_DATABASE"."TAG_SCHEMA"."TAG_NAME"|TAG_VALUE|OBJECT_TYPE`. This means that a tuple of tag ID, tag value and object type should be unique across the resources. If you want to specify this combination for more than one object, you should use only one `tag_association` resource with specified `object_identifiers` set.

-> **Note** If you want to change tag value to a value that has already present in another resource, first remove needed `object_identifiers` from the resource with the old value, run `terraform apply`, then add the relevant `object_identifiers` in the resource with new value, and run `terrafrom apply` once again.

# snowflake_tag_association (Resource)

Resource used to manage tag associations. For more information, check [object tagging documentation](https://docs.snowflake.com/en/user-guide/object-tagging).

## Example Usage

Expand All @@ -29,12 +37,10 @@ resource "snowflake_tag" "test" {
}

resource "snowflake_tag_association" "db_association" {
object_identifier {
name = snowflake_database.test.name
}
object_type = "DATABASE"
tag_id = snowflake_tag.test.id
tag_value = "finance"
object_identifiers = [snowflake_database.test.fully_qualified_name]
object_type = "DATABASE"
tag_id = snowflake_tag.test.fully_qualified_name
tag_value = "finance"
}

resource "snowflake_table" "test" {
Expand All @@ -53,28 +59,26 @@ resource "snowflake_table" "test" {
}

resource "snowflake_tag_association" "table_association" {
object_identifier {
name = snowflake_table.test.name
database = snowflake_database.test.name
schema = snowflake_schema.test.name
}
object_type = "TABLE"
tag_id = snowflake_tag.test.id
tag_value = "engineering"
object_identifiers = [snowflake_table.test.fully_qualified_name]
object_type = "TABLE"
tag_id = snowflake_tag.test.fully_qualified_name
tag_value = "engineering"
}

resource "snowflake_tag_association" "column_association" {
object_identifier {
name = "${snowflake_table.test.name}.column_name"
database = snowflake_database.test.name
schema = snowflake_schema.test.name
}
object_type = "COLUMN"
tag_id = snowflake_tag.test.id
tag_value = "engineering"
object_identifiers = [snowflake_database.test.fully_qualified_name]
object_type = "COLUMN"
tag_id = snowflake_tag.test.fully_qualified_name
tag_value = "engineering"
}
```

resource "snowflake_tag_association" "account_association" {
object_identifiers = ["\"ORGANIZATION_NAME\".\"ACCOUNT_NAME\""]
object_type = "ACCOUNT"
tag_id = snowflake_tag.test.fully_qualified_name
tag_value = "engineering"
}
```
-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources).
<!-- TODO(SNOW-1634854): include an example showing both methods-->

Expand All @@ -83,9 +87,9 @@ resource "snowflake_tag_association" "column_association" {

### Required

- `object_identifier` (Block List, Min: 1) Specifies the object identifier for the tag association. (see [below for nested schema](#nestedblock--object_identifier))
- `object_identifiers` (Set of String) Specifies the object identifiers for the tag association.
- `object_type` (String) Specifies the type of object to add a tag. Allowed object types: [ACCOUNT APPLICATION APPLICATION PACKAGE DATABASE FAILOVER GROUP INTEGRATION NETWORK POLICY REPLICATION GROUP ROLE SHARE USER WAREHOUSE DATABASE ROLE SCHEMA ALERT SNOWFLAKE.CORE.BUDGET SNOWFLAKE.ML.CLASSIFICATION EXTERNAL FUNCTION EXTERNAL TABLE FUNCTION GIT REPOSITORY ICEBERG TABLE MATERIALIZED VIEW PIPE MASKING POLICY PASSWORD POLICY ROW ACCESS POLICY SESSION POLICY PRIVACY POLICY PROCEDURE STAGE STREAM TABLE TASK VIEW COLUMN EVENT TABLE].
- `tag_id` (String) Specifies the identifier for the tag. Note: format must follow: "databaseName"."schemaName"."tagName" or "databaseName.schemaName.tagName" or "databaseName|schemaName.tagName" (snowflake_tag.tag.id)
- `tag_id` (String) Specifies the identifier for the tag.
- `tag_value` (String) Specifies the value of the tag, (e.g. 'finance' or 'engineering')

### Optional
Expand All @@ -98,19 +102,6 @@ resource "snowflake_tag_association" "column_association" {

- `id` (String) The ID of this resource.

<a id="nestedblock--object_identifier"></a>
### Nested Schema for `object_identifier`

Required:

- `name` (String) Name of the object to associate the tag with.

Optional:

- `database` (String) Name of the database that the object was created in.
- `schema` (String) Name of the schema that the object was created in.


<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`

Expand All @@ -120,9 +111,10 @@ Optional:

## Import

~> **Note** Due to technical limitations of Terraform SDK, `object_identifiers` are not set during import state. Please run `terraform refresh` after importing to get this field populated.

Import is supported using the following syntax:

```shell
# format is dbName.schemaName.tagName or dbName.schemaName.tagName
terraform import snowflake_tag_association.example 'dbName.schemaName.tagName'
terraform import snowflake_tag_association.example '"TAG_DATABASE"."TAG_SCHEMA"."TAG_NAME"|TAG_VALUE|OBJECT_TYPE'
```
3 changes: 1 addition & 2 deletions examples/resources/snowflake_tag_association/import.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
# format is dbName.schemaName.tagName or dbName.schemaName.tagName
terraform import snowflake_tag_association.example 'dbName.schemaName.tagName'
terraform import snowflake_tag_association.example '"TAG_DATABASE"."TAG_SCHEMA"."TAG_NAME"|TAG_VALUE|OBJECT_TYPE'
41 changes: 19 additions & 22 deletions examples/resources/snowflake_tag_association/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@ resource "snowflake_tag" "test" {
}

resource "snowflake_tag_association" "db_association" {
object_identifier {
name = snowflake_database.test.name
}
object_type = "DATABASE"
tag_id = snowflake_tag.test.id
tag_value = "finance"
object_identifiers = [snowflake_database.test.fully_qualified_name]
object_type = "DATABASE"
tag_id = snowflake_tag.test.fully_qualified_name
tag_value = "finance"
}

resource "snowflake_table" "test" {
Expand All @@ -39,23 +37,22 @@ resource "snowflake_table" "test" {
}

resource "snowflake_tag_association" "table_association" {
object_identifier {
name = snowflake_table.test.name
database = snowflake_database.test.name
schema = snowflake_schema.test.name
}
object_type = "TABLE"
tag_id = snowflake_tag.test.id
tag_value = "engineering"
object_identifiers = [snowflake_table.test.fully_qualified_name]
object_type = "TABLE"
tag_id = snowflake_tag.test.fully_qualified_name
tag_value = "engineering"
}

resource "snowflake_tag_association" "column_association" {
object_identifier {
name = "${snowflake_table.test.name}.column_name"
database = snowflake_database.test.name
schema = snowflake_schema.test.name
}
object_type = "COLUMN"
tag_id = snowflake_tag.test.id
tag_value = "engineering"
object_identifiers = [snowflake_database.test.fully_qualified_name]
object_type = "COLUMN"
tag_id = snowflake_tag.test.fully_qualified_name
tag_value = "engineering"
}

resource "snowflake_tag_association" "account_association" {
object_identifiers = ["\"ORGANIZATION_NAME\".\"ACCOUNT_NAME\""]
object_type = "ACCOUNT"
tag_id = snowflake_tag.test.fully_qualified_name
tag_value = "engineering"
}
Loading
Loading