diff --git a/docs/resources/api_integration.md b/docs/resources/api_integration.md index e7278dc3320..f96a7d6e720 100644 --- a/docs/resources/api_integration.md +++ b/docs/resources/api_integration.md @@ -13,13 +13,30 @@ description: |- ## Example Usage ```terraform -resource "snowflake_api_integration" "api_integration" { +resource "snowflake_api_integration" "aws" { name = "aws_integration" api_provider = "aws_api_gateway" api_aws_role_arn = "arn:aws:iam::000000000001:/role/test" api_allowed_prefixes = ["https://123456.execute-api.us-west-2.amazonaws.com/prod/"] enabled = true } + +resource "snowflake_api_integration" "azure" { + name = "azure_integration" + api_provider = "azure_api_management" + azure_tenant_id = "00000000-0000-0000-0000-000000000000" + azure_ad_application_id = "11111111-1111-1111-1111-111111111111" + api_allowed_prefixes = ["https://apim-hello-world.azure-api.net/"] + enabled = true +} + +resource "snowflake_api_integration" "gcp" { + name = "gcp_integration" + api_provider = "google_api_gateway" + google_audience = "api-gateway-id-123456.apigateway.gcp-project.cloud.goog" + api_allowed_prefixes = ["https://gateway-id-123456.uc.gateway.dev/"] + enabled = true +} ``` @@ -38,7 +55,9 @@ resource "snowflake_api_integration" "api_integration" { - `api_key` (String, Sensitive) The API key (also called a “subscription key”). - `azure_ad_application_id` (String) The 'Application (client) id' of the Azure AD app for your remote service. - `azure_tenant_id` (String) Specifies the ID for your Office 365 tenant that all Azure API Management instances belong to. +- `comment` (String) - `enabled` (Boolean) Specifies whether this API integration is enabled or disabled. If the API integration is disabled, any external function that relies on it will not work. +- `google_audience` (String) The audience claim when generating the JWT (JSON Web Token) to authenticate to the Google API Gateway. ### Read-Only diff --git a/examples/resources/snowflake_api_integration/resource.tf b/examples/resources/snowflake_api_integration/resource.tf index 8da0dfc97f1..4c0d75dc7bd 100644 --- a/examples/resources/snowflake_api_integration/resource.tf +++ b/examples/resources/snowflake_api_integration/resource.tf @@ -1,7 +1,24 @@ -resource "snowflake_api_integration" "api_integration" { +resource "snowflake_api_integration" "aws" { name = "aws_integration" api_provider = "aws_api_gateway" api_aws_role_arn = "arn:aws:iam::000000000001:/role/test" api_allowed_prefixes = ["https://123456.execute-api.us-west-2.amazonaws.com/prod/"] enabled = true +} + +resource "snowflake_api_integration" "azure" { + name = "azure_integration" + api_provider = "azure_api_management" + azure_tenant_id = "00000000-0000-0000-0000-000000000000" + azure_ad_application_id = "11111111-1111-1111-1111-111111111111" + api_allowed_prefixes = ["https://apim-hello-world.azure-api.net/"] + enabled = true +} + +resource "snowflake_api_integration" "gcp" { + name = "gcp_integration" + api_provider = "google_api_gateway" + google_audience = "api-gateway-id-123456.apigateway.gcp-project.cloud.goog" + api_allowed_prefixes = ["https://gateway-id-123456.uc.gateway.dev/"] + enabled = true } \ No newline at end of file diff --git a/pkg/resources/api_integration.go b/pkg/resources/api_integration.go index cc755168e2d..76b04be3b48 100644 --- a/pkg/resources/api_integration.go +++ b/pkg/resources/api_integration.go @@ -21,7 +21,7 @@ var apiIntegrationSchema = map[string]*schema.Schema{ "api_provider": { Type: schema.TypeString, Required: true, - ValidateFunc: validation.StringInSlice([]string{"aws_api_gateway", "aws_private_api_gateway", "azure_api_management", "aws_gov_api_gateway", "aws_gov_private_api_gateway"}, false), + ValidateFunc: validation.StringInSlice([]string{"aws_api_gateway", "aws_private_api_gateway", "azure_api_management", "aws_gov_api_gateway", "aws_gov_private_api_gateway", "google_api_gateway"}, false), Description: "Specifies the HTTPS proxy service type.", }, "api_aws_role_arn": { @@ -64,6 +64,12 @@ var apiIntegrationSchema = map[string]*schema.Schema{ Type: schema.TypeString, Computed: true, }, + "google_audience": { + Type: schema.TypeString, + Optional: true, + Default: "", + Description: "The audience claim when generating the JWT (JSON Web Token) to authenticate to the Google API Gateway.", + }, "api_allowed_prefixes": { Type: schema.TypeList, Elem: &schema.Schema{Type: schema.TypeString}, @@ -89,6 +95,10 @@ var apiIntegrationSchema = map[string]*schema.Schema{ Default: true, Description: "Specifies whether this API integration is enabled or disabled. If the API integration is disabled, any external function that relies on it will not work.", }, + "comment": { + Type: schema.TypeString, + Optional: true, + }, "created_on": { Type: schema.TypeString, Computed: true, @@ -132,6 +142,10 @@ func CreateAPIIntegration(d *schema.ResourceData, meta interface{}) error { stmt.SetString("API_KEY", d.Get("api_key").(string)) } + if _, ok := d.GetOk("comment"); ok { + stmt.SetString("COMMENT", d.Get("comment").(string)) + } + // Now, set the API provider if err := setAPIProviderSettings(d, stmt); err != nil { return err @@ -175,6 +189,10 @@ func ReadAPIIntegration(d *schema.ResourceData, meta interface{}) error { return err } + if err := d.Set("comment", s.Comment.String); err != nil { + return err + } + if err := d.Set("created_on", s.CreatedOn.String); err != nil { return err } @@ -230,6 +248,10 @@ func ReadAPIIntegration(d *schema.ResourceData, meta interface{}) error { if err := d.Set("azure_multi_tenant_app_name", v.(string)); err != nil { return err } + case "GOOGLE_AUDIENCE": + if err := d.Set("google_audience", v.(string)); err != nil { + return err + } default: log.Printf("[WARN] unexpected api integration property %v returned from Snowflake", k) } @@ -262,6 +284,11 @@ func UpdateAPIIntegration(d *schema.ResourceData, meta interface{}) error { stmt.SetString("API_KEY", d.Get("api_key").(string)) } + if d.HasChange("comment") { + runSetStatement = true + stmt.SetString("COMMENT", d.Get("comment").(string)) + } + // We need to UNSET this if we remove all api blocked prefixes. if d.HasChange("api_blocked_prefixes") { v := d.Get("api_blocked_prefixes").([]interface{}) @@ -294,6 +321,10 @@ func UpdateAPIIntegration(d *schema.ResourceData, meta interface{}) error { runSetStatement = true stmt.SetString("AZURE_AD_APPLICATION_ID", d.Get("azure_ad_application_id").(string)) } + if d.HasChange("google_audience") { + runSetStatement = true + stmt.SetString("GOOGLE_AUDIENCE", d.Get("google_audience").(string)) + } } if runSetStatement { @@ -333,6 +364,12 @@ func setAPIProviderSettings(data *schema.ResourceData, stmt snowflake.SettingBui return fmt.Errorf("if you use the Azure api provider you must specify an azure_ad_application_id") } stmt.SetString(`AZURE_AD_APPLICATION_ID`, v.(string)) + case "google_api_gateway": + v, ok := data.GetOk("google_audience") + if !ok { + return fmt.Errorf("if you use GCP api provider you must specify a google_audience") + } + stmt.SetString(`GOOGLE_AUDIENCE`, v.(string)) default: return fmt.Errorf("unexpected provider %v", apiProvider) } diff --git a/pkg/resources/api_integration_acceptance_test.go b/pkg/resources/api_integration_acceptance_test.go index 1b10791d6ba..78f6a106c87 100644 --- a/pkg/resources/api_integration_acceptance_test.go +++ b/pkg/resources/api_integration_acceptance_test.go @@ -15,18 +15,20 @@ func TestAcc_ApiIntegration(t *testing.T) { t.Skip("Skipping TestAccApiIntegration") } - apiIntName := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) - apiIntName2 := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + apiIntNameAWS := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + apiIntNameAzure := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + apiIntNameGCP := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) resource.Test(t, resource.TestCase{ Providers: providers(), CheckDestroy: nil, Steps: []resource.TestStep{ { - Config: apiIntegrationConfigAWS(apiIntName, []string{"https://123456.execute-api.us-west-2.amazonaws.com/prod/"}), + Config: apiIntegrationConfigAWS(apiIntNameAWS, []string{"https://123456.execute-api.us-west-2.amazonaws.com/prod/"}), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_api_integration.test_aws_int", "name", apiIntName), + resource.TestCheckResourceAttr("snowflake_api_integration.test_aws_int", "name", apiIntNameAWS), resource.TestCheckResourceAttr("snowflake_api_integration.test_aws_int", "api_provider", "aws_api_gateway"), + resource.TestCheckResourceAttr("snowflake_api_integration.test_aws_int", "comment", "acceptance test"), resource.TestCheckResourceAttrSet("snowflake_api_integration.test_aws_int", "created_on"), resource.TestCheckResourceAttrSet("snowflake_api_integration.test_aws_int", "api_aws_iam_user_arn"), resource.TestCheckResourceAttrSet("snowflake_api_integration.test_aws_int", "api_aws_external_id"), @@ -34,16 +36,27 @@ func TestAcc_ApiIntegration(t *testing.T) { ), }, { - Config: apiIntegrationConfigAzure(apiIntName2, []string{"https://apim-hello-world.azure-api.net/"}), + Config: apiIntegrationConfigAzure(apiIntNameAzure, []string{"https://apim-hello-world.azure-api.net/"}), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_api_integration.test_azure_int", "name", apiIntName2), + resource.TestCheckResourceAttr("snowflake_api_integration.test_azure_int", "name", apiIntNameAzure), resource.TestCheckResourceAttr("snowflake_api_integration.test_azure_int", "api_provider", "azure_api_management"), + resource.TestCheckResourceAttr("snowflake_api_integration.test_azure_int", "comment", "acceptance test"), resource.TestCheckResourceAttrSet("snowflake_api_integration.test_azure_int", "created_on"), resource.TestCheckResourceAttrSet("snowflake_api_integration.test_azure_int", "azure_multi_tenant_app_name"), resource.TestCheckResourceAttrSet("snowflake_api_integration.test_azure_int", "azure_consent_url"), resource.TestCheckResourceAttrSet("snowflake_api_integration.test_azure_int", "api_key"), ), }, + { + Config: apiIntegrationConfigGCP(apiIntNameGCP, []string{"https://gateway-id-123456.uc.gateway.dev/"}), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("snowflake_api_integration.test_gcp_int", "name", apiIntNameGCP), + resource.TestCheckResourceAttr("snowflake_api_integration.test_gcp_int", "api_provider", "google_api_gateway"), + resource.TestCheckResourceAttr("snowflake_api_integration.test_gcp_int", "comment", "acceptance test"), + resource.TestCheckResourceAttrSet("snowflake_api_integration.test_gcp_int", "created_on"), + resource.TestCheckResourceAttrSet("snowflake_api_integration.test_gcp_int", "google_audience"), + ), + }, }, }) } @@ -56,6 +69,7 @@ func apiIntegrationConfigAWS(name string, prefixes []string) string { api_aws_role_arn = "arn:aws:iam::000000000001:/role/test" api_allowed_prefixes = %q api_key = "12345" + comment = "acceptance test" enabled = true } `, name, prefixes) @@ -70,6 +84,20 @@ func apiIntegrationConfigAzure(name string, prefixes []string) string { azure_ad_application_id = "7890" api_allowed_prefixes = %q api_key = "12345" + comment = "acceptance test" + enabled = true + } + `, name, prefixes) +} + +func apiIntegrationConfigGCP(name string, prefixes []string) string { + return fmt.Sprintf(` + resource "snowflake_api_integration" "test_gcp_int" { + name = "%s" + api_provider = "google_api_gateway" + google_audience = "api-gateway-id-123456.apigateway.gcp-project.cloud.goog" + api_allowed_prefixes = %q + comment = "acceptance test" enabled = true } `, name, prefixes) diff --git a/pkg/snowflake/api_integration.go b/pkg/snowflake/api_integration.go index ed09d5f73cf..11ff2d6c715 100644 --- a/pkg/snowflake/api_integration.go +++ b/pkg/snowflake/api_integration.go @@ -28,6 +28,7 @@ type APIIntegration struct { Category sql.NullString `db:"category"` IntegrationType sql.NullString `db:"type"` CreatedOn sql.NullString `db:"created_on"` + Comment sql.NullString `db:"comment"` Enabled sql.NullBool `db:"enabled"` }