Skip to content

Commit

Permalink
feat: Rework user resource (#3026)
Browse files Browse the repository at this point in the history
Rework user resource:
- schema adjusted
- handle show output properly
- updated user acceptance tests with new builders and assertions
- introduce new helpers in `resource_helpers_create.go`,
`resource_helpers_update.go`, and `resource_helpers_read.go`
- cleaned parameters handling a bit
- reused `parameterDef` between user and schema
- removed old way of handling keys in tests
- added float property to the SDK
- added integration tests documenting specific attributes behavior

Next PRs:
- handle policies for user (SNOW-1645875)
- deal with improper custom diffs with diff suppression (SNOW-1629468)
- move collection util (SNOW-1473414)
- remove `checkBool` helper
- datasource
- rename methods in `resource_helpers_read.go`
- update all changes in README (+ note that external changes for a few
attributes)
- change description of user public keys resource (should be used only
if user is not managed by terraform)
- add one more test for login and display name
- check the exact behavior of default_namespace and default_role because
it looks like it is handled in a case-insensitive manner on Snowflake
side
- check if any user parameter needs diffsuppression or validation
- test if hasMfa is always non-nullable, check if this has mfa helps
with disable mfa, add to the describe output too
- test what is visible if everything is set if there is no ownership on
the active role (+ update docs)
- handle `snowflake_user_password_policy_attachment` and
`snowflake_user_public_keys`
- add `IgnoreChangeToCurrentSnowflakeValueInShow` and other suppressors

References:
- #1155 
- #1572
  • Loading branch information
sfc-gh-asawicki authored Sep 1, 2024
1 parent e05377d commit bde2638
Show file tree
Hide file tree
Showing 48 changed files with 2,330 additions and 827 deletions.
37 changes: 34 additions & 3 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,24 +206,55 @@ The following set of [parameters](https://docs.snowflake.com/en/sql-reference/pa

Connected issues: [#2938](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2938)

### *(breaking change)* Changes in sensitiveness of name and login_name
#### *(breaking change)* Changes in sensitiveness of name, login_name, and display_name

According to https://docs.snowflake.com/en/sql-reference/functions/all_user_names#usage-notes, `NAME`s are not considered sensitive data and `LOGIN_NAME`s are. Previous versions of the provider had this the other way around. In this version, `name` attribute was unmarked as sensitive, whereas `login_name` was marked as sensitive. This may break your configuration if you were using `login_name`s before e.g. in a `for_each` loop.

The `display_name` attribute was marked as sensitive. It defaults to `name` if not provided on Snowflake side. Because `name` is no longer sensitive, we also change the setting for the `display_name`.

Connected issues: [#2662](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2662), [#2668](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2668).

### *(bugfix)* Correctly handle `default_warehouse`, `default_namespace`, and `default_role`
#### *(bugfix)* Correctly handle `default_warehouse`, `default_namespace`, and `default_role`

During the [identifiers rework](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/ROADMAP.md#identifiers-rework), we generalized how we compute the differences correctly for the identifier fields (read more in [this document](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/docs/technical-documentation/identifiers_rework_design_decisions.md)). Proper suppressor was applied to `default_warehouse`, `default_namespace`, and `default_role`. Also, all these three attributes were corrected (e.g. handling spaces/hyphens in names).

Connected issues: [#2836](https://github.com/Snowflake-Labs/terraform-provider-snowflake/pull/2836), [#2942](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2942)

### *(bugfix)* Correctly handle failed update
#### *(bugfix)* Correctly handle failed update

Not every attribute can be updated in the state during read (like `password` in the `snowflake_user` resource). In situations where update fails, we may end up with an incorrect state (read more in https://github.com/hashicorp/terraform-plugin-sdk/issues/476). We use a deprecated method from the plugin SDK, and now, for partially failed updates, we preserve the resource's previous state. It fixed this kind of situations for `snowflake_user` resource.

Connected issues: [#2970](https://github.com/Snowflake-Labs/terraform-provider-snowflake/pull/2970)

#### *(breaking change)* Attributes changes

Attributes that are no longer computed:
- `login_name`
- `display_name`
- `disabled`
- `default_role`

New fields:
- `middle_name`
- `days_to_expiry`
- `mins_to_unlock`
- `mins_to_bypass_mfa`
- `disable_mfa`

Removed fields:
- `has_rsa_public_key`

Default changes:
- `must_change_password`
- `disabled`

Type changes:
- `must_change_password`: bool -> string
- `disabled`: bool -> string

Validation changes:
- `default_secondary_roles` - only 1-element lists with `"ALL"` element are now supported. Check [Snowflake docs](https://docs.snowflake.com/en/sql-reference/sql/create-user#optional-object-properties-objectproperties) for more details.

## v0.94.0 ➞ v0.94.1
### changes in snowflake_schema

Expand Down
1 change: 1 addition & 0 deletions docs/data-sources/database_roles.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Read-Only:

- `comment` (String)
- `created_on` (String)
- `database_name` (String)
- `granted_database_roles` (Number)
- `granted_to_database_roles` (Number)
- `granted_to_roles` (Number)
Expand Down
1 change: 1 addition & 0 deletions docs/resources/database_role.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Read-Only:

- `comment` (String)
- `created_on` (String)
- `database_name` (String)
- `granted_database_roles` (Number)
- `granted_to_database_roles` (Number)
- `granted_to_roles` (Number)
Expand Down
35 changes: 21 additions & 14 deletions docs/resources/user.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
page_title: "snowflake_user Resource - terraform-provider-snowflake"
subcategory: ""
description: |-
Resource used to manage user objects. For more information, check user documentation https://docs.snowflake.com/en/sql-reference/commands-user-role.
---

!> **V1 release candidate** This resource was reworked and is a release candidate for the V1. We do not expect significant changes in it before the V1. We will welcome any feedback and adjust the resource if needed. Any errors reported will be resolved with a higher priority. We encourage checking this resource out before the V1 release. Please follow the [migration guide](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/MIGRATION_GUIDE.md#v094x--v0950) to use it.

# snowflake_user (Resource)


Resource used to manage user objects. For more information, check [user documentation](https://docs.snowflake.com/en/sql-reference/commands-user-role).

## Example Usage

Expand Down Expand Up @@ -43,7 +43,7 @@ resource "snowflake_user" "user" {

### Required

- `name` (String) Name of the user. Note that if you do not supply login_name this will be used as login_name. [doc](https://docs.snowflake.net/manuals/sql-reference/sql/create-user.html#required-parameters)
- `name` (String) Name of the user. Note that if you do not supply login_name this will be used as login_name. Check the [docs](https://docs.snowflake.net/manuals/sql-reference/sql/create-user.html#required-parameters). Due to technical limitations (read more [here](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/docs/technical-documentation/identifiers_rework_design_decisions.md#known-limitations-and-identifier-recommendations)), avoid using the following characters: `|`, `.`, `(`, `)`, `"`

### Optional

Expand All @@ -59,15 +59,17 @@ resource "snowflake_user" "user" {
- `client_session_keep_alive` (Boolean) Parameter that indicates whether to force a user to log in again after a period of inactivity in the session. For more information, check [CLIENT_SESSION_KEEP_ALIVE docs](https://docs.snowflake.com/en/sql-reference/parameters#client-session-keep-alive).
- `client_session_keep_alive_heartbeat_frequency` (Number) Number of seconds in-between client attempts to update the token for the session. For more information, check [CLIENT_SESSION_KEEP_ALIVE_HEARTBEAT_FREQUENCY docs](https://docs.snowflake.com/en/sql-reference/parameters#client-session-keep-alive-heartbeat-frequency).
- `client_timestamp_type_mapping` (String) Specifies the [TIMESTAMP_* variation](https://docs.snowflake.com/en/sql-reference/data-types-datetime.html#label-datatypes-timestamp-variations) to use when binding timestamp variables for JDBC or ODBC applications that use the bind API to load data. For more information, check [CLIENT_TIMESTAMP_TYPE_MAPPING docs](https://docs.snowflake.com/en/sql-reference/parameters#client-timestamp-type-mapping).
- `comment` (String)
- `comment` (String) Specifies a comment for the user.
- `date_input_format` (String) Specifies the input format for the DATE data type. For more information, see [Date and time input and output formats](https://docs.snowflake.com/en/sql-reference/date-time-input-output). For more information, check [DATE_INPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#date-input-format).
- `date_output_format` (String) Specifies the display format for the DATE data type. For more information, see [Date and time input and output formats](https://docs.snowflake.com/en/sql-reference/date-time-input-output). For more information, check [DATE_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#date-output-format).
- `default_namespace` (String) Specifies the namespace (database only or database and schema) that is active by default for the user’s session upon login.
- `default_role` (String) Specifies the role that is active by default for the user’s session upon login.
- `default_secondary_roles` (Set of String) Specifies the set of secondary roles that are active for the user’s session upon login. Currently only ["ALL"] value is supported - more information can be found in [doc](https://docs.snowflake.com/en/sql-reference/sql/create-user#optional-object-properties-objectproperties)
- `default_warehouse` (String) Specifies the virtual warehouse that is active by default for the user’s session upon login.
- `disabled` (Boolean)
- `display_name` (String, Sensitive) Name displayed for the user in the Snowflake web interface.
- `days_to_expiry` (Number) Specifies the number of days after which the user status is set to `Expired` and the user is no longer allowed to log in. This is useful for defining temporary users (i.e. users who should only have access to Snowflake for a limited time period). In general, you should not set this property for [account administrators](https://docs.snowflake.com/en/user-guide/security-access-control-considerations.html#label-accountadmin-users) (i.e. users with the `ACCOUNTADMIN` role) because Snowflake locks them out when they become `Expired`.
- `default_namespace` (String) Specifies the namespace (database only or database and schema) that is active by default for the user’s session upon login. Note that the CREATE USER operation does not verify that the namespace exists.
- `default_role` (String) Specifies the role that is active by default for the user’s session upon login. Note that specifying a default role for a user does **not** grant the role to the user. The role must be granted explicitly to the user using the [GRANT ROLE](https://docs.snowflake.com/en/sql-reference/sql/grant-role) command. In addition, the CREATE USER operation does not verify that the role exists.
- `default_secondary_roles` (Set of String) Specifies the set of secondary roles that are active for the user’s session upon login. Currently only ["ALL"] value is supported - more information can be found in [doc](https://docs.snowflake.com/en/sql-reference/sql/create-user#optional-object-properties-objectproperties).
- `default_warehouse` (String) Specifies the virtual warehouse that is active by default for the user’s session upon login. Note that the CREATE USER operation does not verify that the warehouse exists.
- `disable_mfa` (String) Allows enabling or disabling [multi-factor authentication](https://docs.snowflake.com/en/user-guide/security-mfa). Available options are: "true" or "false". When the value is not set in the configuration the provider will put "default" there which means to use the Snowflake default for this value.
- `disabled` (String) Specifies whether the user is disabled, which prevents logging in and aborts all the currently-running queries for the user. Available options are: "true" or "false". When the value is not set in the configuration the provider will put "default" there which means to use the Snowflake default for this value.
- `display_name` (String) Name displayed for the user in the Snowflake web interface.
- `email` (String, Sensitive) Email address for the user.
- `enable_unload_physical_type_optimization` (Boolean) Specifies whether to set the schema for unloaded Parquet files based on the logical column data types (i.e. the types in the unload SQL query or source table) or on the unloaded column values (i.e. the smallest data types and precision that support the values in the output columns of the unload SQL statement or source table). For more information, check [ENABLE_UNLOAD_PHYSICAL_TYPE_OPTIMIZATION docs](https://docs.snowflake.com/en/sql-reference/parameters#enable-unload-physical-type-optimization).
- `enable_unredacted_query_syntax_error` (Boolean) Controls whether query text is redacted if a SQL query fails due to a syntax or parsing error. If `FALSE`, the content of a failed query is redacted in the views, pages, and functions that provide a query history. Only users with a role that is granted or inherits the AUDIT privilege can set the ENABLE_UNREDACTED_QUERY_SYNTAX_ERROR parameter. When using the ALTER USER command to set the parameter to `TRUE` for a particular user, modify the user that you want to see the query text, not the user who executed the query (if those are different users). For more information, check [ENABLE_UNREDACTED_QUERY_SYNTAX_ERROR docs](https://docs.snowflake.com/en/sql-reference/parameters#enable-unredacted-query-syntax-error).
Expand All @@ -83,13 +85,16 @@ resource "snowflake_user" "user" {
- `last_name` (String, Sensitive) Last name of the user.
- `lock_timeout` (Number) Number of seconds to wait while trying to lock a resource, before timing out and aborting the statement. For more information, check [LOCK_TIMEOUT docs](https://docs.snowflake.com/en/sql-reference/parameters#lock-timeout).
- `log_level` (String) Specifies the severity level of messages that should be ingested and made available in the active event table. Messages at the specified level (and at more severe levels) are ingested. For more information about log levels, see [Setting log level](https://docs.snowflake.com/en/developer-guide/logging-tracing/logging-log-level). For more information, check [LOG_LEVEL docs](https://docs.snowflake.com/en/sql-reference/parameters#log-level).
- `login_name` (String, Sensitive) The name users use to log in. If not supplied, snowflake will use name instead.
- `login_name` (String, Sensitive) The name users use to log in. If not supplied, snowflake will use name instead. Login names are always case-insensitive.
- `middle_name` (String, Sensitive) Middle name of the user.
- `mins_to_bypass_mfa` (Number) Specifies the number of minutes to temporarily bypass MFA for the user. This property can be used to allow a MFA-enrolled user to temporarily bypass MFA during login in the event that their MFA device is not available.
- `mins_to_unlock` (Number) Specifies the number of minutes until the temporary lock on the user login is cleared. To protect against unauthorized user login, Snowflake places a temporary lock on a user after five consecutive unsuccessful login attempts. When creating a user, this property can be set to prevent them from logging in until the specified amount of time passes. To remove a lock immediately for a user, specify a value of 0 for this parameter.
- `multi_statement_count` (Number) Number of statements to execute when using the multi-statement capability. For more information, check [MULTI_STATEMENT_COUNT docs](https://docs.snowflake.com/en/sql-reference/parameters#multi-statement-count).
- `must_change_password` (Boolean) Specifies whether the user is forced to change their password on next login (including their first/initial login) into the system.
- `must_change_password` (String) Specifies whether the user is forced to change their password on next login (including their first/initial login) into the system. Available options are: "true" or "false". When the value is not set in the configuration the provider will put "default" there which means to use the Snowflake default for this value.
- `network_policy` (String) Specifies the network policy to enforce for your account. Network policies enable restricting access to your account based on users’ IP address. For more details, see [Controlling network traffic with network policies](https://docs.snowflake.com/en/user-guide/network-policies). Any existing network policy (created using [CREATE NETWORK POLICY](https://docs.snowflake.com/en/sql-reference/sql/create-network-policy)). For more information, check [NETWORK_POLICY docs](https://docs.snowflake.com/en/sql-reference/parameters#network-policy).
- `noorder_sequence_as_default` (Boolean) Specifies whether the ORDER or NOORDER property is set by default when you create a new sequence or add a new table column. The ORDER and NOORDER properties determine whether or not the values are generated for the sequence or auto-incremented column in [increasing or decreasing order](https://docs.snowflake.com/en/user-guide/querying-sequences.html#label-querying-sequences-increasing-values). For more information, check [NOORDER_SEQUENCE_AS_DEFAULT docs](https://docs.snowflake.com/en/sql-reference/parameters#noorder-sequence-as-default).
- `odbc_treat_decimal_as_int` (Boolean) Specifies how ODBC processes columns that have a scale of zero (0). For more information, check [ODBC_TREAT_DECIMAL_AS_INT docs](https://docs.snowflake.com/en/sql-reference/parameters#odbc-treat-decimal-as-int).
- `password` (String, Sensitive) **WARNING:** this will put the password in the terraform state file. Use carefully.
- `password` (String, Sensitive) Password for the user. **WARNING:** this will put the password in the terraform state file. Use carefully.
- `prevent_unload_to_internal_stages` (Boolean) Specifies whether to prevent data unload operations to internal (Snowflake) stages using [COPY INTO <location>](https://docs.snowflake.com/en/sql-reference/sql/copy-into-location) statements. For more information, check [PREVENT_UNLOAD_TO_INTERNAL_STAGES docs](https://docs.snowflake.com/en/sql-reference/parameters#prevent-unload-to-internal-stages).
- `query_tag` (String) Optional string that can be used to tag queries and other SQL statements executed within a session. The tags are displayed in the output of the [QUERY_HISTORY, QUERY_HISTORY_BY_*](https://docs.snowflake.com/en/sql-reference/functions/query_history) functions. For more information, check [QUERY_TAG docs](https://docs.snowflake.com/en/sql-reference/parameters#query-tag).
- `quoted_identifiers_ignore_case` (Boolean) Specifies whether letters in double-quoted object identifiers are stored and resolved as uppercase letters. By default, Snowflake preserves the case of alphabetic characters when storing and resolving double-quoted identifiers (see [Identifier resolution](https://docs.snowflake.com/en/sql-reference/identifiers-syntax.html#label-identifier-casing)). You can use this parameter in situations in which [third-party applications always use double quotes around identifiers](https://docs.snowflake.com/en/sql-reference/identifiers-syntax.html#label-identifier-casing-parameter). For more information, check [QUOTED_IDENTIFIERS_IGNORE_CASE docs](https://docs.snowflake.com/en/sql-reference/parameters#quoted-identifiers-ignore-case).
Expand Down Expand Up @@ -124,10 +129,10 @@ resource "snowflake_user" "user" {
### Read-Only

- `fully_qualified_name` (String) Fully qualified name of the resource. For more information, see [object name resolution](https://docs.snowflake.com/en/sql-reference/name-resolution).
- `has_rsa_public_key` (Boolean) Will be true if user as an RSA key set.
- `id` (String) The ID of this resource.
- `parameters` (List of Object) Outputs the result of `SHOW PARAMETERS IN USER` for the given user. (see [below for nested schema](#nestedatt--parameters))
- `show_output` (List of Object) Outputs the result of `SHOW USER` for the given user. (see [below for nested schema](#nestedatt--show_output))
- `user_type` (String) Specifies a type for the user.

<a id="nestedatt--parameters"></a>
### Nested Schema for `parameters`
Expand Down Expand Up @@ -909,6 +914,7 @@ Read-Only:
- `ext_authn_duo` (Boolean)
- `ext_authn_uid` (String)
- `first_name` (String)
- `has_mfa` (Boolean)
- `has_password` (Boolean)
- `has_rsa_public_key` (Boolean)
- `last_name` (String)
Expand All @@ -921,6 +927,7 @@ Read-Only:
- `name` (String)
- `owner` (String)
- `snowflake_lock` (Boolean)
- `type` (String)

## Import

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,18 @@ func (w *UserAssert) HasDaysToExpiryNotEmpty() *UserAssert {
w.AddAssertion(func(t *testing.T, o *sdk.User) error {
t.Helper()
if o.DaysToExpiry == "" {
return fmt.Errorf("expected days to expiry not empty; got: %v", o.DaysToExpiry)
return fmt.Errorf("expected days to expiry not empty; got empty")
}
return nil
})
return w
}

func (w *UserAssert) HasDaysToExpiryEmpty() *UserAssert {
w.AddAssertion(func(t *testing.T, o *sdk.User) error {
t.Helper()
if o.DaysToExpiry != "" {
return fmt.Errorf("expected days to expiry empty; got: %v", o.DaysToExpiry)
}
return nil
})
Expand Down
Loading

0 comments on commit bde2638

Please sign in to comment.