Skip to content

Commit

Permalink
feat(integration): add google api integration
Browse files Browse the repository at this point in the history
  • Loading branch information
philippeboyd committed Mar 1, 2023
1 parent 23b64fa commit 4031b41
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 9 deletions.
21 changes: 20 additions & 1 deletion docs/resources/api_integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
```

<!-- schema generated by tfplugindocs -->
Expand All @@ -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

Expand Down
19 changes: 18 additions & 1 deletion examples/resources/snowflake_api_integration/resource.tf
Original file line number Diff line number Diff line change
@@ -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
}
39 changes: 38 additions & 1 deletion pkg/resources/api_integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down Expand Up @@ -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},
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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{})
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}
Expand Down
40 changes: 34 additions & 6 deletions pkg/resources/api_integration_acceptance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,48 @@ 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"),
resource.TestCheckResourceAttrSet("snowflake_api_integration.test_aws_int", "api_key"),
),
},
{
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"),
),
},
},
})
}
Expand All @@ -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)
Expand All @@ -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)
Expand Down
1 change: 1 addition & 0 deletions pkg/snowflake/api_integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}

Expand Down

0 comments on commit 4031b41

Please sign in to comment.