From a1444783981a4faae6ede35289ffb64b7565e621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Tue, 6 Aug 2024 14:46:39 +0200 Subject: [PATCH 1/4] fix database tests and introduce new parameter --- MIGRATION_GUIDE.md | 4 +- docs/resources/database.md | 1 + pkg/acceptance/helpers/database_client.go | 10 + pkg/resources/database.go | 26 ++ pkg/resources/database_acceptance_test.go | 332 +++++++++++----------- 5 files changed, 206 insertions(+), 167 deletions(-) diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 0082d9442c..30898f1c5b 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -461,7 +461,9 @@ resource "snowflake_database" "test" { } ``` -If you had `from_database` set, it should migrate automatically. +If you had `from_database` set, you should follow our [resource migration guide](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/docs/technical-documentation/resource_migration.md) to remove +the database from state to later import it in the newer version of the provider. +Otherwise, it may cause issues when migrating to v0.93.0. 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. diff --git a/docs/resources/database.md b/docs/resources/database.md index 8a8ca5f778..8371e9d137 100644 --- a/docs/resources/database.md +++ b/docs/resources/database.md @@ -90,6 +90,7 @@ resource "snowflake_database" "primary" { - `comment` (String) Specifies a comment for the database. - `data_retention_time_in_days` (Number) Specifies the number of days for which Time Travel actions (CLONE and UNDROP) can be performed on the database, as well as specifying the default Time Travel retention time for all schemas created in the database. For more details, see [Understanding & Using Time Travel](https://docs.snowflake.com/en/user-guide/data-time-travel). - `default_ddl_collation` (String) Specifies a default collation specification for all schemas and tables added to the database. It can be overridden on schema or table level. For more information, see [collation specification](https://docs.snowflake.com/en/sql-reference/collation#label-collation-specification). +- `drop_public_schema_on_creation` (Boolean) Specifies whether to drop public schema on creation or not. Modifying the parameter after database is already created won't have any effect. - `enable_console_output` (Boolean) If true, enables stdout/stderr fast path logging for anonymous stored procedures. - `external_volume` (String) The database parameter that specifies the default external volume to use for Iceberg tables. For more information, see [EXTERNAL_VOLUME](https://docs.snowflake.com/en/sql-reference/parameters#external-volume). - `is_transient` (Boolean) Specifies the database as transient. Transient databases do not have a Fail-safe period so they do not incur additional storage costs once they leave Time Travel; however, this means they are also not protected by Fail-safe in the event of a data loss. diff --git a/pkg/acceptance/helpers/database_client.go b/pkg/acceptance/helpers/database_client.go index bc657a1fa3..e0dc584dfd 100644 --- a/pkg/acceptance/helpers/database_client.go +++ b/pkg/acceptance/helpers/database_client.go @@ -146,3 +146,13 @@ func (c *DatabaseClient) Show(t *testing.T, id sdk.AccountObjectIdentifier) (*sd return c.client().ShowByID(ctx, id) } + +func (c *DatabaseClient) Describe(t *testing.T, id sdk.AccountObjectIdentifier) *sdk.DatabaseDetails { + t.Helper() + ctx := context.Background() + + details, err := c.client().Describe(ctx, id) + require.NoError(t, err) + + return details +} diff --git a/pkg/resources/database.go b/pkg/resources/database.go index 5044cb563d..43de091dd7 100644 --- a/pkg/resources/database.go +++ b/pkg/resources/database.go @@ -6,6 +6,9 @@ import ( "fmt" "slices" "strings" + "time" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/util" "github.com/hashicorp/go-cty/cty" @@ -22,6 +25,11 @@ var databaseSchema = map[string]*schema.Schema{ Required: true, Description: "Specifies the identifier for the database; must be unique for your account. As a best practice for [Database Replication and Failover](https://docs.snowflake.com/en/user-guide/db-replication-intro), it is recommended to give each secondary database the same name as its primary database. This practice supports referencing fully-qualified objects (i.e. '..') by other objects in the same database, such as querying a fully-qualified table name in a view. If a secondary database has a different name from the primary database, then these object references would break in the secondary database.", }, + "drop_public_schema_on_creation": { + Type: schema.TypeBool, + Optional: true, + Description: "Specifies whether to drop public schema on creation or not. Modifying the parameter after database is already created won't have any effect.", + }, "is_transient": { Type: schema.TypeBool, Optional: true, @@ -124,6 +132,24 @@ func CreateDatabase(ctx context.Context, d *schema.ResourceData, meta any) diag. var diags diag.Diagnostics + if d.Get("drop_public_schema_on_creation").(bool) { + var dropSchemaErrs []error + err := util.Retry(3, time.Second, func() (error, bool) { + if err := client.Schemas.Drop(ctx, sdk.NewDatabaseObjectIdentifier(id.Name(), "PUBLIC"), &sdk.DropSchemaOptions{IfExists: sdk.Bool(true)}); err != nil { + dropSchemaErrs = append(dropSchemaErrs, err) + return nil, false + } + return nil, true + }) + if err != nil { + diags = append(diags, diag.Diagnostic{ + Severity: diag.Warning, + Summary: "Failed to drop public schema on creation (failed after 3 attempts)", + Detail: fmt.Sprintf("The '%s' database was created successfully, but the provider was not able to remove public schema on creation. Please drop the public schema manually. Original errors: %s", id.Name(), errors.Join(dropSchemaErrs...)), + }) + } + } + if v, ok := d.GetOk("replication"); ok { replicationConfiguration := v.([]any)[0].(map[string]any) diff --git a/pkg/resources/database_acceptance_test.go b/pkg/resources/database_acceptance_test.go index d79e3d4797..8edeb50402 100644 --- a/pkg/resources/database_acceptance_test.go +++ b/pkg/resources/database_acceptance_test.go @@ -2,10 +2,12 @@ package resources_test import ( "fmt" - "regexp" + "slices" "strconv" "testing" + "github.com/hashicorp/terraform-plugin-testing/terraform" + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" r "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" tfjson "github.com/hashicorp/terraform-json" @@ -15,7 +17,6 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/importchecks" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/planchecks" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/snowflakechecks" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testenvs" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider/resources" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/hashicorp/terraform-plugin-testing/config" @@ -1160,233 +1161,232 @@ resource "snowflake_database" "test" { `, id.Name(), strconv.Quote(enableToAccount)) } -func TestAcc_Database_UpgradeFromShare(t *testing.T) { - _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) - +func TestAcc_Database_WithoutPublicSchema(t *testing.T) { id := acc.TestClient().Ids.RandomAccountObjectIdentifier() - secondaryClientLocator := acc.SecondaryClient(t).GetAccountLocator() - - shareExternalId := createShareableDatabase(t) resource.Test(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { acc.TestAccPreCheck(t) }, TerraformVersionChecks: []tfversion.TerraformVersionCheck{ tfversion.RequireAbove(tfversion.Version1_5_0), }, + CheckDestroy: acc.CheckDestroy(t, resources.Database), Steps: []resource.TestStep{ { - ExternalProviders: map[string]resource.ExternalProvider{ - "snowflake": { - VersionConstraint: "=0.92.0", - Source: "Snowflake-Labs/snowflake", - }, - }, - Config: databaseStateUpgraderFromShareOld(id, secondaryClientLocator, shareExternalId), + Config: databaseWithPublicSchemaConfig(id, false), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_database.test", "id", id.Name()), - resource.TestCheckResourceAttr("snowflake_database.test", "name", id.Name()), - resource.TestCheckResourceAttr("snowflake_database.test", "from_share.provider", secondaryClientLocator), - resource.TestCheckResourceAttr("snowflake_database.test", "from_share.share", shareExternalId.Name()), + doesNotContainPublicSchema(t, id), ), }, + // Change in parameter shouldn't change the state Snowflake { - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - Config: databaseStateUpgraderFromShareNewAfterUpgrade(id), - ExpectError: regexp.MustCompile("failed to upgrade the state with database created from share, please use snowflake_shared_database or deprecated snowflake_database_old instead"), - }, - { - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - Config: databaseStateUpgraderFromShareNew(id, shareExternalId), - ResourceName: "snowflake_shared_database.test", - ImportStateId: id.FullyQualifiedName(), - ImportState: true, + Config: databaseWithPublicSchemaConfig(id, true), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("snowflake_database.test", "id", id.Name()), + doesNotContainPublicSchema(t, id), + ), }, }, }) } -func databaseStateUpgraderFromShareOld(id sdk.AccountObjectIdentifier, secondaryClientLocator string, externalShare sdk.ExternalObjectIdentifier) string { - return fmt.Sprintf(` -resource "snowflake_database" "test" { - name = "%s" - data_retention_time_in_days = 0 # to avoid in-place update to -1 - from_share = { - provider = "%s" - share = "%s" - } -} -`, id.Name(), secondaryClientLocator, externalShare.Name()) -} - -func databaseStateUpgraderFromShareNewAfterUpgrade(id sdk.AccountObjectIdentifier) string { - return fmt.Sprintf(` -resource "snowflake_database" "test" { - name = "%s" - data_retention_time_in_days = 0 # to avoid in-place update to -1 -} -`, id.Name()) -} - -func databaseStateUpgraderFromShareNew(id sdk.AccountObjectIdentifier, externalShare sdk.ExternalObjectIdentifier) string { - return fmt.Sprintf(` -resource "snowflake_shared_database" "test" { - name = "%s" - from_share = %s -} -`, id.Name(), strconv.Quote(externalShare.FullyQualifiedName())) -} - -func TestAcc_Database_UpgradeFromReplica(t *testing.T) { - _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) - +func TestAcc_Database_WithPublicSchema(t *testing.T) { id := acc.TestClient().Ids.RandomAccountObjectIdentifier() - _, primaryDatabaseId, databaseCleanup := acc.SecondaryTestClient().Database.CreatePrimaryDatabase(t, []sdk.AccountIdentifier{ - acc.TestClient().Account.GetAccountIdentifier(t), - }) - t.Cleanup(databaseCleanup) resource.Test(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { acc.TestAccPreCheck(t) }, TerraformVersionChecks: []tfversion.TerraformVersionCheck{ tfversion.RequireAbove(tfversion.Version1_5_0), }, + CheckDestroy: acc.CheckDestroy(t, resources.Database), Steps: []resource.TestStep{ { - ExternalProviders: map[string]resource.ExternalProvider{ - "snowflake": { - VersionConstraint: "=0.92.0", - Source: "Snowflake-Labs/snowflake", - }, - }, - Config: databaseStateUpgraderFromReplicaOld(id, primaryDatabaseId), + Config: databaseWithPublicSchemaConfig(id, true), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_database.test", "id", id.Name()), - resource.TestCheckResourceAttr("snowflake_database.test", "name", id.Name()), - resource.TestCheckResourceAttr("snowflake_database.test", "from_replica", primaryDatabaseId.FullyQualifiedName()), + containsPublicSchema(t, id), ), }, + // Change in parameter shouldn't change the state Snowflake { - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - Config: databaseStateUpgraderFromReplicaNewAfterUpgrade(id), - ExpectError: regexp.MustCompile("failed to upgrade the state with database created from replica, please use snowflake_secondary_database or deprecated snowflake_database_old instead"), - }, - { - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - Config: databaseStateUpgraderFromReplicaNew(id, primaryDatabaseId), - ResourceName: "snowflake_secondary_database.test", - ImportStateId: id.FullyQualifiedName(), - ImportState: true, + Config: databaseWithPublicSchemaConfig(id, false), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("snowflake_database.test", "id", id.Name()), + containsPublicSchema(t, id), + ), }, }, }) } -func databaseStateUpgraderFromReplicaOld(id sdk.AccountObjectIdentifier, primaryDatabaseId sdk.ExternalObjectIdentifier) string { - return fmt.Sprintf(` -resource "snowflake_database" "test" { - name = "%s" - data_retention_time_in_days = 0 # to avoid in-place update to -1 - from_replica = %s +func doesNotContainPublicSchema(t *testing.T, id sdk.AccountObjectIdentifier) resource.TestCheckFunc { + t.Helper() + return func(state *terraform.State) error { + if slices.ContainsFunc(acc.TestClient().Database.Describe(t, id).Rows, func(row sdk.DatabaseDetailsRow) bool { return row.Name == "PUBLIC" && row.Kind == "SCHEMA" }) { + return fmt.Errorf("expected database %s to not contain public schema", id.FullyQualifiedName()) + } + return nil + } } -`, id.Name(), strconv.Quote(primaryDatabaseId.FullyQualifiedName())) + +func containsPublicSchema(t *testing.T, id sdk.AccountObjectIdentifier) resource.TestCheckFunc { + t.Helper() + return func(state *terraform.State) error { + if !slices.ContainsFunc(acc.TestClient().Database.Describe(t, id).Rows, func(row sdk.DatabaseDetailsRow) bool { return row.Name == "PUBLIC" && row.Kind == "SCHEMA" }) { + return fmt.Errorf("expected database %s to contain public schema", id.FullyQualifiedName()) + } + return nil + } } -func databaseStateUpgraderFromReplicaNewAfterUpgrade(id sdk.AccountObjectIdentifier) string { +func databaseWithPublicSchemaConfig(id sdk.AccountObjectIdentifier, withPublicSchema bool) string { return fmt.Sprintf(` resource "snowflake_database" "test" { name = "%s" - data_retention_time_in_days = 0 + drop_public_schema_on_creation = %s } -`, id.Name()) +`, id.Name(), strconv.FormatBool(!withPublicSchema)) } -func databaseStateUpgraderFromReplicaNew(id sdk.AccountObjectIdentifier, primaryDatabaseId sdk.ExternalObjectIdentifier) string { - return fmt.Sprintf(` -resource "snowflake_secondary_database" "test" { - name = "%s" - as_replica_of = %s +/* +Test database upgrade from share + +step: 1 +version: 0.92.0 +config: +resource "snowflake_share" "test" { + provider = snowflake.second_account + name = "test_share" + accounts = ["."] } -`, id.Name(), strconv.Quote(id.FullyQualifiedName())) + +resource "snowflake_database" "test" { + provider = snowflake.second_account + name = "test_database" } -func TestAcc_Database_UpgradeFromClonedDatabase(t *testing.T) { - id := acc.TestClient().Ids.RandomAccountObjectIdentifier() - cloneId := acc.TestClient().Ids.RandomAccountObjectIdentifier() +resource "snowflake_grant_privileges_to_share" "test" { + provider = snowflake.second_account + privileges = ["USAGE"] + on_database = snowflake_database.test.name + to_share = snowflake_share.test.name +} - resource.Test(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: acc.CheckDestroy(t, resources.Database), - Steps: []resource.TestStep{ - { - ExternalProviders: map[string]resource.ExternalProvider{ - "snowflake": { - VersionConstraint: "=0.92.0", - Source: "Snowflake-Labs/snowflake", - }, - }, - Config: databaseStateUpgraderFromDatabaseOld(id, cloneId), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_database.cloned", "id", cloneId.Name()), - resource.TestCheckResourceAttr("snowflake_database.cloned", "name", cloneId.Name()), - resource.TestCheckResourceAttr("snowflake_database.cloned", "from_database", id.Name()), - ), - }, - { - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - Config: databaseStateUpgraderFromDatabaseNewAfterUpgrade(id, cloneId), - ExpectError: regexp.MustCompile("failed to upgrade the state with database created from database, please use snowflake_database or deprecated snowflake_database_old instead"), - }, - { - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - Config: databaseStateUpgraderFromDatabaseNew(id, cloneId), - ResourceName: "snowflake_database.cloned", - ImportStateId: cloneId.FullyQualifiedName(), - ImportState: true, - }, - }, - }) +resource "snowflake_database" "from_share" { + depends_on = [ snowflake_grant_privileges_to_share.test ] + name = snowflake_database.test.name + from_share = { + provider = "" + share = snowflake_share.test.name + } } -func databaseStateUpgraderFromDatabaseOld(id sdk.AccountObjectIdentifier, secondId sdk.AccountObjectIdentifier) string { - return fmt.Sprintf(` -resource "snowflake_database" "test" { - name = "%s" +step: 2 +version: newest +expect error (after terraform plan): failed to upgrade the state with database created from share, please use snowflake_shared_database or deprecated snowflake_database_old instead + +step: 3 +version: newest +action: remove database from share from the state (terraform state rm) + +step: 4 +version: newest +action: +- modify database from share to look like this: +resource "snowflake_shared_database" "from_share" { + depends_on = [ snowflake_grant_privileges_to_share.test ] + name = snowflake_database.test.name + from_share = "\"\".\"\".\"${snowflake_share.test.name}\"" +} +- run terraform plan and validate if the state is empty +*/ + +/* +Test database upgrade from replica + +step: 1 +version: 0.92.0 +config: +resource "snowflake_database" "primary" { + provider = snowflake.second_account + name = "test" data_retention_time_in_days = 0 # to avoid in-place update to -1 + replication_configuration { + accounts = [""] + ignore_edition_check = true + } } -resource "snowflake_database" "cloned" { - name = "%s" +resource "snowflake_database" "secondary" { + name = "test" data_retention_time_in_days = 0 # to avoid in-place update to -1 - from_database = snowflake_database.test.name -} -`, id.Name(), secondId.Name()) + from_replica = ".\"${snowflake_database.primary.name}\"" } -func databaseStateUpgraderFromDatabaseNewAfterUpgrade(id sdk.AccountObjectIdentifier, secondId sdk.AccountObjectIdentifier) string { - return fmt.Sprintf(` -resource "snowflake_database" "test" { - name = "%s" - data_retention_time_in_days = 0 +step: 2 +version: newest +expect error (after terraform plan): failed to upgrade the state with database created from replica, please use snowflake_secondary_database or deprecated snowflake_database_old instead + +step: 3 +version: newest +action: remove secondary database from state (terraform state rm) + +step: 4 +version: newest +action: +- modify primary database to look like this: +resource "snowflake_database" "primary" { + provider = snowflake.second_account + name = "test" + data_retention_time_in_days = 0 # to avoid in-place update to -1 + replication { + enable_to_account { + account_identifier = "." + with_failover = true + } + ignore_edition_check = true + } } -resource "snowflake_database" "cloned" { - name = "%s" - data_retention_time_in_days = 0 -} -`, id.Name(), secondId.Name()) +- change secondary database config and run terraform import for secondary database (changed config under) +resource "snowflake_secondary_database" "secondary" { + name = "test" + data_retention_time_in_days = 0 # to avoid in-place update to -1 + from_replica = "\"\".\"\".\"${snowflake_database.primary.name}\"" } +- run terraform plan and validate if the state is empty +*/ -func databaseStateUpgraderFromDatabaseNew(id sdk.AccountObjectIdentifier, secondId sdk.AccountObjectIdentifier) string { - return fmt.Sprintf(` +/* +Test database upgrade from cloned database + +step: 1 +version: 0.92.0 +config: resource "snowflake_database" "test" { - name = "%s" + name = "test" + data_retention_time_in_days = 0 # to avoid in-place update to -1 } resource "snowflake_database" "cloned" { - name = "%s" -} -`, id.Name(), secondId.Name()) + name = "cloned" + from_database = snowflake_database.test.name + data_retention_time_in_days = 0 # to avoid in-place update to -1 } + +step: 2 +version: newest +expect error (after terraform plan): failed to upgrade the state with database created from database, please use snowflake_database or deprecated snowflake_database_old instead... + +step: 3 +version: newest +action: remove cloned database from state (terraform state rm) + +step: 4 +version: newest +action: +- import cloned database into state +- run terraform plan and validate if the state is empty +*/ From be1f9b8ad89c781e61c6fd1d316314f7c2407da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Tue, 6 Aug 2024 15:35:03 +0200 Subject: [PATCH 2/4] Update pkg/resources/database_acceptance_test.go Co-authored-by: Jakub Michalak --- pkg/resources/database_acceptance_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/resources/database_acceptance_test.go b/pkg/resources/database_acceptance_test.go index 8edeb50402..786344cc42 100644 --- a/pkg/resources/database_acceptance_test.go +++ b/pkg/resources/database_acceptance_test.go @@ -1241,7 +1241,7 @@ func containsPublicSchema(t *testing.T, id sdk.AccountObjectIdentifier) resource } } -func databaseWithPublicSchemaConfig(id sdk.AccountObjectIdentifier, withPublicSchema bool) string { +func databaseWithDropPublicSchemaConfig(id sdk.AccountObjectIdentifier, withDropPublicSchema bool) string { return fmt.Sprintf(` resource "snowflake_database" "test" { name = "%s" From 8e88ce022d660c4e9e615a2577330c57ea6d2df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Tue, 6 Aug 2024 15:39:53 +0200 Subject: [PATCH 3/4] changes after review --- pkg/resources/database.go | 7 ++++--- pkg/resources/database_acceptance_test.go | 20 +++++++++++++++----- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/pkg/resources/database.go b/pkg/resources/database.go index 43de091dd7..63eb9e8271 100644 --- a/pkg/resources/database.go +++ b/pkg/resources/database.go @@ -26,9 +26,10 @@ var databaseSchema = map[string]*schema.Schema{ Description: "Specifies the identifier for the database; must be unique for your account. As a best practice for [Database Replication and Failover](https://docs.snowflake.com/en/user-guide/db-replication-intro), it is recommended to give each secondary database the same name as its primary database. This practice supports referencing fully-qualified objects (i.e. '..') by other objects in the same database, such as querying a fully-qualified table name in a view. If a secondary database has a different name from the primary database, then these object references would break in the secondary database.", }, "drop_public_schema_on_creation": { - Type: schema.TypeBool, - Optional: true, - Description: "Specifies whether to drop public schema on creation or not. Modifying the parameter after database is already created won't have any effect.", + Type: schema.TypeBool, + Optional: true, + Description: "Specifies whether to drop public schema on creation or not. Modifying the parameter after database is already created won't have any effect.", + DiffSuppressFunc: IgnoreAfterCreation, }, "is_transient": { Type: schema.TypeBool, diff --git a/pkg/resources/database_acceptance_test.go b/pkg/resources/database_acceptance_test.go index 786344cc42..1ca54ab331 100644 --- a/pkg/resources/database_acceptance_test.go +++ b/pkg/resources/database_acceptance_test.go @@ -1173,7 +1173,7 @@ func TestAcc_Database_WithoutPublicSchema(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.Database), Steps: []resource.TestStep{ { - Config: databaseWithPublicSchemaConfig(id, false), + Config: databaseWithDropPublicSchemaConfig(id, true), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_database.test", "id", id.Name()), doesNotContainPublicSchema(t, id), @@ -1181,7 +1181,12 @@ func TestAcc_Database_WithoutPublicSchema(t *testing.T) { }, // Change in parameter shouldn't change the state Snowflake { - Config: databaseWithPublicSchemaConfig(id, true), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("snowflake_database.test", plancheck.ResourceActionNoop), + }, + }, + Config: databaseWithDropPublicSchemaConfig(id, false), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_database.test", "id", id.Name()), doesNotContainPublicSchema(t, id), @@ -1203,7 +1208,7 @@ func TestAcc_Database_WithPublicSchema(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.Database), Steps: []resource.TestStep{ { - Config: databaseWithPublicSchemaConfig(id, true), + Config: databaseWithDropPublicSchemaConfig(id, false), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_database.test", "id", id.Name()), containsPublicSchema(t, id), @@ -1211,7 +1216,12 @@ func TestAcc_Database_WithPublicSchema(t *testing.T) { }, // Change in parameter shouldn't change the state Snowflake { - Config: databaseWithPublicSchemaConfig(id, false), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("snowflake_database.test", plancheck.ResourceActionNoop), + }, + }, + Config: databaseWithDropPublicSchemaConfig(id, true), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_database.test", "id", id.Name()), containsPublicSchema(t, id), @@ -1247,7 +1257,7 @@ resource "snowflake_database" "test" { name = "%s" drop_public_schema_on_creation = %s } -`, id.Name(), strconv.FormatBool(!withPublicSchema)) +`, id.Name(), strconv.FormatBool(withDropPublicSchema)) } /* From 9f4dc3f1184c85d7ea00543eacf50ebf2f4aaffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Wed, 7 Aug 2024 16:02:54 +0200 Subject: [PATCH 4/4] changes after review --- pkg/acceptance/snowflakechecks/database.go | 21 +++ pkg/resources/database_acceptance_test.go | 172 +----------------- pkg/resources/manual_tests/README.md | 21 +++ .../upgrade_cloned_database/step_1.tf | 24 +++ .../upgrade_cloned_database/step_2.tf | 26 +++ .../upgrade_cloned_database/step_3.tf | 24 +++ .../upgrade_secondary_database/step_1.tf | 34 ++++ .../upgrade_secondary_database/step_2.tf | 36 ++++ .../upgrade_secondary_database/step_3.tf | 38 ++++ .../upgrade_shared_database/step_1.tf | 45 +++++ .../upgrade_shared_database/step_2.tf | 47 +++++ .../upgrade_shared_database/step_3.tf | 44 +++++ 12 files changed, 364 insertions(+), 168 deletions(-) create mode 100644 pkg/resources/manual_tests/README.md create mode 100644 pkg/resources/manual_tests/upgrade_cloned_database/step_1.tf create mode 100644 pkg/resources/manual_tests/upgrade_cloned_database/step_2.tf create mode 100644 pkg/resources/manual_tests/upgrade_cloned_database/step_3.tf create mode 100644 pkg/resources/manual_tests/upgrade_secondary_database/step_1.tf create mode 100644 pkg/resources/manual_tests/upgrade_secondary_database/step_2.tf create mode 100644 pkg/resources/manual_tests/upgrade_secondary_database/step_3.tf create mode 100644 pkg/resources/manual_tests/upgrade_shared_database/step_1.tf create mode 100644 pkg/resources/manual_tests/upgrade_shared_database/step_2.tf create mode 100644 pkg/resources/manual_tests/upgrade_shared_database/step_3.tf diff --git a/pkg/acceptance/snowflakechecks/database.go b/pkg/acceptance/snowflakechecks/database.go index f3630aa2e1..d43601fa66 100644 --- a/pkg/acceptance/snowflakechecks/database.go +++ b/pkg/acceptance/snowflakechecks/database.go @@ -3,6 +3,7 @@ package snowflakechecks import ( "errors" "fmt" + "slices" "testing" acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" @@ -26,3 +27,23 @@ func CheckDatabaseDataRetentionTimeInDays(t *testing.T, databaseId sdk.AccountOb return errors.Join(errs...) } } + +func DoesNotContainPublicSchema(t *testing.T, id sdk.AccountObjectIdentifier) resource.TestCheckFunc { + t.Helper() + return func(state *terraform.State) error { + if slices.ContainsFunc(acc.TestClient().Database.Describe(t, id).Rows, func(row sdk.DatabaseDetailsRow) bool { return row.Name == "PUBLIC" && row.Kind == "SCHEMA" }) { + return fmt.Errorf("expected database %s to not contain public schema", id.FullyQualifiedName()) + } + return nil + } +} + +func ContainsPublicSchema(t *testing.T, id sdk.AccountObjectIdentifier) resource.TestCheckFunc { + t.Helper() + return func(state *terraform.State) error { + if !slices.ContainsFunc(acc.TestClient().Database.Describe(t, id).Rows, func(row sdk.DatabaseDetailsRow) bool { return row.Name == "PUBLIC" && row.Kind == "SCHEMA" }) { + return fmt.Errorf("expected database %s to contain public schema", id.FullyQualifiedName()) + } + return nil + } +} diff --git a/pkg/resources/database_acceptance_test.go b/pkg/resources/database_acceptance_test.go index 1ca54ab331..eed0d2691b 100644 --- a/pkg/resources/database_acceptance_test.go +++ b/pkg/resources/database_acceptance_test.go @@ -2,12 +2,9 @@ package resources_test import ( "fmt" - "slices" "strconv" "testing" - "github.com/hashicorp/terraform-plugin-testing/terraform" - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" r "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" tfjson "github.com/hashicorp/terraform-json" @@ -1176,7 +1173,7 @@ func TestAcc_Database_WithoutPublicSchema(t *testing.T) { Config: databaseWithDropPublicSchemaConfig(id, true), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_database.test", "id", id.Name()), - doesNotContainPublicSchema(t, id), + snowflakechecks.DoesNotContainPublicSchema(t, id), ), }, // Change in parameter shouldn't change the state Snowflake @@ -1189,7 +1186,7 @@ func TestAcc_Database_WithoutPublicSchema(t *testing.T) { Config: databaseWithDropPublicSchemaConfig(id, false), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_database.test", "id", id.Name()), - doesNotContainPublicSchema(t, id), + snowflakechecks.DoesNotContainPublicSchema(t, id), ), }, }, @@ -1211,7 +1208,7 @@ func TestAcc_Database_WithPublicSchema(t *testing.T) { Config: databaseWithDropPublicSchemaConfig(id, false), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_database.test", "id", id.Name()), - containsPublicSchema(t, id), + snowflakechecks.ContainsPublicSchema(t, id), ), }, // Change in parameter shouldn't change the state Snowflake @@ -1224,33 +1221,13 @@ func TestAcc_Database_WithPublicSchema(t *testing.T) { Config: databaseWithDropPublicSchemaConfig(id, true), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_database.test", "id", id.Name()), - containsPublicSchema(t, id), + snowflakechecks.ContainsPublicSchema(t, id), ), }, }, }) } -func doesNotContainPublicSchema(t *testing.T, id sdk.AccountObjectIdentifier) resource.TestCheckFunc { - t.Helper() - return func(state *terraform.State) error { - if slices.ContainsFunc(acc.TestClient().Database.Describe(t, id).Rows, func(row sdk.DatabaseDetailsRow) bool { return row.Name == "PUBLIC" && row.Kind == "SCHEMA" }) { - return fmt.Errorf("expected database %s to not contain public schema", id.FullyQualifiedName()) - } - return nil - } -} - -func containsPublicSchema(t *testing.T, id sdk.AccountObjectIdentifier) resource.TestCheckFunc { - t.Helper() - return func(state *terraform.State) error { - if !slices.ContainsFunc(acc.TestClient().Database.Describe(t, id).Rows, func(row sdk.DatabaseDetailsRow) bool { return row.Name == "PUBLIC" && row.Kind == "SCHEMA" }) { - return fmt.Errorf("expected database %s to contain public schema", id.FullyQualifiedName()) - } - return nil - } -} - func databaseWithDropPublicSchemaConfig(id sdk.AccountObjectIdentifier, withDropPublicSchema bool) string { return fmt.Sprintf(` resource "snowflake_database" "test" { @@ -1259,144 +1236,3 @@ resource "snowflake_database" "test" { } `, id.Name(), strconv.FormatBool(withDropPublicSchema)) } - -/* -Test database upgrade from share - -step: 1 -version: 0.92.0 -config: -resource "snowflake_share" "test" { - provider = snowflake.second_account - name = "test_share" - accounts = ["."] -} - -resource "snowflake_database" "test" { - provider = snowflake.second_account - name = "test_database" -} - -resource "snowflake_grant_privileges_to_share" "test" { - provider = snowflake.second_account - privileges = ["USAGE"] - on_database = snowflake_database.test.name - to_share = snowflake_share.test.name -} - -resource "snowflake_database" "from_share" { - depends_on = [ snowflake_grant_privileges_to_share.test ] - name = snowflake_database.test.name - from_share = { - provider = "" - share = snowflake_share.test.name - } -} - -step: 2 -version: newest -expect error (after terraform plan): failed to upgrade the state with database created from share, please use snowflake_shared_database or deprecated snowflake_database_old instead - -step: 3 -version: newest -action: remove database from share from the state (terraform state rm) - -step: 4 -version: newest -action: -- modify database from share to look like this: -resource "snowflake_shared_database" "from_share" { - depends_on = [ snowflake_grant_privileges_to_share.test ] - name = snowflake_database.test.name - from_share = "\"\".\"\".\"${snowflake_share.test.name}\"" -} -- run terraform plan and validate if the state is empty -*/ - -/* -Test database upgrade from replica - -step: 1 -version: 0.92.0 -config: -resource "snowflake_database" "primary" { - provider = snowflake.second_account - name = "test" - data_retention_time_in_days = 0 # to avoid in-place update to -1 - replication_configuration { - accounts = [""] - ignore_edition_check = true - } -} - -resource "snowflake_database" "secondary" { - name = "test" - data_retention_time_in_days = 0 # to avoid in-place update to -1 - from_replica = ".\"${snowflake_database.primary.name}\"" -} - -step: 2 -version: newest -expect error (after terraform plan): failed to upgrade the state with database created from replica, please use snowflake_secondary_database or deprecated snowflake_database_old instead - -step: 3 -version: newest -action: remove secondary database from state (terraform state rm) - -step: 4 -version: newest -action: -- modify primary database to look like this: -resource "snowflake_database" "primary" { - provider = snowflake.second_account - name = "test" - data_retention_time_in_days = 0 # to avoid in-place update to -1 - replication { - enable_to_account { - account_identifier = "." - with_failover = true - } - ignore_edition_check = true - } -} - -- change secondary database config and run terraform import for secondary database (changed config under) -resource "snowflake_secondary_database" "secondary" { - name = "test" - data_retention_time_in_days = 0 # to avoid in-place update to -1 - from_replica = "\"\".\"\".\"${snowflake_database.primary.name}\"" -} -- run terraform plan and validate if the state is empty -*/ - -/* -Test database upgrade from cloned database - -step: 1 -version: 0.92.0 -config: -resource "snowflake_database" "test" { - name = "test" - data_retention_time_in_days = 0 # to avoid in-place update to -1 -} - -resource "snowflake_database" "cloned" { - name = "cloned" - from_database = snowflake_database.test.name - data_retention_time_in_days = 0 # to avoid in-place update to -1 -} - -step: 2 -version: newest -expect error (after terraform plan): failed to upgrade the state with database created from database, please use snowflake_database or deprecated snowflake_database_old instead... - -step: 3 -version: newest -action: remove cloned database from state (terraform state rm) - -step: 4 -version: newest -action: -- import cloned database into state -- run terraform plan and validate if the state is empty -*/ diff --git a/pkg/resources/manual_tests/README.md b/pkg/resources/manual_tests/README.md new file mode 100644 index 0000000000..f9a06a475f --- /dev/null +++ b/pkg/resources/manual_tests/README.md @@ -0,0 +1,21 @@ +# Manual tests + +This directory is dedicated to hold steps for manual tests that are not possible to re-recreate in automated acceptance tests. +The main limitations come from using [terraform-plugin-testing](https://github.com/hashicorp/terraform-plugin-testing) which is +not supporting every action you are able to perform with Terraform CLI. + +Here's the list of cases we currently cannot reproduce and write acceptance tests for: +- When upgrading from version to version we need to remove the state of the deprecated object (terraform state rm) and import a new type representing the same object (terraform import) + - Specifically, `terraform state rm` is not possible. As an example we can have `snowflake_database` in version 0.92.0 which in version 0.93.0 could be represented as e.g. `snowflake_shared_database`. To fully test such upgrade path, it has to be done manually. + - Currently tests under this category: + - `upgrade_cloned_database` + - `upgrade_secondary_database` + - `upgrade_shared_database` + +## How to use manual tests +- Choose the test you want to run and go into the test folder. +- Take the first step from that test copy it into a separate folder (outside the project) to initialize terraform and start the first step. + - The tests contain provider configuration, but you have to make sure you have compliant configuration in your `~/snowflake/config` file. + - Please mind which commands should be run to perform a given test step correctly (instructions are at the top of the file; run after project is initialized). + - Also, please mind `TODO: Replace` comments that indicate lines where configuration should be changed before running any test command. +- To proceed with the test, take the content of the next test step file and replace the previous one (with the same rules as above). \ No newline at end of file diff --git a/pkg/resources/manual_tests/upgrade_cloned_database/step_1.tf b/pkg/resources/manual_tests/upgrade_cloned_database/step_1.tf new file mode 100644 index 0000000000..fc29a277dd --- /dev/null +++ b/pkg/resources/manual_tests/upgrade_cloned_database/step_1.tf @@ -0,0 +1,24 @@ +# Commands to run +# - terraform apply + +terraform { + required_providers { + snowflake = { + source = "Snowflake-Labs/snowflake" + version = "0.92.0" + } + } +} + +provider "snowflake" {} + +resource "snowflake_database" "test" { + name = "test" + data_retention_time_in_days = 0 # to avoid in-place update to -1 +} + +resource "snowflake_database" "cloned" { + name = "cloned" + from_database = snowflake_database.test.name + data_retention_time_in_days = 0 # to avoid in-place update to -1 +} diff --git a/pkg/resources/manual_tests/upgrade_cloned_database/step_2.tf b/pkg/resources/manual_tests/upgrade_cloned_database/step_2.tf new file mode 100644 index 0000000000..f6446ce3a2 --- /dev/null +++ b/pkg/resources/manual_tests/upgrade_cloned_database/step_2.tf @@ -0,0 +1,26 @@ +# Commands to run +# - terraform init - upgrade +# - terraform plan (should observe upgrader errors similar to: failed to upgrade the state with database created from database, please use snowflake_database or deprecated snowflake_database_old instead...) +# - terraform state rm snowflake_database.cloned (remove cloned database from the state) + +terraform { + required_providers { + snowflake = { + source = "Snowflake-Labs/snowflake" + version = ">= 0.92.0" # latest + } + } +} + +provider "snowflake" {} + +resource "snowflake_database" "test" { + name = "test" + data_retention_time_in_days = 0 # to avoid in-place update to -1 +} + +resource "snowflake_database" "cloned" { + name = "cloned" + from_database = snowflake_database.test.name + data_retention_time_in_days = 0 # to avoid in-place update to -1 +} diff --git a/pkg/resources/manual_tests/upgrade_cloned_database/step_3.tf b/pkg/resources/manual_tests/upgrade_cloned_database/step_3.tf new file mode 100644 index 0000000000..1fa465dcc4 --- /dev/null +++ b/pkg/resources/manual_tests/upgrade_cloned_database/step_3.tf @@ -0,0 +1,24 @@ +# Commands to run +# - terraform import snowflake__database.cloned '"cloned"' (import cloned database into state) +# - terraform plan (expect empty plan) + +terraform { + required_providers { + snowflake = { + source = "Snowflake-Labs/snowflake" + version = ">= 0.92.0" # latest + } + } +} + +provider "snowflake" {} + +resource "snowflake_database" "test" { + name = "test" + data_retention_time_in_days = 0 # to avoid in-place update to -1 +} + +resource "snowflake_database" "cloned" { + name = "cloned" + data_retention_time_in_days = 0 # to avoid in-place update to -1 +} diff --git a/pkg/resources/manual_tests/upgrade_secondary_database/step_1.tf b/pkg/resources/manual_tests/upgrade_secondary_database/step_1.tf new file mode 100644 index 0000000000..268b636c8a --- /dev/null +++ b/pkg/resources/manual_tests/upgrade_secondary_database/step_1.tf @@ -0,0 +1,34 @@ +# Commands to run +# - terraform apply + +terraform { + required_providers { + snowflake = { + source = "Snowflake-Labs/snowflake" + version = "0.92.0" + } + } +} + +provider "snowflake" {} + +provider "snowflake" { + profile = "secondary_test_account" + alias = second_account +} + +resource "snowflake_database" "primary" { + provider = snowflake.second_account + name = "test" + data_retention_time_in_days = 0 # to avoid in-place update to -1 + replication_configuration { + accounts = [""] # TODO: Replace + ignore_edition_check = true + } +} + +resource "snowflake_database" "secondary" { + name = "test" + data_retention_time_in_days = 0 # to avoid in-place update to -1 + from_replica = ".\"${snowflake_database.primary.name}\"" # TODO: Replace +} diff --git a/pkg/resources/manual_tests/upgrade_secondary_database/step_2.tf b/pkg/resources/manual_tests/upgrade_secondary_database/step_2.tf new file mode 100644 index 0000000000..599e971a51 --- /dev/null +++ b/pkg/resources/manual_tests/upgrade_secondary_database/step_2.tf @@ -0,0 +1,36 @@ +# Commands to run +# - terraform init - upgrade +# - terraform plan (should observe upgrader errors similar to: failed to upgrade the state with database created from replica, please use snowflake_secondary_database or deprecated snowflake_database_old instead) +# - terraform state rm snowflake_database.secondary (remove secondary database from the state) + +terraform { + required_providers { + snowflake = { + source = "Snowflake-Labs/snowflake" + version = ">= 0.92.0" # latest + } + } +} + +provider "snowflake" {} + +provider "snowflake" { + profile = "secondary_test_account" + alias = second_account +} + +resource "snowflake_database" "primary" { + provider = snowflake.second_account + name = "test" + data_retention_time_in_days = 0 # to avoid in-place update to -1 + replication_configuration { + accounts = [""] # TODO: Replace + ignore_edition_check = true + } +} + +resource "snowflake_database" "secondary" { + name = "test" + data_retention_time_in_days = 0 # to avoid in-place update to -1 + from_replica = ".\"${snowflake_database.primary.name}\"" # TODO: Replace +} diff --git a/pkg/resources/manual_tests/upgrade_secondary_database/step_3.tf b/pkg/resources/manual_tests/upgrade_secondary_database/step_3.tf new file mode 100644 index 0000000000..d112fe2927 --- /dev/null +++ b/pkg/resources/manual_tests/upgrade_secondary_database/step_3.tf @@ -0,0 +1,38 @@ +# Commands to run +# - terraform import snowflake_secondary_database.secondary '"test"' (import secondary database into state) +# - terraform plan (expect empty plan) + +terraform { + required_providers { + snowflake = { + source = "Snowflake-Labs/snowflake" + version = ">= 0.92.0" # latest + } + } +} + +provider "snowflake" {} + +provider "snowflake" { + profile = "secondary_test_account" + alias = second_account +} + +resource "snowflake_database" "primary" { + provider = snowflake.second_account + name = "test" + data_retention_time_in_days = 0 # to avoid in-place update to -1 + replication { + enable_to_account { + account_identifier = "." # TODO: Replace + with_failover = true + } + ignore_edition_check = true + } +} + +resource "snowflake_secondary_database" "secondary" { + name = "test" + data_retention_time_in_days = 0 # to avoid in-place update to -1 + from_replica = "\"\".\"\".\"${snowflake_database.primary.name}\"" # TODO: Replace +} diff --git a/pkg/resources/manual_tests/upgrade_shared_database/step_1.tf b/pkg/resources/manual_tests/upgrade_shared_database/step_1.tf new file mode 100644 index 0000000000..f6a9bac28b --- /dev/null +++ b/pkg/resources/manual_tests/upgrade_shared_database/step_1.tf @@ -0,0 +1,45 @@ +# Commands to run +# - terraform apply + +terraform { + required_providers { + snowflake = { + source = "Snowflake-Labs/snowflake" + version = "0.92.0" + } + } +} + +provider "snowflake" {} + +provider "snowflake" { + profile = "secondary_test_account" + alias = second_account +} + +resource "snowflake_share" "test" { + provider = snowflake.second_account + name = "test_share" + accounts = ["."] # TODO: Replace +} + +resource "snowflake_database" "test" { + provider = snowflake.second_account + name = "test_database" +} + +resource "snowflake_grant_privileges_to_share" "test" { + provider = snowflake.second_account + privileges = ["USAGE"] + on_database = snowflake_database.test.name + to_share = snowflake_share.test.name +} + +resource "snowflake_database" "from_share" { + depends_on = [ snowflake_grant_privileges_to_share.test ] + name = snowflake_database.test.name + from_share = { + provider = "" # TODO: Replace + share = snowflake_share.test.name + } +} diff --git a/pkg/resources/manual_tests/upgrade_shared_database/step_2.tf b/pkg/resources/manual_tests/upgrade_shared_database/step_2.tf new file mode 100644 index 0000000000..ed8bce3132 --- /dev/null +++ b/pkg/resources/manual_tests/upgrade_shared_database/step_2.tf @@ -0,0 +1,47 @@ +# Commands to run +# - terraform init - upgrade +# - terraform plan (should observe upgrader errors similar to: failed to upgrade the state with database created from share, please use snowflake_shared_database or deprecated snowflake_database_old instead) +# - terraform state rm snowflake_database.from_share (remove shared database from the state) + +terraform { + required_providers { + snowflake = { + source = "Snowflake-Labs/snowflake" + version = ">= 0.92.0" # latest + } + } +} + +provider "snowflake" {} + +provider "snowflake" { + profile = "secondary_test_account" + alias = second_account +} + +resource "snowflake_share" "test" { + provider = snowflake.second_account + name = "test_share" + accounts = ["."] # TODO: Replace +} + +resource "snowflake_database" "test" { + provider = snowflake.second_account + name = "test_database" +} + +resource "snowflake_grant_privileges_to_share" "test" { + provider = snowflake.second_account + privileges = ["USAGE"] + on_database = snowflake_database.test.name + to_share = snowflake_share.test.name +} + +resource "snowflake_database" "from_share" { + depends_on = [ snowflake_grant_privileges_to_share.test ] + name = snowflake_database.test.name + from_share = { + provider = "" # TODO: Replace + share = snowflake_share.test.name + } +} diff --git a/pkg/resources/manual_tests/upgrade_shared_database/step_3.tf b/pkg/resources/manual_tests/upgrade_shared_database/step_3.tf new file mode 100644 index 0000000000..af4bee02e3 --- /dev/null +++ b/pkg/resources/manual_tests/upgrade_shared_database/step_3.tf @@ -0,0 +1,44 @@ +# Commands to run +# - terraform import snowflake_shared_database.from_share '"test_database"' (import shared database into state) +# - terraform plan (expect empty plan) + +terraform { + required_providers { + snowflake = { + source = "Snowflake-Labs/snowflake" + version = ">= 0.92.0" # latest + } + } +} + +provider "snowflake" {} + +provider "snowflake" { + profile = "secondary_test_account" + alias = second_account +} + +resource "snowflake_share" "test" { + provider = snowflake.second_account + name = "test_share" + accounts = ["."] # TODO: Replace +} + +resource "snowflake_database" "test" { + provider = snowflake.second_account + name = "test_database" +} + +resource "snowflake_grant_privileges_to_share" "test" { + provider = snowflake.second_account + privileges = ["USAGE"] + on_database = snowflake_database.test.name + to_share = snowflake_share.test.name +} + +# Changed old snowflake_database to the new snowflake_shared_database counter-part +resource "snowflake_shared_database" "from_share" { + depends_on = [ snowflake_grant_privileges_to_share.test ] + name = snowflake_database.test.name + from_share = "\"\".\"\".\"${snowflake_share.test.name}\"" # TODO: Replace +}