From 713b060ad04d8b88b12e02ab818b5588d673f3eb Mon Sep 17 00:00:00 2001 From: Jakub Michalak Date: Mon, 12 Aug 2024 16:18:29 +0200 Subject: [PATCH] Add fully_qualified_name field for remaining resources --- MIGRATION_GUIDE.md | 25 +++- pkg/resources/account.go | 11 ++ pkg/resources/account_acceptance_test.go | 9 +- pkg/resources/account_role.go | 11 +- pkg/resources/account_role_acceptance_test.go | 3 + pkg/resources/alert.go | 10 +- pkg/resources/alert_acceptance_test.go | 25 ++-- .../api_authentication_integration_common.go | 5 + ...tegration_with_authorization_code_grant.go | 2 +- ...uthorization_code_grant_acceptance_test.go | 1 + ...ion_integration_with_client_credentials.go | 2 +- ...with_client_credentials_acceptance_test.go | 1 + ...hentication_integration_with_jwt_bearer.go | 2 +- ...gration_with_jwt_bearer_acceptance_test.go | 1 + pkg/resources/api_integration.go | 6 + .../api_integration_acceptance_test.go | 12 +- pkg/resources/cortex_search_service.go | 5 + .../cortex_search_service_acceptance_test.go | 2 + pkg/resources/database.go | 12 +- pkg/resources/database_acceptance_test.go | 1 + pkg/resources/database_role.go | 12 +- .../database_role_acceptance_test.go | 12 +- pkg/resources/doc_helpers.go | 12 ++ pkg/resources/dynamic_table.go | 5 + .../dynamic_table_acceptance_test.go | 12 +- .../email_notification_integration.go | 6 + ...otification_integration_acceptance_test.go | 7 +- pkg/resources/external_function.go | 5 + .../external_function_acceptance_test.go | 11 +- pkg/resources/external_oauth_integration.go | 4 + ...ernal_oauth_integration_acceptance_test.go | 1 + .../external_stage_acceptance_test.go | 7 +- pkg/resources/external_table.go | 8 +- .../external_table_acceptance_test.go | 1 + pkg/resources/failover_group.go | 6 + .../failover_group_acceptance_test.go | 7 +- pkg/resources/file_format.go | 11 ++ pkg/resources/file_format_acceptance_test.go | 14 +- pkg/resources/function.go | 10 ++ pkg/resources/function_acceptance_test.go | 14 +- .../internal_stage_acceptance_test.go | 7 +- pkg/resources/managed_account.go | 10 +- .../managed_account_acceptance_test.go | 7 +- pkg/resources/masking_policy.go | 44 ++++-- .../masking_policy_acceptance_test.go | 58 ++++++-- .../masking_policy_state_upgraders.go | 16 +++ pkg/resources/materialized_view.go | 13 +- .../materialized_view_acceptance_test.go | 2 + pkg/resources/network_policy.go | 5 + .../network_policy_acceptance_test.go | 2 + pkg/resources/network_rule.go | 20 ++- pkg/resources/network_rule_acceptance_test.go | 37 +++++ pkg/resources/network_rule_state_upgraders.go | 16 +++ pkg/resources/notification_integration.go | 6 +- ...otification_integration_acceptance_test.go | 12 +- .../oauth_integration_for_custom_clients.go | 5 +- ...tion_for_custom_clients_acceptance_test.go | 2 + ...th_integration_for_partner_applications.go | 5 +- ...or_partner_applications_acceptance_test.go | 2 + pkg/resources/password_policy.go | 44 +++--- .../password_policy_acceptance_test.go | 64 ++++++++- .../password_policy_state_upgraders.go | 16 +++ pkg/resources/pipe.go | 10 +- pkg/resources/pipe_acceptance_test.go | 7 +- pkg/resources/procedure.go | 10 ++ pkg/resources/procedure_acceptance_test.go | 14 +- pkg/resources/resource_monitor.go | 9 +- .../resource_monitor_acceptance_test.go | 17 ++- pkg/resources/row_access_policy.go | 5 + .../row_access_policy_acceptance_test.go | 13 +- pkg/resources/saml2_integration.go | 4 + .../saml2_integration_acceptance_test.go | 2 + pkg/resources/schema.go | 5 + pkg/resources/schema_acceptance_test.go | 14 +- pkg/resources/scim_integration.go | 4 + .../scim_integration_acceptance_test.go | 2 + pkg/resources/secondary_database.go | 13 +- .../secondary_database_acceptance_test.go | 2 + pkg/resources/sequence.go | 9 +- pkg/resources/sequence_acceptance_test.go | 22 +-- pkg/resources/share.go | 5 + pkg/resources/share_acceptance_test.go | 13 +- pkg/resources/shared_database.go | 10 ++ .../shared_database_acceptance_test.go | 1 + pkg/resources/special_values.go | 12 -- pkg/resources/stage.go | 7 +- pkg/resources/stage_acceptance_test.go | 17 ++- pkg/resources/storage_integration.go | 5 + .../storage_integration_acceptance_test.go | 13 +- pkg/resources/stream.go | 5 + pkg/resources/stream_acceptance_test.go | 12 +- pkg/resources/table.go | 37 +++-- pkg/resources/table_acceptance_test.go | 133 ++++++++++++------ pkg/resources/table_state_upgraders.go | 16 +++ pkg/resources/tag.go | 5 + pkg/resources/tag_acceptance_test.go | 13 +- pkg/resources/task.go | 5 + pkg/resources/task_acceptance_test.go | 12 ++ pkg/resources/user.go | 5 + pkg/resources/user_acceptance_test.go | 5 + pkg/resources/view.go | 12 +- pkg/resources/view_acceptance_test.go | 4 + pkg/resources/warehouse.go | 6 +- pkg/resources/warehouse_acceptance_test.go | 3 + 104 files changed, 940 insertions(+), 282 deletions(-) create mode 100644 pkg/resources/masking_policy_state_upgraders.go create mode 100644 pkg/resources/network_rule_state_upgraders.go create mode 100644 pkg/resources/password_policy_state_upgraders.go create mode 100644 pkg/resources/table_state_upgraders.go diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 3b17f255327..e26793fb42d 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -6,8 +6,8 @@ across different versions. ## v0.94.x ➞ v0.95.0 -### New `fully_qualified_name` field in all resources. -We added a new `fully_qualified_name` to all resources. This should help with referencing other resources in fields that expect a fully qualified name. For example, instead of +### New `fully_qualified_name` field in the resources. +We added a new `fully_qualified_name` to snowflake resources. This should help with referencing other resources in fields that expect a fully qualified name. For example, instead of writing ```object_name = “\”${snowflake_table.database}\”.\”${snowflake_table.schema}\”.\”${snowflake_table.name}\””``` @@ -16,6 +16,27 @@ writing ```object_name = snowflake_table.fully_qualified_name``` +Some of the resources are excluded from this change: +- deprecated resources + - `snowflake_database_old` + - `snowflake_oauth_integration` + - `snowflake_saml_integration` +- resources for which fully qualified name is not appropriate + - `snowflake_account_parameter` + - `snowflake_account_password_policy_attachment` + - `snowflake_network_policy_attachment` + - `snowflake_session_parameter` + - `snowflake_table_constraint` + - `snowflake_table_column_masking_policy_application` + - `snowflake_tag_masking_policy_association` + - `snowflake_tag_association` + - `snowflake_user_password_policy_attachment` + - `snowflake_user_public_keys` + - grant resources + +#### *(breaking change)* removed `qualified_name` from `snowflake_masking_policy`, `snowflake_network_rule`, `snowflake_password_policy` and `snowflake_table` +Because of introducing a new field for all of the resources, `qualified_name` was removed from `snowflake_masking_policy`, `snowflake_network_rule`, `snowflake_password_policy` and `snowflake_table`. State is automatically migrated. + ### snowflake_user resource changes #### *(breaking change)* user parameters added to snowflake_user resource diff --git a/pkg/resources/account.go b/pkg/resources/account.go index 57791e88ac2..2f41737bdd4 100644 --- a/pkg/resources/account.go +++ b/pkg/resources/account.go @@ -9,7 +9,9 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/util" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) @@ -202,6 +204,7 @@ var accountSchema = map[string]*schema.Schema{ Default: 3, Description: "Specifies the number of days to wait before dropping the account. The default is 3 days.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func Account() *schema.Resource { @@ -212,6 +215,10 @@ func Account() *schema.Resource { Update: UpdateAccount, Delete: DeleteAccount, + CustomizeDiff: customdiff.All( + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), + ), + Schema: accountSchema, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, @@ -324,6 +331,10 @@ func ReadAccount(d *schema.ResourceData, meta interface{}) error { return err } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } + if err = d.Set("name", acc.AccountName); err != nil { return fmt.Errorf("error setting name: %w", err) } diff --git a/pkg/resources/account_acceptance_test.go b/pkg/resources/account_acceptance_test.go index 0ec9cb8842a..ceb1a5df643 100644 --- a/pkg/resources/account_acceptance_test.go +++ b/pkg/resources/account_acceptance_test.go @@ -15,7 +15,7 @@ import ( func TestAcc_Account_complete(t *testing.T) { _ = testenvs.GetOrSkipTest(t, testenvs.TestAccountCreate) - accountName := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() password := acc.TestClient().Ids.AlphaContaining("123ABC") resource.Test(t, resource.TestCase{ @@ -29,9 +29,10 @@ func TestAcc_Account_complete(t *testing.T) { // unless we change the resource to return nil on destroy then this is unavoidable Steps: []resource.TestStep{ { - Config: accountConfig(accountName, password, "Terraform acceptance test", 3), + Config: accountConfig(id.Name(), password, "Terraform acceptance test", 3), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_account.test", "name", accountName), + resource.TestCheckResourceAttr("snowflake_account.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_account.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_account.test", "admin_name", "someadmin"), resource.TestCheckResourceAttr("snowflake_account.test", "first_name", "Ad"), resource.TestCheckResourceAttr("snowflake_account.test", "last_name", "Min"), @@ -45,7 +46,7 @@ func TestAcc_Account_complete(t *testing.T) { }, // Change Grace Period In Days { - Config: accountConfig(accountName, password, "Terraform acceptance test", 4), + Config: accountConfig(id.Name(), password, "Terraform acceptance test", 4), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_account.test", "grace_period_in_days", "4"), ), diff --git a/pkg/resources/account_role.go b/pkg/resources/account_role.go index 25f87ebf018..0626082501f 100644 --- a/pkg/resources/account_role.go +++ b/pkg/resources/account_role.go @@ -11,6 +11,7 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -33,6 +34,7 @@ var accountRoleSchema = map[string]*schema.Schema{ Schema: schemas.ShowRoleSchema, }, }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func AccountRole() *schema.Resource { @@ -45,7 +47,10 @@ func AccountRole() *schema.Resource { UpdateContext: UpdateAccountRole, Description: "The resource is used for role management, where roles can be assigned privileges and, in turn, granted to users and other roles. When granted to roles they can create hierarchies of privilege structures. For more details, refer to the [official documentation](https://docs.snowflake.com/en/user-guide/security-access-control-overview).", - CustomizeDiff: ComputedIfAnyAttributeChanged(ShowOutputAttributeName, "name", "comment"), + CustomizeDiff: customdiff.All( + ComputedIfAnyAttributeChanged(ShowOutputAttributeName, "name", "comment"), + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), + ), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, @@ -104,6 +109,10 @@ func ReadAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag } } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } + if err := d.Set("name", sdk.NewAccountObjectIdentifier(accountRole.Name).Name()); err != nil { return diag.Diagnostics{ diag.Diagnostic{ diff --git a/pkg/resources/account_role_acceptance_test.go b/pkg/resources/account_role_acceptance_test.go index 8a0dcf6800e..9b24568b96b 100644 --- a/pkg/resources/account_role_acceptance_test.go +++ b/pkg/resources/account_role_acceptance_test.go @@ -148,6 +148,7 @@ func TestAcc_AccountRole_Complete(t *testing.T) { Config: accountRoleBasicConfig(id.Name(), comment), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("snowflake_account_role.role", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_account_role.role", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_account_role.role", "comment", comment), resource.TestCheckResourceAttr("snowflake_account_role.role", "show_output.#", "1"), @@ -169,6 +170,7 @@ func TestAcc_AccountRole_Complete(t *testing.T) { ImportState: true, ImportStateCheck: importchecks.ComposeAggregateImportStateCheck( importchecks.TestCheckResourceAttrInstanceState(id.Name(), "name", id.Name()), + importchecks.TestCheckResourceAttrInstanceState(id.Name(), "fully_qualified_name", id.FullyQualifiedName()), importchecks.TestCheckResourceAttrInstanceState(id.Name(), "comment", comment), ), }, @@ -177,6 +179,7 @@ func TestAcc_AccountRole_Complete(t *testing.T) { Config: accountRoleBasicConfig(newId.Name(), newComment), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("snowflake_account_role.role", "name", newId.Name()), + resource.TestCheckResourceAttr("snowflake_account_role.role", "fully_qualified_name", newId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_account_role.role", "comment", newComment), resource.TestCheckResourceAttr("snowflake_account_role.role", "show_output.#", "1"), diff --git a/pkg/resources/alert.go b/pkg/resources/alert.go index 6e7f48763f1..15d72819370 100644 --- a/pkg/resources/alert.go +++ b/pkg/resources/alert.go @@ -11,6 +11,7 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/util" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -103,6 +104,7 @@ var alertSchema = map[string]*schema.Schema{ Default: false, Description: "Specifies if an alert should be 'started' (enabled) after creation or should remain 'suspended' (default).", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // Alert returns a pointer to the resource representing an alert. @@ -123,9 +125,9 @@ func Alert() *schema.Resource { // ReadAlert implements schema.ReadContextFunc. func ReadAlert(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client := meta.(*provider.Context).Client - objectIdentifier := helpers.DecodeSnowflakeID(d.Id()).(sdk.SchemaObjectIdentifier) + id := helpers.DecodeSnowflakeID(d.Id()).(sdk.SchemaObjectIdentifier) - alert, err := client.Alerts.ShowByID(ctx, objectIdentifier) + alert, err := client.Alerts.ShowByID(ctx, id) if err != nil { // If not found, mark resource to be removed from state file during apply or refresh log.Printf("[DEBUG] alert (%s) not found", d.Id()) @@ -137,6 +139,10 @@ func ReadAlert(ctx context.Context, d *schema.ResourceData, meta interface{}) di return diag.FromErr(err) } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } + if err := d.Set("name", alert.Name); err != nil { return diag.FromErr(err) } diff --git a/pkg/resources/alert_acceptance_test.go b/pkg/resources/alert_acceptance_test.go index 243b4d66705..7725ddec5f1 100644 --- a/pkg/resources/alert_acceptance_test.go +++ b/pkg/resources/alert_acceptance_test.go @@ -33,13 +33,13 @@ type ( ) var ( - alertName = acc.TestClient().Ids.Alpha() + id = acc.TestClient().Ids.RandomSchemaObjectIdentifier() alertInitialState = &AccAlertTestSettings{ //nolint WarehouseName: acc.TestWarehouseName, DatabaseName: acc.TestDatabaseName, Alert: &AlertSettings{ - Name: alertName, + Name: id.Name(), Condition: "select 0 as c", Action: "select 0 as c", Schema: acc.TestSchemaName, @@ -54,7 +54,7 @@ var ( WarehouseName: acc.TestWarehouseName, DatabaseName: acc.TestDatabaseName, Alert: &AlertSettings{ - Name: alertName, + Name: id.Name(), Condition: "select 1 as c", Action: "select 1 as c", Schema: acc.TestSchemaName, @@ -69,7 +69,7 @@ var ( WarehouseName: acc.TestWarehouseName, DatabaseName: acc.TestDatabaseName, Alert: &AlertSettings{ - Name: alertName, + Name: id.Name(), Condition: "select 2 as c", Action: "select 2 as c", Schema: acc.TestSchemaName, @@ -84,7 +84,7 @@ var ( WarehouseName: acc.TestWarehouseName, DatabaseName: acc.TestDatabaseName, Alert: &AlertSettings{ - Name: alertName, + Name: id.Name(), Condition: "select 2 as c", Action: "select 2 as c", Schema: acc.TestSchemaName, @@ -107,7 +107,8 @@ func TestAcc_Alert(t *testing.T) { Config: alertConfig(alertInitialState), Check: resource.ComposeTestCheckFunc( checkBool("snowflake_alert.test_alert", "enabled", alertInitialState.Alert.Enabled), - resource.TestCheckResourceAttr("snowflake_alert.test_alert", "name", alertName), + resource.TestCheckResourceAttr("snowflake_alert.test_alert", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_alert.test_alert", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_alert.test_alert", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_alert.test_alert", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_alert.test_alert", "condition", alertInitialState.Alert.Condition), @@ -120,7 +121,8 @@ func TestAcc_Alert(t *testing.T) { Config: alertConfig(alertStepOne), Check: resource.ComposeTestCheckFunc( checkBool("snowflake_alert.test_alert", "enabled", alertStepOne.Alert.Enabled), - resource.TestCheckResourceAttr("snowflake_alert.test_alert", "name", alertName), + resource.TestCheckResourceAttr("snowflake_alert.test_alert", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_alert.test_alert", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_alert.test_alert", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_alert.test_alert", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_alert.test_alert", "condition", alertStepOne.Alert.Condition), @@ -133,7 +135,8 @@ func TestAcc_Alert(t *testing.T) { Config: alertConfig(alertStepTwo), Check: resource.ComposeTestCheckFunc( checkBool("snowflake_alert.test_alert", "enabled", alertStepTwo.Alert.Enabled), - resource.TestCheckResourceAttr("snowflake_alert.test_alert", "name", alertName), + resource.TestCheckResourceAttr("snowflake_alert.test_alert", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_alert.test_alert", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_alert.test_alert", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_alert.test_alert", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_alert.test_alert", "condition", alertStepTwo.Alert.Condition), @@ -146,7 +149,8 @@ func TestAcc_Alert(t *testing.T) { Config: alertConfig(alertStepThree), Check: resource.ComposeTestCheckFunc( checkBool("snowflake_alert.test_alert", "enabled", alertStepThree.Alert.Enabled), - resource.TestCheckResourceAttr("snowflake_alert.test_alert", "name", alertName), + resource.TestCheckResourceAttr("snowflake_alert.test_alert", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_alert.test_alert", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_alert.test_alert", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_alert.test_alert", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_alert.test_alert", "condition", alertStepThree.Alert.Condition), @@ -159,7 +163,8 @@ func TestAcc_Alert(t *testing.T) { Config: alertConfig(alertInitialState), Check: resource.ComposeTestCheckFunc( checkBool("snowflake_alert.test_alert", "enabled", alertInitialState.Alert.Enabled), - resource.TestCheckResourceAttr("snowflake_alert.test_alert", "name", alertName), + resource.TestCheckResourceAttr("snowflake_alert.test_alert", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_alert.test_alert", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_alert.test_alert", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_alert.test_alert", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_alert.test_alert", "condition", alertInitialState.Alert.Condition), diff --git a/pkg/resources/api_authentication_integration_common.go b/pkg/resources/api_authentication_integration_common.go index aafad99b24e..66ad5336496 100644 --- a/pkg/resources/api_authentication_integration_common.go +++ b/pkg/resources/api_authentication_integration_common.go @@ -81,6 +81,7 @@ var apiAuthCommonSchema = map[string]*schema.Schema{ Schema: schemas.DescribeApiAuthSecurityIntegrationSchema, }, }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } type commonApiAuthSet struct { @@ -268,11 +269,15 @@ func handleApiAuthImport(d *schema.ResourceData, integration *sdk.SecurityIntegr } func handleApiAuthRead(d *schema.ResourceData, + id sdk.AccountObjectIdentifier, integration *sdk.SecurityIntegration, properties []sdk.SecurityIntegrationProperty, withExternalChangesMarking bool, extraFieldsDescribeMappings []describeMapping, ) error { + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } if err := d.Set("name", integration.Name); err != nil { return err } diff --git a/pkg/resources/api_authentication_integration_with_authorization_code_grant.go b/pkg/resources/api_authentication_integration_with_authorization_code_grant.go index 538b6440da9..63cb8ca0b41 100644 --- a/pkg/resources/api_authentication_integration_with_authorization_code_grant.go +++ b/pkg/resources/api_authentication_integration_with_authorization_code_grant.go @@ -169,7 +169,7 @@ func ReadContextApiAuthenticationIntegrationWithAuthorizationCodeGrant(withExter return diag.FromErr(err) } - if err := handleApiAuthRead(d, integration, properties, withExternalChangesMarking, []describeMapping{ + if err := handleApiAuthRead(d, id, integration, properties, withExternalChangesMarking, []describeMapping{ {"oauth_authorization_endpoint", "oauth_authorization_endpoint", oauthAuthorizationEndpoint.Value, oauthAuthorizationEndpoint.Value, nil}, {"oauth_allowed_scopes", "oauth_allowed_scopes", oauthAllowedScopes.Value, sdk.ParseCommaSeparatedStringArray(oauthAllowedScopes.Value, false), nil}, }); err != nil { diff --git a/pkg/resources/api_authentication_integration_with_authorization_code_grant_acceptance_test.go b/pkg/resources/api_authentication_integration_with_authorization_code_grant_acceptance_test.go index 046f5d0cc67..5c2ede37000 100644 --- a/pkg/resources/api_authentication_integration_with_authorization_code_grant_acceptance_test.go +++ b/pkg/resources/api_authentication_integration_with_authorization_code_grant_acceptance_test.go @@ -205,6 +205,7 @@ func TestAcc_ApiAuthenticationIntegrationWithAuthorizationCodeGrant_complete(t * resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_authorization_code_grant.test", "comment", "foo"), resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_authorization_code_grant.test", "enabled", "true"), resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_authorization_code_grant.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_authorization_code_grant.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_authorization_code_grant.test", "oauth_access_token_validity", "42"), resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_authorization_code_grant.test", "oauth_authorization_endpoint", "https://example.com"), resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_authorization_code_grant.test", "oauth_client_auth_method", string(sdk.ApiAuthenticationSecurityIntegrationOauthClientAuthMethodClientSecretPost)), diff --git a/pkg/resources/api_authentication_integration_with_client_credentials.go b/pkg/resources/api_authentication_integration_with_client_credentials.go index d027493ab25..d7eef754573 100644 --- a/pkg/resources/api_authentication_integration_with_client_credentials.go +++ b/pkg/resources/api_authentication_integration_with_client_credentials.go @@ -141,7 +141,7 @@ func ReadContextApiAuthenticationIntegrationWithClientCredentials(withExternalCh return diag.FromErr(err) } - if err := handleApiAuthRead(d, integration, properties, withExternalChangesMarking, []describeMapping{ + if err := handleApiAuthRead(d, id, integration, properties, withExternalChangesMarking, []describeMapping{ {"oauth_allowed_scopes", "oauth_allowed_scopes", oauthAllowedScopes.Value, sdk.ParseCommaSeparatedStringArray(oauthAllowedScopes.Value, false), nil}, }); err != nil { return diag.FromErr(err) diff --git a/pkg/resources/api_authentication_integration_with_client_credentials_acceptance_test.go b/pkg/resources/api_authentication_integration_with_client_credentials_acceptance_test.go index 3b259d80268..061074304bf 100644 --- a/pkg/resources/api_authentication_integration_with_client_credentials_acceptance_test.go +++ b/pkg/resources/api_authentication_integration_with_client_credentials_acceptance_test.go @@ -199,6 +199,7 @@ func TestAcc_ApiAuthenticationIntegrationWithClientCredentials_complete(t *testi resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_client_credentials.test", "comment", "foo"), resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_client_credentials.test", "enabled", "true"), resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_client_credentials.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_client_credentials.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_client_credentials.test", "oauth_access_token_validity", "42"), resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_client_credentials.test", "oauth_client_auth_method", string(sdk.ApiAuthenticationSecurityIntegrationOauthClientAuthMethodClientSecretPost)), resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_client_credentials.test", "oauth_client_id", "foo"), diff --git a/pkg/resources/api_authentication_integration_with_jwt_bearer.go b/pkg/resources/api_authentication_integration_with_jwt_bearer.go index edc612f56d9..73080acb8f0 100644 --- a/pkg/resources/api_authentication_integration_with_jwt_bearer.go +++ b/pkg/resources/api_authentication_integration_with_jwt_bearer.go @@ -156,7 +156,7 @@ func ReadContextApiAuthenticationIntegrationWithJwtBearer(withExternalChangesMar if err != nil { return diag.FromErr(err) } - if err := handleApiAuthRead(d, integration, properties, withExternalChangesMarking, []describeMapping{ + if err := handleApiAuthRead(d, id, integration, properties, withExternalChangesMarking, []describeMapping{ {"oauth_authorization_endpoint", "oauth_authorization_endpoint", oauthAuthorizationEndpoint.Value, oauthAuthorizationEndpoint.Value, nil}, {"oauth_assertion_issuer", "oauth_assertion_issuer", oauthAssertionIssuer.Value, oauthAssertionIssuer.Value, nil}, }); err != nil { diff --git a/pkg/resources/api_authentication_integration_with_jwt_bearer_acceptance_test.go b/pkg/resources/api_authentication_integration_with_jwt_bearer_acceptance_test.go index 9f4d24d8ffe..b7332e4fb73 100644 --- a/pkg/resources/api_authentication_integration_with_jwt_bearer_acceptance_test.go +++ b/pkg/resources/api_authentication_integration_with_jwt_bearer_acceptance_test.go @@ -163,6 +163,7 @@ func TestAcc_ApiAuthenticationIntegrationWithJwtBearer_complete(t *testing.T) { resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_jwt_bearer.test", "created_on", "foo"), resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_jwt_bearer.test", "enabled", "true"), resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_jwt_bearer.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_jwt_bearer.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_jwt_bearer.test", "oauth_access_token_validity", "42"), resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_jwt_bearer.test", "oauth_authorization_endpoint", "foo"), resource.TestCheckResourceAttr("snowflake_api_authentication_integration_with_jwt_bearer.test", "oauth_client_auth_method", "foo"), diff --git a/pkg/resources/api_integration.go b/pkg/resources/api_integration.go index 5f8f3d5aa20..c6d8ffc8d75 100644 --- a/pkg/resources/api_integration.go +++ b/pkg/resources/api_integration.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" @@ -114,6 +115,7 @@ var apiIntegrationSchema = map[string]*schema.Schema{ Computed: true, Description: "Date and time when the API integration was created.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // APIIntegration returns a pointer to the resource representing an api integration. @@ -227,6 +229,10 @@ func ReadAPIIntegration(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("expected %v to be an api integration, got %v", id, c) } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } + if err := d.Set("name", integration.Name); err != nil { return err } diff --git a/pkg/resources/api_integration_acceptance_test.go b/pkg/resources/api_integration_acceptance_test.go index 3840e62a7c6..bd8a975c17b 100644 --- a/pkg/resources/api_integration_acceptance_test.go +++ b/pkg/resources/api_integration_acceptance_test.go @@ -293,12 +293,12 @@ func TestAcc_ApiIntegration_changeApiProvider(t *testing.T) { const dummyAzureTenantId = "00000000-0000-0000-0000-000000000000" const dummyAzureAdApplicationId = "22222222-2222-2222-2222-222222222222" - name := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() comment := "acceptance test" key := "12345" m := func() map[string]config.Variable { return map[string]config.Variable{ - "name": config.StringVariable(name), + "name": config.StringVariable(id.Name()), "api_provider": config.StringVariable("aws_api_gateway"), "api_aws_role_arn": config.StringVariable(dummyAwsApiRoleArn), "api_allowed_prefixes": config.ListVariable( @@ -314,7 +314,7 @@ func TestAcc_ApiIntegration_changeApiProvider(t *testing.T) { } m2 := func() map[string]config.Variable { return map[string]config.Variable{ - "name": config.StringVariable(name), + "name": config.StringVariable(id.Name()), "azure_tenant_id": config.StringVariable(dummyAzureTenantId), "azure_ad_application_id": config.StringVariable(dummyAzureAdApplicationId), "api_allowed_prefixes": config.ListVariable( @@ -341,7 +341,8 @@ func TestAcc_ApiIntegration_changeApiProvider(t *testing.T) { ConfigDirectory: config.TestStepDirectory(), ConfigVariables: m(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_api_integration.test_change", "name", name), + resource.TestCheckResourceAttr("snowflake_api_integration.test_change", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_api_integration.test_change", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_api_integration.test_change", "api_provider", "aws_api_gateway"), resource.TestCheckResourceAttr("snowflake_api_integration.test_change", "api_aws_role_arn", dummyAwsApiRoleArn), resource.TestCheckResourceAttr("snowflake_api_integration.test_change", "api_allowed_prefixes.#", "1"), @@ -360,7 +361,8 @@ func TestAcc_ApiIntegration_changeApiProvider(t *testing.T) { ConfigDirectory: config.TestStepDirectory(), ConfigVariables: m2(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_api_integration.test_change", "name", name), + resource.TestCheckResourceAttr("snowflake_api_integration.test_change", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_api_integration.test_change", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_api_integration.test_change", "api_provider", "azure_api_management"), resource.TestCheckResourceAttr("snowflake_api_integration.test_change", "azure_tenant_id", dummyAzureTenantId), resource.TestCheckResourceAttr("snowflake_api_integration.test_change", "azure_ad_application_id", dummyAzureAdApplicationId), diff --git a/pkg/resources/cortex_search_service.go b/pkg/resources/cortex_search_service.go index bcba7ea2245..059e537aca4 100644 --- a/pkg/resources/cortex_search_service.go +++ b/pkg/resources/cortex_search_service.go @@ -8,6 +8,7 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -73,6 +74,7 @@ var cortexSearchServiceSchema = map[string]*schema.Schema{ Computed: true, Description: "Creation date for the given Cortex search service.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // CortexSearchService returns a pointer to the resource representing a Cortex search service. @@ -110,6 +112,9 @@ func ReadCortexSearchService(ctx context.Context, d *schema.ResourceData, meta a } return diag.FromErr(err) } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if err := d.Set("name", cortexSearchService.Name); err != nil { return diag.FromErr(err) } diff --git a/pkg/resources/cortex_search_service_acceptance_test.go b/pkg/resources/cortex_search_service_acceptance_test.go index d4b831cbeaa..b99171d43ef 100644 --- a/pkg/resources/cortex_search_service_acceptance_test.go +++ b/pkg/resources/cortex_search_service_acceptance_test.go @@ -54,6 +54,7 @@ func TestAcc_CortexSearchService_basic(t *testing.T) { }, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "database", acc.TestDatabaseName), resource.TestCheckResourceAttr(resourceName, "schema", acc.TestSchemaName), resource.TestCheckResourceAttr(resourceName, "on", "SOME_TEXT"), @@ -75,6 +76,7 @@ func TestAcc_CortexSearchService_basic(t *testing.T) { }, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "database", acc.TestDatabaseName), resource.TestCheckResourceAttr(resourceName, "schema", acc.TestSchemaName), resource.TestCheckResourceAttr(resourceName, "on", "SOME_TEXT"), diff --git a/pkg/resources/database.go b/pkg/resources/database.go index 63eb9e8271c..8090832e759 100644 --- a/pkg/resources/database.go +++ b/pkg/resources/database.go @@ -9,6 +9,7 @@ import ( "time" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/util" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/hashicorp/go-cty/cty" @@ -16,6 +17,7 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -81,6 +83,7 @@ var databaseSchema = map[string]*schema.Schema{ Optional: true, Description: "Specifies a comment for the database.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func Database() *schema.Resource { @@ -98,7 +101,10 @@ func Database() *schema.Resource { StateContext: schema.ImportStatePassthroughContext, }, - CustomizeDiff: databaseParametersCustomDiff, + CustomizeDiff: customdiff.All( + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), + databaseParametersCustomDiff, + ), StateUpgraders: []schema.StateUpgrader{ { @@ -359,6 +365,10 @@ func ReadDatabase(ctx context.Context, d *schema.ResourceData, meta any) diag.Di return diag.FromErr(err) } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } + if err := d.Set("name", database.Name); err != nil { return diag.FromErr(err) } diff --git a/pkg/resources/database_acceptance_test.go b/pkg/resources/database_acceptance_test.go index eed0d2691bf..fca3de6b9cc 100644 --- a/pkg/resources/database_acceptance_test.go +++ b/pkg/resources/database_acceptance_test.go @@ -368,6 +368,7 @@ func TestAcc_Database_Complete(t *testing.T) { ConfigVariables: completeConfigVariables, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_database.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_database.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_database.test", "is_transient", "false"), resource.TestCheckResourceAttr("snowflake_database.test", "comment", comment), diff --git a/pkg/resources/database_role.go b/pkg/resources/database_role.go index 0a0700972f8..d44d40a4698 100644 --- a/pkg/resources/database_role.go +++ b/pkg/resources/database_role.go @@ -6,6 +6,7 @@ import ( "log" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" @@ -30,6 +31,7 @@ var databaseRoleSchema = map[string]*schema.Schema{ Optional: true, Description: "Specifies a comment for the database role.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // DatabaseRole returns a pointer to the resource representing a database role. @@ -51,10 +53,10 @@ func DatabaseRole() *schema.Resource { func ReadDatabaseRole(d *schema.ResourceData, meta interface{}) error { client := meta.(*provider.Context).Client - objectIdentifier := helpers.DecodeSnowflakeID(d.Id()).(sdk.DatabaseObjectIdentifier) + id := helpers.DecodeSnowflakeID(d.Id()).(sdk.DatabaseObjectIdentifier) ctx := context.Background() - databaseRole, err := client.DatabaseRoles.ShowByID(ctx, objectIdentifier) + databaseRole, err := client.DatabaseRoles.ShowByID(ctx, id) if err != nil { // If not found, mark resource to be removed from state file during apply or refresh log.Printf("[DEBUG] database role (%s) not found", d.Id()) @@ -62,11 +64,15 @@ func ReadDatabaseRole(d *schema.ResourceData, meta interface{}) error { return nil } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } + if err := d.Set("name", databaseRole.Name); err != nil { return err } - if err := d.Set("database", objectIdentifier.DatabaseName()); err != nil { + if err := d.Set("database", id.DatabaseName()); err != nil { return err } diff --git a/pkg/resources/database_role_acceptance_test.go b/pkg/resources/database_role_acceptance_test.go index b0373efa757..92738f7de76 100644 --- a/pkg/resources/database_role_acceptance_test.go +++ b/pkg/resources/database_role_acceptance_test.go @@ -14,7 +14,7 @@ import ( func TestAcc_DatabaseRole(t *testing.T) { resourceName := "snowflake_database_role.test_db_role" - dbRoleName := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomDatabaseObjectIdentifier() comment := random.Comment() comment2 := random.Comment() @@ -27,17 +27,19 @@ func TestAcc_DatabaseRole(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.DatabaseRole), Steps: []resource.TestStep{ { - Config: databaseRoleConfig(dbRoleName, acc.TestDatabaseName, comment), + Config: databaseRoleConfig(id.Name(), acc.TestDatabaseName, comment), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", dbRoleName), + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "database", acc.TestDatabaseName), resource.TestCheckResourceAttr(resourceName, "comment", comment), ), }, { - Config: databaseRoleConfig(dbRoleName, acc.TestDatabaseName, comment2), + Config: databaseRoleConfig(id.Name(), acc.TestDatabaseName, comment2), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", dbRoleName), + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "database", acc.TestDatabaseName), resource.TestCheckResourceAttr(resourceName, "comment", comment2), ), diff --git a/pkg/resources/doc_helpers.go b/pkg/resources/doc_helpers.go index 020f70ce463..9ec02009637 100644 --- a/pkg/resources/doc_helpers.go +++ b/pkg/resources/doc_helpers.go @@ -12,3 +12,15 @@ func possibleValuesListed[T ~string](values []T) string { } return strings.Join(valuesWrapped, " | ") } + +func booleanStringFieldDescription(description string) string { + return fmt.Sprintf(`%s Available options are: "%s" or "%s". When the value is not set in the configuration the provider will put "%s" there which means to use the Snowflake default for this value.`, description, BooleanTrue, BooleanFalse, BooleanDefault) +} + +func externalChangesNotDetectedFieldDescription(description string) string { + return fmt.Sprintf(`%s External changes for this field won't be detected. In case you want to apply external changes, you can re-create the resource manually using "terraform taint".`, description) +} + +func withPrivilegedRolesDescription(description, paramName string) string { + return fmt.Sprintf(`%s By default, this list includes the ACCOUNTADMIN, ORGADMIN and SECURITYADMIN roles. To remove these privileged roles from the list, use the ALTER ACCOUNT command to set the %s account parameter to FALSE. `, description, paramName) +} diff --git a/pkg/resources/dynamic_table.go b/pkg/resources/dynamic_table.go index 606a2f760fa..e8b64b64e4b 100644 --- a/pkg/resources/dynamic_table.go +++ b/pkg/resources/dynamic_table.go @@ -8,6 +8,7 @@ import ( "time" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" @@ -156,6 +157,7 @@ var dynamicTableSchema = map[string]*schema.Schema{ Description: "Timestamp of the data in the base object(s) that is included in the dynamic table.", Computed: true, }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // DynamicTable returns a pointer to the resource representing a dynamic table. @@ -184,6 +186,9 @@ func ReadDynamicTable(d *schema.ResourceData, meta interface{}) error { d.SetId("") return nil } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } if err := d.Set("name", dynamicTable.Name); err != nil { return err } diff --git a/pkg/resources/dynamic_table_acceptance_test.go b/pkg/resources/dynamic_table_acceptance_test.go index 092fa2185ba..d7f58fbc37d 100644 --- a/pkg/resources/dynamic_table_acceptance_test.go +++ b/pkg/resources/dynamic_table_acceptance_test.go @@ -15,13 +15,13 @@ import ( ) func TestAcc_DynamicTable_basic(t *testing.T) { - name := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() resourceName := "snowflake_dynamic_table.dt" - tableName := name + "_table" + tableName := id.Name() + "_table" newWarehouseName := acc.TestClient().Ids.Alpha() m := func() map[string]config.Variable { return map[string]config.Variable{ - "name": config.StringVariable(name), + "name": config.StringVariable(id.Name()), "database": config.StringVariable(acc.TestDatabaseName), "schema": config.StringVariable(acc.TestSchemaName), "warehouse": config.StringVariable(acc.TestWarehouseName), @@ -56,7 +56,8 @@ func TestAcc_DynamicTable_basic(t *testing.T) { ConfigDirectory: config.TestStepDirectory(), ConfigVariables: m(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "database", acc.TestDatabaseName), resource.TestCheckResourceAttr(resourceName, "schema", acc.TestSchemaName), resource.TestCheckResourceAttr(resourceName, "warehouse", acc.TestWarehouseName), @@ -94,7 +95,8 @@ func TestAcc_DynamicTable_basic(t *testing.T) { ConfigDirectory: config.TestStepDirectory(), ConfigVariables: variableSet2, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "database", acc.TestDatabaseName), resource.TestCheckResourceAttr(resourceName, "schema", acc.TestSchemaName), resource.TestCheckResourceAttr(resourceName, "warehouse", newWarehouseName), diff --git a/pkg/resources/email_notification_integration.go b/pkg/resources/email_notification_integration.go index c75cb4066db..586adfc72d3 100644 --- a/pkg/resources/email_notification_integration.go +++ b/pkg/resources/email_notification_integration.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" @@ -35,6 +36,7 @@ var emailNotificationIntegrationSchema = map[string]*schema.Schema{ Optional: true, Description: "A comment for the email integration.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // EmailNotificationIntegration returns a pointer to the resource representing a notification integration. @@ -104,6 +106,10 @@ func ReadEmailNotificationIntegration(d *schema.ResourceData, meta interface{}) return err } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } + if err := d.Set("name", integration.Name); err != nil { return err } diff --git a/pkg/resources/email_notification_integration_acceptance_test.go b/pkg/resources/email_notification_integration_acceptance_test.go index db7b422cabb..311cc35a4f7 100644 --- a/pkg/resources/email_notification_integration_acceptance_test.go +++ b/pkg/resources/email_notification_integration_acceptance_test.go @@ -13,7 +13,7 @@ import ( // TODO [SNOW-1007539]: use email of our service user (verified email address is required) func TestAcc_EmailNotificationIntegration(t *testing.T) { - emailIntegrationName := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() verifiedEmail := "artur.sawicki@snowflake.com" resource.Test(t, resource.TestCase{ @@ -25,9 +25,10 @@ func TestAcc_EmailNotificationIntegration(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.EmailNotificationIntegration), Steps: []resource.TestStep{ { - Config: emailNotificationIntegrationConfig(emailIntegrationName, verifiedEmail), + Config: emailNotificationIntegrationConfig(id.Name(), verifiedEmail), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_email_notification_integration.test", "name", emailIntegrationName), + resource.TestCheckResourceAttr("snowflake_email_notification_integration.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_email_notification_integration.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_email_notification_integration.test", "allowed_recipients.0", verifiedEmail), ), }, diff --git a/pkg/resources/external_function.go b/pkg/resources/external_function.go index e57e43ce515..d1362ad1046 100644 --- a/pkg/resources/external_function.go +++ b/pkg/resources/external_function.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/hashicorp/go-cty/cty" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -177,6 +178,7 @@ var externalFunctionSchema = map[string]*schema.Schema{ Computed: true, Description: "Date and time when the external function was created.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // ExternalFunction returns a pointer to the resource representing an external function. @@ -333,6 +335,9 @@ func ReadContextExternalFunction(ctx context.Context, d *schema.ResourceData, me } // Some properties can come from the SHOW EXTERNAL FUNCTION call + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if err := d.Set("name", externalFunction.Name); err != nil { return diag.FromErr(err) } diff --git a/pkg/resources/external_function_acceptance_test.go b/pkg/resources/external_function_acceptance_test.go index d147071fd2f..d4b038aa003 100644 --- a/pkg/resources/external_function_acceptance_test.go +++ b/pkg/resources/external_function_acceptance_test.go @@ -152,13 +152,13 @@ func TestAcc_ExternalFunction_no_arguments(t *testing.T) { } func TestAcc_ExternalFunction_complete(t *testing.T) { - accName := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() m := func() map[string]config.Variable { return map[string]config.Variable{ "database": config.StringVariable(acc.TestDatabaseName), "schema": config.StringVariable(acc.TestSchemaName), - "name": config.StringVariable(accName), + "name": config.StringVariable(id.Name()), "api_allowed_prefixes": config.ListVariable(config.StringVariable("https://123456.execute-api.us-west-2.amazonaws.com/prod/")), "url_of_proxy_and_resource": config.StringVariable("https://123456.execute-api.us-west-2.amazonaws.com/prod/test_func"), "comment": config.StringVariable("Terraform acceptance test"), @@ -182,7 +182,8 @@ func TestAcc_ExternalFunction_complete(t *testing.T) { ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalFunction/complete"), ConfigVariables: configVariables, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", accName), + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "database", acc.TestDatabaseName), resource.TestCheckResourceAttr(resourceName, "schema", acc.TestSchemaName), resource.TestCheckResourceAttr(resourceName, "arg.#", "0"), @@ -199,8 +200,8 @@ func TestAcc_ExternalFunction_complete(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "header.0.name", "x-custom-header"), resource.TestCheckResourceAttr(resourceName, "header.0.value", "snowflake"), resource.TestCheckResourceAttr(resourceName, "max_batch_rows", "500"), - resource.TestCheckResourceAttr(resourceName, "request_translator", fmt.Sprintf("%s.%s.%s%s", acc.TestDatabaseName, acc.TestSchemaName, accName, "_request_translator")), - resource.TestCheckResourceAttr(resourceName, "response_translator", fmt.Sprintf("%s.%s.%s%s", acc.TestDatabaseName, acc.TestSchemaName, accName, "_response_translator")), + resource.TestCheckResourceAttr(resourceName, "request_translator", fmt.Sprintf("%s.%s.%s%s", acc.TestDatabaseName, acc.TestSchemaName, id.Name(), "_request_translator")), + resource.TestCheckResourceAttr(resourceName, "response_translator", fmt.Sprintf("%s.%s.%s%s", acc.TestDatabaseName, acc.TestSchemaName, id.Name(), "_response_translator")), ), }, { diff --git a/pkg/resources/external_oauth_integration.go b/pkg/resources/external_oauth_integration.go index 37c91ded280..1b98e1f76d6 100644 --- a/pkg/resources/external_oauth_integration.go +++ b/pkg/resources/external_oauth_integration.go @@ -147,6 +147,7 @@ var externalOauthIntegrationSchema = map[string]*schema.Schema{ Schema: schemas.ShowExternalOauthParametersSchema, }, }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func ExternalOauthIntegration() *schema.Resource { @@ -422,6 +423,9 @@ func ReadContextExternalOauthIntegration(withExternalChangesMarking bool) schema if c := integration.Category; c != sdk.SecurityIntegrationCategory { return diag.FromErr(fmt.Errorf("expected %v to be a %s integration, got %v", id, sdk.SecurityIntegrationCategory, c)) } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if err := d.Set("name", integration.Name); err != nil { return diag.FromErr(err) } diff --git a/pkg/resources/external_oauth_integration_acceptance_test.go b/pkg/resources/external_oauth_integration_acceptance_test.go index 02b5f57b58b..93786843d7e 100644 --- a/pkg/resources/external_oauth_integration_acceptance_test.go +++ b/pkg/resources/external_oauth_integration_acceptance_test.go @@ -380,6 +380,7 @@ func TestAcc_ExternalOauthIntegration_completeWithJwsKeysUrlAndAllowedRolesList( resource.TestCheckResourceAttr("snowflake_external_oauth_integration.test", "external_oauth_token_user_mapping_claim.#", "1"), resource.TestCheckResourceAttr("snowflake_external_oauth_integration.test", "external_oauth_token_user_mapping_claim.0", "foo"), resource.TestCheckResourceAttr("snowflake_external_oauth_integration.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_external_oauth_integration.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_external_oauth_integration.test", "external_oauth_type", string(sdk.ExternalOauthSecurityIntegrationTypeCustom)), resource.TestCheckResourceAttr("snowflake_external_oauth_integration.test", "show_output.#", "1"), diff --git a/pkg/resources/external_stage_acceptance_test.go b/pkg/resources/external_stage_acceptance_test.go index fb78e3b34e8..4daf06d8388 100644 --- a/pkg/resources/external_stage_acceptance_test.go +++ b/pkg/resources/external_stage_acceptance_test.go @@ -12,7 +12,7 @@ import ( ) func TestAcc_ExternalStage(t *testing.T) { - accName := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, @@ -23,9 +23,10 @@ func TestAcc_ExternalStage(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.Stage), Steps: []resource.TestStep{ { - Config: externalStageConfig(accName, acc.TestDatabaseName, acc.TestSchemaName), + Config: externalStageConfig(id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_stage.test", "name", accName), + resource.TestCheckResourceAttr("snowflake_stage.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_stage.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_stage.test", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_stage.test", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_stage.test", "comment", "Terraform acceptance test"), diff --git a/pkg/resources/external_table.go b/pkg/resources/external_table.go index bec15f69389..94cd921cf19 100644 --- a/pkg/resources/external_table.go +++ b/pkg/resources/external_table.go @@ -6,6 +6,7 @@ import ( "log" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -133,7 +134,8 @@ var externalTableSchema = map[string]*schema.Schema{ Computed: true, Description: "Name of the role that owns the external table.", }, - "tag": tagReferenceSchema, + "tag": tagReferenceSchema, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func ExternalTable() *schema.Resource { @@ -256,6 +258,10 @@ func ReadExternalTable(d *schema.ResourceData, meta any) error { return err } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } + if err := d.Set("name", externalTable.Name); err != nil { return err } diff --git a/pkg/resources/external_table_acceptance_test.go b/pkg/resources/external_table_acceptance_test.go index 24f575a5ba9..0541a230594 100644 --- a/pkg/resources/external_table_acceptance_test.go +++ b/pkg/resources/external_table_acceptance_test.go @@ -81,6 +81,7 @@ func TestAcc_ExternalTable_basic(t *testing.T) { ConfigVariables: configVariables, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "database", acc.TestDatabaseName), resource.TestCheckResourceAttr(resourceName, "schema", acc.TestSchemaName), resource.TestCheckResourceAttr(resourceName, "location", fmt.Sprintf(`@"%s"."%s"."%s"%s`, acc.TestDatabaseName, acc.TestSchemaName, name, innerDirectory)), diff --git a/pkg/resources/failover_group.go b/pkg/resources/failover_group.go index 6d515133459..e873436b586 100644 --- a/pkg/resources/failover_group.go +++ b/pkg/resources/failover_group.go @@ -10,6 +10,7 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -131,6 +132,7 @@ var failoverGroupSchema = map[string]*schema.Schema{ }, }, }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // FailoverGroup returns a pointer to the resource representing a failover group. @@ -272,6 +274,10 @@ func ReadFailoverGroup(d *schema.ResourceData, meta interface{}) error { return err } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } + if err := d.Set("name", failoverGroup.Name); err != nil { return err } diff --git a/pkg/resources/failover_group_acceptance_test.go b/pkg/resources/failover_group_acceptance_test.go index f44e039ad63..58f68ab0d7d 100644 --- a/pkg/resources/failover_group_acceptance_test.go +++ b/pkg/resources/failover_group_acceptance_test.go @@ -16,7 +16,7 @@ func TestAcc_FailoverGroupBasic(t *testing.T) { // TODO [SNOW-1002023]: Unskip; Business Critical Snowflake Edition needed _ = testenvs.GetOrSkipTest(t, testenvs.TestFailoverGroups) - randomCharacters := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() accountName := testenvs.GetOrSkipTest(t, testenvs.BusinessCriticalAccount) resource.Test(t, resource.TestCase{ @@ -28,9 +28,10 @@ func TestAcc_FailoverGroupBasic(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.FailoverGroup), Steps: []resource.TestStep{ { - Config: failoverGroupBasic(randomCharacters, accountName, acc.TestDatabaseName), + Config: failoverGroupBasic(id.Name(), accountName, acc.TestDatabaseName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_failover_group.fg", "name", randomCharacters), + resource.TestCheckResourceAttr("snowflake_failover_group.fg", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_failover_group.fg", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_failover_group.fg", "object_types.#", "4"), resource.TestCheckResourceAttr("snowflake_failover_group.fg", "allowed_accounts.#", "1"), resource.TestCheckResourceAttr("snowflake_failover_group.fg", "allowed_databases.#", "1"), diff --git a/pkg/resources/file_format.go b/pkg/resources/file_format.go index bb6a80bf180..adc751fca69 100644 --- a/pkg/resources/file_format.go +++ b/pkg/resources/file_format.go @@ -8,9 +8,11 @@ import ( "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -288,6 +290,7 @@ var fileFormatSchema = map[string]*schema.Schema{ Optional: true, Description: "Specifies a comment for the file format.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } type fileFormatID struct { @@ -315,6 +318,10 @@ func FileFormat() *schema.Resource { Update: UpdateFileFormat, Delete: DeleteFileFormat, + CustomizeDiff: customdiff.All( + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), + ), + Schema: fileFormatSchema, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, @@ -544,6 +551,10 @@ func ReadFileFormat(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("cannot read file format: %w", err) } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } + if err := d.Set("name", fileFormat.Name.Name()); err != nil { return err } diff --git a/pkg/resources/file_format_acceptance_test.go b/pkg/resources/file_format_acceptance_test.go index 4b4b0cd3f30..0ec415273f1 100644 --- a/pkg/resources/file_format_acceptance_test.go +++ b/pkg/resources/file_format_acceptance_test.go @@ -450,8 +450,8 @@ func TestAcc_FileFormat_issue1947(t *testing.T) { } func TestAcc_FileFormat_Rename(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - newName := acc.TestClient().Ids.Alpha() + oldId := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + newId := acc.TestClient().Ids.RandomSchemaObjectIdentifier() comment := random.Comment() newComment := random.Comment() resourceName := "snowflake_file_format.test" @@ -465,16 +465,18 @@ func TestAcc_FileFormat_Rename(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.FileFormat), Steps: []resource.TestStep{ { - Config: fileFormatConfigWithComment(name, acc.TestDatabaseName, acc.TestSchemaName, comment), + Config: fileFormatConfigWithComment(oldId.Name(), acc.TestDatabaseName, acc.TestSchemaName, comment), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "name", oldId.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", oldId.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "comment", comment), ), }, { - Config: fileFormatConfigWithComment(newName, acc.TestDatabaseName, acc.TestSchemaName, newComment), + Config: fileFormatConfigWithComment(newId.Name(), acc.TestDatabaseName, acc.TestSchemaName, newComment), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", newName), + resource.TestCheckResourceAttr(resourceName, "name", newId.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", newId.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "comment", newComment), ), ConfigPlanChecks: resource.ConfigPlanChecks{ diff --git a/pkg/resources/function.go b/pkg/resources/function.go index f222c9b0a75..18a70e4e19b 100644 --- a/pkg/resources/function.go +++ b/pkg/resources/function.go @@ -8,10 +8,12 @@ import ( "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/go-cty/cty" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) @@ -157,6 +159,7 @@ var functionSchema = map[string]*schema.Schema{ ForceNew: true, Description: "The target path for the Java / Python functions. For Java, it is the path of compiled jar files and for the Python it is the path of the Python files.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func Function() *schema.Resource { @@ -168,6 +171,10 @@ func Function() *schema.Resource { UpdateContext: UpdateContextFunction, DeleteContext: DeleteContextFunction, + CustomizeDiff: customdiff.All( + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), + ), + Schema: functionSchema, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, @@ -521,6 +528,9 @@ func ReadContextFunction(ctx context.Context, d *schema.ResourceData, meta inter if err != nil { return diag.FromErr(err) } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if err := d.Set("name", id.Name()); err != nil { return diag.FromErr(err) } diff --git a/pkg/resources/function_acceptance_test.go b/pkg/resources/function_acceptance_test.go index b4e99be3012..b463874c366 100644 --- a/pkg/resources/function_acceptance_test.go +++ b/pkg/resources/function_acceptance_test.go @@ -271,8 +271,8 @@ func TestAcc_Function_EnsureSmoothResourceIdMigrationToV0950(t *testing.T) { } func TestAcc_Function_Rename(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - newName := acc.TestClient().Ids.Alpha() + oldId := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.DataTypeVARCHAR) + newId := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.DataTypeVARCHAR) comment := random.Comment() newComment := random.Comment() resourceName := "snowflake_function.f" @@ -286,16 +286,18 @@ func TestAcc_Function_Rename(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.Function), Steps: []resource.TestStep{ { - Config: functionConfig(acc.TestDatabaseName, acc.TestSchemaName, name, comment), + Config: functionConfig(acc.TestDatabaseName, acc.TestSchemaName, oldId.Name(), comment), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "name", oldId.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", oldId.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "comment", comment), ), }, { - Config: functionConfig(acc.TestDatabaseName, acc.TestSchemaName, newName, newComment), + Config: functionConfig(acc.TestDatabaseName, acc.TestSchemaName, newId.Name(), newComment), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", newName), + resource.TestCheckResourceAttr(resourceName, "name", newId.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", newId.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "comment", newComment), ), ConfigPlanChecks: resource.ConfigPlanChecks{ diff --git a/pkg/resources/internal_stage_acceptance_test.go b/pkg/resources/internal_stage_acceptance_test.go index 11b31c5ccc0..c865589db1e 100644 --- a/pkg/resources/internal_stage_acceptance_test.go +++ b/pkg/resources/internal_stage_acceptance_test.go @@ -12,7 +12,7 @@ import ( ) func TestAcc_InternalStage(t *testing.T) { - accName := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, @@ -23,9 +23,10 @@ func TestAcc_InternalStage(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.Stage), Steps: []resource.TestStep{ { - Config: internalStageConfig(accName, acc.TestDatabaseName, acc.TestSchemaName), + Config: internalStageConfig(id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_stage.test", "name", accName), + resource.TestCheckResourceAttr("snowflake_stage.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_stage.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_stage.test", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_stage.test", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_stage.test", "comment", "Terraform acceptance test"), diff --git a/pkg/resources/managed_account.go b/pkg/resources/managed_account.go index bbc1751152d..a92d2bf76a2 100644 --- a/pkg/resources/managed_account.go +++ b/pkg/resources/managed_account.go @@ -8,6 +8,7 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/util" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -76,6 +77,7 @@ var managedAccountSchema = map[string]*schema.Schema{ Computed: true, Description: "URL for accessing the managed account, particularly through the web interface.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // ManagedAccount returns a pointer to the resource representing a managed account. @@ -125,7 +127,7 @@ func ReadManagedAccount(d *schema.ResourceData, meta interface{}) error { client := meta.(*provider.Context).Client ctx := context.Background() - objectIdentifier := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier) + id := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier) // We have to wait during the first read, since the locator takes some time to appear. // This approach has a downside of not handling correctly the situation where managed account was removed externally. @@ -133,7 +135,7 @@ func ReadManagedAccount(d *schema.ResourceData, meta interface{}) error { var managedAccount *sdk.ManagedAccount var err error err = util.Retry(5, 3*time.Second, func() (error, bool) { - managedAccount, err = client.ManagedAccounts.ShowByID(ctx, objectIdentifier) + managedAccount, err = client.ManagedAccounts.ShowByID(ctx, id) if err != nil { return nil, false } @@ -142,7 +144,9 @@ func ReadManagedAccount(d *schema.ResourceData, meta interface{}) error { if err != nil { return err } - + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } if err := d.Set("name", managedAccount.Name); err != nil { return err } diff --git a/pkg/resources/managed_account_acceptance_test.go b/pkg/resources/managed_account_acceptance_test.go index f5009a15870..0aee50698ed 100644 --- a/pkg/resources/managed_account_acceptance_test.go +++ b/pkg/resources/managed_account_acceptance_test.go @@ -20,7 +20,7 @@ func TestAcc_ManagedAccount(t *testing.T) { // TODO [SNOW-1011985]: unskip the tests testenvs.SkipTestIfSet(t, testenvs.SkipManagedAccountTest, "error: 090337 (23001): Number of managed accounts allowed exceeded the limit. Please contact Snowflake support") - accName := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() adminName := acc.TestClient().Ids.Alpha() adminPass := acc.TestClient().Ids.AlphaWithPrefix("A1") @@ -33,9 +33,10 @@ func TestAcc_ManagedAccount(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.ManagedAccount), Steps: []resource.TestStep{ { - Config: managedAccountConfig(accName, adminName, adminPass), + Config: managedAccountConfig(id.Name(), adminName, adminPass), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_managed_account.test", "name", accName), + resource.TestCheckResourceAttr("snowflake_managed_account.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_managed_account.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_managed_account.test", "admin_name", adminName), resource.TestCheckResourceAttr("snowflake_managed_account.test", "admin_password", adminPass), resource.TestCheckResourceAttr("snowflake_managed_account.test", "comment", managedAccountComment), diff --git a/pkg/resources/masking_policy.go b/pkg/resources/masking_policy.go index 46427f128cf..b9cefa4fd11 100644 --- a/pkg/resources/masking_policy.go +++ b/pkg/resources/masking_policy.go @@ -4,9 +4,12 @@ import ( "context" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/go-cty/cty" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -106,11 +109,7 @@ var maskingPolicySchema = map[string]*schema.Schema{ Optional: true, Description: "Specifies a comment for the masking policy.", }, - "qualified_name": { - Type: schema.TypeString, - Computed: true, - Description: "Specifies the qualified identifier for the masking policy.", - }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // DatabaseName|SchemaName|MaskingPolicyName. @@ -118,15 +117,29 @@ var maskingPolicySchema = map[string]*schema.Schema{ // MaskingPolicy returns a pointer to the resource representing a masking policy. func MaskingPolicy() *schema.Resource { return &schema.Resource{ - Create: CreateMaskingPolicy, - Read: ReadMaskingPolicy, - Update: UpdateMaskingPolicy, - Delete: DeleteMaskingPolicy, + SchemaVersion: 1, + Create: CreateMaskingPolicy, + Read: ReadMaskingPolicy, + Update: UpdateMaskingPolicy, + Delete: DeleteMaskingPolicy, + + CustomizeDiff: customdiff.All( + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), + ), Schema: maskingPolicySchema, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, + + StateUpgraders: []schema.StateUpgrader{ + { + Version: 0, + // setting type to cty.EmptyObject is a bit hacky here but following https://developer.hashicorp.com/terraform/plugin/framework/migrating/resources/state-upgrade#sdkv2-1 would require lots of repetitive code; this should work with cty.EmptyObject + Type: cty.EmptyObject, + Upgrade: v0_94_1_MaskingPolicyStateUpgrader, + }, + }, } } @@ -186,13 +199,17 @@ func CreateMaskingPolicy(d *schema.ResourceData, meta interface{}) error { // ReadMaskingPolicy implements schema.ReadFunc. func ReadMaskingPolicy(d *schema.ResourceData, meta interface{}) error { client := meta.(*provider.Context).Client - objectIdentifier := helpers.DecodeSnowflakeID(d.Id()).(sdk.SchemaObjectIdentifier) + id := helpers.DecodeSnowflakeID(d.Id()).(sdk.SchemaObjectIdentifier) ctx := context.Background() - maskingPolicy, err := client.MaskingPolicies.ShowByID(ctx, objectIdentifier) + maskingPolicy, err := client.MaskingPolicies.ShowByID(ctx, id) if err != nil { return err } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } + if err := d.Set("name", maskingPolicy.Name); err != nil { return err } @@ -213,7 +230,7 @@ func ReadMaskingPolicy(d *schema.ResourceData, meta interface{}) error { return err } - maskingPolicyDetails, err := client.MaskingPolicies.Describe(ctx, objectIdentifier) + maskingPolicyDetails, err := client.MaskingPolicies.Describe(ctx, id) if err != nil { return err } @@ -239,9 +256,6 @@ func ReadMaskingPolicy(d *schema.ResourceData, meta interface{}) error { if err := d.Set("signature", signature); err != nil { return err } - if err := d.Set("qualified_name", objectIdentifier.FullyQualifiedName()); err != nil { - return err - } return err } diff --git a/pkg/resources/masking_policy_acceptance_test.go b/pkg/resources/masking_policy_acceptance_test.go index 8a21066153d..94c0e5494f4 100644 --- a/pkg/resources/masking_policy_acceptance_test.go +++ b/pkg/resources/masking_policy_acceptance_test.go @@ -14,8 +14,8 @@ import ( ) func TestAcc_MaskingPolicy(t *testing.T) { - accName := acc.TestClient().Ids.Alpha() - accName2 := acc.TestClient().Ids.Alpha() + oldId := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + newId := acc.TestClient().Ids.RandomSchemaObjectIdentifier() comment := "Terraform acceptance test" comment2 := "Terraform acceptance test 2" resource.Test(t, resource.TestCase{ @@ -27,9 +27,10 @@ func TestAcc_MaskingPolicy(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.MaskingPolicy), Steps: []resource.TestStep{ { - Config: maskingPolicyConfig(accName, accName, comment, acc.TestDatabaseName, acc.TestSchemaName), + Config: maskingPolicyConfig(oldId.Name(), comment, acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_masking_policy.test", "name", accName), + resource.TestCheckResourceAttr("snowflake_masking_policy.test", "name", oldId.Name()), + resource.TestCheckResourceAttr("snowflake_masking_policy.test", "fully_qualified_name", oldId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_masking_policy.test", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_masking_policy.test", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_masking_policy.test", "comment", comment), @@ -43,20 +44,21 @@ func TestAcc_MaskingPolicy(t *testing.T) { }, // rename + change comment { - Config: maskingPolicyConfig(accName, accName2, comment2, acc.TestDatabaseName, acc.TestSchemaName), + Config: maskingPolicyConfig(newId.Name(), comment2, acc.TestDatabaseName, acc.TestSchemaName), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectResourceAction("snowflake_masking_policy.test", plancheck.ResourceActionUpdate), }, }, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_masking_policy.test", "name", accName2), + resource.TestCheckResourceAttr("snowflake_masking_policy.test", "name", newId.Name()), + resource.TestCheckResourceAttr("snowflake_masking_policy.test", "fully_qualified_name", newId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_masking_policy.test", "comment", comment2), ), }, // change body and unset comment { - Config: maskingPolicyConfigMultiline(accName, accName2, acc.TestDatabaseName, acc.TestSchemaName), + Config: maskingPolicyConfigMultiline(newId.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_masking_policy.test", "masking_expression", "case\n\twhen current_role() in ('ROLE_A') then\n\t\tval\n\twhen is_role_in_session( 'ROLE_B' ) then\n\t\t'ABC123'\n\telse\n\t\t'******'\nend"), resource.TestCheckResourceAttr("snowflake_masking_policy.test", "comment", ""), @@ -72,7 +74,7 @@ func TestAcc_MaskingPolicy(t *testing.T) { }) } -func maskingPolicyConfig(n string, name string, comment string, databaseName string, schemaName string) string { +func maskingPolicyConfig(name string, comment string, databaseName string, schemaName string) string { return fmt.Sprintf(` resource "snowflake_masking_policy" "test" { name = "%s" @@ -91,7 +93,7 @@ resource "snowflake_masking_policy" "test" { `, name, databaseName, schemaName, comment) } -func maskingPolicyConfigMultiline(n string, name string, databaseName string, schemaName string) string { +func maskingPolicyConfigMultiline(name string, databaseName string, schemaName string) string { return fmt.Sprintf(` resource "snowflake_masking_policy" "test" { name = "%s" @@ -176,3 +178,41 @@ resource "snowflake_masking_policy" "test" { } `, name, databaseName, schemaName) } + +func TestAcc_MaskingPolicy_migrateFromVersion_0_94_1(t *testing.T) { + id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + resourceName := "snowflake_masking_policy.test" + comment := "foo" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + + Steps: []resource.TestStep{ + { + ExternalProviders: map[string]resource.ExternalProvider{ + "snowflake": { + VersionConstraint: "=0.94.1", + Source: "Snowflake-Labs/snowflake", + }, + }, + Config: maskingPolicyConfig(id.Name(), comment, acc.TestDatabaseName, acc.TestSchemaName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "qualified_name", id.FullyQualifiedName()), + ), + }, + { + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + Config: maskingPolicyConfig(id.Name(), comment, acc.TestDatabaseName, acc.TestSchemaName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), + resource.TestCheckNoResourceAttr(resourceName, "qualified_name"), + ), + }, + }, + }) +} diff --git a/pkg/resources/masking_policy_state_upgraders.go b/pkg/resources/masking_policy_state_upgraders.go new file mode 100644 index 00000000000..8401f4cc141 --- /dev/null +++ b/pkg/resources/masking_policy_state_upgraders.go @@ -0,0 +1,16 @@ +package resources + +import ( + "context" +) + +func v0_94_1_MaskingPolicyStateUpgrader(ctx context.Context, rawState map[string]any, meta any) (map[string]any, error) { + if rawState == nil { + return rawState, nil + } + + rawState[FullyQualifiedNameAttributeName] = rawState["qualified_name"] + delete(rawState, "qualified_name") + + return rawState, nil +} diff --git a/pkg/resources/materialized_view.go b/pkg/resources/materialized_view.go index 18c16b57c9a..e2801504180 100644 --- a/pkg/resources/materialized_view.go +++ b/pkg/resources/materialized_view.go @@ -6,10 +6,12 @@ import ( "log" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -61,7 +63,8 @@ var materializedViewSchema = map[string]*schema.Schema{ ForceNew: true, DiffSuppressFunc: DiffSuppressStatement, }, - "tag": tagReferenceSchema, + "tag": tagReferenceSchema, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // MaterializedView returns a pointer to the resource representing a view. @@ -72,6 +75,10 @@ func MaterializedView() *schema.Resource { Update: UpdateMaterializedView, Delete: DeleteMaterializedView, + CustomizeDiff: customdiff.All( + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), + ), + Schema: materializedViewSchema, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, @@ -142,7 +149,9 @@ func ReadMaterializedView(d *schema.ResourceData, meta interface{}) error { d.SetId("") return nil } - + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } if err := d.Set("name", materializedView.Name); err != nil { return err } diff --git a/pkg/resources/materialized_view_acceptance_test.go b/pkg/resources/materialized_view_acceptance_test.go index 6b24a143ac2..f77838c3a16 100644 --- a/pkg/resources/materialized_view_acceptance_test.go +++ b/pkg/resources/materialized_view_acceptance_test.go @@ -160,6 +160,7 @@ func TestAcc_MaterializedView_Rename(t *testing.T) { Config: materializedViewConfig(acc.TestWarehouseName, tableId, viewId, queryEscaped, "Terraform test resource", true, false), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_materialized_view.test", "name", viewId.Name()), + resource.TestCheckResourceAttr("snowflake_materialized_view.test", "fully_qualified_name", viewId.FullyQualifiedName()), ), }, // rename with one param change @@ -167,6 +168,7 @@ func TestAcc_MaterializedView_Rename(t *testing.T) { Config: materializedViewConfig(acc.TestWarehouseName, tableId, newViewId, queryEscaped, "Terraform test resource", false, false), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_materialized_view.test", "name", newViewId.Name()), + resource.TestCheckResourceAttr("snowflake_materialized_view.test", "fully_qualified_name", newViewId.FullyQualifiedName()), ), }, }, diff --git a/pkg/resources/network_policy.go b/pkg/resources/network_policy.go index 8ca3e82f94d..381740912f4 100644 --- a/pkg/resources/network_policy.go +++ b/pkg/resources/network_policy.go @@ -79,6 +79,7 @@ var networkPolicySchema = map[string]*schema.Schema{ Schema: schemas.DescribeNetworkPolicySchema, }, }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func NetworkPolicy() *schema.Resource { @@ -111,6 +112,7 @@ func NetworkPolicy() *schema.Resource { "allowed_ip_list", "blocked_ip_list", ), + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), ), Importer: &schema.ResourceImporter{ @@ -184,6 +186,9 @@ func ReadContextNetworkPolicy(ctx context.Context, d *schema.ResourceData, meta }, } } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if err = d.Set("name", sdk.NewAccountObjectIdentifier(networkPolicy.Name).Name()); err != nil { return diag.FromErr(err) diff --git a/pkg/resources/network_policy_acceptance_test.go b/pkg/resources/network_policy_acceptance_test.go index e552fe84e55..3c3c538e2a6 100644 --- a/pkg/resources/network_policy_acceptance_test.go +++ b/pkg/resources/network_policy_acceptance_test.go @@ -324,6 +324,7 @@ func TestAcc_NetworkPolicy_Rename(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("snowflake_network_policy.test", "id", id.Name()), resource.TestCheckResourceAttr("snowflake_network_policy.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_network_policy.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_network_policy.test", "show_output.0.name", id.Name()), ), }, @@ -337,6 +338,7 @@ func TestAcc_NetworkPolicy_Rename(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("snowflake_network_policy.test", "id", newId.Name()), resource.TestCheckResourceAttr("snowflake_network_policy.test", "name", newId.Name()), + resource.TestCheckResourceAttr("snowflake_network_policy.test", "fully_qualified_name", newId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_network_policy.test", "show_output.0.name", newId.Name()), ), }, diff --git a/pkg/resources/network_rule.go b/pkg/resources/network_rule.go index 52a6a68dafb..df138793ba5 100644 --- a/pkg/resources/network_rule.go +++ b/pkg/resources/network_rule.go @@ -7,7 +7,9 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/go-cty/cty" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -58,16 +60,13 @@ var networkRuleSchema = map[string]*schema.Schema{ Optional: true, Description: "Specifies a comment for the network rule.", }, - "qualified_name": { - Type: schema.TypeString, - Computed: true, - Description: "Qualified name of the network rule.", - }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // NetworkRule returns a pointer to the resource representing a network rule. func NetworkRule() *schema.Resource { return &schema.Resource{ + SchemaVersion: 1, CreateContext: CreateContextNetworkRule, ReadContext: ReadContextNetworkRule, UpdateContext: UpdateContextNetworkRule, @@ -77,6 +76,15 @@ func NetworkRule() *schema.Resource { Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, + + StateUpgraders: []schema.StateUpgrader{ + { + Version: 0, + // setting type to cty.EmptyObject is a bit hacky here but following https://developer.hashicorp.com/terraform/plugin/framework/migrating/resources/state-upgrade#sdkv2-1 would require lots of repetitive code; this should work with cty.EmptyObject + Type: cty.EmptyObject, + Upgrade: v0_94_1_NetworkRuleStateUpgrader, + }, + }, } } @@ -168,7 +176,7 @@ func ReadContextNetworkRule(ctx context.Context, d *schema.ResourceData, meta in if err = d.Set("comment", networkRule.Comment); err != nil { return diag.FromErr(err) } - if err = d.Set("qualified_name", id.FullyQualifiedName()); err != nil { + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { return diag.FromErr(err) } diff --git a/pkg/resources/network_rule_acceptance_test.go b/pkg/resources/network_rule_acceptance_test.go index a9102801bbd..0c4e274d889 100644 --- a/pkg/resources/network_rule_acceptance_test.go +++ b/pkg/resources/network_rule_acceptance_test.go @@ -121,3 +121,40 @@ resource "snowflake_network_rule" "test" { } `, name, database, schema, networkRuleComment) } + +func TestAcc_NetworkRule_migrateFromVersion_0_94_1(t *testing.T) { + id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + resourceName := "snowflake_network_rule.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + + Steps: []resource.TestStep{ + { + ExternalProviders: map[string]resource.ExternalProvider{ + "snowflake": { + VersionConstraint: "=0.94.1", + Source: "Snowflake-Labs/snowflake", + }, + }, + Config: networkRuleIpv4(id.Name(), acc.TestDatabaseName, acc.TestSchemaName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "qualified_name", id.FullyQualifiedName()), + ), + }, + { + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + Config: networkRuleIpv4(id.Name(), acc.TestDatabaseName, acc.TestSchemaName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), + resource.TestCheckNoResourceAttr(resourceName, "qualified_name"), + ), + }, + }, + }) +} diff --git a/pkg/resources/network_rule_state_upgraders.go b/pkg/resources/network_rule_state_upgraders.go new file mode 100644 index 00000000000..6180e6a4b6e --- /dev/null +++ b/pkg/resources/network_rule_state_upgraders.go @@ -0,0 +1,16 @@ +package resources + +import ( + "context" +) + +func v0_94_1_NetworkRuleStateUpgrader(ctx context.Context, rawState map[string]any, meta any) (map[string]any, error) { + if rawState == nil { + return rawState, nil + } + + rawState[FullyQualifiedNameAttributeName] = rawState["qualified_name"] + delete(rawState, "qualified_name") + + return rawState, nil +} diff --git a/pkg/resources/notification_integration.go b/pkg/resources/notification_integration.go index a8db893f6e0..a69e474f331 100644 --- a/pkg/resources/notification_integration.go +++ b/pkg/resources/notification_integration.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" @@ -144,6 +145,7 @@ var notificationIntegrationSchema = map[string]*schema.Schema{ Computed: true, Description: "The GCP service account identifier that Snowflake will use when assuming the GCP role", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // NotificationIntegration returns a pointer to the resource representing a notification integration. @@ -244,7 +246,9 @@ func ReadNotificationIntegration(d *schema.ResourceData, meta interface{}) error if c := integration.Category; c != "NOTIFICATION" { return fmt.Errorf("expected %v to be a NOTIFICATION integration, got %v", id, c) } - + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } if err := d.Set("name", integration.Name); err != nil { return err } diff --git a/pkg/resources/notification_integration_acceptance_test.go b/pkg/resources/notification_integration_acceptance_test.go index 826bc7f2d84..fc473440aa4 100644 --- a/pkg/resources/notification_integration_acceptance_test.go +++ b/pkg/resources/notification_integration_acceptance_test.go @@ -13,7 +13,7 @@ import ( ) func TestAcc_NotificationIntegration_AutoGoogle(t *testing.T) { - accName := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() const gcpPubsubSubscriptionName = "projects/project-1234/subscriptions/sub2" const gcpOtherPubsubSubscriptionName = "projects/project-1234/subscriptions/other" @@ -27,10 +27,11 @@ func TestAcc_NotificationIntegration_AutoGoogle(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.NotificationIntegration), Steps: []resource.TestStep{ { - Config: googleAutoConfig(accName, gcpPubsubSubscriptionName), + Config: googleAutoConfig(id.Name(), gcpPubsubSubscriptionName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_notification_integration.test", "enabled", "true"), - resource.TestCheckResourceAttr("snowflake_notification_integration.test", "name", accName), + resource.TestCheckResourceAttr("snowflake_notification_integration.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_notification_integration.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_notification_integration.test", "notification_provider", "GCP_PUBSUB"), resource.TestCheckResourceAttr("snowflake_notification_integration.test", "gcp_pubsub_subscription_name", gcpPubsubSubscriptionName), resource.TestCheckResourceAttr("snowflake_notification_integration.test", "direction", "INBOUND"), @@ -39,10 +40,11 @@ func TestAcc_NotificationIntegration_AutoGoogle(t *testing.T) { }, // change parameters { - Config: googleAutoConfig(accName, gcpOtherPubsubSubscriptionName), + Config: googleAutoConfig(id.Name(), gcpOtherPubsubSubscriptionName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_notification_integration.test", "enabled", "true"), - resource.TestCheckResourceAttr("snowflake_notification_integration.test", "name", accName), + resource.TestCheckResourceAttr("snowflake_notification_integration.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_notification_integration.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_notification_integration.test", "notification_provider", "GCP_PUBSUB"), resource.TestCheckResourceAttr("snowflake_notification_integration.test", "gcp_pubsub_subscription_name", gcpOtherPubsubSubscriptionName), resource.TestCheckResourceAttr("snowflake_notification_integration.test", "direction", "INBOUND"), diff --git a/pkg/resources/oauth_integration_for_custom_clients.go b/pkg/resources/oauth_integration_for_custom_clients.go index c7b549f3a16..c287b87f95e 100644 --- a/pkg/resources/oauth_integration_for_custom_clients.go +++ b/pkg/resources/oauth_integration_for_custom_clients.go @@ -144,6 +144,7 @@ var oauthIntegrationForCustomClientsSchema = map[string]*schema.Schema{ Schema: schemas.DescribeOauthIntegrationForCustomClients, }, }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func OauthIntegrationForCustomClients() *schema.Resource { @@ -371,7 +372,9 @@ func ReadContextOauthIntegrationForCustomClients(withExternalChangesMarking bool if c := integration.Category; c != sdk.SecurityIntegrationCategory { return diag.FromErr(fmt.Errorf("expected %v to be a %s integration, got %v", id, sdk.SecurityIntegrationCategory, c)) } - + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if err := d.Set("name", integration.Name); err != nil { return diag.FromErr(err) } diff --git a/pkg/resources/oauth_integration_for_custom_clients_acceptance_test.go b/pkg/resources/oauth_integration_for_custom_clients_acceptance_test.go index 2bc16b4af16..4eccc8625c1 100644 --- a/pkg/resources/oauth_integration_for_custom_clients_acceptance_test.go +++ b/pkg/resources/oauth_integration_for_custom_clients_acceptance_test.go @@ -413,6 +413,7 @@ func TestAcc_OauthIntegrationForCustomClients_Complete(t *testing.T) { ConfigVariables: configVariables, Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("snowflake_oauth_integration_for_custom_clients.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_oauth_integration_for_custom_clients.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_oauth_integration_for_custom_clients.test", "oauth_client_type", string(sdk.OauthSecurityIntegrationClientTypeConfidential)), resource.TestCheckResourceAttr("snowflake_oauth_integration_for_custom_clients.test", "oauth_redirect_uri", validUrl), resource.TestCheckResourceAttr("snowflake_oauth_integration_for_custom_clients.test", "enabled", "true"), @@ -467,6 +468,7 @@ func TestAcc_OauthIntegrationForCustomClients_Complete(t *testing.T) { ImportState: true, ImportStateCheck: importchecks.ComposeAggregateImportStateCheck( importchecks.TestCheckResourceAttrInstanceState(id.Name(), "name", id.Name()), + importchecks.TestCheckResourceAttrInstanceState(id.Name(), "fully_qualified_name", id.FullyQualifiedName()), importchecks.TestCheckResourceAttrInstanceState(id.Name(), "oauth_client_type", string(sdk.OauthSecurityIntegrationClientTypeConfidential)), importchecks.TestCheckResourceAttrInstanceState(id.Name(), "oauth_redirect_uri", validUrl), importchecks.TestCheckResourceAttrInstanceState(id.Name(), "enabled", "true"), diff --git a/pkg/resources/oauth_integration_for_partner_applications.go b/pkg/resources/oauth_integration_for_partner_applications.go index 4c9c34b1ba1..e419ecf6e64 100644 --- a/pkg/resources/oauth_integration_for_partner_applications.go +++ b/pkg/resources/oauth_integration_for_partner_applications.go @@ -105,6 +105,7 @@ var oauthIntegrationForPartnerApplicationsSchema = map[string]*schema.Schema{ Schema: schemas.DescribeOauthIntegrationForPartnerApplications, }, }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func OauthIntegrationForPartnerApplications() *schema.Resource { @@ -288,7 +289,9 @@ func ReadContextOauthIntegrationForPartnerApplications(withExternalChangesMarkin if c := integration.Category; c != sdk.SecurityIntegrationCategory { return diag.FromErr(fmt.Errorf("expected %v to be a %s integration, got %v", id, sdk.SecurityIntegrationCategory, c)) } - + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if err := d.Set("name", sdk.NewAccountObjectIdentifier(integration.Name).Name()); err != nil { return diag.FromErr(err) } diff --git a/pkg/resources/oauth_integration_for_partner_applications_acceptance_test.go b/pkg/resources/oauth_integration_for_partner_applications_acceptance_test.go index d3f94e12571..89890402532 100644 --- a/pkg/resources/oauth_integration_for_partner_applications_acceptance_test.go +++ b/pkg/resources/oauth_integration_for_partner_applications_acceptance_test.go @@ -579,6 +579,7 @@ func TestAcc_OauthIntegrationForPartnerApplications_Complete(t *testing.T) { ConfigVariables: configVariables, Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("snowflake_oauth_integration_for_partner_applications.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_oauth_integration_for_partner_applications.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_oauth_integration_for_partner_applications.test", "oauth_client", string(sdk.OauthSecurityIntegrationClientTableauServer)), resource.TestCheckNoResourceAttr("snowflake_oauth_integration_for_partner_applications.test", "oauth_redirect_uri"), resource.TestCheckResourceAttr("snowflake_oauth_integration_for_partner_applications.test", "enabled", "true"), @@ -620,6 +621,7 @@ func TestAcc_OauthIntegrationForPartnerApplications_Complete(t *testing.T) { ImportState: true, ImportStateCheck: importchecks.ComposeAggregateImportStateCheck( importchecks.TestCheckResourceAttrInstanceState(id.Name(), "name", id.Name()), + importchecks.TestCheckResourceAttrInstanceState(id.Name(), "fully_qualified_name", id.FullyQualifiedName()), importchecks.TestCheckResourceAttrInstanceState(id.Name(), "oauth_client", string(sdk.OauthSecurityIntegrationClientTableauServer)), importchecks.TestCheckResourceAttrInstanceState(id.Name(), "enabled", "true"), importchecks.TestCheckResourceAttrInstanceState(id.Name(), "oauth_issue_refresh_tokens", "false"), diff --git a/pkg/resources/password_policy.go b/pkg/resources/password_policy.go index 7035fc38956..f90411ab8c8 100644 --- a/pkg/resources/password_policy.go +++ b/pkg/resources/password_policy.go @@ -4,9 +4,12 @@ import ( "context" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/go-cty/cty" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) @@ -131,25 +134,35 @@ var passwordPolicySchema = map[string]*schema.Schema{ Optional: true, Description: "Adds a comment or overwrites an existing comment for the password policy.", }, - "qualified_name": { - Type: schema.TypeString, - Computed: true, - Description: "The qualified name for the password policy.", - }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func PasswordPolicy() *schema.Resource { return &schema.Resource{ - Description: "A password policy specifies the requirements that must be met to create and reset a password to authenticate to Snowflake.", - Create: CreatePasswordPolicy, - Read: ReadPasswordPolicy, - Update: UpdatePasswordPolicy, - Delete: DeletePasswordPolicy, + SchemaVersion: 1, + Description: "A password policy specifies the requirements that must be met to create and reset a password to authenticate to Snowflake.", + Create: CreatePasswordPolicy, + Read: ReadPasswordPolicy, + Update: UpdatePasswordPolicy, + Delete: DeletePasswordPolicy, + + CustomizeDiff: customdiff.All( + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), + ), Schema: passwordPolicySchema, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, + + StateUpgraders: []schema.StateUpgrader{ + { + Version: 0, + // setting type to cty.EmptyObject is a bit hacky here but following https://developer.hashicorp.com/terraform/plugin/framework/migrating/resources/state-upgrade#sdkv2-1 would require lots of repetitive code; this should work with cty.EmptyObject + Type: cty.EmptyObject, + Upgrade: v0_94_1_PasswordPolicyStateUpgrader, + }, + }, } } @@ -194,14 +207,13 @@ func CreatePasswordPolicy(d *schema.ResourceData, meta interface{}) error { func ReadPasswordPolicy(d *schema.ResourceData, meta interface{}) error { client := meta.(*provider.Context).Client ctx := context.Background() - objectIdentifier := helpers.DecodeSnowflakeID(d.Id()).(sdk.SchemaObjectIdentifier) + id := helpers.DecodeSnowflakeID(d.Id()).(sdk.SchemaObjectIdentifier) - if err := d.Set("qualified_name", objectIdentifier.FullyQualifiedName()); err != nil { + passwordPolicy, err := client.PasswordPolicies.ShowByID(ctx, id) + if err != nil { return err } - - passwordPolicy, err := client.PasswordPolicies.ShowByID(ctx, objectIdentifier) - if err != nil { + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { return err } @@ -217,7 +229,7 @@ func ReadPasswordPolicy(d *schema.ResourceData, meta interface{}) error { if err := d.Set("comment", passwordPolicy.Comment); err != nil { return err } - passwordPolicyDetails, err := client.PasswordPolicies.Describe(ctx, objectIdentifier) + passwordPolicyDetails, err := client.PasswordPolicies.Describe(ctx, id) if err != nil { return err } diff --git a/pkg/resources/password_policy_acceptance_test.go b/pkg/resources/password_policy_acceptance_test.go index 189bae44d62..6fef84a84d3 100644 --- a/pkg/resources/password_policy_acceptance_test.go +++ b/pkg/resources/password_policy_acceptance_test.go @@ -1,11 +1,13 @@ package resources_test import ( + "fmt" "testing" "github.com/hashicorp/terraform-plugin-testing/plancheck" acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider/resources" "github.com/hashicorp/terraform-plugin-testing/config" @@ -102,12 +104,12 @@ func TestAcc_PasswordPolicy(t *testing.T) { } func TestAcc_PasswordPolicyMaxAgeDays(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - newName := acc.TestClient().Ids.Alpha() + oldId := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + newId := acc.TestClient().Ids.RandomSchemaObjectIdentifier() m := func(maxAgeDays int) map[string]config.Variable { return map[string]config.Variable{ - "name": config.StringVariable(name), + "name": config.StringVariable(oldId.Name()), "database": config.StringVariable(acc.TestDatabaseName), "schema": config.StringVariable(acc.TestSchemaName), "max_age_days": config.IntegerVariable(maxAgeDays), @@ -115,7 +117,7 @@ func TestAcc_PasswordPolicyMaxAgeDays(t *testing.T) { } configValueWithNewName := m(10) - configValueWithNewName["name"] = config.StringVariable(newName) + configValueWithNewName["name"] = config.StringVariable(newId.Name()) resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, @@ -131,6 +133,7 @@ func TestAcc_PasswordPolicyMaxAgeDays(t *testing.T) { ConfigVariables: m(0), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_password_policy.pa", "max_age_days", "0"), + resource.TestCheckResourceAttr("snowflake_password_policy.pa", "fully_qualified_name", oldId.FullyQualifiedName()), ), }, { @@ -152,7 +155,7 @@ func TestAcc_PasswordPolicyMaxAgeDays(t *testing.T) { { ConfigDirectory: acc.ConfigurationDirectory("TestAcc_PasswordPolicy_noOptionals"), ConfigVariables: map[string]config.Variable{ - "name": config.StringVariable(newName), + "name": config.StringVariable(newId.Name()), "database": config.StringVariable(acc.TestDatabaseName), "schema": config.StringVariable(acc.TestSchemaName), }, @@ -162,14 +165,15 @@ func TestAcc_PasswordPolicyMaxAgeDays(t *testing.T) { }, }, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_password_policy.pa", "name", newName), + resource.TestCheckResourceAttr("snowflake_password_policy.pa", "name", newId.Name()), + resource.TestCheckResourceAttr("snowflake_password_policy.pa", "fully_qualified_name", newId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_password_policy.pa", "max_age_days", "90"), ), }, { ConfigDirectory: acc.ConfigurationDirectory("TestAcc_PasswordPolicy_noOptionals"), ConfigVariables: map[string]config.Variable{ - "name": config.StringVariable(name), + "name": config.StringVariable(oldId.Name()), "database": config.StringVariable(acc.TestDatabaseName), "schema": config.StringVariable(acc.TestSchemaName), }, @@ -180,3 +184,49 @@ func TestAcc_PasswordPolicyMaxAgeDays(t *testing.T) { }, }) } + +func TestAcc_PasswordPolicy_migrateFromVersion_0_94_1(t *testing.T) { + id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + resourceName := "snowflake_password_policy.pa" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + + Steps: []resource.TestStep{ + { + ExternalProviders: map[string]resource.ExternalProvider{ + "snowflake": { + VersionConstraint: "=0.94.1", + Source: "Snowflake-Labs/snowflake", + }, + }, + Config: passwordPolicyBasicConfig(id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "qualified_name", id.FullyQualifiedName()), + ), + }, + { + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + Config: passwordPolicyBasicConfig(id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), + resource.TestCheckNoResourceAttr(resourceName, "qualified_name"), + ), + }, + }, + }) +} + +func passwordPolicyBasicConfig(id sdk.SchemaObjectIdentifier) string { + return fmt.Sprintf(` +resource "snowflake_password_policy" "pa" { + name = "%s" + database = "%s" + schema = "%s" +}`, id.Name(), id.DatabaseName(), id.SchemaName()) +} diff --git a/pkg/resources/password_policy_state_upgraders.go b/pkg/resources/password_policy_state_upgraders.go new file mode 100644 index 00000000000..725f9a69623 --- /dev/null +++ b/pkg/resources/password_policy_state_upgraders.go @@ -0,0 +1,16 @@ +package resources + +import ( + "context" +) + +func v0_94_1_PasswordPolicyStateUpgrader(ctx context.Context, rawState map[string]any, meta any) (map[string]any, error) { + if rawState == nil { + return rawState, nil + } + + rawState[FullyQualifiedNameAttributeName] = rawState["qualified_name"] + delete(rawState, "qualified_name") + + return rawState, nil +} diff --git a/pkg/resources/pipe.go b/pkg/resources/pipe.go index 6d6ddcc446b..208d08e13ab 100644 --- a/pkg/resources/pipe.go +++ b/pkg/resources/pipe.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" @@ -77,6 +78,7 @@ var pipeSchema = map[string]*schema.Schema{ Optional: true, Description: "Specifies the name of the notification integration used for error notifications.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func Pipe() *schema.Resource { @@ -151,10 +153,10 @@ func CreatePipe(d *schema.ResourceData, meta interface{}) error { // ReadPipe implements schema.ReadFunc. func ReadPipe(d *schema.ResourceData, meta interface{}) error { client := meta.(*provider.Context).Client - objectIdentifier := helpers.DecodeSnowflakeID(d.Id()).(sdk.SchemaObjectIdentifier) + id := helpers.DecodeSnowflakeID(d.Id()).(sdk.SchemaObjectIdentifier) ctx := context.Background() - pipe, err := client.Pipes.ShowByID(ctx, objectIdentifier) + pipe, err := client.Pipes.ShowByID(ctx, id) if err != nil { // If not found, mark resource to be removed from state file during apply or refresh log.Printf("[DEBUG] pipe (%s) not found", d.Id()) @@ -162,6 +164,10 @@ func ReadPipe(d *schema.ResourceData, meta interface{}) error { return nil } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } + if err := d.Set("name", pipe.Name); err != nil { return err } diff --git a/pkg/resources/pipe_acceptance_test.go b/pkg/resources/pipe_acceptance_test.go index 5deb743dfbe..de34f99b836 100644 --- a/pkg/resources/pipe_acceptance_test.go +++ b/pkg/resources/pipe_acceptance_test.go @@ -12,7 +12,7 @@ import ( ) func TestAcc_Pipe(t *testing.T) { - accName := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, @@ -23,9 +23,10 @@ func TestAcc_Pipe(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.Pipe), Steps: []resource.TestStep{ { - Config: pipeConfig(accName, acc.TestDatabaseName, acc.TestSchemaName), + Config: pipeConfig(id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_pipe.test", "name", accName), + resource.TestCheckResourceAttr("snowflake_pipe.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_pipe.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_pipe.test", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_pipe.test", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_pipe.test", "comment", "Terraform acceptance test"), diff --git a/pkg/resources/procedure.go b/pkg/resources/procedure.go index 118bcde2534..49e2b3d559d 100644 --- a/pkg/resources/procedure.go +++ b/pkg/resources/procedure.go @@ -9,9 +9,11 @@ import ( "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/hashicorp/go-cty/cty" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) @@ -171,6 +173,7 @@ var procedureSchema = map[string]*schema.Schema{ ForceNew: true, Description: "The handler method for Java / Python procedures.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // Procedure returns a pointer to the resource representing a stored procedure. @@ -183,6 +186,10 @@ func Procedure() *schema.Resource { UpdateContext: UpdateContextProcedure, DeleteContext: DeleteContextProcedure, + CustomizeDiff: customdiff.All( + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), + ), + Schema: procedureSchema, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, @@ -525,6 +532,9 @@ func ReadContextProcedure(ctx context.Context, d *schema.ResourceData, meta inte client := meta.(*provider.Context).Client id := sdk.NewSchemaObjectIdentifierFromFullyQualifiedName(d.Id()) + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if err := d.Set("name", id.Name()); err != nil { return diag.FromErr(err) } diff --git a/pkg/resources/procedure_acceptance_test.go b/pkg/resources/procedure_acceptance_test.go index 29e89243c15..9ff3dc67bdb 100644 --- a/pkg/resources/procedure_acceptance_test.go +++ b/pkg/resources/procedure_acceptance_test.go @@ -17,13 +17,13 @@ import ( func testAccProcedure(t *testing.T, configDirectory string) { t.Helper() - name := acc.TestClient().Ids.Alpha() - newName := acc.TestClient().Ids.Alpha() + oldId := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + newId := acc.TestClient().Ids.RandomSchemaObjectIdentifier() resourceName := "snowflake_procedure.p" m := func() map[string]config.Variable { return map[string]config.Variable{ - "name": config.StringVariable(name), + "name": config.StringVariable(oldId.Name()), "database": config.StringVariable(acc.TestDatabaseName), "schema": config.StringVariable(acc.TestSchemaName), "comment": config.StringVariable("Terraform acceptance test"), @@ -31,7 +31,7 @@ func testAccProcedure(t *testing.T, configDirectory string) { } } variableSet2 := m() - variableSet2["name"] = config.StringVariable(newName) + variableSet2["name"] = config.StringVariable(newId.Name()) variableSet2["comment"] = config.StringVariable("Terraform acceptance test - updated") variableSet2["execute_as"] = config.StringVariable("OWNER") @@ -52,7 +52,8 @@ func testAccProcedure(t *testing.T, configDirectory string) { ConfigDirectory: acc.ConfigurationDirectory(configDirectory), ConfigVariables: m(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "name", oldId.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", oldId.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "database", acc.TestDatabaseName), resource.TestCheckResourceAttr(resourceName, "schema", acc.TestSchemaName), resource.TestCheckResourceAttr(resourceName, "comment", "Terraform acceptance test"), @@ -76,7 +77,8 @@ func testAccProcedure(t *testing.T, configDirectory string) { }, }, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", newName), + resource.TestCheckResourceAttr(resourceName, "name", newId.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", newId.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "database", acc.TestDatabaseName), resource.TestCheckResourceAttr(resourceName, "schema", acc.TestSchemaName), resource.TestCheckResourceAttr(resourceName, "comment", "Terraform acceptance test - updated"), diff --git a/pkg/resources/resource_monitor.go b/pkg/resources/resource_monitor.go index a79f52d2457..bf862b715b3 100644 --- a/pkg/resources/resource_monitor.go +++ b/pkg/resources/resource_monitor.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" @@ -99,6 +100,7 @@ var resourceMonitorSchema = map[string]*schema.Schema{ Description: "A list of warehouses to apply the resource monitor to.", Elem: &schema.Schema{Type: schema.TypeString}, }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // ResourceMonitor returns a pointer to the resource representing a resource monitor. @@ -229,13 +231,16 @@ func CreateResourceMonitor(d *schema.ResourceData, meta interface{}) error { // ReadResourceMonitor implements schema.ReadFunc. func ReadResourceMonitor(d *schema.ResourceData, meta interface{}) error { client := meta.(*provider.Context).Client - objectIdentifier := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier) + id := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier) ctx := context.Background() - resourceMonitor, err := client.ResourceMonitors.ShowByID(ctx, objectIdentifier) + resourceMonitor, err := client.ResourceMonitors.ShowByID(ctx, id) if err != nil { return err } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } if err := d.Set("name", resourceMonitor.Name); err != nil { return err diff --git a/pkg/resources/resource_monitor_acceptance_test.go b/pkg/resources/resource_monitor_acceptance_test.go index 7d207a0bf09..54aeaf7146e 100644 --- a/pkg/resources/resource_monitor_acceptance_test.go +++ b/pkg/resources/resource_monitor_acceptance_test.go @@ -18,7 +18,7 @@ import ( func TestAcc_ResourceMonitor(t *testing.T) { // TODO test more attributes - name := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, @@ -29,9 +29,10 @@ func TestAcc_ResourceMonitor(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.ResourceMonitor), Steps: []resource.TestStep{ { - Config: resourceMonitorConfig(name, acc.TestWarehouseName), + Config: resourceMonitorConfig(id.Name(), acc.TestWarehouseName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "name", name), + resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "credit_quota", "100"), resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "set_for_account", "false"), resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "notify_triggers.0", "40"), @@ -41,9 +42,10 @@ func TestAcc_ResourceMonitor(t *testing.T) { }, // CHANGE PROPERTIES { - Config: resourceMonitorConfig2(name, 75), + Config: resourceMonitorConfig2(id.Name(), 75), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "name", name), + resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "credit_quota", "150"), resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "set_for_account", "true"), resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "notify_triggers.0", "50"), @@ -53,9 +55,10 @@ func TestAcc_ResourceMonitor(t *testing.T) { }, // CHANGE JUST suspend_trigger; proves https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2316 { - Config: resourceMonitorConfig2(name, 60), + Config: resourceMonitorConfig2(id.Name(), 60), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "name", name), + resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "credit_quota", "150"), resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "set_for_account", "true"), resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "notify_triggers.0", "50"), diff --git a/pkg/resources/row_access_policy.go b/pkg/resources/row_access_policy.go index f0b119621fb..544ec1cad23 100644 --- a/pkg/resources/row_access_policy.go +++ b/pkg/resources/row_access_policy.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" @@ -50,6 +51,7 @@ var rowAccessPolicySchema = map[string]*schema.Schema{ Optional: true, Description: "Specifies a comment for the row access policy.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // RowAccessPolicy returns a pointer to the resource representing a row access policy. @@ -115,6 +117,9 @@ func ReadRowAccessPolicy(d *schema.ResourceData, meta interface{}) error { d.SetId("") return nil } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } if err := d.Set("name", rowAccessPolicy.Name); err != nil { return err diff --git a/pkg/resources/row_access_policy_acceptance_test.go b/pkg/resources/row_access_policy_acceptance_test.go index a24ed1f6566..c9544c203a0 100644 --- a/pkg/resources/row_access_policy_acceptance_test.go +++ b/pkg/resources/row_access_policy_acceptance_test.go @@ -12,10 +12,10 @@ import ( ) func TestAcc_RowAccessPolicy(t *testing.T) { - name := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() m := func() map[string]config.Variable { return map[string]config.Variable{ - "name": config.StringVariable(name), + "name": config.StringVariable(id.Name()), "database": config.StringVariable(acc.TestDatabaseName), "schema": config.StringVariable(acc.TestSchemaName), } @@ -33,7 +33,8 @@ func TestAcc_RowAccessPolicy(t *testing.T) { ConfigDirectory: config.TestStepDirectory(), ConfigVariables: m(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "name", name), + resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "comment", "Terraform acceptance test"), @@ -47,7 +48,8 @@ func TestAcc_RowAccessPolicy(t *testing.T) { ConfigDirectory: config.TestStepDirectory(), ConfigVariables: m(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "name", name), + resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "comment", "Terraform acceptance test - changed comment"), @@ -61,7 +63,8 @@ func TestAcc_RowAccessPolicy(t *testing.T) { ConfigDirectory: config.TestStepDirectory(), ConfigVariables: m(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "name", name), + resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_row_access_policy.test", "comment", "Terraform acceptance test - changed comment"), diff --git a/pkg/resources/saml2_integration.go b/pkg/resources/saml2_integration.go index f1261391fc1..82a834d44ec 100644 --- a/pkg/resources/saml2_integration.go +++ b/pkg/resources/saml2_integration.go @@ -149,6 +149,7 @@ var saml2IntegrationSchema = map[string]*schema.Schema{ Schema: schemas.DescribeSaml2IntegrationSchema, }, }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func SAML2Integration() *schema.Resource { @@ -478,6 +479,9 @@ func ReadContextSAML2Integration(withExternalChangesMarking bool) schema.ReadCon if c := integration.Category; c != sdk.SecurityIntegrationCategory { return diag.FromErr(fmt.Errorf("expected %v to be a %s integration, got %v", id, sdk.SecurityIntegrationCategory, c)) } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if err := d.Set("name", sdk.NewAccountObjectIdentifier(integration.Name).Name()); err != nil { return diag.FromErr(err) diff --git a/pkg/resources/saml2_integration_acceptance_test.go b/pkg/resources/saml2_integration_acceptance_test.go index 318fafd3c4b..fc3d1128524 100644 --- a/pkg/resources/saml2_integration_acceptance_test.go +++ b/pkg/resources/saml2_integration_acceptance_test.go @@ -592,6 +592,7 @@ func TestAcc_Saml2Integration_complete(t *testing.T) { ConfigVariables: m(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("snowflake_saml2_integration.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_saml2_integration.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_saml2_integration.test", "enabled", "true"), resource.TestCheckResourceAttr("snowflake_saml2_integration.test", "saml2_issuer", issuer), resource.TestCheckResourceAttr("snowflake_saml2_integration.test", "saml2_sso_url", validUrl), @@ -648,6 +649,7 @@ func TestAcc_Saml2Integration_complete(t *testing.T) { ImportState: true, ImportStateCheck: importchecks.ComposeAggregateImportStateCheck( importchecks.TestCheckResourceAttrInstanceState(id.Name(), "name", id.Name()), + importchecks.TestCheckResourceAttrInstanceState(id.Name(), "fully_qualified_name", id.FullyQualifiedName()), importchecks.TestCheckResourceAttrInstanceState(id.Name(), "enabled", "true"), importchecks.TestCheckResourceAttrInstanceState(id.Name(), "saml2_issuer", issuer), importchecks.TestCheckResourceAttrInstanceState(id.Name(), "saml2_sso_url", validUrl), diff --git a/pkg/resources/schema.go b/pkg/resources/schema.go index 57c2baf88ba..2a0e39ef791 100644 --- a/pkg/resources/schema.go +++ b/pkg/resources/schema.go @@ -82,6 +82,7 @@ var schemaSchema = map[string]*schema.Schema{ Schema: schemas.ShowSchemaParametersSchema, }, }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // Schema returns a pointer to the resource representing a schema. @@ -98,6 +99,7 @@ func Schema() *schema.Resource { CustomizeDiff: customdiff.All( ComputedIfAnyAttributeChanged(ShowOutputAttributeName, "name", "comment", "with_managed_access", "is_transient"), ComputedIfAnyAttributeChanged(DescribeOutputAttributeName, "name"), + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), // TODO [SNOW-1348101]: use list from schema parameters definition instead listing all here (after moving to the SDK) ComputedIfAnyAttributeChanged(ParametersAttributeName, strings.ToLower(string(sdk.ObjectParameterDataRetentionTimeInDays)), @@ -254,6 +256,9 @@ func ReadContextSchema(withExternalChangesMarking bool) schema.ReadContextFunc { } return diag.FromErr(err) } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if err := d.Set("name", schema.Name); err != nil { return diag.FromErr(err) } diff --git a/pkg/resources/schema_acceptance_test.go b/pkg/resources/schema_acceptance_test.go index d07397a08e1..fe0d041f81e 100644 --- a/pkg/resources/schema_acceptance_test.go +++ b/pkg/resources/schema_acceptance_test.go @@ -402,8 +402,8 @@ func TestAcc_Schema_complete(t *testing.T) { } func TestAcc_Schema_Rename(t *testing.T) { - oldSchemaName := acc.TestClient().Ids.Alpha() - newSchemaName := acc.TestClient().Ids.Alpha() + oldId := acc.TestClient().Ids.RandomDatabaseObjectIdentifier() + newId := acc.TestClient().Ids.RandomDatabaseObjectIdentifier() comment := "Terraform acceptance test" resource.Test(t, resource.TestCase{ @@ -417,12 +417,13 @@ func TestAcc_Schema_Rename(t *testing.T) { { ConfigDirectory: config.TestNameDirectory(), ConfigVariables: map[string]config.Variable{ - "name": config.StringVariable(oldSchemaName), + "name": config.StringVariable(oldId.Name()), "database": config.StringVariable(acc.TestDatabaseName), "comment": config.StringVariable(comment), }, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_schema.test", "name", oldSchemaName), + resource.TestCheckResourceAttr("snowflake_schema.test", "name", oldId.Name()), + resource.TestCheckResourceAttr("snowflake_schema.test", "fully_qualified_name", oldId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_schema.test", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_schema.test", "comment", comment), ), @@ -430,7 +431,7 @@ func TestAcc_Schema_Rename(t *testing.T) { { ConfigDirectory: config.TestNameDirectory(), ConfigVariables: map[string]config.Variable{ - "name": config.StringVariable(newSchemaName), + "name": config.StringVariable(newId.Name()), "database": config.StringVariable(acc.TestDatabaseName), "comment": config.StringVariable(comment), }, @@ -440,7 +441,8 @@ func TestAcc_Schema_Rename(t *testing.T) { }, }, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_schema.test", "name", newSchemaName), + resource.TestCheckResourceAttr("snowflake_schema.test", "name", newId.Name()), + resource.TestCheckResourceAttr("snowflake_schema.test", "fully_qualified_name", newId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_schema.test", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_schema.test", "comment", comment), ), diff --git a/pkg/resources/scim_integration.go b/pkg/resources/scim_integration.go index ba78acbeac8..6fb91db0446 100644 --- a/pkg/resources/scim_integration.go +++ b/pkg/resources/scim_integration.go @@ -90,6 +90,7 @@ var scimIntegrationSchema = map[string]*schema.Schema{ Schema: schemas.DescribeScimSecurityIntegrationSchema, }, }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func SCIMIntegration() *schema.Resource { @@ -271,6 +272,9 @@ func ReadContextSCIMIntegration(withExternalChangesMarking bool) schema.ReadCont } return diag.FromErr(err) } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if c := integration.Category; c != sdk.SecurityIntegrationCategory { return diag.FromErr(fmt.Errorf("expected %v to be a SECURITY integration, got %v", id, c)) diff --git a/pkg/resources/scim_integration_acceptance_test.go b/pkg/resources/scim_integration_acceptance_test.go index 159b31e8740..1ae06e9413a 100644 --- a/pkg/resources/scim_integration_acceptance_test.go +++ b/pkg/resources/scim_integration_acceptance_test.go @@ -134,6 +134,7 @@ func TestAcc_ScimIntegration_basic(t *testing.T) { ImportState: true, ImportStateCheck: importchecks.ComposeImportStateCheck( importchecks.TestCheckResourceAttrInstanceState(id.Name(), "name", id.Name()), + importchecks.TestCheckResourceAttrInstanceState(id.Name(), "fully_qualified_name", id.FullyQualifiedName()), importchecks.TestCheckResourceAttrInstanceState(id.Name(), "enabled", "true"), importchecks.TestCheckResourceAttrInstanceState(id.Name(), "scim_client", "OKTA"), importchecks.TestCheckResourceAttrInstanceState(id.Name(), "run_as_role", role2.Name()), @@ -189,6 +190,7 @@ func TestAcc_ScimIntegration_complete(t *testing.T) { ConfigVariables: m(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_scim_integration.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_scim_integration.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_scim_integration.test", "enabled", "false"), resource.TestCheckResourceAttr("snowflake_scim_integration.test", "scim_client", "GENERIC"), resource.TestCheckResourceAttr("snowflake_scim_integration.test", "run_as_role", role.Name()), diff --git a/pkg/resources/secondary_database.go b/pkg/resources/secondary_database.go index 111947a39e1..9363a3e26dc 100644 --- a/pkg/resources/secondary_database.go +++ b/pkg/resources/secondary_database.go @@ -7,8 +7,10 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -35,6 +37,7 @@ var secondaryDatabaseSchema = map[string]*schema.Schema{ Optional: true, Description: "Specifies a comment for the database.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func SecondaryDatabase() *schema.Resource { @@ -45,8 +48,11 @@ func SecondaryDatabase() *schema.Resource { DeleteContext: DeleteSecondaryDatabase, Description: "A secondary database creates a replica of an existing primary database (i.e. a secondary database). For more information about database replication, see [Introduction to database replication across multiple accounts](https://docs.snowflake.com/en/user-guide/db-replication-intro).", - CustomizeDiff: databaseParametersCustomDiff, - Schema: helpers.MergeMaps(secondaryDatabaseSchema, databaseParametersSchema), + CustomizeDiff: customdiff.All( + databaseParametersCustomDiff, + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), + ), + Schema: helpers.MergeMaps(secondaryDatabaseSchema, databaseParametersSchema), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -170,6 +176,9 @@ func ReadSecondaryDatabase(ctx context.Context, d *schema.ResourceData, meta any if replicationPrimaryDatabase == nil { return diag.FromErr(fmt.Errorf("could not find replication database for %s", secondaryDatabaseId.Name())) } + if err := d.Set(FullyQualifiedNameAttributeName, secondaryDatabaseId.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if err := d.Set("name", secondaryDatabase.Name); err != nil { return diag.FromErr(err) diff --git a/pkg/resources/secondary_database_acceptance_test.go b/pkg/resources/secondary_database_acceptance_test.go index edac458ec54..902922a469f 100644 --- a/pkg/resources/secondary_database_acceptance_test.go +++ b/pkg/resources/secondary_database_acceptance_test.go @@ -91,6 +91,7 @@ func TestAcc_CreateSecondaryDatabase_Basic(t *testing.T) { ConfigDirectory: acc.ConfigurationDirectory("TestAcc_SecondaryDatabase/basic"), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_secondary_database.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_secondary_database.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_secondary_database.test", "as_replica_of", externalPrimaryId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_secondary_database.test", "comment", comment), @@ -118,6 +119,7 @@ func TestAcc_CreateSecondaryDatabase_Basic(t *testing.T) { ConfigDirectory: acc.ConfigurationDirectory("TestAcc_SecondaryDatabase/basic"), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_secondary_database.test", "name", newId.Name()), + resource.TestCheckResourceAttr("snowflake_secondary_database.test", "fully_qualified_name", newId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_secondary_database.test", "as_replica_of", externalPrimaryId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_secondary_database.test", "comment", newComment), diff --git a/pkg/resources/sequence.go b/pkg/resources/sequence.go index e0f98e5bd74..207b78d9091 100644 --- a/pkg/resources/sequence.go +++ b/pkg/resources/sequence.go @@ -4,6 +4,7 @@ import ( "context" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" @@ -58,11 +59,7 @@ var sequenceSchema = map[string]*schema.Schema{ string(sdk.ValuesBehaviorOrder), }, false), }, - "fully_qualified_name": { - Type: schema.TypeString, - Description: "The fully qualified name of the sequence.", - Computed: true, - }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func Sequence() *schema.Resource { @@ -150,7 +147,7 @@ func ReadSequence(d *schema.ResourceData, meta interface{}) error { } } - if err := d.Set("fully_qualified_name", id.FullyQualifiedName()); err != nil { + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { return err } return nil diff --git a/pkg/resources/sequence_acceptance_test.go b/pkg/resources/sequence_acceptance_test.go index 1c7ed6b48d2..c1c901a9152 100644 --- a/pkg/resources/sequence_acceptance_test.go +++ b/pkg/resources/sequence_acceptance_test.go @@ -12,8 +12,8 @@ import ( ) func TestAcc_Sequence(t *testing.T) { - accName := acc.TestClient().Ids.Alpha() - accRename := acc.TestClient().Ids.Alpha() + oldId := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + newId := acc.TestClient().Ids.RandomSchemaObjectIdentifier() resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, @@ -25,34 +25,34 @@ func TestAcc_Sequence(t *testing.T) { Steps: []resource.TestStep{ // CREATE { - Config: sequenceConfig(accName, acc.TestDatabaseName, acc.TestSchemaName), + Config: sequenceConfig(oldId.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "name", accName), + resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "name", oldId.Name()), resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "next_value", "1"), - resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "fully_qualified_name", fmt.Sprintf(`"%v"."%v"."%v"`, acc.TestDatabaseName, acc.TestSchemaName, accName)), + resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "fully_qualified_name", oldId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "ordering", "ORDER"), ), }, // Set comment and rename { - Config: sequenceConfigWithComment(accRename, "look at me I am a comment", acc.TestDatabaseName, acc.TestSchemaName), + Config: sequenceConfigWithComment(newId.Name(), "look at me I am a comment", acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "name", accRename), + resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "name", newId.Name()), resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "comment", "look at me I am a comment"), resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "next_value", "1"), - resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "fully_qualified_name", fmt.Sprintf(`"%v"."%v"."%v"`, acc.TestDatabaseName, acc.TestSchemaName, accRename)), + resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "fully_qualified_name", newId.FullyQualifiedName()), ), }, // Unset comment and set increment { - Config: sequenceConfigWithIncrement(accName, acc.TestDatabaseName, acc.TestSchemaName), + Config: sequenceConfigWithIncrement(oldId.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "name", accName), + resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "name", oldId.Name()), resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "comment", ""), resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "next_value", "1"), resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "increment", "32"), resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "ordering", "NOORDER"), - resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "fully_qualified_name", fmt.Sprintf(`"%v"."%v"."%v"`, acc.TestDatabaseName, acc.TestSchemaName, accName)), + resource.TestCheckResourceAttr("snowflake_sequence.test_sequence", "fully_qualified_name", oldId.FullyQualifiedName()), ), }, // IMPORT diff --git a/pkg/resources/share.go b/pkg/resources/share.go index f0fbcf8c3ab..d14f63bd49e 100644 --- a/pkg/resources/share.go +++ b/pkg/resources/share.go @@ -9,6 +9,7 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -37,6 +38,7 @@ var shareSchema = map[string]*schema.Schema{ "in the form of 'organization_name.account_name", DiffSuppressFunc: ignoreCaseSuppressFunc, }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // Share returns a pointer to the resource representing a share. @@ -162,6 +164,9 @@ func ReadShare(d *schema.ResourceData, meta interface{}) error { if err != nil { return fmt.Errorf("error reading share (%v) err = %w", d.Id(), err) } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } if err := d.Set("name", share.Name.Name()); err != nil { return err } diff --git a/pkg/resources/share_acceptance_test.go b/pkg/resources/share_acceptance_test.go index 7af1a7d3e76..675e53f01d0 100644 --- a/pkg/resources/share_acceptance_test.go +++ b/pkg/resources/share_acceptance_test.go @@ -19,7 +19,7 @@ func TestAcc_Share(t *testing.T) { var account3 string shareComment := "Created by a Terraform acceptance test" - name := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, @@ -30,15 +30,16 @@ func TestAcc_Share(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.Share), Steps: []resource.TestStep{ { - Config: shareConfig(name, shareComment), + Config: shareConfig(id.Name(), shareComment), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_share.test", "name", name), + resource.TestCheckResourceAttr("snowflake_share.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_share.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_share.test", "comment", shareComment), resource.TestCheckResourceAttr("snowflake_share.test", "accounts.#", "0"), ), }, { - Config: shareConfigTwoAccounts(name, shareComment, account2, account3), + Config: shareConfigTwoAccounts(id.Name(), shareComment, account2, account3), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_share.test", "accounts.#", "2"), resource.TestCheckResourceAttr("snowflake_share.test", "accounts.0", account2), @@ -46,14 +47,14 @@ func TestAcc_Share(t *testing.T) { ), }, { - Config: shareConfigOneAccount(name, shareComment, account2), + Config: shareConfigOneAccount(id.Name(), shareComment, account2), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_share.test", "accounts.#", "1"), resource.TestCheckResourceAttr("snowflake_share.test", "accounts.0", account2), ), }, { - Config: shareConfig(name, shareComment), + Config: shareConfig(id.Name(), shareComment), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_share.test", "accounts.#", "0"), ), diff --git a/pkg/resources/shared_database.go b/pkg/resources/shared_database.go index 5f290b05c5e..e5093201f6b 100644 --- a/pkg/resources/shared_database.go +++ b/pkg/resources/shared_database.go @@ -7,8 +7,10 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -36,6 +38,7 @@ var sharedDatabaseSchema = map[string]*schema.Schema{ // ForceNew: true, // Description: "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.", // }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func SharedDatabase() *schema.Resource { @@ -46,6 +49,10 @@ func SharedDatabase() *schema.Resource { DeleteContext: DeleteSharedDatabase, Description: "A shared database creates a database from a share provided by another Snowflake account. For more information about shares, see [Introduction to Secure Data Sharing](https://docs.snowflake.com/en/user-guide/data-sharing-intro).", + CustomizeDiff: customdiff.All( + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), + ), + Schema: helpers.MergeMaps(sharedDatabaseSchema, sharedDatabaseParametersSchema), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, @@ -138,6 +145,9 @@ func ReadSharedDatabase(ctx context.Context, d *schema.ResourceData, meta any) d } return diag.FromErr(err) } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if err := d.Set("name", database.Name); err != nil { return diag.FromErr(err) diff --git a/pkg/resources/shared_database_acceptance_test.go b/pkg/resources/shared_database_acceptance_test.go index d700a256462..3aafa8d150f 100644 --- a/pkg/resources/shared_database_acceptance_test.go +++ b/pkg/resources/shared_database_acceptance_test.go @@ -205,6 +205,7 @@ func TestAcc_CreateSharedDatabase_complete(t *testing.T) { ConfigDirectory: acc.ConfigurationDirectory("TestAcc_SharedDatabase/complete"), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_shared_database.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_shared_database.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_shared_database.test", "from_share", externalShareId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_shared_database.test", "comment", comment), diff --git a/pkg/resources/special_values.go b/pkg/resources/special_values.go index 4a74508a8ef..5993e02cc02 100644 --- a/pkg/resources/special_values.go +++ b/pkg/resources/special_values.go @@ -33,15 +33,3 @@ func booleanStringToBool(value string) (bool, error) { return false, fmt.Errorf("cannot retrieve boolean value from %s", value) } } - -func booleanStringFieldDescription(description string) string { - return fmt.Sprintf(`%s Available options are: "%s" or "%s". When the value is not set in the configuration the provider will put "%s" there which means to use the Snowflake default for this value.`, description, BooleanTrue, BooleanFalse, BooleanDefault) -} - -func externalChangesNotDetectedFieldDescription(description string) string { - return fmt.Sprintf(`%s External changes for this field won't be detected. In case you want to apply external changes, you can re-create the resource manually using "terraform taint".`, description) -} - -func withPrivilegedRolesDescription(description, paramName string) string { - return fmt.Sprintf(`%s By default, this list includes the ACCOUNTADMIN, ORGADMIN and SECURITYADMIN roles. To remove these privileged roles from the list, use the ALTER ACCOUNT command to set the %s account parameter to FALSE. `, description, paramName) -} diff --git a/pkg/resources/stage.go b/pkg/resources/stage.go index 884ca76d796..d102bd2a711 100644 --- a/pkg/resources/stage.go +++ b/pkg/resources/stage.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" @@ -91,7 +92,8 @@ var stageSchema = map[string]*schema.Schema{ // Description based on https://docs.snowflake.com/en/user-guide/data-load-s3-config-aws-iam-role#step-3-create-an-external-stage Description: "An AWS IAM user created for your Snowflake account. This user is the same for every external S3 stage created in your account.", }, - "tag": tagReferenceSchema, + "tag": tagReferenceSchema, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // TODO (SNOW-1019005): Remove snowflake package that is used in Create and Update operations @@ -193,6 +195,9 @@ func ReadStage(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagn }, } } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if err := d.Set("name", stage.Name); err != nil { return diag.FromErr(err) diff --git a/pkg/resources/stage_acceptance_test.go b/pkg/resources/stage_acceptance_test.go index f734f1de92b..7275987e566 100644 --- a/pkg/resources/stage_acceptance_test.go +++ b/pkg/resources/stage_acceptance_test.go @@ -5,6 +5,7 @@ import ( "testing" acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/helpers/random" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/ids" @@ -17,7 +18,7 @@ import ( ) func TestAcc_StageAlterWhenBothURLAndStorageIntegrationChange(t *testing.T) { - name := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, @@ -28,16 +29,18 @@ func TestAcc_StageAlterWhenBothURLAndStorageIntegrationChange(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.Stage), Steps: []resource.TestStep{ { - Config: stageIntegrationConfig(name, "si1", "s3://foo/", acc.TestDatabaseName, acc.TestSchemaName), + Config: stageIntegrationConfig(id.Name(), "si1", "s3://foo/", acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_stage.test", "name", name), + resource.TestCheckResourceAttr("snowflake_stage.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_stage.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_stage.test", "url", "s3://foo/"), ), }, { - Config: stageIntegrationConfig(name, "changed", "s3://changed/", acc.TestDatabaseName, acc.TestSchemaName), + Config: stageIntegrationConfig(id.Name(), "changed", "s3://changed/", acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_stage.test", "name", name), + resource.TestCheckResourceAttr("snowflake_stage.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_stage.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_stage.test", "url", "s3://changed/"), ), }, @@ -53,6 +56,7 @@ func TestAcc_Stage_CreateAndAlter(t *testing.T) { databaseName := acc.TestClient().Ids.Alpha() schemaName := acc.TestClient().Ids.Alpha() name := acc.TestClient().Ids.Alpha() + id := sdk.NewSchemaObjectIdentifier(databaseName, schemaName, name) url := "s3://foo/" comment := random.Comment() initialStorageIntegration := "" @@ -119,6 +123,7 @@ func TestAcc_Stage_CreateAndAlter(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "database", databaseName), resource.TestCheckResourceAttr(resourceName, "schema", schemaName), resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "storage_integration", changedStorageIntegration.Name()), resource.TestCheckResourceAttr(resourceName, "credentials", credentials), resource.TestCheckResourceAttr(resourceName, "encryption", changedEncryption), @@ -138,6 +143,7 @@ func TestAcc_Stage_CreateAndAlter(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "database", databaseName), resource.TestCheckResourceAttr(resourceName, "schema", schemaName), resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "storage_integration", changedStorageIntegration.Name()), resource.TestCheckResourceAttr(resourceName, "credentials", credentials), resource.TestCheckResourceAttr(resourceName, "encryption", changedEncryption), @@ -162,6 +168,7 @@ func TestAcc_Stage_CreateAndAlter(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "database", databaseName), resource.TestCheckResourceAttr(resourceName, "schema", schemaName), resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "storage_integration", initialStorageIntegration), resource.TestCheckResourceAttr(resourceName, "credentials", credentials), resource.TestCheckResourceAttr(resourceName, "encryption", encryption), diff --git a/pkg/resources/storage_integration.go b/pkg/resources/storage_integration.go index 0a7a8308415..8fd4fe378d7 100644 --- a/pkg/resources/storage_integration.go +++ b/pkg/resources/storage_integration.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" @@ -104,6 +105,7 @@ var storageIntegrationSchema = map[string]*schema.Schema{ Computed: true, Description: "Date and time when the storage integration was created.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // StorageIntegration returns a pointer to the resource representing a storage integration. @@ -199,6 +201,9 @@ func ReadStorageIntegration(d *schema.ResourceData, meta any) error { d.SetId("") return nil } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } if s.Category != "STORAGE" { return fmt.Errorf("expected %v to be a STORAGE integration, got %v", d.Id(), s.Category) diff --git a/pkg/resources/storage_integration_acceptance_test.go b/pkg/resources/storage_integration_acceptance_test.go index ad85a207a42..38fe546e3f0 100644 --- a/pkg/resources/storage_integration_acceptance_test.go +++ b/pkg/resources/storage_integration_acceptance_test.go @@ -87,11 +87,11 @@ func TestAcc_StorageIntegration_AWSObjectACL_Update(t *testing.T) { } func TestAcc_StorageIntegration_AWS_Update(t *testing.T) { - name := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() awsRoleArn := "arn:aws:iam::000000000001:/role/test" configVariables := func(set bool) config.Variables { variables := config.Variables{ - "name": config.StringVariable(name), + "name": config.StringVariable(id.Name()), "aws_role_arn": config.StringVariable(awsRoleArn), "allowed_locations": config.SetVariable( config.StringVariable("s3://foo/"), @@ -124,7 +124,8 @@ func TestAcc_StorageIntegration_AWS_Update(t *testing.T) { ConfigVariables: configVariables(false), ConfigDirectory: acc.ConfigurationDirectory("TestAcc_StorageIntegration/AWS_Update/unset"), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_storage_integration.test", "name", name), + resource.TestCheckResourceAttr("snowflake_storage_integration.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_storage_integration.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_storage_integration.test", "enabled", "false"), resource.TestCheckResourceAttr("snowflake_storage_integration.test", "storage_aws_role_arn", awsRoleArn), resource.TestCheckResourceAttr("snowflake_storage_integration.test", "storage_allowed_locations.#", "1"), @@ -138,7 +139,8 @@ func TestAcc_StorageIntegration_AWS_Update(t *testing.T) { ConfigVariables: configVariables(true), ConfigDirectory: acc.ConfigurationDirectory("TestAcc_StorageIntegration/AWS_Update/set"), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_storage_integration.test", "name", name), + resource.TestCheckResourceAttr("snowflake_storage_integration.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_storage_integration.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_storage_integration.test", "enabled", "true"), resource.TestCheckResourceAttr("snowflake_storage_integration.test", "comment", "some comment"), resource.TestCheckResourceAttr("snowflake_storage_integration.test", "storage_aws_role_arn", awsRoleArn), @@ -155,7 +157,8 @@ func TestAcc_StorageIntegration_AWS_Update(t *testing.T) { ConfigVariables: configVariables(false), ConfigDirectory: acc.ConfigurationDirectory("TestAcc_StorageIntegration/AWS_Update/unset"), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_storage_integration.test", "name", name), + resource.TestCheckResourceAttr("snowflake_storage_integration.test", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_storage_integration.test", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_storage_integration.test", "enabled", "false"), resource.TestCheckResourceAttr("snowflake_storage_integration.test", "storage_aws_role_arn", awsRoleArn), resource.TestCheckResourceAttr("snowflake_storage_integration.test", "storage_allowed_locations.#", "1"), diff --git a/pkg/resources/stream.go b/pkg/resources/stream.go index 7aa0701aaab..8af0f25be8e 100644 --- a/pkg/resources/stream.go +++ b/pkg/resources/stream.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" @@ -93,6 +94,7 @@ var streamSchema = map[string]*schema.Schema{ Computed: true, Description: "Name of the role that owns the stream.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func Stream() *schema.Resource { @@ -232,6 +234,9 @@ func ReadStream(d *schema.ResourceData, meta interface{}) error { d.SetId("") return nil } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } if err := d.Set("name", stream.Name); err != nil { return err } diff --git a/pkg/resources/stream_acceptance_test.go b/pkg/resources/stream_acceptance_test.go index a13b17365de..a85c6d67a01 100644 --- a/pkg/resources/stream_acceptance_test.go +++ b/pkg/resources/stream_acceptance_test.go @@ -63,7 +63,7 @@ func TestAcc_StreamCreateOnStage(t *testing.T) { func TestAcc_Stream_OnTable(t *testing.T) { tableName := acc.TestClient().Ids.Alpha() tableName2 := acc.TestClient().Ids.Alpha() - name := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, @@ -74,9 +74,10 @@ func TestAcc_Stream_OnTable(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.Stream), Steps: []resource.TestStep{ { - Config: streamConfigOnTable(acc.TestDatabaseName, acc.TestSchemaName, tableName, name), + Config: streamConfigOnTable(acc.TestDatabaseName, acc.TestSchemaName, tableName, id.Name()), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_stream.test_stream", "name", name), + resource.TestCheckResourceAttr("snowflake_stream.test_stream", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_stream.test_stream", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_stream.test_stream", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_stream.test_stream", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_stream.test_stream", "on_table", fmt.Sprintf("\"%s\".\"%s\".%s", acc.TestDatabaseName, acc.TestSchemaName, tableName)), @@ -87,9 +88,10 @@ func TestAcc_Stream_OnTable(t *testing.T) { }, }, { - Config: streamConfigOnTable(acc.TestDatabaseName, acc.TestSchemaName, tableName2, name), + Config: streamConfigOnTable(acc.TestDatabaseName, acc.TestSchemaName, tableName2, id.Name()), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_stream.test_stream", "name", name), + resource.TestCheckResourceAttr("snowflake_stream.test_stream", "name", id.Name()), + resource.TestCheckResourceAttr("snowflake_stream.test_stream", "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_stream.test_stream", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_stream.test_stream", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_stream.test_stream", "on_table", fmt.Sprintf("\"%s\".\"%s\".%s", acc.TestDatabaseName, acc.TestSchemaName, tableName2)), diff --git a/pkg/resources/table.go b/pkg/resources/table.go index 434b12dd056..d7689efc03b 100644 --- a/pkg/resources/table.go +++ b/pkg/resources/table.go @@ -8,10 +8,13 @@ import ( "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" + "github.com/hashicorp/go-cty/cty" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) @@ -196,25 +199,35 @@ var tableSchema = map[string]*schema.Schema{ Default: false, Description: "Specifies whether to enable change tracking on the table. Default false.", }, - "qualified_name": { - Type: schema.TypeString, - Computed: true, - Description: "Qualified name of the table.", - }, - "tag": tagReferenceSchema, + "tag": tagReferenceSchema, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func Table() *schema.Resource { return &schema.Resource{ - Create: CreateTable, - Read: ReadTable, - Update: UpdateTable, - Delete: DeleteTable, + SchemaVersion: 1, + Create: CreateTable, + Read: ReadTable, + Update: UpdateTable, + Delete: DeleteTable, + + CustomizeDiff: customdiff.All( + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), + ), Schema: tableSchema, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, + + StateUpgraders: []schema.StateUpgrader{ + { + Version: 0, + // setting type to cty.EmptyObject is a bit hacky here but following https://developer.hashicorp.com/terraform/plugin/framework/migrating/resources/state-upgrade#sdkv2-1 would require lots of repetitive code; this should work with cty.EmptyObject + Type: cty.EmptyObject, + Upgrade: v0_94_1_TableStateUpgrader, + }, + }, } } @@ -643,6 +656,9 @@ func ReadTable(d *schema.ResourceData, meta interface{}) error { d.SetId("") return nil } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } var schemaRetentionTime int64 // "retention_time" may sometimes be empty string instead of an integer { @@ -672,7 +688,6 @@ func ReadTable(d *schema.ResourceData, meta interface{}) error { "column": toColumnConfig(tableDescription), "cluster_by": table.GetClusterByKeys(), "change_tracking": table.ChangeTracking, - "qualified_name": id.FullyQualifiedName(), } if v := d.Get("data_retention_time_in_days"); v.(int) != IntDefault || int64(table.RetentionTime) != schemaRetentionTime { toSet["data_retention_time_in_days"] = table.RetentionTime diff --git a/pkg/resources/table_acceptance_test.go b/pkg/resources/table_acceptance_test.go index 937263d0a80..51be5c9e924 100644 --- a/pkg/resources/table_acceptance_test.go +++ b/pkg/resources/table_acceptance_test.go @@ -135,10 +135,9 @@ func TestAcc_TableWithSeparateDataRetentionObjectParameterWithLifecycle(t *testi } func TestAcc_Table(t *testing.T) { - accName := acc.TestClient().Ids.Alpha() - - table2Name := acc.TestClient().Ids.Alpha() - table3Name := acc.TestClient().Ids.Alpha() + table1Id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + table2Id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + table3Id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, @@ -149,9 +148,10 @@ func TestAcc_Table(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.Table), Steps: []resource.TestStep{ { - Config: tableConfig(accName, acc.TestDatabaseName, acc.TestSchemaName), + Config: tableConfig(table1Id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table", "name", accName), + resource.TestCheckResourceAttr("snowflake_table.test_table", "name", table1Id.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table", "fully_qualified_name", table1Id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table", "data_retention_time_in_days", "1"), @@ -167,9 +167,10 @@ func TestAcc_Table(t *testing.T) { ), }, { - Config: tableConfig2(accName, acc.TestDatabaseName, acc.TestSchemaName), + Config: tableConfig2(table1Id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table", "name", accName), + resource.TestCheckResourceAttr("snowflake_table.test_table", "name", table1Id.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table", "fully_qualified_name", table1Id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table", "data_retention_time_in_days", "1"), @@ -186,9 +187,10 @@ func TestAcc_Table(t *testing.T) { ), }, { - Config: tableConfig3(table2Name, acc.TestDatabaseName, acc.TestSchemaName), + Config: tableConfig3(table2Id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table2", "name", table2Name), + resource.TestCheckResourceAttr("snowflake_table.test_table2", "name", table2Id.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table2", "fully_qualified_name", table2Id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table2", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table2", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table2", "data_retention_time_in_days", "1"), @@ -203,9 +205,10 @@ func TestAcc_Table(t *testing.T) { ), }, { - Config: tableConfig4(table2Name, acc.TestDatabaseName, acc.TestSchemaName), + Config: tableConfig4(table2Id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table2", "name", table2Name), + resource.TestCheckResourceAttr("snowflake_table.test_table2", "name", table2Id.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table2", "fully_qualified_name", table2Id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table2", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table2", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table2", "data_retention_time_in_days", "1"), @@ -219,9 +222,10 @@ func TestAcc_Table(t *testing.T) { ), }, { - Config: tableConfig5(table2Name, acc.TestDatabaseName, acc.TestSchemaName), + Config: tableConfig5(table2Id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table2", "name", table2Name), + resource.TestCheckResourceAttr("snowflake_table.test_table2", "name", table2Id.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table2", "fully_qualified_name", table2Id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table2", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table2", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table2", "data_retention_time_in_days", "1"), @@ -235,9 +239,10 @@ func TestAcc_Table(t *testing.T) { ), }, { - Config: tableConfig6(accName, acc.TestDatabaseName, acc.TestSchemaName), + Config: tableConfig6(table1Id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table", "name", accName), + resource.TestCheckResourceAttr("snowflake_table.test_table", "name", table1Id.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table", "fully_qualified_name", table1Id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table", "data_retention_time_in_days", "1"), @@ -254,9 +259,10 @@ func TestAcc_Table(t *testing.T) { ), }, { - Config: tableConfig7(accName, acc.TestDatabaseName, acc.TestSchemaName), + Config: tableConfig7(table1Id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table", "name", accName), + resource.TestCheckResourceAttr("snowflake_table.test_table", "name", table1Id.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table", "fully_qualified_name", table1Id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table", "data_retention_time_in_days", "1"), @@ -274,9 +280,10 @@ func TestAcc_Table(t *testing.T) { ), }, { - Config: tableConfig8(accName, acc.TestDatabaseName, acc.TestSchemaName), + Config: tableConfig8(table1Id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table", "name", accName), + resource.TestCheckResourceAttr("snowflake_table.test_table", "name", table1Id.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table", "fully_qualified_name", table1Id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table", "data_retention_time_in_days", "1"), @@ -295,9 +302,10 @@ func TestAcc_Table(t *testing.T) { ), }, { - Config: tableConfig9CreateTableWithColumnComment(table2Name, acc.TestDatabaseName, acc.TestSchemaName), + Config: tableConfig9CreateTableWithColumnComment(table2Id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table2", "name", table2Name), + resource.TestCheckResourceAttr("snowflake_table.test_table2", "name", table2Id.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table2", "fully_qualified_name", table2Id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table2", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table2", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table2", "data_retention_time_in_days", "1"), @@ -316,9 +324,10 @@ func TestAcc_Table(t *testing.T) { ), }, { - Config: tableConfig10AlterTableColumnComment(table2Name, acc.TestDatabaseName, acc.TestSchemaName), + Config: tableConfig10AlterTableColumnComment(table2Id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table2", "name", table2Name), + resource.TestCheckResourceAttr("snowflake_table.test_table2", "name", table2Id.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table2", "fully_qualified_name", table2Id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table2", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table2", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table2", "data_retention_time_in_days", "1"), @@ -337,9 +346,10 @@ func TestAcc_Table(t *testing.T) { ), }, { - Config: tableConfig11AlterTableAddColumnWithComment(table2Name, acc.TestDatabaseName, acc.TestSchemaName), + Config: tableConfig11AlterTableAddColumnWithComment(table2Id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table2", "name", table2Name), + resource.TestCheckResourceAttr("snowflake_table.test_table2", "name", table2Id.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table2", "fully_qualified_name", table2Id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table2", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table2", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table2", "data_retention_time_in_days", "1"), @@ -362,9 +372,10 @@ func TestAcc_Table(t *testing.T) { ), }, { - Config: tableConfig12CreateTableWithDataRetention(table3Name, acc.TestDatabaseName, acc.TestSchemaName), + Config: tableConfig12CreateTableWithDataRetention(table3Id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table3", "name", table3Name), + resource.TestCheckResourceAttr("snowflake_table.test_table3", "name", table3Id.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table3", "fully_qualified_name", table3Id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table3", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table3", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table3", "data_retention_time_in_days", "10"), @@ -379,9 +390,10 @@ func TestAcc_Table(t *testing.T) { ), }, { - Config: tableConfig13AlterTableDataRetention(table3Name, acc.TestDatabaseName, acc.TestSchemaName), + Config: tableConfig13AlterTableDataRetention(table3Id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table3", "name", table3Name), + resource.TestCheckResourceAttr("snowflake_table.test_table3", "name", table3Id.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table3", "fully_qualified_name", table3Id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table3", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table3", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table3", "data_retention_time_in_days", "0"), @@ -396,9 +408,10 @@ func TestAcc_Table(t *testing.T) { ), }, { - Config: tableConfig14AlterTableEnableChangeTracking(table3Name, acc.TestDatabaseName, acc.TestSchemaName), + Config: tableConfig14AlterTableEnableChangeTracking(table3Id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table3", "name", table3Name), + resource.TestCheckResourceAttr("snowflake_table.test_table3", "name", table3Id.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table3", "fully_qualified_name", table3Id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table3", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table3", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table3", "data_retention_time_in_days", "0"), @@ -413,9 +426,10 @@ func TestAcc_Table(t *testing.T) { ), }, { - Config: tableConfig15CreateTableWithChangeTracking(accName, acc.TestDatabaseName, acc.TestSchemaName), + Config: tableConfig15CreateTableWithChangeTracking(table1Id.Name(), acc.TestDatabaseName, acc.TestSchemaName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table", "name", accName), + resource.TestCheckResourceAttr("snowflake_table.test_table", "name", table1Id.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table", "fully_qualified_name", table1Id.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table", "data_retention_time_in_days", "1"), @@ -1364,8 +1378,8 @@ resource "snowflake_table" "test_table" { } func TestAcc_TableRename(t *testing.T) { - oldTableName := acc.TestClient().Ids.Alpha() - newTableName := acc.TestClient().Ids.Alpha() + oldId := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + newId := acc.TestClient().Ids.RandomSchemaObjectIdentifier() oldComment := acc.TestClient().Ids.Alpha() newComment := acc.TestClient().Ids.Alpha() @@ -1378,9 +1392,10 @@ func TestAcc_TableRename(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.Table), Steps: []resource.TestStep{ { - Config: tableConfigWithName(oldTableName, acc.TestDatabaseName, acc.TestSchemaName, oldComment), + Config: tableConfigWithName(oldId.Name(), acc.TestDatabaseName, acc.TestSchemaName, oldComment), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table", "name", oldTableName), + resource.TestCheckResourceAttr("snowflake_table.test_table", "name", oldId.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table", "fully_qualified_name", oldId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table", "comment", oldComment), @@ -1392,14 +1407,15 @@ func TestAcc_TableRename(t *testing.T) { ), }, { - Config: tableConfigWithName(newTableName, acc.TestDatabaseName, acc.TestSchemaName, newComment), + Config: tableConfigWithName(newId.Name(), acc.TestDatabaseName, acc.TestSchemaName, newComment), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectResourceAction("snowflake_table.test_table", plancheck.ResourceActionUpdate), }, }, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table.test_table", "name", newTableName), + resource.TestCheckResourceAttr("snowflake_table.test_table", "name", newId.Name()), + resource.TestCheckResourceAttr("snowflake_table.test_table", "fully_qualified_name", newId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_table.test_table", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_table.test_table", "schema", acc.TestSchemaName), resource.TestCheckResourceAttr("snowflake_table.test_table", "comment", newComment), @@ -1967,3 +1983,40 @@ resource "snowflake_table" "test_table" { } `, database, schema, name) } + +func TestAcc_Table_migrateFromVersion_0_94_1(t *testing.T) { + id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + resourceName := "snowflake_table.test_table" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + + Steps: []resource.TestStep{ + { + ExternalProviders: map[string]resource.ExternalProvider{ + "snowflake": { + VersionConstraint: "=0.94.1", + Source: "Snowflake-Labs/snowflake", + }, + }, + Config: tableConfig(id.Name(), id.DatabaseName(), id.SchemaName()), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "qualified_name", id.FullyQualifiedName()), + ), + }, + { + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + Config: tableConfig(id.Name(), id.DatabaseName(), id.SchemaName()), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), + resource.TestCheckNoResourceAttr(resourceName, "qualified_name"), + ), + }, + }, + }) +} diff --git a/pkg/resources/table_state_upgraders.go b/pkg/resources/table_state_upgraders.go new file mode 100644 index 00000000000..48ff09bc037 --- /dev/null +++ b/pkg/resources/table_state_upgraders.go @@ -0,0 +1,16 @@ +package resources + +import ( + "context" +) + +func v0_94_1_TableStateUpgrader(ctx context.Context, rawState map[string]any, meta any) (map[string]any, error) { + if rawState == nil { + return rawState, nil + } + + rawState[FullyQualifiedNameAttributeName] = rawState["qualified_name"] + delete(rawState, "qualified_name") + + return rawState, nil +} diff --git a/pkg/resources/tag.go b/pkg/resources/tag.go index 5029a5d3d84..37e4018b9d7 100644 --- a/pkg/resources/tag.go +++ b/pkg/resources/tag.go @@ -10,6 +10,7 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" ) @@ -43,6 +44,7 @@ var tagSchema = map[string]*schema.Schema{ Optional: true, Description: "List of allowed values for the tag.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } var tagReferenceSchema = &schema.Schema{ @@ -122,6 +124,9 @@ func ReadContextTag(ctx context.Context, d *schema.ResourceData, meta any) diag. if err != nil { return diag.FromErr(err) } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if err := d.Set("name", tag.Name); err != nil { return diag.FromErr(err) } diff --git a/pkg/resources/tag_acceptance_test.go b/pkg/resources/tag_acceptance_test.go index 49ba2f0a8e3..f831685a6e2 100644 --- a/pkg/resources/tag_acceptance_test.go +++ b/pkg/resources/tag_acceptance_test.go @@ -12,11 +12,11 @@ import ( ) func TestAcc_Tag(t *testing.T) { - name := acc.TestClient().Ids.Alpha() + id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() resourceName := "snowflake_tag.t" m := func() map[string]config.Variable { return map[string]config.Variable{ - "name": config.StringVariable(name), + "name": config.StringVariable(id.Name()), "database": config.StringVariable(acc.TestDatabaseName), "schema": config.StringVariable(acc.TestSchemaName), "comment": config.StringVariable("Terraform acceptance test"), @@ -42,7 +42,8 @@ func TestAcc_Tag(t *testing.T) { ConfigDirectory: acc.ConfigurationDirectory("TestAcc_Tag/basic"), ConfigVariables: m(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "database", acc.TestDatabaseName), resource.TestCheckResourceAttr(resourceName, "schema", acc.TestSchemaName), resource.TestCheckResourceAttr(resourceName, "allowed_values.#", "1"), @@ -56,7 +57,8 @@ func TestAcc_Tag(t *testing.T) { ConfigDirectory: acc.ConfigurationDirectory("TestAcc_Tag/basic"), ConfigVariables: variableSet2, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "allowed_values.#", "2"), resource.TestCheckResourceAttr(resourceName, "allowed_values.0", "alv1"), resource.TestCheckResourceAttr(resourceName, "allowed_values.1", "alv2"), @@ -68,7 +70,8 @@ func TestAcc_Tag(t *testing.T) { ConfigDirectory: acc.ConfigurationDirectory("TestAcc_Tag/basic"), ConfigVariables: variableSet3, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "name", id.Name()), + resource.TestCheckResourceAttr(resourceName, "fully_qualified_name", id.FullyQualifiedName()), resource.TestCheckResourceAttr(resourceName, "comment", "Terraform acceptance test - updated"), ), }, diff --git a/pkg/resources/task.go b/pkg/resources/task.go index 3b9cb73351b..8a135be2c3d 100644 --- a/pkg/resources/task.go +++ b/pkg/resources/task.go @@ -11,6 +11,7 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/util" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -118,6 +119,7 @@ var taskSchema = map[string]*schema.Schema{ Default: false, Description: "By default, Snowflake ensures that only one instance of a particular DAG is allowed to run at a time, setting the parameter value to TRUE permits DAG runs to overlap.", }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // difference find keys in 'a' but not in 'b'. @@ -176,6 +178,9 @@ func ReadTask(d *schema.ResourceData, meta interface{}) error { d.SetId("") return nil } + if err := d.Set(FullyQualifiedNameAttributeName, taskId.FullyQualifiedName()); err != nil { + return err + } if err := d.Set("enabled", task.IsStarted()); err != nil { return err diff --git a/pkg/resources/task_acceptance_test.go b/pkg/resources/task_acceptance_test.go index 4b046c1a4a3..03b3b212559 100644 --- a/pkg/resources/task_acceptance_test.go +++ b/pkg/resources/task_acceptance_test.go @@ -41,7 +41,9 @@ type ( var ( rootname = acc.TestClient().Ids.AlphaContaining("_root_task") + rootId = sdk.NewSchemaObjectIdentifier(acc.TestDatabaseName, acc.TestSchemaName, rootname) childname = acc.TestClient().Ids.AlphaContaining("_child_task") + childId = sdk.NewSchemaObjectIdentifier(acc.TestDatabaseName, acc.TestSchemaName, childname) soloname = acc.TestClient().Ids.AlphaContaining("_standalone_task") initialState = &AccTaskTestSettings{ //nolint @@ -204,7 +206,9 @@ func TestAcc_Task(t *testing.T) { checkBool("snowflake_task.root_task", "enabled", true), checkBool("snowflake_task.child_task", "enabled", false), resource.TestCheckResourceAttr("snowflake_task.root_task", "name", rootname), + resource.TestCheckResourceAttr("snowflake_task.root_task", "fully_qualified_name", rootId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_task.child_task", "name", childname), + resource.TestCheckResourceAttr("snowflake_task.child_task", "fully_qualified_name", childId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_task.root_task", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_task.child_task", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_task.root_task", "schema", acc.TestSchemaName), @@ -228,7 +232,9 @@ func TestAcc_Task(t *testing.T) { checkBool("snowflake_task.root_task", "enabled", true), checkBool("snowflake_task.child_task", "enabled", true), resource.TestCheckResourceAttr("snowflake_task.root_task", "name", rootname), + resource.TestCheckResourceAttr("snowflake_task.root_task", "fully_qualified_name", rootId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_task.child_task", "name", childname), + resource.TestCheckResourceAttr("snowflake_task.child_task", "fully_qualified_name", childId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_task.root_task", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_task.child_task", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_task.root_task", "schema", acc.TestSchemaName), @@ -251,7 +257,9 @@ func TestAcc_Task(t *testing.T) { checkBool("snowflake_task.root_task", "enabled", true), checkBool("snowflake_task.child_task", "enabled", true), resource.TestCheckResourceAttr("snowflake_task.root_task", "name", rootname), + resource.TestCheckResourceAttr("snowflake_task.root_task", "fully_qualified_name", rootId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_task.child_task", "name", childname), + resource.TestCheckResourceAttr("snowflake_task.child_task", "fully_qualified_name", childId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_task.root_task", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_task.child_task", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_task.root_task", "schema", acc.TestSchemaName), @@ -274,7 +282,9 @@ func TestAcc_Task(t *testing.T) { checkBool("snowflake_task.root_task", "enabled", false), checkBool("snowflake_task.child_task", "enabled", false), resource.TestCheckResourceAttr("snowflake_task.root_task", "name", rootname), + resource.TestCheckResourceAttr("snowflake_task.root_task", "fully_qualified_name", rootId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_task.child_task", "name", childname), + resource.TestCheckResourceAttr("snowflake_task.child_task", "fully_qualified_name", childId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_task.root_task", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_task.child_task", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_task.root_task", "schema", acc.TestSchemaName), @@ -297,7 +307,9 @@ func TestAcc_Task(t *testing.T) { checkBool("snowflake_task.root_task", "enabled", true), checkBool("snowflake_task.child_task", "enabled", false), resource.TestCheckResourceAttr("snowflake_task.root_task", "name", rootname), + resource.TestCheckResourceAttr("snowflake_task.root_task", "fully_qualified_name", rootId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_task.child_task", "name", childname), + resource.TestCheckResourceAttr("snowflake_task.child_task", "fully_qualified_name", childId.FullyQualifiedName()), resource.TestCheckResourceAttr("snowflake_task.root_task", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_task.child_task", "database", acc.TestDatabaseName), resource.TestCheckResourceAttr("snowflake_task.root_task", "schema", acc.TestSchemaName), diff --git a/pkg/resources/user.go b/pkg/resources/user.go index 6eb80092665..9a2b50dbc0e 100644 --- a/pkg/resources/user.go +++ b/pkg/resources/user.go @@ -144,6 +144,7 @@ var userSchema = map[string]*schema.Schema{ Schema: schemas.ShowUserParametersSchema, }, }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func User() *schema.Resource { @@ -163,6 +164,7 @@ func User() *schema.Resource { // ComputedIfAnyAttributeChanged(ShowOutputAttributeName), // TODO [SNOW-1348101]: use list from user parameters definition instead listing all here ComputedIfAnyAttributeChanged(ParametersAttributeName, strings.ToLower(string(sdk.UserParameterAbortDetachedQuery)), strings.ToLower(string(sdk.UserParameterAutocommit)), strings.ToLower(string(sdk.UserParameterBinaryInputFormat)), strings.ToLower(string(sdk.UserParameterBinaryOutputFormat)), strings.ToLower(string(sdk.UserParameterClientMemoryLimit)), strings.ToLower(string(sdk.UserParameterClientMetadataRequestUseConnectionCtx)), strings.ToLower(string(sdk.UserParameterClientPrefetchThreads)), strings.ToLower(string(sdk.UserParameterClientResultChunkSize)), strings.ToLower(string(sdk.UserParameterClientResultColumnCaseInsensitive)), strings.ToLower(string(sdk.UserParameterClientSessionKeepAlive)), strings.ToLower(string(sdk.UserParameterClientSessionKeepAliveHeartbeatFrequency)), strings.ToLower(string(sdk.UserParameterClientTimestampTypeMapping)), strings.ToLower(string(sdk.UserParameterDateInputFormat)), strings.ToLower(string(sdk.UserParameterDateOutputFormat)), strings.ToLower(string(sdk.UserParameterEnableUnloadPhysicalTypeOptimization)), strings.ToLower(string(sdk.UserParameterErrorOnNondeterministicMerge)), strings.ToLower(string(sdk.UserParameterErrorOnNondeterministicUpdate)), strings.ToLower(string(sdk.UserParameterGeographyOutputFormat)), strings.ToLower(string(sdk.UserParameterGeometryOutputFormat)), strings.ToLower(string(sdk.UserParameterJdbcTreatDecimalAsInt)), strings.ToLower(string(sdk.UserParameterJdbcTreatTimestampNtzAsUtc)), strings.ToLower(string(sdk.UserParameterJdbcUseSessionTimezone)), strings.ToLower(string(sdk.UserParameterJsonIndent)), strings.ToLower(string(sdk.UserParameterLockTimeout)), strings.ToLower(string(sdk.UserParameterLogLevel)), strings.ToLower(string(sdk.UserParameterMultiStatementCount)), strings.ToLower(string(sdk.UserParameterNoorderSequenceAsDefault)), strings.ToLower(string(sdk.UserParameterOdbcTreatDecimalAsInt)), strings.ToLower(string(sdk.UserParameterQueryTag)), strings.ToLower(string(sdk.UserParameterQuotedIdentifiersIgnoreCase)), strings.ToLower(string(sdk.UserParameterRowsPerResultset)), strings.ToLower(string(sdk.UserParameterS3StageVpceDnsName)), strings.ToLower(string(sdk.UserParameterSearchPath)), strings.ToLower(string(sdk.UserParameterSimulatedDataSharingConsumer)), strings.ToLower(string(sdk.UserParameterStatementQueuedTimeoutInSeconds)), strings.ToLower(string(sdk.UserParameterStatementTimeoutInSeconds)), strings.ToLower(string(sdk.UserParameterStrictJsonOutput)), strings.ToLower(string(sdk.UserParameterTimestampDayIsAlways24h)), strings.ToLower(string(sdk.UserParameterTimestampInputFormat)), strings.ToLower(string(sdk.UserParameterTimestampLtzOutputFormat)), strings.ToLower(string(sdk.UserParameterTimestampNtzOutputFormat)), strings.ToLower(string(sdk.UserParameterTimestampOutputFormat)), strings.ToLower(string(sdk.UserParameterTimestampTypeMapping)), strings.ToLower(string(sdk.UserParameterTimestampTzOutputFormat)), strings.ToLower(string(sdk.UserParameterTimezone)), strings.ToLower(string(sdk.UserParameterTimeInputFormat)), strings.ToLower(string(sdk.UserParameterTimeOutputFormat)), strings.ToLower(string(sdk.UserParameterTraceLevel)), strings.ToLower(string(sdk.UserParameterTransactionAbortOnError)), strings.ToLower(string(sdk.UserParameterTransactionDefaultIsolationLevel)), strings.ToLower(string(sdk.UserParameterTwoDigitCenturyStart)), strings.ToLower(string(sdk.UserParameterUnsupportedDdlAction)), strings.ToLower(string(sdk.UserParameterUseCachedResult)), strings.ToLower(string(sdk.UserParameterWeekOfYearPolicy)), strings.ToLower(string(sdk.UserParameterWeekStart)), strings.ToLower(string(sdk.UserParameterEnableUnredactedQuerySyntaxError)), strings.ToLower(string(sdk.UserParameterNetworkPolicy)), strings.ToLower(string(sdk.UserParameterPreventUnloadToInternalStages))), + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), userParametersCustomDiff, ), } @@ -284,6 +286,9 @@ func GetReadUserFunc(withExternalChangesMarking bool) schema.ReadContextFunc { } return diag.FromErr(err) } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } userParameters, err := client.Users.ShowParameters(ctx, id) if err != nil { diff --git a/pkg/resources/user_acceptance_test.go b/pkg/resources/user_acceptance_test.go index 00e0de720a9..0844c755266 100644 --- a/pkg/resources/user_acceptance_test.go +++ b/pkg/resources/user_acceptance_test.go @@ -47,6 +47,8 @@ func TestAcc_User(t *testing.T) { r := require.New(t) prefix := acc.TestClient().Ids.Alpha() prefix2 := acc.TestClient().Ids.Alpha() + id := sdk.NewAccountObjectIdentifier(prefix) + id2 := sdk.NewAccountObjectIdentifier(prefix) comment := random.Comment() newComment := random.Comment() @@ -80,6 +82,7 @@ func TestAcc_User(t *testing.T) { resource.TestCheckResourceAttr("snowflake_user.w", "default_role", "foo"), resource.TestCheckResourceAttr("snowflake_user.w", "default_secondary_roles.0", "ALL"), resource.TestCheckResourceAttr("snowflake_user.w", "default_namespace", "foo.bar"), + resource.TestCheckResourceAttr("snowflake_user.w", "fully_qualified_name", id.FullyQualifiedName()), checkBool("snowflake_user.w", "has_rsa_public_key", true), checkBool("snowflake_user.w", "must_change_password", true), ), @@ -105,6 +108,7 @@ func TestAcc_User(t *testing.T) { resource.TestCheckResourceAttr("snowflake_user.w", "default_role", "foo"), resource.TestCheckResourceAttr("snowflake_user.w", "default_secondary_roles.0", "ALL"), resource.TestCheckResourceAttr("snowflake_user.w", "default_namespace", "foo.bar"), + resource.TestCheckResourceAttr("snowflake_user.w", "fully_qualified_name", id2.FullyQualifiedName()), ), }, // CHANGE PROPERTIES @@ -125,6 +129,7 @@ func TestAcc_User(t *testing.T) { resource.TestCheckResourceAttr("snowflake_user.w", "default_secondary_roles.#", "0"), resource.TestCheckResourceAttr("snowflake_user.w", "default_namespace", "bar.baz"), checkBool("snowflake_user.w", "has_rsa_public_key", false), + resource.TestCheckResourceAttr("snowflake_user.w", "fully_qualified_name", id2.FullyQualifiedName()), ), }, // IMPORT diff --git a/pkg/resources/view.go b/pkg/resources/view.go index 8fea2690082..33700718abf 100644 --- a/pkg/resources/view.go +++ b/pkg/resources/view.go @@ -7,10 +7,12 @@ import ( "regexp" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -73,7 +75,8 @@ var viewSchema = map[string]*schema.Schema{ Computed: true, Description: "The timestamp at which the view was created.", }, - "tag": tagReferenceSchema, + "tag": tagReferenceSchema, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } // View returns a pointer to the resource representing a view. @@ -84,6 +87,10 @@ func View() *schema.Resource { Update: UpdateView, Delete: DeleteView, + CustomizeDiff: customdiff.All( + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), + ), + Schema: viewSchema, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, @@ -151,6 +158,9 @@ func ReadView(d *schema.ResourceData, meta interface{}) error { d.SetId("") return nil } + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return err + } if err = d.Set("name", view.Name); err != nil { return err diff --git a/pkg/resources/view_acceptance_test.go b/pkg/resources/view_acceptance_test.go index dc553bb1b27..b5149c8e7b3 100644 --- a/pkg/resources/view_acceptance_test.go +++ b/pkg/resources/view_acceptance_test.go @@ -184,6 +184,8 @@ func TestAcc_View_Tags(t *testing.T) { func TestAcc_View_Rename(t *testing.T) { viewName := acc.TestClient().Ids.Alpha() newViewName := acc.TestClient().Ids.Alpha() + viewId := sdk.NewSchemaObjectIdentifier(acc.TestDatabaseName, acc.TestSchemaName, viewName) + newViewId := sdk.NewSchemaObjectIdentifier(acc.TestDatabaseName, acc.TestSchemaName, newViewName) query := "SELECT ROLE_NAME, ROLE_OWNER FROM INFORMATION_SCHEMA.APPLICABLE_ROLES" m := func() map[string]config.Variable { @@ -215,6 +217,7 @@ func TestAcc_View_Rename(t *testing.T) { ConfigVariables: m(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_view.test", "name", viewName), + resource.TestCheckResourceAttr("snowflake_view.test", "fully_qualified_name", viewId.FullyQualifiedName()), ), }, // rename with one param changed @@ -229,6 +232,7 @@ func TestAcc_View_Rename(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_view.test", "name", newViewName), resource.TestCheckResourceAttr("snowflake_view.test", "comment", "new comment"), + resource.TestCheckResourceAttr("snowflake_view.test", "fully_qualified_name", newViewId.FullyQualifiedName()), ), }, }, diff --git a/pkg/resources/warehouse.go b/pkg/resources/warehouse.go index f5952b85700..d054d26c082 100644 --- a/pkg/resources/warehouse.go +++ b/pkg/resources/warehouse.go @@ -147,6 +147,7 @@ var warehouseSchema = map[string]*schema.Schema{ Schema: schemas.ShowWarehouseParametersSchema, }, }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, } func warehouseParametersProvider(ctx context.Context, d ResourceIdProvider, meta any) ([]*sdk.Parameter, error) { @@ -204,6 +205,7 @@ func Warehouse() *schema.Resource { CustomizeDiff: customdiff.All( ComputedIfAnyAttributeChanged(ShowOutputAttributeName, "warehouse_type", "warehouse_size", "max_cluster_count", "min_cluster_count", "scaling_policy", "auto_suspend", "auto_resume", "resource_monitor", "comment", "enable_query_acceleration", "query_acceleration_max_scale_factor"), ComputedIfAnyAttributeChanged(ParametersAttributeName, strings.ToLower(string(sdk.ObjectParameterMaxConcurrencyLevel)), strings.ToLower(string(sdk.ObjectParameterStatementQueuedTimeoutInSeconds)), strings.ToLower(string(sdk.ObjectParameterStatementTimeoutInSeconds))), + ComputedIfAnyAttributeChanged(FullyQualifiedNameAttributeName, "name"), customdiff.ForceNewIfChange("warehouse_size", func(ctx context.Context, old, new, meta any) bool { return old.(string) != "" && new.(string) == "" }), @@ -400,7 +402,9 @@ func GetReadWarehouseFunc(withExternalChangesMarking bool) schema.ReadContextFun return diag.FromErr(err) } } - + if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil { + return diag.FromErr(err) + } if err = d.Set("name", w.Name); err != nil { return diag.FromErr(err) } diff --git a/pkg/resources/warehouse_acceptance_test.go b/pkg/resources/warehouse_acceptance_test.go index 1c337f0f549..bb9656888aa 100644 --- a/pkg/resources/warehouse_acceptance_test.go +++ b/pkg/resources/warehouse_acceptance_test.go @@ -121,6 +121,7 @@ func TestAcc_Warehouse_BasicFlows(t *testing.T) { HasAllDefaultsExplicit(), // we can still use normal checks assert.Check(resource.TestCheckResourceAttr("snowflake_warehouse.w", "name", warehouseId.Name())), + assert.Check(resource.TestCheckResourceAttr("snowflake_warehouse.w", "fully_qualified_name", warehouseId.FullyQualifiedName())), ), }, // IMPORT after empty config (in this method, most of the attributes will be filled with the defaults acquired from Snowflake) @@ -129,6 +130,7 @@ func TestAcc_Warehouse_BasicFlows(t *testing.T) { ImportState: true, ImportStateCheck: assert.AssertThatImport(t, assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(warehouseId.Name(), "name", name)), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(warehouseId.Name(), "fully_qualified_name", warehouseId.FullyQualifiedName())), resourceassert.ImportedWarehouseResource(t, warehouseId.Name()). HasNameString(name). HasWarehouseTypeString(string(sdk.WarehouseTypeStandard)). @@ -182,6 +184,7 @@ func TestAcc_Warehouse_BasicFlows(t *testing.T) { }, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_warehouse.w", "name", name2), + resource.TestCheckResourceAttr("snowflake_warehouse.w", "fully_qualified_name", warehouseId2.FullyQualifiedName()), ), }, // Change config but use defaults for every attribute (but not the parameters) - expect no changes (because these are already SF values) except computed show_output (follow-up why suppress diff is not taken into account in has changes?)