diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 2ceb3780e4..122d97ec8c 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -78,6 +78,14 @@ To easily handle three-value logic (true, false, unknown) in provider's configs, #### *(note)* `resource_monitor` validation and diff suppression `resource_monitor` is an identifier and handling logic may be still slightly changed as part of https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/ROADMAP.md#identifiers-rework. It should be handled automatically (without needed manual actions on user side), though, but it is not guaranteed. +#### *(behavior change)* snowflake_databases datasource +- Added `like` field to enable warehouse filtering +- Added missing fields returned by SHOW WAREHOUSES and enclosed its output in `show_output` field. +- Added outputs from **DESC WAREHOUSE** and **SHOW PARAMETERS IN WAREHOUSE** (they can be turned off by declaring `with_describe = false` and `with_parameters = false`, **they're turned on by default**). + The additional parameters call **DESC WAREHOUSE** (with `with_describe` turned on) and **SHOW PARAMETERS IN WAREHOUSE** (with `with_parameters` turned on) **per warehouse** returned by **SHOW WAREHOUSES**. + The outputs of both commands are held in `warehouses` entry, where **DESC WAREHOUSE** is saved in the `describe_output` field, and **SHOW PARAMETERS IN WAREHOUSE** in the `parameters` field. + It's important to limit the records and calls to Snowflake to the minimum. That's why we recommend assessing which information you need from the data source and then providing strong filters and turning off additional fields for better plan performance. + ### new database resources As part of the [preparation for v1](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/ROADMAP.md#preparing-essential-ga-objects-for-the-provider-v1), we split up the database resource into multiple ones: - Standard database - can be used as `snowflake_database` (replaces the old one and is used to create databases with optional ability to become a primary database ready for replication) diff --git a/docs/data-sources/databases.md b/docs/data-sources/databases.md index 48a5bc1fff..700b8d6bbc 100644 --- a/docs/data-sources/databases.md +++ b/docs/data-sources/databases.md @@ -2,12 +2,12 @@ page_title: "snowflake_databases Data Source - terraform-provider-snowflake" subcategory: "" description: |- - + Datasource used to get details of filtered databases. Filtering is aligned with the current possibilities for SHOW DATABASES (https://docs.snowflake.com/en/sql-reference/sql/show-databases) query (`like`, 'starts_with', and `limit` are all supported. The results of SHOW, DESCRIBE, and SHOW PARAMETERS IN are encapsulated in one output collection. --- # snowflake_databases (Data Source) - +Datasource used to get details of filtered databases. Filtering is aligned with the current possibilities for [SHOW DATABASES]((https://docs.snowflake.com/en/sql-reference/sql/show-databases) query (`like`, 'starts_with', and `limit` are all supported). The results of SHOW, DESCRIBE, and SHOW PARAMETERS IN are encapsulated in one output collection. ## Example Usage @@ -81,8 +81,8 @@ check "database_check" { } assert { - condition = length(data.snowflake_databases.test.databases) == 1 - error_message = "Databases filtered by '${data.snowflake_databases.test.like}' returned ${length(data.snowflake_databases.test.databases)} databases where one was expected" + condition = length(data.snowflake_databases.assert_with_check_block.databases) == 1 + error_message = "Databases filtered by '${data.snowflake_databases.assert_with_check_block.like}' returned ${length(data.snowflake_databases.assert_with_check_block.databases)} databases where one was expected" } } ``` @@ -100,7 +100,7 @@ check "database_check" { ### Read-Only -- `databases` (List of Object) Holds the output of SHOW DATABASES. (see [below for nested schema](#nestedatt--databases)) +- `databases` (List of Object) Holds the aggregated output of all database details queries. (see [below for nested schema](#nestedatt--databases)) - `id` (String) The ID of this resource. diff --git a/docs/data-sources/warehouses.md b/docs/data-sources/warehouses.md index 7a5b7bf73b..e5f84c0c27 100644 --- a/docs/data-sources/warehouses.md +++ b/docs/data-sources/warehouses.md @@ -2,36 +2,187 @@ page_title: "snowflake_warehouses Data Source - terraform-provider-snowflake" subcategory: "" description: |- - + Datasource used to get details of filtered warehouses. Filtering is aligned with the current possibilities for [SHOW WAREHOUSES]((https://docs.snowflake.com/en/sql-reference/sql/show-warehouses) query (only like is supported). The results of SHOW, DESCRIBE, and SHOW PARAMETERS IN are encapsulated in one output collection. --- # snowflake_warehouses (Data Source) - +Datasource used to get details of filtered warehouses. Filtering is aligned with the current possibilities for [SHOW WAREHOUSES]((https://docs.snowflake.com/en/sql-reference/sql/show-warehouses) query (only `like` is supported). The results of SHOW, DESCRIBE, and SHOW PARAMETERS IN are encapsulated in one output collection. ## Example Usage ```terraform -data "snowflake_warehouses" "current" { +# Simple usage +data "snowflake_warehouses" "simple" { +} + +output "simple_output" { + value = data.snowflake_warehouses.simple.warehouses +} + +# Filtering (like) +data "snowflake_warehouses" "like" { + like = "warehouse-name" +} + +output "like_output" { + value = data.snowflake_warehouses.like.warehouses +} + +# Filtering by prefix (like) +data "snowflake_warehouses" "like_prefix" { + like = "prefix%" +} + +output "like_prefix_output" { + value = data.snowflake_warehouses.like_prefix.warehouses +} + +# Without additional data (to limit the number of calls make for every found warehouse) +data "snowflake_warehouses" "only_show" { + # with_describe is turned on by default and it calls DESCRIBE WAREHOUSE for every warehouse found and attaches its output to warehouses.*.describe_output field + with_describe = false + + # with_parameters is turned on by default and it calls SHOW PARAMETERS FOR WAREHOUSE for every warehouse found and attaches its output to warehouses.*.parameters field + with_parameters = false +} + +output "only_show_output" { + value = data.snowflake_warehouses.only_show.warehouses +} + +# Ensure the number of warehouses is equal to at least one element (with the use of postcondition) +data "snowflake_warehouses" "assert_with_postcondition" { + like = "warehouse-name%" + lifecycle { + postcondition { + condition = length(self.warehouses) > 0 + error_message = "there should be at least one warehouse" + } + } +} + +# Ensure the number of warehouses is equal to at exactly one element (with the use of check block) +check "warehouse_check" { + data "snowflake_warehouses" "assert_with_check_block" { + like = "warehouse-name" + } + + assert { + condition = length(data.snowflake_warehouses.assert_with_check_block.warehouses) == 1 + error_message = "warehouses filtered by '${data.snowflake_warehouses.assert_with_check_block.like}' returned ${length(data.snowflake_warehouses.assert_with_check_block.warehouses)} warehouses where one was expected" + } } ``` ## Schema +### Optional + +- `like` (String) Filters the output with **case-insensitive** pattern, with support for SQL wildcard characters (`%` and `_`). +- `with_describe` (Boolean) Runs DESC WAREHOUSE for each warehouse returned by SHOW WAREHOUSES. The output of describe is saved to the description field. By default this value is set to true. +- `with_parameters` (Boolean) Runs SHOW PARAMETERS FOR WAREHOUSE for each warehouse returned by SHOW WAREHOUSES. The output of describe is saved to the parameters field as a map. By default this value is set to true. + ### Read-Only - `id` (String) The ID of this resource. -- `warehouses` (List of Object) The warehouses in the database (see [below for nested schema](#nestedatt--warehouses)) +- `warehouses` (List of Object) Holds the aggregated output of all warehouse details queries. (see [below for nested schema](#nestedatt--warehouses)) ### Nested Schema for `warehouses` Read-Only: +- `describe_output` (List of Object) (see [below for nested schema](#nestedobjatt--warehouses--describe_output)) +- `parameters` (List of Object) (see [below for nested schema](#nestedobjatt--warehouses--parameters)) +- `show_output` (List of Object) (see [below for nested schema](#nestedobjatt--warehouses--show_output)) + + +### Nested Schema for `warehouses.describe_output` + +Read-Only: + +- `created_on` (String) +- `kind` (String) +- `name` (String) + + + +### Nested Schema for `warehouses.parameters` + +Read-Only: + +- `max_concurrency_level` (List of Object) (see [below for nested schema](#nestedobjatt--warehouses--parameters--max_concurrency_level)) +- `statement_queued_timeout_in_seconds` (List of Object) (see [below for nested schema](#nestedobjatt--warehouses--parameters--statement_queued_timeout_in_seconds)) +- `statement_timeout_in_seconds` (List of Object) (see [below for nested schema](#nestedobjatt--warehouses--parameters--statement_timeout_in_seconds)) + + +### Nested Schema for `warehouses.parameters.max_concurrency_level` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `warehouses.parameters.statement_queued_timeout_in_seconds` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + +### Nested Schema for `warehouses.parameters.statement_timeout_in_seconds` + +Read-Only: + +- `default` (String) +- `description` (String) +- `key` (String) +- `level` (String) +- `value` (String) + + + + +### Nested Schema for `warehouses.show_output` + +Read-Only: + +- `auto_resume` (Boolean) +- `auto_suspend` (Number) +- `available` (Number) - `comment` (String) +- `created_on` (String) +- `enable_query_acceleration` (Boolean) +- `is_current` (Boolean) +- `is_default` (Boolean) +- `max_cluster_count` (Number) +- `min_cluster_count` (Number) - `name` (String) +- `other` (Number) +- `owner` (String) +- `owner_role_type` (String) +- `provisioning` (Number) +- `query_acceleration_max_scale_factor` (Number) +- `queued` (Number) +- `quiescing` (Number) +- `resource_monitor` (String) +- `resumed_on` (String) +- `running` (Number) - `scaling_policy` (String) - `size` (String) +- `started_clusters` (Number) - `state` (String) - `type` (String) +- `updated_on` (String) diff --git a/examples/data-sources/snowflake_databases/data-source.tf b/examples/data-sources/snowflake_databases/data-source.tf index 1c235421f3..2683d8f126 100644 --- a/examples/data-sources/snowflake_databases/data-source.tf +++ b/examples/data-sources/snowflake_databases/data-source.tf @@ -67,7 +67,7 @@ check "database_check" { } assert { - condition = length(data.snowflake_databases.test.databases) == 1 - error_message = "Databases filtered by '${data.snowflake_databases.test.like}' returned ${length(data.snowflake_databases.test.databases)} databases where one was expected" + condition = length(data.snowflake_databases.assert_with_check_block.databases) == 1 + error_message = "Databases filtered by '${data.snowflake_databases.assert_with_check_block.like}' returned ${length(data.snowflake_databases.assert_with_check_block.databases)} databases where one was expected" } } diff --git a/examples/data-sources/snowflake_warehouses/data-source.tf b/examples/data-sources/snowflake_warehouses/data-source.tf index 3046f77d4c..ba39948bd2 100644 --- a/examples/data-sources/snowflake_warehouses/data-source.tf +++ b/examples/data-sources/snowflake_warehouses/data-source.tf @@ -1,2 +1,61 @@ -data "snowflake_warehouses" "current" { -} \ No newline at end of file +# Simple usage +data "snowflake_warehouses" "simple" { +} + +output "simple_output" { + value = data.snowflake_warehouses.simple.warehouses +} + +# Filtering (like) +data "snowflake_warehouses" "like" { + like = "warehouse-name" +} + +output "like_output" { + value = data.snowflake_warehouses.like.warehouses +} + +# Filtering by prefix (like) +data "snowflake_warehouses" "like_prefix" { + like = "prefix%" +} + +output "like_prefix_output" { + value = data.snowflake_warehouses.like_prefix.warehouses +} + +# Without additional data (to limit the number of calls make for every found warehouse) +data "snowflake_warehouses" "only_show" { + # with_describe is turned on by default and it calls DESCRIBE WAREHOUSE for every warehouse found and attaches its output to warehouses.*.describe_output field + with_describe = false + + # with_parameters is turned on by default and it calls SHOW PARAMETERS FOR WAREHOUSE for every warehouse found and attaches its output to warehouses.*.parameters field + with_parameters = false +} + +output "only_show_output" { + value = data.snowflake_warehouses.only_show.warehouses +} + +# Ensure the number of warehouses is equal to at least one element (with the use of postcondition) +data "snowflake_warehouses" "assert_with_postcondition" { + like = "warehouse-name%" + lifecycle { + postcondition { + condition = length(self.warehouses) > 0 + error_message = "there should be at least one warehouse" + } + } +} + +# Ensure the number of warehouses is equal to at exactly one element (with the use of check block) +check "warehouse_check" { + data "snowflake_warehouses" "assert_with_check_block" { + like = "warehouse-name" + } + + assert { + condition = length(data.snowflake_warehouses.assert_with_check_block.warehouses) == 1 + error_message = "warehouses filtered by '${data.snowflake_warehouses.assert_with_check_block.like}' returned ${length(data.snowflake_warehouses.assert_with_check_block.warehouses)} warehouses where one was expected" + } +} diff --git a/pkg/datasources/databases.go b/pkg/datasources/databases.go index 8142955008..679c1948e8 100644 --- a/pkg/datasources/databases.go +++ b/pkg/datasources/databases.go @@ -58,7 +58,7 @@ var databasesSchema = map[string]*schema.Schema{ "databases": { Type: schema.TypeList, Computed: true, - Description: "Holds the output of SHOW DATABASES.", + Description: "Holds the aggregated output of all database details queries.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "show_output": { @@ -95,6 +95,7 @@ func Databases() *schema.Resource { return &schema.Resource{ ReadContext: ReadDatabases, Schema: databasesSchema, + Description: "Datasource used to get details of filtered databases. Filtering is aligned with the current possibilities for [SHOW DATABASES]((https://docs.snowflake.com/en/sql-reference/sql/show-databases) query (`like`, 'starts_with', and `limit` are all supported). The results of SHOW, DESCRIBE, and SHOW PARAMETERS IN are encapsulated in one output collection.", } } diff --git a/pkg/datasources/databases_acceptance_test.go b/pkg/datasources/databases_acceptance_test.go index 2a8e6356ab..4feed5b06a 100644 --- a/pkg/datasources/databases_acceptance_test.go +++ b/pkg/datasources/databases_acceptance_test.go @@ -5,17 +5,18 @@ import ( "regexp" "testing" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider/resources" - "github.com/hashicorp/terraform-plugin-testing/config" - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" "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/hashicorp/terraform-plugin-testing/config" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/tfversion" ) func TestAcc_Databases_Complete(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.ConfigureClientOnce) databaseName := acc.TestClient().Ids.Alpha() comment := random.Comment() @@ -42,8 +43,7 @@ func TestAcc_Databases_Complete(t *testing.T) { resource.TestCheckResourceAttr("data.snowflake_databases.test", "databases.0.show_output.0.kind", "STANDARD"), resource.TestCheckResourceAttr("data.snowflake_databases.test", "databases.0.show_output.0.transient", "false"), resource.TestCheckResourceAttr("data.snowflake_databases.test", "databases.0.show_output.0.is_default", "false"), - // Commenting as this value depends on the currently used database, which is different when running as a single test and multiple tests (e.g., on CI) - // resource.TestCheckResourceAttr("data.snowflake_databases.test", "databases.0.is_current", "true"), + resource.TestCheckResourceAttr("data.snowflake_databases.test", "databases.0.show_output.0.is_current", "true"), resource.TestCheckResourceAttr("data.snowflake_databases.test", "databases.0.show_output.0.origin", ""), resource.TestCheckResourceAttrSet("data.snowflake_databases.test", "databases.0.show_output.0.owner"), resource.TestCheckResourceAttr("data.snowflake_databases.test", "databases.0.show_output.0.comment", comment), @@ -85,8 +85,7 @@ func TestAcc_Databases_Complete(t *testing.T) { resource.TestCheckResourceAttr("data.snowflake_databases.test", "databases.0.show_output.0.kind", "STANDARD"), resource.TestCheckResourceAttr("data.snowflake_databases.test", "databases.0.show_output.0.transient", "false"), resource.TestCheckResourceAttr("data.snowflake_databases.test", "databases.0.show_output.0.is_default", "false"), - // Commenting for the same reason as above - // resource.TestCheckResourceAttr("data.snowflake_databases.test", "databases.0.is_current", "false"), + resource.TestCheckResourceAttr("data.snowflake_databases.test", "databases.0.show_output.0.is_current", "true"), resource.TestCheckResourceAttr("data.snowflake_databases.test", "databases.0.show_output.0.origin", ""), resource.TestCheckResourceAttrSet("data.snowflake_databases.test", "databases.0.show_output.0.owner"), resource.TestCheckResourceAttr("data.snowflake_databases.test", "databases.0.show_output.0.comment", comment), @@ -104,7 +103,7 @@ func TestAcc_Databases_Complete(t *testing.T) { } func TestAcc_Databases_DifferentFiltering(t *testing.T) { - prefix := random.String() + prefix := random.AlphaN(4) idOne := acc.TestClient().Ids.RandomAccountObjectIdentifierWithPrefix(prefix) idTwo := acc.TestClient().Ids.RandomAccountObjectIdentifierWithPrefix(prefix) idThree := acc.TestClient().Ids.RandomAccountObjectIdentifier() diff --git a/pkg/datasources/testdata/TestAcc_Warehouses/like/test.tf b/pkg/datasources/testdata/TestAcc_Warehouses/like/test.tf new file mode 100644 index 0000000000..e089b3c155 --- /dev/null +++ b/pkg/datasources/testdata/TestAcc_Warehouses/like/test.tf @@ -0,0 +1,16 @@ +resource "snowflake_warehouse" "test_1" { + name = var.name_1 +} + +resource "snowflake_warehouse" "test_2" { + name = var.name_2 +} + +resource "snowflake_warehouse" "test_3" { + name = var.name_3 +} + +data "snowflake_warehouses" "test" { + depends_on = [snowflake_warehouse.test_1, snowflake_warehouse.test_2, snowflake_warehouse.test_3] + like = var.like +} diff --git a/pkg/datasources/testdata/TestAcc_Warehouses/like/variables.tf b/pkg/datasources/testdata/TestAcc_Warehouses/like/variables.tf new file mode 100644 index 0000000000..6bd0278080 --- /dev/null +++ b/pkg/datasources/testdata/TestAcc_Warehouses/like/variables.tf @@ -0,0 +1,15 @@ +variable "name_1" { + type = string +} + +variable "name_2" { + type = string +} + +variable "name_3" { + type = string +} + +variable "like" { + type = string +} diff --git a/pkg/datasources/testdata/TestAcc_Warehouses/optionals_set/test.tf b/pkg/datasources/testdata/TestAcc_Warehouses/optionals_set/test.tf new file mode 100644 index 0000000000..a818c089df --- /dev/null +++ b/pkg/datasources/testdata/TestAcc_Warehouses/optionals_set/test.tf @@ -0,0 +1,9 @@ +resource "snowflake_warehouse" "test" { + name = var.name + comment = var.comment +} + +data "snowflake_warehouses" "test" { + depends_on = [snowflake_warehouse.test] + like = var.name +} diff --git a/pkg/datasources/testdata/TestAcc_Warehouses/optionals_set/variables.tf b/pkg/datasources/testdata/TestAcc_Warehouses/optionals_set/variables.tf new file mode 100644 index 0000000000..821eeebe89 --- /dev/null +++ b/pkg/datasources/testdata/TestAcc_Warehouses/optionals_set/variables.tf @@ -0,0 +1,7 @@ +variable "name" { + type = string +} + +variable "comment" { + type = string +} diff --git a/pkg/datasources/testdata/TestAcc_Warehouses/optionals_unset/test.tf b/pkg/datasources/testdata/TestAcc_Warehouses/optionals_unset/test.tf new file mode 100644 index 0000000000..2608f537c9 --- /dev/null +++ b/pkg/datasources/testdata/TestAcc_Warehouses/optionals_unset/test.tf @@ -0,0 +1,11 @@ +resource "snowflake_warehouse" "test" { + name = var.name + comment = var.comment +} + +data "snowflake_warehouses" "test" { + with_describe = false + with_parameters = false + depends_on = [snowflake_warehouse.test] + like = var.name +} diff --git a/pkg/datasources/testdata/TestAcc_Warehouses/optionals_unset/variables.tf b/pkg/datasources/testdata/TestAcc_Warehouses/optionals_unset/variables.tf new file mode 100644 index 0000000000..821eeebe89 --- /dev/null +++ b/pkg/datasources/testdata/TestAcc_Warehouses/optionals_unset/variables.tf @@ -0,0 +1,7 @@ +variable "name" { + type = string +} + +variable "comment" { + type = string +} diff --git a/pkg/datasources/testdata/TestAcc_Warehouses/without_warehouse/test.tf b/pkg/datasources/testdata/TestAcc_Warehouses/without_warehouse/test.tf new file mode 100644 index 0000000000..959985746e --- /dev/null +++ b/pkg/datasources/testdata/TestAcc_Warehouses/without_warehouse/test.tf @@ -0,0 +1,10 @@ +data "snowflake_warehouses" "test" { + like = "non-existing-warehouse" + + lifecycle { + postcondition { + condition = length(self.warehouses) > 0 + error_message = "there should be at least one warehouse" + } + } +} diff --git a/pkg/datasources/warehouses.go b/pkg/datasources/warehouses.go index 384cfec302..ed3bd1d504 100644 --- a/pkg/datasources/warehouses.go +++ b/pkg/datasources/warehouses.go @@ -2,47 +2,61 @@ package datasources import ( "context" - "fmt" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) var warehousesSchema = map[string]*schema.Schema{ + "with_describe": { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Runs DESC WAREHOUSE for each warehouse returned by SHOW WAREHOUSES. The output of describe is saved to the description field. By default this value is set to true.", + }, + "with_parameters": { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Runs SHOW PARAMETERS FOR WAREHOUSE for each warehouse returned by SHOW WAREHOUSES. The output of describe is saved to the parameters field as a map. By default this value is set to true.", + }, + "like": { + Type: schema.TypeString, + Optional: true, + Description: "Filters the output with **case-insensitive** pattern, with support for SQL wildcard characters (`%` and `_`).", + }, "warehouses": { Type: schema.TypeList, Computed: true, - Description: "The warehouses in the database", + Description: "Holds the aggregated output of all warehouse details queries.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Computed: true, - }, - "type": { - Type: schema.TypeString, - Computed: true, - }, - "size": { - Type: schema.TypeString, - Optional: true, - Computed: true, + "show_output": { + Type: schema.TypeList, + Computed: true, + Description: "Holds the output of SHOW WAREHOUSES.", + Elem: &schema.Resource{ + Schema: schemas.ShowWarehouseSchema, + }, }, - "scaling_policy": { - Type: schema.TypeString, - Optional: true, - Computed: true, + "describe_output": { + Type: schema.TypeList, + Computed: true, + Description: "Holds the output of DESCRIBE WAREHOUSE.", + Elem: &schema.Resource{ + Schema: schemas.WarehouseDescribeSchema, + }, }, - "state": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "comment": { - Type: schema.TypeString, - Optional: true, - Computed: true, + "parameters": { + Type: schema.TypeList, + Computed: true, + Description: "Holds the output of SHOW PARAMETERS FOR WAREHOUSE.", + Elem: &schema.Resource{ + Schema: schemas.ShowWarehouseParametersSchema, + }, }, }, }, @@ -51,41 +65,65 @@ var warehousesSchema = map[string]*schema.Schema{ func Warehouses() *schema.Resource { return &schema.Resource{ - Read: ReadWarehouses, - Schema: warehousesSchema, + ReadContext: ReadWarehouses, + Schema: warehousesSchema, + Description: "Datasource used to get details of filtered warehouses. Filtering is aligned with the current possibilities for [SHOW WAREHOUSES]((https://docs.snowflake.com/en/sql-reference/sql/show-warehouses) query (only `like` is supported). The results of SHOW, DESCRIBE, and SHOW PARAMETERS IN are encapsulated in one output collection.", } } -func ReadWarehouses(d *schema.ResourceData, meta interface{}) error { +func ReadWarehouses(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { client := meta.(*provider.Context).Client - ctx := context.Background() + var opts sdk.ShowWarehouseOptions - account, err := client.ContextFunctions.CurrentSessionDetails(ctx) - if err != nil { - d.SetId("") - return nil + if likePattern, ok := d.GetOk("like"); ok { + opts.Like = &sdk.Like{ + Pattern: sdk.String(likePattern.(string)), + } } - d.SetId(fmt.Sprintf("%s.%s", account.Account, account.Region)) - result, err := client.Warehouses.Show(ctx, nil) + warehouses, err := client.Warehouses.Show(ctx, &opts) if err != nil { - return err + return diag.FromErr(err) } + d.SetId("warehouses_read") + + flattenedWarehouses := make([]map[string]any, len(warehouses)) - warehouses := []map[string]interface{}{} + for i, warehouse := range warehouses { + warehouse := warehouse + var warehouseDescription []map[string]any + if d.Get("with_describe").(bool) { + describeResult, err := client.Warehouses.Describe(ctx, warehouse.ID()) + if err != nil { + return diag.FromErr(err) + } + warehouseDescription = schemas.WarehouseDescriptionToSchema(*describeResult) + } - for _, warehouse := range result { - warehouseMap := map[string]interface{}{} + var warehouseParameters []map[string]any + if d.Get("with_parameters").(bool) { + parameters, err := client.Parameters.ShowParameters(ctx, &sdk.ShowParametersOptions{ + In: &sdk.ParametersIn{ + Warehouse: warehouse.ID(), + }, + }) + if err != nil { + return diag.FromErr(err) + } + warehouseParameters = []map[string]any{schemas.WarehouseParametersToSchema(parameters)} + } - warehouseMap["name"] = warehouse.Name - warehouseMap["type"] = warehouse.Type - warehouseMap["size"] = warehouse.Size - warehouseMap["scaling_policy"] = warehouse.ScalingPolicy - warehouseMap["state"] = warehouse.State - warehouseMap["comment"] = warehouse.Comment + flattenedWarehouses[i] = map[string]any{ + "show_output": []map[string]any{schemas.WarehouseToSchema(&warehouse)}, + "describe_output": warehouseDescription, + "parameters": warehouseParameters, + } + } - warehouses = append(warehouses, warehouseMap) + err = d.Set("warehouses", flattenedWarehouses) + if err != nil { + return diag.FromErr(err) } - return d.Set("warehouses", warehouses) + return nil } diff --git a/pkg/datasources/warehouses_acceptance_test.go b/pkg/datasources/warehouses_acceptance_test.go index 940b28c745..6e8c6cceaa 100644 --- a/pkg/datasources/warehouses_acceptance_test.go +++ b/pkg/datasources/warehouses_acceptance_test.go @@ -1,49 +1,183 @@ package datasources_test import ( - "fmt" + "maps" + "regexp" "testing" acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + "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/config" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/tfversion" ) -func TestAcc_Warehouses(t *testing.T) { - warehouseName := acc.TestClient().Ids.Alpha() +func TestAcc_Warehouses_Complete(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.ConfigureClientOnce) + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() + comment := random.Comment() + + configVariables := config.Variables{ + "name": config.StringVariable(id.Name()), + "comment": config.StringVariable(comment), + } + resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, TerraformVersionChecks: []tfversion.TerraformVersionCheck{ tfversion.RequireAbove(tfversion.Version1_5_0), }, - CheckDestroy: nil, + CheckDestroy: acc.CheckDestroy(t, resources.Warehouse), Steps: []resource.TestStep{ { - Config: warehouses(warehouseName), + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_Warehouses/optionals_set"), + ConfigVariables: configVariables, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.snowflake_warehouses.s", "warehouses.#"), - resource.TestCheckResourceAttrSet("data.snowflake_warehouses.s", "warehouses.0.name"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.#", "1"), + + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.name", id.Name()), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.state"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.type", string(sdk.WarehouseTypeStandard)), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.size", string(sdk.WarehouseSizeXSmall)), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.min_cluster_count", "1"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.max_cluster_count", "1"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.started_clusters"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.running"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.queued"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.is_default", "false"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.is_current", "true"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.auto_suspend", "600"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.auto_resume", "true"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.available"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.provisioning"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.quiescing"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.other"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.created_on"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.resumed_on"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.updated_on"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.owner"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.comment", comment), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.enable_query_acceleration", "false"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.query_acceleration_max_scale_factor", "8"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.resource_monitor", ""), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.scaling_policy", string(sdk.ScalingPolicyStandard)), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.owner_role_type"), + + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.describe_output.#", "1"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.describe_output.0.created_on"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.describe_output.0.name"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.describe_output.0.kind", "WAREHOUSE"), + + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.parameters.#", "1"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.parameters.0.max_concurrency_level.0.value", "8"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.parameters.0.statement_queued_timeout_in_seconds.0.value", "0"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.parameters.0.statement_timeout_in_seconds.0.value", "172800"), + ), + }, + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_Warehouses/optionals_unset"), + ConfigVariables: configVariables, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.#", "1"), + + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.name", id.Name()), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.state"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.type", string(sdk.WarehouseTypeStandard)), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.size", string(sdk.WarehouseSizeXSmall)), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.min_cluster_count", "1"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.max_cluster_count", "1"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.started_clusters"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.running"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.queued"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.is_default", "false"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.is_current", "true"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.auto_suspend", "600"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.auto_resume", "true"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.available"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.provisioning"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.quiescing"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.other"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.created_on"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.resumed_on"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.updated_on"), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.owner"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.comment", comment), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.enable_query_acceleration", "false"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.query_acceleration_max_scale_factor", "8"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.resource_monitor", ""), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.show_output.0.scaling_policy", string(sdk.ScalingPolicyStandard)), + resource.TestCheckResourceAttrSet("data.snowflake_warehouses.test", "warehouses.0.show_output.0.owner_role_type"), + + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.describe_output.#", "0"), + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.0.parameters.#", "0"), ), }, }, }) } -func warehouses(warehouseName string) string { - return fmt.Sprintf(` - resource snowflake_warehouse "s"{ - name = "%v" - warehouse_size = "XSMALL" - initially_suspended = true - auto_suspend = 60 - max_concurrency_level = 8 - statement_timeout_in_seconds = 172800 - warehouse_type = "STANDARD" +func TestAcc_Warehouses_Filtering(t *testing.T) { + prefix := random.AlphaN(4) + idOne := acc.TestClient().Ids.RandomAccountObjectIdentifierWithPrefix(prefix) + idTwo := acc.TestClient().Ids.RandomAccountObjectIdentifierWithPrefix(prefix) + idThree := acc.TestClient().Ids.RandomAccountObjectIdentifier() + + commonVariables := config.Variables{ + "name_1": config.StringVariable(idOne.Name()), + "name_2": config.StringVariable(idTwo.Name()), + "name_3": config.StringVariable(idThree.Name()), + } + + likeConfig := config.Variables{ + "like": config.StringVariable(idOne.Name()), } + maps.Copy(likeConfig, commonVariables) - data snowflake_warehouses "s" { - depends_on = [snowflake_warehouse.s] + likeConfig2 := config.Variables{ + "like": config.StringVariable(prefix + "%"), } - `, warehouseName) + maps.Copy(likeConfig2, commonVariables) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + CheckDestroy: acc.CheckDestroy(t, resources.Warehouse), + Steps: []resource.TestStep{ + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_Warehouses/like"), + ConfigVariables: likeConfig, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.#", "1"), + ), + }, + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_Warehouses/like"), + ConfigVariables: likeConfig2, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.snowflake_warehouses.test", "warehouses.#", "2"), + ), + }, + }, + }) +} + +func TestAcc_Warehouses_WarehouseNotFound_WithPostConditions(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + Steps: []resource.TestStep{ + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_Warehouses/without_warehouse"), + ExpectError: regexp.MustCompile("there should be at least one warehouse"), + }, + }, + }) } diff --git a/pkg/resources/warehouse.go b/pkg/resources/warehouse.go index bdc51b0881..71ab1d0ba1 100644 --- a/pkg/resources/warehouse.go +++ b/pkg/resources/warehouse.go @@ -2,6 +2,7 @@ package resources import ( "context" + "errors" "fmt" "strconv" "strings" @@ -324,6 +325,16 @@ func GetReadWarehouseFunc(withExternalChangesMarking bool) schema.ReadContextFun w, err := client.Warehouses.ShowByID(ctx, id) if err != nil { + if errors.Is(err, sdk.ErrObjectNotFound) { + d.SetId("") + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Warning, + Summary: "Failed to query warehouse. Marking the resource as removed.", + Detail: fmt.Sprintf("Warehouse: %s, Err: %s", id.FullyQualifiedName(), err), + }, + } + } return diag.FromErr(err) } diff --git a/pkg/schemas/warehouse.go b/pkg/schemas/warehouse.go new file mode 100644 index 0000000000..0e380fefa8 --- /dev/null +++ b/pkg/schemas/warehouse.go @@ -0,0 +1,31 @@ +package schemas + +import ( + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var WarehouseDescribeSchema = map[string]*schema.Schema{ + "created_on": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "kind": { + Type: schema.TypeString, + Computed: true, + }, +} + +func WarehouseDescriptionToSchema(description sdk.WarehouseDetails) []map[string]any { + return []map[string]any{ + { + "created_on": description.CreatedOn.String(), + "name": description.Name, + "kind": description.Kind, + }, + } +}