From 5fce02256585ab42f7eba35c253a042b32c625dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Tue, 7 May 2024 10:46:36 +0200 Subject: [PATCH 1/4] Add missing documentation --- .../system_get_aws_sns_iam_policy.md | 10 ++++++++ docs/resources/stage.md | 4 ++-- .../data-source.tf | 3 +++ .../system_get_aws_sns_iam_policy.go | 1 - pkg/resources/stage.go | 4 ++++ .../system_get_aws_sns_iam_policy.md.tmpl | 24 +++++++++++++++++++ 6 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 examples/data-sources/snowflake_system_get_aws_sns_iam_policy/data-source.tf create mode 100644 templates/data-sources/system_get_aws_sns_iam_policy.md.tmpl diff --git a/docs/data-sources/system_get_aws_sns_iam_policy.md b/docs/data-sources/system_get_aws_sns_iam_policy.md index 14565701a5..cbbe270f60 100644 --- a/docs/data-sources/system_get_aws_sns_iam_policy.md +++ b/docs/data-sources/system_get_aws_sns_iam_policy.md @@ -9,7 +9,17 @@ description: |- +For more details, visit the official Snowflake documentation: https://docs.snowflake.com/en/sql-reference/functions/system_get_aws_sns_iam_policy. +Read this guide to understand how to use the snowflake_system_get_aws_sns_iam_policy to integrate with AWS: https://docs.snowflake.com/en/user-guide/data-load-snowpipe-auto-s3#step-1-subscribe-the-snowflake-sqs-queue-to-the-sns-topic. +It's SQL-based, but after knowing what has to be done use corresponding resources and data-sources from the Snowflake and AWS Terraform provider. +## Example Usage + +```terraform +data "snowflake_system_get_aws_sns_iam_policy" "snowflake_policy" { + aws_sns_topic_arn = "" +} +``` ## Schema diff --git a/docs/resources/stage.md b/docs/resources/stage.md index 09bff1f17d..418919fe49 100644 --- a/docs/resources/stage.md +++ b/docs/resources/stage.md @@ -32,14 +32,14 @@ resource "snowflake_stage" "example_stage" { ### Optional -- `aws_external_id` (String) +- `aws_external_id` (String) A unique ID assigned to the specific stage. The ID has the following format: <snowflakeAccount>_SFCRole=<snowflakeRoleId>_<randomId> - `comment` (String) Specifies a comment for the stage. - `copy_options` (String) Specifies the copy options for the stage. - `credentials` (String, Sensitive) Specifies the credentials for the stage. - `directory` (String) Specifies the directory settings for the stage. - `encryption` (String) Specifies the encryption settings for the stage. - `file_format` (String) Specifies the file format for the stage. -- `snowflake_iam_user` (String) +- `snowflake_iam_user` (String) An AWS IAM user created for your Snowflake account. This user is the same for every external S3 stage created in your account. - `storage_integration` (String) Specifies the name of the storage integration used to delegate authentication responsibility for external cloud storage to a Snowflake identity and access management (IAM) entity. - `tag` (Block List, Deprecated) Definitions of a tag to associate with the resource. (see [below for nested schema](#nestedblock--tag)) - `url` (String) Specifies the URL for the stage. diff --git a/examples/data-sources/snowflake_system_get_aws_sns_iam_policy/data-source.tf b/examples/data-sources/snowflake_system_get_aws_sns_iam_policy/data-source.tf new file mode 100644 index 0000000000..d7720edf28 --- /dev/null +++ b/examples/data-sources/snowflake_system_get_aws_sns_iam_policy/data-source.tf @@ -0,0 +1,3 @@ +data "snowflake_system_get_aws_sns_iam_policy" "snowflake_policy" { + aws_sns_topic_arn = "" +} diff --git a/pkg/datasources/system_get_aws_sns_iam_policy.go b/pkg/datasources/system_get_aws_sns_iam_policy.go index 1b5e8d0f22..2f27b43736 100644 --- a/pkg/datasources/system_get_aws_sns_iam_policy.go +++ b/pkg/datasources/system_get_aws_sns_iam_policy.go @@ -17,7 +17,6 @@ var systemGetAWSSNSIAMPolicySchema = map[string]*schema.Schema{ Required: true, Description: "Amazon Resource Name (ARN) of the SNS topic for your S3 bucket", }, - "aws_sns_topic_policy_json": { Type: schema.TypeString, Computed: true, diff --git a/pkg/resources/stage.go b/pkg/resources/stage.go index b5046c8224..4d1c549d46 100644 --- a/pkg/resources/stage.go +++ b/pkg/resources/stage.go @@ -80,11 +80,15 @@ var stageSchema = map[string]*schema.Schema{ Type: schema.TypeString, Optional: true, Computed: true, + // Description based on https://docs.snowflake.com/en/user-guide/data-load-s3-config-aws-iam-role#step-3-create-an-external-stage + Description: "A unique ID assigned to the specific stage. The ID has the following format: <snowflakeAccount>_SFCRole=<snowflakeRoleId>_<randomId>", }, "snowflake_iam_user": { Type: schema.TypeString, Optional: true, Computed: true, + // Description based on https://docs.snowflake.com/en/user-guide/data-load-s3-config-aws-iam-role#step-3-create-an-external-stage + Description: "An AWS IAM user created for your Snowflake account. This user is the same for every external S3 stage created in your account.", }, "tag": tagReferenceSchema, } diff --git a/templates/data-sources/system_get_aws_sns_iam_policy.md.tmpl b/templates/data-sources/system_get_aws_sns_iam_policy.md.tmpl new file mode 100644 index 0000000000..99dae46eb4 --- /dev/null +++ b/templates/data-sources/system_get_aws_sns_iam_policy.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 }} +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +For more details, visit the official Snowflake documentation: https://docs.snowflake.com/en/sql-reference/functions/system_get_aws_sns_iam_policy. +Read this guide to understand how to use the snowflake_system_get_aws_sns_iam_policy to integrate with AWS: https://docs.snowflake.com/en/user-guide/data-load-snowpipe-auto-s3#step-1-subscribe-the-snowflake-sqs-queue-to-the-sns-topic. +It's SQL-based, but after knowing what has to be done use corresponding resources and data-sources from the Snowflake and AWS Terraform provider. + +## Example Usage + +{{ tffile (printf "examples/data-sources/%s/data-source.tf" .Name) }} + +{{ .SchemaMarkdown | trimspace }} From 64f4bebd106e8987a153f02787ce4bae396114d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Tue, 7 May 2024 12:52:41 +0200 Subject: [PATCH 2/4] Add missing documentation --- CREATING_ISSUES.md | 24 +++++++++++++++++++----- pkg/snowflake/errors.go | 18 ------------------ 2 files changed, 19 insertions(+), 23 deletions(-) delete mode 100644 pkg/snowflake/errors.go diff --git a/CREATING_ISSUES.md b/CREATING_ISSUES.md index 9f7e56d269..d3358ef066 100644 --- a/CREATING_ISSUES.md +++ b/CREATING_ISSUES.md @@ -57,15 +57,17 @@ It depends on the status of the feature. Snowflake marks features as follows: - Private Preview (PrPr) - Public Preview (PuPr) - Generally Available (GA) -Currently, our main focus is on making the provider stable with the most stable GA features. -If you would like to see a preview feature in the provider, please place a request, but keep in mind that we will most likely take care of preview features after the first stable release (v1.0.0). -Also, If any of the features recently went GA, they will most likely be addressed after v1.0.0 right with the preview ones. + +Currently, our main focus is on making the provider stable with the most stable GA features, +but please take a closer look at our recently updated [roadmap](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/ROADMAP.md#05052024-roadmap-overview) +which describes our priorities for the next quarters. ### When will my bug report be fixed/released? Our team is checking daily incoming GitHub issues. The resolution depends on the complexity and the topic of a given issue, but the general rules are: - If the issue is easy enough, we tend to answer it immediately and provide fix depending on the issue and our current workload. - If the issue needs more insight, we tend to reproduce the issue usually in the matter of days and answer/fix it right away (also very dependent on our current workload). - If the issue is a part of the incoming topic on the [roadmap](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/ROADMAP.md), we postpone it to resolve it with the related tasks. + The releases are usually happening once every two weeks, mostly done on Wednesday. ### How to migrate from version X to Y? @@ -86,6 +88,12 @@ The provider is simply an abstraction issuing SQL commands through the Go Snowfl To see what SQLs are being run you have to set the `TF_LOG=DEBUG` environment variable. To confirm the correctness of the SQLs, refer to the [official Snowflake documentation](https://docs.snowflake.com/). +### How can I import already existing Snowflake infrastructure into Terraform? +Please refer to [this document](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/docs/technical-documentation/resource_migration.md#3-two-options-from-here) +as it describes different approaches of importing the existing Snowflake infrastructure into Terrafrom as configuration. +One thing worth noting is that some approaches can be automated by scripts interacting with Snowflake and generating needed configuration blocks, +which is highly recommended for large-scale migrations. + ## Commonly known issues ### Old Terraform CLI version **Problem:** Sometimes you can get errors similar to: @@ -102,9 +110,15 @@ To confirm the correctness of the SQLs, refer to the [official Snowflake documen **Solution:** You have to be using at least 1.1.5 version of the Terraform CLI. ### Errors with connection to Snowflake -**Problem:** If you are getting connection errors, there may be a chance of finding solution by error id. +**Problem**: If you are getting connection errors with Snowflake error code, similar to this one: +```text +│ +│ Error: open snowflake connection: 390144 (08004): JWT token is invalid. +│ +``` +**Solution**: Go to the [official Snowflake documentation](https://docs.snowflake.com/en/user-guide/key-pair-auth-troubleshooting#list-of-errors) and search by error code (390144 in this case). -**Solution:** Go to the [official Snowflake documentation](https://docs.snowflake.com/) and search for your issue by error id. +[GitHub issue reference](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2432#issuecomment-1915074774) ### How to set up the connection with the private key? **Problem:** From the version v0.78.0, we introduced a lot of provider configuration changes. One of them was deprecating `private_key_path` in favor of `private_key`. diff --git a/pkg/snowflake/errors.go b/pkg/snowflake/errors.go deleted file mode 100644 index 2da2aa3c5e..0000000000 --- a/pkg/snowflake/errors.go +++ /dev/null @@ -1,18 +0,0 @@ -package snowflake - -import ( - "fmt" - "regexp" - "strings" -) - -// Generic Errors. -var ( - ErrNoRowInRS = "sql: no rows in result set" -) - -func IsResourceNotExistOrNotAuthorized(errorString string, resourceType string) bool { - regexStr := fmt.Sprintf("SQL compilation error:%s '.*' does not exist or not authorized", resourceType) - userNotExistOrNotAuthorizedRegEx, _ := regexp.Compile(regexStr) - return userNotExistOrNotAuthorizedRegEx.MatchString(strings.ReplaceAll(errorString, "\n", "")) -} From 4501e72ceb12e2fb254f344aa2ef2a6a71d430b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Tue, 7 May 2024 13:10:01 +0200 Subject: [PATCH 3/4] Re-export internal SDK error and use it --- pkg/resources/grant_privileges_to_account_role.go | 3 +-- pkg/resources/grant_privileges_to_database_role.go | 3 +-- pkg/resources/grant_privileges_to_role.go | 2 +- pkg/resources/role.go | 3 ++- pkg/sdk/errors.go | 4 ++++ 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/pkg/resources/grant_privileges_to_account_role.go b/pkg/resources/grant_privileges_to_account_role.go index fbe53ae1e7..56fab09757 100644 --- a/pkg/resources/grant_privileges_to_account_role.go +++ b/pkg/resources/grant_privileges_to_account_role.go @@ -741,8 +741,7 @@ func ReadGrantPrivilegesToAccountRole(ctx context.Context, d *schema.ResourceDat client := meta.(*provider.Context).Client - // TODO(SNOW-891217): Use custom error. Right now, "object does not exist" error is hidden in sdk/internal/collections package - if _, err := client.Roles.ShowByID(ctx, id.RoleName); err != nil && err.Error() == "object does not exist" { + if _, err := client.Roles.ShowByID(ctx, id.RoleName); err != nil && errors.Is(err, sdk.ErrObjectNotFound) { d.SetId("") return diag.Diagnostics{ diag.Diagnostic{ diff --git a/pkg/resources/grant_privileges_to_database_role.go b/pkg/resources/grant_privileges_to_database_role.go index 0cc23661a1..75b151f11c 100644 --- a/pkg/resources/grant_privileges_to_database_role.go +++ b/pkg/resources/grant_privileges_to_database_role.go @@ -656,8 +656,7 @@ func ReadGrantPrivilegesToDatabaseRole(ctx context.Context, d *schema.ResourceDa } client := meta.(*provider.Context).Client - // TODO(SNOW-891217): Use custom error. Right now, "object does not exist" error is hidden in sdk/internal/collections package - if _, err := client.DatabaseRoles.ShowByID(ctx, id.DatabaseRoleName); err != nil && err.Error() == "object does not exist" { + if _, err := client.DatabaseRoles.ShowByID(ctx, id.DatabaseRoleName); err != nil && errors.Is(err, sdk.ErrObjectNotFound) { d.SetId("") return diag.Diagnostics{ diag.Diagnostic{ diff --git a/pkg/resources/grant_privileges_to_role.go b/pkg/resources/grant_privileges_to_role.go index 21b5ac2e30..357e26d36b 100644 --- a/pkg/resources/grant_privileges_to_role.go +++ b/pkg/resources/grant_privileges_to_role.go @@ -828,7 +828,7 @@ func setRolePrivilegeOptions(privileges []string, allPrivileges bool, onAccount } func readRoleGrantPrivileges(ctx context.Context, client *sdk.Client, grantedOn sdk.ObjectType, id GrantPrivilegesToRoleID, opts *sdk.ShowGrantOptions, d *schema.ResourceData) error { - if _, err := client.Roles.ShowByID(ctx, sdk.NewAccountObjectIdentifier(id.RoleName)); err != nil && err.Error() == "object does not exist" { + if _, err := client.Roles.ShowByID(ctx, sdk.NewAccountObjectIdentifier(id.RoleName)); err != nil && errors.Is(err, sdk.ErrObjectNotFound) { d.SetId("") log.Printf("[DEBUG] Failed to retrieve account role. Marking the resource as removed.") return nil diff --git a/pkg/resources/role.go b/pkg/resources/role.go index 75469c8524..bf585ddf7f 100644 --- a/pkg/resources/role.go +++ b/pkg/resources/role.go @@ -2,6 +2,7 @@ package resources import ( "context" + "errors" "fmt" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" @@ -77,7 +78,7 @@ func ReadAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag accountRole, err := client.Roles.ShowByID(ctx, id) if err != nil { - if err.Error() == "object does not exist" { + if errors.Is(err, sdk.ErrObjectNotFound) { d.SetId("") return diag.Diagnostics{ diag.Diagnostic{ diff --git a/pkg/sdk/errors.go b/pkg/sdk/errors.go index 2d7bbc6089..9b0e22c802 100644 --- a/pkg/sdk/errors.go +++ b/pkg/sdk/errors.go @@ -3,6 +3,7 @@ package sdk import ( "errors" "fmt" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/internal/collections" "log" "regexp" "runtime" @@ -13,6 +14,9 @@ var ( ErrNilOptions = NewError("options cannot be nil") ErrPatternRequiredForLikeKeyword = NewError("pattern must be specified for like keyword") + // re-importing from internal package + ErrObjectNotFound = collections.ErrObjectNotFound + // go-snowflake errors. ErrObjectNotExistOrAuthorized = NewError("object does not exist or not authorized") ErrAccountIsEmpty = NewError("account is empty") From 49b73d1874d8c56609c3fe1360672ae2a56417ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Tue, 7 May 2024 13:27:40 +0200 Subject: [PATCH 4/4] lint fix --- pkg/sdk/errors.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/sdk/errors.go b/pkg/sdk/errors.go index 9b0e22c802..79a659d08d 100644 --- a/pkg/sdk/errors.go +++ b/pkg/sdk/errors.go @@ -3,11 +3,12 @@ package sdk import ( "errors" "fmt" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/internal/collections" "log" "regexp" "runtime" "strings" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/internal/collections" ) var (