diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 2c75e172d8..148dc15e45 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -9,6 +9,13 @@ across different versions. ## v0.98.0 ➞ v0.99.0 +### *(new feature)* snowflake_tags datasource +Added a new datasource enabling querying and filtering tags. Notes: +- all results are stored in `tags` field. +- `like` field enables tags filtering by name. +- `in` field enables tags filtering by `account`, `database`, `schema`, `application` and `application_package`. +- `SHOW TAGS` output is enclosed in `show_output` field inside `tags`. + ### snowflake_tag_masking_policy_association deprecation `snowflake_tag_masking_policy_association` is now deprecated in favor of `snowflake_tag` with a new `masking_policy` field. It will be removed with the v1 release. Please adjust your configuration files. diff --git a/docs/data-sources/streams.md b/docs/data-sources/streams.md index ee575faa06..62ca70cb22 100644 --- a/docs/data-sources/streams.md +++ b/docs/data-sources/streams.md @@ -14,9 +14,120 @@ Datasource used to get details of filtered streams. Filtering is aligned with th ## Example Usage ```terraform -data "snowflake_streams" "current" { - database = "MYDB" - schema = "MYSCHEMA" +# Simple usage +data "snowflake_streams" "simple" { +} + +output "simple_output" { + value = data.snowflake_streams.simple.streams +} + +# Filtering (like) +data "snowflake_streams" "like" { + like = "stream-name" +} + +output "like_output" { + value = data.snowflake_streams.like.streams +} + +# Filtering by prefix (like) +data "snowflake_streams" "like_prefix" { + like = "prefix%" +} + +output "like_prefix_output" { + value = data.snowflake_streams.like_prefix.streams +} + +# Filtering (limit) +data "snowflake_streams" "limit" { + limit { + rows = 10 + from = "prefix-" + } +} + +output "limit_output" { + value = data.snowflake_streams.limit.streams +} + +# Filtering (in) +data "snowflake_streams" "in_account" { + in { + account = true + } +} + +data "snowflake_streams" "in_database" { + in { + database = "" + } +} + +data "snowflake_streams" "in_schema" { + in { + schema = "." + } +} + +data "snowflake_streams" "in_application" { + in { + application = "" + } +} + +data "snowflake_streams" "in_application_package" { + in { + application_package = "" + } +} + +output "in_output" { + value = { + "account" : data.snowflake_streams.in_account.streams, + "database" : data.snowflake_streams.in_database.streams, + "schema" : data.snowflake_streams.in_schema.streams, + "application" : data.snowflake_streams.in_application.streams, + "application_package" : data.snowflake_streams.in_application_package.streams, + } +} + +output "in_output" { + value = data.snowflake_streams.in.streams +} + +# Without additional data (to limit the number of calls make for every found stream) +data "snowflake_streams" "only_show" { + # with_describe is turned on by default and it calls DESCRIBE STREAM for every stream found and attaches its output to streams.*.describe_output field + with_describe = false +} + +output "only_show_output" { + value = data.snowflake_streams.only_show.streams +} + +# Ensure the number of streams is equal to at least one element (with the use of postcondition) +data "snowflake_streams" "assert_with_postcondition" { + like = "stream-name%" + lifecycle { + postcondition { + condition = length(self.streams) > 0 + error_message = "there should be at least one stream" + } + } +} + +# Ensure the number of streams is equal to at exactly one element (with the use of check block) +check "stream_check" { + data "snowflake_streams" "assert_with_check_block" { + like = "stream-name" + } + + assert { + condition = length(data.snowflake_streams.assert_with_check_block.streams) == 1 + error_message = "streams filtered by '${data.snowflake_streams.assert_with_check_block.like}' returned ${length(data.snowflake_streams.assert_with_check_block.streams)} streams where one was expected" + } } ``` diff --git a/docs/data-sources/tags.md b/docs/data-sources/tags.md new file mode 100644 index 0000000000..bb8e360071 --- /dev/null +++ b/docs/data-sources/tags.md @@ -0,0 +1,156 @@ +--- +page_title: "snowflake_tags Data Source - terraform-provider-snowflake" +subcategory: "" +description: |- + Datasource used to get details of filtered tags. Filtering is aligned with the current possibilities for SHOW TAGS https://docs.snowflake.com/en/sql-reference/sql/show-tags query. The results of SHOW are encapsulated in one output collection tags. +--- + +!> **V1 release candidate** This data source 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 data source if needed. Any errors reported will be resolved with a higher priority. We encourage checking this data source out before the V1 release. Please follow the [migration guide](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/MIGRATION_GUIDE.md#v0980--v0990) to use it. + +# snowflake_tags (Data Source) + +Datasource used to get details of filtered tags. Filtering is aligned with the current possibilities for [SHOW TAGS](https://docs.snowflake.com/en/sql-reference/sql/show-tags) query. The results of SHOW are encapsulated in one output collection `tags`. + +## Example Usage + +```terraform +# Simple usage +data "snowflake_tags" "simple" { +} + +output "simple_output" { + value = data.snowflake_tags.simple.tags +} + +# Filtering (like) +data "snowflake_tags" "like" { + like = "tag-name" +} + +output "like_output" { + value = data.snowflake_tags.like.tags +} + +# Filtering by prefix (like) +data "snowflake_tags" "like_prefix" { + like = "prefix%" +} + +output "like_prefix_output" { + value = data.snowflake_tags.like_prefix.tags +} + +# Filtering (in) +data "snowflake_tags" "in_account" { + in { + account = true + } +} + +data "snowflake_tags" "in_database" { + in { + database = "" + } +} + +data "snowflake_tags" "in_schema" { + in { + schema = "." + } +} + +data "snowflake_tags" "in_application" { + in { + application = "" + } +} + +data "snowflake_tags" "in_application_package" { + in { + application_package = "" + } +} + +output "in_output" { + value = { + "account" : data.snowflake_tags.in_account.tags, + "database" : data.snowflake_tags.in_database.tags, + "schema" : data.snowflake_tags.in_schema.tags, + "application" : data.snowflake_tags.in_application.tags, + "application_package" : data.snowflake_tags.in_application_package.tags, + } +} + +output "in_output" { + value = data.snowflake_tags.in.tags +} + +# Ensure the number of tags is equal to at least one element (with the use of postcondition) +data "snowflake_tags" "assert_with_postcondition" { + like = "tag-name%" + lifecycle { + postcondition { + condition = length(self.tags) > 0 + error_message = "there should be at least one tag" + } + } +} + +# Ensure the number of tags is equal to at exactly one element (with the use of check block) +check "tag_check" { + data "snowflake_tags" "assert_with_check_block" { + like = "tag-name" + } + + assert { + condition = length(data.snowflake_tags.assert_with_check_block.tags) == 1 + error_message = "tags filtered by '${data.snowflake_tags.assert_with_check_block.like}' returned ${length(data.snowflake_tags.assert_with_check_block.tags)} tags where one was expected" + } +} +``` + + +## Schema + +### Optional + +- `in` (Block List, Max: 1) IN clause to filter the list of objects (see [below for nested schema](#nestedblock--in)) +- `like` (String) Filters the output with **case-insensitive** pattern, with support for SQL wildcard characters (`%` and `_`). + +### Read-Only + +- `id` (String) The ID of this resource. +- `tags` (List of Object) Holds the aggregated output of all tags details queries. (see [below for nested schema](#nestedatt--tags)) + + +### Nested Schema for `in` + +Optional: + +- `account` (Boolean) Returns records for the entire account. +- `application` (String) Returns records for the specified application. +- `application_package` (String) Returns records for the specified application package. +- `database` (String) Returns records for the current database in use or for a specified database. +- `schema` (String) Returns records for the current schema in use or a specified schema. Use fully qualified name. + + + +### Nested Schema for `tags` + +Read-Only: + +- `show_output` (List of Object) (see [below for nested schema](#nestedobjatt--tags--show_output)) + + +### Nested Schema for `tags.show_output` + +Read-Only: + +- `allowed_values` (Set of String) +- `comment` (String) +- `created_on` (String) +- `database_name` (String) +- `name` (String) +- `owner` (String) +- `owner_role_type` (String) +- `schema_name` (String) diff --git a/examples/data-sources/snowflake_streams/data-source.tf b/examples/data-sources/snowflake_streams/data-source.tf index 00afc182f3..f275f36fb0 100644 --- a/examples/data-sources/snowflake_streams/data-source.tf +++ b/examples/data-sources/snowflake_streams/data-source.tf @@ -1,4 +1,115 @@ -data "snowflake_streams" "current" { - database = "MYDB" - schema = "MYSCHEMA" -} \ No newline at end of file +# Simple usage +data "snowflake_streams" "simple" { +} + +output "simple_output" { + value = data.snowflake_streams.simple.streams +} + +# Filtering (like) +data "snowflake_streams" "like" { + like = "stream-name" +} + +output "like_output" { + value = data.snowflake_streams.like.streams +} + +# Filtering by prefix (like) +data "snowflake_streams" "like_prefix" { + like = "prefix%" +} + +output "like_prefix_output" { + value = data.snowflake_streams.like_prefix.streams +} + +# Filtering (limit) +data "snowflake_streams" "limit" { + limit { + rows = 10 + from = "prefix-" + } +} + +output "limit_output" { + value = data.snowflake_streams.limit.streams +} + +# Filtering (in) +data "snowflake_streams" "in_account" { + in { + account = true + } +} + +data "snowflake_streams" "in_database" { + in { + database = "" + } +} + +data "snowflake_streams" "in_schema" { + in { + schema = "." + } +} + +data "snowflake_streams" "in_application" { + in { + application = "" + } +} + +data "snowflake_streams" "in_application_package" { + in { + application_package = "" + } +} + +output "in_output" { + value = { + "account" : data.snowflake_streams.in_account.streams, + "database" : data.snowflake_streams.in_database.streams, + "schema" : data.snowflake_streams.in_schema.streams, + "application" : data.snowflake_streams.in_application.streams, + "application_package" : data.snowflake_streams.in_application_package.streams, + } +} + +output "in_output" { + value = data.snowflake_streams.in.streams +} + +# Without additional data (to limit the number of calls make for every found stream) +data "snowflake_streams" "only_show" { + # with_describe is turned on by default and it calls DESCRIBE STREAM for every stream found and attaches its output to streams.*.describe_output field + with_describe = false +} + +output "only_show_output" { + value = data.snowflake_streams.only_show.streams +} + +# Ensure the number of streams is equal to at least one element (with the use of postcondition) +data "snowflake_streams" "assert_with_postcondition" { + like = "stream-name%" + lifecycle { + postcondition { + condition = length(self.streams) > 0 + error_message = "there should be at least one stream" + } + } +} + +# Ensure the number of streams is equal to at exactly one element (with the use of check block) +check "stream_check" { + data "snowflake_streams" "assert_with_check_block" { + like = "stream-name" + } + + assert { + condition = length(data.snowflake_streams.assert_with_check_block.streams) == 1 + error_message = "streams filtered by '${data.snowflake_streams.assert_with_check_block.like}' returned ${length(data.snowflake_streams.assert_with_check_block.streams)} streams where one was expected" + } +} diff --git a/examples/data-sources/snowflake_tags/data-source.tf b/examples/data-sources/snowflake_tags/data-source.tf new file mode 100644 index 0000000000..0152d21715 --- /dev/null +++ b/examples/data-sources/snowflake_tags/data-source.tf @@ -0,0 +1,93 @@ +# Simple usage +data "snowflake_tags" "simple" { +} + +output "simple_output" { + value = data.snowflake_tags.simple.tags +} + +# Filtering (like) +data "snowflake_tags" "like" { + like = "tag-name" +} + +output "like_output" { + value = data.snowflake_tags.like.tags +} + +# Filtering by prefix (like) +data "snowflake_tags" "like_prefix" { + like = "prefix%" +} + +output "like_prefix_output" { + value = data.snowflake_tags.like_prefix.tags +} + +# Filtering (in) +data "snowflake_tags" "in_account" { + in { + account = true + } +} + +data "snowflake_tags" "in_database" { + in { + database = "" + } +} + +data "snowflake_tags" "in_schema" { + in { + schema = "." + } +} + +data "snowflake_tags" "in_application" { + in { + application = "" + } +} + +data "snowflake_tags" "in_application_package" { + in { + application_package = "" + } +} + +output "in_output" { + value = { + "account" : data.snowflake_tags.in_account.tags, + "database" : data.snowflake_tags.in_database.tags, + "schema" : data.snowflake_tags.in_schema.tags, + "application" : data.snowflake_tags.in_application.tags, + "application_package" : data.snowflake_tags.in_application_package.tags, + } +} + +output "in_output" { + value = data.snowflake_tags.in.tags +} + +# Ensure the number of tags is equal to at least one element (with the use of postcondition) +data "snowflake_tags" "assert_with_postcondition" { + like = "tag-name%" + lifecycle { + postcondition { + condition = length(self.tags) > 0 + error_message = "there should be at least one tag" + } + } +} + +# Ensure the number of tags is equal to at exactly one element (with the use of check block) +check "tag_check" { + data "snowflake_tags" "assert_with_check_block" { + like = "tag-name" + } + + assert { + condition = length(data.snowflake_tags.assert_with_check_block.tags) == 1 + error_message = "tags filtered by '${data.snowflake_tags.assert_with_check_block.like}' returned ${length(data.snowflake_tags.assert_with_check_block.tags)} tags where one was expected" + } +} diff --git a/pkg/acceptance/bettertestspoc/assert/resourceshowoutputassert/tag_show_output_ext.go b/pkg/acceptance/bettertestspoc/assert/resourceshowoutputassert/tag_show_output_ext.go index 9fb4de087b..46873a7668 100644 --- a/pkg/acceptance/bettertestspoc/assert/resourceshowoutputassert/tag_show_output_ext.go +++ b/pkg/acceptance/bettertestspoc/assert/resourceshowoutputassert/tag_show_output_ext.go @@ -3,10 +3,22 @@ package resourceshowoutputassert import ( "fmt" "strconv" + "testing" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" ) +// TagsDatasourceShowOutput is a temporary workaround to have better show output assertions in data source acceptance tests. +func TagsDatasourceShowOutput(t *testing.T, name string) *TagShowOutputAssert { + t.Helper() + + s := TagShowOutputAssert{ + ResourceAssert: assert.NewDatasourceAssert("data."+name, "show_output", "tags.0."), + } + s.AddAssertion(assert.ValueSet("show_output.#", "1")) + return &s +} + func (s *TagShowOutputAssert) HasCreatedOnNotEmpty() *TagShowOutputAssert { s.AddAssertion(assert.ResourceShowOutputValuePresent("created_on")) return s diff --git a/pkg/datasources/tags.go b/pkg/datasources/tags.go new file mode 100644 index 0000000000..05b551fc0b --- /dev/null +++ b/pkg/datasources/tags.go @@ -0,0 +1,72 @@ +package datasources + +import ( + "context" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" + "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 tagsSchema = map[string]*schema.Schema{ + "like": likeSchema, + "in": extendedInSchema, + "tags": { + Type: schema.TypeList, + Computed: true, + Description: "Holds the aggregated output of all tags details queries.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + resources.ShowOutputAttributeName: { + Type: schema.TypeList, + Computed: true, + Description: "Holds the output of SHOW TAGS.", + Elem: &schema.Resource{ + Schema: schemas.ShowTagSchema, + }, + }, + }, + }, + }, +} + +func Tags() *schema.Resource { + return &schema.Resource{ + ReadContext: ReadTags, + Schema: tagsSchema, + Description: "Datasource used to get details of filtered tags. Filtering is aligned with the current possibilities for [SHOW TAGS](https://docs.snowflake.com/en/sql-reference/sql/show-tags) query. The results of SHOW are encapsulated in one output collection `tags`.", + } +} + +func ReadTags(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + client := meta.(*provider.Context).Client + req := sdk.ShowTagRequest{} + + handleLike(d, &req.Like) + err := handleExtendedIn(d, &req.In) + if err != nil { + return diag.FromErr(err) + } + + tags, err := client.Tags.Show(ctx, &req) + if err != nil { + return diag.FromErr(err) + } + d.SetId("tags_read") + + flattenedTags := make([]map[string]any, len(tags)) + for i, tag := range tags { + tag := tag + flattenedTags[i] = map[string]any{ + resources.ShowOutputAttributeName: []map[string]any{schemas.TagToSchema(&tag)}, + } + } + if err := d.Set("tags", flattenedTags); err != nil { + return diag.FromErr(err) + } + return nil +} diff --git a/pkg/datasources/tags_acceptance_test.go b/pkg/datasources/tags_acceptance_test.go new file mode 100644 index 0000000000..a29eacc082 --- /dev/null +++ b/pkg/datasources/tags_acceptance_test.go @@ -0,0 +1,160 @@ +package datasources_test + +import ( + "fmt" + "regexp" + "testing" + + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceshowoutputassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config" + testconfig "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/internal/snowflakeroles" + tfconfig "github.com/hashicorp/terraform-plugin-testing/config" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/tfversion" +) + +func TestAcc_Tags(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) + acc.TestAccPreCheck(t) + id := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + + model := model.Tag("test", id.DatabaseName(), id.Name(), id.SchemaName()). + WithComment("foo"). + WithAllowedValuesValue(tfconfig.ListVariable(tfconfig.StringVariable("foo"), tfconfig.StringVariable(""), tfconfig.StringVariable("bar"))) + + dsName := "data.snowflake_tags.test" + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { acc.TestAccPreCheck(t) }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + Steps: []resource.TestStep{ + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_Tags/basic"), + ConfigVariables: config.ConfigVariablesFromModel(t, model), + + Check: assert.AssertThat(t, + assert.Check(resource.TestCheckResourceAttr(dsName, "tags.#", "1")), + + resourceshowoutputassert.TagsDatasourceShowOutput(t, "snowflake_tags.test"). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasDatabaseName(id.DatabaseName()). + HasSchemaName(id.SchemaName()). + HasComment("foo"). + HasOwner(snowflakeroles.Accountadmin.Name()). + HasOwnerRoleType("ROLE"), + assert.Check(resource.TestCheckResourceAttr(model.ResourceReference(), "show_output.0.allowed_values.#", "3")), + assert.Check(resource.TestCheckTypeSetElemAttr(model.ResourceReference(), "show_output.0.allowed_values.*", "foo")), + assert.Check(resource.TestCheckTypeSetElemAttr(model.ResourceReference(), "show_output.0.allowed_values.*", "")), + assert.Check(resource.TestCheckTypeSetElemAttr(model.ResourceReference(), "show_output.0.allowed_values.*", "bar")), + ), + }, + }, + }) +} + +func tagsDatasource(like, resourceName string) string { + return fmt.Sprintf(` +data "snowflake_tags" "test" { + depends_on = [%s] + + like = "%s" +} +`, resourceName, like) +} + +func TestAcc_Tags_Filtering(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) + acc.TestAccPreCheck(t) + + prefix := random.AlphaN(4) + id1 := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithPrefix(prefix) + id2 := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithPrefix(prefix) + id3 := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + + model1 := model.Tag("test_1", id1.DatabaseName(), id1.Name(), id1.SchemaName()) + model2 := model.Tag("test_2", id2.DatabaseName(), id2.Name(), id2.SchemaName()) + model3 := model.Tag("test_3", id3.DatabaseName(), id3.Name(), id3.SchemaName()) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Steps: []resource.TestStep{ + { + Config: testconfig.FromModel(t, model1) + testconfig.FromModel(t, model2) + testconfig.FromModel(t, model3) + tagsDatasourceLike(id1.Name()), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.snowflake_tags.test", "tags.#", "1"), + ), + }, + { + Config: testconfig.FromModel(t, model1) + testconfig.FromModel(t, model2) + testconfig.FromModel(t, model3) + tagsDatasourceLike(prefix+"%"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.snowflake_tags.test", "tags.#", "2"), + ), + }, + }, + }) +} + +func tagsDatasourceLike(like string) string { + return fmt.Sprintf(` +data "snowflake_tags" "test" { + depends_on = [snowflake_tag.test_1, snowflake_tag.test_2, snowflake_tag.test_3] + + like = "%s" +} +`, like) +} + +func TestAcc_Tags_emptyIn(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { acc.TestAccPreCheck(t) }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: tagsDatasourceEmptyIn(), + ExpectError: regexp.MustCompile("Invalid combination of arguments"), + }, + }, + }) +} + +func tagsDatasourceEmptyIn() string { + return ` +data "snowflake_tags" "test" { + in { + } +} +` +} + +func TestAcc_Tags_NotFound_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_Tags/non_existing"), + ExpectError: regexp.MustCompile("there should be at least one tag"), + }, + }, + }) +} diff --git a/pkg/datasources/testdata/TestAcc_Tags/basic/test.tf b/pkg/datasources/testdata/TestAcc_Tags/basic/test.tf new file mode 100644 index 0000000000..595bd930e1 --- /dev/null +++ b/pkg/datasources/testdata/TestAcc_Tags/basic/test.tf @@ -0,0 +1,15 @@ +resource "snowflake_tag" "test" { + name = var.name + schema = var.schema + database = var.database + + allowed_values = var.allowed_values + + comment = var.comment +} + +data "snowflake_tags" "test" { + depends_on = [snowflake_tag.test] + + like = var.name +} diff --git a/pkg/datasources/testdata/TestAcc_Tags/basic/variables.tf b/pkg/datasources/testdata/TestAcc_Tags/basic/variables.tf new file mode 100644 index 0000000000..8b9daeb051 --- /dev/null +++ b/pkg/datasources/testdata/TestAcc_Tags/basic/variables.tf @@ -0,0 +1,19 @@ +variable "name" { + type = string +} + +variable "database" { + type = string +} + +variable "schema" { + type = string +} + +variable "comment" { + type = string +} + +variable "allowed_values" { + type = set(string) +} diff --git a/pkg/datasources/testdata/TestAcc_Tags/non_existing/test.tf b/pkg/datasources/testdata/TestAcc_Tags/non_existing/test.tf new file mode 100644 index 0000000000..919b121905 --- /dev/null +++ b/pkg/datasources/testdata/TestAcc_Tags/non_existing/test.tf @@ -0,0 +1,10 @@ +data "snowflake_tags" "test" { + like = "non-existing-tag" + + lifecycle { + postcondition { + condition = length(self.tags) > 0 + error_message = "there should be at least one tag" + } + } +} diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index ddc0512a20..94318dc77f 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -609,6 +609,7 @@ func getDataSources() map[string]*schema.Resource { "snowflake_system_get_privatelink_config": datasources.SystemGetPrivateLinkConfig(), "snowflake_system_get_snowflake_platform_info": datasources.SystemGetSnowflakePlatformInfo(), "snowflake_tables": datasources.Tables(), + "snowflake_tags": datasources.Tags(), "snowflake_tasks": datasources.Tasks(), "snowflake_users": datasources.Users(), "snowflake_views": datasources.Views(), diff --git a/pkg/sdk/tags_dto.go b/pkg/sdk/tags_dto.go index 4aa1a50df4..10580f9ceb 100644 --- a/pkg/sdk/tags_dto.go +++ b/pkg/sdk/tags_dto.go @@ -73,8 +73,8 @@ type TagUnsetRequest struct { } type ShowTagRequest struct { - like *Like - in *ExtendedIn + Like *Like + In *ExtendedIn } type DropTagRequest struct { diff --git a/pkg/sdk/tags_dto_builders.go b/pkg/sdk/tags_dto_builders.go index 4e8a155989..505d0ca854 100644 --- a/pkg/sdk/tags_dto_builders.go +++ b/pkg/sdk/tags_dto_builders.go @@ -195,14 +195,14 @@ func NewShowTagRequest() *ShowTagRequest { } func (s *ShowTagRequest) WithLike(pattern string) *ShowTagRequest { - s.like = &Like{ + s.Like = &Like{ Pattern: String(pattern), } return s } func (s *ShowTagRequest) WithIn(in *ExtendedIn) *ShowTagRequest { - s.in = in + s.In = in return s } diff --git a/pkg/sdk/tags_impl.go b/pkg/sdk/tags_impl.go index 9813b03803..d0e534ae57 100644 --- a/pkg/sdk/tags_impl.go +++ b/pkg/sdk/tags_impl.go @@ -116,8 +116,8 @@ func (s *AlterTagRequest) toOpts() *alterTagOptions { func (s *ShowTagRequest) toOpts() *showTagOptions { return &showTagOptions{ - Like: s.like, - In: s.in, + Like: s.Like, + In: s.In, } } diff --git a/templates/data-sources/tags.md.tmpl b/templates/data-sources/tags.md.tmpl new file mode 100644 index 0000000000..2aef1476da --- /dev/null +++ b/templates/data-sources/tags.md.tmpl @@ -0,0 +1,24 @@ +--- +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 data source 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 data source if needed. Any errors reported will be resolved with a higher priority. We encourage checking this data source out before the V1 release. Please follow the [migration guide](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/MIGRATION_GUIDE.md#v0980--v0990) to use it. + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +{{ if .HasExample -}} +## Example Usage + +{{ tffile (printf "examples/data-sources/%s/data-source.tf" .Name)}} +{{- end }} + +{{ .SchemaMarkdown | trimspace }}