From 0e88e082282adf35f605c323569908a99bd406f9 Mon Sep 17 00:00:00 2001 From: Artur Sawicki Date: Thu, 10 Oct 2024 10:43:55 +0200 Subject: [PATCH] feat: Add service user and legacy service user resources (#3119) Introduce `snowflake_service_user` and `snowflake_legacy_service_user` resources: - Add new resources (almost the same schema and the same limitations as `snowflake_user` resource - read below) - Adjust datasource and add `type` to the `describe_output` - Adjust SDK: handling types - Add SDK integration tests to validate and document the Snowflake behavior of handling user types (create, alter set, alter unset, and parameters) - Fix `TestAcc_User_issue2970` test - Add migration guide - Generate models and assertions for the new resources - Fix sweepers References: #2951 ##### Implementation considerations Users of different types differ in Snowflake just slightly - a few fields are restricted from SERVICE and LEGACY_SERVICE type users. We decided to split Snowflake resources into multiple resources on our route to V1, to simplify the logic and usage (in this case, not to handle the type changes which are followed by attributes being hidden/revealed). That led to three choices for the implementation, to reuse the existing resource: - copy-paste `snowflake_user` resource - parameterized handling methods of `snowflake_user` resource with the user type - enrich the helper methods with the knowledge of the schema (i.e. to change the logic of setting a field to always check first if the attribute exists in the given schema) Ultimately, the second option was picked for the current implementation. More details of pros and cons of each solution are presented in points below. ###### copy-paste Pros: - Fastest implementation - We plan to ultimately generate the resources, so at the end the implementation would be close to duplicated resources Cons: - Need to alter the logic in three different places - Separate implementation of resources would require separate complete set of tests ###### parameterized handling methods Pros: - user object handled in "one" place - implementation reused, so only smoke acceptance tests are justified Cons: - more complex logic in user resource, spread over multiple handling methods ###### enrich the helper methods Pros: - user resource implementation could stay the same in helper methods (because the checks would be delegated to helper methods) - solution that can be reused in more resources - only smoke tests would be justified Cons: - SDKv2 does not allow to fetch the schema in context of helper methods without exposing unexported fields - "unsafe" solution potentially used in the majority of resources (because helper methods should be reused more and more) --- MIGRATION_GUIDE.md | 61 + docs/data-sources/users.md | 1 + docs/resources/legacy_service_user.md | 1013 +++++++++++++++ docs/resources/service_user.md | 1008 +++++++++++++++ docs/resources/user.md | 103 +- .../snowflake_legacy_service_user/import.sh | 1 + .../snowflake_legacy_service_user/resource.tf | 92 ++ .../snowflake_service_user/import.sh | 1 + .../snowflake_service_user/resource.tf | 89 ++ examples/resources/snowflake_user/import.sh | 2 +- examples/resources/snowflake_user/resource.tf | 95 +- .../resourceassert/gen/resource_schema_def.go | 8 + .../legacy_service_user_resource_ext.go | 22 + .../legacy_service_user_resource_gen.go | 797 ++++++++++++ .../service_user_resource_ext.go | 17 + .../service_user_resource_gen.go | 777 ++++++++++++ .../model/legacy_service_user_model_ext.go | 66 + .../model/legacy_service_user_model_gen.go | 880 +++++++++++++ .../config/model/service_user_model_ext.go | 66 + .../config/model/service_user_model_gen.go | 858 +++++++++++++ pkg/acceptance/check_destroy.go | 6 + pkg/acceptance/helpers/user_client.go | 46 +- pkg/datasources/users_acceptance_test.go | 335 ++++- pkg/provider/provider.go | 2 + pkg/provider/resources/resources.go | 2 + pkg/resources/custom_diffs.go | 18 + pkg/resources/custom_diffs_test.go | 149 +++ .../legacy_service_user_acceptance_test.go | 651 ++++++++++ pkg/resources/service_user_acceptance_test.go | 643 ++++++++++ pkg/resources/user.go | 573 +++++---- pkg/resources/user_acceptance_test.go | 40 +- pkg/resources/user_commons.go | 74 ++ pkg/schemas/user_describe.go | 7 + pkg/sdk/sweepers_test.go | 12 +- pkg/sdk/testint/users_integration_test.go | 1109 +++++++++++++---- pkg/sdk/users.go | 53 +- pkg/sdk/users_test.go | 71 +- .../resources/legacy_service_user.md.tmpl | 43 + templates/resources/service_user.md.tmpl | 43 + templates/resources/user.md.tmpl | 2 +- 40 files changed, 9312 insertions(+), 524 deletions(-) create mode 100644 docs/resources/legacy_service_user.md create mode 100644 docs/resources/service_user.md create mode 100644 examples/resources/snowflake_legacy_service_user/import.sh create mode 100644 examples/resources/snowflake_legacy_service_user/resource.tf create mode 100644 examples/resources/snowflake_service_user/import.sh create mode 100644 examples/resources/snowflake_service_user/resource.tf create mode 100644 pkg/acceptance/bettertestspoc/assert/resourceassert/legacy_service_user_resource_ext.go create mode 100644 pkg/acceptance/bettertestspoc/assert/resourceassert/legacy_service_user_resource_gen.go create mode 100644 pkg/acceptance/bettertestspoc/assert/resourceassert/service_user_resource_ext.go create mode 100644 pkg/acceptance/bettertestspoc/assert/resourceassert/service_user_resource_gen.go create mode 100644 pkg/acceptance/bettertestspoc/config/model/legacy_service_user_model_ext.go create mode 100644 pkg/acceptance/bettertestspoc/config/model/legacy_service_user_model_gen.go create mode 100644 pkg/acceptance/bettertestspoc/config/model/service_user_model_ext.go create mode 100644 pkg/acceptance/bettertestspoc/config/model/service_user_model_gen.go create mode 100644 pkg/resources/legacy_service_user_acceptance_test.go create mode 100644 pkg/resources/service_user_acceptance_test.go create mode 100644 pkg/resources/user_commons.go create mode 100644 templates/resources/legacy_service_user.md.tmpl create mode 100644 templates/resources/service_user.md.tmpl diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 4c461f6fa8..460c40bf92 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -47,6 +47,67 @@ resource "snowflake_stream_on_table" "stream" { Then, follow our [Resource migration guide](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/docs/technical-documentation/resource_migration.md). +### *(new feature)* new snowflake_service_user and snowflake_legacy_service_user resources + +Release v0.95.0 introduced reworked `snowflake_user` resource. As [noted](#note-user-types), the new `SERVICE` and `LEGACY_SERVICE` user types were not supported. + +This release introduces two new resources to handle these new user types: `snowflake_service_user` and `snowflake_legacy_service_user`. + +Both resources have schemas almost identical to the `snowflake_user` resource with the following exceptions: +- `snowflake_service_user` does not contain the following fields (because they are not supported for the user of type `SERVICE` in Snowflake): + - `password` + - `first_name` + - `middle_name` + - `last_name` + - `must_change_password` + - `mins_to_bypass_mfa` + - `disable_mfa` +- `snowflake_legacy_service_user` does not contain the following fields (because they are not supported for the user of type `LEGACY_SERVICE` in Snowflake): + - `first_name` + - `middle_name` + - `last_name` + - `mins_to_bypass_mfa` + - `disable_mfa` + +`snowflake_users` datasource was adjusted to handle different user types and `type` field was added to the `describe_output`. + +If you used to manage service or legacy service users through `snowflake_user` resource (e.g. using `lifecycle.ignore_changes`) or `snowflake_unsafe_execute`, please migrate to the new resources following [our guidelines on resource migration](docs/technical-documentation/resource_migration.md). + +E.g. change the old config from: + +```terraform +resource "snowflake_user" "service_user" { + lifecycle { + ignore_changes = [user_type] + } + + name = "Snowflake Service User" + login_name = "service_user" + email = "service_user@snowflake.example" + + rsa_public_key = "..." + rsa_public_key_2 = "..." +} +``` + +to + +``` +resource "snowflake_service_user" "service_user" { + name = "Snowflake Service User" + login_name = "service_user" + email = "service_user@snowflake.example" + + rsa_public_key = "..." + rsa_public_key_2 = "..." +} + +``` + +Then, follow our [resource migration guide](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/docs/technical-documentation/resource_migration.md). + +Connected issues: [#2951](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2951) + ## v0.95.0 ➞ v0.96.0 ### snowflake_masking_policies data source changes diff --git a/docs/data-sources/users.md b/docs/data-sources/users.md index e59fc18b17..c5e501510f 100644 --- a/docs/data-sources/users.md +++ b/docs/data-sources/users.md @@ -162,6 +162,7 @@ Read-Only: - `rsa_public_key_fp` (String) - `snowflake_lock` (Boolean) - `snowflake_support` (Boolean) +- `type` (String) diff --git a/docs/resources/legacy_service_user.md b/docs/resources/legacy_service_user.md new file mode 100644 index 0000000000..bd5865064b --- /dev/null +++ b/docs/resources/legacy_service_user.md @@ -0,0 +1,1013 @@ +--- +page_title: "snowflake_legacy_service_user Resource - terraform-provider-snowflake" +subcategory: "" +description: |- + Resource used to manage legacy service user objects. For more information, check user documentation https://docs.snowflake.com/en/sql-reference/commands-user-role#user-management. +--- + +!> **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#v0960--v0970) 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** Other two user types are handled in separate resources: `snowflake_service_user` for user type `service` and `snowflake_user` for user type `person`. + +-> **Note** External changes to `days_to_expiry` and `mins_to_unlock` are not currently handled by the provider (because the value changes continuously on Snowflake side after setting it). + +# snowflake_legacy_service_user (Resource) + +Resource used to manage legacy service user objects. For more information, check [user documentation](https://docs.snowflake.com/en/sql-reference/commands-user-role#user-management). + +## Example Usage + +```terraform +# minimal +resource "snowflake_legacy_service_user" "minimal" { + name = "Snowflake Legacy Service User - minimal" +} + +# with all attributes set +resource "snowflake_legacy_service_user" "user" { + name = "Snowflake Legacy Service User" + login_name = "legacy_service_user" + comment = "A legacy service user of snowflake." + password = "secret" + disabled = "false" + display_name = "Snowflake Legacy Service User display name" + email = "legacy.service.user@snowflake.example" + + default_warehouse = "warehouse" + default_secondary_roles_option = "ALL" + default_role = "role1" + default_namespace = "some.namespace" + + mins_to_unlock = 9 + days_to_expiry = 8 + + rsa_public_key = "..." + rsa_public_key_2 = "..." + + must_change_password = "true" +} + +# all parameters set on the resource level +resource "snowflake_legacy_service_user" "u" { + name = "Snowflake Legacy Service User with all parameters" + + abort_detached_query = true + autocommit = false + binary_input_format = "UTF8" + binary_output_format = "BASE64" + client_memory_limit = 1024 + client_metadata_request_use_connection_ctx = true + client_prefetch_threads = 2 + client_result_chunk_size = 48 + client_result_column_case_insensitive = true + client_session_keep_alive = true + client_session_keep_alive_heartbeat_frequency = 2400 + client_timestamp_type_mapping = "TIMESTAMP_NTZ" + date_input_format = "YYYY-MM-DD" + date_output_format = "YY-MM-DD" + enable_unload_physical_type_optimization = false + enable_unredacted_query_syntax_error = true + error_on_nondeterministic_merge = false + error_on_nondeterministic_update = true + geography_output_format = "WKB" + geometry_output_format = "WKB" + jdbc_treat_decimal_as_int = false + jdbc_treat_timestamp_ntz_as_utc = true + jdbc_use_session_timezone = false + json_indent = 4 + lock_timeout = 21222 + log_level = "ERROR" + multi_statement_count = 0 + network_policy = "BVYDGRAT_0D5E3DD1_F644_03DE_318A_1179886518A7" + noorder_sequence_as_default = false + odbc_treat_decimal_as_int = true + prevent_unload_to_internal_stages = true + query_tag = "some_tag" + quoted_identifiers_ignore_case = true + rows_per_resultset = 2 + search_path = "$public, $current" + simulated_data_sharing_consumer = "some_consumer" + statement_queued_timeout_in_seconds = 10 + statement_timeout_in_seconds = 10 + strict_json_output = true + s3_stage_vpce_dns_name = "vpce-id.s3.region.vpce.amazonaws.com" + time_input_format = "HH24:MI" + time_output_format = "HH24:MI" + timestamp_day_is_always_24h = true + timestamp_input_format = "YYYY-MM-DD" + timestamp_ltz_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_ntz_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_type_mapping = "TIMESTAMP_LTZ" + timestamp_tz_output_format = "YYYY-MM-DD HH24:MI:SS" + timezone = "Europe/Warsaw" + trace_level = "ON_EVENT" + transaction_abort_on_error = true + transaction_default_isolation_level = "READ COMMITTED" + two_digit_century_start = 1980 + unsupported_ddl_action = "FAIL" + use_cached_result = false + week_of_year_policy = 1 + week_start = 1 +} +``` +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + + + +## Schema + +### Required + +- `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 + +- `abort_detached_query` (Boolean) Specifies the action that Snowflake performs for in-progress queries if connectivity is lost due to abrupt termination of a session (e.g. network outage, browser termination, service interruption). For more information, check [ABORT_DETACHED_QUERY docs](https://docs.snowflake.com/en/sql-reference/parameters#abort-detached-query). +- `autocommit` (Boolean) Specifies whether autocommit is enabled for the session. Autocommit determines whether a DML statement, when executed without an active transaction, is automatically committed after the statement successfully completes. For more information, see [Transactions](https://docs.snowflake.com/en/sql-reference/transactions). For more information, check [AUTOCOMMIT docs](https://docs.snowflake.com/en/sql-reference/parameters#autocommit). +- `binary_input_format` (String) The format of VARCHAR values passed as input to VARCHAR-to-BINARY conversion functions. For more information, see [Binary input and output](https://docs.snowflake.com/en/sql-reference/binary-input-output). For more information, check [BINARY_INPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#binary-input-format). +- `binary_output_format` (String) The format for VARCHAR values returned as output by BINARY-to-VARCHAR conversion functions. For more information, see [Binary input and output](https://docs.snowflake.com/en/sql-reference/binary-input-output). For more information, check [BINARY_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#binary-output-format). +- `client_memory_limit` (Number) Parameter that specifies the maximum amount of memory the JDBC driver or ODBC driver should use for the result set from queries (in MB). For more information, check [CLIENT_MEMORY_LIMIT docs](https://docs.snowflake.com/en/sql-reference/parameters#client-memory-limit). +- `client_metadata_request_use_connection_ctx` (Boolean) For specific ODBC functions and JDBC methods, this parameter can change the default search scope from all databases/schemas to the current database/schema. The narrower search typically returns fewer rows and executes more quickly. For more information, check [CLIENT_METADATA_REQUEST_USE_CONNECTION_CTX docs](https://docs.snowflake.com/en/sql-reference/parameters#client-metadata-request-use-connection-ctx). +- `client_prefetch_threads` (Number) Parameter that specifies the number of threads used by the client to pre-fetch large result sets. The driver will attempt to honor the parameter value, but defines the minimum and maximum values (depending on your system’s resources) to improve performance. For more information, check [CLIENT_PREFETCH_THREADS docs](https://docs.snowflake.com/en/sql-reference/parameters#client-prefetch-threads). +- `client_result_chunk_size` (Number) Parameter that specifies the maximum size of each set (or chunk) of query results to download (in MB). The JDBC driver downloads query results in chunks. For more information, check [CLIENT_RESULT_CHUNK_SIZE docs](https://docs.snowflake.com/en/sql-reference/parameters#client-result-chunk-size). +- `client_result_column_case_insensitive` (Boolean) Parameter that indicates whether to match column name case-insensitively in ResultSet.get* methods in JDBC. For more information, check [CLIENT_RESULT_COLUMN_CASE_INSENSITIVE docs](https://docs.snowflake.com/en/sql-reference/parameters#client-result-column-case-insensitive). +- `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) 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`. 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_option` (String) Specifies the secondary roles that are active for the user’s session upon login. Valid values are (case-insensitive): `DEFAULT` | `NONE` | `ALL`. 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. +- `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). +- `error_on_nondeterministic_merge` (Boolean) Specifies whether to return an error when the [MERGE](https://docs.snowflake.com/en/sql-reference/sql/merge) command is used to update or delete a target row that joins multiple source rows and the system cannot determine the action to perform on the target row. For more information, check [ERROR_ON_NONDETERMINISTIC_MERGE docs](https://docs.snowflake.com/en/sql-reference/parameters#error-on-nondeterministic-merge). +- `error_on_nondeterministic_update` (Boolean) Specifies whether to return an error when the [UPDATE](https://docs.snowflake.com/en/sql-reference/sql/update) command is used to update a target row that joins multiple source rows and the system cannot determine the action to perform on the target row. For more information, check [ERROR_ON_NONDETERMINISTIC_UPDATE docs](https://docs.snowflake.com/en/sql-reference/parameters#error-on-nondeterministic-update). +- `geography_output_format` (String) Display format for [GEOGRAPHY values](https://docs.snowflake.com/en/sql-reference/data-types-geospatial.html#label-data-types-geography). For more information, check [GEOGRAPHY_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#geography-output-format). +- `geometry_output_format` (String) Display format for [GEOMETRY values](https://docs.snowflake.com/en/sql-reference/data-types-geospatial.html#label-data-types-geometry). For more information, check [GEOMETRY_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#geometry-output-format). +- `jdbc_treat_decimal_as_int` (Boolean) Specifies how JDBC processes columns that have a scale of zero (0). For more information, check [JDBC_TREAT_DECIMAL_AS_INT docs](https://docs.snowflake.com/en/sql-reference/parameters#jdbc-treat-decimal-as-int). +- `jdbc_treat_timestamp_ntz_as_utc` (Boolean) Specifies how JDBC processes TIMESTAMP_NTZ values. For more information, check [JDBC_TREAT_TIMESTAMP_NTZ_AS_UTC docs](https://docs.snowflake.com/en/sql-reference/parameters#jdbc-treat-timestamp-ntz-as-utc). +- `jdbc_use_session_timezone` (Boolean) Specifies whether the JDBC Driver uses the time zone of the JVM or the time zone of the session (specified by the [TIMEZONE](https://docs.snowflake.com/en/sql-reference/parameters#label-timezone) parameter) for the getDate(), getTime(), and getTimestamp() methods of the ResultSet class. For more information, check [JDBC_USE_SESSION_TIMEZONE docs](https://docs.snowflake.com/en/sql-reference/parameters#jdbc-use-session-timezone). +- `json_indent` (Number) Specifies the number of blank spaces to indent each new element in JSON output in the session. Also specifies whether to insert newline characters after each element. For more information, check [JSON_INDENT docs](https://docs.snowflake.com/en/sql-reference/parameters#json-indent). +- `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 names are always case-insensitive. +- `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). +- `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) 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 ](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). +- `rows_per_resultset` (Number) Specifies the maximum number of rows returned in a result set. A value of 0 specifies no maximum. For more information, check [ROWS_PER_RESULTSET docs](https://docs.snowflake.com/en/sql-reference/parameters#rows-per-resultset). +- `rsa_public_key` (String) Specifies the user’s RSA public key; used for key-pair authentication. Must be on 1 line without header and trailer. +- `rsa_public_key_2` (String) Specifies the user’s second RSA public key; used to rotate the public and private keys for key-pair authentication based on an expiration schedule set by your organization. Must be on 1 line without header and trailer. +- `s3_stage_vpce_dns_name` (String) Specifies the DNS name of an Amazon S3 interface endpoint. Requests sent to the internal stage of an account via [AWS PrivateLink for Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/privatelink-interface-endpoints.html) use this endpoint to connect. For more information, see [Accessing Internal stages with dedicated interface endpoints](https://docs.snowflake.com/en/user-guide/private-internal-stages-aws.html#label-aws-privatelink-internal-stage-network-isolation). For more information, check [S3_STAGE_VPCE_DNS_NAME docs](https://docs.snowflake.com/en/sql-reference/parameters#s3-stage-vpce-dns-name). +- `search_path` (String) Specifies the path to search to resolve unqualified object names in queries. For more information, see [Name resolution in queries](https://docs.snowflake.com/en/sql-reference/name-resolution.html#label-object-name-resolution-search-path). Comma-separated list of identifiers. An identifier can be a fully or partially qualified schema name. For more information, check [SEARCH_PATH docs](https://docs.snowflake.com/en/sql-reference/parameters#search-path). +- `simulated_data_sharing_consumer` (String) Specifies the name of a consumer account to simulate for testing/validating shared data, particularly shared secure views. When this parameter is set in a session, shared views return rows as if executed in the specified consumer account rather than the provider account. For more information, see [Introduction to Secure Data Sharing](https://docs.snowflake.com/en/user-guide/data-sharing-intro) and [Working with shares](https://docs.snowflake.com/en/user-guide/data-sharing-provider). For more information, check [SIMULATED_DATA_SHARING_CONSUMER docs](https://docs.snowflake.com/en/sql-reference/parameters#simulated-data-sharing-consumer). +- `statement_queued_timeout_in_seconds` (Number) Amount of time, in seconds, a SQL statement (query, DDL, DML, etc.) remains queued for a warehouse before it is canceled by the system. This parameter can be used in conjunction with the [MAX_CONCURRENCY_LEVEL](https://docs.snowflake.com/en/sql-reference/parameters#label-max-concurrency-level) parameter to ensure a warehouse is never backlogged. For more information, check [STATEMENT_QUEUED_TIMEOUT_IN_SECONDS docs](https://docs.snowflake.com/en/sql-reference/parameters#statement-queued-timeout-in-seconds). +- `statement_timeout_in_seconds` (Number) Amount of time, in seconds, after which a running SQL statement (query, DDL, DML, etc.) is canceled by the system. For more information, check [STATEMENT_TIMEOUT_IN_SECONDS docs](https://docs.snowflake.com/en/sql-reference/parameters#statement-timeout-in-seconds). +- `strict_json_output` (Boolean) This parameter specifies whether JSON output in a session is compatible with the general standard (as described by [http://json.org](http://json.org)). By design, Snowflake allows JSON input that contains non-standard values; however, these non-standard values might result in Snowflake outputting JSON that is incompatible with other platforms and languages. This parameter, when enabled, ensures that Snowflake outputs valid/compatible JSON. For more information, check [STRICT_JSON_OUTPUT docs](https://docs.snowflake.com/en/sql-reference/parameters#strict-json-output). +- `time_input_format` (String) Specifies the input format for the TIME data type. For more information, see [Date and time input and output formats](https://docs.snowflake.com/en/sql-reference/date-time-input-output). Any valid, supported time format or AUTO (AUTO specifies that Snowflake attempts to automatically detect the format of times stored in the system during the session). For more information, check [TIME_INPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#time-input-format). +- `time_output_format` (String) Specifies the display format for the TIME 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 [TIME_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#time-output-format). +- `timestamp_day_is_always_24h` (Boolean) Specifies whether the [DATEADD](https://docs.snowflake.com/en/sql-reference/functions/dateadd) function (and its aliases) always consider a day to be exactly 24 hours for expressions that span multiple days. For more information, check [TIMESTAMP_DAY_IS_ALWAYS_24H docs](https://docs.snowflake.com/en/sql-reference/parameters#timestamp-day-is-always-24h). +- `timestamp_input_format` (String) Specifies the input format for the TIMESTAMP data type alias. For more information, see [Date and time input and output formats](https://docs.snowflake.com/en/sql-reference/date-time-input-output). Any valid, supported timestamp format or AUTO (AUTO specifies that Snowflake attempts to automatically detect the format of timestamps stored in the system during the session). For more information, check [TIMESTAMP_INPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#timestamp-input-format). +- `timestamp_ltz_output_format` (String) Specifies the display format for the TIMESTAMP_LTZ data type. If no format is specified, defaults to [TIMESTAMP_OUTPUT_FORMAT](https://docs.snowflake.com/en/sql-reference/parameters#label-timestamp-output-format). 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 [TIMESTAMP_LTZ_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#timestamp-ltz-output-format). +- `timestamp_ntz_output_format` (String) Specifies the display format for the TIMESTAMP_NTZ data type. For more information, check [TIMESTAMP_NTZ_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#timestamp-ntz-output-format). +- `timestamp_output_format` (String) Specifies the display format for the TIMESTAMP data type alias. 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 [TIMESTAMP_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#timestamp-output-format). +- `timestamp_type_mapping` (String) Specifies the TIMESTAMP_* variation that the TIMESTAMP data type alias maps to. For more information, check [TIMESTAMP_TYPE_MAPPING docs](https://docs.snowflake.com/en/sql-reference/parameters#timestamp-type-mapping). +- `timestamp_tz_output_format` (String) Specifies the display format for the TIMESTAMP_TZ data type. If no format is specified, defaults to [TIMESTAMP_OUTPUT_FORMAT](https://docs.snowflake.com/en/sql-reference/parameters#label-timestamp-output-format). 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 [TIMESTAMP_TZ_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#timestamp-tz-output-format). +- `timezone` (String) Specifies the time zone for the session. You can specify a [time zone name](https://data.iana.org/time-zones/tzdb-2021a/zone1970.tab) or a [link name](https://data.iana.org/time-zones/tzdb-2021a/backward) from release 2021a of the [IANA Time Zone Database](https://www.iana.org/time-zones) (e.g. America/Los_Angeles, Europe/London, UTC, Etc/GMT, etc.). For more information, check [TIMEZONE docs](https://docs.snowflake.com/en/sql-reference/parameters#timezone). +- `trace_level` (String) Controls how trace events are ingested into the event table. For more information about trace levels, see [Setting trace level](https://docs.snowflake.com/en/developer-guide/logging-tracing/tracing-trace-level). For more information, check [TRACE_LEVEL docs](https://docs.snowflake.com/en/sql-reference/parameters#trace-level). +- `transaction_abort_on_error` (Boolean) Specifies the action to perform when a statement issued within a non-autocommit transaction returns with an error. For more information, check [TRANSACTION_ABORT_ON_ERROR docs](https://docs.snowflake.com/en/sql-reference/parameters#transaction-abort-on-error). +- `transaction_default_isolation_level` (String) Specifies the isolation level for transactions in the user session. For more information, check [TRANSACTION_DEFAULT_ISOLATION_LEVEL docs](https://docs.snowflake.com/en/sql-reference/parameters#transaction-default-isolation-level). +- `two_digit_century_start` (Number) Specifies the “century start” year for 2-digit years (i.e. the earliest year such dates can represent). This parameter prevents ambiguous dates when importing or converting data with the `YY` date format component (i.e. years represented as 2 digits). For more information, check [TWO_DIGIT_CENTURY_START docs](https://docs.snowflake.com/en/sql-reference/parameters#two-digit-century-start). +- `unsupported_ddl_action` (String) Determines if an unsupported (i.e. non-default) value specified for a constraint property returns an error. For more information, check [UNSUPPORTED_DDL_ACTION docs](https://docs.snowflake.com/en/sql-reference/parameters#unsupported-ddl-action). +- `use_cached_result` (Boolean) Specifies whether to reuse persisted query results, if available, when a matching query is submitted. For more information, check [USE_CACHED_RESULT docs](https://docs.snowflake.com/en/sql-reference/parameters#use-cached-result). +- `week_of_year_policy` (Number) Specifies how the weeks in a given year are computed. `0`: The semantics used are equivalent to the ISO semantics, in which a week belongs to a given year if at least 4 days of that week are in that year. `1`: January 1 is included in the first week of the year and December 31 is included in the last week of the year. For more information, check [WEEK_OF_YEAR_POLICY docs](https://docs.snowflake.com/en/sql-reference/parameters#week-of-year-policy). +- `week_start` (Number) Specifies the first day of the week (used by week-related date functions). `0`: Legacy Snowflake behavior is used (i.e. ISO-like semantics). `1` (Monday) to `7` (Sunday): All the week-related functions use weeks that start on the specified day of the week. For more information, check [WEEK_START docs](https://docs.snowflake.com/en/sql-reference/parameters#week-start). + +### 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). +- `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. + + +### Nested Schema for `parameters` + +Read-Only: + +- `abort_detached_query` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--abort_detached_query)) +- `autocommit` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--autocommit)) +- `binary_input_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--binary_input_format)) +- `binary_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--binary_output_format)) +- `client_memory_limit` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_memory_limit)) +- `client_metadata_request_use_connection_ctx` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_metadata_request_use_connection_ctx)) +- `client_prefetch_threads` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_prefetch_threads)) +- `client_result_chunk_size` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_result_chunk_size)) +- `client_result_column_case_insensitive` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_result_column_case_insensitive)) +- `client_session_keep_alive` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_session_keep_alive)) +- `client_session_keep_alive_heartbeat_frequency` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_session_keep_alive_heartbeat_frequency)) +- `client_timestamp_type_mapping` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_timestamp_type_mapping)) +- `date_input_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--date_input_format)) +- `date_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--date_output_format)) +- `enable_unload_physical_type_optimization` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--enable_unload_physical_type_optimization)) +- `enable_unredacted_query_syntax_error` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--enable_unredacted_query_syntax_error)) +- `error_on_nondeterministic_merge` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--error_on_nondeterministic_merge)) +- `error_on_nondeterministic_update` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--error_on_nondeterministic_update)) +- `geography_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--geography_output_format)) +- `geometry_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--geometry_output_format)) +- `jdbc_treat_decimal_as_int` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--jdbc_treat_decimal_as_int)) +- `jdbc_treat_timestamp_ntz_as_utc` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--jdbc_treat_timestamp_ntz_as_utc)) +- `jdbc_use_session_timezone` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--jdbc_use_session_timezone)) +- `json_indent` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--json_indent)) +- `lock_timeout` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--lock_timeout)) +- `log_level` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--log_level)) +- `multi_statement_count` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--multi_statement_count)) +- `network_policy` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--network_policy)) +- `noorder_sequence_as_default` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--noorder_sequence_as_default)) +- `odbc_treat_decimal_as_int` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--odbc_treat_decimal_as_int)) +- `prevent_unload_to_internal_stages` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--prevent_unload_to_internal_stages)) +- `query_tag` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--query_tag)) +- `quoted_identifiers_ignore_case` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--quoted_identifiers_ignore_case)) +- `rows_per_resultset` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--rows_per_resultset)) +- `s3_stage_vpce_dns_name` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--s3_stage_vpce_dns_name)) +- `search_path` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--search_path)) +- `simulated_data_sharing_consumer` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--simulated_data_sharing_consumer)) +- `statement_queued_timeout_in_seconds` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--statement_queued_timeout_in_seconds)) +- `statement_timeout_in_seconds` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--statement_timeout_in_seconds)) +- `strict_json_output` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--strict_json_output)) +- `time_input_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--time_input_format)) +- `time_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--time_output_format)) +- `timestamp_day_is_always_24h` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timestamp_day_is_always_24h)) +- `timestamp_input_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timestamp_input_format)) +- `timestamp_ltz_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timestamp_ltz_output_format)) +- `timestamp_ntz_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timestamp_ntz_output_format)) +- `timestamp_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timestamp_output_format)) +- `timestamp_type_mapping` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timestamp_type_mapping)) +- `timestamp_tz_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timestamp_tz_output_format)) +- `timezone` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timezone)) +- `trace_level` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--trace_level)) +- `transaction_abort_on_error` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--transaction_abort_on_error)) +- `transaction_default_isolation_level` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--transaction_default_isolation_level)) +- `two_digit_century_start` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--two_digit_century_start)) +- `unsupported_ddl_action` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--unsupported_ddl_action)) +- `use_cached_result` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--use_cached_result)) +- `week_of_year_policy` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--week_of_year_policy)) +- `week_start` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--week_start)) + + +### Nested Schema for `parameters.abort_detached_query` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.autocommit` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.binary_input_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.binary_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_memory_limit` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_metadata_request_use_connection_ctx` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_prefetch_threads` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_result_chunk_size` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_result_column_case_insensitive` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_session_keep_alive` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_session_keep_alive_heartbeat_frequency` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_timestamp_type_mapping` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.date_input_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.date_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.enable_unload_physical_type_optimization` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.enable_unredacted_query_syntax_error` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.error_on_nondeterministic_merge` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.error_on_nondeterministic_update` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.geography_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.geometry_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.jdbc_treat_decimal_as_int` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.jdbc_treat_timestamp_ntz_as_utc` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.jdbc_use_session_timezone` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.json_indent` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.lock_timeout` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.log_level` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.multi_statement_count` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.network_policy` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.noorder_sequence_as_default` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.odbc_treat_decimal_as_int` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.prevent_unload_to_internal_stages` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.query_tag` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.quoted_identifiers_ignore_case` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.rows_per_resultset` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.s3_stage_vpce_dns_name` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.search_path` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.simulated_data_sharing_consumer` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.statement_queued_timeout_in_seconds` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.statement_timeout_in_seconds` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.strict_json_output` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.time_input_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.time_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timestamp_day_is_always_24h` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timestamp_input_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timestamp_ltz_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timestamp_ntz_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timestamp_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timestamp_type_mapping` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timestamp_tz_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timezone` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.trace_level` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.transaction_abort_on_error` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.transaction_default_isolation_level` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.two_digit_century_start` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.unsupported_ddl_action` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.use_cached_result` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.week_of_year_policy` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.week_start` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + + +### Nested Schema for `show_output` + +Read-Only: + +- `comment` (String) +- `created_on` (String) +- `days_to_expiry` (String) +- `default_namespace` (String) +- `default_role` (String) +- `default_secondary_roles` (String) +- `default_warehouse` (String) +- `disabled` (Boolean) +- `display_name` (String) +- `email` (String) +- `expires_at_time` (String) +- `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) +- `last_success_login` (String) +- `locked_until_time` (String) +- `login_name` (String) +- `mins_to_bypass_mfa` (String) +- `mins_to_unlock` (String) +- `must_change_password` (Boolean) +- `name` (String) +- `owner` (String) +- `snowflake_lock` (Boolean) +- `type` (String) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import snowflake_legacy_service_user.example '""' +``` diff --git a/docs/resources/service_user.md b/docs/resources/service_user.md new file mode 100644 index 0000000000..dd74130322 --- /dev/null +++ b/docs/resources/service_user.md @@ -0,0 +1,1008 @@ +--- +page_title: "snowflake_service_user Resource - terraform-provider-snowflake" +subcategory: "" +description: |- + Resource used to manage service user objects. For more information, check user documentation https://docs.snowflake.com/en/sql-reference/commands-user-role#user-management. +--- + +!> **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#v0960--v0970) 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** Other two user types are handled in separate resources: `snowflake_legacy_service_user` for user type `legacy_service` and `snowflake_user` for user type `person`. + +-> **Note** External changes to `days_to_expiry` and `mins_to_unlock` are not currently handled by the provider (because the value changes continuously on Snowflake side after setting it). + +# snowflake_service_user (Resource) + +Resource used to manage service user objects. For more information, check [user documentation](https://docs.snowflake.com/en/sql-reference/commands-user-role#user-management). + +## Example Usage + +```terraform +# minimal +resource "snowflake_service_user" "minimal" { + name = "Snowflake Service User - minimal" +} + +# with all attributes set +resource "snowflake_service_user" "service_user" { + name = "Snowflake Service User" + login_name = "service_user" + comment = "A service user of snowflake." + disabled = "false" + display_name = "Snowflake Service User" + email = "service_user@snowflake.example" + + default_warehouse = "warehouse" + default_secondary_roles_option = "ALL" + default_role = "role1" + default_namespace = "some.namespace" + + mins_to_unlock = 9 + days_to_expiry = 8 + + rsa_public_key = "..." + rsa_public_key_2 = "..." +} + +# all parameters set on the resource level +resource "snowflake_service_user" "u" { + name = "Snowflake Service User with all parameters" + + abort_detached_query = true + autocommit = false + binary_input_format = "UTF8" + binary_output_format = "BASE64" + client_memory_limit = 1024 + client_metadata_request_use_connection_ctx = true + client_prefetch_threads = 2 + client_result_chunk_size = 48 + client_result_column_case_insensitive = true + client_session_keep_alive = true + client_session_keep_alive_heartbeat_frequency = 2400 + client_timestamp_type_mapping = "TIMESTAMP_NTZ" + date_input_format = "YYYY-MM-DD" + date_output_format = "YY-MM-DD" + enable_unload_physical_type_optimization = false + enable_unredacted_query_syntax_error = true + error_on_nondeterministic_merge = false + error_on_nondeterministic_update = true + geography_output_format = "WKB" + geometry_output_format = "WKB" + jdbc_treat_decimal_as_int = false + jdbc_treat_timestamp_ntz_as_utc = true + jdbc_use_session_timezone = false + json_indent = 4 + lock_timeout = 21222 + log_level = "ERROR" + multi_statement_count = 0 + network_policy = "BVYDGRAT_0D5E3DD1_F644_03DE_318A_1179886518A7" + noorder_sequence_as_default = false + odbc_treat_decimal_as_int = true + prevent_unload_to_internal_stages = true + query_tag = "some_tag" + quoted_identifiers_ignore_case = true + rows_per_resultset = 2 + search_path = "$public, $current" + simulated_data_sharing_consumer = "some_consumer" + statement_queued_timeout_in_seconds = 10 + statement_timeout_in_seconds = 10 + strict_json_output = true + s3_stage_vpce_dns_name = "vpce-id.s3.region.vpce.amazonaws.com" + time_input_format = "HH24:MI" + time_output_format = "HH24:MI" + timestamp_day_is_always_24h = true + timestamp_input_format = "YYYY-MM-DD" + timestamp_ltz_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_ntz_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_type_mapping = "TIMESTAMP_LTZ" + timestamp_tz_output_format = "YYYY-MM-DD HH24:MI:SS" + timezone = "Europe/Warsaw" + trace_level = "ON_EVENT" + transaction_abort_on_error = true + transaction_default_isolation_level = "READ COMMITTED" + two_digit_century_start = 1980 + unsupported_ddl_action = "FAIL" + use_cached_result = false + week_of_year_policy = 1 + week_start = 1 +} +``` +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + + + +## Schema + +### Required + +- `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 + +- `abort_detached_query` (Boolean) Specifies the action that Snowflake performs for in-progress queries if connectivity is lost due to abrupt termination of a session (e.g. network outage, browser termination, service interruption). For more information, check [ABORT_DETACHED_QUERY docs](https://docs.snowflake.com/en/sql-reference/parameters#abort-detached-query). +- `autocommit` (Boolean) Specifies whether autocommit is enabled for the session. Autocommit determines whether a DML statement, when executed without an active transaction, is automatically committed after the statement successfully completes. For more information, see [Transactions](https://docs.snowflake.com/en/sql-reference/transactions). For more information, check [AUTOCOMMIT docs](https://docs.snowflake.com/en/sql-reference/parameters#autocommit). +- `binary_input_format` (String) The format of VARCHAR values passed as input to VARCHAR-to-BINARY conversion functions. For more information, see [Binary input and output](https://docs.snowflake.com/en/sql-reference/binary-input-output). For more information, check [BINARY_INPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#binary-input-format). +- `binary_output_format` (String) The format for VARCHAR values returned as output by BINARY-to-VARCHAR conversion functions. For more information, see [Binary input and output](https://docs.snowflake.com/en/sql-reference/binary-input-output). For more information, check [BINARY_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#binary-output-format). +- `client_memory_limit` (Number) Parameter that specifies the maximum amount of memory the JDBC driver or ODBC driver should use for the result set from queries (in MB). For more information, check [CLIENT_MEMORY_LIMIT docs](https://docs.snowflake.com/en/sql-reference/parameters#client-memory-limit). +- `client_metadata_request_use_connection_ctx` (Boolean) For specific ODBC functions and JDBC methods, this parameter can change the default search scope from all databases/schemas to the current database/schema. The narrower search typically returns fewer rows and executes more quickly. For more information, check [CLIENT_METADATA_REQUEST_USE_CONNECTION_CTX docs](https://docs.snowflake.com/en/sql-reference/parameters#client-metadata-request-use-connection-ctx). +- `client_prefetch_threads` (Number) Parameter that specifies the number of threads used by the client to pre-fetch large result sets. The driver will attempt to honor the parameter value, but defines the minimum and maximum values (depending on your system’s resources) to improve performance. For more information, check [CLIENT_PREFETCH_THREADS docs](https://docs.snowflake.com/en/sql-reference/parameters#client-prefetch-threads). +- `client_result_chunk_size` (Number) Parameter that specifies the maximum size of each set (or chunk) of query results to download (in MB). The JDBC driver downloads query results in chunks. For more information, check [CLIENT_RESULT_CHUNK_SIZE docs](https://docs.snowflake.com/en/sql-reference/parameters#client-result-chunk-size). +- `client_result_column_case_insensitive` (Boolean) Parameter that indicates whether to match column name case-insensitively in ResultSet.get* methods in JDBC. For more information, check [CLIENT_RESULT_COLUMN_CASE_INSENSITIVE docs](https://docs.snowflake.com/en/sql-reference/parameters#client-result-column-case-insensitive). +- `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) 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`. 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_option` (String) Specifies the secondary roles that are active for the user’s session upon login. Valid values are (case-insensitive): `DEFAULT` | `NONE` | `ALL`. 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. +- `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). +- `error_on_nondeterministic_merge` (Boolean) Specifies whether to return an error when the [MERGE](https://docs.snowflake.com/en/sql-reference/sql/merge) command is used to update or delete a target row that joins multiple source rows and the system cannot determine the action to perform on the target row. For more information, check [ERROR_ON_NONDETERMINISTIC_MERGE docs](https://docs.snowflake.com/en/sql-reference/parameters#error-on-nondeterministic-merge). +- `error_on_nondeterministic_update` (Boolean) Specifies whether to return an error when the [UPDATE](https://docs.snowflake.com/en/sql-reference/sql/update) command is used to update a target row that joins multiple source rows and the system cannot determine the action to perform on the target row. For more information, check [ERROR_ON_NONDETERMINISTIC_UPDATE docs](https://docs.snowflake.com/en/sql-reference/parameters#error-on-nondeterministic-update). +- `geography_output_format` (String) Display format for [GEOGRAPHY values](https://docs.snowflake.com/en/sql-reference/data-types-geospatial.html#label-data-types-geography). For more information, check [GEOGRAPHY_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#geography-output-format). +- `geometry_output_format` (String) Display format for [GEOMETRY values](https://docs.snowflake.com/en/sql-reference/data-types-geospatial.html#label-data-types-geometry). For more information, check [GEOMETRY_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#geometry-output-format). +- `jdbc_treat_decimal_as_int` (Boolean) Specifies how JDBC processes columns that have a scale of zero (0). For more information, check [JDBC_TREAT_DECIMAL_AS_INT docs](https://docs.snowflake.com/en/sql-reference/parameters#jdbc-treat-decimal-as-int). +- `jdbc_treat_timestamp_ntz_as_utc` (Boolean) Specifies how JDBC processes TIMESTAMP_NTZ values. For more information, check [JDBC_TREAT_TIMESTAMP_NTZ_AS_UTC docs](https://docs.snowflake.com/en/sql-reference/parameters#jdbc-treat-timestamp-ntz-as-utc). +- `jdbc_use_session_timezone` (Boolean) Specifies whether the JDBC Driver uses the time zone of the JVM or the time zone of the session (specified by the [TIMEZONE](https://docs.snowflake.com/en/sql-reference/parameters#label-timezone) parameter) for the getDate(), getTime(), and getTimestamp() methods of the ResultSet class. For more information, check [JDBC_USE_SESSION_TIMEZONE docs](https://docs.snowflake.com/en/sql-reference/parameters#jdbc-use-session-timezone). +- `json_indent` (Number) Specifies the number of blank spaces to indent each new element in JSON output in the session. Also specifies whether to insert newline characters after each element. For more information, check [JSON_INDENT docs](https://docs.snowflake.com/en/sql-reference/parameters#json-indent). +- `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 names are always case-insensitive. +- `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). +- `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). +- `prevent_unload_to_internal_stages` (Boolean) Specifies whether to prevent data unload operations to internal (Snowflake) stages using [COPY INTO ](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). +- `rows_per_resultset` (Number) Specifies the maximum number of rows returned in a result set. A value of 0 specifies no maximum. For more information, check [ROWS_PER_RESULTSET docs](https://docs.snowflake.com/en/sql-reference/parameters#rows-per-resultset). +- `rsa_public_key` (String) Specifies the user’s RSA public key; used for key-pair authentication. Must be on 1 line without header and trailer. +- `rsa_public_key_2` (String) Specifies the user’s second RSA public key; used to rotate the public and private keys for key-pair authentication based on an expiration schedule set by your organization. Must be on 1 line without header and trailer. +- `s3_stage_vpce_dns_name` (String) Specifies the DNS name of an Amazon S3 interface endpoint. Requests sent to the internal stage of an account via [AWS PrivateLink for Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/privatelink-interface-endpoints.html) use this endpoint to connect. For more information, see [Accessing Internal stages with dedicated interface endpoints](https://docs.snowflake.com/en/user-guide/private-internal-stages-aws.html#label-aws-privatelink-internal-stage-network-isolation). For more information, check [S3_STAGE_VPCE_DNS_NAME docs](https://docs.snowflake.com/en/sql-reference/parameters#s3-stage-vpce-dns-name). +- `search_path` (String) Specifies the path to search to resolve unqualified object names in queries. For more information, see [Name resolution in queries](https://docs.snowflake.com/en/sql-reference/name-resolution.html#label-object-name-resolution-search-path). Comma-separated list of identifiers. An identifier can be a fully or partially qualified schema name. For more information, check [SEARCH_PATH docs](https://docs.snowflake.com/en/sql-reference/parameters#search-path). +- `simulated_data_sharing_consumer` (String) Specifies the name of a consumer account to simulate for testing/validating shared data, particularly shared secure views. When this parameter is set in a session, shared views return rows as if executed in the specified consumer account rather than the provider account. For more information, see [Introduction to Secure Data Sharing](https://docs.snowflake.com/en/user-guide/data-sharing-intro) and [Working with shares](https://docs.snowflake.com/en/user-guide/data-sharing-provider). For more information, check [SIMULATED_DATA_SHARING_CONSUMER docs](https://docs.snowflake.com/en/sql-reference/parameters#simulated-data-sharing-consumer). +- `statement_queued_timeout_in_seconds` (Number) Amount of time, in seconds, a SQL statement (query, DDL, DML, etc.) remains queued for a warehouse before it is canceled by the system. This parameter can be used in conjunction with the [MAX_CONCURRENCY_LEVEL](https://docs.snowflake.com/en/sql-reference/parameters#label-max-concurrency-level) parameter to ensure a warehouse is never backlogged. For more information, check [STATEMENT_QUEUED_TIMEOUT_IN_SECONDS docs](https://docs.snowflake.com/en/sql-reference/parameters#statement-queued-timeout-in-seconds). +- `statement_timeout_in_seconds` (Number) Amount of time, in seconds, after which a running SQL statement (query, DDL, DML, etc.) is canceled by the system. For more information, check [STATEMENT_TIMEOUT_IN_SECONDS docs](https://docs.snowflake.com/en/sql-reference/parameters#statement-timeout-in-seconds). +- `strict_json_output` (Boolean) This parameter specifies whether JSON output in a session is compatible with the general standard (as described by [http://json.org](http://json.org)). By design, Snowflake allows JSON input that contains non-standard values; however, these non-standard values might result in Snowflake outputting JSON that is incompatible with other platforms and languages. This parameter, when enabled, ensures that Snowflake outputs valid/compatible JSON. For more information, check [STRICT_JSON_OUTPUT docs](https://docs.snowflake.com/en/sql-reference/parameters#strict-json-output). +- `time_input_format` (String) Specifies the input format for the TIME data type. For more information, see [Date and time input and output formats](https://docs.snowflake.com/en/sql-reference/date-time-input-output). Any valid, supported time format or AUTO (AUTO specifies that Snowflake attempts to automatically detect the format of times stored in the system during the session). For more information, check [TIME_INPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#time-input-format). +- `time_output_format` (String) Specifies the display format for the TIME 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 [TIME_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#time-output-format). +- `timestamp_day_is_always_24h` (Boolean) Specifies whether the [DATEADD](https://docs.snowflake.com/en/sql-reference/functions/dateadd) function (and its aliases) always consider a day to be exactly 24 hours for expressions that span multiple days. For more information, check [TIMESTAMP_DAY_IS_ALWAYS_24H docs](https://docs.snowflake.com/en/sql-reference/parameters#timestamp-day-is-always-24h). +- `timestamp_input_format` (String) Specifies the input format for the TIMESTAMP data type alias. For more information, see [Date and time input and output formats](https://docs.snowflake.com/en/sql-reference/date-time-input-output). Any valid, supported timestamp format or AUTO (AUTO specifies that Snowflake attempts to automatically detect the format of timestamps stored in the system during the session). For more information, check [TIMESTAMP_INPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#timestamp-input-format). +- `timestamp_ltz_output_format` (String) Specifies the display format for the TIMESTAMP_LTZ data type. If no format is specified, defaults to [TIMESTAMP_OUTPUT_FORMAT](https://docs.snowflake.com/en/sql-reference/parameters#label-timestamp-output-format). 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 [TIMESTAMP_LTZ_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#timestamp-ltz-output-format). +- `timestamp_ntz_output_format` (String) Specifies the display format for the TIMESTAMP_NTZ data type. For more information, check [TIMESTAMP_NTZ_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#timestamp-ntz-output-format). +- `timestamp_output_format` (String) Specifies the display format for the TIMESTAMP data type alias. 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 [TIMESTAMP_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#timestamp-output-format). +- `timestamp_type_mapping` (String) Specifies the TIMESTAMP_* variation that the TIMESTAMP data type alias maps to. For more information, check [TIMESTAMP_TYPE_MAPPING docs](https://docs.snowflake.com/en/sql-reference/parameters#timestamp-type-mapping). +- `timestamp_tz_output_format` (String) Specifies the display format for the TIMESTAMP_TZ data type. If no format is specified, defaults to [TIMESTAMP_OUTPUT_FORMAT](https://docs.snowflake.com/en/sql-reference/parameters#label-timestamp-output-format). 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 [TIMESTAMP_TZ_OUTPUT_FORMAT docs](https://docs.snowflake.com/en/sql-reference/parameters#timestamp-tz-output-format). +- `timezone` (String) Specifies the time zone for the session. You can specify a [time zone name](https://data.iana.org/time-zones/tzdb-2021a/zone1970.tab) or a [link name](https://data.iana.org/time-zones/tzdb-2021a/backward) from release 2021a of the [IANA Time Zone Database](https://www.iana.org/time-zones) (e.g. America/Los_Angeles, Europe/London, UTC, Etc/GMT, etc.). For more information, check [TIMEZONE docs](https://docs.snowflake.com/en/sql-reference/parameters#timezone). +- `trace_level` (String) Controls how trace events are ingested into the event table. For more information about trace levels, see [Setting trace level](https://docs.snowflake.com/en/developer-guide/logging-tracing/tracing-trace-level). For more information, check [TRACE_LEVEL docs](https://docs.snowflake.com/en/sql-reference/parameters#trace-level). +- `transaction_abort_on_error` (Boolean) Specifies the action to perform when a statement issued within a non-autocommit transaction returns with an error. For more information, check [TRANSACTION_ABORT_ON_ERROR docs](https://docs.snowflake.com/en/sql-reference/parameters#transaction-abort-on-error). +- `transaction_default_isolation_level` (String) Specifies the isolation level for transactions in the user session. For more information, check [TRANSACTION_DEFAULT_ISOLATION_LEVEL docs](https://docs.snowflake.com/en/sql-reference/parameters#transaction-default-isolation-level). +- `two_digit_century_start` (Number) Specifies the “century start” year for 2-digit years (i.e. the earliest year such dates can represent). This parameter prevents ambiguous dates when importing or converting data with the `YY` date format component (i.e. years represented as 2 digits). For more information, check [TWO_DIGIT_CENTURY_START docs](https://docs.snowflake.com/en/sql-reference/parameters#two-digit-century-start). +- `unsupported_ddl_action` (String) Determines if an unsupported (i.e. non-default) value specified for a constraint property returns an error. For more information, check [UNSUPPORTED_DDL_ACTION docs](https://docs.snowflake.com/en/sql-reference/parameters#unsupported-ddl-action). +- `use_cached_result` (Boolean) Specifies whether to reuse persisted query results, if available, when a matching query is submitted. For more information, check [USE_CACHED_RESULT docs](https://docs.snowflake.com/en/sql-reference/parameters#use-cached-result). +- `week_of_year_policy` (Number) Specifies how the weeks in a given year are computed. `0`: The semantics used are equivalent to the ISO semantics, in which a week belongs to a given year if at least 4 days of that week are in that year. `1`: January 1 is included in the first week of the year and December 31 is included in the last week of the year. For more information, check [WEEK_OF_YEAR_POLICY docs](https://docs.snowflake.com/en/sql-reference/parameters#week-of-year-policy). +- `week_start` (Number) Specifies the first day of the week (used by week-related date functions). `0`: Legacy Snowflake behavior is used (i.e. ISO-like semantics). `1` (Monday) to `7` (Sunday): All the week-related functions use weeks that start on the specified day of the week. For more information, check [WEEK_START docs](https://docs.snowflake.com/en/sql-reference/parameters#week-start). + +### 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). +- `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. + + +### Nested Schema for `parameters` + +Read-Only: + +- `abort_detached_query` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--abort_detached_query)) +- `autocommit` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--autocommit)) +- `binary_input_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--binary_input_format)) +- `binary_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--binary_output_format)) +- `client_memory_limit` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_memory_limit)) +- `client_metadata_request_use_connection_ctx` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_metadata_request_use_connection_ctx)) +- `client_prefetch_threads` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_prefetch_threads)) +- `client_result_chunk_size` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_result_chunk_size)) +- `client_result_column_case_insensitive` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_result_column_case_insensitive)) +- `client_session_keep_alive` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_session_keep_alive)) +- `client_session_keep_alive_heartbeat_frequency` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_session_keep_alive_heartbeat_frequency)) +- `client_timestamp_type_mapping` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--client_timestamp_type_mapping)) +- `date_input_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--date_input_format)) +- `date_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--date_output_format)) +- `enable_unload_physical_type_optimization` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--enable_unload_physical_type_optimization)) +- `enable_unredacted_query_syntax_error` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--enable_unredacted_query_syntax_error)) +- `error_on_nondeterministic_merge` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--error_on_nondeterministic_merge)) +- `error_on_nondeterministic_update` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--error_on_nondeterministic_update)) +- `geography_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--geography_output_format)) +- `geometry_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--geometry_output_format)) +- `jdbc_treat_decimal_as_int` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--jdbc_treat_decimal_as_int)) +- `jdbc_treat_timestamp_ntz_as_utc` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--jdbc_treat_timestamp_ntz_as_utc)) +- `jdbc_use_session_timezone` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--jdbc_use_session_timezone)) +- `json_indent` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--json_indent)) +- `lock_timeout` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--lock_timeout)) +- `log_level` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--log_level)) +- `multi_statement_count` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--multi_statement_count)) +- `network_policy` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--network_policy)) +- `noorder_sequence_as_default` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--noorder_sequence_as_default)) +- `odbc_treat_decimal_as_int` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--odbc_treat_decimal_as_int)) +- `prevent_unload_to_internal_stages` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--prevent_unload_to_internal_stages)) +- `query_tag` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--query_tag)) +- `quoted_identifiers_ignore_case` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--quoted_identifiers_ignore_case)) +- `rows_per_resultset` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--rows_per_resultset)) +- `s3_stage_vpce_dns_name` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--s3_stage_vpce_dns_name)) +- `search_path` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--search_path)) +- `simulated_data_sharing_consumer` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--simulated_data_sharing_consumer)) +- `statement_queued_timeout_in_seconds` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--statement_queued_timeout_in_seconds)) +- `statement_timeout_in_seconds` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--statement_timeout_in_seconds)) +- `strict_json_output` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--strict_json_output)) +- `time_input_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--time_input_format)) +- `time_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--time_output_format)) +- `timestamp_day_is_always_24h` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timestamp_day_is_always_24h)) +- `timestamp_input_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timestamp_input_format)) +- `timestamp_ltz_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timestamp_ltz_output_format)) +- `timestamp_ntz_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timestamp_ntz_output_format)) +- `timestamp_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timestamp_output_format)) +- `timestamp_type_mapping` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timestamp_type_mapping)) +- `timestamp_tz_output_format` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timestamp_tz_output_format)) +- `timezone` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--timezone)) +- `trace_level` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--trace_level)) +- `transaction_abort_on_error` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--transaction_abort_on_error)) +- `transaction_default_isolation_level` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--transaction_default_isolation_level)) +- `two_digit_century_start` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--two_digit_century_start)) +- `unsupported_ddl_action` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--unsupported_ddl_action)) +- `use_cached_result` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--use_cached_result)) +- `week_of_year_policy` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--week_of_year_policy)) +- `week_start` (List of Object) (see [below for nested schema](#nestedobjatt--parameters--week_start)) + + +### Nested Schema for `parameters.abort_detached_query` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.autocommit` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.binary_input_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.binary_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_memory_limit` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_metadata_request_use_connection_ctx` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_prefetch_threads` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_result_chunk_size` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_result_column_case_insensitive` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_session_keep_alive` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_session_keep_alive_heartbeat_frequency` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.client_timestamp_type_mapping` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.date_input_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.date_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.enable_unload_physical_type_optimization` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.enable_unredacted_query_syntax_error` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.error_on_nondeterministic_merge` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.error_on_nondeterministic_update` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.geography_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.geometry_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.jdbc_treat_decimal_as_int` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.jdbc_treat_timestamp_ntz_as_utc` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.jdbc_use_session_timezone` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.json_indent` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.lock_timeout` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.log_level` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.multi_statement_count` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.network_policy` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.noorder_sequence_as_default` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.odbc_treat_decimal_as_int` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.prevent_unload_to_internal_stages` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.query_tag` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.quoted_identifiers_ignore_case` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.rows_per_resultset` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.s3_stage_vpce_dns_name` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.search_path` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.simulated_data_sharing_consumer` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.statement_queued_timeout_in_seconds` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.statement_timeout_in_seconds` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.strict_json_output` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.time_input_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.time_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timestamp_day_is_always_24h` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timestamp_input_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timestamp_ltz_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timestamp_ntz_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timestamp_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timestamp_type_mapping` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timestamp_tz_output_format` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.timezone` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.trace_level` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.transaction_abort_on_error` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.transaction_default_isolation_level` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.two_digit_century_start` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.unsupported_ddl_action` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.use_cached_result` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.week_of_year_policy` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `parameters.week_start` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + + +### Nested Schema for `show_output` + +Read-Only: + +- `comment` (String) +- `created_on` (String) +- `days_to_expiry` (String) +- `default_namespace` (String) +- `default_role` (String) +- `default_secondary_roles` (String) +- `default_warehouse` (String) +- `disabled` (Boolean) +- `display_name` (String) +- `email` (String) +- `expires_at_time` (String) +- `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) +- `last_success_login` (String) +- `locked_until_time` (String) +- `login_name` (String) +- `mins_to_bypass_mfa` (String) +- `mins_to_unlock` (String) +- `must_change_password` (Boolean) +- `name` (String) +- `owner` (String) +- `snowflake_lock` (Boolean) +- `type` (String) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import snowflake_service_user.example '""' +``` diff --git a/docs/resources/user.md b/docs/resources/user.md index c265d27851..48e3f1e7f8 100644 --- a/docs/resources/user.md +++ b/docs/resources/user.md @@ -2,7 +2,7 @@ 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. + Resource used to manage user objects. For more information, check user documentation https://docs.snowflake.com/en/sql-reference/commands-user-role#user-management. --- !> **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. @@ -11,36 +11,113 @@ description: |- -> **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** Other two user types are handled in separate resources: `snowflake_service_user` for user type `service` and `snowflake_legacy_service_user` for user type `legacy_service`. -> **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). +Resource used to manage user objects. For more information, check [user documentation](https://docs.snowflake.com/en/sql-reference/commands-user-role#user-management). ## Example Usage ```terraform +# minimal +resource "snowflake_user" "minimal" { + name = "Snowflake User - minimal" +} + +# with all attributes set resource "snowflake_user" "user" { name = "Snowflake User" login_name = "snowflake_user" - comment = "A user of snowflake." - password = "secret" - disabled = false - display_name = "Snowflake User" - email = "user@snowflake.example" first_name = "Snowflake" + middle_name = "Middle" last_name = "User" + comment = "User of snowflake." + password = "secret" + disabled = "false" + display_name = "Snowflake User display name" + email = "user@snowflake.example" + + default_warehouse = "warehouse" + default_secondary_roles_option = "ALL" + default_role = "role1" + default_namespace = "some.namespace" - default_warehouse = "warehouse" - default_secondary_roles = "ALL" - default_role = "role1" + mins_to_unlock = 9 + days_to_expiry = 8 + mins_to_bypass_mfa = 10 rsa_public_key = "..." rsa_public_key_2 = "..." - must_change_password = false + must_change_password = "true" + disable_mfa = "false" +} + +# all parameters set on the resource level +resource "snowflake_user" "u" { + name = "Snowflake User with all parameters" + + abort_detached_query = true + autocommit = false + binary_input_format = "UTF8" + binary_output_format = "BASE64" + client_memory_limit = 1024 + client_metadata_request_use_connection_ctx = true + client_prefetch_threads = 2 + client_result_chunk_size = 48 + client_result_column_case_insensitive = true + client_session_keep_alive = true + client_session_keep_alive_heartbeat_frequency = 2400 + client_timestamp_type_mapping = "TIMESTAMP_NTZ" + date_input_format = "YYYY-MM-DD" + date_output_format = "YY-MM-DD" + enable_unload_physical_type_optimization = false + enable_unredacted_query_syntax_error = true + error_on_nondeterministic_merge = false + error_on_nondeterministic_update = true + geography_output_format = "WKB" + geometry_output_format = "WKB" + jdbc_treat_decimal_as_int = false + jdbc_treat_timestamp_ntz_as_utc = true + jdbc_use_session_timezone = false + json_indent = 4 + lock_timeout = 21222 + log_level = "ERROR" + multi_statement_count = 0 + network_policy = "BVYDGRAT_0D5E3DD1_F644_03DE_318A_1179886518A7" + noorder_sequence_as_default = false + odbc_treat_decimal_as_int = true + prevent_unload_to_internal_stages = true + query_tag = "some_tag" + quoted_identifiers_ignore_case = true + rows_per_resultset = 2 + search_path = "$public, $current" + simulated_data_sharing_consumer = "some_consumer" + statement_queued_timeout_in_seconds = 10 + statement_timeout_in_seconds = 10 + strict_json_output = true + s3_stage_vpce_dns_name = "vpce-id.s3.region.vpce.amazonaws.com" + time_input_format = "HH24:MI" + time_output_format = "HH24:MI" + timestamp_day_is_always_24h = true + timestamp_input_format = "YYYY-MM-DD" + timestamp_ltz_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_ntz_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_type_mapping = "TIMESTAMP_LTZ" + timestamp_tz_output_format = "YYYY-MM-DD HH24:MI:SS" + timezone = "Europe/Warsaw" + trace_level = "ON_EVENT" + transaction_abort_on_error = true + transaction_default_isolation_level = "READ COMMITTED" + two_digit_century_start = 1980 + unsupported_ddl_action = "FAIL" + use_cached_result = false + week_of_year_policy = 1 + week_start = 1 } ``` -> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). @@ -942,5 +1019,5 @@ Read-Only: Import is supported using the following syntax: ```shell -terraform import snowflake_user.example userName +terraform import snowflake_user.example '""' ``` diff --git a/examples/resources/snowflake_legacy_service_user/import.sh b/examples/resources/snowflake_legacy_service_user/import.sh new file mode 100644 index 0000000000..cf731f1586 --- /dev/null +++ b/examples/resources/snowflake_legacy_service_user/import.sh @@ -0,0 +1 @@ +terraform import snowflake_legacy_service_user.example '""' diff --git a/examples/resources/snowflake_legacy_service_user/resource.tf b/examples/resources/snowflake_legacy_service_user/resource.tf new file mode 100644 index 0000000000..f51d3752bc --- /dev/null +++ b/examples/resources/snowflake_legacy_service_user/resource.tf @@ -0,0 +1,92 @@ +# minimal +resource "snowflake_legacy_service_user" "minimal" { + name = "Snowflake Legacy Service User - minimal" +} + +# with all attributes set +resource "snowflake_legacy_service_user" "user" { + name = "Snowflake Legacy Service User" + login_name = "legacy_service_user" + comment = "A legacy service user of snowflake." + password = "secret" + disabled = "false" + display_name = "Snowflake Legacy Service User display name" + email = "legacy.service.user@snowflake.example" + + default_warehouse = "warehouse" + default_secondary_roles_option = "ALL" + default_role = "role1" + default_namespace = "some.namespace" + + mins_to_unlock = 9 + days_to_expiry = 8 + + rsa_public_key = "..." + rsa_public_key_2 = "..." + + must_change_password = "true" +} + +# all parameters set on the resource level +resource "snowflake_legacy_service_user" "u" { + name = "Snowflake Legacy Service User with all parameters" + + abort_detached_query = true + autocommit = false + binary_input_format = "UTF8" + binary_output_format = "BASE64" + client_memory_limit = 1024 + client_metadata_request_use_connection_ctx = true + client_prefetch_threads = 2 + client_result_chunk_size = 48 + client_result_column_case_insensitive = true + client_session_keep_alive = true + client_session_keep_alive_heartbeat_frequency = 2400 + client_timestamp_type_mapping = "TIMESTAMP_NTZ" + date_input_format = "YYYY-MM-DD" + date_output_format = "YY-MM-DD" + enable_unload_physical_type_optimization = false + enable_unredacted_query_syntax_error = true + error_on_nondeterministic_merge = false + error_on_nondeterministic_update = true + geography_output_format = "WKB" + geometry_output_format = "WKB" + jdbc_treat_decimal_as_int = false + jdbc_treat_timestamp_ntz_as_utc = true + jdbc_use_session_timezone = false + json_indent = 4 + lock_timeout = 21222 + log_level = "ERROR" + multi_statement_count = 0 + network_policy = "BVYDGRAT_0D5E3DD1_F644_03DE_318A_1179886518A7" + noorder_sequence_as_default = false + odbc_treat_decimal_as_int = true + prevent_unload_to_internal_stages = true + query_tag = "some_tag" + quoted_identifiers_ignore_case = true + rows_per_resultset = 2 + search_path = "$public, $current" + simulated_data_sharing_consumer = "some_consumer" + statement_queued_timeout_in_seconds = 10 + statement_timeout_in_seconds = 10 + strict_json_output = true + s3_stage_vpce_dns_name = "vpce-id.s3.region.vpce.amazonaws.com" + time_input_format = "HH24:MI" + time_output_format = "HH24:MI" + timestamp_day_is_always_24h = true + timestamp_input_format = "YYYY-MM-DD" + timestamp_ltz_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_ntz_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_type_mapping = "TIMESTAMP_LTZ" + timestamp_tz_output_format = "YYYY-MM-DD HH24:MI:SS" + timezone = "Europe/Warsaw" + trace_level = "ON_EVENT" + transaction_abort_on_error = true + transaction_default_isolation_level = "READ COMMITTED" + two_digit_century_start = 1980 + unsupported_ddl_action = "FAIL" + use_cached_result = false + week_of_year_policy = 1 + week_start = 1 +} diff --git a/examples/resources/snowflake_service_user/import.sh b/examples/resources/snowflake_service_user/import.sh new file mode 100644 index 0000000000..7ef670730b --- /dev/null +++ b/examples/resources/snowflake_service_user/import.sh @@ -0,0 +1 @@ +terraform import snowflake_service_user.example '""' diff --git a/examples/resources/snowflake_service_user/resource.tf b/examples/resources/snowflake_service_user/resource.tf new file mode 100644 index 0000000000..b764ad979b --- /dev/null +++ b/examples/resources/snowflake_service_user/resource.tf @@ -0,0 +1,89 @@ +# minimal +resource "snowflake_service_user" "minimal" { + name = "Snowflake Service User - minimal" +} + +# with all attributes set +resource "snowflake_service_user" "service_user" { + name = "Snowflake Service User" + login_name = "service_user" + comment = "A service user of snowflake." + disabled = "false" + display_name = "Snowflake Service User" + email = "service_user@snowflake.example" + + default_warehouse = "warehouse" + default_secondary_roles_option = "ALL" + default_role = "role1" + default_namespace = "some.namespace" + + mins_to_unlock = 9 + days_to_expiry = 8 + + rsa_public_key = "..." + rsa_public_key_2 = "..." +} + +# all parameters set on the resource level +resource "snowflake_service_user" "u" { + name = "Snowflake Service User with all parameters" + + abort_detached_query = true + autocommit = false + binary_input_format = "UTF8" + binary_output_format = "BASE64" + client_memory_limit = 1024 + client_metadata_request_use_connection_ctx = true + client_prefetch_threads = 2 + client_result_chunk_size = 48 + client_result_column_case_insensitive = true + client_session_keep_alive = true + client_session_keep_alive_heartbeat_frequency = 2400 + client_timestamp_type_mapping = "TIMESTAMP_NTZ" + date_input_format = "YYYY-MM-DD" + date_output_format = "YY-MM-DD" + enable_unload_physical_type_optimization = false + enable_unredacted_query_syntax_error = true + error_on_nondeterministic_merge = false + error_on_nondeterministic_update = true + geography_output_format = "WKB" + geometry_output_format = "WKB" + jdbc_treat_decimal_as_int = false + jdbc_treat_timestamp_ntz_as_utc = true + jdbc_use_session_timezone = false + json_indent = 4 + lock_timeout = 21222 + log_level = "ERROR" + multi_statement_count = 0 + network_policy = "BVYDGRAT_0D5E3DD1_F644_03DE_318A_1179886518A7" + noorder_sequence_as_default = false + odbc_treat_decimal_as_int = true + prevent_unload_to_internal_stages = true + query_tag = "some_tag" + quoted_identifiers_ignore_case = true + rows_per_resultset = 2 + search_path = "$public, $current" + simulated_data_sharing_consumer = "some_consumer" + statement_queued_timeout_in_seconds = 10 + statement_timeout_in_seconds = 10 + strict_json_output = true + s3_stage_vpce_dns_name = "vpce-id.s3.region.vpce.amazonaws.com" + time_input_format = "HH24:MI" + time_output_format = "HH24:MI" + timestamp_day_is_always_24h = true + timestamp_input_format = "YYYY-MM-DD" + timestamp_ltz_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_ntz_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_type_mapping = "TIMESTAMP_LTZ" + timestamp_tz_output_format = "YYYY-MM-DD HH24:MI:SS" + timezone = "Europe/Warsaw" + trace_level = "ON_EVENT" + transaction_abort_on_error = true + transaction_default_isolation_level = "READ COMMITTED" + two_digit_century_start = 1980 + unsupported_ddl_action = "FAIL" + use_cached_result = false + week_of_year_policy = 1 + week_start = 1 +} diff --git a/examples/resources/snowflake_user/import.sh b/examples/resources/snowflake_user/import.sh index 8565816768..c9ddd214c7 100644 --- a/examples/resources/snowflake_user/import.sh +++ b/examples/resources/snowflake_user/import.sh @@ -1 +1 @@ -terraform import snowflake_user.example userName +terraform import snowflake_user.example '""' diff --git a/examples/resources/snowflake_user/resource.tf b/examples/resources/snowflake_user/resource.tf index 3c44d99314..1892a4568f 100644 --- a/examples/resources/snowflake_user/resource.tf +++ b/examples/resources/snowflake_user/resource.tf @@ -1,20 +1,97 @@ +# minimal +resource "snowflake_user" "minimal" { + name = "Snowflake User - minimal" +} + +# with all attributes set resource "snowflake_user" "user" { name = "Snowflake User" login_name = "snowflake_user" - comment = "A user of snowflake." - password = "secret" - disabled = false - display_name = "Snowflake User" - email = "user@snowflake.example" first_name = "Snowflake" + middle_name = "Middle" last_name = "User" + comment = "User of snowflake." + password = "secret" + disabled = "false" + display_name = "Snowflake User display name" + email = "user@snowflake.example" + + default_warehouse = "warehouse" + default_secondary_roles_option = "ALL" + default_role = "role1" + default_namespace = "some.namespace" - default_warehouse = "warehouse" - default_secondary_roles = "ALL" - default_role = "role1" + mins_to_unlock = 9 + days_to_expiry = 8 + mins_to_bypass_mfa = 10 rsa_public_key = "..." rsa_public_key_2 = "..." - must_change_password = false + must_change_password = "true" + disable_mfa = "false" +} + +# all parameters set on the resource level +resource "snowflake_user" "u" { + name = "Snowflake User with all parameters" + + abort_detached_query = true + autocommit = false + binary_input_format = "UTF8" + binary_output_format = "BASE64" + client_memory_limit = 1024 + client_metadata_request_use_connection_ctx = true + client_prefetch_threads = 2 + client_result_chunk_size = 48 + client_result_column_case_insensitive = true + client_session_keep_alive = true + client_session_keep_alive_heartbeat_frequency = 2400 + client_timestamp_type_mapping = "TIMESTAMP_NTZ" + date_input_format = "YYYY-MM-DD" + date_output_format = "YY-MM-DD" + enable_unload_physical_type_optimization = false + enable_unredacted_query_syntax_error = true + error_on_nondeterministic_merge = false + error_on_nondeterministic_update = true + geography_output_format = "WKB" + geometry_output_format = "WKB" + jdbc_treat_decimal_as_int = false + jdbc_treat_timestamp_ntz_as_utc = true + jdbc_use_session_timezone = false + json_indent = 4 + lock_timeout = 21222 + log_level = "ERROR" + multi_statement_count = 0 + network_policy = "BVYDGRAT_0D5E3DD1_F644_03DE_318A_1179886518A7" + noorder_sequence_as_default = false + odbc_treat_decimal_as_int = true + prevent_unload_to_internal_stages = true + query_tag = "some_tag" + quoted_identifiers_ignore_case = true + rows_per_resultset = 2 + search_path = "$public, $current" + simulated_data_sharing_consumer = "some_consumer" + statement_queued_timeout_in_seconds = 10 + statement_timeout_in_seconds = 10 + strict_json_output = true + s3_stage_vpce_dns_name = "vpce-id.s3.region.vpce.amazonaws.com" + time_input_format = "HH24:MI" + time_output_format = "HH24:MI" + timestamp_day_is_always_24h = true + timestamp_input_format = "YYYY-MM-DD" + timestamp_ltz_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_ntz_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_output_format = "YYYY-MM-DD HH24:MI:SS" + timestamp_type_mapping = "TIMESTAMP_LTZ" + timestamp_tz_output_format = "YYYY-MM-DD HH24:MI:SS" + timezone = "Europe/Warsaw" + trace_level = "ON_EVENT" + transaction_abort_on_error = true + transaction_default_isolation_level = "READ COMMITTED" + two_digit_century_start = 1980 + unsupported_ddl_action = "FAIL" + use_cached_result = false + week_of_year_policy = 1 + week_start = 1 } diff --git a/pkg/acceptance/bettertestspoc/assert/resourceassert/gen/resource_schema_def.go b/pkg/acceptance/bettertestspoc/assert/resourceassert/gen/resource_schema_def.go index 3b71f952ec..abeb9018b8 100644 --- a/pkg/acceptance/bettertestspoc/assert/resourceassert/gen/resource_schema_def.go +++ b/pkg/acceptance/bettertestspoc/assert/resourceassert/gen/resource_schema_def.go @@ -29,6 +29,14 @@ var allResourceSchemaDefs = []ResourceSchemaDef{ name: "User", schema: resources.User().Schema, }, + { + name: "ServiceUser", + schema: resources.ServiceUser().Schema, + }, + { + name: "LegacyServiceUser", + schema: resources.LegacyServiceUser().Schema, + }, { name: "View", schema: resources.View().Schema, diff --git a/pkg/acceptance/bettertestspoc/assert/resourceassert/legacy_service_user_resource_ext.go b/pkg/acceptance/bettertestspoc/assert/resourceassert/legacy_service_user_resource_ext.go new file mode 100644 index 0000000000..bfd05ae481 --- /dev/null +++ b/pkg/acceptance/bettertestspoc/assert/resourceassert/legacy_service_user_resource_ext.go @@ -0,0 +1,22 @@ +package resourceassert + +import ( + "strconv" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" +) + +func (u *LegacyServiceUserResourceAssert) HasDisabled(expected bool) *LegacyServiceUserResourceAssert { + u.AddAssertion(assert.ValueSet("disabled", strconv.FormatBool(expected))) + return u +} + +func (u *LegacyServiceUserResourceAssert) HasMustChangePassword(expected bool) *LegacyServiceUserResourceAssert { + u.AddAssertion(assert.ValueSet("must_change_password", strconv.FormatBool(expected))) + return u +} + +func (u *LegacyServiceUserResourceAssert) HasDefaultSecondaryRolesOption(expected sdk.SecondaryRolesOption) *LegacyServiceUserResourceAssert { + return u.HasDefaultSecondaryRolesOptionString(string(expected)) +} diff --git a/pkg/acceptance/bettertestspoc/assert/resourceassert/legacy_service_user_resource_gen.go b/pkg/acceptance/bettertestspoc/assert/resourceassert/legacy_service_user_resource_gen.go new file mode 100644 index 0000000000..3cefca9af2 --- /dev/null +++ b/pkg/acceptance/bettertestspoc/assert/resourceassert/legacy_service_user_resource_gen.go @@ -0,0 +1,797 @@ +// Code generated by assertions generator; DO NOT EDIT. + +package resourceassert + +import ( + "testing" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" +) + +type LegacyServiceUserResourceAssert struct { + *assert.ResourceAssert +} + +func LegacyServiceUserResource(t *testing.T, name string) *LegacyServiceUserResourceAssert { + t.Helper() + + return &LegacyServiceUserResourceAssert{ + ResourceAssert: assert.NewResourceAssert(name, "resource"), + } +} + +func ImportedLegacyServiceUserResource(t *testing.T, id string) *LegacyServiceUserResourceAssert { + t.Helper() + + return &LegacyServiceUserResourceAssert{ + ResourceAssert: assert.NewImportedResourceAssert(id, "imported resource"), + } +} + +/////////////////////////////////// +// Attribute value string checks // +/////////////////////////////////// + +func (l *LegacyServiceUserResourceAssert) HasAbortDetachedQueryString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("abort_detached_query", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasAutocommitString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("autocommit", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasBinaryInputFormatString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("binary_input_format", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasBinaryOutputFormatString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("binary_output_format", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasClientMemoryLimitString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("client_memory_limit", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasClientMetadataRequestUseConnectionCtxString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("client_metadata_request_use_connection_ctx", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasClientPrefetchThreadsString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("client_prefetch_threads", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasClientResultChunkSizeString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("client_result_chunk_size", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasClientResultColumnCaseInsensitiveString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("client_result_column_case_insensitive", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasClientSessionKeepAliveString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("client_session_keep_alive", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasClientSessionKeepAliveHeartbeatFrequencyString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("client_session_keep_alive_heartbeat_frequency", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasClientTimestampTypeMappingString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("client_timestamp_type_mapping", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasCommentString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("comment", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasDateInputFormatString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("date_input_format", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasDateOutputFormatString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("date_output_format", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasDaysToExpiryString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("days_to_expiry", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasDefaultNamespaceString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("default_namespace", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasDefaultRoleString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("default_role", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasDefaultSecondaryRolesOptionString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("default_secondary_roles_option", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasDefaultWarehouseString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("default_warehouse", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasDisabledString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("disabled", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasDisplayNameString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("display_name", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasEmailString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("email", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasEnableUnloadPhysicalTypeOptimizationString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("enable_unload_physical_type_optimization", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasEnableUnredactedQuerySyntaxErrorString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("enable_unredacted_query_syntax_error", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasErrorOnNondeterministicMergeString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("error_on_nondeterministic_merge", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasErrorOnNondeterministicUpdateString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("error_on_nondeterministic_update", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasFullyQualifiedNameString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("fully_qualified_name", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasGeographyOutputFormatString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("geography_output_format", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasGeometryOutputFormatString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("geometry_output_format", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasJdbcTreatDecimalAsIntString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("jdbc_treat_decimal_as_int", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasJdbcTreatTimestampNtzAsUtcString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("jdbc_treat_timestamp_ntz_as_utc", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasJdbcUseSessionTimezoneString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("jdbc_use_session_timezone", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasJsonIndentString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("json_indent", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasLockTimeoutString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("lock_timeout", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasLogLevelString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("log_level", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasLoginNameString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("login_name", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasMinsToUnlockString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("mins_to_unlock", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasMultiStatementCountString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("multi_statement_count", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasMustChangePasswordString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("must_change_password", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNameString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("name", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNetworkPolicyString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("network_policy", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoorderSequenceAsDefaultString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("noorder_sequence_as_default", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasOdbcTreatDecimalAsIntString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("odbc_treat_decimal_as_int", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasPasswordString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("password", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasPreventUnloadToInternalStagesString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("prevent_unload_to_internal_stages", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasQueryTagString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("query_tag", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasQuotedIdentifiersIgnoreCaseString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("quoted_identifiers_ignore_case", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasRowsPerResultsetString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("rows_per_resultset", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasRsaPublicKeyString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("rsa_public_key", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasRsaPublicKey2String(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("rsa_public_key_2", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasS3StageVpceDnsNameString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("s3_stage_vpce_dns_name", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasSearchPathString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("search_path", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasSimulatedDataSharingConsumerString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("simulated_data_sharing_consumer", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasStatementQueuedTimeoutInSecondsString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("statement_queued_timeout_in_seconds", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasStatementTimeoutInSecondsString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("statement_timeout_in_seconds", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasStrictJsonOutputString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("strict_json_output", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasTimeInputFormatString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("time_input_format", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasTimeOutputFormatString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("time_output_format", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasTimestampDayIsAlways24hString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("timestamp_day_is_always_24h", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasTimestampInputFormatString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("timestamp_input_format", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasTimestampLtzOutputFormatString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("timestamp_ltz_output_format", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasTimestampNtzOutputFormatString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("timestamp_ntz_output_format", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasTimestampOutputFormatString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("timestamp_output_format", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasTimestampTypeMappingString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("timestamp_type_mapping", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasTimestampTzOutputFormatString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("timestamp_tz_output_format", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasTimezoneString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("timezone", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasTraceLevelString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("trace_level", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasTransactionAbortOnErrorString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("transaction_abort_on_error", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasTransactionDefaultIsolationLevelString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("transaction_default_isolation_level", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasTwoDigitCenturyStartString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("two_digit_century_start", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasUnsupportedDdlActionString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("unsupported_ddl_action", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasUseCachedResultString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("use_cached_result", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasUserTypeString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("user_type", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasWeekOfYearPolicyString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("week_of_year_policy", expected)) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasWeekStartString(expected string) *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueSet("week_start", expected)) + return l +} + +//////////////////////////// +// Attribute empty checks // +//////////////////////////// + +func (l *LegacyServiceUserResourceAssert) HasNoAbortDetachedQuery() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("abort_detached_query")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoAutocommit() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("autocommit")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoBinaryInputFormat() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("binary_input_format")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoBinaryOutputFormat() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("binary_output_format")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoClientMemoryLimit() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("client_memory_limit")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoClientMetadataRequestUseConnectionCtx() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("client_metadata_request_use_connection_ctx")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoClientPrefetchThreads() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("client_prefetch_threads")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoClientResultChunkSize() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("client_result_chunk_size")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoClientResultColumnCaseInsensitive() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("client_result_column_case_insensitive")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoClientSessionKeepAlive() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("client_session_keep_alive")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoClientSessionKeepAliveHeartbeatFrequency() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("client_session_keep_alive_heartbeat_frequency")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoClientTimestampTypeMapping() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("client_timestamp_type_mapping")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoComment() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("comment")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoDateInputFormat() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("date_input_format")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoDateOutputFormat() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("date_output_format")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoDaysToExpiry() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("days_to_expiry")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoDefaultNamespace() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("default_namespace")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoDefaultRole() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("default_role")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoDefaultSecondaryRolesOption() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("default_secondary_roles_option")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoDefaultWarehouse() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("default_warehouse")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoDisabled() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("disabled")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoDisplayName() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("display_name")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoEmail() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("email")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoEnableUnloadPhysicalTypeOptimization() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("enable_unload_physical_type_optimization")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoEnableUnredactedQuerySyntaxError() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("enable_unredacted_query_syntax_error")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoErrorOnNondeterministicMerge() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("error_on_nondeterministic_merge")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoErrorOnNondeterministicUpdate() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("error_on_nondeterministic_update")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoFullyQualifiedName() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("fully_qualified_name")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoGeographyOutputFormat() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("geography_output_format")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoGeometryOutputFormat() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("geometry_output_format")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoJdbcTreatDecimalAsInt() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("jdbc_treat_decimal_as_int")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoJdbcTreatTimestampNtzAsUtc() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("jdbc_treat_timestamp_ntz_as_utc")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoJdbcUseSessionTimezone() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("jdbc_use_session_timezone")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoJsonIndent() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("json_indent")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoLockTimeout() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("lock_timeout")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoLogLevel() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("log_level")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoLoginName() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("login_name")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoMinsToUnlock() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("mins_to_unlock")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoMultiStatementCount() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("multi_statement_count")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoMustChangePassword() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("must_change_password")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoName() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("name")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoNetworkPolicy() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("network_policy")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoNoorderSequenceAsDefault() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("noorder_sequence_as_default")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoOdbcTreatDecimalAsInt() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("odbc_treat_decimal_as_int")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoPassword() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("password")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoPreventUnloadToInternalStages() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("prevent_unload_to_internal_stages")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoQueryTag() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("query_tag")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoQuotedIdentifiersIgnoreCase() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("quoted_identifiers_ignore_case")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoRowsPerResultset() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("rows_per_resultset")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoRsaPublicKey() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("rsa_public_key")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoRsaPublicKey2() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("rsa_public_key_2")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoS3StageVpceDnsName() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("s3_stage_vpce_dns_name")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoSearchPath() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("search_path")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoSimulatedDataSharingConsumer() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("simulated_data_sharing_consumer")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoStatementQueuedTimeoutInSeconds() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("statement_queued_timeout_in_seconds")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoStatementTimeoutInSeconds() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("statement_timeout_in_seconds")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoStrictJsonOutput() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("strict_json_output")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoTimeInputFormat() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("time_input_format")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoTimeOutputFormat() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("time_output_format")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoTimestampDayIsAlways24h() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("timestamp_day_is_always_24h")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoTimestampInputFormat() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("timestamp_input_format")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoTimestampLtzOutputFormat() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("timestamp_ltz_output_format")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoTimestampNtzOutputFormat() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("timestamp_ntz_output_format")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoTimestampOutputFormat() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("timestamp_output_format")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoTimestampTypeMapping() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("timestamp_type_mapping")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoTimestampTzOutputFormat() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("timestamp_tz_output_format")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoTimezone() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("timezone")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoTraceLevel() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("trace_level")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoTransactionAbortOnError() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("transaction_abort_on_error")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoTransactionDefaultIsolationLevel() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("transaction_default_isolation_level")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoTwoDigitCenturyStart() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("two_digit_century_start")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoUnsupportedDdlAction() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("unsupported_ddl_action")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoUseCachedResult() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("use_cached_result")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoUserType() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("user_type")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoWeekOfYearPolicy() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("week_of_year_policy")) + return l +} + +func (l *LegacyServiceUserResourceAssert) HasNoWeekStart() *LegacyServiceUserResourceAssert { + l.AddAssertion(assert.ValueNotSet("week_start")) + return l +} diff --git a/pkg/acceptance/bettertestspoc/assert/resourceassert/service_user_resource_ext.go b/pkg/acceptance/bettertestspoc/assert/resourceassert/service_user_resource_ext.go new file mode 100644 index 0000000000..9a2720bbbd --- /dev/null +++ b/pkg/acceptance/bettertestspoc/assert/resourceassert/service_user_resource_ext.go @@ -0,0 +1,17 @@ +package resourceassert + +import ( + "strconv" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" +) + +func (u *ServiceUserResourceAssert) HasDisabled(expected bool) *ServiceUserResourceAssert { + u.AddAssertion(assert.ValueSet("disabled", strconv.FormatBool(expected))) + return u +} + +func (u *ServiceUserResourceAssert) HasDefaultSecondaryRolesOption(expected sdk.SecondaryRolesOption) *ServiceUserResourceAssert { + return u.HasDefaultSecondaryRolesOptionString(string(expected)) +} diff --git a/pkg/acceptance/bettertestspoc/assert/resourceassert/service_user_resource_gen.go b/pkg/acceptance/bettertestspoc/assert/resourceassert/service_user_resource_gen.go new file mode 100644 index 0000000000..3fa43f7363 --- /dev/null +++ b/pkg/acceptance/bettertestspoc/assert/resourceassert/service_user_resource_gen.go @@ -0,0 +1,777 @@ +// Code generated by assertions generator; DO NOT EDIT. + +package resourceassert + +import ( + "testing" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" +) + +type ServiceUserResourceAssert struct { + *assert.ResourceAssert +} + +func ServiceUserResource(t *testing.T, name string) *ServiceUserResourceAssert { + t.Helper() + + return &ServiceUserResourceAssert{ + ResourceAssert: assert.NewResourceAssert(name, "resource"), + } +} + +func ImportedServiceUserResource(t *testing.T, id string) *ServiceUserResourceAssert { + t.Helper() + + return &ServiceUserResourceAssert{ + ResourceAssert: assert.NewImportedResourceAssert(id, "imported resource"), + } +} + +/////////////////////////////////// +// Attribute value string checks // +/////////////////////////////////// + +func (s *ServiceUserResourceAssert) HasAbortDetachedQueryString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("abort_detached_query", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasAutocommitString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("autocommit", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasBinaryInputFormatString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("binary_input_format", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasBinaryOutputFormatString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("binary_output_format", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasClientMemoryLimitString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("client_memory_limit", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasClientMetadataRequestUseConnectionCtxString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("client_metadata_request_use_connection_ctx", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasClientPrefetchThreadsString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("client_prefetch_threads", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasClientResultChunkSizeString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("client_result_chunk_size", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasClientResultColumnCaseInsensitiveString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("client_result_column_case_insensitive", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasClientSessionKeepAliveString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("client_session_keep_alive", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasClientSessionKeepAliveHeartbeatFrequencyString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("client_session_keep_alive_heartbeat_frequency", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasClientTimestampTypeMappingString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("client_timestamp_type_mapping", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasCommentString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("comment", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasDateInputFormatString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("date_input_format", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasDateOutputFormatString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("date_output_format", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasDaysToExpiryString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("days_to_expiry", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasDefaultNamespaceString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("default_namespace", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasDefaultRoleString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("default_role", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasDefaultSecondaryRolesOptionString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("default_secondary_roles_option", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasDefaultWarehouseString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("default_warehouse", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasDisabledString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("disabled", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasDisplayNameString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("display_name", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasEmailString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("email", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasEnableUnloadPhysicalTypeOptimizationString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("enable_unload_physical_type_optimization", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasEnableUnredactedQuerySyntaxErrorString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("enable_unredacted_query_syntax_error", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasErrorOnNondeterministicMergeString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("error_on_nondeterministic_merge", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasErrorOnNondeterministicUpdateString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("error_on_nondeterministic_update", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasFullyQualifiedNameString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("fully_qualified_name", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasGeographyOutputFormatString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("geography_output_format", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasGeometryOutputFormatString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("geometry_output_format", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasJdbcTreatDecimalAsIntString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("jdbc_treat_decimal_as_int", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasJdbcTreatTimestampNtzAsUtcString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("jdbc_treat_timestamp_ntz_as_utc", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasJdbcUseSessionTimezoneString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("jdbc_use_session_timezone", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasJsonIndentString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("json_indent", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasLockTimeoutString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("lock_timeout", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasLogLevelString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("log_level", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasLoginNameString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("login_name", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasMinsToUnlockString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("mins_to_unlock", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasMultiStatementCountString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("multi_statement_count", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasNameString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("name", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasNetworkPolicyString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("network_policy", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasNoorderSequenceAsDefaultString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("noorder_sequence_as_default", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasOdbcTreatDecimalAsIntString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("odbc_treat_decimal_as_int", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasPreventUnloadToInternalStagesString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("prevent_unload_to_internal_stages", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasQueryTagString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("query_tag", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasQuotedIdentifiersIgnoreCaseString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("quoted_identifiers_ignore_case", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasRowsPerResultsetString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("rows_per_resultset", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasRsaPublicKeyString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("rsa_public_key", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasRsaPublicKey2String(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("rsa_public_key_2", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasS3StageVpceDnsNameString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("s3_stage_vpce_dns_name", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasSearchPathString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("search_path", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasSimulatedDataSharingConsumerString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("simulated_data_sharing_consumer", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasStatementQueuedTimeoutInSecondsString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("statement_queued_timeout_in_seconds", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasStatementTimeoutInSecondsString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("statement_timeout_in_seconds", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasStrictJsonOutputString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("strict_json_output", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasTimeInputFormatString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("time_input_format", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasTimeOutputFormatString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("time_output_format", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasTimestampDayIsAlways24hString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("timestamp_day_is_always_24h", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasTimestampInputFormatString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("timestamp_input_format", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasTimestampLtzOutputFormatString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("timestamp_ltz_output_format", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasTimestampNtzOutputFormatString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("timestamp_ntz_output_format", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasTimestampOutputFormatString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("timestamp_output_format", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasTimestampTypeMappingString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("timestamp_type_mapping", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasTimestampTzOutputFormatString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("timestamp_tz_output_format", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasTimezoneString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("timezone", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasTraceLevelString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("trace_level", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasTransactionAbortOnErrorString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("transaction_abort_on_error", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasTransactionDefaultIsolationLevelString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("transaction_default_isolation_level", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasTwoDigitCenturyStartString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("two_digit_century_start", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasUnsupportedDdlActionString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("unsupported_ddl_action", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasUseCachedResultString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("use_cached_result", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasUserTypeString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("user_type", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasWeekOfYearPolicyString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("week_of_year_policy", expected)) + return s +} + +func (s *ServiceUserResourceAssert) HasWeekStartString(expected string) *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueSet("week_start", expected)) + return s +} + +//////////////////////////// +// Attribute empty checks // +//////////////////////////// + +func (s *ServiceUserResourceAssert) HasNoAbortDetachedQuery() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("abort_detached_query")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoAutocommit() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("autocommit")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoBinaryInputFormat() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("binary_input_format")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoBinaryOutputFormat() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("binary_output_format")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoClientMemoryLimit() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("client_memory_limit")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoClientMetadataRequestUseConnectionCtx() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("client_metadata_request_use_connection_ctx")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoClientPrefetchThreads() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("client_prefetch_threads")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoClientResultChunkSize() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("client_result_chunk_size")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoClientResultColumnCaseInsensitive() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("client_result_column_case_insensitive")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoClientSessionKeepAlive() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("client_session_keep_alive")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoClientSessionKeepAliveHeartbeatFrequency() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("client_session_keep_alive_heartbeat_frequency")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoClientTimestampTypeMapping() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("client_timestamp_type_mapping")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoComment() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("comment")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoDateInputFormat() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("date_input_format")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoDateOutputFormat() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("date_output_format")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoDaysToExpiry() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("days_to_expiry")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoDefaultNamespace() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("default_namespace")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoDefaultRole() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("default_role")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoDefaultSecondaryRolesOption() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("default_secondary_roles_option")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoDefaultWarehouse() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("default_warehouse")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoDisabled() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("disabled")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoDisplayName() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("display_name")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoEmail() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("email")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoEnableUnloadPhysicalTypeOptimization() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("enable_unload_physical_type_optimization")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoEnableUnredactedQuerySyntaxError() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("enable_unredacted_query_syntax_error")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoErrorOnNondeterministicMerge() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("error_on_nondeterministic_merge")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoErrorOnNondeterministicUpdate() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("error_on_nondeterministic_update")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoFullyQualifiedName() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("fully_qualified_name")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoGeographyOutputFormat() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("geography_output_format")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoGeometryOutputFormat() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("geometry_output_format")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoJdbcTreatDecimalAsInt() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("jdbc_treat_decimal_as_int")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoJdbcTreatTimestampNtzAsUtc() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("jdbc_treat_timestamp_ntz_as_utc")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoJdbcUseSessionTimezone() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("jdbc_use_session_timezone")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoJsonIndent() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("json_indent")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoLockTimeout() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("lock_timeout")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoLogLevel() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("log_level")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoLoginName() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("login_name")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoMinsToUnlock() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("mins_to_unlock")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoMultiStatementCount() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("multi_statement_count")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoName() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("name")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoNetworkPolicy() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("network_policy")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoNoorderSequenceAsDefault() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("noorder_sequence_as_default")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoOdbcTreatDecimalAsInt() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("odbc_treat_decimal_as_int")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoPreventUnloadToInternalStages() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("prevent_unload_to_internal_stages")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoQueryTag() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("query_tag")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoQuotedIdentifiersIgnoreCase() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("quoted_identifiers_ignore_case")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoRowsPerResultset() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("rows_per_resultset")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoRsaPublicKey() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("rsa_public_key")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoRsaPublicKey2() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("rsa_public_key_2")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoS3StageVpceDnsName() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("s3_stage_vpce_dns_name")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoSearchPath() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("search_path")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoSimulatedDataSharingConsumer() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("simulated_data_sharing_consumer")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoStatementQueuedTimeoutInSeconds() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("statement_queued_timeout_in_seconds")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoStatementTimeoutInSeconds() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("statement_timeout_in_seconds")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoStrictJsonOutput() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("strict_json_output")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoTimeInputFormat() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("time_input_format")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoTimeOutputFormat() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("time_output_format")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoTimestampDayIsAlways24h() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("timestamp_day_is_always_24h")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoTimestampInputFormat() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("timestamp_input_format")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoTimestampLtzOutputFormat() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("timestamp_ltz_output_format")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoTimestampNtzOutputFormat() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("timestamp_ntz_output_format")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoTimestampOutputFormat() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("timestamp_output_format")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoTimestampTypeMapping() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("timestamp_type_mapping")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoTimestampTzOutputFormat() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("timestamp_tz_output_format")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoTimezone() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("timezone")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoTraceLevel() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("trace_level")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoTransactionAbortOnError() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("transaction_abort_on_error")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoTransactionDefaultIsolationLevel() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("transaction_default_isolation_level")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoTwoDigitCenturyStart() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("two_digit_century_start")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoUnsupportedDdlAction() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("unsupported_ddl_action")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoUseCachedResult() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("use_cached_result")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoUserType() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("user_type")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoWeekOfYearPolicy() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("week_of_year_policy")) + return s +} + +func (s *ServiceUserResourceAssert) HasNoWeekStart() *ServiceUserResourceAssert { + s.AddAssertion(assert.ValueNotSet("week_start")) + return s +} diff --git a/pkg/acceptance/bettertestspoc/config/model/legacy_service_user_model_ext.go b/pkg/acceptance/bettertestspoc/config/model/legacy_service_user_model_ext.go new file mode 100644 index 0000000000..bb1ed4aa35 --- /dev/null +++ b/pkg/acceptance/bettertestspoc/config/model/legacy_service_user_model_ext.go @@ -0,0 +1,66 @@ +package model + +import ( + tfconfig "github.com/hashicorp/terraform-plugin-testing/config" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" +) + +func (u *LegacyServiceUserModel) WithBinaryInputFormatEnum(binaryInputFormat sdk.BinaryInputFormat) *LegacyServiceUserModel { + u.BinaryInputFormat = tfconfig.StringVariable(string(binaryInputFormat)) + return u +} + +func (u *LegacyServiceUserModel) WithBinaryOutputFormatEnum(binaryOutputFormat sdk.BinaryOutputFormat) *LegacyServiceUserModel { + u.BinaryOutputFormat = tfconfig.StringVariable(string(binaryOutputFormat)) + return u +} + +func (u *LegacyServiceUserModel) WithClientTimestampTypeMappingEnum(clientTimestampTypeMapping sdk.ClientTimestampTypeMapping) *LegacyServiceUserModel { + u.ClientTimestampTypeMapping = tfconfig.StringVariable(string(clientTimestampTypeMapping)) + return u +} + +func (u *LegacyServiceUserModel) WithGeographyOutputFormatEnum(geographyOutputFormat sdk.GeographyOutputFormat) *LegacyServiceUserModel { + u.GeographyOutputFormat = tfconfig.StringVariable(string(geographyOutputFormat)) + return u +} + +func (u *LegacyServiceUserModel) WithGeometryOutputFormatEnum(geometryOutputFormat sdk.GeometryOutputFormat) *LegacyServiceUserModel { + u.GeometryOutputFormat = tfconfig.StringVariable(string(geometryOutputFormat)) + return u +} + +func (u *LegacyServiceUserModel) WithLogLevelEnum(logLevel sdk.LogLevel) *LegacyServiceUserModel { + u.LogLevel = tfconfig.StringVariable(string(logLevel)) + return u +} + +func (u *LegacyServiceUserModel) WithTimestampTypeMappingEnum(timestampTypeMapping sdk.TimestampTypeMapping) *LegacyServiceUserModel { + u.TimestampTypeMapping = tfconfig.StringVariable(string(timestampTypeMapping)) + return u +} + +func (u *LegacyServiceUserModel) WithTraceLevelEnum(traceLevel sdk.TraceLevel) *LegacyServiceUserModel { + u.TraceLevel = tfconfig.StringVariable(string(traceLevel)) + return u +} + +func (u *LegacyServiceUserModel) WithTransactionDefaultIsolationLevelEnum(transactionDefaultIsolationLevel sdk.TransactionDefaultIsolationLevel) *LegacyServiceUserModel { + u.TransactionDefaultIsolationLevel = tfconfig.StringVariable(string(transactionDefaultIsolationLevel)) + return u +} + +func (u *LegacyServiceUserModel) WithUnsupportedDdlActionEnum(unsupportedDdlAction sdk.UnsupportedDDLAction) *LegacyServiceUserModel { + u.UnsupportedDdlAction = tfconfig.StringVariable(string(unsupportedDdlAction)) + return u +} + +func (u *LegacyServiceUserModel) WithNetworkPolicyId(networkPolicy sdk.AccountObjectIdentifier) *LegacyServiceUserModel { + u.NetworkPolicy = tfconfig.StringVariable(networkPolicy.Name()) + return u +} + +func (u *LegacyServiceUserModel) WithDefaultSecondaryRolesOptionEnum(option sdk.SecondaryRolesOption) *LegacyServiceUserModel { + return u.WithDefaultSecondaryRolesOption(string(option)) +} diff --git a/pkg/acceptance/bettertestspoc/config/model/legacy_service_user_model_gen.go b/pkg/acceptance/bettertestspoc/config/model/legacy_service_user_model_gen.go new file mode 100644 index 0000000000..cfa415e5aa --- /dev/null +++ b/pkg/acceptance/bettertestspoc/config/model/legacy_service_user_model_gen.go @@ -0,0 +1,880 @@ +// Code generated by config model builder generator; DO NOT EDIT. + +package model + +import ( + tfconfig "github.com/hashicorp/terraform-plugin-testing/config" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider/resources" +) + +type LegacyServiceUserModel struct { + AbortDetachedQuery tfconfig.Variable `json:"abort_detached_query,omitempty"` + Autocommit tfconfig.Variable `json:"autocommit,omitempty"` + BinaryInputFormat tfconfig.Variable `json:"binary_input_format,omitempty"` + BinaryOutputFormat tfconfig.Variable `json:"binary_output_format,omitempty"` + ClientMemoryLimit tfconfig.Variable `json:"client_memory_limit,omitempty"` + ClientMetadataRequestUseConnectionCtx tfconfig.Variable `json:"client_metadata_request_use_connection_ctx,omitempty"` + ClientPrefetchThreads tfconfig.Variable `json:"client_prefetch_threads,omitempty"` + ClientResultChunkSize tfconfig.Variable `json:"client_result_chunk_size,omitempty"` + ClientResultColumnCaseInsensitive tfconfig.Variable `json:"client_result_column_case_insensitive,omitempty"` + ClientSessionKeepAlive tfconfig.Variable `json:"client_session_keep_alive,omitempty"` + ClientSessionKeepAliveHeartbeatFrequency tfconfig.Variable `json:"client_session_keep_alive_heartbeat_frequency,omitempty"` + ClientTimestampTypeMapping tfconfig.Variable `json:"client_timestamp_type_mapping,omitempty"` + Comment tfconfig.Variable `json:"comment,omitempty"` + DateInputFormat tfconfig.Variable `json:"date_input_format,omitempty"` + DateOutputFormat tfconfig.Variable `json:"date_output_format,omitempty"` + DaysToExpiry tfconfig.Variable `json:"days_to_expiry,omitempty"` + DefaultNamespace tfconfig.Variable `json:"default_namespace,omitempty"` + DefaultRole tfconfig.Variable `json:"default_role,omitempty"` + DefaultSecondaryRolesOption tfconfig.Variable `json:"default_secondary_roles_option,omitempty"` + DefaultWarehouse tfconfig.Variable `json:"default_warehouse,omitempty"` + Disabled tfconfig.Variable `json:"disabled,omitempty"` + DisplayName tfconfig.Variable `json:"display_name,omitempty"` + Email tfconfig.Variable `json:"email,omitempty"` + EnableUnloadPhysicalTypeOptimization tfconfig.Variable `json:"enable_unload_physical_type_optimization,omitempty"` + EnableUnredactedQuerySyntaxError tfconfig.Variable `json:"enable_unredacted_query_syntax_error,omitempty"` + ErrorOnNondeterministicMerge tfconfig.Variable `json:"error_on_nondeterministic_merge,omitempty"` + ErrorOnNondeterministicUpdate tfconfig.Variable `json:"error_on_nondeterministic_update,omitempty"` + FullyQualifiedName tfconfig.Variable `json:"fully_qualified_name,omitempty"` + GeographyOutputFormat tfconfig.Variable `json:"geography_output_format,omitempty"` + GeometryOutputFormat tfconfig.Variable `json:"geometry_output_format,omitempty"` + JdbcTreatDecimalAsInt tfconfig.Variable `json:"jdbc_treat_decimal_as_int,omitempty"` + JdbcTreatTimestampNtzAsUtc tfconfig.Variable `json:"jdbc_treat_timestamp_ntz_as_utc,omitempty"` + JdbcUseSessionTimezone tfconfig.Variable `json:"jdbc_use_session_timezone,omitempty"` + JsonIndent tfconfig.Variable `json:"json_indent,omitempty"` + LockTimeout tfconfig.Variable `json:"lock_timeout,omitempty"` + LogLevel tfconfig.Variable `json:"log_level,omitempty"` + LoginName tfconfig.Variable `json:"login_name,omitempty"` + MinsToUnlock tfconfig.Variable `json:"mins_to_unlock,omitempty"` + MultiStatementCount tfconfig.Variable `json:"multi_statement_count,omitempty"` + MustChangePassword tfconfig.Variable `json:"must_change_password,omitempty"` + Name tfconfig.Variable `json:"name,omitempty"` + NetworkPolicy tfconfig.Variable `json:"network_policy,omitempty"` + NoorderSequenceAsDefault tfconfig.Variable `json:"noorder_sequence_as_default,omitempty"` + OdbcTreatDecimalAsInt tfconfig.Variable `json:"odbc_treat_decimal_as_int,omitempty"` + Password tfconfig.Variable `json:"password,omitempty"` + PreventUnloadToInternalStages tfconfig.Variable `json:"prevent_unload_to_internal_stages,omitempty"` + QueryTag tfconfig.Variable `json:"query_tag,omitempty"` + QuotedIdentifiersIgnoreCase tfconfig.Variable `json:"quoted_identifiers_ignore_case,omitempty"` + RowsPerResultset tfconfig.Variable `json:"rows_per_resultset,omitempty"` + RsaPublicKey tfconfig.Variable `json:"rsa_public_key,omitempty"` + RsaPublicKey2 tfconfig.Variable `json:"rsa_public_key_2,omitempty"` + S3StageVpceDnsName tfconfig.Variable `json:"s3_stage_vpce_dns_name,omitempty"` + SearchPath tfconfig.Variable `json:"search_path,omitempty"` + SimulatedDataSharingConsumer tfconfig.Variable `json:"simulated_data_sharing_consumer,omitempty"` + StatementQueuedTimeoutInSeconds tfconfig.Variable `json:"statement_queued_timeout_in_seconds,omitempty"` + StatementTimeoutInSeconds tfconfig.Variable `json:"statement_timeout_in_seconds,omitempty"` + StrictJsonOutput tfconfig.Variable `json:"strict_json_output,omitempty"` + TimeInputFormat tfconfig.Variable `json:"time_input_format,omitempty"` + TimeOutputFormat tfconfig.Variable `json:"time_output_format,omitempty"` + TimestampDayIsAlways24h tfconfig.Variable `json:"timestamp_day_is_always_24h,omitempty"` + TimestampInputFormat tfconfig.Variable `json:"timestamp_input_format,omitempty"` + TimestampLtzOutputFormat tfconfig.Variable `json:"timestamp_ltz_output_format,omitempty"` + TimestampNtzOutputFormat tfconfig.Variable `json:"timestamp_ntz_output_format,omitempty"` + TimestampOutputFormat tfconfig.Variable `json:"timestamp_output_format,omitempty"` + TimestampTypeMapping tfconfig.Variable `json:"timestamp_type_mapping,omitempty"` + TimestampTzOutputFormat tfconfig.Variable `json:"timestamp_tz_output_format,omitempty"` + Timezone tfconfig.Variable `json:"timezone,omitempty"` + TraceLevel tfconfig.Variable `json:"trace_level,omitempty"` + TransactionAbortOnError tfconfig.Variable `json:"transaction_abort_on_error,omitempty"` + TransactionDefaultIsolationLevel tfconfig.Variable `json:"transaction_default_isolation_level,omitempty"` + TwoDigitCenturyStart tfconfig.Variable `json:"two_digit_century_start,omitempty"` + UnsupportedDdlAction tfconfig.Variable `json:"unsupported_ddl_action,omitempty"` + UseCachedResult tfconfig.Variable `json:"use_cached_result,omitempty"` + UserType tfconfig.Variable `json:"user_type,omitempty"` + WeekOfYearPolicy tfconfig.Variable `json:"week_of_year_policy,omitempty"` + WeekStart tfconfig.Variable `json:"week_start,omitempty"` + + *config.ResourceModelMeta +} + +///////////////////////////////////////////////// +// Basic builders (resource name and required) // +///////////////////////////////////////////////// + +func LegacyServiceUser( + resourceName string, + name string, +) *LegacyServiceUserModel { + l := &LegacyServiceUserModel{ResourceModelMeta: config.Meta(resourceName, resources.LegacyServiceUser)} + l.WithName(name) + return l +} + +func LegacyServiceUserWithDefaultMeta( + name string, +) *LegacyServiceUserModel { + l := &LegacyServiceUserModel{ResourceModelMeta: config.DefaultMeta(resources.LegacyServiceUser)} + l.WithName(name) + return l +} + +///////////////////////////////// +// below all the proper values // +///////////////////////////////// + +func (l *LegacyServiceUserModel) WithAbortDetachedQuery(abortDetachedQuery bool) *LegacyServiceUserModel { + l.AbortDetachedQuery = tfconfig.BoolVariable(abortDetachedQuery) + return l +} + +func (l *LegacyServiceUserModel) WithAutocommit(autocommit bool) *LegacyServiceUserModel { + l.Autocommit = tfconfig.BoolVariable(autocommit) + return l +} + +func (l *LegacyServiceUserModel) WithBinaryInputFormat(binaryInputFormat string) *LegacyServiceUserModel { + l.BinaryInputFormat = tfconfig.StringVariable(binaryInputFormat) + return l +} + +func (l *LegacyServiceUserModel) WithBinaryOutputFormat(binaryOutputFormat string) *LegacyServiceUserModel { + l.BinaryOutputFormat = tfconfig.StringVariable(binaryOutputFormat) + return l +} + +func (l *LegacyServiceUserModel) WithClientMemoryLimit(clientMemoryLimit int) *LegacyServiceUserModel { + l.ClientMemoryLimit = tfconfig.IntegerVariable(clientMemoryLimit) + return l +} + +func (l *LegacyServiceUserModel) WithClientMetadataRequestUseConnectionCtx(clientMetadataRequestUseConnectionCtx bool) *LegacyServiceUserModel { + l.ClientMetadataRequestUseConnectionCtx = tfconfig.BoolVariable(clientMetadataRequestUseConnectionCtx) + return l +} + +func (l *LegacyServiceUserModel) WithClientPrefetchThreads(clientPrefetchThreads int) *LegacyServiceUserModel { + l.ClientPrefetchThreads = tfconfig.IntegerVariable(clientPrefetchThreads) + return l +} + +func (l *LegacyServiceUserModel) WithClientResultChunkSize(clientResultChunkSize int) *LegacyServiceUserModel { + l.ClientResultChunkSize = tfconfig.IntegerVariable(clientResultChunkSize) + return l +} + +func (l *LegacyServiceUserModel) WithClientResultColumnCaseInsensitive(clientResultColumnCaseInsensitive bool) *LegacyServiceUserModel { + l.ClientResultColumnCaseInsensitive = tfconfig.BoolVariable(clientResultColumnCaseInsensitive) + return l +} + +func (l *LegacyServiceUserModel) WithClientSessionKeepAlive(clientSessionKeepAlive bool) *LegacyServiceUserModel { + l.ClientSessionKeepAlive = tfconfig.BoolVariable(clientSessionKeepAlive) + return l +} + +func (l *LegacyServiceUserModel) WithClientSessionKeepAliveHeartbeatFrequency(clientSessionKeepAliveHeartbeatFrequency int) *LegacyServiceUserModel { + l.ClientSessionKeepAliveHeartbeatFrequency = tfconfig.IntegerVariable(clientSessionKeepAliveHeartbeatFrequency) + return l +} + +func (l *LegacyServiceUserModel) WithClientTimestampTypeMapping(clientTimestampTypeMapping string) *LegacyServiceUserModel { + l.ClientTimestampTypeMapping = tfconfig.StringVariable(clientTimestampTypeMapping) + return l +} + +func (l *LegacyServiceUserModel) WithComment(comment string) *LegacyServiceUserModel { + l.Comment = tfconfig.StringVariable(comment) + return l +} + +func (l *LegacyServiceUserModel) WithDateInputFormat(dateInputFormat string) *LegacyServiceUserModel { + l.DateInputFormat = tfconfig.StringVariable(dateInputFormat) + return l +} + +func (l *LegacyServiceUserModel) WithDateOutputFormat(dateOutputFormat string) *LegacyServiceUserModel { + l.DateOutputFormat = tfconfig.StringVariable(dateOutputFormat) + return l +} + +func (l *LegacyServiceUserModel) WithDaysToExpiry(daysToExpiry int) *LegacyServiceUserModel { + l.DaysToExpiry = tfconfig.IntegerVariable(daysToExpiry) + return l +} + +func (l *LegacyServiceUserModel) WithDefaultNamespace(defaultNamespace string) *LegacyServiceUserModel { + l.DefaultNamespace = tfconfig.StringVariable(defaultNamespace) + return l +} + +func (l *LegacyServiceUserModel) WithDefaultRole(defaultRole string) *LegacyServiceUserModel { + l.DefaultRole = tfconfig.StringVariable(defaultRole) + return l +} + +func (l *LegacyServiceUserModel) WithDefaultSecondaryRolesOption(defaultSecondaryRolesOption string) *LegacyServiceUserModel { + l.DefaultSecondaryRolesOption = tfconfig.StringVariable(defaultSecondaryRolesOption) + return l +} + +func (l *LegacyServiceUserModel) WithDefaultWarehouse(defaultWarehouse string) *LegacyServiceUserModel { + l.DefaultWarehouse = tfconfig.StringVariable(defaultWarehouse) + return l +} + +func (l *LegacyServiceUserModel) WithDisabled(disabled string) *LegacyServiceUserModel { + l.Disabled = tfconfig.StringVariable(disabled) + return l +} + +func (l *LegacyServiceUserModel) WithDisplayName(displayName string) *LegacyServiceUserModel { + l.DisplayName = tfconfig.StringVariable(displayName) + return l +} + +func (l *LegacyServiceUserModel) WithEmail(email string) *LegacyServiceUserModel { + l.Email = tfconfig.StringVariable(email) + return l +} + +func (l *LegacyServiceUserModel) WithEnableUnloadPhysicalTypeOptimization(enableUnloadPhysicalTypeOptimization bool) *LegacyServiceUserModel { + l.EnableUnloadPhysicalTypeOptimization = tfconfig.BoolVariable(enableUnloadPhysicalTypeOptimization) + return l +} + +func (l *LegacyServiceUserModel) WithEnableUnredactedQuerySyntaxError(enableUnredactedQuerySyntaxError bool) *LegacyServiceUserModel { + l.EnableUnredactedQuerySyntaxError = tfconfig.BoolVariable(enableUnredactedQuerySyntaxError) + return l +} + +func (l *LegacyServiceUserModel) WithErrorOnNondeterministicMerge(errorOnNondeterministicMerge bool) *LegacyServiceUserModel { + l.ErrorOnNondeterministicMerge = tfconfig.BoolVariable(errorOnNondeterministicMerge) + return l +} + +func (l *LegacyServiceUserModel) WithErrorOnNondeterministicUpdate(errorOnNondeterministicUpdate bool) *LegacyServiceUserModel { + l.ErrorOnNondeterministicUpdate = tfconfig.BoolVariable(errorOnNondeterministicUpdate) + return l +} + +func (l *LegacyServiceUserModel) WithFullyQualifiedName(fullyQualifiedName string) *LegacyServiceUserModel { + l.FullyQualifiedName = tfconfig.StringVariable(fullyQualifiedName) + return l +} + +func (l *LegacyServiceUserModel) WithGeographyOutputFormat(geographyOutputFormat string) *LegacyServiceUserModel { + l.GeographyOutputFormat = tfconfig.StringVariable(geographyOutputFormat) + return l +} + +func (l *LegacyServiceUserModel) WithGeometryOutputFormat(geometryOutputFormat string) *LegacyServiceUserModel { + l.GeometryOutputFormat = tfconfig.StringVariable(geometryOutputFormat) + return l +} + +func (l *LegacyServiceUserModel) WithJdbcTreatDecimalAsInt(jdbcTreatDecimalAsInt bool) *LegacyServiceUserModel { + l.JdbcTreatDecimalAsInt = tfconfig.BoolVariable(jdbcTreatDecimalAsInt) + return l +} + +func (l *LegacyServiceUserModel) WithJdbcTreatTimestampNtzAsUtc(jdbcTreatTimestampNtzAsUtc bool) *LegacyServiceUserModel { + l.JdbcTreatTimestampNtzAsUtc = tfconfig.BoolVariable(jdbcTreatTimestampNtzAsUtc) + return l +} + +func (l *LegacyServiceUserModel) WithJdbcUseSessionTimezone(jdbcUseSessionTimezone bool) *LegacyServiceUserModel { + l.JdbcUseSessionTimezone = tfconfig.BoolVariable(jdbcUseSessionTimezone) + return l +} + +func (l *LegacyServiceUserModel) WithJsonIndent(jsonIndent int) *LegacyServiceUserModel { + l.JsonIndent = tfconfig.IntegerVariable(jsonIndent) + return l +} + +func (l *LegacyServiceUserModel) WithLockTimeout(lockTimeout int) *LegacyServiceUserModel { + l.LockTimeout = tfconfig.IntegerVariable(lockTimeout) + return l +} + +func (l *LegacyServiceUserModel) WithLogLevel(logLevel string) *LegacyServiceUserModel { + l.LogLevel = tfconfig.StringVariable(logLevel) + return l +} + +func (l *LegacyServiceUserModel) WithLoginName(loginName string) *LegacyServiceUserModel { + l.LoginName = tfconfig.StringVariable(loginName) + return l +} + +func (l *LegacyServiceUserModel) WithMinsToUnlock(minsToUnlock int) *LegacyServiceUserModel { + l.MinsToUnlock = tfconfig.IntegerVariable(minsToUnlock) + return l +} + +func (l *LegacyServiceUserModel) WithMultiStatementCount(multiStatementCount int) *LegacyServiceUserModel { + l.MultiStatementCount = tfconfig.IntegerVariable(multiStatementCount) + return l +} + +func (l *LegacyServiceUserModel) WithMustChangePassword(mustChangePassword string) *LegacyServiceUserModel { + l.MustChangePassword = tfconfig.StringVariable(mustChangePassword) + return l +} + +func (l *LegacyServiceUserModel) WithName(name string) *LegacyServiceUserModel { + l.Name = tfconfig.StringVariable(name) + return l +} + +func (l *LegacyServiceUserModel) WithNetworkPolicy(networkPolicy string) *LegacyServiceUserModel { + l.NetworkPolicy = tfconfig.StringVariable(networkPolicy) + return l +} + +func (l *LegacyServiceUserModel) WithNoorderSequenceAsDefault(noorderSequenceAsDefault bool) *LegacyServiceUserModel { + l.NoorderSequenceAsDefault = tfconfig.BoolVariable(noorderSequenceAsDefault) + return l +} + +func (l *LegacyServiceUserModel) WithOdbcTreatDecimalAsInt(odbcTreatDecimalAsInt bool) *LegacyServiceUserModel { + l.OdbcTreatDecimalAsInt = tfconfig.BoolVariable(odbcTreatDecimalAsInt) + return l +} + +func (l *LegacyServiceUserModel) WithPassword(password string) *LegacyServiceUserModel { + l.Password = tfconfig.StringVariable(password) + return l +} + +func (l *LegacyServiceUserModel) WithPreventUnloadToInternalStages(preventUnloadToInternalStages bool) *LegacyServiceUserModel { + l.PreventUnloadToInternalStages = tfconfig.BoolVariable(preventUnloadToInternalStages) + return l +} + +func (l *LegacyServiceUserModel) WithQueryTag(queryTag string) *LegacyServiceUserModel { + l.QueryTag = tfconfig.StringVariable(queryTag) + return l +} + +func (l *LegacyServiceUserModel) WithQuotedIdentifiersIgnoreCase(quotedIdentifiersIgnoreCase bool) *LegacyServiceUserModel { + l.QuotedIdentifiersIgnoreCase = tfconfig.BoolVariable(quotedIdentifiersIgnoreCase) + return l +} + +func (l *LegacyServiceUserModel) WithRowsPerResultset(rowsPerResultset int) *LegacyServiceUserModel { + l.RowsPerResultset = tfconfig.IntegerVariable(rowsPerResultset) + return l +} + +func (l *LegacyServiceUserModel) WithRsaPublicKey(rsaPublicKey string) *LegacyServiceUserModel { + l.RsaPublicKey = tfconfig.StringVariable(rsaPublicKey) + return l +} + +func (l *LegacyServiceUserModel) WithRsaPublicKey2(rsaPublicKey2 string) *LegacyServiceUserModel { + l.RsaPublicKey2 = tfconfig.StringVariable(rsaPublicKey2) + return l +} + +func (l *LegacyServiceUserModel) WithS3StageVpceDnsName(s3StageVpceDnsName string) *LegacyServiceUserModel { + l.S3StageVpceDnsName = tfconfig.StringVariable(s3StageVpceDnsName) + return l +} + +func (l *LegacyServiceUserModel) WithSearchPath(searchPath string) *LegacyServiceUserModel { + l.SearchPath = tfconfig.StringVariable(searchPath) + return l +} + +func (l *LegacyServiceUserModel) WithSimulatedDataSharingConsumer(simulatedDataSharingConsumer string) *LegacyServiceUserModel { + l.SimulatedDataSharingConsumer = tfconfig.StringVariable(simulatedDataSharingConsumer) + return l +} + +func (l *LegacyServiceUserModel) WithStatementQueuedTimeoutInSeconds(statementQueuedTimeoutInSeconds int) *LegacyServiceUserModel { + l.StatementQueuedTimeoutInSeconds = tfconfig.IntegerVariable(statementQueuedTimeoutInSeconds) + return l +} + +func (l *LegacyServiceUserModel) WithStatementTimeoutInSeconds(statementTimeoutInSeconds int) *LegacyServiceUserModel { + l.StatementTimeoutInSeconds = tfconfig.IntegerVariable(statementTimeoutInSeconds) + return l +} + +func (l *LegacyServiceUserModel) WithStrictJsonOutput(strictJsonOutput bool) *LegacyServiceUserModel { + l.StrictJsonOutput = tfconfig.BoolVariable(strictJsonOutput) + return l +} + +func (l *LegacyServiceUserModel) WithTimeInputFormat(timeInputFormat string) *LegacyServiceUserModel { + l.TimeInputFormat = tfconfig.StringVariable(timeInputFormat) + return l +} + +func (l *LegacyServiceUserModel) WithTimeOutputFormat(timeOutputFormat string) *LegacyServiceUserModel { + l.TimeOutputFormat = tfconfig.StringVariable(timeOutputFormat) + return l +} + +func (l *LegacyServiceUserModel) WithTimestampDayIsAlways24h(timestampDayIsAlways24h bool) *LegacyServiceUserModel { + l.TimestampDayIsAlways24h = tfconfig.BoolVariable(timestampDayIsAlways24h) + return l +} + +func (l *LegacyServiceUserModel) WithTimestampInputFormat(timestampInputFormat string) *LegacyServiceUserModel { + l.TimestampInputFormat = tfconfig.StringVariable(timestampInputFormat) + return l +} + +func (l *LegacyServiceUserModel) WithTimestampLtzOutputFormat(timestampLtzOutputFormat string) *LegacyServiceUserModel { + l.TimestampLtzOutputFormat = tfconfig.StringVariable(timestampLtzOutputFormat) + return l +} + +func (l *LegacyServiceUserModel) WithTimestampNtzOutputFormat(timestampNtzOutputFormat string) *LegacyServiceUserModel { + l.TimestampNtzOutputFormat = tfconfig.StringVariable(timestampNtzOutputFormat) + return l +} + +func (l *LegacyServiceUserModel) WithTimestampOutputFormat(timestampOutputFormat string) *LegacyServiceUserModel { + l.TimestampOutputFormat = tfconfig.StringVariable(timestampOutputFormat) + return l +} + +func (l *LegacyServiceUserModel) WithTimestampTypeMapping(timestampTypeMapping string) *LegacyServiceUserModel { + l.TimestampTypeMapping = tfconfig.StringVariable(timestampTypeMapping) + return l +} + +func (l *LegacyServiceUserModel) WithTimestampTzOutputFormat(timestampTzOutputFormat string) *LegacyServiceUserModel { + l.TimestampTzOutputFormat = tfconfig.StringVariable(timestampTzOutputFormat) + return l +} + +func (l *LegacyServiceUserModel) WithTimezone(timezone string) *LegacyServiceUserModel { + l.Timezone = tfconfig.StringVariable(timezone) + return l +} + +func (l *LegacyServiceUserModel) WithTraceLevel(traceLevel string) *LegacyServiceUserModel { + l.TraceLevel = tfconfig.StringVariable(traceLevel) + return l +} + +func (l *LegacyServiceUserModel) WithTransactionAbortOnError(transactionAbortOnError bool) *LegacyServiceUserModel { + l.TransactionAbortOnError = tfconfig.BoolVariable(transactionAbortOnError) + return l +} + +func (l *LegacyServiceUserModel) WithTransactionDefaultIsolationLevel(transactionDefaultIsolationLevel string) *LegacyServiceUserModel { + l.TransactionDefaultIsolationLevel = tfconfig.StringVariable(transactionDefaultIsolationLevel) + return l +} + +func (l *LegacyServiceUserModel) WithTwoDigitCenturyStart(twoDigitCenturyStart int) *LegacyServiceUserModel { + l.TwoDigitCenturyStart = tfconfig.IntegerVariable(twoDigitCenturyStart) + return l +} + +func (l *LegacyServiceUserModel) WithUnsupportedDdlAction(unsupportedDdlAction string) *LegacyServiceUserModel { + l.UnsupportedDdlAction = tfconfig.StringVariable(unsupportedDdlAction) + return l +} + +func (l *LegacyServiceUserModel) WithUseCachedResult(useCachedResult bool) *LegacyServiceUserModel { + l.UseCachedResult = tfconfig.BoolVariable(useCachedResult) + return l +} + +func (l *LegacyServiceUserModel) WithUserType(userType string) *LegacyServiceUserModel { + l.UserType = tfconfig.StringVariable(userType) + return l +} + +func (l *LegacyServiceUserModel) WithWeekOfYearPolicy(weekOfYearPolicy int) *LegacyServiceUserModel { + l.WeekOfYearPolicy = tfconfig.IntegerVariable(weekOfYearPolicy) + return l +} + +func (l *LegacyServiceUserModel) WithWeekStart(weekStart int) *LegacyServiceUserModel { + l.WeekStart = tfconfig.IntegerVariable(weekStart) + return l +} + +////////////////////////////////////////// +// below it's possible to set any value // +////////////////////////////////////////// + +func (l *LegacyServiceUserModel) WithAbortDetachedQueryValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.AbortDetachedQuery = value + return l +} + +func (l *LegacyServiceUserModel) WithAutocommitValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.Autocommit = value + return l +} + +func (l *LegacyServiceUserModel) WithBinaryInputFormatValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.BinaryInputFormat = value + return l +} + +func (l *LegacyServiceUserModel) WithBinaryOutputFormatValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.BinaryOutputFormat = value + return l +} + +func (l *LegacyServiceUserModel) WithClientMemoryLimitValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.ClientMemoryLimit = value + return l +} + +func (l *LegacyServiceUserModel) WithClientMetadataRequestUseConnectionCtxValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.ClientMetadataRequestUseConnectionCtx = value + return l +} + +func (l *LegacyServiceUserModel) WithClientPrefetchThreadsValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.ClientPrefetchThreads = value + return l +} + +func (l *LegacyServiceUserModel) WithClientResultChunkSizeValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.ClientResultChunkSize = value + return l +} + +func (l *LegacyServiceUserModel) WithClientResultColumnCaseInsensitiveValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.ClientResultColumnCaseInsensitive = value + return l +} + +func (l *LegacyServiceUserModel) WithClientSessionKeepAliveValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.ClientSessionKeepAlive = value + return l +} + +func (l *LegacyServiceUserModel) WithClientSessionKeepAliveHeartbeatFrequencyValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.ClientSessionKeepAliveHeartbeatFrequency = value + return l +} + +func (l *LegacyServiceUserModel) WithClientTimestampTypeMappingValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.ClientTimestampTypeMapping = value + return l +} + +func (l *LegacyServiceUserModel) WithCommentValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.Comment = value + return l +} + +func (l *LegacyServiceUserModel) WithDateInputFormatValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.DateInputFormat = value + return l +} + +func (l *LegacyServiceUserModel) WithDateOutputFormatValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.DateOutputFormat = value + return l +} + +func (l *LegacyServiceUserModel) WithDaysToExpiryValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.DaysToExpiry = value + return l +} + +func (l *LegacyServiceUserModel) WithDefaultNamespaceValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.DefaultNamespace = value + return l +} + +func (l *LegacyServiceUserModel) WithDefaultRoleValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.DefaultRole = value + return l +} + +func (l *LegacyServiceUserModel) WithDefaultSecondaryRolesOptionValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.DefaultSecondaryRolesOption = value + return l +} + +func (l *LegacyServiceUserModel) WithDefaultWarehouseValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.DefaultWarehouse = value + return l +} + +func (l *LegacyServiceUserModel) WithDisabledValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.Disabled = value + return l +} + +func (l *LegacyServiceUserModel) WithDisplayNameValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.DisplayName = value + return l +} + +func (l *LegacyServiceUserModel) WithEmailValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.Email = value + return l +} + +func (l *LegacyServiceUserModel) WithEnableUnloadPhysicalTypeOptimizationValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.EnableUnloadPhysicalTypeOptimization = value + return l +} + +func (l *LegacyServiceUserModel) WithEnableUnredactedQuerySyntaxErrorValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.EnableUnredactedQuerySyntaxError = value + return l +} + +func (l *LegacyServiceUserModel) WithErrorOnNondeterministicMergeValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.ErrorOnNondeterministicMerge = value + return l +} + +func (l *LegacyServiceUserModel) WithErrorOnNondeterministicUpdateValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.ErrorOnNondeterministicUpdate = value + return l +} + +func (l *LegacyServiceUserModel) WithFullyQualifiedNameValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.FullyQualifiedName = value + return l +} + +func (l *LegacyServiceUserModel) WithGeographyOutputFormatValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.GeographyOutputFormat = value + return l +} + +func (l *LegacyServiceUserModel) WithGeometryOutputFormatValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.GeometryOutputFormat = value + return l +} + +func (l *LegacyServiceUserModel) WithJdbcTreatDecimalAsIntValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.JdbcTreatDecimalAsInt = value + return l +} + +func (l *LegacyServiceUserModel) WithJdbcTreatTimestampNtzAsUtcValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.JdbcTreatTimestampNtzAsUtc = value + return l +} + +func (l *LegacyServiceUserModel) WithJdbcUseSessionTimezoneValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.JdbcUseSessionTimezone = value + return l +} + +func (l *LegacyServiceUserModel) WithJsonIndentValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.JsonIndent = value + return l +} + +func (l *LegacyServiceUserModel) WithLockTimeoutValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.LockTimeout = value + return l +} + +func (l *LegacyServiceUserModel) WithLogLevelValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.LogLevel = value + return l +} + +func (l *LegacyServiceUserModel) WithLoginNameValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.LoginName = value + return l +} + +func (l *LegacyServiceUserModel) WithMinsToUnlockValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.MinsToUnlock = value + return l +} + +func (l *LegacyServiceUserModel) WithMultiStatementCountValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.MultiStatementCount = value + return l +} + +func (l *LegacyServiceUserModel) WithMustChangePasswordValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.MustChangePassword = value + return l +} + +func (l *LegacyServiceUserModel) WithNameValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.Name = value + return l +} + +func (l *LegacyServiceUserModel) WithNetworkPolicyValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.NetworkPolicy = value + return l +} + +func (l *LegacyServiceUserModel) WithNoorderSequenceAsDefaultValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.NoorderSequenceAsDefault = value + return l +} + +func (l *LegacyServiceUserModel) WithOdbcTreatDecimalAsIntValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.OdbcTreatDecimalAsInt = value + return l +} + +func (l *LegacyServiceUserModel) WithPasswordValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.Password = value + return l +} + +func (l *LegacyServiceUserModel) WithPreventUnloadToInternalStagesValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.PreventUnloadToInternalStages = value + return l +} + +func (l *LegacyServiceUserModel) WithQueryTagValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.QueryTag = value + return l +} + +func (l *LegacyServiceUserModel) WithQuotedIdentifiersIgnoreCaseValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.QuotedIdentifiersIgnoreCase = value + return l +} + +func (l *LegacyServiceUserModel) WithRowsPerResultsetValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.RowsPerResultset = value + return l +} + +func (l *LegacyServiceUserModel) WithRsaPublicKeyValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.RsaPublicKey = value + return l +} + +func (l *LegacyServiceUserModel) WithRsaPublicKey2Value(value tfconfig.Variable) *LegacyServiceUserModel { + l.RsaPublicKey2 = value + return l +} + +func (l *LegacyServiceUserModel) WithS3StageVpceDnsNameValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.S3StageVpceDnsName = value + return l +} + +func (l *LegacyServiceUserModel) WithSearchPathValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.SearchPath = value + return l +} + +func (l *LegacyServiceUserModel) WithSimulatedDataSharingConsumerValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.SimulatedDataSharingConsumer = value + return l +} + +func (l *LegacyServiceUserModel) WithStatementQueuedTimeoutInSecondsValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.StatementQueuedTimeoutInSeconds = value + return l +} + +func (l *LegacyServiceUserModel) WithStatementTimeoutInSecondsValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.StatementTimeoutInSeconds = value + return l +} + +func (l *LegacyServiceUserModel) WithStrictJsonOutputValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.StrictJsonOutput = value + return l +} + +func (l *LegacyServiceUserModel) WithTimeInputFormatValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.TimeInputFormat = value + return l +} + +func (l *LegacyServiceUserModel) WithTimeOutputFormatValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.TimeOutputFormat = value + return l +} + +func (l *LegacyServiceUserModel) WithTimestampDayIsAlways24hValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.TimestampDayIsAlways24h = value + return l +} + +func (l *LegacyServiceUserModel) WithTimestampInputFormatValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.TimestampInputFormat = value + return l +} + +func (l *LegacyServiceUserModel) WithTimestampLtzOutputFormatValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.TimestampLtzOutputFormat = value + return l +} + +func (l *LegacyServiceUserModel) WithTimestampNtzOutputFormatValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.TimestampNtzOutputFormat = value + return l +} + +func (l *LegacyServiceUserModel) WithTimestampOutputFormatValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.TimestampOutputFormat = value + return l +} + +func (l *LegacyServiceUserModel) WithTimestampTypeMappingValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.TimestampTypeMapping = value + return l +} + +func (l *LegacyServiceUserModel) WithTimestampTzOutputFormatValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.TimestampTzOutputFormat = value + return l +} + +func (l *LegacyServiceUserModel) WithTimezoneValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.Timezone = value + return l +} + +func (l *LegacyServiceUserModel) WithTraceLevelValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.TraceLevel = value + return l +} + +func (l *LegacyServiceUserModel) WithTransactionAbortOnErrorValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.TransactionAbortOnError = value + return l +} + +func (l *LegacyServiceUserModel) WithTransactionDefaultIsolationLevelValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.TransactionDefaultIsolationLevel = value + return l +} + +func (l *LegacyServiceUserModel) WithTwoDigitCenturyStartValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.TwoDigitCenturyStart = value + return l +} + +func (l *LegacyServiceUserModel) WithUnsupportedDdlActionValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.UnsupportedDdlAction = value + return l +} + +func (l *LegacyServiceUserModel) WithUseCachedResultValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.UseCachedResult = value + return l +} + +func (l *LegacyServiceUserModel) WithUserTypeValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.UserType = value + return l +} + +func (l *LegacyServiceUserModel) WithWeekOfYearPolicyValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.WeekOfYearPolicy = value + return l +} + +func (l *LegacyServiceUserModel) WithWeekStartValue(value tfconfig.Variable) *LegacyServiceUserModel { + l.WeekStart = value + return l +} diff --git a/pkg/acceptance/bettertestspoc/config/model/service_user_model_ext.go b/pkg/acceptance/bettertestspoc/config/model/service_user_model_ext.go new file mode 100644 index 0000000000..0f67f69af7 --- /dev/null +++ b/pkg/acceptance/bettertestspoc/config/model/service_user_model_ext.go @@ -0,0 +1,66 @@ +package model + +import ( + tfconfig "github.com/hashicorp/terraform-plugin-testing/config" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" +) + +func (u *ServiceUserModel) WithBinaryInputFormatEnum(binaryInputFormat sdk.BinaryInputFormat) *ServiceUserModel { + u.BinaryInputFormat = tfconfig.StringVariable(string(binaryInputFormat)) + return u +} + +func (u *ServiceUserModel) WithBinaryOutputFormatEnum(binaryOutputFormat sdk.BinaryOutputFormat) *ServiceUserModel { + u.BinaryOutputFormat = tfconfig.StringVariable(string(binaryOutputFormat)) + return u +} + +func (u *ServiceUserModel) WithClientTimestampTypeMappingEnum(clientTimestampTypeMapping sdk.ClientTimestampTypeMapping) *ServiceUserModel { + u.ClientTimestampTypeMapping = tfconfig.StringVariable(string(clientTimestampTypeMapping)) + return u +} + +func (u *ServiceUserModel) WithGeographyOutputFormatEnum(geographyOutputFormat sdk.GeographyOutputFormat) *ServiceUserModel { + u.GeographyOutputFormat = tfconfig.StringVariable(string(geographyOutputFormat)) + return u +} + +func (u *ServiceUserModel) WithGeometryOutputFormatEnum(geometryOutputFormat sdk.GeometryOutputFormat) *ServiceUserModel { + u.GeometryOutputFormat = tfconfig.StringVariable(string(geometryOutputFormat)) + return u +} + +func (u *ServiceUserModel) WithLogLevelEnum(logLevel sdk.LogLevel) *ServiceUserModel { + u.LogLevel = tfconfig.StringVariable(string(logLevel)) + return u +} + +func (u *ServiceUserModel) WithTimestampTypeMappingEnum(timestampTypeMapping sdk.TimestampTypeMapping) *ServiceUserModel { + u.TimestampTypeMapping = tfconfig.StringVariable(string(timestampTypeMapping)) + return u +} + +func (u *ServiceUserModel) WithTraceLevelEnum(traceLevel sdk.TraceLevel) *ServiceUserModel { + u.TraceLevel = tfconfig.StringVariable(string(traceLevel)) + return u +} + +func (u *ServiceUserModel) WithTransactionDefaultIsolationLevelEnum(transactionDefaultIsolationLevel sdk.TransactionDefaultIsolationLevel) *ServiceUserModel { + u.TransactionDefaultIsolationLevel = tfconfig.StringVariable(string(transactionDefaultIsolationLevel)) + return u +} + +func (u *ServiceUserModel) WithUnsupportedDdlActionEnum(unsupportedDdlAction sdk.UnsupportedDDLAction) *ServiceUserModel { + u.UnsupportedDdlAction = tfconfig.StringVariable(string(unsupportedDdlAction)) + return u +} + +func (u *ServiceUserModel) WithNetworkPolicyId(networkPolicy sdk.AccountObjectIdentifier) *ServiceUserModel { + u.NetworkPolicy = tfconfig.StringVariable(networkPolicy.Name()) + return u +} + +func (u *ServiceUserModel) WithDefaultSecondaryRolesOptionEnum(option sdk.SecondaryRolesOption) *ServiceUserModel { + return u.WithDefaultSecondaryRolesOption(string(option)) +} diff --git a/pkg/acceptance/bettertestspoc/config/model/service_user_model_gen.go b/pkg/acceptance/bettertestspoc/config/model/service_user_model_gen.go new file mode 100644 index 0000000000..930ec8f644 --- /dev/null +++ b/pkg/acceptance/bettertestspoc/config/model/service_user_model_gen.go @@ -0,0 +1,858 @@ +// Code generated by config model builder generator; DO NOT EDIT. + +package model + +import ( + tfconfig "github.com/hashicorp/terraform-plugin-testing/config" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider/resources" +) + +type ServiceUserModel struct { + AbortDetachedQuery tfconfig.Variable `json:"abort_detached_query,omitempty"` + Autocommit tfconfig.Variable `json:"autocommit,omitempty"` + BinaryInputFormat tfconfig.Variable `json:"binary_input_format,omitempty"` + BinaryOutputFormat tfconfig.Variable `json:"binary_output_format,omitempty"` + ClientMemoryLimit tfconfig.Variable `json:"client_memory_limit,omitempty"` + ClientMetadataRequestUseConnectionCtx tfconfig.Variable `json:"client_metadata_request_use_connection_ctx,omitempty"` + ClientPrefetchThreads tfconfig.Variable `json:"client_prefetch_threads,omitempty"` + ClientResultChunkSize tfconfig.Variable `json:"client_result_chunk_size,omitempty"` + ClientResultColumnCaseInsensitive tfconfig.Variable `json:"client_result_column_case_insensitive,omitempty"` + ClientSessionKeepAlive tfconfig.Variable `json:"client_session_keep_alive,omitempty"` + ClientSessionKeepAliveHeartbeatFrequency tfconfig.Variable `json:"client_session_keep_alive_heartbeat_frequency,omitempty"` + ClientTimestampTypeMapping tfconfig.Variable `json:"client_timestamp_type_mapping,omitempty"` + Comment tfconfig.Variable `json:"comment,omitempty"` + DateInputFormat tfconfig.Variable `json:"date_input_format,omitempty"` + DateOutputFormat tfconfig.Variable `json:"date_output_format,omitempty"` + DaysToExpiry tfconfig.Variable `json:"days_to_expiry,omitempty"` + DefaultNamespace tfconfig.Variable `json:"default_namespace,omitempty"` + DefaultRole tfconfig.Variable `json:"default_role,omitempty"` + DefaultSecondaryRolesOption tfconfig.Variable `json:"default_secondary_roles_option,omitempty"` + DefaultWarehouse tfconfig.Variable `json:"default_warehouse,omitempty"` + Disabled tfconfig.Variable `json:"disabled,omitempty"` + DisplayName tfconfig.Variable `json:"display_name,omitempty"` + Email tfconfig.Variable `json:"email,omitempty"` + EnableUnloadPhysicalTypeOptimization tfconfig.Variable `json:"enable_unload_physical_type_optimization,omitempty"` + EnableUnredactedQuerySyntaxError tfconfig.Variable `json:"enable_unredacted_query_syntax_error,omitempty"` + ErrorOnNondeterministicMerge tfconfig.Variable `json:"error_on_nondeterministic_merge,omitempty"` + ErrorOnNondeterministicUpdate tfconfig.Variable `json:"error_on_nondeterministic_update,omitempty"` + FullyQualifiedName tfconfig.Variable `json:"fully_qualified_name,omitempty"` + GeographyOutputFormat tfconfig.Variable `json:"geography_output_format,omitempty"` + GeometryOutputFormat tfconfig.Variable `json:"geometry_output_format,omitempty"` + JdbcTreatDecimalAsInt tfconfig.Variable `json:"jdbc_treat_decimal_as_int,omitempty"` + JdbcTreatTimestampNtzAsUtc tfconfig.Variable `json:"jdbc_treat_timestamp_ntz_as_utc,omitempty"` + JdbcUseSessionTimezone tfconfig.Variable `json:"jdbc_use_session_timezone,omitempty"` + JsonIndent tfconfig.Variable `json:"json_indent,omitempty"` + LockTimeout tfconfig.Variable `json:"lock_timeout,omitempty"` + LogLevel tfconfig.Variable `json:"log_level,omitempty"` + LoginName tfconfig.Variable `json:"login_name,omitempty"` + MinsToUnlock tfconfig.Variable `json:"mins_to_unlock,omitempty"` + MultiStatementCount tfconfig.Variable `json:"multi_statement_count,omitempty"` + Name tfconfig.Variable `json:"name,omitempty"` + NetworkPolicy tfconfig.Variable `json:"network_policy,omitempty"` + NoorderSequenceAsDefault tfconfig.Variable `json:"noorder_sequence_as_default,omitempty"` + OdbcTreatDecimalAsInt tfconfig.Variable `json:"odbc_treat_decimal_as_int,omitempty"` + PreventUnloadToInternalStages tfconfig.Variable `json:"prevent_unload_to_internal_stages,omitempty"` + QueryTag tfconfig.Variable `json:"query_tag,omitempty"` + QuotedIdentifiersIgnoreCase tfconfig.Variable `json:"quoted_identifiers_ignore_case,omitempty"` + RowsPerResultset tfconfig.Variable `json:"rows_per_resultset,omitempty"` + RsaPublicKey tfconfig.Variable `json:"rsa_public_key,omitempty"` + RsaPublicKey2 tfconfig.Variable `json:"rsa_public_key_2,omitempty"` + S3StageVpceDnsName tfconfig.Variable `json:"s3_stage_vpce_dns_name,omitempty"` + SearchPath tfconfig.Variable `json:"search_path,omitempty"` + SimulatedDataSharingConsumer tfconfig.Variable `json:"simulated_data_sharing_consumer,omitempty"` + StatementQueuedTimeoutInSeconds tfconfig.Variable `json:"statement_queued_timeout_in_seconds,omitempty"` + StatementTimeoutInSeconds tfconfig.Variable `json:"statement_timeout_in_seconds,omitempty"` + StrictJsonOutput tfconfig.Variable `json:"strict_json_output,omitempty"` + TimeInputFormat tfconfig.Variable `json:"time_input_format,omitempty"` + TimeOutputFormat tfconfig.Variable `json:"time_output_format,omitempty"` + TimestampDayIsAlways24h tfconfig.Variable `json:"timestamp_day_is_always_24h,omitempty"` + TimestampInputFormat tfconfig.Variable `json:"timestamp_input_format,omitempty"` + TimestampLtzOutputFormat tfconfig.Variable `json:"timestamp_ltz_output_format,omitempty"` + TimestampNtzOutputFormat tfconfig.Variable `json:"timestamp_ntz_output_format,omitempty"` + TimestampOutputFormat tfconfig.Variable `json:"timestamp_output_format,omitempty"` + TimestampTypeMapping tfconfig.Variable `json:"timestamp_type_mapping,omitempty"` + TimestampTzOutputFormat tfconfig.Variable `json:"timestamp_tz_output_format,omitempty"` + Timezone tfconfig.Variable `json:"timezone,omitempty"` + TraceLevel tfconfig.Variable `json:"trace_level,omitempty"` + TransactionAbortOnError tfconfig.Variable `json:"transaction_abort_on_error,omitempty"` + TransactionDefaultIsolationLevel tfconfig.Variable `json:"transaction_default_isolation_level,omitempty"` + TwoDigitCenturyStart tfconfig.Variable `json:"two_digit_century_start,omitempty"` + UnsupportedDdlAction tfconfig.Variable `json:"unsupported_ddl_action,omitempty"` + UseCachedResult tfconfig.Variable `json:"use_cached_result,omitempty"` + UserType tfconfig.Variable `json:"user_type,omitempty"` + WeekOfYearPolicy tfconfig.Variable `json:"week_of_year_policy,omitempty"` + WeekStart tfconfig.Variable `json:"week_start,omitempty"` + + *config.ResourceModelMeta +} + +///////////////////////////////////////////////// +// Basic builders (resource name and required) // +///////////////////////////////////////////////// + +func ServiceUser( + resourceName string, + name string, +) *ServiceUserModel { + s := &ServiceUserModel{ResourceModelMeta: config.Meta(resourceName, resources.ServiceUser)} + s.WithName(name) + return s +} + +func ServiceUserWithDefaultMeta( + name string, +) *ServiceUserModel { + s := &ServiceUserModel{ResourceModelMeta: config.DefaultMeta(resources.ServiceUser)} + s.WithName(name) + return s +} + +///////////////////////////////// +// below all the proper values // +///////////////////////////////// + +func (s *ServiceUserModel) WithAbortDetachedQuery(abortDetachedQuery bool) *ServiceUserModel { + s.AbortDetachedQuery = tfconfig.BoolVariable(abortDetachedQuery) + return s +} + +func (s *ServiceUserModel) WithAutocommit(autocommit bool) *ServiceUserModel { + s.Autocommit = tfconfig.BoolVariable(autocommit) + return s +} + +func (s *ServiceUserModel) WithBinaryInputFormat(binaryInputFormat string) *ServiceUserModel { + s.BinaryInputFormat = tfconfig.StringVariable(binaryInputFormat) + return s +} + +func (s *ServiceUserModel) WithBinaryOutputFormat(binaryOutputFormat string) *ServiceUserModel { + s.BinaryOutputFormat = tfconfig.StringVariable(binaryOutputFormat) + return s +} + +func (s *ServiceUserModel) WithClientMemoryLimit(clientMemoryLimit int) *ServiceUserModel { + s.ClientMemoryLimit = tfconfig.IntegerVariable(clientMemoryLimit) + return s +} + +func (s *ServiceUserModel) WithClientMetadataRequestUseConnectionCtx(clientMetadataRequestUseConnectionCtx bool) *ServiceUserModel { + s.ClientMetadataRequestUseConnectionCtx = tfconfig.BoolVariable(clientMetadataRequestUseConnectionCtx) + return s +} + +func (s *ServiceUserModel) WithClientPrefetchThreads(clientPrefetchThreads int) *ServiceUserModel { + s.ClientPrefetchThreads = tfconfig.IntegerVariable(clientPrefetchThreads) + return s +} + +func (s *ServiceUserModel) WithClientResultChunkSize(clientResultChunkSize int) *ServiceUserModel { + s.ClientResultChunkSize = tfconfig.IntegerVariable(clientResultChunkSize) + return s +} + +func (s *ServiceUserModel) WithClientResultColumnCaseInsensitive(clientResultColumnCaseInsensitive bool) *ServiceUserModel { + s.ClientResultColumnCaseInsensitive = tfconfig.BoolVariable(clientResultColumnCaseInsensitive) + return s +} + +func (s *ServiceUserModel) WithClientSessionKeepAlive(clientSessionKeepAlive bool) *ServiceUserModel { + s.ClientSessionKeepAlive = tfconfig.BoolVariable(clientSessionKeepAlive) + return s +} + +func (s *ServiceUserModel) WithClientSessionKeepAliveHeartbeatFrequency(clientSessionKeepAliveHeartbeatFrequency int) *ServiceUserModel { + s.ClientSessionKeepAliveHeartbeatFrequency = tfconfig.IntegerVariable(clientSessionKeepAliveHeartbeatFrequency) + return s +} + +func (s *ServiceUserModel) WithClientTimestampTypeMapping(clientTimestampTypeMapping string) *ServiceUserModel { + s.ClientTimestampTypeMapping = tfconfig.StringVariable(clientTimestampTypeMapping) + return s +} + +func (s *ServiceUserModel) WithComment(comment string) *ServiceUserModel { + s.Comment = tfconfig.StringVariable(comment) + return s +} + +func (s *ServiceUserModel) WithDateInputFormat(dateInputFormat string) *ServiceUserModel { + s.DateInputFormat = tfconfig.StringVariable(dateInputFormat) + return s +} + +func (s *ServiceUserModel) WithDateOutputFormat(dateOutputFormat string) *ServiceUserModel { + s.DateOutputFormat = tfconfig.StringVariable(dateOutputFormat) + return s +} + +func (s *ServiceUserModel) WithDaysToExpiry(daysToExpiry int) *ServiceUserModel { + s.DaysToExpiry = tfconfig.IntegerVariable(daysToExpiry) + return s +} + +func (s *ServiceUserModel) WithDefaultNamespace(defaultNamespace string) *ServiceUserModel { + s.DefaultNamespace = tfconfig.StringVariable(defaultNamespace) + return s +} + +func (s *ServiceUserModel) WithDefaultRole(defaultRole string) *ServiceUserModel { + s.DefaultRole = tfconfig.StringVariable(defaultRole) + return s +} + +func (s *ServiceUserModel) WithDefaultSecondaryRolesOption(defaultSecondaryRolesOption string) *ServiceUserModel { + s.DefaultSecondaryRolesOption = tfconfig.StringVariable(defaultSecondaryRolesOption) + return s +} + +func (s *ServiceUserModel) WithDefaultWarehouse(defaultWarehouse string) *ServiceUserModel { + s.DefaultWarehouse = tfconfig.StringVariable(defaultWarehouse) + return s +} + +func (s *ServiceUserModel) WithDisabled(disabled string) *ServiceUserModel { + s.Disabled = tfconfig.StringVariable(disabled) + return s +} + +func (s *ServiceUserModel) WithDisplayName(displayName string) *ServiceUserModel { + s.DisplayName = tfconfig.StringVariable(displayName) + return s +} + +func (s *ServiceUserModel) WithEmail(email string) *ServiceUserModel { + s.Email = tfconfig.StringVariable(email) + return s +} + +func (s *ServiceUserModel) WithEnableUnloadPhysicalTypeOptimization(enableUnloadPhysicalTypeOptimization bool) *ServiceUserModel { + s.EnableUnloadPhysicalTypeOptimization = tfconfig.BoolVariable(enableUnloadPhysicalTypeOptimization) + return s +} + +func (s *ServiceUserModel) WithEnableUnredactedQuerySyntaxError(enableUnredactedQuerySyntaxError bool) *ServiceUserModel { + s.EnableUnredactedQuerySyntaxError = tfconfig.BoolVariable(enableUnredactedQuerySyntaxError) + return s +} + +func (s *ServiceUserModel) WithErrorOnNondeterministicMerge(errorOnNondeterministicMerge bool) *ServiceUserModel { + s.ErrorOnNondeterministicMerge = tfconfig.BoolVariable(errorOnNondeterministicMerge) + return s +} + +func (s *ServiceUserModel) WithErrorOnNondeterministicUpdate(errorOnNondeterministicUpdate bool) *ServiceUserModel { + s.ErrorOnNondeterministicUpdate = tfconfig.BoolVariable(errorOnNondeterministicUpdate) + return s +} + +func (s *ServiceUserModel) WithFullyQualifiedName(fullyQualifiedName string) *ServiceUserModel { + s.FullyQualifiedName = tfconfig.StringVariable(fullyQualifiedName) + return s +} + +func (s *ServiceUserModel) WithGeographyOutputFormat(geographyOutputFormat string) *ServiceUserModel { + s.GeographyOutputFormat = tfconfig.StringVariable(geographyOutputFormat) + return s +} + +func (s *ServiceUserModel) WithGeometryOutputFormat(geometryOutputFormat string) *ServiceUserModel { + s.GeometryOutputFormat = tfconfig.StringVariable(geometryOutputFormat) + return s +} + +func (s *ServiceUserModel) WithJdbcTreatDecimalAsInt(jdbcTreatDecimalAsInt bool) *ServiceUserModel { + s.JdbcTreatDecimalAsInt = tfconfig.BoolVariable(jdbcTreatDecimalAsInt) + return s +} + +func (s *ServiceUserModel) WithJdbcTreatTimestampNtzAsUtc(jdbcTreatTimestampNtzAsUtc bool) *ServiceUserModel { + s.JdbcTreatTimestampNtzAsUtc = tfconfig.BoolVariable(jdbcTreatTimestampNtzAsUtc) + return s +} + +func (s *ServiceUserModel) WithJdbcUseSessionTimezone(jdbcUseSessionTimezone bool) *ServiceUserModel { + s.JdbcUseSessionTimezone = tfconfig.BoolVariable(jdbcUseSessionTimezone) + return s +} + +func (s *ServiceUserModel) WithJsonIndent(jsonIndent int) *ServiceUserModel { + s.JsonIndent = tfconfig.IntegerVariable(jsonIndent) + return s +} + +func (s *ServiceUserModel) WithLockTimeout(lockTimeout int) *ServiceUserModel { + s.LockTimeout = tfconfig.IntegerVariable(lockTimeout) + return s +} + +func (s *ServiceUserModel) WithLogLevel(logLevel string) *ServiceUserModel { + s.LogLevel = tfconfig.StringVariable(logLevel) + return s +} + +func (s *ServiceUserModel) WithLoginName(loginName string) *ServiceUserModel { + s.LoginName = tfconfig.StringVariable(loginName) + return s +} + +func (s *ServiceUserModel) WithMinsToUnlock(minsToUnlock int) *ServiceUserModel { + s.MinsToUnlock = tfconfig.IntegerVariable(minsToUnlock) + return s +} + +func (s *ServiceUserModel) WithMultiStatementCount(multiStatementCount int) *ServiceUserModel { + s.MultiStatementCount = tfconfig.IntegerVariable(multiStatementCount) + return s +} + +func (s *ServiceUserModel) WithName(name string) *ServiceUserModel { + s.Name = tfconfig.StringVariable(name) + return s +} + +func (s *ServiceUserModel) WithNetworkPolicy(networkPolicy string) *ServiceUserModel { + s.NetworkPolicy = tfconfig.StringVariable(networkPolicy) + return s +} + +func (s *ServiceUserModel) WithNoorderSequenceAsDefault(noorderSequenceAsDefault bool) *ServiceUserModel { + s.NoorderSequenceAsDefault = tfconfig.BoolVariable(noorderSequenceAsDefault) + return s +} + +func (s *ServiceUserModel) WithOdbcTreatDecimalAsInt(odbcTreatDecimalAsInt bool) *ServiceUserModel { + s.OdbcTreatDecimalAsInt = tfconfig.BoolVariable(odbcTreatDecimalAsInt) + return s +} + +func (s *ServiceUserModel) WithPreventUnloadToInternalStages(preventUnloadToInternalStages bool) *ServiceUserModel { + s.PreventUnloadToInternalStages = tfconfig.BoolVariable(preventUnloadToInternalStages) + return s +} + +func (s *ServiceUserModel) WithQueryTag(queryTag string) *ServiceUserModel { + s.QueryTag = tfconfig.StringVariable(queryTag) + return s +} + +func (s *ServiceUserModel) WithQuotedIdentifiersIgnoreCase(quotedIdentifiersIgnoreCase bool) *ServiceUserModel { + s.QuotedIdentifiersIgnoreCase = tfconfig.BoolVariable(quotedIdentifiersIgnoreCase) + return s +} + +func (s *ServiceUserModel) WithRowsPerResultset(rowsPerResultset int) *ServiceUserModel { + s.RowsPerResultset = tfconfig.IntegerVariable(rowsPerResultset) + return s +} + +func (s *ServiceUserModel) WithRsaPublicKey(rsaPublicKey string) *ServiceUserModel { + s.RsaPublicKey = tfconfig.StringVariable(rsaPublicKey) + return s +} + +func (s *ServiceUserModel) WithRsaPublicKey2(rsaPublicKey2 string) *ServiceUserModel { + s.RsaPublicKey2 = tfconfig.StringVariable(rsaPublicKey2) + return s +} + +func (s *ServiceUserModel) WithS3StageVpceDnsName(s3StageVpceDnsName string) *ServiceUserModel { + s.S3StageVpceDnsName = tfconfig.StringVariable(s3StageVpceDnsName) + return s +} + +func (s *ServiceUserModel) WithSearchPath(searchPath string) *ServiceUserModel { + s.SearchPath = tfconfig.StringVariable(searchPath) + return s +} + +func (s *ServiceUserModel) WithSimulatedDataSharingConsumer(simulatedDataSharingConsumer string) *ServiceUserModel { + s.SimulatedDataSharingConsumer = tfconfig.StringVariable(simulatedDataSharingConsumer) + return s +} + +func (s *ServiceUserModel) WithStatementQueuedTimeoutInSeconds(statementQueuedTimeoutInSeconds int) *ServiceUserModel { + s.StatementQueuedTimeoutInSeconds = tfconfig.IntegerVariable(statementQueuedTimeoutInSeconds) + return s +} + +func (s *ServiceUserModel) WithStatementTimeoutInSeconds(statementTimeoutInSeconds int) *ServiceUserModel { + s.StatementTimeoutInSeconds = tfconfig.IntegerVariable(statementTimeoutInSeconds) + return s +} + +func (s *ServiceUserModel) WithStrictJsonOutput(strictJsonOutput bool) *ServiceUserModel { + s.StrictJsonOutput = tfconfig.BoolVariable(strictJsonOutput) + return s +} + +func (s *ServiceUserModel) WithTimeInputFormat(timeInputFormat string) *ServiceUserModel { + s.TimeInputFormat = tfconfig.StringVariable(timeInputFormat) + return s +} + +func (s *ServiceUserModel) WithTimeOutputFormat(timeOutputFormat string) *ServiceUserModel { + s.TimeOutputFormat = tfconfig.StringVariable(timeOutputFormat) + return s +} + +func (s *ServiceUserModel) WithTimestampDayIsAlways24h(timestampDayIsAlways24h bool) *ServiceUserModel { + s.TimestampDayIsAlways24h = tfconfig.BoolVariable(timestampDayIsAlways24h) + return s +} + +func (s *ServiceUserModel) WithTimestampInputFormat(timestampInputFormat string) *ServiceUserModel { + s.TimestampInputFormat = tfconfig.StringVariable(timestampInputFormat) + return s +} + +func (s *ServiceUserModel) WithTimestampLtzOutputFormat(timestampLtzOutputFormat string) *ServiceUserModel { + s.TimestampLtzOutputFormat = tfconfig.StringVariable(timestampLtzOutputFormat) + return s +} + +func (s *ServiceUserModel) WithTimestampNtzOutputFormat(timestampNtzOutputFormat string) *ServiceUserModel { + s.TimestampNtzOutputFormat = tfconfig.StringVariable(timestampNtzOutputFormat) + return s +} + +func (s *ServiceUserModel) WithTimestampOutputFormat(timestampOutputFormat string) *ServiceUserModel { + s.TimestampOutputFormat = tfconfig.StringVariable(timestampOutputFormat) + return s +} + +func (s *ServiceUserModel) WithTimestampTypeMapping(timestampTypeMapping string) *ServiceUserModel { + s.TimestampTypeMapping = tfconfig.StringVariable(timestampTypeMapping) + return s +} + +func (s *ServiceUserModel) WithTimestampTzOutputFormat(timestampTzOutputFormat string) *ServiceUserModel { + s.TimestampTzOutputFormat = tfconfig.StringVariable(timestampTzOutputFormat) + return s +} + +func (s *ServiceUserModel) WithTimezone(timezone string) *ServiceUserModel { + s.Timezone = tfconfig.StringVariable(timezone) + return s +} + +func (s *ServiceUserModel) WithTraceLevel(traceLevel string) *ServiceUserModel { + s.TraceLevel = tfconfig.StringVariable(traceLevel) + return s +} + +func (s *ServiceUserModel) WithTransactionAbortOnError(transactionAbortOnError bool) *ServiceUserModel { + s.TransactionAbortOnError = tfconfig.BoolVariable(transactionAbortOnError) + return s +} + +func (s *ServiceUserModel) WithTransactionDefaultIsolationLevel(transactionDefaultIsolationLevel string) *ServiceUserModel { + s.TransactionDefaultIsolationLevel = tfconfig.StringVariable(transactionDefaultIsolationLevel) + return s +} + +func (s *ServiceUserModel) WithTwoDigitCenturyStart(twoDigitCenturyStart int) *ServiceUserModel { + s.TwoDigitCenturyStart = tfconfig.IntegerVariable(twoDigitCenturyStart) + return s +} + +func (s *ServiceUserModel) WithUnsupportedDdlAction(unsupportedDdlAction string) *ServiceUserModel { + s.UnsupportedDdlAction = tfconfig.StringVariable(unsupportedDdlAction) + return s +} + +func (s *ServiceUserModel) WithUseCachedResult(useCachedResult bool) *ServiceUserModel { + s.UseCachedResult = tfconfig.BoolVariable(useCachedResult) + return s +} + +func (s *ServiceUserModel) WithUserType(userType string) *ServiceUserModel { + s.UserType = tfconfig.StringVariable(userType) + return s +} + +func (s *ServiceUserModel) WithWeekOfYearPolicy(weekOfYearPolicy int) *ServiceUserModel { + s.WeekOfYearPolicy = tfconfig.IntegerVariable(weekOfYearPolicy) + return s +} + +func (s *ServiceUserModel) WithWeekStart(weekStart int) *ServiceUserModel { + s.WeekStart = tfconfig.IntegerVariable(weekStart) + return s +} + +////////////////////////////////////////// +// below it's possible to set any value // +////////////////////////////////////////// + +func (s *ServiceUserModel) WithAbortDetachedQueryValue(value tfconfig.Variable) *ServiceUserModel { + s.AbortDetachedQuery = value + return s +} + +func (s *ServiceUserModel) WithAutocommitValue(value tfconfig.Variable) *ServiceUserModel { + s.Autocommit = value + return s +} + +func (s *ServiceUserModel) WithBinaryInputFormatValue(value tfconfig.Variable) *ServiceUserModel { + s.BinaryInputFormat = value + return s +} + +func (s *ServiceUserModel) WithBinaryOutputFormatValue(value tfconfig.Variable) *ServiceUserModel { + s.BinaryOutputFormat = value + return s +} + +func (s *ServiceUserModel) WithClientMemoryLimitValue(value tfconfig.Variable) *ServiceUserModel { + s.ClientMemoryLimit = value + return s +} + +func (s *ServiceUserModel) WithClientMetadataRequestUseConnectionCtxValue(value tfconfig.Variable) *ServiceUserModel { + s.ClientMetadataRequestUseConnectionCtx = value + return s +} + +func (s *ServiceUserModel) WithClientPrefetchThreadsValue(value tfconfig.Variable) *ServiceUserModel { + s.ClientPrefetchThreads = value + return s +} + +func (s *ServiceUserModel) WithClientResultChunkSizeValue(value tfconfig.Variable) *ServiceUserModel { + s.ClientResultChunkSize = value + return s +} + +func (s *ServiceUserModel) WithClientResultColumnCaseInsensitiveValue(value tfconfig.Variable) *ServiceUserModel { + s.ClientResultColumnCaseInsensitive = value + return s +} + +func (s *ServiceUserModel) WithClientSessionKeepAliveValue(value tfconfig.Variable) *ServiceUserModel { + s.ClientSessionKeepAlive = value + return s +} + +func (s *ServiceUserModel) WithClientSessionKeepAliveHeartbeatFrequencyValue(value tfconfig.Variable) *ServiceUserModel { + s.ClientSessionKeepAliveHeartbeatFrequency = value + return s +} + +func (s *ServiceUserModel) WithClientTimestampTypeMappingValue(value tfconfig.Variable) *ServiceUserModel { + s.ClientTimestampTypeMapping = value + return s +} + +func (s *ServiceUserModel) WithCommentValue(value tfconfig.Variable) *ServiceUserModel { + s.Comment = value + return s +} + +func (s *ServiceUserModel) WithDateInputFormatValue(value tfconfig.Variable) *ServiceUserModel { + s.DateInputFormat = value + return s +} + +func (s *ServiceUserModel) WithDateOutputFormatValue(value tfconfig.Variable) *ServiceUserModel { + s.DateOutputFormat = value + return s +} + +func (s *ServiceUserModel) WithDaysToExpiryValue(value tfconfig.Variable) *ServiceUserModel { + s.DaysToExpiry = value + return s +} + +func (s *ServiceUserModel) WithDefaultNamespaceValue(value tfconfig.Variable) *ServiceUserModel { + s.DefaultNamespace = value + return s +} + +func (s *ServiceUserModel) WithDefaultRoleValue(value tfconfig.Variable) *ServiceUserModel { + s.DefaultRole = value + return s +} + +func (s *ServiceUserModel) WithDefaultSecondaryRolesOptionValue(value tfconfig.Variable) *ServiceUserModel { + s.DefaultSecondaryRolesOption = value + return s +} + +func (s *ServiceUserModel) WithDefaultWarehouseValue(value tfconfig.Variable) *ServiceUserModel { + s.DefaultWarehouse = value + return s +} + +func (s *ServiceUserModel) WithDisabledValue(value tfconfig.Variable) *ServiceUserModel { + s.Disabled = value + return s +} + +func (s *ServiceUserModel) WithDisplayNameValue(value tfconfig.Variable) *ServiceUserModel { + s.DisplayName = value + return s +} + +func (s *ServiceUserModel) WithEmailValue(value tfconfig.Variable) *ServiceUserModel { + s.Email = value + return s +} + +func (s *ServiceUserModel) WithEnableUnloadPhysicalTypeOptimizationValue(value tfconfig.Variable) *ServiceUserModel { + s.EnableUnloadPhysicalTypeOptimization = value + return s +} + +func (s *ServiceUserModel) WithEnableUnredactedQuerySyntaxErrorValue(value tfconfig.Variable) *ServiceUserModel { + s.EnableUnredactedQuerySyntaxError = value + return s +} + +func (s *ServiceUserModel) WithErrorOnNondeterministicMergeValue(value tfconfig.Variable) *ServiceUserModel { + s.ErrorOnNondeterministicMerge = value + return s +} + +func (s *ServiceUserModel) WithErrorOnNondeterministicUpdateValue(value tfconfig.Variable) *ServiceUserModel { + s.ErrorOnNondeterministicUpdate = value + return s +} + +func (s *ServiceUserModel) WithFullyQualifiedNameValue(value tfconfig.Variable) *ServiceUserModel { + s.FullyQualifiedName = value + return s +} + +func (s *ServiceUserModel) WithGeographyOutputFormatValue(value tfconfig.Variable) *ServiceUserModel { + s.GeographyOutputFormat = value + return s +} + +func (s *ServiceUserModel) WithGeometryOutputFormatValue(value tfconfig.Variable) *ServiceUserModel { + s.GeometryOutputFormat = value + return s +} + +func (s *ServiceUserModel) WithJdbcTreatDecimalAsIntValue(value tfconfig.Variable) *ServiceUserModel { + s.JdbcTreatDecimalAsInt = value + return s +} + +func (s *ServiceUserModel) WithJdbcTreatTimestampNtzAsUtcValue(value tfconfig.Variable) *ServiceUserModel { + s.JdbcTreatTimestampNtzAsUtc = value + return s +} + +func (s *ServiceUserModel) WithJdbcUseSessionTimezoneValue(value tfconfig.Variable) *ServiceUserModel { + s.JdbcUseSessionTimezone = value + return s +} + +func (s *ServiceUserModel) WithJsonIndentValue(value tfconfig.Variable) *ServiceUserModel { + s.JsonIndent = value + return s +} + +func (s *ServiceUserModel) WithLockTimeoutValue(value tfconfig.Variable) *ServiceUserModel { + s.LockTimeout = value + return s +} + +func (s *ServiceUserModel) WithLogLevelValue(value tfconfig.Variable) *ServiceUserModel { + s.LogLevel = value + return s +} + +func (s *ServiceUserModel) WithLoginNameValue(value tfconfig.Variable) *ServiceUserModel { + s.LoginName = value + return s +} + +func (s *ServiceUserModel) WithMinsToUnlockValue(value tfconfig.Variable) *ServiceUserModel { + s.MinsToUnlock = value + return s +} + +func (s *ServiceUserModel) WithMultiStatementCountValue(value tfconfig.Variable) *ServiceUserModel { + s.MultiStatementCount = value + return s +} + +func (s *ServiceUserModel) WithNameValue(value tfconfig.Variable) *ServiceUserModel { + s.Name = value + return s +} + +func (s *ServiceUserModel) WithNetworkPolicyValue(value tfconfig.Variable) *ServiceUserModel { + s.NetworkPolicy = value + return s +} + +func (s *ServiceUserModel) WithNoorderSequenceAsDefaultValue(value tfconfig.Variable) *ServiceUserModel { + s.NoorderSequenceAsDefault = value + return s +} + +func (s *ServiceUserModel) WithOdbcTreatDecimalAsIntValue(value tfconfig.Variable) *ServiceUserModel { + s.OdbcTreatDecimalAsInt = value + return s +} + +func (s *ServiceUserModel) WithPreventUnloadToInternalStagesValue(value tfconfig.Variable) *ServiceUserModel { + s.PreventUnloadToInternalStages = value + return s +} + +func (s *ServiceUserModel) WithQueryTagValue(value tfconfig.Variable) *ServiceUserModel { + s.QueryTag = value + return s +} + +func (s *ServiceUserModel) WithQuotedIdentifiersIgnoreCaseValue(value tfconfig.Variable) *ServiceUserModel { + s.QuotedIdentifiersIgnoreCase = value + return s +} + +func (s *ServiceUserModel) WithRowsPerResultsetValue(value tfconfig.Variable) *ServiceUserModel { + s.RowsPerResultset = value + return s +} + +func (s *ServiceUserModel) WithRsaPublicKeyValue(value tfconfig.Variable) *ServiceUserModel { + s.RsaPublicKey = value + return s +} + +func (s *ServiceUserModel) WithRsaPublicKey2Value(value tfconfig.Variable) *ServiceUserModel { + s.RsaPublicKey2 = value + return s +} + +func (s *ServiceUserModel) WithS3StageVpceDnsNameValue(value tfconfig.Variable) *ServiceUserModel { + s.S3StageVpceDnsName = value + return s +} + +func (s *ServiceUserModel) WithSearchPathValue(value tfconfig.Variable) *ServiceUserModel { + s.SearchPath = value + return s +} + +func (s *ServiceUserModel) WithSimulatedDataSharingConsumerValue(value tfconfig.Variable) *ServiceUserModel { + s.SimulatedDataSharingConsumer = value + return s +} + +func (s *ServiceUserModel) WithStatementQueuedTimeoutInSecondsValue(value tfconfig.Variable) *ServiceUserModel { + s.StatementQueuedTimeoutInSeconds = value + return s +} + +func (s *ServiceUserModel) WithStatementTimeoutInSecondsValue(value tfconfig.Variable) *ServiceUserModel { + s.StatementTimeoutInSeconds = value + return s +} + +func (s *ServiceUserModel) WithStrictJsonOutputValue(value tfconfig.Variable) *ServiceUserModel { + s.StrictJsonOutput = value + return s +} + +func (s *ServiceUserModel) WithTimeInputFormatValue(value tfconfig.Variable) *ServiceUserModel { + s.TimeInputFormat = value + return s +} + +func (s *ServiceUserModel) WithTimeOutputFormatValue(value tfconfig.Variable) *ServiceUserModel { + s.TimeOutputFormat = value + return s +} + +func (s *ServiceUserModel) WithTimestampDayIsAlways24hValue(value tfconfig.Variable) *ServiceUserModel { + s.TimestampDayIsAlways24h = value + return s +} + +func (s *ServiceUserModel) WithTimestampInputFormatValue(value tfconfig.Variable) *ServiceUserModel { + s.TimestampInputFormat = value + return s +} + +func (s *ServiceUserModel) WithTimestampLtzOutputFormatValue(value tfconfig.Variable) *ServiceUserModel { + s.TimestampLtzOutputFormat = value + return s +} + +func (s *ServiceUserModel) WithTimestampNtzOutputFormatValue(value tfconfig.Variable) *ServiceUserModel { + s.TimestampNtzOutputFormat = value + return s +} + +func (s *ServiceUserModel) WithTimestampOutputFormatValue(value tfconfig.Variable) *ServiceUserModel { + s.TimestampOutputFormat = value + return s +} + +func (s *ServiceUserModel) WithTimestampTypeMappingValue(value tfconfig.Variable) *ServiceUserModel { + s.TimestampTypeMapping = value + return s +} + +func (s *ServiceUserModel) WithTimestampTzOutputFormatValue(value tfconfig.Variable) *ServiceUserModel { + s.TimestampTzOutputFormat = value + return s +} + +func (s *ServiceUserModel) WithTimezoneValue(value tfconfig.Variable) *ServiceUserModel { + s.Timezone = value + return s +} + +func (s *ServiceUserModel) WithTraceLevelValue(value tfconfig.Variable) *ServiceUserModel { + s.TraceLevel = value + return s +} + +func (s *ServiceUserModel) WithTransactionAbortOnErrorValue(value tfconfig.Variable) *ServiceUserModel { + s.TransactionAbortOnError = value + return s +} + +func (s *ServiceUserModel) WithTransactionDefaultIsolationLevelValue(value tfconfig.Variable) *ServiceUserModel { + s.TransactionDefaultIsolationLevel = value + return s +} + +func (s *ServiceUserModel) WithTwoDigitCenturyStartValue(value tfconfig.Variable) *ServiceUserModel { + s.TwoDigitCenturyStart = value + return s +} + +func (s *ServiceUserModel) WithUnsupportedDdlActionValue(value tfconfig.Variable) *ServiceUserModel { + s.UnsupportedDdlAction = value + return s +} + +func (s *ServiceUserModel) WithUseCachedResultValue(value tfconfig.Variable) *ServiceUserModel { + s.UseCachedResult = value + return s +} + +func (s *ServiceUserModel) WithUserTypeValue(value tfconfig.Variable) *ServiceUserModel { + s.UserType = value + return s +} + +func (s *ServiceUserModel) WithWeekOfYearPolicyValue(value tfconfig.Variable) *ServiceUserModel { + s.WeekOfYearPolicy = value + return s +} + +func (s *ServiceUserModel) WithWeekStartValue(value tfconfig.Variable) *ServiceUserModel { + s.WeekStart = value + return s +} diff --git a/pkg/acceptance/check_destroy.go b/pkg/acceptance/check_destroy.go index a05da630c2..fcde35e9bf 100644 --- a/pkg/acceptance/check_destroy.go +++ b/pkg/acceptance/check_destroy.go @@ -122,6 +122,9 @@ var showByIdFunctions = map[resources.Resource]showByIdFunc{ resources.Function: func(ctx context.Context, client *sdk.Client, id sdk.ObjectIdentifier) error { return runShowById(ctx, id, client.Functions.ShowByID) }, + resources.LegacyServiceUser: func(ctx context.Context, client *sdk.Client, id sdk.ObjectIdentifier) error { + return runShowById(ctx, id, client.Users.ShowByID) + }, resources.ManagedAccount: func(ctx context.Context, client *sdk.Client, id sdk.ObjectIdentifier) error { return runShowById(ctx, id, client.ManagedAccounts.ShowByID) }, @@ -179,6 +182,9 @@ var showByIdFunctions = map[resources.Resource]showByIdFunc{ resources.Sequence: func(ctx context.Context, client *sdk.Client, id sdk.ObjectIdentifier) error { return runShowById(ctx, id, client.Sequences.ShowByID) }, + resources.ServiceUser: func(ctx context.Context, client *sdk.Client, id sdk.ObjectIdentifier) error { + return runShowById(ctx, id, client.Users.ShowByID) + }, resources.Share: func(ctx context.Context, client *sdk.Client, id sdk.ObjectIdentifier) error { return runShowById(ctx, id, client.Shares.ShowByID) }, diff --git a/pkg/acceptance/helpers/user_client.go b/pkg/acceptance/helpers/user_client.go index 6316ff26de..c64afcf723 100644 --- a/pkg/acceptance/helpers/user_client.go +++ b/pkg/acceptance/helpers/user_client.go @@ -2,7 +2,6 @@ package helpers import ( "context" - "fmt" "testing" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" @@ -30,6 +29,24 @@ func (c *UserClient) CreateUser(t *testing.T) (*sdk.User, func()) { return c.CreateUserWithOptions(t, c.ids.RandomAccountObjectIdentifier(), &sdk.CreateUserOptions{}) } +func (c *UserClient) CreateServiceUser(t *testing.T) (*sdk.User, func()) { + t.Helper() + return c.CreateUserWithOptions(t, c.ids.RandomAccountObjectIdentifier(), &sdk.CreateUserOptions{ + ObjectProperties: &sdk.UserObjectProperties{ + Type: sdk.Pointer(sdk.UserTypeService), + }, + }) +} + +func (c *UserClient) CreateLegacyServiceUser(t *testing.T) (*sdk.User, func()) { + t.Helper() + return c.CreateUserWithOptions(t, c.ids.RandomAccountObjectIdentifier(), &sdk.CreateUserOptions{ + ObjectProperties: &sdk.UserObjectProperties{ + Type: sdk.Pointer(sdk.UserTypeLegacyService), + }, + }) +} + func (c *UserClient) CreateUserWithPrefix(t *testing.T, prefix string) (*sdk.User, func()) { t.Helper() return c.CreateUserWithOptions(t, c.ids.RandomAccountObjectIdentifierWithPrefix(prefix), &sdk.CreateUserOptions{}) @@ -100,12 +117,33 @@ func (c *UserClient) SetDaysToExpiry(t *testing.T, id sdk.AccountObjectIdentifie require.NoError(t, err) } -func (c *UserClient) SetType(t *testing.T, id sdk.AccountObjectIdentifier, value string) { +func (c *UserClient) SetType(t *testing.T, id sdk.AccountObjectIdentifier, userType sdk.UserType) { + t.Helper() + ctx := context.Background() + + err := c.client().Alter(ctx, id, &sdk.AlterUserOptions{ + Set: &sdk.UserSet{ + ObjectProperties: &sdk.UserAlterObjectProperties{ + UserObjectProperties: sdk.UserObjectProperties{ + Type: sdk.Pointer(userType), + }, + }, + }, + }) + require.NoError(t, err) +} + +func (c *UserClient) UnsetType(t *testing.T, id sdk.AccountObjectIdentifier) { t.Helper() ctx := context.Background() - // TODO [SNOW-1645348]: use type from SDK - _, err := c.context.client.ExecForTests(ctx, fmt.Sprintf("ALTER USER %s SET TYPE = %s", id.FullyQualifiedName(), value)) + err := c.client().Alter(ctx, id, &sdk.AlterUserOptions{ + Unset: &sdk.UserUnset{ + ObjectProperties: &sdk.UserObjectPropertiesUnset{ + Type: sdk.Bool(true), + }, + }, + }) require.NoError(t, err) } diff --git a/pkg/datasources/users_acceptance_test.go b/pkg/datasources/users_acceptance_test.go index 7693e335cf..109761d3b5 100644 --- a/pkg/datasources/users_acceptance_test.go +++ b/pkg/datasources/users_acceptance_test.go @@ -20,7 +20,7 @@ import ( "github.com/hashicorp/terraform-plugin-testing/tfversion" ) -func TestAcc_Users_Complete(t *testing.T) { +func TestAcc_Users_PersonUser(t *testing.T) { id := acc.TestClient().Ids.RandomAccountObjectIdentifier() comment := random.Comment() @@ -60,11 +60,12 @@ func TestAcc_Users_Complete(t *testing.T) { CheckDestroy: acc.CheckDestroy(t, resources.User), Steps: []resource.TestStep{ { - Config: config.FromModel(t, userModelAllAttributes) + datasourceWithLike(), + Config: config.FromModel(t, userModelAllAttributes) + datasourceWithLike(resources.User), Check: assert.AssertThat(t, assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.#", "1")), resourceshowoutputassert.UsersDatasourceShowOutput(t, "snowflake_users.test"). HasName(id.Name()). + HasType(""). HasCreatedOnNotEmpty(). HasLoginName(fmt.Sprintf("%s_LOGIN", id.Name())). HasDisplayName("Display Name"). @@ -87,6 +88,7 @@ func TestAcc_Users_Complete(t *testing.T) { resourceparametersassert.UsersDatasourceParameters(t, "snowflake_users.test"). HasAllDefaults(), assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.name", id.Name())), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.type", "")), assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.comment", comment)), assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.display_name", "Display Name")), assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.login_name", fmt.Sprintf("%s_LOGIN", id.Name()))), @@ -120,11 +122,12 @@ func TestAcc_Users_Complete(t *testing.T) { ), }, { - Config: config.FromModel(t, userModelNoAttributes) + datasourceWithLike(), + Config: config.FromModel(t, userModelNoAttributes) + datasourceWithLike(resources.User), Check: assert.AssertThat(t, assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.#", "1")), resourceshowoutputassert.UsersDatasourceShowOutput(t, "snowflake_users.test"). HasName(id.Name()). + HasType(""). HasCreatedOnNotEmpty(). HasLoginName(strings.ToUpper(id.Name())). HasDisplayName(""). @@ -146,6 +149,7 @@ func TestAcc_Users_Complete(t *testing.T) { resourceparametersassert.UsersDatasourceParameters(t, "snowflake_users.test"). HasAllDefaults(), assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.name", id.Name())), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.type", "")), assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.comment", "")), assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.display_name", "")), assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.login_name", strings.ToUpper(id.Name()))), @@ -181,6 +185,323 @@ func TestAcc_Users_Complete(t *testing.T) { }) } +func TestAcc_Users_ServiceUser(t *testing.T) { + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() + + comment := random.Comment() + key1, key1Fp := random.GenerateRSAPublicKey(t) + key2, key2Fp := random.GenerateRSAPublicKey(t) + + userModelNoAttributes := model.ServiceUser("u", id.Name()) + userModelAllAttributes := model.ServiceUser("u", id.Name()). + WithLoginName(id.Name() + "_login"). + WithDisplayName("Display Name"). + WithEmail("fake@email.com"). + WithDisabled("false"). + WithDaysToExpiry(8). + WithMinsToUnlock(9). + WithDefaultWarehouse("some_warehouse"). + WithDefaultNamespace("some.namespace"). + WithDefaultRole("some_role"). + WithDefaultSecondaryRolesOptionEnum(sdk.SecondaryRolesOptionAll). + WithRsaPublicKey(key1). + WithRsaPublicKey2(key2). + WithComment(comment) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { acc.TestAccPreCheck(t) }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + CheckDestroy: acc.CheckDestroy(t, resources.ServiceUser), + Steps: []resource.TestStep{ + { + Config: config.FromModel(t, userModelAllAttributes) + datasourceWithLike(resources.ServiceUser), + Check: assert.AssertThat(t, + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.#", "1")), + resourceshowoutputassert.UsersDatasourceShowOutput(t, "snowflake_users.test"). + HasName(id.Name()). + HasType(string(sdk.UserTypeService)). + HasCreatedOnNotEmpty(). + HasLoginName(fmt.Sprintf("%s_LOGIN", id.Name())). + HasDisplayName("Display Name"). + HasFirstName(""). + HasLastName(""). + HasEmail("fake@email.com"). + HasMustChangePassword(false). + HasDisabled(false). + HasSnowflakeLock(false). + HasDaysToExpiryNotEmpty(). + HasMinsToUnlockNotEmpty(). + HasDefaultWarehouse("some_warehouse"). + HasDefaultNamespace("some.namespace"). + HasDefaultRole("some_role"). + HasDefaultSecondaryRoles(`["ALL"]`). + HasMinsToBypassMfa(""). + HasHasRsaPublicKey(true). + HasComment(comment). + HasHasMfa(false), + resourceparametersassert.UsersDatasourceParameters(t, "snowflake_users.test"). + HasAllDefaults(), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.name", id.Name())), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.type", string(sdk.UserTypeService))), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.display_name", "Display Name")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.login_name", fmt.Sprintf("%s_LOGIN", id.Name()))), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.first_name", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.middle_name", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.last_name", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.email", "fake@email.com")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.password", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.must_change_password", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.disabled", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.snowflake_lock", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.snowflake_support", "false")), + assert.Check(resource.TestCheckResourceAttrSet("data.snowflake_users.test", "users.0.describe_output.0.days_to_expiry")), + assert.Check(resource.TestCheckResourceAttrSet("data.snowflake_users.test", "users.0.describe_output.0.mins_to_unlock")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_warehouse", "some_warehouse")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_namespace", "some.namespace")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_role", "some_role")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_secondary_roles", `["ALL"]`)), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.ext_authn_duo", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.ext_authn_uid", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.mins_to_bypass_mfa", "0")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.mins_to_bypass_network_policy", "0")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key", key1)), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key_fp", "SHA256:"+key1Fp)), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key2", key2)), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key2_fp", "SHA256:"+key2Fp)), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.password_last_set_time", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.custom_landing_page_url", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.custom_landing_page_url_flush_next_ui_load", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.has_mfa", "false")), + ), + }, + { + Config: config.FromModel(t, userModelNoAttributes) + datasourceWithLike(resources.ServiceUser), + Check: assert.AssertThat(t, + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.#", "1")), + resourceshowoutputassert.UsersDatasourceShowOutput(t, "snowflake_users.test"). + HasName(id.Name()). + HasType(string(sdk.UserTypeService)). + HasCreatedOnNotEmpty(). + HasLoginName(strings.ToUpper(id.Name())). + HasDisplayName(""). + HasFirstName(""). + HasLastName(""). + HasEmail(""). + HasMustChangePassword(false). + HasDisabled(false). + HasSnowflakeLock(false). + HasDaysToExpiry(""). + HasMinsToUnlock(""). + HasDefaultWarehouse(""). + HasDefaultNamespace(""). + HasDefaultRole(""). + HasDefaultSecondaryRoles(""). + HasMinsToBypassMfa(""). + HasHasRsaPublicKey(false). + HasComment(""), + resourceparametersassert.UsersDatasourceParameters(t, "snowflake_users.test"). + HasAllDefaults(), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.name", id.Name())), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.comment", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.type", string(sdk.UserTypeService))), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.display_name", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.login_name", strings.ToUpper(id.Name()))), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.first_name", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.middle_name", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.last_name", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.email", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.password", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.must_change_password", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.disabled", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.snowflake_lock", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.snowflake_support", "false")), + assert.Check(resource.TestCheckResourceAttrSet("data.snowflake_users.test", "users.0.describe_output.0.days_to_expiry")), + assert.Check(resource.TestCheckResourceAttrSet("data.snowflake_users.test", "users.0.describe_output.0.mins_to_unlock")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_warehouse", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_namespace", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_role", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_secondary_roles", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.ext_authn_duo", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.ext_authn_uid", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.mins_to_bypass_mfa", "0")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.mins_to_bypass_network_policy", "0")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key_fp", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key2", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key2_fp", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.password_last_set_time", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.custom_landing_page_url", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.custom_landing_page_url_flush_next_ui_load", "false")), + ), + }, + }, + }) +} + +func TestAcc_Users_LegacyServiceUser(t *testing.T) { + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() + + comment := random.Comment() + pass := random.Password() + key1, key1Fp := random.GenerateRSAPublicKey(t) + key2, key2Fp := random.GenerateRSAPublicKey(t) + + userModelNoAttributes := model.LegacyServiceUser("u", id.Name()) + userModelAllAttributes := model.LegacyServiceUser("u", id.Name()). + WithPassword(pass). + WithLoginName(id.Name() + "_login"). + WithDisplayName("Display Name"). + WithEmail("fake@email.com"). + WithMustChangePassword("true"). + WithDisabled("false"). + WithDaysToExpiry(8). + WithMinsToUnlock(9). + WithDefaultWarehouse("some_warehouse"). + WithDefaultNamespace("some.namespace"). + WithDefaultRole("some_role"). + WithDefaultSecondaryRolesOptionEnum(sdk.SecondaryRolesOptionAll). + WithRsaPublicKey(key1). + WithRsaPublicKey2(key2). + WithComment(comment) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { acc.TestAccPreCheck(t) }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + CheckDestroy: acc.CheckDestroy(t, resources.LegacyServiceUser), + Steps: []resource.TestStep{ + { + Config: config.FromModel(t, userModelAllAttributes) + datasourceWithLike(resources.LegacyServiceUser), + Check: assert.AssertThat(t, + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.#", "1")), + resourceshowoutputassert.UsersDatasourceShowOutput(t, "snowflake_users.test"). + HasName(id.Name()). + HasType(string(sdk.UserTypeLegacyService)). + HasCreatedOnNotEmpty(). + HasLoginName(fmt.Sprintf("%s_LOGIN", id.Name())). + HasDisplayName("Display Name"). + HasFirstName(""). + HasLastName(""). + HasEmail("fake@email.com"). + HasMustChangePassword(true). + HasDisabled(false). + HasSnowflakeLock(false). + HasDaysToExpiryNotEmpty(). + HasMinsToUnlockNotEmpty(). + HasDefaultWarehouse("some_warehouse"). + HasDefaultNamespace("some.namespace"). + HasDefaultRole("some_role"). + HasDefaultSecondaryRoles(`["ALL"]`). + HasMinsToBypassMfa(""). + HasHasRsaPublicKey(true). + HasComment(comment). + HasHasMfa(false), + resourceparametersassert.UsersDatasourceParameters(t, "snowflake_users.test"). + HasAllDefaults(), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.name", id.Name())), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.type", string(sdk.UserTypeLegacyService))), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.display_name", "Display Name")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.login_name", fmt.Sprintf("%s_LOGIN", id.Name()))), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.first_name", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.middle_name", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.last_name", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.email", "fake@email.com")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.password", "********")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.must_change_password", "true")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.disabled", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.snowflake_lock", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.snowflake_support", "false")), + assert.Check(resource.TestCheckResourceAttrSet("data.snowflake_users.test", "users.0.describe_output.0.days_to_expiry")), + assert.Check(resource.TestCheckResourceAttrSet("data.snowflake_users.test", "users.0.describe_output.0.mins_to_unlock")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_warehouse", "some_warehouse")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_namespace", "some.namespace")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_role", "some_role")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_secondary_roles", `["ALL"]`)), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.ext_authn_duo", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.ext_authn_uid", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.mins_to_bypass_mfa", "0")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.mins_to_bypass_network_policy", "0")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key", key1)), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key_fp", "SHA256:"+key1Fp)), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key2", key2)), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key2_fp", "SHA256:"+key2Fp)), + assert.Check(resource.TestCheckResourceAttrSet("data.snowflake_users.test", "users.0.describe_output.0.password_last_set_time")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.custom_landing_page_url", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.custom_landing_page_url_flush_next_ui_load", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.has_mfa", "false")), + ), + }, + { + Config: config.FromModel(t, userModelNoAttributes) + datasourceWithLike(resources.LegacyServiceUser), + Check: assert.AssertThat(t, + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.#", "1")), + resourceshowoutputassert.UsersDatasourceShowOutput(t, "snowflake_users.test"). + HasName(id.Name()). + HasType(string(sdk.UserTypeLegacyService)). + HasCreatedOnNotEmpty(). + HasLoginName(strings.ToUpper(id.Name())). + HasDisplayName(""). + HasFirstName(""). + HasLastName(""). + HasEmail(""). + HasMustChangePassword(false). + HasDisabled(false). + HasSnowflakeLock(false). + HasDaysToExpiry(""). + HasMinsToUnlock(""). + HasDefaultWarehouse(""). + HasDefaultNamespace(""). + HasDefaultRole(""). + HasDefaultSecondaryRoles(""). + HasMinsToBypassMfa(""). + HasHasRsaPublicKey(false). + HasComment(""), + resourceparametersassert.UsersDatasourceParameters(t, "snowflake_users.test"). + HasAllDefaults(), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.name", id.Name())), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.type", string(sdk.UserTypeLegacyService))), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.comment", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.display_name", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.login_name", strings.ToUpper(id.Name()))), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.first_name", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.middle_name", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.last_name", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.email", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.password", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.must_change_password", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.disabled", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.snowflake_lock", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.snowflake_support", "false")), + assert.Check(resource.TestCheckResourceAttrSet("data.snowflake_users.test", "users.0.describe_output.0.days_to_expiry")), + assert.Check(resource.TestCheckResourceAttrSet("data.snowflake_users.test", "users.0.describe_output.0.mins_to_unlock")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_warehouse", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_namespace", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_role", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.default_secondary_roles", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.ext_authn_duo", "false")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.ext_authn_uid", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.mins_to_bypass_mfa", "0")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.mins_to_bypass_network_policy", "0")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key_fp", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key2", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.rsa_public_key2_fp", "")), + assert.Check(resource.TestCheckResourceAttrSet("data.snowflake_users.test", "users.0.describe_output.0.password_last_set_time")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.custom_landing_page_url", "")), + assert.Check(resource.TestCheckResourceAttr("data.snowflake_users.test", "users.0.describe_output.0.custom_landing_page_url_flush_next_ui_load", "false")), + ), + }, + }, + }) +} + func TestAcc_Users_DifferentFiltering(t *testing.T) { prefix := random.AlphaN(4) id := acc.TestClient().Ids.RandomAccountObjectIdentifierWithPrefix(prefix) @@ -223,12 +544,12 @@ func TestAcc_Users_DifferentFiltering(t *testing.T) { }) } -func datasourceWithLike() string { - return ` +func datasourceWithLike(resource resources.Resource) string { + return fmt.Sprintf(` data "snowflake_users" "test" { - like = snowflake_user.u.name + like = %s.u.name } -` + `, resource) } func datasourceWithLikeMultipleUsers() string { diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index b42f1abbf3..2c3abf9ce4 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -449,6 +449,7 @@ func getResources() map[string]*schema.Resource { "snowflake_grant_privileges_to_account_role": resources.GrantPrivilegesToAccountRole(), "snowflake_grant_privileges_to_database_role": resources.GrantPrivilegesToDatabaseRole(), "snowflake_grant_privileges_to_share": resources.GrantPrivilegesToShare(), + "snowflake_legacy_service_user": resources.LegacyServiceUser(), "snowflake_managed_account": resources.ManagedAccount(), "snowflake_masking_policy": resources.MaskingPolicy(), "snowflake_materialized_view": resources.MaterializedView(), @@ -472,6 +473,7 @@ func getResources() map[string]*schema.Resource { "snowflake_scim_integration": resources.SCIMIntegration(), "snowflake_secondary_database": resources.SecondaryDatabase(), "snowflake_sequence": resources.Sequence(), + "snowflake_service_user": resources.ServiceUser(), "snowflake_session_parameter": resources.SessionParameter(), "snowflake_share": resources.Share(), "snowflake_shared_database": resources.SharedDatabase(), diff --git a/pkg/provider/resources/resources.go b/pkg/provider/resources/resources.go index 9ebc3e8070..bf13a42ba9 100644 --- a/pkg/provider/resources/resources.go +++ b/pkg/provider/resources/resources.go @@ -22,6 +22,7 @@ const ( FailoverGroup resource = "snowflake_failover_group" FileFormat resource = "snowflake_file_format" Function resource = "snowflake_function" + LegacyServiceUser resource = "snowflake_legacy_service_user" ManagedAccount resource = "snowflake_managed_account" MaskingPolicy resource = "snowflake_masking_policy" MaterializedView resource = "snowflake_materialized_view" @@ -41,6 +42,7 @@ const ( ScimSecurityIntegration resource = "snowflake_scim_integration" SecondaryDatabase resource = "snowflake_secondary_database" Sequence resource = "snowflake_sequence" + ServiceUser resource = "snowflake_service_user" Share resource = "snowflake_share" SharedDatabase resource = "snowflake_shared_database" Stage resource = "snowflake_stage" diff --git a/pkg/resources/custom_diffs.go b/pkg/resources/custom_diffs.go index e685bae834..cb8c56a0b6 100644 --- a/pkg/resources/custom_diffs.go +++ b/pkg/resources/custom_diffs.go @@ -2,12 +2,15 @@ package resources import ( "context" + "errors" "fmt" "log" + "slices" "strconv" "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/collections" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/logging" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider/sdkv2enhancements" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" @@ -177,3 +180,18 @@ func ForceNewIfAllKeysAreNotSet(key string, keys ...string) schema.CustomizeDiff return allUnset }) } + +func RecreateWhenUserTypeChangedExternally(userType sdk.UserType) schema.CustomizeDiffFunc { + return func(_ context.Context, diff *schema.ResourceDiff, _ interface{}) error { + if n := diff.Get("user_type"); n != nil { + logging.DebugLogger.Printf("[DEBUG] new external value for user type %s\n", n.(string)) + if acceptableUserTypes, ok := sdk.AcceptableUserTypes[userType]; ok && !slices.Contains(acceptableUserTypes, strings.ToUpper(n.(string))) { + // we have to set here a value instead of just SetNewComputed + // because with empty value (default snowflake behavior for type) ForceNew fails + // because there are no changes (at least from the SDKv2 point of view) for "user_type" + return errors.Join(diff.SetNew("user_type", ""), diff.ForceNew("user_type")) + } + } + return nil + } +} diff --git a/pkg/resources/custom_diffs_test.go b/pkg/resources/custom_diffs_test.go index 19d5a338e9..b1e3772d6b 100644 --- a/pkg/resources/custom_diffs_test.go +++ b/pkg/resources/custom_diffs_test.go @@ -129,6 +129,20 @@ func createProviderWithValuePropertyAndCustomDiff(t *testing.T, valueSchema *sch } } +func createProviderWithNamedPropertyAndCustomDiff(t *testing.T, propertyName string, valueSchema *schema.Schema, customDiffFunc schema.CustomizeDiffFunc) *schema.Provider { + t.Helper() + return &schema.Provider{ + ResourcesMap: map[string]*schema.Resource{ + "test": { + Schema: map[string]*schema.Schema{ + propertyName: valueSchema, + }, + CustomizeDiff: customDiffFunc, + }, + }, + } +} + func calculateDiff(t *testing.T, providerConfig *schema.Provider, rawConfigValue cty.Value, stateValue map[string]any) *terraform.InstanceDiff { t.Helper() diff, err := providerConfig.ResourcesMap["test"].Diff( @@ -637,3 +651,138 @@ func TestForceNewIfAllKeysAreNotSet(t *testing.T) { }) } } + +func Test_RecreateWhenUserTypeChangedExternally(t *testing.T) { + tests := []struct { + name string + userType sdk.UserType + stateValue map[string]string + wantForceNew bool + }{ + { + name: "person - nothing in state", + userType: sdk.UserTypePerson, + stateValue: map[string]string{}, + wantForceNew: false, + }, + { + name: "person - person in state", + userType: sdk.UserTypePerson, + stateValue: map[string]string{ + "user_type": "PERSON", + }, + wantForceNew: false, + }, + { + name: "person - person in state lowercased", + userType: sdk.UserTypePerson, + stateValue: map[string]string{ + "user_type": "person", + }, + wantForceNew: false, + }, + { + name: "person - service in state", + userType: sdk.UserTypePerson, + stateValue: map[string]string{ + "user_type": "SERVICE", + }, + wantForceNew: true, + }, + { + name: "person - service in state lowercased", + userType: sdk.UserTypePerson, + stateValue: map[string]string{ + "user_type": "service", + }, + wantForceNew: true, + }, + { + name: "person - empty value in state", + userType: sdk.UserTypePerson, + stateValue: map[string]string{ + "user_type": "", + }, + wantForceNew: false, + }, + { + name: "person - garbage in state", + userType: sdk.UserTypePerson, + stateValue: map[string]string{ + "user_type": "garbage", + }, + wantForceNew: true, + }, + { + name: "service - nothing in state", + userType: sdk.UserTypeService, + stateValue: map[string]string{}, + wantForceNew: true, + }, + { + name: "service - service in state", + userType: sdk.UserTypeService, + stateValue: map[string]string{ + "user_type": "SERVICE", + }, + wantForceNew: false, + }, + { + name: "service - service in state lowercased", + userType: sdk.UserTypeService, + stateValue: map[string]string{ + "user_type": "service", + }, + wantForceNew: false, + }, + { + name: "service - person in state", + userType: sdk.UserTypeService, + stateValue: map[string]string{ + "user_type": "PERSON", + }, + wantForceNew: true, + }, + { + name: "service - person in state lowercased", + userType: sdk.UserTypeService, + stateValue: map[string]string{ + "user_type": "person", + }, + wantForceNew: true, + }, + { + name: "service - empty value in state", + userType: sdk.UserTypeService, + stateValue: map[string]string{ + "user_type": "", + }, + wantForceNew: true, + }, + { + name: "service - garbage in state", + userType: sdk.UserTypeService, + stateValue: map[string]string{ + "user_type": "garbage", + }, + wantForceNew: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + customDiff := resources.RecreateWhenUserTypeChangedExternally(tt.userType) + testProvider := createProviderWithNamedPropertyAndCustomDiff(t, "user_type", &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, customDiff) + diff := calculateDiffFromAttributes( + t, + testProvider, + tt.stateValue, + map[string]any{}, + ) + assert.Equal(t, tt.wantForceNew, diff.RequiresNew()) + }) + } +} diff --git a/pkg/resources/legacy_service_user_acceptance_test.go b/pkg/resources/legacy_service_user_acceptance_test.go new file mode 100644 index 0000000000..55c0033448 --- /dev/null +++ b/pkg/resources/legacy_service_user_acceptance_test.go @@ -0,0 +1,651 @@ +package resources_test + +import ( + "fmt" + "regexp" + "strings" + "testing" + + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + r "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/objectassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/objectparametersassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceparametersassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceshowoutputassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config/model" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/helpers/random" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testenvs" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider/resources" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/tfversion" +) + +func TestAcc_LegacyServiceUser_BasicFlows(t *testing.T) { + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() + id2 := acc.TestClient().Ids.RandomAccountObjectIdentifier() + + comment := random.Comment() + newComment := random.Comment() + + key1, _ := random.GenerateRSAPublicKey(t) + key2, _ := random.GenerateRSAPublicKey(t) + + pass := random.Password() + newPass := random.Password() + + userModelNoAttributes := model.LegacyServiceUser("w", id.Name()) + userModelNoAttributesRenamed := model.LegacyServiceUser("w", id2.Name()). + WithComment(newComment) + + userModelAllAttributes := model.LegacyServiceUser("w", id.Name()). + WithPassword(pass). + WithLoginName(id.Name() + "_login"). + WithDisplayName("Display Name"). + WithEmail("fake@email.com"). + WithMustChangePassword("true"). + WithDisabled("false"). + WithDaysToExpiry(8). + WithMinsToUnlock(9). + WithDefaultWarehouse("some_warehouse"). + WithDefaultNamespace("some.namespace"). + WithDefaultRole("some_role"). + WithDefaultSecondaryRolesOptionEnum(sdk.SecondaryRolesOptionAll). + WithRsaPublicKey(key1). + WithRsaPublicKey2(key2). + WithComment(comment) + + userModelAllAttributesChanged := func(loginName string) *model.LegacyServiceUserModel { + return model.LegacyServiceUser("w", id.Name()). + WithPassword(newPass). + WithLoginName(loginName). + WithDisplayName("New Display Name"). + WithEmail("fake@email.net"). + WithMustChangePassword("false"). + WithDisabled("true"). + WithDaysToExpiry(12). + WithMinsToUnlock(13). + WithDefaultWarehouse("other_warehouse"). + WithDefaultNamespace("one_part_namespace"). + WithDefaultRole("other_role"). + WithDefaultSecondaryRolesOptionEnum(sdk.SecondaryRolesOptionAll). + WithRsaPublicKey(key2). + WithRsaPublicKey2(key1). + WithComment(newComment) + } + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.LegacyServiceUser), + Steps: []resource.TestStep{ + // CREATE WITHOUT ATTRIBUTES + { + Config: config.FromModel(t, userModelNoAttributes), + Check: assert.AssertThat(t, + resourceassert.LegacyServiceUserResource(t, userModelNoAttributes.ResourceReference()). + HasNameString(id.Name()). + HasNoPassword(). + HasNoLoginName(). + HasNoDisplayName(). + HasNoEmail(). + HasMustChangePasswordString(r.BooleanDefault). + HasDisabledString(r.BooleanDefault). + HasNoDaysToExpiry(). + HasMinsToUnlockString(r.IntDefaultString). + HasNoDefaultWarehouse(). + HasNoDefaultNamespace(). + HasNoDefaultRole(). + HasDefaultSecondaryRolesOption(sdk.SecondaryRolesOptionDefault). + HasNoRsaPublicKey(). + HasNoRsaPublicKey2(). + HasNoComment(). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.UserShowOutput(t, userModelNoAttributes.ResourceReference()). + HasLoginName(strings.ToUpper(id.Name())). + HasDisplayName(id.Name()), + ), + }, + // RENAME AND CHANGE ONE PROP + { + Config: config.FromModel(t, userModelNoAttributesRenamed), + Check: assert.AssertThat(t, + resourceassert.LegacyServiceUserResource(t, userModelNoAttributes.ResourceReference()). + HasNameString(id2.Name()). + HasCommentString(newComment), + // default names stay the same + resourceshowoutputassert.UserShowOutput(t, userModelNoAttributes.ResourceReference()). + HasLoginName(strings.ToUpper(id.Name())). + HasDisplayName(id.Name()), + ), + }, + // IMPORT + { + ResourceName: userModelNoAttributesRenamed.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"password", "days_to_expiry", "mins_to_unlock", "login_name", "display_name", "disabled", "must_change_password"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedLegacyServiceUserResource(t, id2.Name()). + HasLoginNameString(strings.ToUpper(id.Name())). + HasDisplayNameString(id.Name()). + HasDisabled(false). + HasMustChangePassword(false), + ), + }, + // DESTROY + { + Config: config.FromModel(t, userModelNoAttributes), + Destroy: true, + }, + // CREATE WITH ALL ATTRIBUTES + { + Config: config.FromModel(t, userModelAllAttributes), + Check: assert.AssertThat(t, + resourceassert.LegacyServiceUserResource(t, userModelAllAttributes.ResourceReference()). + HasNameString(id.Name()). + HasPasswordString(pass). + HasLoginNameString(fmt.Sprintf("%s_login", id.Name())). + HasDisplayNameString("Display Name"). + HasEmailString("fake@email.com"). + HasMustChangePassword(true). + HasDisabled(false). + HasDaysToExpiryString("8"). + HasMinsToUnlockString("9"). + HasDefaultWarehouseString("some_warehouse"). + HasDefaultNamespaceString("some.namespace"). + HasDefaultRoleString("some_role"). + HasDefaultSecondaryRolesOption(sdk.SecondaryRolesOptionAll). + HasRsaPublicKeyString(key1). + HasRsaPublicKey2String(key2). + HasCommentString(comment). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + ), + }, + // CHANGE PROPERTIES + { + Config: config.FromModel(t, userModelAllAttributesChanged(id.Name()+"_other_login")), + Check: assert.AssertThat(t, + resourceassert.LegacyServiceUserResource(t, userModelAllAttributesChanged(id.Name()+"_other_login").ResourceReference()). + HasNameString(id.Name()). + HasPasswordString(newPass). + HasLoginNameString(fmt.Sprintf("%s_other_login", id.Name())). + HasDisplayNameString("New Display Name"). + HasEmailString("fake@email.net"). + HasMustChangePassword(false). + HasDisabled(true). + HasDaysToExpiryString("12"). + HasMinsToUnlockString("13"). + HasDefaultWarehouseString("other_warehouse"). + HasDefaultNamespaceString("one_part_namespace"). + HasDefaultRoleString("other_role"). + HasDefaultSecondaryRolesOption(sdk.SecondaryRolesOptionAll). + HasRsaPublicKeyString(key2). + HasRsaPublicKey2String(key1). + HasCommentString(newComment). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + ), + }, + // IMPORT + { + ResourceName: userModelAllAttributesChanged(id.Name() + "_other_login").ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"password", "days_to_expiry", "mins_to_unlock", "default_namespace", "login_name", "show_output.0.days_to_expiry"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedLegacyServiceUserResource(t, id.Name()). + HasDefaultNamespaceString("ONE_PART_NAMESPACE"). + HasLoginNameString(fmt.Sprintf("%s_OTHER_LOGIN", id.Name())), + ), + }, + // CHANGE PROP TO THE CURRENT SNOWFLAKE VALUE + { + PreConfig: func() { + acc.TestClient().User.SetLoginName(t, id, id.Name()+"_different_login") + }, + Config: config.FromModel(t, userModelAllAttributesChanged(id.Name()+"_different_login")), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // UNSET ALL + { + Config: config.FromModel(t, userModelNoAttributes), + Check: assert.AssertThat(t, + resourceassert.LegacyServiceUserResource(t, userModelNoAttributes.ResourceReference()). + HasNameString(id.Name()). + HasPasswordString(""). + HasLoginNameString(""). + HasDisplayNameString(""). + HasEmailString(""). + HasMustChangePasswordString(r.BooleanDefault). + HasDisabledString(r.BooleanDefault). + HasDaysToExpiryString("0"). + HasMinsToUnlockString(r.IntDefaultString). + HasDefaultWarehouseString(""). + HasDefaultNamespaceString(""). + HasDefaultRoleString(""). + HasDefaultSecondaryRolesOption(sdk.SecondaryRolesOptionDefault). + HasRsaPublicKeyString(""). + HasRsaPublicKey2String(""). + HasCommentString(""). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.UserShowOutput(t, userModelNoAttributes.ResourceReference()). + HasLoginName(strings.ToUpper(id.Name())). + HasDisplayName(""), + ), + }, + }, + }) +} + +func TestAcc_LegacyServiceUser_AllParameters(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) + networkPolicy, networkPolicyCleanup := acc.TestClient().NetworkPolicy.CreateNetworkPolicy(t) + t.Cleanup(networkPolicyCleanup) + + userId := acc.TestClient().Ids.RandomAccountObjectIdentifier() + + userModel := model.LegacyServiceUser("u", userId.Name()) + userModelWithAllParametersSet := model.LegacyServiceUser("u", userId.Name()). + WithAbortDetachedQuery(true). + WithAutocommit(false). + WithBinaryInputFormatEnum(sdk.BinaryInputFormatUTF8). + WithBinaryOutputFormatEnum(sdk.BinaryOutputFormatBase64). + WithClientMemoryLimit(1024). + WithClientMetadataRequestUseConnectionCtx(true). + WithClientPrefetchThreads(2). + WithClientResultChunkSize(48). + WithClientResultColumnCaseInsensitive(true). + WithClientSessionKeepAlive(true). + WithClientSessionKeepAliveHeartbeatFrequency(2400). + WithClientTimestampTypeMappingEnum(sdk.ClientTimestampTypeMappingNtz). + WithDateInputFormat("YYYY-MM-DD"). + WithDateOutputFormat("YY-MM-DD"). + WithEnableUnloadPhysicalTypeOptimization(false). + WithErrorOnNondeterministicMerge(false). + WithErrorOnNondeterministicUpdate(true). + WithGeographyOutputFormatEnum(sdk.GeographyOutputFormatWKB). + WithGeometryOutputFormatEnum(sdk.GeometryOutputFormatWKB). + WithJdbcTreatDecimalAsInt(false). + WithJdbcTreatTimestampNtzAsUtc(true). + WithJdbcUseSessionTimezone(false). + WithJsonIndent(4). + WithLockTimeout(21222). + WithLogLevelEnum(sdk.LogLevelError). + WithMultiStatementCount(0). + WithNoorderSequenceAsDefault(false). + WithOdbcTreatDecimalAsInt(true). + WithQueryTag("some_tag"). + WithQuotedIdentifiersIgnoreCase(true). + WithRowsPerResultset(2). + WithS3StageVpceDnsName("vpce-id.s3.region.vpce.amazonaws.com"). + WithSearchPath("$public, $current"). + WithSimulatedDataSharingConsumer("some_consumer"). + WithStatementQueuedTimeoutInSeconds(10). + WithStatementTimeoutInSeconds(10). + WithStrictJsonOutput(true). + WithTimestampDayIsAlways24h(true). + WithTimestampInputFormat("YYYY-MM-DD"). + WithTimestampLtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + WithTimestampNtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + WithTimestampOutputFormat("YYYY-MM-DD HH24:MI:SS"). + WithTimestampTypeMappingEnum(sdk.TimestampTypeMappingLtz). + WithTimestampTzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + WithTimezone("Europe/Warsaw"). + WithTimeInputFormat("HH24:MI"). + WithTimeOutputFormat("HH24:MI"). + WithTraceLevelEnum(sdk.TraceLevelOnEvent). + WithTransactionAbortOnError(true). + WithTransactionDefaultIsolationLevelEnum(sdk.TransactionDefaultIsolationLevelReadCommitted). + WithTwoDigitCenturyStart(1980). + WithUnsupportedDdlActionEnum(sdk.UnsupportedDDLActionFail). + WithUseCachedResult(false). + WithWeekOfYearPolicy(1). + WithWeekStart(1). + WithEnableUnredactedQuerySyntaxError(true). + WithNetworkPolicyId(networkPolicy.ID()). + WithPreventUnloadToInternalStages(true) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.LegacyServiceUser), + Steps: []resource.TestStep{ + // create with default values for all the parameters + { + Config: config.FromModel(t, userModel), + Check: assert.AssertThat(t, + objectparametersassert.UserParameters(t, userId). + HasAllDefaults(). + HasAllDefaultsExplicit(), + resourceparametersassert.UserResourceParameters(t, userModel.ResourceReference()). + HasAllDefaults(), + ), + }, + // import when no parameter set + { + ResourceName: userModel.ResourceReference(), + ImportState: true, + ImportStateCheck: assert.AssertThatImport(t, + resourceparametersassert.ImportedUserResourceParameters(t, userId.Name()). + HasAllDefaults(), + ), + }, + // set all parameters + { + Config: config.FromModel(t, userModelWithAllParametersSet), + Check: assert.AssertThat(t, + objectparametersassert.UserParameters(t, userId). + HasAbortDetachedQuery(true). + HasAutocommit(false). + HasBinaryInputFormat(sdk.BinaryInputFormatUTF8). + HasBinaryOutputFormat(sdk.BinaryOutputFormatBase64). + HasClientMemoryLimit(1024). + HasClientMetadataRequestUseConnectionCtx(true). + HasClientPrefetchThreads(2). + HasClientResultChunkSize(48). + HasClientResultColumnCaseInsensitive(true). + HasClientSessionKeepAlive(true). + HasClientSessionKeepAliveHeartbeatFrequency(2400). + HasClientTimestampTypeMapping(sdk.ClientTimestampTypeMappingNtz). + HasDateInputFormat("YYYY-MM-DD"). + HasDateOutputFormat("YY-MM-DD"). + HasEnableUnloadPhysicalTypeOptimization(false). + HasErrorOnNondeterministicMerge(false). + HasErrorOnNondeterministicUpdate(true). + HasGeographyOutputFormat(sdk.GeographyOutputFormatWKB). + HasGeometryOutputFormat(sdk.GeometryOutputFormatWKB). + HasJdbcTreatDecimalAsInt(false). + HasJdbcTreatTimestampNtzAsUtc(true). + HasJdbcUseSessionTimezone(false). + HasJsonIndent(4). + HasLockTimeout(21222). + HasLogLevel(sdk.LogLevelError). + HasMultiStatementCount(0). + HasNoorderSequenceAsDefault(false). + HasOdbcTreatDecimalAsInt(true). + HasQueryTag("some_tag"). + HasQuotedIdentifiersIgnoreCase(true). + HasRowsPerResultset(2). + HasS3StageVpceDnsName("vpce-id.s3.region.vpce.amazonaws.com"). + HasSearchPath("$public, $current"). + HasSimulatedDataSharingConsumer("some_consumer"). + HasStatementQueuedTimeoutInSeconds(10). + HasStatementTimeoutInSeconds(10). + HasStrictJsonOutput(true). + HasTimestampDayIsAlways24h(true). + HasTimestampInputFormat("YYYY-MM-DD"). + HasTimestampLtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampNtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampTypeMapping(sdk.TimestampTypeMappingLtz). + HasTimestampTzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimezone("Europe/Warsaw"). + HasTimeInputFormat("HH24:MI"). + HasTimeOutputFormat("HH24:MI"). + HasTraceLevel(sdk.TraceLevelOnEvent). + HasTransactionAbortOnError(true). + HasTransactionDefaultIsolationLevel(sdk.TransactionDefaultIsolationLevelReadCommitted). + HasTwoDigitCenturyStart(1980). + HasUnsupportedDdlAction(sdk.UnsupportedDDLActionFail). + HasUseCachedResult(false). + HasWeekOfYearPolicy(1). + HasWeekStart(1). + HasEnableUnredactedQuerySyntaxError(true). + HasNetworkPolicy(networkPolicy.ID().Name()). + HasPreventUnloadToInternalStages(true), + resourceparametersassert.UserResourceParameters(t, userModelWithAllParametersSet.ResourceReference()). + HasAbortDetachedQuery(true). + HasAutocommit(false). + HasBinaryInputFormat(sdk.BinaryInputFormatUTF8). + HasBinaryOutputFormat(sdk.BinaryOutputFormatBase64). + HasClientMemoryLimit(1024). + HasClientMetadataRequestUseConnectionCtx(true). + HasClientPrefetchThreads(2). + HasClientResultChunkSize(48). + HasClientResultColumnCaseInsensitive(true). + HasClientSessionKeepAlive(true). + HasClientSessionKeepAliveHeartbeatFrequency(2400). + HasClientTimestampTypeMapping(sdk.ClientTimestampTypeMappingNtz). + HasDateInputFormat("YYYY-MM-DD"). + HasDateOutputFormat("YY-MM-DD"). + HasEnableUnloadPhysicalTypeOptimization(false). + HasErrorOnNondeterministicMerge(false). + HasErrorOnNondeterministicUpdate(true). + HasGeographyOutputFormat(sdk.GeographyOutputFormatWKB). + HasGeometryOutputFormat(sdk.GeometryOutputFormatWKB). + HasJdbcTreatDecimalAsInt(false). + HasJdbcTreatTimestampNtzAsUtc(true). + HasJdbcUseSessionTimezone(false). + HasJsonIndent(4). + HasLockTimeout(21222). + HasLogLevel(sdk.LogLevelError). + HasMultiStatementCount(0). + HasNoorderSequenceAsDefault(false). + HasOdbcTreatDecimalAsInt(true). + HasQueryTag("some_tag"). + HasQuotedIdentifiersIgnoreCase(true). + HasRowsPerResultset(2). + HasS3StageVpceDnsName("vpce-id.s3.region.vpce.amazonaws.com"). + HasSearchPath("$public, $current"). + HasSimulatedDataSharingConsumer("some_consumer"). + HasStatementQueuedTimeoutInSeconds(10). + HasStatementTimeoutInSeconds(10). + HasStrictJsonOutput(true). + HasTimestampDayIsAlways24h(true). + HasTimestampInputFormat("YYYY-MM-DD"). + HasTimestampLtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampNtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampTypeMapping(sdk.TimestampTypeMappingLtz). + HasTimestampTzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimezone("Europe/Warsaw"). + HasTimeInputFormat("HH24:MI"). + HasTimeOutputFormat("HH24:MI"). + HasTraceLevel(sdk.TraceLevelOnEvent). + HasTransactionAbortOnError(true). + HasTransactionDefaultIsolationLevel(sdk.TransactionDefaultIsolationLevelReadCommitted). + HasTwoDigitCenturyStart(1980). + HasUnsupportedDdlAction(sdk.UnsupportedDDLActionFail). + HasUseCachedResult(false). + HasWeekOfYearPolicy(1). + HasWeekStart(1). + HasEnableUnredactedQuerySyntaxError(true). + HasNetworkPolicy(networkPolicy.ID().Name()). + HasPreventUnloadToInternalStages(true), + ), + }, + // import when all parameters set + { + ResourceName: userModelWithAllParametersSet.ResourceReference(), + ImportState: true, + ImportStateCheck: assert.AssertThatImport(t, + resourceparametersassert.ImportedUserResourceParameters(t, userId.Name()). + HasAbortDetachedQuery(true). + HasAutocommit(false). + HasBinaryInputFormat(sdk.BinaryInputFormatUTF8). + HasBinaryOutputFormat(sdk.BinaryOutputFormatBase64). + HasClientMemoryLimit(1024). + HasClientMetadataRequestUseConnectionCtx(true). + HasClientPrefetchThreads(2). + HasClientResultChunkSize(48). + HasClientResultColumnCaseInsensitive(true). + HasClientSessionKeepAlive(true). + HasClientSessionKeepAliveHeartbeatFrequency(2400). + HasClientTimestampTypeMapping(sdk.ClientTimestampTypeMappingNtz). + HasDateInputFormat("YYYY-MM-DD"). + HasDateOutputFormat("YY-MM-DD"). + HasEnableUnloadPhysicalTypeOptimization(false). + HasErrorOnNondeterministicMerge(false). + HasErrorOnNondeterministicUpdate(true). + HasGeographyOutputFormat(sdk.GeographyOutputFormatWKB). + HasGeometryOutputFormat(sdk.GeometryOutputFormatWKB). + HasJdbcTreatDecimalAsInt(false). + HasJdbcTreatTimestampNtzAsUtc(true). + HasJdbcUseSessionTimezone(false). + HasJsonIndent(4). + HasLockTimeout(21222). + HasLogLevel(sdk.LogLevelError). + HasMultiStatementCount(0). + HasNoorderSequenceAsDefault(false). + HasOdbcTreatDecimalAsInt(true). + HasQueryTag("some_tag"). + HasQuotedIdentifiersIgnoreCase(true). + HasRowsPerResultset(2). + HasS3StageVpceDnsName("vpce-id.s3.region.vpce.amazonaws.com"). + HasSearchPath("$public, $current"). + HasSimulatedDataSharingConsumer("some_consumer"). + HasStatementQueuedTimeoutInSeconds(10). + HasStatementTimeoutInSeconds(10). + HasStrictJsonOutput(true). + HasTimestampDayIsAlways24h(true). + HasTimestampInputFormat("YYYY-MM-DD"). + HasTimestampLtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampNtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampTypeMapping(sdk.TimestampTypeMappingLtz). + HasTimestampTzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimezone("Europe/Warsaw"). + HasTimeInputFormat("HH24:MI"). + HasTimeOutputFormat("HH24:MI"). + HasTraceLevel(sdk.TraceLevelOnEvent). + HasTransactionAbortOnError(true). + HasTransactionDefaultIsolationLevel(sdk.TransactionDefaultIsolationLevelReadCommitted). + HasTwoDigitCenturyStart(1980). + HasUnsupportedDdlAction(sdk.UnsupportedDDLActionFail). + HasUseCachedResult(false). + HasWeekOfYearPolicy(1). + HasWeekStart(1). + HasEnableUnredactedQuerySyntaxError(true). + HasNetworkPolicy(networkPolicy.ID().Name()). + HasPreventUnloadToInternalStages(true), + ), + }, + // unset all the parameters + { + Config: config.FromModel(t, userModel), + Check: assert.AssertThat(t, + objectparametersassert.UserParameters(t, userId). + HasAllDefaults(). + HasAllDefaultsExplicit(), + resourceparametersassert.UserResourceParameters(t, userModel.ResourceReference()). + HasAllDefaults(), + ), + }, + }, + }) +} + +func TestAcc_LegacyServiceUser_handleExternalTypeChange(t *testing.T) { + userId := acc.TestClient().Ids.RandomAccountObjectIdentifier() + + userModel := model.LegacyServiceUserWithDefaultMeta(userId.Name()) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.LegacyServiceUser), + Steps: []resource.TestStep{ + { + Config: config.FromModel(t, userModel), + Check: assert.AssertThat(t, + resourceassert.UserResource(t, userModel.ResourceReference()).HasNameString(userId.Name()).HasUserTypeString("LEGACY_SERVICE"), + resourceshowoutputassert.UserShowOutput(t, userModel.ResourceReference()).HasType("LEGACY_SERVICE"), + ), + }, + { + PreConfig: func() { + acc.TestClient().User.SetType(t, userId, sdk.UserTypeService) + objectassert.User(t, userId).HasType(string(sdk.UserTypeService)) + }, + Config: config.FromModel(t, userModel), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(userModel.ResourceReference(), plancheck.ResourceActionDestroyBeforeCreate), + }, + }, + Check: assert.AssertThat(t, + resourceassert.UserResource(t, userModel.ResourceReference()).HasNameString(userId.Name()).HasUserTypeString("LEGACY_SERVICE"), + resourceshowoutputassert.UserShowOutput(t, userModel.ResourceReference()).HasType("LEGACY_SERVICE"), + ), + }, + { + PreConfig: func() { + acc.TestClient().User.UnsetType(t, userId) + objectassert.User(t, userId).HasType("") + }, + Config: config.FromModel(t, userModel), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(userModel.ResourceReference(), plancheck.ResourceActionDestroyBeforeCreate), + }, + }, + Check: assert.AssertThat(t, + resourceassert.UserResource(t, userModel.ResourceReference()).HasNameString(userId.Name()).HasUserTypeString("LEGACY_SERVICE"), + resourceshowoutputassert.UserShowOutput(t, userModel.ResourceReference()).HasType("LEGACY_SERVICE"), + ), + }, + }, + }) +} + +func TestAcc_LegacyServiceUser_setIncompatibleAttributes(t *testing.T) { + userId := acc.TestClient().Ids.RandomAccountObjectIdentifier() + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.LegacyServiceUser), + Steps: []resource.TestStep{ + { + Config: legacyServiceUserConfigWithIncompatibleAttribute(userId, "first_name", random.AlphaN(6)), + ExpectError: regexp.MustCompile("An argument named \"first_name\" is not expected here"), + }, + { + Config: legacyServiceUserConfigWithIncompatibleAttribute(userId, "middle_name", random.AlphaN(6)), + ExpectError: regexp.MustCompile("An argument named \"middle_name\" is not expected here"), + }, + { + Config: legacyServiceUserConfigWithIncompatibleAttribute(userId, "last_name", random.AlphaN(6)), + ExpectError: regexp.MustCompile("An argument named \"last_name\" is not expected here"), + }, + { + Config: legacyServiceUserConfigWithIncompatibleAttribute(userId, "mins_to_bypass_mfa", random.AlphaN(6)), + ExpectError: regexp.MustCompile("An argument named \"mins_to_bypass_mfa\" is not expected here"), + }, + { + Config: legacyServiceUserConfigWithIncompatibleAttribute(userId, "disable_mfa", random.AlphaN(6)), + ExpectError: regexp.MustCompile("An argument named \"disable_mfa\" is not expected here"), + }, + }, + }) +} + +func legacyServiceUserConfigWithIncompatibleAttribute(userId sdk.AccountObjectIdentifier, key string, value string) string { + return fmt.Sprintf(` + resource "snowflake_legacy_service_user" "test" { + name = %s + %s = "%s" + } + `, userId.FullyQualifiedName(), key, value) +} diff --git a/pkg/resources/service_user_acceptance_test.go b/pkg/resources/service_user_acceptance_test.go new file mode 100644 index 0000000000..a314e774fd --- /dev/null +++ b/pkg/resources/service_user_acceptance_test.go @@ -0,0 +1,643 @@ +package resources_test + +import ( + "fmt" + "regexp" + "strings" + "testing" + + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + r "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/objectassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/objectparametersassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceparametersassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceshowoutputassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config/model" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/helpers/random" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testenvs" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider/resources" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/tfversion" +) + +func TestAcc_ServiceUser_BasicFlows(t *testing.T) { + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() + id2 := acc.TestClient().Ids.RandomAccountObjectIdentifier() + + comment := random.Comment() + newComment := random.Comment() + + key1, _ := random.GenerateRSAPublicKey(t) + key2, _ := random.GenerateRSAPublicKey(t) + + userModelNoAttributes := model.ServiceUser("w", id.Name()) + userModelNoAttributesRenamed := model.ServiceUser("w", id2.Name()). + WithComment(newComment) + + userModelAllAttributes := model.ServiceUser("w", id.Name()). + WithLoginName(id.Name() + "_login"). + WithDisplayName("Display Name"). + WithEmail("fake@email.com"). + WithDisabled("false"). + WithDaysToExpiry(8). + WithMinsToUnlock(9). + WithDefaultWarehouse("some_warehouse"). + WithDefaultNamespace("some.namespace"). + WithDefaultRole("some_role"). + WithDefaultSecondaryRolesOptionEnum(sdk.SecondaryRolesOptionAll). + WithRsaPublicKey(key1). + WithRsaPublicKey2(key2). + WithComment(comment) + + userModelAllAttributesChanged := func(loginName string) *model.ServiceUserModel { + return model.ServiceUser("w", id.Name()). + WithLoginName(loginName). + WithDisplayName("New Display Name"). + WithEmail("fake@email.net"). + WithDisabled("true"). + WithDaysToExpiry(12). + WithMinsToUnlock(13). + WithDefaultWarehouse("other_warehouse"). + WithDefaultNamespace("one_part_namespace"). + WithDefaultRole("other_role"). + WithDefaultSecondaryRolesOptionEnum(sdk.SecondaryRolesOptionAll). + WithRsaPublicKey(key2). + WithRsaPublicKey2(key1). + WithComment(newComment) + } + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.ServiceUser), + Steps: []resource.TestStep{ + // CREATE WITHOUT ATTRIBUTES + { + Config: config.FromModel(t, userModelNoAttributes), + Check: assert.AssertThat(t, + resourceassert.ServiceUserResource(t, userModelNoAttributes.ResourceReference()). + HasNameString(id.Name()). + HasNoLoginName(). + HasNoDisplayName(). + HasNoEmail(). + HasDisabledString(r.BooleanDefault). + HasNoDaysToExpiry(). + HasMinsToUnlockString(r.IntDefaultString). + HasNoDefaultWarehouse(). + HasNoDefaultNamespace(). + HasNoDefaultRole(). + HasDefaultSecondaryRolesOption(sdk.SecondaryRolesOptionDefault). + HasNoRsaPublicKey(). + HasNoRsaPublicKey2(). + HasNoComment(). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.UserShowOutput(t, userModelNoAttributes.ResourceReference()). + HasLoginName(strings.ToUpper(id.Name())). + HasDisplayName(id.Name()), + ), + }, + // RENAME AND CHANGE ONE PROP + { + Config: config.FromModel(t, userModelNoAttributesRenamed), + Check: assert.AssertThat(t, + resourceassert.ServiceUserResource(t, userModelNoAttributes.ResourceReference()). + HasNameString(id2.Name()). + HasCommentString(newComment), + // default names stay the same + resourceshowoutputassert.UserShowOutput(t, userModelNoAttributes.ResourceReference()). + HasLoginName(strings.ToUpper(id.Name())). + HasDisplayName(id.Name()), + ), + }, + // IMPORT + { + ResourceName: userModelNoAttributesRenamed.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"days_to_expiry", "mins_to_unlock", "mins_to_bypass_mfa", "login_name", "display_name", "disabled"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedServiceUserResource(t, id2.Name()). + HasLoginNameString(strings.ToUpper(id.Name())). + HasDisplayNameString(id.Name()). + HasDisabled(false), + ), + }, + // DESTROY + { + Config: config.FromModel(t, userModelNoAttributes), + Destroy: true, + }, + // CREATE WITH ALL ATTRIBUTES + { + Config: config.FromModel(t, userModelAllAttributes), + Check: assert.AssertThat(t, + resourceassert.ServiceUserResource(t, userModelAllAttributes.ResourceReference()). + HasNameString(id.Name()). + HasLoginNameString(fmt.Sprintf("%s_login", id.Name())). + HasDisplayNameString("Display Name"). + HasEmailString("fake@email.com"). + HasDisabled(false). + HasDaysToExpiryString("8"). + HasMinsToUnlockString("9"). + HasDefaultWarehouseString("some_warehouse"). + HasDefaultNamespaceString("some.namespace"). + HasDefaultRoleString("some_role"). + HasDefaultSecondaryRolesOption(sdk.SecondaryRolesOptionAll). + HasRsaPublicKeyString(key1). + HasRsaPublicKey2String(key2). + HasCommentString(comment). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + ), + }, + // CHANGE PROPERTIES + { + Config: config.FromModel(t, userModelAllAttributesChanged(id.Name()+"_other_login")), + Check: assert.AssertThat(t, + resourceassert.ServiceUserResource(t, userModelAllAttributesChanged(id.Name()+"_other_login").ResourceReference()). + HasNameString(id.Name()). + HasLoginNameString(fmt.Sprintf("%s_other_login", id.Name())). + HasDisplayNameString("New Display Name"). + HasEmailString("fake@email.net"). + HasDisabled(true). + HasDaysToExpiryString("12"). + HasMinsToUnlockString("13"). + HasDefaultWarehouseString("other_warehouse"). + HasDefaultNamespaceString("one_part_namespace"). + HasDefaultRoleString("other_role"). + HasDefaultSecondaryRolesOption(sdk.SecondaryRolesOptionAll). + HasRsaPublicKeyString(key2). + HasRsaPublicKey2String(key1). + HasCommentString(newComment). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + ), + }, + // IMPORT + { + ResourceName: userModelAllAttributesChanged(id.Name() + "_other_login").ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"days_to_expiry", "mins_to_unlock", "default_namespace", "login_name", "show_output.0.days_to_expiry"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedServiceUserResource(t, id.Name()). + HasDefaultNamespaceString("ONE_PART_NAMESPACE"). + HasLoginNameString(fmt.Sprintf("%s_OTHER_LOGIN", id.Name())), + ), + }, + // CHANGE PROP TO THE CURRENT SNOWFLAKE VALUE + { + PreConfig: func() { + acc.TestClient().User.SetLoginName(t, id, id.Name()+"_different_login") + }, + Config: config.FromModel(t, userModelAllAttributesChanged(id.Name()+"_different_login")), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // UNSET ALL + { + Config: config.FromModel(t, userModelNoAttributes), + Check: assert.AssertThat(t, + resourceassert.ServiceUserResource(t, userModelNoAttributes.ResourceReference()). + HasNameString(id.Name()). + HasLoginNameString(""). + HasDisplayNameString(""). + HasEmailString(""). + HasDisabledString(r.BooleanDefault). + HasDaysToExpiryString("0"). + HasMinsToUnlockString(r.IntDefaultString). + HasDefaultWarehouseString(""). + HasDefaultNamespaceString(""). + HasDefaultRoleString(""). + HasDefaultSecondaryRolesOption(sdk.SecondaryRolesOptionDefault). + HasRsaPublicKeyString(""). + HasRsaPublicKey2String(""). + HasCommentString(""). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.UserShowOutput(t, userModelNoAttributes.ResourceReference()). + HasLoginName(strings.ToUpper(id.Name())). + HasDisplayName(""), + ), + }, + }, + }) +} + +func TestAcc_ServiceUser_AllParameters(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) + networkPolicy, networkPolicyCleanup := acc.TestClient().NetworkPolicy.CreateNetworkPolicy(t) + t.Cleanup(networkPolicyCleanup) + + userId := acc.TestClient().Ids.RandomAccountObjectIdentifier() + + userModel := model.ServiceUser("u", userId.Name()) + userModelWithAllParametersSet := model.ServiceUser("u", userId.Name()). + WithAbortDetachedQuery(true). + WithAutocommit(false). + WithBinaryInputFormatEnum(sdk.BinaryInputFormatUTF8). + WithBinaryOutputFormatEnum(sdk.BinaryOutputFormatBase64). + WithClientMemoryLimit(1024). + WithClientMetadataRequestUseConnectionCtx(true). + WithClientPrefetchThreads(2). + WithClientResultChunkSize(48). + WithClientResultColumnCaseInsensitive(true). + WithClientSessionKeepAlive(true). + WithClientSessionKeepAliveHeartbeatFrequency(2400). + WithClientTimestampTypeMappingEnum(sdk.ClientTimestampTypeMappingNtz). + WithDateInputFormat("YYYY-MM-DD"). + WithDateOutputFormat("YY-MM-DD"). + WithEnableUnloadPhysicalTypeOptimization(false). + WithErrorOnNondeterministicMerge(false). + WithErrorOnNondeterministicUpdate(true). + WithGeographyOutputFormatEnum(sdk.GeographyOutputFormatWKB). + WithGeometryOutputFormatEnum(sdk.GeometryOutputFormatWKB). + WithJdbcTreatDecimalAsInt(false). + WithJdbcTreatTimestampNtzAsUtc(true). + WithJdbcUseSessionTimezone(false). + WithJsonIndent(4). + WithLockTimeout(21222). + WithLogLevelEnum(sdk.LogLevelError). + WithMultiStatementCount(0). + WithNoorderSequenceAsDefault(false). + WithOdbcTreatDecimalAsInt(true). + WithQueryTag("some_tag"). + WithQuotedIdentifiersIgnoreCase(true). + WithRowsPerResultset(2). + WithS3StageVpceDnsName("vpce-id.s3.region.vpce.amazonaws.com"). + WithSearchPath("$public, $current"). + WithSimulatedDataSharingConsumer("some_consumer"). + WithStatementQueuedTimeoutInSeconds(10). + WithStatementTimeoutInSeconds(10). + WithStrictJsonOutput(true). + WithTimestampDayIsAlways24h(true). + WithTimestampInputFormat("YYYY-MM-DD"). + WithTimestampLtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + WithTimestampNtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + WithTimestampOutputFormat("YYYY-MM-DD HH24:MI:SS"). + WithTimestampTypeMappingEnum(sdk.TimestampTypeMappingLtz). + WithTimestampTzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + WithTimezone("Europe/Warsaw"). + WithTimeInputFormat("HH24:MI"). + WithTimeOutputFormat("HH24:MI"). + WithTraceLevelEnum(sdk.TraceLevelOnEvent). + WithTransactionAbortOnError(true). + WithTransactionDefaultIsolationLevelEnum(sdk.TransactionDefaultIsolationLevelReadCommitted). + WithTwoDigitCenturyStart(1980). + WithUnsupportedDdlActionEnum(sdk.UnsupportedDDLActionFail). + WithUseCachedResult(false). + WithWeekOfYearPolicy(1). + WithWeekStart(1). + WithEnableUnredactedQuerySyntaxError(true). + WithNetworkPolicyId(networkPolicy.ID()). + WithPreventUnloadToInternalStages(true) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.ServiceUser), + Steps: []resource.TestStep{ + // create with default values for all the parameters + { + Config: config.FromModel(t, userModel), + Check: assert.AssertThat(t, + objectparametersassert.UserParameters(t, userId). + HasAllDefaults(). + HasAllDefaultsExplicit(), + resourceparametersassert.UserResourceParameters(t, userModel.ResourceReference()). + HasAllDefaults(), + ), + }, + // import when no parameter set + { + ResourceName: userModel.ResourceReference(), + ImportState: true, + ImportStateCheck: assert.AssertThatImport(t, + resourceparametersassert.ImportedUserResourceParameters(t, userId.Name()). + HasAllDefaults(), + ), + }, + // set all parameters + { + Config: config.FromModel(t, userModelWithAllParametersSet), + Check: assert.AssertThat(t, + objectparametersassert.UserParameters(t, userId). + HasAbortDetachedQuery(true). + HasAutocommit(false). + HasBinaryInputFormat(sdk.BinaryInputFormatUTF8). + HasBinaryOutputFormat(sdk.BinaryOutputFormatBase64). + HasClientMemoryLimit(1024). + HasClientMetadataRequestUseConnectionCtx(true). + HasClientPrefetchThreads(2). + HasClientResultChunkSize(48). + HasClientResultColumnCaseInsensitive(true). + HasClientSessionKeepAlive(true). + HasClientSessionKeepAliveHeartbeatFrequency(2400). + HasClientTimestampTypeMapping(sdk.ClientTimestampTypeMappingNtz). + HasDateInputFormat("YYYY-MM-DD"). + HasDateOutputFormat("YY-MM-DD"). + HasEnableUnloadPhysicalTypeOptimization(false). + HasErrorOnNondeterministicMerge(false). + HasErrorOnNondeterministicUpdate(true). + HasGeographyOutputFormat(sdk.GeographyOutputFormatWKB). + HasGeometryOutputFormat(sdk.GeometryOutputFormatWKB). + HasJdbcTreatDecimalAsInt(false). + HasJdbcTreatTimestampNtzAsUtc(true). + HasJdbcUseSessionTimezone(false). + HasJsonIndent(4). + HasLockTimeout(21222). + HasLogLevel(sdk.LogLevelError). + HasMultiStatementCount(0). + HasNoorderSequenceAsDefault(false). + HasOdbcTreatDecimalAsInt(true). + HasQueryTag("some_tag"). + HasQuotedIdentifiersIgnoreCase(true). + HasRowsPerResultset(2). + HasS3StageVpceDnsName("vpce-id.s3.region.vpce.amazonaws.com"). + HasSearchPath("$public, $current"). + HasSimulatedDataSharingConsumer("some_consumer"). + HasStatementQueuedTimeoutInSeconds(10). + HasStatementTimeoutInSeconds(10). + HasStrictJsonOutput(true). + HasTimestampDayIsAlways24h(true). + HasTimestampInputFormat("YYYY-MM-DD"). + HasTimestampLtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampNtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampTypeMapping(sdk.TimestampTypeMappingLtz). + HasTimestampTzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimezone("Europe/Warsaw"). + HasTimeInputFormat("HH24:MI"). + HasTimeOutputFormat("HH24:MI"). + HasTraceLevel(sdk.TraceLevelOnEvent). + HasTransactionAbortOnError(true). + HasTransactionDefaultIsolationLevel(sdk.TransactionDefaultIsolationLevelReadCommitted). + HasTwoDigitCenturyStart(1980). + HasUnsupportedDdlAction(sdk.UnsupportedDDLActionFail). + HasUseCachedResult(false). + HasWeekOfYearPolicy(1). + HasWeekStart(1). + HasEnableUnredactedQuerySyntaxError(true). + HasNetworkPolicy(networkPolicy.ID().Name()). + HasPreventUnloadToInternalStages(true), + resourceparametersassert.UserResourceParameters(t, userModelWithAllParametersSet.ResourceReference()). + HasAbortDetachedQuery(true). + HasAutocommit(false). + HasBinaryInputFormat(sdk.BinaryInputFormatUTF8). + HasBinaryOutputFormat(sdk.BinaryOutputFormatBase64). + HasClientMemoryLimit(1024). + HasClientMetadataRequestUseConnectionCtx(true). + HasClientPrefetchThreads(2). + HasClientResultChunkSize(48). + HasClientResultColumnCaseInsensitive(true). + HasClientSessionKeepAlive(true). + HasClientSessionKeepAliveHeartbeatFrequency(2400). + HasClientTimestampTypeMapping(sdk.ClientTimestampTypeMappingNtz). + HasDateInputFormat("YYYY-MM-DD"). + HasDateOutputFormat("YY-MM-DD"). + HasEnableUnloadPhysicalTypeOptimization(false). + HasErrorOnNondeterministicMerge(false). + HasErrorOnNondeterministicUpdate(true). + HasGeographyOutputFormat(sdk.GeographyOutputFormatWKB). + HasGeometryOutputFormat(sdk.GeometryOutputFormatWKB). + HasJdbcTreatDecimalAsInt(false). + HasJdbcTreatTimestampNtzAsUtc(true). + HasJdbcUseSessionTimezone(false). + HasJsonIndent(4). + HasLockTimeout(21222). + HasLogLevel(sdk.LogLevelError). + HasMultiStatementCount(0). + HasNoorderSequenceAsDefault(false). + HasOdbcTreatDecimalAsInt(true). + HasQueryTag("some_tag"). + HasQuotedIdentifiersIgnoreCase(true). + HasRowsPerResultset(2). + HasS3StageVpceDnsName("vpce-id.s3.region.vpce.amazonaws.com"). + HasSearchPath("$public, $current"). + HasSimulatedDataSharingConsumer("some_consumer"). + HasStatementQueuedTimeoutInSeconds(10). + HasStatementTimeoutInSeconds(10). + HasStrictJsonOutput(true). + HasTimestampDayIsAlways24h(true). + HasTimestampInputFormat("YYYY-MM-DD"). + HasTimestampLtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampNtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampTypeMapping(sdk.TimestampTypeMappingLtz). + HasTimestampTzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimezone("Europe/Warsaw"). + HasTimeInputFormat("HH24:MI"). + HasTimeOutputFormat("HH24:MI"). + HasTraceLevel(sdk.TraceLevelOnEvent). + HasTransactionAbortOnError(true). + HasTransactionDefaultIsolationLevel(sdk.TransactionDefaultIsolationLevelReadCommitted). + HasTwoDigitCenturyStart(1980). + HasUnsupportedDdlAction(sdk.UnsupportedDDLActionFail). + HasUseCachedResult(false). + HasWeekOfYearPolicy(1). + HasWeekStart(1). + HasEnableUnredactedQuerySyntaxError(true). + HasNetworkPolicy(networkPolicy.ID().Name()). + HasPreventUnloadToInternalStages(true), + ), + }, + // import when all parameters set + { + ResourceName: userModelWithAllParametersSet.ResourceReference(), + ImportState: true, + ImportStateCheck: assert.AssertThatImport(t, + resourceparametersassert.ImportedUserResourceParameters(t, userId.Name()). + HasAbortDetachedQuery(true). + HasAutocommit(false). + HasBinaryInputFormat(sdk.BinaryInputFormatUTF8). + HasBinaryOutputFormat(sdk.BinaryOutputFormatBase64). + HasClientMemoryLimit(1024). + HasClientMetadataRequestUseConnectionCtx(true). + HasClientPrefetchThreads(2). + HasClientResultChunkSize(48). + HasClientResultColumnCaseInsensitive(true). + HasClientSessionKeepAlive(true). + HasClientSessionKeepAliveHeartbeatFrequency(2400). + HasClientTimestampTypeMapping(sdk.ClientTimestampTypeMappingNtz). + HasDateInputFormat("YYYY-MM-DD"). + HasDateOutputFormat("YY-MM-DD"). + HasEnableUnloadPhysicalTypeOptimization(false). + HasErrorOnNondeterministicMerge(false). + HasErrorOnNondeterministicUpdate(true). + HasGeographyOutputFormat(sdk.GeographyOutputFormatWKB). + HasGeometryOutputFormat(sdk.GeometryOutputFormatWKB). + HasJdbcTreatDecimalAsInt(false). + HasJdbcTreatTimestampNtzAsUtc(true). + HasJdbcUseSessionTimezone(false). + HasJsonIndent(4). + HasLockTimeout(21222). + HasLogLevel(sdk.LogLevelError). + HasMultiStatementCount(0). + HasNoorderSequenceAsDefault(false). + HasOdbcTreatDecimalAsInt(true). + HasQueryTag("some_tag"). + HasQuotedIdentifiersIgnoreCase(true). + HasRowsPerResultset(2). + HasS3StageVpceDnsName("vpce-id.s3.region.vpce.amazonaws.com"). + HasSearchPath("$public, $current"). + HasSimulatedDataSharingConsumer("some_consumer"). + HasStatementQueuedTimeoutInSeconds(10). + HasStatementTimeoutInSeconds(10). + HasStrictJsonOutput(true). + HasTimestampDayIsAlways24h(true). + HasTimestampInputFormat("YYYY-MM-DD"). + HasTimestampLtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampNtzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimestampTypeMapping(sdk.TimestampTypeMappingLtz). + HasTimestampTzOutputFormat("YYYY-MM-DD HH24:MI:SS"). + HasTimezone("Europe/Warsaw"). + HasTimeInputFormat("HH24:MI"). + HasTimeOutputFormat("HH24:MI"). + HasTraceLevel(sdk.TraceLevelOnEvent). + HasTransactionAbortOnError(true). + HasTransactionDefaultIsolationLevel(sdk.TransactionDefaultIsolationLevelReadCommitted). + HasTwoDigitCenturyStart(1980). + HasUnsupportedDdlAction(sdk.UnsupportedDDLActionFail). + HasUseCachedResult(false). + HasWeekOfYearPolicy(1). + HasWeekStart(1). + HasEnableUnredactedQuerySyntaxError(true). + HasNetworkPolicy(networkPolicy.ID().Name()). + HasPreventUnloadToInternalStages(true), + ), + }, + // unset all the parameters + { + Config: config.FromModel(t, userModel), + Check: assert.AssertThat(t, + objectparametersassert.UserParameters(t, userId). + HasAllDefaults(). + HasAllDefaultsExplicit(), + resourceparametersassert.UserResourceParameters(t, userModel.ResourceReference()). + HasAllDefaults(), + ), + }, + }, + }) +} + +func TestAcc_ServiceUser_handleExternalTypeChange(t *testing.T) { + userId := acc.TestClient().Ids.RandomAccountObjectIdentifier() + + userModel := model.ServiceUserWithDefaultMeta(userId.Name()) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.ServiceUser), + Steps: []resource.TestStep{ + { + Config: config.FromModel(t, userModel), + Check: assert.AssertThat(t, + resourceassert.ServiceUserResource(t, userModel.ResourceReference()).HasNameString(userId.Name()).HasUserTypeString("SERVICE"), + resourceshowoutputassert.UserShowOutput(t, userModel.ResourceReference()).HasType("SERVICE"), + ), + }, + { + PreConfig: func() { + acc.TestClient().User.SetType(t, userId, sdk.UserTypePerson) + objectassert.User(t, userId).HasType(string(sdk.UserTypePerson)) + }, + Config: config.FromModel(t, userModel), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(userModel.ResourceReference(), plancheck.ResourceActionDestroyBeforeCreate), + }, + }, + Check: assert.AssertThat(t, + resourceassert.UserResource(t, userModel.ResourceReference()).HasNameString(userId.Name()).HasUserTypeString("SERVICE"), + resourceshowoutputassert.UserShowOutput(t, userModel.ResourceReference()).HasType("SERVICE"), + ), + }, + { + PreConfig: func() { + acc.TestClient().User.UnsetType(t, userId) + objectassert.User(t, userId).HasType("") + }, + Config: config.FromModel(t, userModel), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(userModel.ResourceReference(), plancheck.ResourceActionDestroyBeforeCreate), + }, + }, + Check: assert.AssertThat(t, + resourceassert.UserResource(t, userModel.ResourceReference()).HasNameString(userId.Name()).HasUserTypeString("SERVICE"), + resourceshowoutputassert.UserShowOutput(t, userModel.ResourceReference()).HasType("SERVICE"), + ), + }, + }, + }) +} + +func TestAcc_ServiceUser_setIncompatibleAttributes(t *testing.T) { + userId := acc.TestClient().Ids.RandomAccountObjectIdentifier() + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.ServiceUser), + Steps: []resource.TestStep{ + { + Config: serviceUserConfigWithIncompatibleAttribute(userId, "first_name", random.AlphaN(6)), + ExpectError: regexp.MustCompile("An argument named \"first_name\" is not expected here"), + }, + { + Config: serviceUserConfigWithIncompatibleAttribute(userId, "middle_name", random.AlphaN(6)), + ExpectError: regexp.MustCompile("An argument named \"middle_name\" is not expected here"), + }, + { + Config: serviceUserConfigWithIncompatibleAttribute(userId, "last_name", random.AlphaN(6)), + ExpectError: regexp.MustCompile("An argument named \"last_name\" is not expected here"), + }, + { + Config: serviceUserConfigWithIncompatibleAttribute(userId, "mins_to_bypass_mfa", random.AlphaN(6)), + ExpectError: regexp.MustCompile("An argument named \"mins_to_bypass_mfa\" is not expected here"), + }, + { + Config: serviceUserConfigWithIncompatibleAttribute(userId, "disable_mfa", random.AlphaN(6)), + ExpectError: regexp.MustCompile("An argument named \"disable_mfa\" is not expected here"), + }, + { + Config: serviceUserConfigWithIncompatibleAttribute(userId, "password", random.AlphaN(6)), + ExpectError: regexp.MustCompile("An argument named \"password\" is not expected here"), + }, + { + Config: serviceUserConfigWithIncompatibleAttribute(userId, "must_change_password", random.AlphaN(6)), + ExpectError: regexp.MustCompile("An argument named \"must_change_password\" is not expected here"), + }, + }, + }) +} + +func serviceUserConfigWithIncompatibleAttribute(userId sdk.AccountObjectIdentifier, key string, value string) string { + return fmt.Sprintf(` + resource "snowflake_service_user" "test" { + name = %s + %s = "%s" + } + `, userId.FullyQualifiedName(), key, value) +} diff --git a/pkg/resources/user.go b/pkg/resources/user.go index 77d5fcf418..29cf25a441 100644 --- a/pkg/resources/user.go +++ b/pkg/resources/user.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "log" - "slices" "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" @@ -186,33 +185,24 @@ func User() *schema.Resource { return &schema.Resource{ SchemaVersion: 1, - CreateContext: CreateUser, - UpdateContext: UpdateUser, - ReadContext: GetReadUserFunc(true), + CreateContext: GetCreateUserFunc(sdk.UserTypePerson), + UpdateContext: GetUpdateUserFunc(sdk.UserTypePerson), + ReadContext: GetReadUserFunc(sdk.UserTypePerson, true), DeleteContext: DeleteUser, - Description: "Resource used to manage user objects. For more information, check [user documentation](https://docs.snowflake.com/en/sql-reference/commands-user-role).", + Description: "Resource used to manage user objects. For more information, check [user documentation](https://docs.snowflake.com/en/sql-reference/commands-user-role#user-management).", Schema: helpers.MergeMaps(userSchema, userParametersSchema), Importer: &schema.ResourceImporter{ - StateContext: ImportUser, + StateContext: GetImportUserFunc(sdk.UserTypePerson), }, CustomizeDiff: customdiff.All( // TODO [SNOW-1629468 - next pr]: test "default_role", "default_secondary_roles" - ComputedIfAnyAttributeChanged(userSchema, ShowOutputAttributeName, "password", "login_name", "display_name", "first_name", "last_name", "email", "must_change_password", "disabled", "days_to_expiry", "mins_to_unlock", "default_warehouse", "default_namespace", "default_role", "default_secondary_roles_option", "mins_to_bypass_mfa", "rsa_public_key", "rsa_public_key_2", "comment", "disable_mfa"), + ComputedIfAnyAttributeChanged(userSchema, ShowOutputAttributeName, userExternalChangesAttributes...), ComputedIfAnyAttributeChanged(userParametersSchema, ParametersAttributeName, collections.Map(sdk.AsStringList(sdk.AllUserParameters), strings.ToLower)...), ComputedIfAnyAttributeChanged(userSchema, FullyQualifiedNameAttributeName, "name"), userParametersCustomDiff, - // TODO [SNOW-1645348]: revisit with service user work - func(_ context.Context, diff *schema.ResourceDiff, _ interface{}) error { - if n := diff.Get("user_type"); n != nil { - logging.DebugLogger.Printf("[DEBUG] new external value for user type %s\n", n.(string)) - if !slices.Contains([]string{"", "PERSON"}, strings.ToUpper(n.(string))) { - return errors.Join(diff.SetNewComputed("user_type"), diff.ForceNew("user_type")) - } - } - return nil - }, + RecreateWhenUserTypeChangedExternally(sdk.UserTypePerson), ), StateUpgraders: []schema.StateUpgrader{ @@ -226,126 +216,207 @@ func User() *schema.Resource { } } -func ImportUser(ctx context.Context, d *schema.ResourceData, meta any) ([]*schema.ResourceData, error) { - logging.DebugLogger.Printf("[DEBUG] Starting user import") - client := meta.(*provider.Context).Client - id, err := sdk.ParseAccountObjectIdentifier(d.Id()) - if err != nil { - return nil, err - } +func ServiceUser() *schema.Resource { + return &schema.Resource{ + CreateContext: GetCreateUserFunc(sdk.UserTypeService), + UpdateContext: GetUpdateUserFunc(sdk.UserTypeService), + ReadContext: GetReadUserFunc(sdk.UserTypeService, true), + DeleteContext: DeleteUser, + Description: "Resource used to manage service user objects. For more information, check [user documentation](https://docs.snowflake.com/en/sql-reference/commands-user-role#user-management).", - userDetails, err := client.Users.Describe(ctx, id) - if err != nil { - return nil, err - } + Schema: helpers.MergeMaps(serviceUserSchema, userParametersSchema), + Importer: &schema.ResourceImporter{ + StateContext: GetImportUserFunc(sdk.UserTypeService), + }, - u, err := client.Users.ShowByID(ctx, id) - if err != nil { - return nil, err + CustomizeDiff: customdiff.All( + ComputedIfAnyAttributeChanged(userSchema, ShowOutputAttributeName, serviceUserExternalChangesAttributes...), + ComputedIfAnyAttributeChanged(userParametersSchema, ParametersAttributeName, collections.Map(sdk.AsStringList(sdk.AllUserParameters), strings.ToLower)...), + ComputedIfAnyAttributeChanged(userSchema, FullyQualifiedNameAttributeName, "name"), + userParametersCustomDiff, + RecreateWhenUserTypeChangedExternally(sdk.UserTypeService), + ), } +} - err = errors.Join( - d.Set("name", id.Name()), - setFromStringPropertyIfNotEmpty(d, "login_name", userDetails.LoginName), - setFromStringPropertyIfNotEmpty(d, "display_name", userDetails.DisplayName), - setFromStringPropertyIfNotEmpty(d, "default_namespace", userDetails.DefaultNamespace), - setBooleanStringFromBoolProperty(d, "must_change_password", userDetails.MustChangePassword), - setBooleanStringFromBoolProperty(d, "disabled", userDetails.Disabled), - d.Set("default_secondary_roles_option", u.GetSecondaryRolesOption()), - // all others are set in read - ) - if err != nil { - return nil, err - } +func LegacyServiceUser() *schema.Resource { + return &schema.Resource{ + CreateContext: GetCreateUserFunc(sdk.UserTypeLegacyService), + UpdateContext: GetUpdateUserFunc(sdk.UserTypeLegacyService), + ReadContext: GetReadUserFunc(sdk.UserTypeLegacyService, true), + DeleteContext: DeleteUser, + Description: "Resource used to manage legacy service user objects. For more information, check [user documentation](https://docs.snowflake.com/en/sql-reference/commands-user-role#user-management).", + + Schema: helpers.MergeMaps(legacyServiceUserSchema, userParametersSchema), + Importer: &schema.ResourceImporter{ + StateContext: GetImportUserFunc(sdk.UserTypeLegacyService), + }, - return []*schema.ResourceData{d}, nil + CustomizeDiff: customdiff.All( + ComputedIfAnyAttributeChanged(userSchema, ShowOutputAttributeName, legacyServiceUserExternalChangesAttributes...), + ComputedIfAnyAttributeChanged(userParametersSchema, ParametersAttributeName, collections.Map(sdk.AsStringList(sdk.AllUserParameters), strings.ToLower)...), + ComputedIfAnyAttributeChanged(userSchema, FullyQualifiedNameAttributeName, "name"), + userParametersCustomDiff, + RecreateWhenUserTypeChangedExternally(sdk.UserTypeLegacyService), + ), + } } -func CreateUser(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - client := meta.(*provider.Context).Client +func GetImportUserFunc(userType sdk.UserType) func(ctx context.Context, d *schema.ResourceData, meta any) ([]*schema.ResourceData, error) { + return func(ctx context.Context, d *schema.ResourceData, meta any) ([]*schema.ResourceData, error) { + logging.DebugLogger.Printf("[DEBUG] Starting user import") + client := meta.(*provider.Context).Client + id, err := sdk.ParseAccountObjectIdentifier(d.Id()) + if err != nil { + return nil, err + } - opts := &sdk.CreateUserOptions{ - ObjectProperties: &sdk.UserObjectProperties{}, - ObjectParameters: &sdk.UserObjectParameters{}, - SessionParameters: &sdk.SessionParameters{}, - } - name := d.Get("name").(string) - id := sdk.NewAccountObjectIdentifier(name) - - errs := errors.Join( - stringAttributeCreate(d, "password", &opts.ObjectProperties.Password), - stringAttributeCreate(d, "login_name", &opts.ObjectProperties.LoginName), - stringAttributeCreate(d, "display_name", &opts.ObjectProperties.DisplayName), - stringAttributeCreate(d, "first_name", &opts.ObjectProperties.FirstName), - stringAttributeCreate(d, "middle_name", &opts.ObjectProperties.MiddleName), - stringAttributeCreate(d, "last_name", &opts.ObjectProperties.LastName), - stringAttributeCreate(d, "email", &opts.ObjectProperties.Email), - booleanStringAttributeCreate(d, "must_change_password", &opts.ObjectProperties.MustChangePassword), - booleanStringAttributeCreate(d, "disabled", &opts.ObjectProperties.Disable), - intAttributeCreate(d, "days_to_expiry", &opts.ObjectProperties.DaysToExpiry), - intAttributeWithSpecialDefaultCreate(d, "mins_to_unlock", &opts.ObjectProperties.MinsToUnlock), - accountObjectIdentifierAttributeCreate(d, "default_warehouse", &opts.ObjectProperties.DefaultWarehouse), - objectIdentifierAttributeCreate(d, "default_namespace", &opts.ObjectProperties.DefaultNamespace), - accountObjectIdentifierAttributeCreate(d, "default_role", &opts.ObjectProperties.DefaultRole), - func() error { - defaultSecondaryRolesOption, err := sdk.ToSecondaryRolesOption(d.Get("default_secondary_roles_option").(string)) + userDetails, err := client.Users.Describe(ctx, id) + if err != nil { + return nil, err + } + + u, err := client.Users.ShowByID(ctx, id) + if err != nil { + return nil, err + } + + err = errors.Join( + d.Set("name", id.Name()), + setFromStringPropertyIfNotEmpty(d, "login_name", userDetails.LoginName), + setFromStringPropertyIfNotEmpty(d, "display_name", userDetails.DisplayName), + setFromStringPropertyIfNotEmpty(d, "default_namespace", userDetails.DefaultNamespace), + setBooleanStringFromBoolProperty(d, "disabled", userDetails.Disabled), + d.Set("default_secondary_roles_option", u.GetSecondaryRolesOption()), + // all others are set in read + ) + if err != nil { + return nil, err + } + if userType == sdk.UserTypePerson || userType == sdk.UserTypeLegacyService { + err := setBooleanStringFromBoolProperty(d, "must_change_password", userDetails.MustChangePassword) if err != nil { - return err + return nil, err } - switch defaultSecondaryRolesOption { - case sdk.SecondaryRolesOptionDefault: - return nil - case sdk.SecondaryRolesOptionNone: - opts.ObjectProperties.DefaultSecondaryRoles = &sdk.SecondaryRoles{None: sdk.Bool(true)} - case sdk.SecondaryRolesOptionAll: - opts.ObjectProperties.DefaultSecondaryRoles = &sdk.SecondaryRoles{All: sdk.Bool(true)} - } - return nil - }(), - intAttributeWithSpecialDefaultCreate(d, "mins_to_bypass_mfa", &opts.ObjectProperties.MinsToBypassMFA), - stringAttributeCreate(d, "rsa_public_key", &opts.ObjectProperties.RSAPublicKey), - stringAttributeCreate(d, "rsa_public_key_2", &opts.ObjectProperties.RSAPublicKey2), - stringAttributeCreate(d, "comment", &opts.ObjectProperties.Comment), - // disable mfa cannot be set in create, alter is run after creation - ) - if errs != nil { - return diag.FromErr(errs) - } + } - if parametersCreateDiags := handleUserParametersCreate(d, opts); len(parametersCreateDiags) > 0 { - return parametersCreateDiags + return []*schema.ResourceData{d}, nil } +} - err := client.Users.Create(ctx, id, opts) - if err != nil { - return diag.FromErr(err) - } - d.SetId(helpers.EncodeResourceIdentifier(id)) +func GetCreateUserFunc(userType sdk.UserType) func(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + return func(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + client := meta.(*provider.Context).Client - // disable mfa cannot be set in create, we need to alter if set in config - var diags diag.Diagnostics - if disableMfa := d.Get("disable_mfa").(string); disableMfa != BooleanDefault { - parsed, err := booleanStringToBool(disableMfa) - if err != nil { - diags = append(diags, diag.Diagnostic{ - Severity: diag.Warning, - Summary: fmt.Sprintf("Setting disable mfa failed after create for user %s, err: %v", id.FullyQualifiedName(), err), - }) + opts := &sdk.CreateUserOptions{ + ObjectProperties: &sdk.UserObjectProperties{}, + ObjectParameters: &sdk.UserObjectParameters{}, + SessionParameters: &sdk.SessionParameters{}, } - alterDisableMfa := sdk.AlterUserOptions{Set: &sdk.UserSet{ObjectProperties: &sdk.UserAlterObjectProperties{DisableMfa: sdk.Bool(parsed)}}} - err = client.Users.Alter(ctx, id, &alterDisableMfa) + name := d.Get("name").(string) + id := sdk.NewAccountObjectIdentifier(name) + + errs := errors.Join( + // password handled separately for proper user types, + stringAttributeCreate(d, "login_name", &opts.ObjectProperties.LoginName), + stringAttributeCreate(d, "display_name", &opts.ObjectProperties.DisplayName), + // first_name handled separately for proper user types, + // middle_name handled separately for proper user types, + // last_name handled separately for proper user types, + stringAttributeCreate(d, "email", &opts.ObjectProperties.Email), + // must_change_password handled separately for proper user types, + booleanStringAttributeCreate(d, "disabled", &opts.ObjectProperties.Disable), + intAttributeCreate(d, "days_to_expiry", &opts.ObjectProperties.DaysToExpiry), + intAttributeWithSpecialDefaultCreate(d, "mins_to_unlock", &opts.ObjectProperties.MinsToUnlock), + accountObjectIdentifierAttributeCreate(d, "default_warehouse", &opts.ObjectProperties.DefaultWarehouse), + objectIdentifierAttributeCreate(d, "default_namespace", &opts.ObjectProperties.DefaultNamespace), + accountObjectIdentifierAttributeCreate(d, "default_role", &opts.ObjectProperties.DefaultRole), + func() error { + defaultSecondaryRolesOption, err := sdk.ToSecondaryRolesOption(d.Get("default_secondary_roles_option").(string)) + if err != nil { + return err + } + switch defaultSecondaryRolesOption { + case sdk.SecondaryRolesOptionDefault: + return nil + case sdk.SecondaryRolesOptionNone: + opts.ObjectProperties.DefaultSecondaryRoles = &sdk.SecondaryRoles{None: sdk.Bool(true)} + case sdk.SecondaryRolesOptionAll: + opts.ObjectProperties.DefaultSecondaryRoles = &sdk.SecondaryRoles{All: sdk.Bool(true)} + } + return nil + }(), + // mins_to_bypass_mfa handled separately for proper user types, + stringAttributeCreate(d, "rsa_public_key", &opts.ObjectProperties.RSAPublicKey), + stringAttributeCreate(d, "rsa_public_key_2", &opts.ObjectProperties.RSAPublicKey2), + stringAttributeCreate(d, "comment", &opts.ObjectProperties.Comment), + // disable mfa cannot be set in create, alter is run after creation + ) + if errs != nil { + return diag.FromErr(errs) + } + + var userTypeSpecificFieldsErrs error + switch userType { + case sdk.UserTypePerson: + userTypeSpecificFieldsErrs = errors.Join( + stringAttributeCreate(d, "password", &opts.ObjectProperties.Password), + stringAttributeCreate(d, "first_name", &opts.ObjectProperties.FirstName), + stringAttributeCreate(d, "middle_name", &opts.ObjectProperties.MiddleName), + stringAttributeCreate(d, "last_name", &opts.ObjectProperties.LastName), + booleanStringAttributeCreate(d, "must_change_password", &opts.ObjectProperties.MustChangePassword), + intAttributeWithSpecialDefaultCreate(d, "mins_to_bypass_mfa", &opts.ObjectProperties.MinsToBypassMFA), + ) + case sdk.UserTypeLegacyService: + userTypeSpecificFieldsErrs = errors.Join( + stringAttributeCreate(d, "password", &opts.ObjectProperties.Password), + booleanStringAttributeCreate(d, "must_change_password", &opts.ObjectProperties.MustChangePassword), + ) + opts.ObjectProperties.Type = sdk.Pointer(sdk.UserTypeLegacyService) + case sdk.UserTypeService: + opts.ObjectProperties.Type = sdk.Pointer(sdk.UserTypeService) + } + if userTypeSpecificFieldsErrs != nil { + return diag.FromErr(userTypeSpecificFieldsErrs) + } + + if parametersCreateDiags := handleUserParametersCreate(d, opts); len(parametersCreateDiags) > 0 { + return parametersCreateDiags + } + + err := client.Users.Create(ctx, id, opts) if err != nil { - diags = append(diags, diag.Diagnostic{ - Severity: diag.Warning, - Summary: fmt.Sprintf("Setting disable mfa failed after create for user %s, err: %v", id.FullyQualifiedName(), err), - }) + return diag.FromErr(err) } - } + d.SetId(helpers.EncodeResourceIdentifier(id)) - return append(diags, GetReadUserFunc(false)(ctx, d, meta)...) + var diags diag.Diagnostics + if userType == sdk.UserTypePerson { + // disable mfa cannot be set in create, we need to alter if set in config + if disableMfa := d.Get("disable_mfa").(string); disableMfa != BooleanDefault { + parsed, err := booleanStringToBool(disableMfa) + if err != nil { + diags = append(diags, diag.Diagnostic{ + Severity: diag.Warning, + Summary: fmt.Sprintf("Setting disable mfa failed after create for user %s, err: %v", id.FullyQualifiedName(), err), + }) + } + alterDisableMfa := sdk.AlterUserOptions{Set: &sdk.UserSet{ObjectProperties: &sdk.UserAlterObjectProperties{DisableMfa: sdk.Bool(parsed)}}} + err = client.Users.Alter(ctx, id, &alterDisableMfa) + if err != nil { + diags = append(diags, diag.Diagnostic{ + Severity: diag.Warning, + Summary: fmt.Sprintf("Setting disable mfa failed after create for user %s, err: %v", id.FullyQualifiedName(), err), + }) + } + } + } + + return append(diags, GetReadUserFunc(userType, false)(ctx, d, meta)...) + } } -func GetReadUserFunc(withExternalChangesMarking bool) schema.ReadContextFunc { +func GetReadUserFunc(userType sdk.UserType, withExternalChangesMarking bool) schema.ReadContextFunc { return func(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { client := meta.(*provider.Context).Client id, err := sdk.ParseAccountObjectIdentifier(d.Id()) @@ -389,25 +460,31 @@ func GetReadUserFunc(withExternalChangesMarking bool) schema.ReadContextFunc { } if withExternalChangesMarking { - if err = handleExternalChangesToObjectInShow(d, - showMapping{"login_name", "login_name", u.LoginName, u.LoginName, nil}, - showMapping{"display_name", "display_name", u.DisplayName, u.DisplayName, nil}, - showMapping{"must_change_password", "must_change_password", u.MustChangePassword, fmt.Sprintf("%t", u.MustChangePassword), nil}, - showMapping{"disabled", "disabled", u.Disabled, fmt.Sprintf("%t", u.Disabled), nil}, - showMapping{"default_namespace", "default_namespace", u.DefaultNamespace, u.DefaultNamespace, nil}, - showMapping{"default_secondary_roles", "default_secondary_roles_option", u.DefaultSecondaryRoles, u.GetSecondaryRolesOption(), nil}, - ); err != nil { + showMappings := []showMapping{ + {"login_name", "login_name", u.LoginName, u.LoginName, nil}, + {"display_name", "display_name", u.DisplayName, u.DisplayName, nil}, + {"disabled", "disabled", u.Disabled, fmt.Sprintf("%t", u.Disabled), nil}, + {"default_namespace", "default_namespace", u.DefaultNamespace, u.DefaultNamespace, nil}, + {"default_secondary_roles", "default_secondary_roles_option", u.DefaultSecondaryRoles, u.GetSecondaryRolesOption(), nil}, + } + if userType == sdk.UserTypePerson || userType == sdk.UserTypeLegacyService { + showMappings = append(showMappings, showMapping{"must_change_password", "must_change_password", u.MustChangePassword, fmt.Sprintf("%t", u.MustChangePassword), nil}) + } + if err = handleExternalChangesToObjectInShow(d, showMappings...); err != nil { return diag.FromErr(err) } } - if err = setStateToValuesFromConfig(d, userSchema, []string{ + fieldsToSetStateToValueFromConfig := []string{ "login_name", "display_name", - "must_change_password", "disabled", "default_namespace", - }); err != nil { + } + if userType == sdk.UserTypePerson { + fieldsToSetStateToValueFromConfig = append(fieldsToSetStateToValueFromConfig, "must_change_password") + } + if err = setStateToValuesFromConfig(d, userSchema, fieldsToSetStateToValueFromConfig); err != nil { return diag.FromErr(err) } @@ -416,9 +493,9 @@ func GetReadUserFunc(withExternalChangesMarking bool) schema.ReadContextFunc { // can't read password // not reading login_name on purpose (handled as external change to show output) // not reading display_name on purpose (handled as external change to show output) - setFromStringPropertyIfNotEmpty(d, "first_name", userDetails.FirstName), - setFromStringPropertyIfNotEmpty(d, "middle_name", userDetails.MiddleName), - setFromStringPropertyIfNotEmpty(d, "last_name", userDetails.LastName), + // first_name handled separately for proper user types, + // middle_name handled separately for proper user types, + // last_name handled separately for proper user types, setFromStringPropertyIfNotEmpty(d, "email", userDetails.Email), // not reading must_change_password on purpose (handled as external change to show output) // not reading disabled on purpose (handled as external change to show output) @@ -435,6 +512,18 @@ func GetReadUserFunc(withExternalChangesMarking bool) schema.ReadContextFunc { // can't read disable_mfa d.Set("user_type", u.Type), + func() error { + var errs error + if userType == sdk.UserTypePerson { + errs = errors.Join( + setFromStringPropertyIfNotEmpty(d, "first_name", userDetails.FirstName), + setFromStringPropertyIfNotEmpty(d, "middle_name", userDetails.MiddleName), + setFromStringPropertyIfNotEmpty(d, "last_name", userDetails.LastName), + ) + } + return errs + }(), + d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()), handleUserParameterRead(d, userParameters), d.Set(ShowOutputAttributeName, []map[string]any{schemas.UserToSchema(u)}), @@ -448,120 +537,144 @@ func GetReadUserFunc(withExternalChangesMarking bool) schema.ReadContextFunc { } } -func UpdateUser(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - client := meta.(*provider.Context).Client - id, err := sdk.ParseAccountObjectIdentifier(d.Id()) - if err != nil { - return diag.FromErr(err) - } - - if d.HasChange("name") { - newID := sdk.NewAccountObjectIdentifier(d.Get("name").(string)) - - err := client.Users.Alter(ctx, id, &sdk.AlterUserOptions{ - NewName: newID, - }) +func GetUpdateUserFunc(userType sdk.UserType) func(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + return func(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + client := meta.(*provider.Context).Client + id, err := sdk.ParseAccountObjectIdentifier(d.Id()) if err != nil { return diag.FromErr(err) } - d.SetId(helpers.EncodeResourceIdentifier(newID)) - id = newID - } + if d.HasChange("name") { + newID := sdk.NewAccountObjectIdentifier(d.Get("name").(string)) - setObjectProperties := sdk.UserAlterObjectProperties{} - unsetObjectProperties := sdk.UserObjectPropertiesUnset{} - errs := errors.Join( - stringAttributeUpdate(d, "password", &setObjectProperties.Password, &unsetObjectProperties.Password), - stringAttributeUpdate(d, "login_name", &setObjectProperties.LoginName, &unsetObjectProperties.LoginName), - stringAttributeUpdate(d, "display_name", &setObjectProperties.DisplayName, &unsetObjectProperties.DisplayName), - stringAttributeUpdate(d, "first_name", &setObjectProperties.FirstName, &unsetObjectProperties.FirstName), - stringAttributeUpdate(d, "middle_name", &setObjectProperties.MiddleName, &unsetObjectProperties.MiddleName), - stringAttributeUpdate(d, "last_name", &setObjectProperties.LastName, &unsetObjectProperties.LastName), - stringAttributeUpdate(d, "email", &setObjectProperties.Email, &unsetObjectProperties.Email), - booleanStringAttributeUpdate(d, "must_change_password", &setObjectProperties.MustChangePassword, &unsetObjectProperties.MustChangePassword), - booleanStringAttributeUpdate(d, "disabled", &setObjectProperties.Disable, &unsetObjectProperties.Disable), - intAttributeUpdate(d, "days_to_expiry", &setObjectProperties.DaysToExpiry, &unsetObjectProperties.DaysToExpiry), - intAttributeWithSpecialDefaultUpdate(d, "mins_to_unlock", &setObjectProperties.MinsToUnlock, &unsetObjectProperties.MinsToUnlock), - accountObjectIdentifierAttributeUpdate(d, "default_warehouse", &setObjectProperties.DefaultWarehouse, &unsetObjectProperties.DefaultWarehouse), - objectIdentifierAttributeUpdate(d, "default_namespace", &setObjectProperties.DefaultNamespace, &unsetObjectProperties.DefaultNamespace), - accountObjectIdentifierAttributeUpdate(d, "default_role", &setObjectProperties.DefaultRole, &unsetObjectProperties.DefaultRole), - func() error { - if d.HasChange("default_secondary_roles_option") { - defaultSecondaryRolesOption, err := sdk.ToSecondaryRolesOption(d.Get("default_secondary_roles_option").(string)) - if err != nil { - return err - } - switch defaultSecondaryRolesOption { - case sdk.SecondaryRolesOptionDefault: - unsetObjectProperties.DefaultSecondaryRoles = sdk.Bool(true) - case sdk.SecondaryRolesOptionNone: - setObjectProperties.DefaultSecondaryRoles = &sdk.SecondaryRoles{None: sdk.Bool(true)} - case sdk.SecondaryRolesOptionAll: - setObjectProperties.DefaultSecondaryRoles = &sdk.SecondaryRoles{All: sdk.Bool(true)} - } + err := client.Users.Alter(ctx, id, &sdk.AlterUserOptions{ + NewName: newID, + }) + if err != nil { + return diag.FromErr(err) } - return nil - }(), - intAttributeWithSpecialDefaultUpdate(d, "mins_to_bypass_mfa", &setObjectProperties.MinsToBypassMFA, &unsetObjectProperties.MinsToBypassMFA), - stringAttributeUpdate(d, "rsa_public_key", &setObjectProperties.RSAPublicKey, &unsetObjectProperties.RSAPublicKey), - stringAttributeUpdate(d, "rsa_public_key_2", &setObjectProperties.RSAPublicKey2, &unsetObjectProperties.RSAPublicKey2), - stringAttributeUpdate(d, "comment", &setObjectProperties.Comment, &unsetObjectProperties.Comment), - booleanStringAttributeUpdate(d, "disable_mfa", &setObjectProperties.DisableMfa, &unsetObjectProperties.DisableMfa), - ) - if errs != nil { - return diag.FromErr(errs) - } - if (setObjectProperties != sdk.UserAlterObjectProperties{}) { - err := client.Users.Alter(ctx, id, &sdk.AlterUserOptions{Set: &sdk.UserSet{ObjectProperties: &setObjectProperties}}) - if err != nil { - d.Partial(true) - return diag.FromErr(err) + d.SetId(helpers.EncodeResourceIdentifier(newID)) + id = newID } - } - if (unsetObjectProperties != sdk.UserObjectPropertiesUnset{}) { - err := client.Users.Alter(ctx, id, &sdk.AlterUserOptions{Unset: &sdk.UserUnset{ObjectProperties: &unsetObjectProperties}}) - if err != nil { - d.Partial(true) - return diag.FromErr(err) + + setObjectProperties := sdk.UserAlterObjectProperties{} + unsetObjectProperties := sdk.UserObjectPropertiesUnset{} + errs := errors.Join( + // password handled separately for proper user types, + stringAttributeUpdate(d, "login_name", &setObjectProperties.LoginName, &unsetObjectProperties.LoginName), + stringAttributeUpdate(d, "display_name", &setObjectProperties.DisplayName, &unsetObjectProperties.DisplayName), + // first_name handled separately for proper user types, + // middle_name handled separately for proper user types, + // last_name handled separately for proper user types, + stringAttributeUpdate(d, "email", &setObjectProperties.Email, &unsetObjectProperties.Email), + // must_change_password handled separately for proper user types, + booleanStringAttributeUpdate(d, "disabled", &setObjectProperties.Disable, &unsetObjectProperties.Disable), + intAttributeUpdate(d, "days_to_expiry", &setObjectProperties.DaysToExpiry, &unsetObjectProperties.DaysToExpiry), + intAttributeWithSpecialDefaultUpdate(d, "mins_to_unlock", &setObjectProperties.MinsToUnlock, &unsetObjectProperties.MinsToUnlock), + accountObjectIdentifierAttributeUpdate(d, "default_warehouse", &setObjectProperties.DefaultWarehouse, &unsetObjectProperties.DefaultWarehouse), + objectIdentifierAttributeUpdate(d, "default_namespace", &setObjectProperties.DefaultNamespace, &unsetObjectProperties.DefaultNamespace), + accountObjectIdentifierAttributeUpdate(d, "default_role", &setObjectProperties.DefaultRole, &unsetObjectProperties.DefaultRole), + func() error { + if d.HasChange("default_secondary_roles_option") { + defaultSecondaryRolesOption, err := sdk.ToSecondaryRolesOption(d.Get("default_secondary_roles_option").(string)) + if err != nil { + return err + } + switch defaultSecondaryRolesOption { + case sdk.SecondaryRolesOptionDefault: + unsetObjectProperties.DefaultSecondaryRoles = sdk.Bool(true) + case sdk.SecondaryRolesOptionNone: + setObjectProperties.DefaultSecondaryRoles = &sdk.SecondaryRoles{None: sdk.Bool(true)} + case sdk.SecondaryRolesOptionAll: + setObjectProperties.DefaultSecondaryRoles = &sdk.SecondaryRoles{All: sdk.Bool(true)} + } + } + return nil + }(), + // mins_to_bypass_mfa handled separately for proper user types, + stringAttributeUpdate(d, "rsa_public_key", &setObjectProperties.RSAPublicKey, &unsetObjectProperties.RSAPublicKey), + stringAttributeUpdate(d, "rsa_public_key_2", &setObjectProperties.RSAPublicKey2, &unsetObjectProperties.RSAPublicKey2), + stringAttributeUpdate(d, "comment", &setObjectProperties.Comment, &unsetObjectProperties.Comment), + // disable_mfa handled separately for proper user types, + ) + if errs != nil { + return diag.FromErr(errs) } - } - set := &sdk.UserSet{ - SessionParameters: &sdk.SessionParameters{}, - ObjectParameters: &sdk.UserObjectParameters{}, - } - unset := &sdk.UserUnset{ - SessionParameters: &sdk.SessionParametersUnset{}, - ObjectParameters: &sdk.UserObjectParametersUnset{}, - } - if updateParamDiags := handleUserParametersUpdate(d, set, unset); len(updateParamDiags) > 0 { - return updateParamDiags - } + var userTypeSpecificFieldsErrs error + switch userType { + case sdk.UserTypePerson: + userTypeSpecificFieldsErrs = errors.Join( + stringAttributeUpdate(d, "password", &setObjectProperties.Password, &unsetObjectProperties.Password), + stringAttributeUpdate(d, "first_name", &setObjectProperties.FirstName, &unsetObjectProperties.FirstName), + stringAttributeUpdate(d, "middle_name", &setObjectProperties.MiddleName, &unsetObjectProperties.MiddleName), + stringAttributeUpdate(d, "last_name", &setObjectProperties.LastName, &unsetObjectProperties.LastName), + booleanStringAttributeUpdate(d, "must_change_password", &setObjectProperties.MustChangePassword, &unsetObjectProperties.MustChangePassword), + intAttributeWithSpecialDefaultUpdate(d, "mins_to_bypass_mfa", &setObjectProperties.MinsToBypassMFA, &unsetObjectProperties.MinsToBypassMFA), + booleanStringAttributeUpdate(d, "disable_mfa", &setObjectProperties.DisableMfa, &unsetObjectProperties.DisableMfa), + ) + case sdk.UserTypeLegacyService: + userTypeSpecificFieldsErrs = errors.Join( + stringAttributeUpdate(d, "password", &setObjectProperties.Password, &unsetObjectProperties.Password), + booleanStringAttributeUpdate(d, "must_change_password", &setObjectProperties.MustChangePassword, &unsetObjectProperties.MustChangePassword), + ) + } + if userTypeSpecificFieldsErrs != nil { + return diag.FromErr(userTypeSpecificFieldsErrs) + } - if (*set.SessionParameters != sdk.SessionParameters{} || *set.ObjectParameters != sdk.UserObjectParameters{}) { - err := client.Users.Alter(ctx, id, &sdk.AlterUserOptions{ - Set: set, - }) - if err != nil { - return diag.FromErr(err) + if (setObjectProperties != sdk.UserAlterObjectProperties{}) { + err := client.Users.Alter(ctx, id, &sdk.AlterUserOptions{Set: &sdk.UserSet{ObjectProperties: &setObjectProperties}}) + if err != nil { + d.Partial(true) + return diag.FromErr(err) + } + } + if (unsetObjectProperties != sdk.UserObjectPropertiesUnset{}) { + err := client.Users.Alter(ctx, id, &sdk.AlterUserOptions{Unset: &sdk.UserUnset{ObjectProperties: &unsetObjectProperties}}) + if err != nil { + d.Partial(true) + return diag.FromErr(err) + } } - } - if (*unset.SessionParameters != sdk.SessionParametersUnset{}) || (*unset.ObjectParameters != sdk.UserObjectParametersUnset{}) { - err := client.Users.Alter(ctx, id, &sdk.AlterUserOptions{ - Unset: &sdk.UserUnset{ - SessionParameters: unset.SessionParameters, - ObjectParameters: unset.ObjectParameters, - }, - }) - if err != nil { - return diag.FromErr(err) + set := &sdk.UserSet{ + SessionParameters: &sdk.SessionParameters{}, + ObjectParameters: &sdk.UserObjectParameters{}, + } + unset := &sdk.UserUnset{ + SessionParameters: &sdk.SessionParametersUnset{}, + ObjectParameters: &sdk.UserObjectParametersUnset{}, + } + if updateParamDiags := handleUserParametersUpdate(d, set, unset); len(updateParamDiags) > 0 { + return updateParamDiags } - } - return GetReadUserFunc(false)(ctx, d, meta) + if (*set.SessionParameters != sdk.SessionParameters{} || *set.ObjectParameters != sdk.UserObjectParameters{}) { + err := client.Users.Alter(ctx, id, &sdk.AlterUserOptions{ + Set: set, + }) + if err != nil { + return diag.FromErr(err) + } + } + + if (*unset.SessionParameters != sdk.SessionParametersUnset{}) || (*unset.ObjectParameters != sdk.UserObjectParametersUnset{}) { + err := client.Users.Alter(ctx, id, &sdk.AlterUserOptions{ + Unset: &sdk.UserUnset{ + SessionParameters: unset.SessionParameters, + ObjectParameters: unset.ObjectParameters, + }, + }) + if err != nil { + return diag.FromErr(err) + } + } + + return GetReadUserFunc(userType, false)(ctx, d, meta) + } } func DeleteUser(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { diff --git a/pkg/resources/user_acceptance_test.go b/pkg/resources/user_acceptance_test.go index c7155298fe..dcf3266fa9 100644 --- a/pkg/resources/user_acceptance_test.go +++ b/pkg/resources/user_acceptance_test.go @@ -690,7 +690,7 @@ func TestAcc_User_issue2970(t *testing.T) { newPass := random.Password() newKey, _ := random.GenerateRSAPublicKey(t) - incorrectlyFormattedNewKey := fmt.Sprintf("-----BEGIN PUBLIC KEY-----\n%s-----END PUBLIC KEY-----\n", newKey) + incorrectlyFormattedNewKey := fmt.Sprintf("-invalid----BEGIN PUBLIC KEY-----\n%s-----END PUBLIC KEY-----\n", newKey) userModel := model.User(resourceName, userId.Name()). WithPassword(pass). @@ -993,8 +993,8 @@ func TestAcc_User_handleExternalTypeChange(t *testing.T) { }, { PreConfig: func() { - acc.TestClient().User.SetType(t, userId, "SERVICE") - objectassert.User(t, userId).HasType("SERVICE") + acc.TestClient().User.SetType(t, userId, sdk.UserTypeService) + objectassert.User(t, userId).HasType(string(sdk.UserTypeService)) }, Config: config.FromModel(t, userModel), ConfigPlanChecks: resource.ConfigPlanChecks{ @@ -1007,6 +1007,40 @@ func TestAcc_User_handleExternalTypeChange(t *testing.T) { resourceshowoutputassert.UserShowOutput(t, userModel.ResourceReference()).HasType(""), ), }, + // no change should happen if the change is to PERSON explicitly + { + PreConfig: func() { + acc.TestClient().User.SetType(t, userId, sdk.UserTypePerson) + objectassert.User(t, userId).HasType("PERSON") + }, + Config: config.FromModel(t, userModel), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + Check: assert.AssertThat(t, + resourceassert.UserResource(t, userModel.ResourceReference()).HasNameString(userId.Name()).HasUserTypeString("PERSON"), + resourceshowoutputassert.UserShowOutput(t, userModel.ResourceReference()).HasType("PERSON"), + ), + }, + // no change should happen if we fall back to default + { + PreConfig: func() { + acc.TestClient().User.UnsetType(t, userId) + objectassert.User(t, userId).HasType("") + }, + Config: config.FromModel(t, userModel), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + Check: assert.AssertThat(t, + resourceassert.UserResource(t, userModel.ResourceReference()).HasNameString(userId.Name()).HasUserTypeString(""), + resourceshowoutputassert.UserShowOutput(t, userModel.ResourceReference()).HasType(""), + ), + }, }, }) } diff --git a/pkg/resources/user_commons.go b/pkg/resources/user_commons.go new file mode 100644 index 0000000000..399875fa33 --- /dev/null +++ b/pkg/resources/user_commons.go @@ -0,0 +1,74 @@ +package resources + +import ( + "slices" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var serviceUserNotApplicableAttributes = []string{ + "password", + "first_name", + "middle_name", + "last_name", + "must_change_password", + "mins_to_bypass_mfa", + "disable_mfa", +} + +var legacyServiceUserNotApplicableAttributes = []string{ + "first_name", + "middle_name", + "last_name", + "mins_to_bypass_mfa", + "disable_mfa", +} + +var userExternalChangesAttributes = []string{ + "password", + "login_name", + "display_name", + "first_name", + "last_name", + "email", + "must_change_password", + "disabled", + "days_to_expiry", + "mins_to_unlock", + "default_warehouse", + "default_namespace", + "default_role", + "default_secondary_roles_option", + "mins_to_bypass_mfa", + "rsa_public_key", + "rsa_public_key_2", + "comment", + "disable_mfa", +} + +var ( + serviceUserSchema = make(map[string]*schema.Schema) + legacyServiceUserSchema = make(map[string]*schema.Schema) + + serviceUserExternalChangesAttributes = make([]string, 0) + legacyServiceUserExternalChangesAttributes = make([]string, 0) +) + +func init() { + for k, v := range userSchema { + if !slices.Contains(serviceUserNotApplicableAttributes, k) { + serviceUserSchema[k] = v + } + if !slices.Contains(legacyServiceUserNotApplicableAttributes, k) { + legacyServiceUserSchema[k] = v + } + } + for _, attr := range userExternalChangesAttributes { + if !slices.Contains(serviceUserNotApplicableAttributes, attr) { + serviceUserExternalChangesAttributes = append(serviceUserExternalChangesAttributes, attr) + } + if !slices.Contains(legacyServiceUserNotApplicableAttributes, attr) { + legacyServiceUserExternalChangesAttributes = append(legacyServiceUserExternalChangesAttributes, attr) + } + } +} diff --git a/pkg/schemas/user_describe.go b/pkg/schemas/user_describe.go index acefcfed12..f28acaf47d 100644 --- a/pkg/schemas/user_describe.go +++ b/pkg/schemas/user_describe.go @@ -19,6 +19,10 @@ var UserDescribeSchema = map[string]*schema.Schema{ Type: schema.TypeString, Computed: true, }, + "type": { + Type: schema.TypeString, + Computed: true, + }, "login_name": { Type: schema.TypeString, Computed: true, @@ -146,6 +150,9 @@ func UserDescriptionToSchema(userDetails sdk.UserDetails) []map[string]any { if userDetails.DisplayName != nil { userDetailsSchema["display_name"] = userDetails.DisplayName.Value } + if userDetails.Type != nil { + userDetailsSchema["type"] = userDetails.Type.Value + } if userDetails.LoginName != nil { userDetailsSchema["login_name"] = userDetails.LoginName.Value } diff --git a/pkg/sdk/sweepers_test.go b/pkg/sdk/sweepers_test.go index 8e3d66f3f3..49ce33c9dc 100644 --- a/pkg/sdk/sweepers_test.go +++ b/pkg/sdk/sweepers_test.go @@ -145,8 +145,10 @@ func nukeWarehouses(client *Client, prefix string) func() error { }, nil, ) - errs = append(errs, fmt.Errorf("granting ownership on warehouse %s ended with error, err = %w", wh.ID().FullyQualifiedName(), err)) - continue + if err != nil { + errs = append(errs, fmt.Errorf("granting ownership on warehouse %s ended with error, err = %w", wh.ID().FullyQualifiedName(), err)) + continue + } } log.Printf("[DEBUG] Dropping warehouse %s, created at: %s\n", wh.ID().FullyQualifiedName(), wh.CreatedOn.String()) @@ -196,8 +198,10 @@ func nukeDatabases(client *Client, prefix string) func() error { }, nil, ) - errs = append(errs, fmt.Errorf("granting ownership on database %s ended with error, err = %w", db.ID().FullyQualifiedName(), err)) - continue + if err != nil { + errs = append(errs, fmt.Errorf("granting ownership on database %s ended with error, err = %w", db.ID().FullyQualifiedName(), err)) + continue + } } log.Printf("[DEBUG] Processing database [%d/%d]: %s...\n", idx+1, len(dbs), db.ID().FullyQualifiedName()) diff --git a/pkg/sdk/testint/users_integration_test.go b/pkg/sdk/testint/users_integration_test.go index ea5388c341..60906fe118 100644 --- a/pkg/sdk/testint/users_integration_test.go +++ b/pkg/sdk/testint/users_integration_test.go @@ -6,20 +6,18 @@ import ( "testing" "time" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/collections" - assertions "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/objectassert" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/objectparametersassert" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/helpers/random" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/collections" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // TODO [SNOW-1645875]: test setting/unsetting policies -// TODO [SNOW-1645348]: add type and other 8.26 additions func TestInt_Users(t *testing.T) { client := testClient(t) ctx := testContext(t) @@ -237,6 +235,34 @@ func TestInt_Users(t *testing.T) { ) }) + for _, userType := range sdk.AllUserTypes { + userType := userType + t.Run(fmt.Sprintf("create: type %s - no options", userType), func(t *testing.T) { + id := testClientHelper().Ids.RandomAccountObjectIdentifier() + + err := client.Users.Create(ctx, id, &sdk.CreateUserOptions{ + ObjectProperties: &sdk.UserObjectProperties{ + Type: sdk.Pointer(userType), + }, + }) + require.NoError(t, err) + t.Cleanup(testClientHelper().User.DropUserFunc(t, id)) + + userDetails, err := client.Users.Describe(ctx, id) + require.NoError(t, err) + assert.Equal(t, id.Name(), userDetails.Name.Value) + assert.Equal(t, string(userType), userDetails.Type.Value) + + user, err := client.Users.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.UserFromObject(t, user). + HasDefaults(id.Name()). + HasType(string(userType)), + ) + }) + } + t.Run("create: all object properties", func(t *testing.T) { id := testClientHelper().Ids.RandomAccountObjectIdentifier() currentRole := testClientHelper().Context.CurrentRole(t) @@ -308,6 +334,224 @@ func TestInt_Users(t *testing.T) { ) }) + t.Run("create: all object properties - type service", func(t *testing.T) { + id := testClientHelper().Ids.RandomAccountObjectIdentifier() + currentRole := testClientHelper().Context.CurrentRole(t) + + // omitting FirstName, MiddleName, LastName, Password, MustChangePassword, and MinsToBypassMFA + createOpts := &sdk.CreateUserOptions{ObjectProperties: &sdk.UserObjectProperties{ + LoginName: sdk.String(newValue), + DisplayName: sdk.String(newValue), + Email: sdk.String(email), + Disable: sdk.Bool(true), + DaysToExpiry: sdk.Int(5), + MinsToUnlock: sdk.Int(15), + DefaultWarehouse: sdk.Pointer(warehouseId), + DefaultNamespace: sdk.Pointer(schemaIdObjectIdentifier), + DefaultRole: sdk.Pointer(roleId), + DefaultSecondaryRoles: &sdk.SecondaryRoles{All: sdk.Bool(true)}, + RSAPublicKey: sdk.String(key), + RSAPublicKey2: sdk.String(key2), + Comment: sdk.String("some comment"), + Type: sdk.Pointer(sdk.UserTypeService), + }} + + err := client.Users.Create(ctx, id, createOpts) + require.NoError(t, err) + t.Cleanup(testClientHelper().User.DropUserFunc(t, id)) + + userDetails, err := client.Users.Describe(ctx, id) + require.NoError(t, err) + assert.Equal(t, id.Name(), userDetails.Name.Value) + assert.Equal(t, strings.ToUpper(newValue), userDetails.LoginName.Value) + assert.Equal(t, newValue, userDetails.DisplayName.Value) + assert.Equal(t, email, userDetails.Email.Value) + assert.Equal(t, true, userDetails.Disabled.Value) + assert.NotEmpty(t, userDetails.DaysToExpiry.Value) + assert.Equal(t, 14, *userDetails.MinsToUnlock.Value) + assert.Equal(t, warehouseId.Name(), userDetails.DefaultWarehouse.Value) + assert.Equal(t, fmt.Sprintf("%s.%s", schemaId.DatabaseName(), schemaId.Name()), userDetails.DefaultNamespace.Value) + assert.Equal(t, roleId.Name(), userDetails.DefaultRole.Value) + assert.Equal(t, `["ALL"]`, userDetails.DefaultSecondaryRoles.Value) + assert.Equal(t, "some comment", userDetails.Comment.Value) + assert.Equal(t, string(sdk.UserTypeService), userDetails.Type.Value) + + assert.Equal(t, "", userDetails.FirstName.Value) + assert.Equal(t, "", userDetails.MiddleName.Value) + assert.Equal(t, "", userDetails.LastName.Value) + assert.Equal(t, "", userDetails.Password.Value) + assert.Equal(t, false, userDetails.MustChangePassword.Value) + assert.Nil(t, userDetails.MinsToBypassMfa.Value) + + user, err := client.Users.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.User(t, user.ID()). + HasName(user.Name). + HasType(string(sdk.UserTypeService)). + HasCreatedOnNotEmpty(). + // login name is always case-insensitive + HasLoginName(strings.ToUpper(newValue)). + HasDisplayName(newValue). + HasFirstName(""). + HasLastName(""). + HasEmail(email). + HasMinsToUnlock("14"). + HasDaysToExpiryNotEmpty(). + HasComment("some comment"). + HasDisabled(true). + HasMustChangePassword(false). + HasSnowflakeLock(false). + HasDefaultWarehouse(warehouseId.Name()). + HasDefaultNamespaceId(schemaId). + HasDefaultRole(roleId.Name()). + HasDefaultSecondaryRoles(`["ALL"]`). + HasExtAuthnDuo(false). + HasExtAuthnUid(""). + HasMinsToBypassMfa(""). + HasOwner(currentRole.Name()). + HasLastSuccessLoginEmpty(). + HasExpiresAtTimeNotEmpty(). + HasLockedUntilTimeNotEmpty(). + HasHasPassword(false). + HasHasRsaPublicKey(true), + ) + }) + + t.Run("create: all object properties - type legacy service", func(t *testing.T) { + id := testClientHelper().Ids.RandomAccountObjectIdentifier() + currentRole := testClientHelper().Context.CurrentRole(t) + + // omitting FirstName, MiddleName, LastName, and MinsToBypassMFA + createOpts := &sdk.CreateUserOptions{ObjectProperties: &sdk.UserObjectProperties{ + Password: sdk.String(password), + MustChangePassword: sdk.Bool(true), + LoginName: sdk.String(newValue), + DisplayName: sdk.String(newValue), + Email: sdk.String(email), + Disable: sdk.Bool(true), + DaysToExpiry: sdk.Int(5), + MinsToUnlock: sdk.Int(15), + DefaultWarehouse: sdk.Pointer(warehouseId), + DefaultNamespace: sdk.Pointer(schemaIdObjectIdentifier), + DefaultRole: sdk.Pointer(roleId), + DefaultSecondaryRoles: &sdk.SecondaryRoles{All: sdk.Bool(true)}, + RSAPublicKey: sdk.String(key), + RSAPublicKey2: sdk.String(key2), + Comment: sdk.String("some comment"), + Type: sdk.Pointer(sdk.UserTypeLegacyService), + }} + + err := client.Users.Create(ctx, id, createOpts) + require.NoError(t, err) + t.Cleanup(testClientHelper().User.DropUserFunc(t, id)) + + userDetails, err := client.Users.Describe(ctx, id) + require.NoError(t, err) + assert.Equal(t, id.Name(), userDetails.Name.Value) + assert.Equal(t, strings.ToUpper(newValue), userDetails.LoginName.Value) + assert.Equal(t, newValue, userDetails.DisplayName.Value) + assert.Equal(t, email, userDetails.Email.Value) + assert.Equal(t, true, userDetails.Disabled.Value) + assert.NotEmpty(t, userDetails.DaysToExpiry.Value) + assert.Equal(t, 14, *userDetails.MinsToUnlock.Value) + assert.Equal(t, warehouseId.Name(), userDetails.DefaultWarehouse.Value) + assert.Equal(t, fmt.Sprintf("%s.%s", schemaId.DatabaseName(), schemaId.Name()), userDetails.DefaultNamespace.Value) + assert.Equal(t, roleId.Name(), userDetails.DefaultRole.Value) + assert.Equal(t, `["ALL"]`, userDetails.DefaultSecondaryRoles.Value) + assert.Equal(t, "some comment", userDetails.Comment.Value) + assert.Equal(t, string(sdk.UserTypeLegacyService), userDetails.Type.Value) + assert.NotEmpty(t, userDetails.Password.Value) + assert.Equal(t, true, userDetails.MustChangePassword.Value) + + assert.Equal(t, "", userDetails.FirstName.Value) + assert.Equal(t, "", userDetails.MiddleName.Value) + assert.Equal(t, "", userDetails.LastName.Value) + assert.Nil(t, userDetails.MinsToBypassMfa.Value) + + user, err := client.Users.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.User(t, user.ID()). + HasName(user.Name). + HasType(string(sdk.UserTypeLegacyService)). + HasCreatedOnNotEmpty(). + // login name is always case-insensitive + HasLoginName(strings.ToUpper(newValue)). + HasDisplayName(newValue). + HasFirstName(""). + HasLastName(""). + HasEmail(email). + HasMinsToUnlock("14"). + HasDaysToExpiryNotEmpty(). + HasComment("some comment"). + HasDisabled(true). + HasMustChangePassword(true). + HasSnowflakeLock(false). + HasDefaultWarehouse(warehouseId.Name()). + HasDefaultNamespaceId(schemaId). + HasDefaultRole(roleId.Name()). + HasDefaultSecondaryRoles(`["ALL"]`). + HasExtAuthnDuo(false). + HasExtAuthnUid(""). + HasMinsToBypassMfa(""). + HasOwner(currentRole.Name()). + HasLastSuccessLoginEmpty(). + HasExpiresAtTimeNotEmpty(). + HasLockedUntilTimeNotEmpty(). + HasHasPassword(true). + HasHasRsaPublicKey(true), + ) + }) + + incorrectObjectPropertiesForServiceType := []struct { + property string + userObjectProperties *sdk.UserObjectProperties + }{ + {property: "MINS_TO_BYPASS_MFA", userObjectProperties: &sdk.UserObjectProperties{MinsToBypassMFA: sdk.Int(30)}}, + {property: "MUST_CHANGE_PASSWORD", userObjectProperties: &sdk.UserObjectProperties{MustChangePassword: sdk.Bool(true)}}, + {property: "FIRST_NAME", userObjectProperties: &sdk.UserObjectProperties{FirstName: sdk.String(newValue)}}, + {property: "MIDDLE_NAME", userObjectProperties: &sdk.UserObjectProperties{MiddleName: sdk.String(newValue)}}, + {property: "LAST_NAME", userObjectProperties: &sdk.UserObjectProperties{LastName: sdk.String(newValue)}}, + {property: "PASSWORD", userObjectProperties: &sdk.UserObjectProperties{Password: sdk.String(password)}}, + } + + for _, tt := range incorrectObjectPropertiesForServiceType { + tt := tt + t.Run(fmt.Sprintf("create: incorrect object property %s - type service", tt.property), func(t *testing.T) { + id := testClientHelper().Ids.RandomAccountObjectIdentifier() + + tt.userObjectProperties.Type = sdk.Pointer(sdk.UserTypeService) + createOpts := &sdk.CreateUserOptions{ObjectProperties: tt.userObjectProperties} + + err := client.Users.Create(ctx, id, createOpts) + require.ErrorContains(t, err, fmt.Sprintf("Cannot set %s on users with TYPE=SERVICE.", tt.property)) + }) + } + + incorrectObjectPropertiesForLegacyServiceType := []struct { + property string + userObjectProperties *sdk.UserObjectProperties + }{ + {property: "MINS_TO_BYPASS_MFA", userObjectProperties: &sdk.UserObjectProperties{MinsToBypassMFA: sdk.Int(30)}}, + {property: "FIRST_NAME", userObjectProperties: &sdk.UserObjectProperties{FirstName: sdk.String(newValue)}}, + {property: "MIDDLE_NAME", userObjectProperties: &sdk.UserObjectProperties{MiddleName: sdk.String(newValue)}}, + {property: "LAST_NAME", userObjectProperties: &sdk.UserObjectProperties{LastName: sdk.String(newValue)}}, + } + + for _, tt := range incorrectObjectPropertiesForLegacyServiceType { + tt := tt + t.Run(fmt.Sprintf("create: incorrect object property %s - type legacy service", tt.property), func(t *testing.T) { + id := testClientHelper().Ids.RandomAccountObjectIdentifier() + + tt.userObjectProperties.Type = sdk.Pointer(sdk.UserTypeLegacyService) + createOpts := &sdk.CreateUserOptions{ObjectProperties: tt.userObjectProperties} + + err := client.Users.Create(ctx, id, createOpts) + require.ErrorContains(t, err, fmt.Sprintf("Cannot set %s on users with TYPE=LEGACY_SERVICE.", tt.property)) + }) + } + t.Run("create: set mins to bypass mfa to negative manually", func(t *testing.T) { id := testClientHelper().Ids.RandomAccountObjectIdentifier() @@ -501,87 +745,93 @@ func TestInt_Users(t *testing.T) { assert.Equal(t, randomWithHyphenAndMixedCase, userDetails.DefaultRole.Value) }) - t.Run("create: with all parameters set", func(t *testing.T) { - id := testClientHelper().Ids.RandomAccountObjectIdentifier() - - opts := &sdk.CreateUserOptions{ - SessionParameters: &sdk.SessionParameters{ - AbortDetachedQuery: sdk.Bool(true), - Autocommit: sdk.Bool(false), - BinaryInputFormat: sdk.Pointer(sdk.BinaryInputFormatUTF8), - BinaryOutputFormat: sdk.Pointer(sdk.BinaryOutputFormatBase64), - ClientMemoryLimit: sdk.Int(1024), - ClientMetadataRequestUseConnectionCtx: sdk.Bool(true), - ClientPrefetchThreads: sdk.Int(2), - ClientResultChunkSize: sdk.Int(48), - ClientResultColumnCaseInsensitive: sdk.Bool(true), - ClientSessionKeepAlive: sdk.Bool(true), - ClientSessionKeepAliveHeartbeatFrequency: sdk.Int(2400), - ClientTimestampTypeMapping: sdk.Pointer(sdk.ClientTimestampTypeMappingNtz), - DateInputFormat: sdk.String("YYYY-MM-DD"), - DateOutputFormat: sdk.String("YY-MM-DD"), - EnableUnloadPhysicalTypeOptimization: sdk.Bool(false), - ErrorOnNondeterministicMerge: sdk.Bool(false), - ErrorOnNondeterministicUpdate: sdk.Bool(true), - GeographyOutputFormat: sdk.Pointer(sdk.GeographyOutputFormatWKB), - GeometryOutputFormat: sdk.Pointer(sdk.GeometryOutputFormatWKB), - JdbcTreatDecimalAsInt: sdk.Bool(false), - JdbcTreatTimestampNtzAsUtc: sdk.Bool(true), - JdbcUseSessionTimezone: sdk.Bool(false), - JSONIndent: sdk.Int(4), - LockTimeout: sdk.Int(21222), - LogLevel: sdk.Pointer(sdk.LogLevelError), - MultiStatementCount: sdk.Int(0), - NoorderSequenceAsDefault: sdk.Bool(false), - OdbcTreatDecimalAsInt: sdk.Bool(true), - QueryTag: sdk.String("some_tag"), - QuotedIdentifiersIgnoreCase: sdk.Bool(true), - RowsPerResultset: sdk.Int(2), - S3StageVpceDnsName: sdk.String("vpce-id.s3.region.vpce.amazonaws.com"), - SearchPath: sdk.String("$public, $current"), - SimulatedDataSharingConsumer: sdk.String("some_consumer"), - StatementQueuedTimeoutInSeconds: sdk.Int(10), - StatementTimeoutInSeconds: sdk.Int(10), - StrictJSONOutput: sdk.Bool(true), - TimestampDayIsAlways24h: sdk.Bool(true), - TimestampInputFormat: sdk.String("YYYY-MM-DD"), - TimestampLTZOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), - TimestampNTZOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), - TimestampOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), - TimestampTypeMapping: sdk.Pointer(sdk.TimestampTypeMappingLtz), - TimestampTZOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), - Timezone: sdk.String("Europe/Warsaw"), - TimeInputFormat: sdk.String("HH24:MI"), - TimeOutputFormat: sdk.String("HH24:MI"), - TraceLevel: sdk.Pointer(sdk.TraceLevelOnEvent), - TransactionAbortOnError: sdk.Bool(true), - TransactionDefaultIsolationLevel: sdk.Pointer(sdk.TransactionDefaultIsolationLevelReadCommitted), - TwoDigitCenturyStart: sdk.Int(1980), - UnsupportedDDLAction: sdk.Pointer(sdk.UnsupportedDDLActionFail), - UseCachedResult: sdk.Bool(false), - WeekOfYearPolicy: sdk.Int(1), - WeekStart: sdk.Int(1), - }, - ObjectParameters: &sdk.UserObjectParameters{ - EnableUnredactedQuerySyntaxError: sdk.Bool(true), - NetworkPolicy: sdk.Pointer(networkPolicy.ID()), - PreventUnloadToInternalStages: sdk.Bool(true), - }, - } - - err := client.Users.Create(ctx, id, opts) - require.NoError(t, err) - t.Cleanup(testClientHelper().User.DropUserFunc(t, id)) - - assertParametersSet(objectparametersassert.UserParameters(t, id)) - - // check that ShowParameters works too - parameters, err := client.Users.ShowParameters(ctx, id) - require.NoError(t, err) - assertParametersSet(objectparametersassert.UserParametersPrefetched(t, id, parameters)) - }) - - t.Run("create: with all parameters default", func(t *testing.T) { + for _, userType := range sdk.AllUserTypes { + userType := userType + t.Run(fmt.Sprintf("create: with all parameters set - type %s", userType), func(t *testing.T) { + id := testClientHelper().Ids.RandomAccountObjectIdentifier() + + opts := &sdk.CreateUserOptions{ + ObjectProperties: &sdk.UserObjectProperties{ + Type: sdk.Pointer(userType), + }, + SessionParameters: &sdk.SessionParameters{ + AbortDetachedQuery: sdk.Bool(true), + Autocommit: sdk.Bool(false), + BinaryInputFormat: sdk.Pointer(sdk.BinaryInputFormatUTF8), + BinaryOutputFormat: sdk.Pointer(sdk.BinaryOutputFormatBase64), + ClientMemoryLimit: sdk.Int(1024), + ClientMetadataRequestUseConnectionCtx: sdk.Bool(true), + ClientPrefetchThreads: sdk.Int(2), + ClientResultChunkSize: sdk.Int(48), + ClientResultColumnCaseInsensitive: sdk.Bool(true), + ClientSessionKeepAlive: sdk.Bool(true), + ClientSessionKeepAliveHeartbeatFrequency: sdk.Int(2400), + ClientTimestampTypeMapping: sdk.Pointer(sdk.ClientTimestampTypeMappingNtz), + DateInputFormat: sdk.String("YYYY-MM-DD"), + DateOutputFormat: sdk.String("YY-MM-DD"), + EnableUnloadPhysicalTypeOptimization: sdk.Bool(false), + ErrorOnNondeterministicMerge: sdk.Bool(false), + ErrorOnNondeterministicUpdate: sdk.Bool(true), + GeographyOutputFormat: sdk.Pointer(sdk.GeographyOutputFormatWKB), + GeometryOutputFormat: sdk.Pointer(sdk.GeometryOutputFormatWKB), + JdbcTreatDecimalAsInt: sdk.Bool(false), + JdbcTreatTimestampNtzAsUtc: sdk.Bool(true), + JdbcUseSessionTimezone: sdk.Bool(false), + JSONIndent: sdk.Int(4), + LockTimeout: sdk.Int(21222), + LogLevel: sdk.Pointer(sdk.LogLevelError), + MultiStatementCount: sdk.Int(0), + NoorderSequenceAsDefault: sdk.Bool(false), + OdbcTreatDecimalAsInt: sdk.Bool(true), + QueryTag: sdk.String("some_tag"), + QuotedIdentifiersIgnoreCase: sdk.Bool(true), + RowsPerResultset: sdk.Int(2), + S3StageVpceDnsName: sdk.String("vpce-id.s3.region.vpce.amazonaws.com"), + SearchPath: sdk.String("$public, $current"), + SimulatedDataSharingConsumer: sdk.String("some_consumer"), + StatementQueuedTimeoutInSeconds: sdk.Int(10), + StatementTimeoutInSeconds: sdk.Int(10), + StrictJSONOutput: sdk.Bool(true), + TimestampDayIsAlways24h: sdk.Bool(true), + TimestampInputFormat: sdk.String("YYYY-MM-DD"), + TimestampLTZOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), + TimestampNTZOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), + TimestampOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), + TimestampTypeMapping: sdk.Pointer(sdk.TimestampTypeMappingLtz), + TimestampTZOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), + Timezone: sdk.String("Europe/Warsaw"), + TimeInputFormat: sdk.String("HH24:MI"), + TimeOutputFormat: sdk.String("HH24:MI"), + TraceLevel: sdk.Pointer(sdk.TraceLevelOnEvent), + TransactionAbortOnError: sdk.Bool(true), + TransactionDefaultIsolationLevel: sdk.Pointer(sdk.TransactionDefaultIsolationLevelReadCommitted), + TwoDigitCenturyStart: sdk.Int(1980), + UnsupportedDDLAction: sdk.Pointer(sdk.UnsupportedDDLActionFail), + UseCachedResult: sdk.Bool(false), + WeekOfYearPolicy: sdk.Int(1), + WeekStart: sdk.Int(1), + }, + ObjectParameters: &sdk.UserObjectParameters{ + EnableUnredactedQuerySyntaxError: sdk.Bool(true), + NetworkPolicy: sdk.Pointer(networkPolicy.ID()), + PreventUnloadToInternalStages: sdk.Bool(true), + }, + } + + err := client.Users.Create(ctx, id, opts) + require.NoError(t, err) + t.Cleanup(testClientHelper().User.DropUserFunc(t, id)) + + assertParametersSet(objectparametersassert.UserParameters(t, id)) + + // check that ShowParameters works too + parameters, err := client.Users.ShowParameters(ctx, id) + require.NoError(t, err) + assertParametersSet(objectparametersassert.UserParametersPrefetched(t, id, parameters)) + }) + } + + t.Run("create: with all parameters default", func(t *testing.T) { id := testClientHelper().Ids.RandomAccountObjectIdentifier() err := client.Users.Create(ctx, id, nil) @@ -726,6 +976,366 @@ func TestInt_Users(t *testing.T) { ) }) + t.Run("alter: set and unset object properties - type service", func(t *testing.T) { + user, userCleanup := testClientHelper().User.CreateServiceUser(t) + t.Cleanup(userCleanup) + + currentRole := testClientHelper().Context.CurrentRole(t) + + assertions.AssertThatObject(t, objectassert.UserFromObject(t, user). + HasDefaults(user.Name). + HasDisplayName(user.Name). + HasOwner(currentRole.Name()), + ) + + // omitting FirstName, MiddleName, LastName, Password, MustChangePassword, MinsToBypassMFA, and DisableMfa + alterOpts := &sdk.AlterUserOptions{Set: &sdk.UserSet{ + ObjectProperties: &sdk.UserAlterObjectProperties{ + UserObjectProperties: sdk.UserObjectProperties{ + LoginName: sdk.String(newValue), + DisplayName: sdk.String(newValue), + Email: sdk.String(email), + Disable: sdk.Bool(true), + DaysToExpiry: sdk.Int(5), + MinsToUnlock: sdk.Int(15), + DefaultWarehouse: sdk.Pointer(warehouseId), + DefaultNamespace: sdk.Pointer(schemaIdObjectIdentifier), + DefaultRole: sdk.Pointer(roleId), + DefaultSecondaryRoles: &sdk.SecondaryRoles{All: sdk.Bool(true)}, + RSAPublicKey: sdk.String(key), + RSAPublicKey2: sdk.String(key2), + Comment: sdk.String("some comment"), + }, + }, + }} + + err := client.Users.Alter(ctx, user.ID(), alterOpts) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.User(t, user.ID()). + HasName(user.Name). + HasCreatedOnNotEmpty(). + // login name is always case-insensitive + HasLoginName(strings.ToUpper(newValue)). + HasDisplayName(newValue). + HasFirstName(""). + HasLastName(""). + HasEmail(email). + HasMinsToUnlock("14"). + HasDaysToExpiryNotEmpty(). + HasComment("some comment"). + HasDisabled(true). + HasMustChangePassword(false). + HasSnowflakeLock(false). + HasDefaultWarehouse(warehouseId.Name()). + HasDefaultNamespaceId(schemaId). + HasDefaultRole(roleId.Name()). + HasDefaultSecondaryRoles(`["ALL"]`). + HasExtAuthnDuo(false). + HasExtAuthnUid(""). + HasMinsToBypassMfa(""). + HasOwner(currentRole.Name()). + HasLastSuccessLoginEmpty(). + HasExpiresAtTimeNotEmpty(). + HasLockedUntilTimeNotEmpty(). + HasHasPassword(false). + HasHasRsaPublicKey(true), + ) + + alterOpts = &sdk.AlterUserOptions{Unset: &sdk.UserUnset{ + ObjectProperties: &sdk.UserObjectPropertiesUnset{ + LoginName: sdk.Bool(true), + DisplayName: sdk.Bool(true), + Email: sdk.Bool(true), + Disable: sdk.Bool(true), + DaysToExpiry: sdk.Bool(true), + MinsToUnlock: sdk.Bool(true), + DefaultWarehouse: sdk.Bool(true), + DefaultNamespace: sdk.Bool(true), + DefaultRole: sdk.Bool(true), + DefaultSecondaryRoles: sdk.Bool(true), + RSAPublicKey: sdk.Bool(true), + RSAPublicKey2: sdk.Bool(true), + Comment: sdk.Bool(true), + }, + }} + + err = client.Users.Alter(ctx, user.ID(), alterOpts) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.User(t, user.ID()). + HasDefaults(user.Name). + HasDisplayName(""). + HasOwner(currentRole.Name()), + ) + }) + + t.Run("alter: set and unset object properties - type legacy service", func(t *testing.T) { + user, userCleanup := testClientHelper().User.CreateLegacyServiceUser(t) + t.Cleanup(userCleanup) + + currentRole := testClientHelper().Context.CurrentRole(t) + + assertions.AssertThatObject(t, objectassert.UserFromObject(t, user). + HasDefaults(user.Name). + HasDisplayName(user.Name). + HasOwner(currentRole.Name()), + ) + + // omitting FirstName, MiddleName, LastName, MinsToBypassMFA, and DisableMfa + alterOpts := &sdk.AlterUserOptions{Set: &sdk.UserSet{ + ObjectProperties: &sdk.UserAlterObjectProperties{ + UserObjectProperties: sdk.UserObjectProperties{ + Password: sdk.String(password), + MustChangePassword: sdk.Bool(true), + LoginName: sdk.String(newValue), + DisplayName: sdk.String(newValue), + Email: sdk.String(email), + Disable: sdk.Bool(true), + DaysToExpiry: sdk.Int(5), + MinsToUnlock: sdk.Int(15), + DefaultWarehouse: sdk.Pointer(warehouseId), + DefaultNamespace: sdk.Pointer(schemaIdObjectIdentifier), + DefaultRole: sdk.Pointer(roleId), + DefaultSecondaryRoles: &sdk.SecondaryRoles{All: sdk.Bool(true)}, + RSAPublicKey: sdk.String(key), + RSAPublicKey2: sdk.String(key2), + Comment: sdk.String("some comment"), + }, + }, + }} + + err := client.Users.Alter(ctx, user.ID(), alterOpts) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.User(t, user.ID()). + HasName(user.Name). + HasCreatedOnNotEmpty(). + // login name is always case-insensitive + HasLoginName(strings.ToUpper(newValue)). + HasDisplayName(newValue). + HasFirstName(""). + HasLastName(""). + HasEmail(email). + HasMinsToUnlock("14"). + HasDaysToExpiryNotEmpty(). + HasComment("some comment"). + HasDisabled(true). + HasMustChangePassword(true). + HasSnowflakeLock(false). + HasDefaultWarehouse(warehouseId.Name()). + HasDefaultNamespaceId(schemaId). + HasDefaultRole(roleId.Name()). + HasDefaultSecondaryRoles(`["ALL"]`). + HasExtAuthnDuo(false). + HasExtAuthnUid(""). + HasMinsToBypassMfa(""). + HasOwner(currentRole.Name()). + HasLastSuccessLoginEmpty(). + HasExpiresAtTimeNotEmpty(). + HasLockedUntilTimeNotEmpty(). + HasHasPassword(true). + HasHasRsaPublicKey(true), + ) + + alterOpts = &sdk.AlterUserOptions{Unset: &sdk.UserUnset{ + ObjectProperties: &sdk.UserObjectPropertiesUnset{ + Password: sdk.Bool(true), + MustChangePassword: sdk.Bool(true), + LoginName: sdk.Bool(true), + DisplayName: sdk.Bool(true), + Email: sdk.Bool(true), + Disable: sdk.Bool(true), + DaysToExpiry: sdk.Bool(true), + MinsToUnlock: sdk.Bool(true), + DefaultWarehouse: sdk.Bool(true), + DefaultNamespace: sdk.Bool(true), + DefaultRole: sdk.Bool(true), + DefaultSecondaryRoles: sdk.Bool(true), + RSAPublicKey: sdk.Bool(true), + RSAPublicKey2: sdk.Bool(true), + Comment: sdk.Bool(true), + }, + }} + + err = client.Users.Alter(ctx, user.ID(), alterOpts) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.User(t, user.ID()). + HasDefaults(user.Name). + HasDisplayName(""). + HasOwner(currentRole.Name()), + ) + }) + + t.Run("alter: unset type", func(t *testing.T) { + user, userCleanup := testClientHelper().User.CreateServiceUser(t) + t.Cleanup(userCleanup) + + assertions.AssertThatObject(t, objectassert.UserFromObject(t, user). + HasType(string(sdk.UserTypeService)), + ) + + alterOpts := &sdk.AlterUserOptions{Unset: &sdk.UserUnset{ + ObjectProperties: &sdk.UserObjectPropertiesUnset{ + Type: sdk.Bool(true), + }, + }} + + err := client.Users.Alter(ctx, user.ID(), alterOpts) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.User(t, user.ID()). + HasType(""), + ) + }) + + incorrectAlterForServiceType := []struct { + property string + alterSet *sdk.UserAlterObjectProperties + alterUnset *sdk.UserObjectPropertiesUnset + expectNoUnsetError bool + }{ + { + property: "MINS_TO_BYPASS_MFA", + alterSet: &sdk.UserAlterObjectProperties{UserObjectProperties: sdk.UserObjectProperties{MinsToBypassMFA: sdk.Int(30)}}, + alterUnset: &sdk.UserObjectPropertiesUnset{MinsToBypassMFA: sdk.Bool(true)}, + // unset for MINS_TO_BYPASS_MFA is not returning an error from Snowflake + expectNoUnsetError: true, + }, + { + property: "MUST_CHANGE_PASSWORD", + alterSet: &sdk.UserAlterObjectProperties{UserObjectProperties: sdk.UserObjectProperties{MustChangePassword: sdk.Bool(true)}}, + alterUnset: &sdk.UserObjectPropertiesUnset{MustChangePassword: sdk.Bool(true)}, + }, + { + property: "FIRST_NAME", + alterSet: &sdk.UserAlterObjectProperties{UserObjectProperties: sdk.UserObjectProperties{FirstName: sdk.String(newValue)}}, + alterUnset: &sdk.UserObjectPropertiesUnset{FirstName: sdk.Bool(true)}, + // unset for FIRST_NAME is not returning an error from Snowflake + expectNoUnsetError: true, + }, + { + property: "MIDDLE_NAME", + alterSet: &sdk.UserAlterObjectProperties{UserObjectProperties: sdk.UserObjectProperties{MiddleName: sdk.String(newValue)}}, + alterUnset: &sdk.UserObjectPropertiesUnset{MiddleName: sdk.Bool(true)}, + // unset for MIDDLE_NAME is not returning an error from Snowflake + expectNoUnsetError: true, + }, + { + property: "LAST_NAME", + alterSet: &sdk.UserAlterObjectProperties{UserObjectProperties: sdk.UserObjectProperties{LastName: sdk.String(newValue)}}, + alterUnset: &sdk.UserObjectPropertiesUnset{LastName: sdk.Bool(true)}, + // unset for LAST_NAME is not returning an error from Snowflake + expectNoUnsetError: true, + }, + { + property: "PASSWORD", + alterSet: &sdk.UserAlterObjectProperties{UserObjectProperties: sdk.UserObjectProperties{Password: sdk.String(password)}}, + alterUnset: &sdk.UserObjectPropertiesUnset{Password: sdk.Bool(true)}, + // unset for PASSWORD is not returning an error from Snowflake + expectNoUnsetError: true, + }, + { + property: "DISABLE_MFA", + alterSet: &sdk.UserAlterObjectProperties{DisableMfa: sdk.Bool(true)}, + alterUnset: &sdk.UserObjectPropertiesUnset{DisableMfa: sdk.Bool(true)}, + }, + } + + for _, tt := range incorrectAlterForServiceType { + tt := tt + t.Run(fmt.Sprintf("alter: set and unset incorrect object property %s - type service", tt.property), func(t *testing.T) { + serviceUser, serviceUserCleanup := testClientHelper().User.CreateServiceUser(t) + t.Cleanup(serviceUserCleanup) + + alterSet := &sdk.AlterUserOptions{Set: &sdk.UserSet{ + ObjectProperties: tt.alterSet, + }} + + err := client.Users.Alter(ctx, serviceUser.ID(), alterSet) + require.ErrorContains(t, err, fmt.Sprintf("Cannot set %s on users with TYPE=SERVICE.", tt.property)) + + alterUnset := &sdk.AlterUserOptions{Unset: &sdk.UserUnset{ + ObjectProperties: tt.alterUnset, + }} + + err = client.Users.Alter(ctx, serviceUser.ID(), alterUnset) + if tt.expectNoUnsetError { + require.Nil(t, err) + } else { + require.ErrorContains(t, err, fmt.Sprintf("Cannot set %s on users with TYPE=SERVICE.", tt.property)) + } + }) + } + + incorrectAlterForLegacyServiceType := []struct { + property string + alterSet *sdk.UserAlterObjectProperties + alterUnset *sdk.UserObjectPropertiesUnset + expectNoUnsetError bool + }{ + { + property: "MINS_TO_BYPASS_MFA", + alterSet: &sdk.UserAlterObjectProperties{UserObjectProperties: sdk.UserObjectProperties{MinsToBypassMFA: sdk.Int(30)}}, + alterUnset: &sdk.UserObjectPropertiesUnset{MinsToBypassMFA: sdk.Bool(true)}, + // unset for MINS_TO_BYPASS_MFA is not returning an error from Snowflake + expectNoUnsetError: true, + }, + { + property: "FIRST_NAME", + alterSet: &sdk.UserAlterObjectProperties{UserObjectProperties: sdk.UserObjectProperties{FirstName: sdk.String(newValue)}}, + alterUnset: &sdk.UserObjectPropertiesUnset{FirstName: sdk.Bool(true)}, + // unset for FIRST_NAME is not returning an error from Snowflake + expectNoUnsetError: true, + }, + { + property: "MIDDLE_NAME", + alterSet: &sdk.UserAlterObjectProperties{UserObjectProperties: sdk.UserObjectProperties{MiddleName: sdk.String(newValue)}}, + alterUnset: &sdk.UserObjectPropertiesUnset{MiddleName: sdk.Bool(true)}, + // unset for MIDDLE_NAME is not returning an error from Snowflake + expectNoUnsetError: true, + }, + { + property: "LAST_NAME", + alterSet: &sdk.UserAlterObjectProperties{UserObjectProperties: sdk.UserObjectProperties{LastName: sdk.String(newValue)}}, + alterUnset: &sdk.UserObjectPropertiesUnset{LastName: sdk.Bool(true)}, + // unset for LAST_NAME is not returning an error from Snowflake + expectNoUnsetError: true, + }, + { + property: "DISABLE_MFA", + alterSet: &sdk.UserAlterObjectProperties{DisableMfa: sdk.Bool(true)}, + alterUnset: &sdk.UserObjectPropertiesUnset{DisableMfa: sdk.Bool(true)}, + }, + } + + for _, tt := range incorrectAlterForLegacyServiceType { + tt := tt + t.Run(fmt.Sprintf("alter: set and unset incorrect object property %s - type legacy service", tt.property), func(t *testing.T) { + legacyServiceUser, legacyServiceUserCleanup := testClientHelper().User.CreateLegacyServiceUser(t) + t.Cleanup(legacyServiceUserCleanup) + + alterSet := &sdk.AlterUserOptions{Set: &sdk.UserSet{ + ObjectProperties: tt.alterSet, + }} + + err := client.Users.Alter(ctx, legacyServiceUser.ID(), alterSet) + require.ErrorContains(t, err, fmt.Sprintf("Cannot set %s on users with TYPE=LEGACY_SERVICE.", tt.property)) + + alterUnset := &sdk.AlterUserOptions{Unset: &sdk.UserUnset{ + ObjectProperties: tt.alterUnset, + }} + + err = client.Users.Alter(ctx, legacyServiceUser.ID(), alterUnset) + if tt.expectNoUnsetError { + require.Nil(t, err) + } else { + require.ErrorContains(t, err, fmt.Sprintf("Cannot set %s on users with TYPE=LEGACY_SERVICE.", tt.property)) + } + }) + } + t.Run("set and unset authentication policy", func(t *testing.T) { authenticationPolicyTest, authenticationPolicyCleanup := testClientHelper().AuthenticationPolicy.Create(t) t.Cleanup(authenticationPolicyCleanup) @@ -761,173 +1371,180 @@ func TestInt_Users(t *testing.T) { require.ErrorIs(t, err, sdk.ErrObjectNotFound) }) - t.Run("alter: set and unset parameters", func(t *testing.T) { - id := testClientHelper().Ids.RandomAccountObjectIdentifier() - - err := client.Users.Create(ctx, id, nil) - require.NoError(t, err) - t.Cleanup(testClientHelper().User.DropUserFunc(t, id)) + for _, userType := range sdk.AllUserTypes { + userType := userType + t.Run(fmt.Sprintf("alter: set and unset parameters - type %s", userType), func(t *testing.T) { + id := testClientHelper().Ids.RandomAccountObjectIdentifier() - alterOpts := &sdk.AlterUserOptions{ - Set: &sdk.UserSet{ - SessionParameters: &sdk.SessionParameters{ - AbortDetachedQuery: sdk.Bool(true), - Autocommit: sdk.Bool(false), - BinaryInputFormat: sdk.Pointer(sdk.BinaryInputFormatUTF8), - BinaryOutputFormat: sdk.Pointer(sdk.BinaryOutputFormatBase64), - ClientMemoryLimit: sdk.Int(1024), - ClientMetadataRequestUseConnectionCtx: sdk.Bool(true), - ClientPrefetchThreads: sdk.Int(2), - ClientResultChunkSize: sdk.Int(48), - ClientResultColumnCaseInsensitive: sdk.Bool(true), - ClientSessionKeepAlive: sdk.Bool(true), - ClientSessionKeepAliveHeartbeatFrequency: sdk.Int(2400), - ClientTimestampTypeMapping: sdk.Pointer(sdk.ClientTimestampTypeMappingNtz), - DateInputFormat: sdk.String("YYYY-MM-DD"), - DateOutputFormat: sdk.String("YY-MM-DD"), - EnableUnloadPhysicalTypeOptimization: sdk.Bool(false), - ErrorOnNondeterministicMerge: sdk.Bool(false), - ErrorOnNondeterministicUpdate: sdk.Bool(true), - GeographyOutputFormat: sdk.Pointer(sdk.GeographyOutputFormatWKB), - GeometryOutputFormat: sdk.Pointer(sdk.GeometryOutputFormatWKB), - JdbcTreatDecimalAsInt: sdk.Bool(false), - JdbcTreatTimestampNtzAsUtc: sdk.Bool(true), - JdbcUseSessionTimezone: sdk.Bool(false), - JSONIndent: sdk.Int(4), - LockTimeout: sdk.Int(21222), - LogLevel: sdk.Pointer(sdk.LogLevelError), - MultiStatementCount: sdk.Int(0), - NoorderSequenceAsDefault: sdk.Bool(false), - OdbcTreatDecimalAsInt: sdk.Bool(true), - QueryTag: sdk.String("some_tag"), - QuotedIdentifiersIgnoreCase: sdk.Bool(true), - RowsPerResultset: sdk.Int(2), - S3StageVpceDnsName: sdk.String("vpce-id.s3.region.vpce.amazonaws.com"), - SearchPath: sdk.String("$public, $current"), - SimulatedDataSharingConsumer: sdk.String("some_consumer"), - StatementQueuedTimeoutInSeconds: sdk.Int(10), - StatementTimeoutInSeconds: sdk.Int(10), - StrictJSONOutput: sdk.Bool(true), - TimestampDayIsAlways24h: sdk.Bool(true), - TimestampInputFormat: sdk.String("YYYY-MM-DD"), - TimestampLTZOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), - TimestampNTZOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), - TimestampOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), - TimestampTypeMapping: sdk.Pointer(sdk.TimestampTypeMappingLtz), - TimestampTZOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), - Timezone: sdk.String("Europe/Warsaw"), - TimeInputFormat: sdk.String("HH24:MI"), - TimeOutputFormat: sdk.String("HH24:MI"), - TraceLevel: sdk.Pointer(sdk.TraceLevelOnEvent), - TransactionAbortOnError: sdk.Bool(true), - TransactionDefaultIsolationLevel: sdk.Pointer(sdk.TransactionDefaultIsolationLevelReadCommitted), - TwoDigitCenturyStart: sdk.Int(1980), - UnsupportedDDLAction: sdk.Pointer(sdk.UnsupportedDDLActionFail), - UseCachedResult: sdk.Bool(false), - WeekOfYearPolicy: sdk.Int(1), - WeekStart: sdk.Int(1), + err := client.Users.Create(ctx, id, &sdk.CreateUserOptions{ + ObjectProperties: &sdk.UserObjectProperties{ + Type: sdk.Pointer(userType), }, - ObjectParameters: &sdk.UserObjectParameters{ - EnableUnredactedQuerySyntaxError: sdk.Bool(true), - NetworkPolicy: sdk.Pointer(networkPolicy.ID()), - PreventUnloadToInternalStages: sdk.Bool(true), - }, - }, - } - - err = client.Users.Alter(ctx, id, alterOpts) - require.NoError(t, err) - - assertParametersSet(objectparametersassert.UserParameters(t, id)) - - // check that ShowParameters works too - parameters, err := client.Users.ShowParameters(ctx, id) - require.NoError(t, err) - assertParametersSet(objectparametersassert.UserParametersPrefetched(t, id, parameters)) + }) + require.NoError(t, err) + t.Cleanup(testClientHelper().User.DropUserFunc(t, id)) - alterOpts = &sdk.AlterUserOptions{ - Unset: &sdk.UserUnset{ - SessionParameters: &sdk.SessionParametersUnset{ - AbortDetachedQuery: sdk.Bool(true), - Autocommit: sdk.Bool(true), - BinaryInputFormat: sdk.Bool(true), - BinaryOutputFormat: sdk.Bool(true), - ClientMemoryLimit: sdk.Bool(true), - ClientMetadataRequestUseConnectionCtx: sdk.Bool(true), - ClientPrefetchThreads: sdk.Bool(true), - ClientResultChunkSize: sdk.Bool(true), - ClientResultColumnCaseInsensitive: sdk.Bool(true), - ClientSessionKeepAlive: sdk.Bool(true), - ClientSessionKeepAliveHeartbeatFrequency: sdk.Bool(true), - ClientTimestampTypeMapping: sdk.Bool(true), - DateInputFormat: sdk.Bool(true), - DateOutputFormat: sdk.Bool(true), - EnableUnloadPhysicalTypeOptimization: sdk.Bool(true), - ErrorOnNondeterministicMerge: sdk.Bool(true), - ErrorOnNondeterministicUpdate: sdk.Bool(true), - GeographyOutputFormat: sdk.Bool(true), - GeometryOutputFormat: sdk.Bool(true), - JdbcTreatDecimalAsInt: sdk.Bool(true), - JdbcTreatTimestampNtzAsUtc: sdk.Bool(true), - JdbcUseSessionTimezone: sdk.Bool(true), - JSONIndent: sdk.Bool(true), - LockTimeout: sdk.Bool(true), - LogLevel: sdk.Bool(true), - MultiStatementCount: sdk.Bool(true), - NoorderSequenceAsDefault: sdk.Bool(true), - OdbcTreatDecimalAsInt: sdk.Bool(true), - QueryTag: sdk.Bool(true), - QuotedIdentifiersIgnoreCase: sdk.Bool(true), - RowsPerResultset: sdk.Bool(true), - S3StageVpceDnsName: sdk.Bool(true), - SearchPath: sdk.Bool(true), - SimulatedDataSharingConsumer: sdk.Bool(true), - StatementQueuedTimeoutInSeconds: sdk.Bool(true), - StatementTimeoutInSeconds: sdk.Bool(true), - StrictJSONOutput: sdk.Bool(true), - TimestampDayIsAlways24h: sdk.Bool(true), - TimestampInputFormat: sdk.Bool(true), - TimestampLTZOutputFormat: sdk.Bool(true), - TimestampNTZOutputFormat: sdk.Bool(true), - TimestampOutputFormat: sdk.Bool(true), - TimestampTypeMapping: sdk.Bool(true), - TimestampTZOutputFormat: sdk.Bool(true), - Timezone: sdk.Bool(true), - TimeInputFormat: sdk.Bool(true), - TimeOutputFormat: sdk.Bool(true), - TraceLevel: sdk.Bool(true), - TransactionAbortOnError: sdk.Bool(true), - TransactionDefaultIsolationLevel: sdk.Bool(true), - TwoDigitCenturyStart: sdk.Bool(true), - UnsupportedDDLAction: sdk.Bool(true), - UseCachedResult: sdk.Bool(true), - WeekOfYearPolicy: sdk.Bool(true), - WeekStart: sdk.Bool(true), + alterOpts := &sdk.AlterUserOptions{ + Set: &sdk.UserSet{ + SessionParameters: &sdk.SessionParameters{ + AbortDetachedQuery: sdk.Bool(true), + Autocommit: sdk.Bool(false), + BinaryInputFormat: sdk.Pointer(sdk.BinaryInputFormatUTF8), + BinaryOutputFormat: sdk.Pointer(sdk.BinaryOutputFormatBase64), + ClientMemoryLimit: sdk.Int(1024), + ClientMetadataRequestUseConnectionCtx: sdk.Bool(true), + ClientPrefetchThreads: sdk.Int(2), + ClientResultChunkSize: sdk.Int(48), + ClientResultColumnCaseInsensitive: sdk.Bool(true), + ClientSessionKeepAlive: sdk.Bool(true), + ClientSessionKeepAliveHeartbeatFrequency: sdk.Int(2400), + ClientTimestampTypeMapping: sdk.Pointer(sdk.ClientTimestampTypeMappingNtz), + DateInputFormat: sdk.String("YYYY-MM-DD"), + DateOutputFormat: sdk.String("YY-MM-DD"), + EnableUnloadPhysicalTypeOptimization: sdk.Bool(false), + ErrorOnNondeterministicMerge: sdk.Bool(false), + ErrorOnNondeterministicUpdate: sdk.Bool(true), + GeographyOutputFormat: sdk.Pointer(sdk.GeographyOutputFormatWKB), + GeometryOutputFormat: sdk.Pointer(sdk.GeometryOutputFormatWKB), + JdbcTreatDecimalAsInt: sdk.Bool(false), + JdbcTreatTimestampNtzAsUtc: sdk.Bool(true), + JdbcUseSessionTimezone: sdk.Bool(false), + JSONIndent: sdk.Int(4), + LockTimeout: sdk.Int(21222), + LogLevel: sdk.Pointer(sdk.LogLevelError), + MultiStatementCount: sdk.Int(0), + NoorderSequenceAsDefault: sdk.Bool(false), + OdbcTreatDecimalAsInt: sdk.Bool(true), + QueryTag: sdk.String("some_tag"), + QuotedIdentifiersIgnoreCase: sdk.Bool(true), + RowsPerResultset: sdk.Int(2), + S3StageVpceDnsName: sdk.String("vpce-id.s3.region.vpce.amazonaws.com"), + SearchPath: sdk.String("$public, $current"), + SimulatedDataSharingConsumer: sdk.String("some_consumer"), + StatementQueuedTimeoutInSeconds: sdk.Int(10), + StatementTimeoutInSeconds: sdk.Int(10), + StrictJSONOutput: sdk.Bool(true), + TimestampDayIsAlways24h: sdk.Bool(true), + TimestampInputFormat: sdk.String("YYYY-MM-DD"), + TimestampLTZOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), + TimestampNTZOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), + TimestampOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), + TimestampTypeMapping: sdk.Pointer(sdk.TimestampTypeMappingLtz), + TimestampTZOutputFormat: sdk.String("YYYY-MM-DD HH24:MI:SS"), + Timezone: sdk.String("Europe/Warsaw"), + TimeInputFormat: sdk.String("HH24:MI"), + TimeOutputFormat: sdk.String("HH24:MI"), + TraceLevel: sdk.Pointer(sdk.TraceLevelOnEvent), + TransactionAbortOnError: sdk.Bool(true), + TransactionDefaultIsolationLevel: sdk.Pointer(sdk.TransactionDefaultIsolationLevelReadCommitted), + TwoDigitCenturyStart: sdk.Int(1980), + UnsupportedDDLAction: sdk.Pointer(sdk.UnsupportedDDLActionFail), + UseCachedResult: sdk.Bool(false), + WeekOfYearPolicy: sdk.Int(1), + WeekStart: sdk.Int(1), + }, + ObjectParameters: &sdk.UserObjectParameters{ + EnableUnredactedQuerySyntaxError: sdk.Bool(true), + NetworkPolicy: sdk.Pointer(networkPolicy.ID()), + PreventUnloadToInternalStages: sdk.Bool(true), + }, }, - ObjectParameters: &sdk.UserObjectParametersUnset{ - EnableUnredactedQuerySyntaxError: sdk.Bool(true), - NetworkPolicy: sdk.Bool(true), - PreventUnloadToInternalStages: sdk.Bool(true), + } + + err = client.Users.Alter(ctx, id, alterOpts) + require.NoError(t, err) + + assertParametersSet(objectparametersassert.UserParameters(t, id)) + + // check that ShowParameters works too + parameters, err := client.Users.ShowParameters(ctx, id) + require.NoError(t, err) + assertParametersSet(objectparametersassert.UserParametersPrefetched(t, id, parameters)) + + alterOpts = &sdk.AlterUserOptions{ + Unset: &sdk.UserUnset{ + SessionParameters: &sdk.SessionParametersUnset{ + AbortDetachedQuery: sdk.Bool(true), + Autocommit: sdk.Bool(true), + BinaryInputFormat: sdk.Bool(true), + BinaryOutputFormat: sdk.Bool(true), + ClientMemoryLimit: sdk.Bool(true), + ClientMetadataRequestUseConnectionCtx: sdk.Bool(true), + ClientPrefetchThreads: sdk.Bool(true), + ClientResultChunkSize: sdk.Bool(true), + ClientResultColumnCaseInsensitive: sdk.Bool(true), + ClientSessionKeepAlive: sdk.Bool(true), + ClientSessionKeepAliveHeartbeatFrequency: sdk.Bool(true), + ClientTimestampTypeMapping: sdk.Bool(true), + DateInputFormat: sdk.Bool(true), + DateOutputFormat: sdk.Bool(true), + EnableUnloadPhysicalTypeOptimization: sdk.Bool(true), + ErrorOnNondeterministicMerge: sdk.Bool(true), + ErrorOnNondeterministicUpdate: sdk.Bool(true), + GeographyOutputFormat: sdk.Bool(true), + GeometryOutputFormat: sdk.Bool(true), + JdbcTreatDecimalAsInt: sdk.Bool(true), + JdbcTreatTimestampNtzAsUtc: sdk.Bool(true), + JdbcUseSessionTimezone: sdk.Bool(true), + JSONIndent: sdk.Bool(true), + LockTimeout: sdk.Bool(true), + LogLevel: sdk.Bool(true), + MultiStatementCount: sdk.Bool(true), + NoorderSequenceAsDefault: sdk.Bool(true), + OdbcTreatDecimalAsInt: sdk.Bool(true), + QueryTag: sdk.Bool(true), + QuotedIdentifiersIgnoreCase: sdk.Bool(true), + RowsPerResultset: sdk.Bool(true), + S3StageVpceDnsName: sdk.Bool(true), + SearchPath: sdk.Bool(true), + SimulatedDataSharingConsumer: sdk.Bool(true), + StatementQueuedTimeoutInSeconds: sdk.Bool(true), + StatementTimeoutInSeconds: sdk.Bool(true), + StrictJSONOutput: sdk.Bool(true), + TimestampDayIsAlways24h: sdk.Bool(true), + TimestampInputFormat: sdk.Bool(true), + TimestampLTZOutputFormat: sdk.Bool(true), + TimestampNTZOutputFormat: sdk.Bool(true), + TimestampOutputFormat: sdk.Bool(true), + TimestampTypeMapping: sdk.Bool(true), + TimestampTZOutputFormat: sdk.Bool(true), + Timezone: sdk.Bool(true), + TimeInputFormat: sdk.Bool(true), + TimeOutputFormat: sdk.Bool(true), + TraceLevel: sdk.Bool(true), + TransactionAbortOnError: sdk.Bool(true), + TransactionDefaultIsolationLevel: sdk.Bool(true), + TwoDigitCenturyStart: sdk.Bool(true), + UnsupportedDDLAction: sdk.Bool(true), + UseCachedResult: sdk.Bool(true), + WeekOfYearPolicy: sdk.Bool(true), + WeekStart: sdk.Bool(true), + }, + ObjectParameters: &sdk.UserObjectParametersUnset{ + EnableUnredactedQuerySyntaxError: sdk.Bool(true), + NetworkPolicy: sdk.Bool(true), + PreventUnloadToInternalStages: sdk.Bool(true), + }, }, - }, - } - - err = client.Users.Alter(ctx, id, alterOpts) - require.NoError(t, err) - - assertions.AssertThatObject(t, objectparametersassert.UserParameters(t, id). - HasAllDefaults(). - HasAllDefaultsExplicit(), - ) - - // check that ShowParameters works too - parameters, err = client.Users.ShowParameters(ctx, id) - require.NoError(t, err) - assertions.AssertThatObject(t, objectparametersassert.UserParametersPrefetched(t, id, parameters). - HasAllDefaults(). - HasAllDefaultsExplicit(), - ) - }) + } + + err = client.Users.Alter(ctx, id, alterOpts) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectparametersassert.UserParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + + // check that ShowParameters works too + parameters, err = client.Users.ShowParameters(ctx, id) + require.NoError(t, err) + assertions.AssertThatObject(t, objectparametersassert.UserParametersPrefetched(t, id, parameters). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) + } t.Run("alter: set and unset properties and parameters at the same time", func(t *testing.T) { user, userCleanup := testClientHelper().User.CreateUser(t) diff --git a/pkg/sdk/users.go b/pkg/sdk/users.go index ba56f23a92..263d80198e 100644 --- a/pkg/sdk/users.go +++ b/pkg/sdk/users.go @@ -107,9 +107,8 @@ type userDBRow struct { LockedUntilTime sql.NullTime `db:"locked_until_time"` HasPassword bool `db:"has_password"` HasRsaPublicKey bool `db:"has_rsa_public_key"` - // TODO [SNOW-1645348]: test type thoroughly - Type sql.NullString `db:"type"` - HasMfa bool `db:"has_mfa"` + Type sql.NullString `db:"type"` + HasMfa bool `db:"has_mfa"` } func (row userDBRow) convert() *User { @@ -249,6 +248,7 @@ type UserObjectProperties struct { RSAPublicKeyFp *string `ddl:"parameter,single_quotes" sql:"RSA_PUBLIC_KEY_FP"` RSAPublicKey2 *string `ddl:"parameter,single_quotes" sql:"RSA_PUBLIC_KEY_2"` RSAPublicKey2Fp *string `ddl:"parameter,single_quotes" sql:"RSA_PUBLIC_KEY_2_FP"` + Type *UserType `ddl:"parameter,no_quotes" sql:"TYPE"` Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` } @@ -285,6 +285,7 @@ type UserObjectPropertiesUnset struct { DisableMfa *bool `ddl:"keyword" sql:"DISABLE_MFA"` RSAPublicKey *bool `ddl:"keyword" sql:"RSA_PUBLIC_KEY"` RSAPublicKey2 *bool `ddl:"keyword" sql:"RSA_PUBLIC_KEY_2"` + Type *bool `ddl:"keyword" sql:"TYPE"` Comment *bool `ddl:"keyword" sql:"COMMENT"` } @@ -486,6 +487,7 @@ type UserDetails struct { Name *StringProperty Comment *StringProperty DisplayName *StringProperty + Type *StringProperty LoginName *StringProperty FirstName *StringProperty MiddleName *StringProperty @@ -508,8 +510,10 @@ type UserDetails struct { MinsToBypassNetworkPolicy *IntProperty RsaPublicKey *StringProperty RsaPublicKeyFp *StringProperty + RsaPublicKeyLastSetTime *StringProperty RsaPublicKey2 *StringProperty RsaPublicKey2Fp *StringProperty + RsaPublicKey2LastSetTime *StringProperty PasswordLastSetTime *StringProperty CustomLandingPageUrl *StringProperty CustomLandingPageUrlFlushNextUiLoad *BoolProperty @@ -526,6 +530,8 @@ func userDetailsFromRows(rows []propertyRow) *UserDetails { v.Comment = row.toStringProperty() case "DISPLAY_NAME": v.DisplayName = row.toStringProperty() + case "TYPE": + v.Type = row.toStringProperty() case "LOGIN_NAME": v.LoginName = row.toStringProperty() case "FIRST_NAME": @@ -562,6 +568,8 @@ func userDetailsFromRows(rows []propertyRow) *UserDetails { v.ExtAuthnDuo = row.toBoolProperty() case "EXT_AUTHN_UID": v.ExtAuthnUid = row.toStringProperty() + case "HAS_MFA": + v.HasMfa = row.toBoolProperty() case "MINS_TO_BYPASS_MFA": v.MinsToBypassMfa = row.toIntProperty() case "MINS_TO_BYPASS_NETWORK_POLICY": @@ -570,18 +578,20 @@ func userDetailsFromRows(rows []propertyRow) *UserDetails { v.RsaPublicKey = row.toStringProperty() case "RSA_PUBLIC_KEY_FP": v.RsaPublicKeyFp = row.toStringProperty() + case "RSA_PUBLIC_KEY_LAST_SET_TIME": + v.RsaPublicKeyLastSetTime = row.toStringProperty() case "RSA_PUBLIC_KEY_2": v.RsaPublicKey2 = row.toStringProperty() case "RSA_PUBLIC_KEY_2_FP": v.RsaPublicKey2Fp = row.toStringProperty() + case "RSA_PUBLIC_KEY_2_LAST_SET_TIME": + v.RsaPublicKey2LastSetTime = row.toStringProperty() case "PASSWORD_LAST_SET_TIME": v.PasswordLastSetTime = row.toStringProperty() case "CUSTOM_LANDING_PAGE_URL": v.CustomLandingPageUrl = row.toStringProperty() case "CUSTOM_LANDING_PAGE_URL_FLUSH_NEXT_UI_LOAD": v.CustomLandingPageUrlFlushNextUiLoad = row.toBoolProperty() - case "HAS_MFA": - v.HasMfa = row.toBoolProperty() } } return v @@ -705,3 +715,36 @@ var ValidSecondaryRolesOptionsString = []string{ string(SecondaryRolesOptionNone), string(SecondaryRolesOptionAll), } + +type UserType string + +const ( + UserTypePerson UserType = "PERSON" + UserTypeService UserType = "SERVICE" + UserTypeLegacyService UserType = "LEGACY_SERVICE" +) + +func ToUserType(s string) (UserType, error) { + switch strings.ToUpper(s) { + case string(UserTypePerson): + return UserTypePerson, nil + case string(UserTypeService): + return UserTypeService, nil + case string(UserTypeLegacyService): + return UserTypeLegacyService, nil + default: + return "", fmt.Errorf("invalid user type: %s", s) + } +} + +var AllUserTypes = []UserType{ + UserTypePerson, + UserTypeService, + UserTypeLegacyService, +} + +var AcceptableUserTypes = map[UserType][]string{ + UserTypePerson: {"", string(UserTypePerson)}, + UserTypeService: {string(UserTypeService)}, + UserTypeLegacyService: {string(UserTypeLegacyService)}, +} diff --git a/pkg/sdk/users_test.go b/pkg/sdk/users_test.go index 74fd0851fa..952ac868c2 100644 --- a/pkg/sdk/users_test.go +++ b/pkg/sdk/users_test.go @@ -57,7 +57,17 @@ func TestUserCreate(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("SecondaryRoles", "All", "None")) }) - t.Run("with complete options", func(t *testing.T) { + t.Run("with type", func(t *testing.T) { + opts := &CreateUserOptions{ + name: id, + ObjectProperties: &UserObjectProperties{ + Type: Pointer(UserTypeLegacyService), + }, + } + assertOptsValidAndSQLEquals(t, opts, `CREATE USER %s TYPE = LEGACY_SERVICE`, id.FullyQualifiedName()) + }) + + t.Run("with complete options - no type", func(t *testing.T) { tagId := randomSchemaObjectIdentifier() tags := []TagAssociation{ { @@ -155,6 +165,16 @@ func TestUserAlter(t *testing.T) { assertOptsValidAndSQLEquals(t, opts, "ALTER USER %s SET ENABLE_UNREDACTED_QUERY_SYNTAX_ERROR = true ABORT_DETACHED_QUERY = true", id.FullyQualifiedName()) }) + t.Run("set type", func(t *testing.T) { + opts := &AlterUserOptions{ + name: id, + Set: &UserSet{ + ObjectProperties: &UserAlterObjectProperties{UserObjectProperties: UserObjectProperties{Type: Pointer(UserTypeLegacyService)}}, + }, + } + assertOptsValidAndSQLEquals(t, opts, "ALTER USER %s SET TYPE = LEGACY_SERVICE", id.FullyQualifiedName()) + }) + t.Run("validation: no unset", func(t *testing.T) { opts := &AlterUserOptions{ name: id, @@ -174,6 +194,16 @@ func TestUserAlter(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errors.New("policies cannot be unset with user properties or parameters at the same time")) }) + t.Run("alter: unset type", func(t *testing.T) { + opts := &AlterUserOptions{ + name: id, + Unset: &UserUnset{ + ObjectProperties: &UserObjectPropertiesUnset{Type: Bool(true)}, + }, + } + assertOptsValidAndSQLEquals(t, opts, "ALTER USER %s UNSET TYPE", id.FullyQualifiedName()) + }) + t.Run("validation: unset two policies", func(t *testing.T) { opts := &AlterUserOptions{ name: id, @@ -919,3 +949,42 @@ func Test_User_GetSecondaryRolesOptionFrom(t *testing.T) { }) } } + +func Test_User_ToUserType(t *testing.T) { + type test struct { + input string + want UserType + } + + valid := []test{ + // case insensitive. + {input: "person", want: UserTypePerson}, + + // Supported Values + {input: "PERSON", want: UserTypePerson}, + {input: "SERVICE", want: UserTypeService}, + {input: "LEGACY_SERVICE", want: UserTypeLegacyService}, + } + + invalid := []test{ + // bad values + {input: ""}, + {input: "foo"}, + {input: "legacyservice"}, + } + + for _, tc := range valid { + t.Run(tc.input, func(t *testing.T) { + got, err := ToUserType(tc.input) + require.NoError(t, err) + require.Equal(t, tc.want, got) + }) + } + + for _, tc := range invalid { + t.Run(tc.input, func(t *testing.T) { + _, err := ToUserType(tc.input) + require.Error(t, err) + }) + } +} diff --git a/templates/resources/legacy_service_user.md.tmpl b/templates/resources/legacy_service_user.md.tmpl new file mode 100644 index 0000000000..c07fef3dc5 --- /dev/null +++ b/templates/resources/legacy_service_user.md.tmpl @@ -0,0 +1,43 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +description: |- +{{ if gt (len (split .Description "")) 1 -}} +{{ index (split .Description "") 1 | plainmarkdown | trimspace | prefixlines " " }} +{{- else -}} +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +{{- end }} +--- + +!> **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#v0960--v0970) 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** Other two user types are handled in separate resources: `snowflake_service_user` for user type `service` and `snowflake_user` for user type `person`. + +-> **Note** External changes to `days_to_expiry` and `mins_to_unlock` are not currently handled by the provider (because the value changes continuously on Snowflake side after setting it). + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +{{ if .HasExample -}} +## Example Usage + +{{ tffile (printf "examples/resources/%s/resource.tf" .Name)}} +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + + +{{- end }} + +{{ .SchemaMarkdown | trimspace }} +{{- if .HasImport }} + +## Import + +Import is supported using the following syntax: + +{{ codefile "shell" (printf "examples/resources/%s/import.sh" .Name)}} +{{- end }} diff --git a/templates/resources/service_user.md.tmpl b/templates/resources/service_user.md.tmpl new file mode 100644 index 0000000000..0072836bfc --- /dev/null +++ b/templates/resources/service_user.md.tmpl @@ -0,0 +1,43 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +description: |- +{{ if gt (len (split .Description "")) 1 -}} +{{ index (split .Description "") 1 | plainmarkdown | trimspace | prefixlines " " }} +{{- else -}} +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +{{- end }} +--- + +!> **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#v0960--v0970) 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** Other two user types are handled in separate resources: `snowflake_legacy_service_user` for user type `legacy_service` and `snowflake_user` for user type `person`. + +-> **Note** External changes to `days_to_expiry` and `mins_to_unlock` are not currently handled by the provider (because the value changes continuously on Snowflake side after setting it). + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +{{ if .HasExample -}} +## Example Usage + +{{ tffile (printf "examples/resources/%s/resource.tf" .Name)}} +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + + +{{- end }} + +{{ .SchemaMarkdown | trimspace }} +{{- if .HasImport }} + +## Import + +Import is supported using the following syntax: + +{{ codefile "shell" (printf "examples/resources/%s/import.sh" .Name)}} +{{- end }} diff --git a/templates/resources/user.md.tmpl b/templates/resources/user.md.tmpl index cd2d0b52e5..a15bbb722b 100644 --- a/templates/resources/user.md.tmpl +++ b/templates/resources/user.md.tmpl @@ -15,7 +15,7 @@ description: |- -> **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** Other two user types are handled in separate resources: `snowflake_service_user` for user type `service` and `snowflake_legacy_service_user` for user type `legacy_service`. -> **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).