This document is meant to help you migrate your Terraform config to the new newest version. In migration guides, we will only describe deprecations or breaking changes and help you to change your configuration to keep the same (or similar) behavior across different versions.
Following the announcement we have removed the old grant resources. The two resources snowflake_role_ownership_grant and snowflake_user_ownership_grant were not listed in the announcement, but they were also marked as deprecated ones. We are removing them too to conclude the grants redesign saga.
Renamed field provisioner_role
to run_as_role
to align with Snowflake docs. Please rename this field in your configuration files. State will be migrated automatically.
Field enabled
is now required. Previously the default value during create in Snowflake was true
. If you created a resource with Terraform, please add enabled = true
to have the same value.
Force new was added for the following attributes (because no usable SQL alter statements for them):
scim_client
run_as_role
As part of the redesign we are removing the default values for attributes having their defaults on Snowflake side to reduce coupling with the provider. Because of that the following defaults were removed:
comment
statement_timeout_in_seconds
statement_queued_timeout_in_seconds
max_concurrency_level
enable_query_acceleration
query_acceleration_max_scale_factor
warehouse_type
All previous defaults were aligned with the current Snowflake ones, however:
- if the given parameter was changed on the account level, terraform will try to update it
As part of the redesign we are adjusting validations or removing them to reduce coupling between Snowflake and the provider. Because of that the following validations were removed/adjusted/added:
max_cluster_count
- adjusted: added higher bound (10) according to Snowflake docsmin_cluster_count
- adjusted: added higher bound (10) according to Snowflake docsauto_suspend
- adjusted: added0
as valid valuewarehouse_size
- adjusted: removed incorrect2XLARGE
,3XLARGE
,4XLARGE
,5XLARGE
,6XLARGE
valuesresource_monitor
- added: validation for a valid identifier (still subject to change during identifiers rework)max_concurrency_level
- added: validation according to MAX_CONCURRENCY_LEVEL parameter docsstatement_queued_timeout_in_seconds
- added: validation according to STATEMENT_QUEUED_TIMEOUT_IN_SECONDS parameter docsstatement_timeout_in_seconds
- added: validation according to STATEMENT_TIMEOUT_IN_SECONDS parameter docs
wait_for_provisioning
field was deprecated a long time ago. It's high time it was removed from the schema.
Previously, the query_acceleration_max_scale_factor
was depending on enable_query_acceleration
parameter, but it is not required on Snowflake side. After migration, terraform plan
should suggest changes if enable_query_acceleration
was earlier set to false (manually or from default) and if query_acceleration_max_scale_factor
was set in config.
To easily handle three-value logic (true, false, unknown) in provider's configs, type of auto_resume
and enable_query_acceleration
was changed from boolean to string. This should not require updating existing configs (boolean/int value should be accepted and state will be migrated to string automatically), however we recommend changing config values to strings. Terraform should perform an action for configs lacking auto_resume
or enable_query_acceleration
(ALTER WAREHOUSE UNSET AUTO_RESUME
and/or ALTER WAREHOUSE UNSET ENABLE_QUERY_ACCELERATION
will be run underneath which should not affect the Snowflake object, because auto_resume
and enable_query_acceleration
are false by default).
resource_monitor
is an identifier and handling logic may be still slightly changed as part of https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/ROADMAP.md#identifiers-rework. It should be handled automatically (without needed manual actions on user side), though, but it is not guaranteed.
As part of the preparation for v1, we split up the database resource into multiple ones:
- Standard database - can be used as
snowflake_database
(replaces the old one and is used to create databases with optional ability to become a primary database ready for replication) - Shared database - can be used as
snowflake_shared_database
(used to create databases from externally defined shares) - Secondary database - can be used as
snowflake_secondary_database
(used to create replicas of databases from external sources)
All the field changes in comparison to the previous database resource are:
is_transient
- in
snowflake_shared_database
- removed: the field is removed from
snowflake_shared_database
as it doesn't have any effect on shared databases.
- removed: the field is removed from
- in
from_database
- database cloning was entirely removed and is not possible by any of the new database resources.from_share
- the parameter was moved to the dedicated resource for databases created from sharessnowflake_shared_database
. Right now, it's a text field instead of a map. Additionally, instead of legacy account identifier format we're expecting the new one that with share looks like this:<organization_name>.<account_name>.<share_name>
. For more information on account identifiers, visit the official documentation.- p,
from_replication
- the parameter was moved to the dedicated resource for databases created from primary databasessnowflake_secondary_database
replication_configuration
- renamed: was renamed toconfiguration
and is only available in thesnowflake_database
. Its internal schema changed that instead of list of accounts, we expect a list of nested objects with accounts for which replication (and optionally failover) should be enabled. More information about converting between both versions here. Additionally, instead of legacy account identifier format we're expecting the new one that looks like this:<organization_name>.<account_name>
. For more information on account identifiers, visit the official documentation.data_retention_time_in_days
- in
snowflake_shared_database
- removed: the field is removed from
snowflake_shared_database
as it doesn't have any effect on shared databases.
- removed: the field is removed from
- in
snowflake_database
andsnowflake_secondary_database
- adjusted: now, it uses different approach that won't set it to -1 as a default value, but rather fills the field with the current value from Snowflake (this still can change).
- in
- added: The following set of parameters was added to every database type:
max_data_extension_time_in_days
external_volume
catalog
replace_invalid_characters
default_ddl_collation
storage_serialization_policy
log_level
trace_level
suspend_task_after_num_failures
task_auto_retry_attempts
user_task_managed_initial_warehouse_size
user_task_timeout_ms
user_task_minimum_trigger_interval_in_seconds
quoted_identifiers_ignore_case
enable_console_output
The split was done (and will be done for several objects during the refactor) to simplify the resource on maintainability and usage level. Its purpose was also to divide the resources by their specific purpose rather than cramping every use case of an object into one resource.
We made a decision to use the existing snowflake_database
resource for redesigning it into a standard database.
The previous snowflake_database
was renamed to snowflake_database_old
and the current snowflake_database
contains completely new implementation that follows our guidelines we set for V1.
When upgrading to the 0.93.0 version, the automatic state upgrader should cover the migration for databases that didn't have the following fields set:
from_share
(now, the newsnowflake_shared_database
should be used instead)from_replica
(now, the newsnowflake_secondary_database
should be used instead)replication_configuration
For configurations containing replication_configuraiton
like this one:
resource "snowflake_database" "test" {
name = "<name>"
replication_configuration {
accounts = ["<account_locator>", "<account_locator_2>"]
ignore_edition_check = true
}
}
You have to transform the configuration into the following format (notice the change from account locator into the new account identifier format):
resource "snowflake_database" "test" {
name = "%s"
replication {
enable_to_account {
account_identifier = "<organization_name>.<account_name>"
with_failover = false
}
enable_to_account {
account_identifier = "<organization_name_2>.<account_name_2>"
with_failover = false
}
}
ignore_edition_check = true
}
If you had from_database
set, it should migrate automatically.
For now, we're dropping the possibility to create a clone database from other databases.
The only way will be to clone a database manually and import it as snowflake_database
, but if
cloned databases diverge in behavior from standard databases, it may cause issues.
For databases with one of the fields mentioned above, manual migration will be needed. Please refer to our migration guide to perform zero downtime migration.
If you would like to upgrade to the latest version and postpone the upgrade, you still have to perform the maunal migration
to the snowflake_database_old
resource by following the zero downtime migrations document.
The only difference would be that instead of writing/generating new configurations you have to just rename the existing ones to contain _old
suffix.
terse
andhistory
fields were removed.replication_configuration
field was removed fromdatabases
.pattern
was replaced bylike
field.- Additional filtering options added (
limit
). - Added missing fields returned by SHOW DATABASES.
- Added outputs from DESC DATABASE and SHOW PARAMETERS IN DATABASE (they can be turned off by declaring
with_describe = false
andwith_parameters = false
, they're turned on by default). The additional parameters call DESC DATABASE (withwith_describe
turned on) and SHOW PARAMETERS IN DATABASE (withwith_parameters
turned on) per database returned by SHOW DATABASES. It's important to limit the records and calls to Snowflake to the minimum. That's why we recommend assessing which information you need from the data source and then providing strong filters and turning off additional fields for better plan performance.
While solving issue #2733 we have introduced diff suppression for column.type
. To make it work correctly we have also added a validation to it. It should not cause any problems, but it's worth noting in case of any data types used that the provider is not aware of.
Diff suppression for arguments.type
is needed for the same reason as above for snowflake_table
resource.
Now the tag_masking_policy_association
resource will only accept fully qualified names separated by dot .
instead of pipe |
.
Before
resource "snowflake_tag_masking_policy_association" "name" {
tag_id = snowflake_tag.this.id
masking_policy_id = snowflake_masking_policy.example_masking_policy.id
}
After
resource "snowflake_tag_masking_policy_association" "name" {
tag_id = "\"${snowflake_tag.this.database}\".\"${snowflake_tag.this.schema}\".\"${snowflake_tag.this.name}\""
masking_policy_id = "\"${snowflake_masking_policy.example_masking_policy.database}\".\"${snowflake_masking_policy.example_masking_policy.schema}\".\"${snowflake_masking_policy.example_masking_policy.name}\""
}
It's more verbose now, but after identifier rework it should be similar to the previous form.
The ForceNew
field was removed in favor of in-place Update for name
parameter in:
snowflake_file_format
snowflake_masking_policy
So from now, these objects won't be re-created when thename
changes, but instead only the name will be updated withALTER .. RENAME TO
statements.
From now on, the snowflake_procedure
's execute_as
parameter allows only two values: OWNER and CALLER (case-insensitive). Setting other values earlier resulted in falling back to the Snowflake default (currently OWNER) and creating a permadiff.
snowflake_grants
datasource was refreshed as part of the ongoing Grants Redesign.
To be aligned with the convention in other grant resources, role
was renamed to account_role
for the following fields:
grants_to.role
grants_of.role
future_grants_to.role
.
To migrate simply change role
to account_role
in the aforementioned fields.
grants_to.share
was a text field. Because Snowflake introduced new syntax SHOW GRANTS TO SHARE <share_name> IN APPLICATION PACKAGE <app_package_name>
(check more in the docs) the type was changed to object. To migrate simply change:
data "snowflake_grants" "example_to_share" {
grants_to {
share = "some_share"
}
}
to
data "snowflake_grants" "example_to_share" {
grants_to {
share {
share_name = "some_share"
}
}
}
Note: in_application_package
is not yet supported.
future_grants_in.schema
was an object field allowing to set required schema_name
and optional database_name
. Our strategy is to be explicit, so the schema field was changed to string and fully qualified name is expected. To migrate change:
data "snowflake_grants" "example_future_in_schema" {
future_grants_in {
schema {
database_name = "some_database"
schema_name = "some_schema"
}
}
}
to
data "snowflake_grants" "example_future_in_schema" {
future_grants_in {
schema = "\"some_database\".\"some_schema\""
}
}
grants_to
was enriched with three new options:
application
application_role
database_role
No migration work is needed here.
grants_to
was enriched with two new options:
database_role
application_role
No migration work is needed here.
future_grants_to
was enriched with one new option:
database_role
No migration work is needed here.
Descriptions of attributes were altered. More examples were added (both for old and new features).
Previously, in snowflake_database
when creating a database form share, it was possible to provide from_share.provider
in the format of <org_name>.<account_name>
. It worked even though we expected account locator because our "external" identifier wasn't quoting its string representation.
To be consistent with other identifier types, we quoted the output of "external" identifiers which makes such configurations break
(previously, they were working "by accident"). To fix it, the previous format of <org_name>.<account_name>
has to be changed
to account locator format <account_locator>
(mind that it's now case-sensitive). The account locator can be retrieved by calling select current_account();
on the sharing account.
In the future we would like to eventually come back to the <org_name>.<account_name>
format as it's recommended by Snowflake.
There were several issues reported about the configuration hierarchy, e.g. #2294 and #2242. In fact, the order of precedence described in the docs was not followed. This have led to the incorrect behavior.
After migrating to this version, the hierarchy from the docs should be followed:
The Snowflake provider will use the following order of precedence when determining which credentials to use:
1) Provider Configuration
2) Environment Variables
3) Config File
BEWARE: your configurations will be affected with that change because they may have been leveraging the incorrect configurations precedence. Please be sure to check all the configurations before running terraform.
Longer context in #2517.
After this change, one apply may be required to update the state correctly for failover group resources using ACCOUNT PARAMETERS
.
(behavior change) Database data_retention_time_in_days
+ Schema data_retention_days
+ Table data_retention_time_in_days
For context #2356.
To make data retention fields truly optional (previously they were producing plan every time when no value was set),
we added -1
as a possible value, and it is set as default. That got rid of the unexpected plans when no value is set and added possibility to use default value assigned by Snowflake (see the data retention period).
For context #2356.
To define data retention days for table data_retention_time_in_days
should be used as deprecated data_retention_days
field is being removed.
The type
of the constraint was limited back to UNIQUE
, PRIMARY KEY
, and FOREIGN KEY
.
The reason for that is, that syntax for Out-of-Line constraint (docs) does not contain NOT NULL
.
It is noted as a behavior change but in some way it is not; with the previous implementation it did not work at all with type
set to NOT NULL
because the generated statement was not a valid Snowflake statement.
We will consider adding NOT NULL
back because it can be set by ALTER COLUMN columnX SET NOT NULL
, but first we want to revisit the whole resource design.
The docs were inconsistent. Example prior to 0.86.0 version showed using the table.id
as the table_id
reference. The description of the table_id
parameter never allowed such a value (table.id
is a |
-delimited identifier representation and only the .
-separated values were listed in the docs: https://registry.terraform.io/providers/Snowflake-Labs/snowflake/0.85.0/docs/resources/table_constraint#required. The misuse of table.id
parameter will result in error after migrating to 0.86.0. To make the config work, please remove and reimport the constraint resource from the state as described in resource migration doc.
After discussions in #2535 we decided to provide a temporary workaround in 0.87.0 version, so that the manual migration is not necessary. It allows skipping the migration and jumping straight to 0.87.0 version. However, the temporary workaround will be gone in one of the future versions. Please adjust to the newly suggested reference with the new resources you create.
The return_null_allowed
attribute default value is now true
. This is a behavior change because it was false
before. The reason it was changed is to match the expected default value in the documentation Default: The default is NULL (i.e. the function can return NULL values).
The comment
attribute is now optional. It was required before, but it is not required in Snowflake API.
The schema
attribute is now required with database
attribute to match old implementation SHOW EXTERNAL FUNCTIONS IN SCHEMA "<database>"."<schema>"
. In the future this may change to make schema optional.
In recent changes, we introduced a new grant resources to replace the old ones. To aid with the migration, we wrote a guide to show one of the possible ways to migrate deprecated resources to their new counter-parts. As the guide is more general and applies to every version (and provider), we moved it here.
return_behavior
parameter is deprecated because it is also deprecated in the Snowflake API.
return_type
has become force new because there is no way to alter it without dropping and recreating the function.
Setting copy_options
to ON_ERROR = 'CONTINUE'
would result in a permadiff. Use ON_ERROR = CONTINUE
(without single quotes) or bump to v0.89.0 in which the behavior was fixed.
notification_provider
becomes required and has three possible values AZURE_STORAGE_QUEUE
, AWS_SNS
, and GCP_PUBSUB
.
It is still possible to set it to AWS_SQS
but because there is no underlying SQL, so it will result in an error.
Attributes aws_sqs_arn
and aws_sqs_role_arn
will be ignored.
Computed attributes aws_sqs_external_id
and aws_sqs_iam_user_arn
won't be updated.
Force new was added for the following attributes (because no usable SQL alter statements for them):
azure_storage_queue_primary_uri
azure_tenant_id
gcp_pubsub_subscription_name
gcp_pubsub_topic_name
direction
parameter is deprecated because it is added automatically on the SDK level.
type
parameter is deprecated because it is added automatically on the SDK level (and basically it's always QUEUE
).
In this change we have done a provider refactor to make it more complete and customizable by supporting more options that were already available in Golang Snowflake driver. This lead to several attributes being added and a few deprecated. We will focus on the deprecated ones and show you how to adapt your current configuration to the new changes.
provider "snowflake" {
# before
username = "username"
# after
user = "username"
}
provider "snowflake" {
# before
browser_auth = false
oauth_access_token = "<access_token>"
oauth_refresh_token = "<refresh_token>"
oauth_client_id = "<client_id>"
oauth_client_secret = "<client_secret>"
oauth_endpoint = "<endpoint>"
oauth_redirect_url = "<redirect_uri>"
# after
authenticator = "ExternalBrowser"
token = "<access_token>"
token_accessor {
refresh_token = "<refresh_token>"
client_id = "<client_id>"
client_secret = "<client_secret>"
token_endpoint = "<endpoint>"
redirect_uri = "<redirect_uri>"
}
}
Specifying a region is a legacy thing and according to https://docs.snowflake.com/en/user-guide/admin-account-identifier you can specify a region as a part of account parameter. Specifying account parameter with the region is also considered legacy, but with this approach it will be easier to convert only your account identifier to the new preferred way of specifying account identifier.
provider "snowflake" {
# before
region = "<cloud_region_id>"
# after
account = "<account_locator>.<cloud_region_id>"
}
provider "snowflake" {
# before
private_key_path = "<filepath>"
# after
private_key = file("<filepath>")
}
provider "snowflake" {
# before
session_params = {}
# after
params = {}
}
Before the change authenticator
parameter did not have to be set for private key authentication and was deduced by the provider. The change is a result of the introduced configuration alignment with an underlying gosnowflake driver. The authentication type is required there, and it defaults to user+password one. From this version, set authenticator
to JWT
explicitly.