diff --git a/pkg/resources/common.go b/pkg/resources/common.go index 3f6380258dd..64f57eaf255 100644 --- a/pkg/resources/common.go +++ b/pkg/resources/common.go @@ -1,12 +1,19 @@ package resources import ( + "fmt" "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) +const SnowflakeDefaultStringValuePlaceholder = "Snowflake default value" + +func SnowflakeDefaultStringValueDescription(description string) string { + return fmt.Sprintf("%s When the value is not set in the configuration the provider will put `%s` in the state which is a placeholder that means to use the Snowflake default for this value.", description) +} + // DiffSuppressStatement will suppress diffs between statements if they differ in only case or in // runs of whitespace (\s+ = \s). This is needed because the snowflake api does not faithfully // round-trip queries, so we cannot do a simple character-wise comparison to detect changes. diff --git a/pkg/resources/helpers.go b/pkg/resources/helpers.go index 83f6c5f3b26..c723e2893f6 100644 --- a/pkg/resources/helpers.go +++ b/pkg/resources/helpers.go @@ -145,7 +145,7 @@ func GetPropertyAsPointer[T any](d *schema.ResourceData, property string) *T { // the assumptions are that: // 1. The list is enclosed by [] brackets, and they shouldn't be a part of any item's value // 2. Items are separated by commas, and they shouldn't be a part of any item's value -// 3. items can have as many spaces in between, but after separation they will be trimmed and shouldn't be a part of any item's value +// 3. Items can have as many spaces in between, but after separation they will be trimmed and shouldn't be a part of any item's value func ParseCommaSeparatedStringArray(value string) []string { if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") { if value == "[]" { diff --git a/pkg/resources/saml2_integration.go b/pkg/resources/saml2_integration.go index 5410d5c0b8a..97cb9874a76 100644 --- a/pkg/resources/saml2_integration.go +++ b/pkg/resources/saml2_integration.go @@ -21,11 +21,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -// TODO Scim add suppress for bools (ignore-case) -// TODO: Scim upgrader (can skip diffs when x fields are set after the upgrade) -// TODO: Move and change -const SnowflakeDefaultStringValuePlaceholder = "Snowflake default value" - var saml2IntegrationSchema = map[string]*schema.Schema{ "name": { Type: schema.TypeString, @@ -85,7 +80,7 @@ var saml2IntegrationSchema = map[string]*schema.Schema{ Type: schema.TypeString, Optional: true, Default: SnowflakeDefaultStringValuePlaceholder, - Description: "The Base64 encoded self-signed certificate generated by Snowflake for use with Encrypting SAML Assertions and Signed SAML Requests. You must have at least one of these features (encrypted SAML assertions or signed SAML responses) enabled in your Snowflake account to access the certificate value.", + Description: SnowflakeDefaultStringValueDescription("The Base64 encoded self-signed certificate generated by Snowflake for use with Encrypting SAML Assertions and Signed SAML Requests. You must have at least one of these features (encrypted SAML assertions or signed SAML responses) enabled in your Snowflake account to access the certificate value."), DiffSuppressFunc: IgnoreChangeToCurrentSnowflakeValueInDescribe("saml2_snowflake_x509_cert"), }, "saml2_sign_request": { @@ -99,8 +94,8 @@ var saml2IntegrationSchema = map[string]*schema.Schema{ "saml2_requested_nameid_format": { Type: schema.TypeString, Optional: true, - Default: SnowflakeDefaultStringValuePlaceholder, // TODO: Document in describe - Description: fmt.Sprintf("The SAML NameID format allows Snowflake to set an expectation of the identifying attribute of the user (i.e. SAML Subject) in the SAML assertion from the IdP to ensure a valid authentication to Snowflake. Valid options are: %v", sdk.AllSaml2SecurityIntegrationSaml2RequestedNameidFormats), + Default: SnowflakeDefaultStringValuePlaceholder, + Description: SnowflakeDefaultStringValueDescription(fmt.Sprintf("The SAML NameID format allows Snowflake to set an expectation of the identifying attribute of the user (i.e. SAML Subject) in the SAML assertion from the IdP to ensure a valid authentication to Snowflake. Valid options are: %v", sdk.AllSaml2SecurityIntegrationSaml2RequestedNameidFormats)), ValidateDiagFunc: sdkValidation(sdk.ToSaml2SecurityIntegrationSaml2RequestedNameidFormatOption), DiffSuppressFunc: SuppressIfAny(ignoreCaseSuppressFunc, IgnoreChangeToCurrentSnowflakeValueInDescribe("saml2_requested_nameid_format")), }, @@ -120,14 +115,14 @@ var saml2IntegrationSchema = map[string]*schema.Schema{ Type: schema.TypeString, Optional: true, Default: SnowflakeDefaultStringValuePlaceholder, - Description: "The string containing the EntityID / Issuer for the Snowflake service provider. If an incorrect value is specified, Snowflake returns an error message indicating the acceptable values to use.", + Description: SnowflakeDefaultStringValueDescription("The string containing the EntityID / Issuer for the Snowflake service provider. If an incorrect value is specified, Snowflake returns an error message indicating the acceptable values to use."), DiffSuppressFunc: IgnoreChangeToCurrentSnowflakeValueInDescribe("saml2_snowflake_issuer_url"), }, "saml2_snowflake_acs_url": { Type: schema.TypeString, Optional: true, Default: SnowflakeDefaultStringValuePlaceholder, - Description: "The string containing the Snowflake Assertion Consumer Service URL to which the IdP will send its SAML authentication response back to Snowflake. This property will be set in the SAML authentication request generated by Snowflake when initiating a SAML SSO operation with the IdP. If an incorrect value is specified, Snowflake returns an error message indicating the acceptable values to use.", + Description: SnowflakeDefaultStringValueDescription("The string containing the Snowflake Assertion Consumer Service URL to which the IdP will send its SAML authentication response back to Snowflake. This property will be set in the SAML authentication request generated by Snowflake when initiating a SAML SSO operation with the IdP. If an incorrect value is specified, Snowflake returns an error message indicating the acceptable values to use."), DiffSuppressFunc: IgnoreChangeToCurrentSnowflakeValueInDescribe("saml2_snowflake_acs_url"), }, "allowed_user_domains": { @@ -184,6 +179,9 @@ func SAML2Integration() *schema.Resource { CustomizeDiff: customdiff.All( ForceNewIfChangeToEmptySet("allowed_user_domains"), ForceNewIfChangeToEmptySet("allowed_email_patterns"), + ForceNewIfChangeToEmptyString("saml2_snowflake_issuer_url"), + ForceNewIfChangeToEmptyString("saml2_snowflake_acs_url"), + ForceNewIfChangeToEmptyString("saml2_snowflake_x509_cert"), ForceNewIfChangeToEmptyString("saml2_sp_initiated_login_page_label"), ComputedIfAnyAttributeChanged(showOutputAttributeName, "name", "enabled", "comment"), ComputedIfAnyAttributeChanged(describeOutputAttributeName, "saml2_issuer", "saml2_sso_url", "saml2_provider", "saml2_x509_cert", @@ -497,16 +495,6 @@ func ReadContextSAML2Integration(withExternalChangesMarking bool) schema.ReadCon integrationProperties, err := client.SecurityIntegrations.Describe(ctx, id) if err != nil { - if errors.Is(err, sdk.ErrObjectNotFound) { - d.SetId("") - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Warning, - Summary: "Failed to query security integration properties. Marking the resource as removed.", - Detail: fmt.Sprintf("Security integration name: %s, Err: %s", id.FullyQualifiedName(), err), - }, - } - } return diag.FromErr(err) } @@ -734,7 +722,7 @@ func UpdateContextSAML2Integration(ctx context.Context, d *schema.ResourceData, } set.WithEnabled(parsed) } else { - // TODO: UNSET of type is not implemented + // UNSET is not implemented set.WithEnabled(true) } } @@ -761,6 +749,7 @@ func UpdateContextSAML2Integration(ctx context.Context, d *schema.ResourceData, } if d.HasChange("saml2_sp_initiated_login_page_label") { + // UNSET is not implemented (conditional ForceNew on unset) set.WithSaml2SpInitiatedLoginPageLabel(d.Get("saml2_sp_initiated_login_page_label").(string)) } @@ -772,12 +761,13 @@ func UpdateContextSAML2Integration(ctx context.Context, d *schema.ResourceData, } set.WithSaml2EnableSpInitiated(parsed) } else { + // UNSET is not implemented set.WithSaml2EnableSpInitiated(false) } } if d.HasChange("saml2_snowflake_x509_cert") { - // TODO: ForceNew on empty set + // UNSET is not implemented (conditional ForceNew on unset) set.WithSaml2SnowflakeX509Cert(d.Get("saml2_snowflake_x509_cert").(string)) } @@ -789,6 +779,7 @@ func UpdateContextSAML2Integration(ctx context.Context, d *schema.ResourceData, } set.WithSaml2SignRequest(parsed) } else { + // UNSET is not implemented set.WithSaml2SignRequest(false) } } @@ -821,15 +812,18 @@ func UpdateContextSAML2Integration(ctx context.Context, d *schema.ResourceData, } set.WithSaml2ForceAuthn(parsed) } else { + // UNSET is not implemented set.WithSaml2SignRequest(false) } } if d.HasChange("saml2_snowflake_issuer_url") { + // UNSET is not implemented (conditional ForceNew on unset) set.WithSaml2SnowflakeIssuerUrl(d.Get("saml2_snowflake_issuer_url").(string)) } if d.HasChange("saml2_snowflake_acs_url") { + // UNSET is not implemented (conditional ForceNew on unset) set.WithSaml2SnowflakeAcsUrl(d.Get("saml2_snowflake_acs_url").(string)) }