diff --git a/Makefile b/Makefile index 66435284af3..ae68a5fc7a9 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,7 @@ test: test-client ## run unit and integration tests go test -v -cover -timeout=45m ./... test-acceptance: ## run acceptance tests - TF_ACC=1 SF_TF_ACC_TEST_CONFIGURE_CLIENT_ONCE=true TEST_SF_TF_REQUIRE_TEST_OBJECT_SUFFIX=1 go test -run "^TestAcc_" -v -cover -timeout=120m ./... + TF_ACC=1 SF_TF_ACC_TEST_CONFIGURE_CLIENT_ONCE=true TEST_SF_TF_REQUIRE_TEST_OBJECT_SUFFIX=1 SF_TF_ACC_TEST_ENABLE_ALL_PREVIEW_FEATURES=true go test -run "^TestAcc_" -v -cover -timeout=120m ./... test-integration: ## run SDK integration tests TEST_SF_TF_REQUIRE_TEST_OBJECT_SUFFIX=1 go test -run "^TestInt_" -v -cover -timeout=45m ./... @@ -80,7 +80,7 @@ test-object-renaming: ## runs tests in object_renaming_acceptance_test.go TEST_SF_TF_ENABLE_OBJECT_RENAMING=1 go test ./pkg/resources/object_renaming_acceptace_test.go -v test-acceptance-%: ## run acceptance tests for the given resource only, e.g. test-acceptance-Warehouse - TF_ACC=1 TF_LOG=DEBUG SF_TF_ACC_TEST_CONFIGURE_CLIENT_ONCE=true go test -run ^TestAcc_$*_ -v -timeout=20m ./pkg/resources + TF_ACC=1 TF_LOG=DEBUG SF_TF_ACC_TEST_CONFIGURE_CLIENT_ONCE=true SF_TF_ACC_TEST_ENABLE_ALL_PREVIEW_FEATURES=true go test -run ^TestAcc_$*_ -v -timeout=20m ./pkg/resources build-local: ## build the binary locally go build -o $(BASE_BINARY_NAME) . diff --git a/pkg/acceptance/testenvs/testing_environment_variables.go b/pkg/acceptance/testenvs/testing_environment_variables.go index 997d8cd8a81..4abb131036f 100644 --- a/pkg/acceptance/testenvs/testing_environment_variables.go +++ b/pkg/acceptance/testenvs/testing_environment_variables.go @@ -34,6 +34,7 @@ const ( EnableSweep env = "TEST_SF_TF_ENABLE_SWEEP" EnableManual env = "TEST_SF_TF_ENABLE_MANUAL_TESTS" ConfigureClientOnce env = "SF_TF_ACC_TEST_CONFIGURE_CLIENT_ONCE" + EnableAllPreviewFeatures env = "SF_TF_ACC_TEST_ENABLE_ALL_PREVIEW_FEATURES" TestObjectsSuffix env = "TEST_SF_TF_TEST_OBJECT_SUFFIX" RequireTestObjectsSuffix env = "TEST_SF_TF_REQUIRE_TEST_OBJECT_SUFFIX" ) diff --git a/pkg/datasources/current_account.go b/pkg/datasources/current_account.go index d6a0d1d291f..247c33a4195 100644 --- a/pkg/datasources/current_account.go +++ b/pkg/datasources/current_account.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "slices" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" @@ -41,6 +42,10 @@ func CurrentAccount() *schema.Resource { // ReadCurrentAccount read the current snowflake account information. func ReadCurrentAccount(d *schema.ResourceData, meta interface{}) error { client := meta.(*provider.Context).Client + enabled := meta.(*provider.Context).EnabledFeatures + if !slices.Contains(enabled, "snowflake_current_account") { + return fmt.Errorf("%[1]s is currently a preview data source, and must be enabled by adding %[1]s to `preview_features_enabled` in Terraform configuration.", "snowflake_current_account") + } ctx := context.Background() current, err := client.ContextFunctions.CurrentSessionDetails(ctx) diff --git a/pkg/datasources/current_account_acceptance_test.go b/pkg/datasources/current_account_acceptance_test.go index df58a2001bc..3e10923ef64 100644 --- a/pkg/datasources/current_account_acceptance_test.go +++ b/pkg/datasources/current_account_acceptance_test.go @@ -16,7 +16,6 @@ func TestAcc_CurrentAccount(t *testing.T) { TerraformVersionChecks: []tfversion.TerraformVersionCheck{ tfversion.RequireAbove(tfversion.Version1_5_0), }, - CheckDestroy: nil, Steps: []resource.TestStep{ { Config: currentAccount(), diff --git a/pkg/internal/provider/provider_context.go b/pkg/internal/provider/provider_context.go index 0fbdef82288..64c469fb2f8 100644 --- a/pkg/internal/provider/provider_context.go +++ b/pkg/internal/provider/provider_context.go @@ -3,5 +3,6 @@ package provider import "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" type Context struct { - Client *sdk.Client + Client *sdk.Client + EnabledFeatures []string } diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index ed421495c92..6e10ff91ee3 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -356,6 +356,15 @@ func Provider() *schema.Provider { Optional: true, DefaultFunc: schema.EnvDefaultFunc(snowflakeenvs.Profile, "default"), }, + "preview_features_enabled": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateDiagFunc: validators.StringInSlice(previewFeatures, true), + }, + Description: "A list of preview features that are handled by the provider. See [preview features list](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/v1-preparations/LIST_OF_PREVIEW_FEATURES_FOR_V1.md). Preview features may have breaking changes in future releases, even without raising the major version. This field can not be set with environmental variables.", + }, }, ResourcesMap: getResources(), DataSourcesMap: getDataSources(), @@ -364,6 +373,59 @@ func Provider() *schema.Provider { } } +var previewFeatures = []string{ + "snowflake_current_account", + "snowflake_account_password_policy_attachment", + "snowflake_alert", + "snowflake_alerts", + "snowflake_api_integration", + "snowflake_cortex_search_service", + "snowflake_cortex_search_services", + "snowflake_database", + "snowflake_database_role", + "snowflake_dynamic_table", + "snowflake_dynamic_tables", + "snowflake_external_function", + "snowflake_external_functions", + "snowflake_external_table", + "snowflake_external_tables", + "snowflake_external_volume", + "snowflake_failover_group", + "snowflake_failover_groups", + "snowflake_file_format", + "snowflake_file_formats", + "snowflake_managed_account", + "snowflake_materialized_view", + "snowflake_materialized_views", + "snowflake_network_policy_attachment", + "snowflake_network_rule", + "snowflake_email_notification_integration", + "snowflake_notification_integration", + "snowflake_object_parameter", + "snowflake_password_policy", + "snowflake_pipe", + "snowflake_pipes", + "snowflake_current_role", + "snowflake_sequence", + "snowflake_sequences", + "snowflake_share", + "snowflake_shares", + "snowflake_object_parameter", + "snowflake_parameters", + "snowflake_stage", + "snowflake_stages", + "snowflake_storage_integration", + "snowflake_storage_integrations", + "snowflake_system_generate_scim_access_token", + "snowflake_system_get_aws_sns_iam_policy", + "snowflake_system_get_privatelink_config", + "snowflake_system_get_snowflake_platform_info", + "snowflake_table_column_masking_policy_application", + "snowflake_table_constraint", + "snowflake_user_public_keys", + "snowflake_user_password_policy_attachment", +} + func getResources() map[string]*schema.Resource { resourceList := map[string]*schema.Resource{ "snowflake_account": resources.Account(), @@ -505,15 +567,15 @@ func getDataSources() map[string]*schema.Resource { } var ( - configuredClient *sdk.Client configureClientError error //nolint:errname + configureProviderCtx *provider.Context ) func ConfigureProvider(ctx context.Context, s *schema.ResourceData) (any, diag.Diagnostics) { // hacky way to speed up our acceptance tests if os.Getenv("TF_ACC") != "" && os.Getenv("SF_TF_ACC_TEST_CONFIGURE_CLIENT_ONCE") == "true" { - if configuredClient != nil { - return &provider.Context{Client: configuredClient}, nil + if configureProviderCtx != nil { + return configureProviderCtx, nil } if configureClientError != nil { return nil, diag.FromErr(configureClientError) @@ -535,12 +597,22 @@ func ConfigureProvider(ctx context.Context, s *schema.ResourceData) (any, diag.D client, clientErr := sdk.NewClient(config) + providerCtx := &provider.Context{Client: client} + + if v, ok := s.GetOk("preview_features_enabled"); ok { + providerCtx.EnabledFeatures = expandStringList(v.(*schema.Set).List()) + } + + if os.Getenv("SF_TF_ACC_TEST_ENABLE_ALL_PREVIEW_FEATURES") == "true" { + providerCtx.EnabledFeatures = previewFeatures + } + // needed for tests verifying different provider setups if os.Getenv(resource.EnvTfAcc) != "" && os.Getenv(string(testenvs.ConfigureClientOnce)) == "true" { - configuredClient = client + configureProviderCtx = providerCtx configureClientError = clientErr } else { - configuredClient = nil + configureProviderCtx = nil configureClientError = nil } @@ -548,7 +620,19 @@ func ConfigureProvider(ctx context.Context, s *schema.ResourceData) (any, diag.D return nil, diag.FromErr(clientErr) } - return &provider.Context{Client: client}, nil + return providerCtx, nil +} + +// TODO: reuse with the function from resources package +func expandStringList(configured []interface{}) []string { + vs := make([]string, 0, len(configured)) + for _, v := range configured { + val, ok := v.(string) + if ok && val != "" { + vs = append(vs, val) + } + } + return vs } func getDriverConfigFromTOML(profile string) (*gosnowflake.Config, error) { diff --git a/pkg/provider/provider_acceptance_test.go b/pkg/provider/provider_acceptance_test.go index 9b8dcca9fa8..c1b8323f345 100644 --- a/pkg/provider/provider_acceptance_test.go +++ b/pkg/provider/provider_acceptance_test.go @@ -653,6 +653,34 @@ func TestAcc_Provider_invalidConfigurations(t *testing.T) { }) } +func TestAcc_Provider_PreviewFeaturesEnabled(t *testing.T) { + t.Setenv(string(testenvs.ConfigureClientOnce), "") + t.Setenv(string(testenvs.EnableAllPreviewFeatures), "") + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { acc.TestAccPreCheck(t) }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + Steps: []resource.TestStep{ + { + Config: providerConfigWithDatasourcePreviewFeature(testprofiles.Default, "snowflake_current_account"), + ExpectError: regexp.MustCompile("snowflake_current_account is currently a preview data source, and must be enabled by adding snowflake_current_account to `preview_features_enabled` in Terraform configuration"), + }, + }, + }) +} + +func providerConfigWithDatasourcePreviewFeature(profile, feature string) string { + return fmt.Sprintf(` +provider "snowflake" { + profile = "%[1]s" +} +data %[2]s p {} +`, profile, feature) +} + func providerConfigWithAuthenticator(profile string, authenticator sdk.AuthenticationType) string { return fmt.Sprintf(` provider "snowflake" { diff --git a/v1-preparations/LIST_OF_PREVIEW_FEATURES_FOR_V1.md b/v1-preparations/LIST_OF_PREVIEW_FEATURES_FOR_V1.md index 1f51a82107b..73e4e7f4c7b 100644 --- a/v1-preparations/LIST_OF_PREVIEW_FEATURES_FOR_V1.md +++ b/v1-preparations/LIST_OF_PREVIEW_FEATURES_FOR_V1.md @@ -27,6 +27,7 @@ * [snowflake_network_rule](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/0.97.0/docs/resources/network_rule) * [snowflake_email_notification_integration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/0.97.0/docs/resources/email_notification_integration) * [snowflake_notification_integration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/0.97.0/docs/resources/notification_integration) +* [snowflake_object_parameter](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/0.97.0/docs/resources/object_parameter) * [snowflake_password_policy](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/0.97.0/docs/resources/password_policy) * [snowflake_pipe](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/0.97.0/docs/resources/pipe) * [snowflake_pipes](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/0.97.0/docs/data-sources/pipes) (datasource) @@ -49,3 +50,4 @@ * [snowflake_table_constraint](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/0.97.0/docs/resources/table_constraint) (undecided - may be deleted instead) * [snowflake_user_public_keys](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/0.97.0/docs/resources/user_public_keys) * [snowflake_user_password_policy_attachment](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/0.97.0/docs/resources/user_password_policy_attachment) +* [snowflake_user_authentication_policy_attachment](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/0.97.0/docs/resources/snowflake_user_authentication_policy_attachment)