Skip to content

Commit

Permalink
feat: Conclude user rework (#3036)
Browse files Browse the repository at this point in the history
- Add missing descriptions to public keys resource
- Add missing descriptions to the migration guide
- Add missing references to issues
- Add diff suppressors and tests
- Fix review comments from #3032 
- Add missing descriptions for special fields
- Add missing notes to the user resource
  • Loading branch information
sfc-gh-asawicki authored Sep 4, 2024
1 parent 65b64d7 commit 23e4625
Show file tree
Hide file tree
Showing 13 changed files with 160 additions and 56 deletions.
27 changes: 25 additions & 2 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ New fields:
- `mins_to_unlock`
- `mins_to_bypass_mfa`
- `disable_mfa`
- `show_output` - holds the response from `SHOW USERS`. Remember that the field will be only recomputed if one of the user attributes is changed.
- `parameters` - holds the response from `SHOW PARAMETERS IN USER`.

Removed fields:
- `has_rsa_public_key`
Expand All @@ -266,8 +268,8 @@ Default changes:
- `disabled`

Type changes:
- `must_change_password`: bool -> string
- `disabled`: bool -> string
- `must_change_password`: bool -> string (To easily handle three-value logic (true, false, unknown) in provider's configs, read more in https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/751239b7d2fee4757471db6c03b952d4728ee099/v1-preparations/CHANGES_BEFORE_V1.md?plain=1#L24)
- `disabled`: bool -> string (To easily handle three-value logic (true, false, unknown) in provider's configs, read more in https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/751239b7d2fee4757471db6c03b952d4728ee099/v1-preparations/CHANGES_BEFORE_V1.md?plain=1#L24)

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.
Expand All @@ -289,6 +291,27 @@ Changes:

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

#### *(breaking change)* snowflake_user_public_keys usage with snowflake_user

`snowflake_user_public_keys` is a resource allowing to set keys for the given user. Before this version, it was possible to have `snowflake_user` and `snowflake_user_public_keys` used next to each other.
Because the logic handling the keys in `snowflake_user` was fixed, it is advised to use `snowflake_user_public_keys` only when user is not managed through terraform. Having both resources configured for the same user will result in improper behavior.

To migrate, in case of having two resources:
- copy the keys to `rsa_public_key` and `rsa_public_key2` in `snowflake_user`
- remove `snowflake_user_public_keys` from state (following https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/docs/technical-documentation/resource_migration.md#resource-migration)
- remove `snowflake_user_public_keys` from config

#### *(note)* snowflake_user_password_policy_attachment and other user policies

`snowflake_user_password_policy_attachment` is not addressed in the current version.
Attaching other user policies is not addressed in the current version.

Both topics will be addressed in the following versions.

#### *(note)* user types

`service` and `legacy_service` user types are currently not supported. They will be supported in the following versions as separate resources (namely `snowflake_service_user` and `snowflake_legacy_service_user`).

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

Expand Down
16 changes: 12 additions & 4 deletions docs/resources/user.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ description: |-

!> **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.

-> **Note** `snowflake_user_password_policy_attachment` will be reworked in the following versions of the provider which may still affect this resource.

-> **Note** Attaching user policies will be handled in the following versions of the provider which may still affect this resource.

-> **Note** `service` and `legacy_service` user types are currently not supported. They will be supported in the following versions as separate resources (namely `snowflake_service_user` and `snowflake_legacy_service_user`).

-> **Note** External changes to `days_to_expiry`, `mins_to_unlock`, and `mins_to_bypass_mfa` are not currently handled by the provider (because the value changes continuously on Snowflake side after setting 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).
Expand Down Expand Up @@ -62,12 +70,12 @@ resource "snowflake_user" "user" {
- `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).
- `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`.
- `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`. 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".
- `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.
- `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. 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".
- `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.
Expand All @@ -87,8 +95,8 @@ resource "snowflake_user" "user" {
- `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 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.
- `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. 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".
- `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. **Note** because this value changes continuously after setting it, the provider is currently NOT handling the external changes to it. 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".
- `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` (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).
Expand Down
2 changes: 2 additions & 0 deletions docs/resources/user_public_keys.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ description: |-
---

!> **Important** Starting from v0.95.0, it is advised to use this resource **only** if users are not managed through terraform. Check more in the [migration guide](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/MIGRATION_GUIDE.md#v094x--v0950).

# snowflake_user_public_keys (Resource)


Expand Down
16 changes: 16 additions & 0 deletions pkg/acceptance/helpers/user_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,22 @@ func (c *UserClient) SetType(t *testing.T, id sdk.AccountObjectIdentifier, value
require.NoError(t, err)
}

func (c *UserClient) SetLoginName(t *testing.T, id sdk.AccountObjectIdentifier, newLoginName string) {
t.Helper()
ctx := context.Background()

err := c.client().Alter(ctx, id, &sdk.AlterUserOptions{
Set: &sdk.UserSet{
ObjectProperties: &sdk.UserAlterObjectProperties{
UserObjectProperties: sdk.UserObjectProperties{
LoginName: sdk.String(newLoginName),
},
},
},
})
require.NoError(t, err)
}

func (c *UserClient) UnsetDefaultSecondaryRoles(t *testing.T, id sdk.AccountObjectIdentifier) {
t.Helper()
ctx := context.Background()
Expand Down
5 changes: 2 additions & 3 deletions pkg/internal/provider/sdkv2enhancements/resource_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package sdkv2enhancements

import (
"reflect"
"unsafe"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
Expand All @@ -17,9 +16,9 @@ import (
// - terraform.InstanceState and terraform.InstanceDiff are unexported in schema.ResourceDiff, so we get them using reflection
func CreateResourceDataFromResourceDiff(resourceSchema schema.InternalMap, diff *schema.ResourceDiff) (*schema.ResourceData, bool) {
unexportedState := reflect.ValueOf(diff).Elem().FieldByName("state")
stateFromResourceDiff := reflect.NewAt(unexportedState.Type(), unsafe.Pointer(unexportedState.UnsafeAddr())).Elem().Interface()
stateFromResourceDiff := reflect.NewAt(unexportedState.Type(), unexportedState.Addr().UnsafePointer()).Elem().Interface()
unexportedDiff := reflect.ValueOf(diff).Elem().FieldByName("diff")
diffFroResourceDif := reflect.NewAt(unexportedDiff.Type(), unsafe.Pointer(unexportedDiff.UnsafeAddr())).Elem().Interface()
diffFroResourceDif := reflect.NewAt(unexportedDiff.Type(), unexportedDiff.Addr().UnsafePointer()).Elem().Interface()
castState, ok := stateFromResourceDiff.(*terraform.InstanceState)
if !ok {
return nil, false
Expand Down
4 changes: 2 additions & 2 deletions pkg/resources/custom_diffs.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func ForceNewIfChangeToEmptyString(key string) schema.CustomizeDiffFunc {

// ComputedIfAnyAttributeChanged marks the given fields as computed if any of the listed fields changes.
// It takes field-level diffSuppress into consideration based on the schema passed.
// If the field is not found in the given schema, it continues without error.
// If the field is not found in the given schema, it continues without error. Only top level schema fields should be used.
func ComputedIfAnyAttributeChanged(resourceSchema map[string]*schema.Schema, key string, changedAttributeKeys ...string) schema.CustomizeDiffFunc {
return customdiff.ComputedIf(key, func(ctx context.Context, diff *schema.ResourceDiff, meta interface{}) bool {
var result bool
Expand All @@ -106,7 +106,7 @@ func ComputedIfAnyAttributeChanged(resourceSchema map[string]*schema.Schema, key
log.Printf("[DEBUG] ComputedIfAnyAttributeChanged: key %s was changed and the diff is not suppressed", changedKey)
result = true
} else {
log.Printf("[DEBUG] ComputedIfAnyAttributeChanged: key %s was changed but the diff is suppresed", changedKey)
log.Printf("[DEBUG] ComputedIfAnyAttributeChanged: key %s was changed but the diff is suppressed", changedKey)
}
} else {
log.Printf("[DEBUG] ComputedIfAnyAttributeChanged: key %s was changed and it does not have a diff suppressor", changedKey)
Expand Down
1 change: 1 addition & 0 deletions pkg/resources/network_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func NetworkPolicy() *schema.Resource {
// The main issue lays in the old Terraform SDK and how its handling DiffSuppression and CustomizeDiff
// for complex types like Sets, Lists, and Maps. When every element of the Set is suppressed in custom diff,
// it returns true for d.HasChange anyway (it returns false for suppressed changes on primitive types like Number, Bool, String, etc.).
// TODO [SNOW-1648997]: address the above comment
ComputedIfAnyAttributeChanged(
networkPolicySchema,
ShowOutputAttributeName,
Expand Down
Loading

0 comments on commit 23e4625

Please sign in to comment.