From 187222b9fd4eddc5226fcc3e69cd7b058f079f40 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 22 Jun 2020 18:12:06 -0400 Subject: [PATCH 1/9] Add aws_apigatewayv2_api and aws_apigatewayv2_apis data source. --- .changelog/13883.txt | 7 + aws/data_source_aws_apigatewayv2_api.go | 149 +++++++++++++++ aws/data_source_aws_apigatewayv2_api_test.go | 127 +++++++++++++ aws/data_source_aws_apigatewayv2_apis.go | 105 +++++++++++ aws/data_source_aws_apigatewayv2_apis_test.go | 170 ++++++++++++++++++ aws/provider.go | 2 + website/docs/d/apigatewayv2_api.html.markdown | 57 ++++++ .../docs/d/apigatewayv2_apis.html.markdown | 34 ++++ website/docs/index.html.markdown | 1 + 9 files changed, 652 insertions(+) create mode 100644 .changelog/13883.txt create mode 100644 aws/data_source_aws_apigatewayv2_api.go create mode 100644 aws/data_source_aws_apigatewayv2_api_test.go create mode 100644 aws/data_source_aws_apigatewayv2_apis.go create mode 100644 aws/data_source_aws_apigatewayv2_apis_test.go create mode 100644 website/docs/d/apigatewayv2_api.html.markdown create mode 100644 website/docs/d/apigatewayv2_apis.html.markdown diff --git a/.changelog/13883.txt b/.changelog/13883.txt new file mode 100644 index 00000000000..07581b9f2eb --- /dev/null +++ b/.changelog/13883.txt @@ -0,0 +1,7 @@ +```release-note:new-data-source +aws_apigatewayv2_api +``` + +```release-note:new-data-source +aws_apigatewayv2_api +``` diff --git a/aws/data_source_aws_apigatewayv2_api.go b/aws/data_source_aws_apigatewayv2_api.go new file mode 100644 index 00000000000..5c4c6c9faff --- /dev/null +++ b/aws/data_source_aws_apigatewayv2_api.go @@ -0,0 +1,149 @@ +package aws + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +func dataSourceAwsApiGatewayV2Api() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsAwsApiGatewayV2ApiRead, + + Schema: map[string]*schema.Schema{ + "api_endpoint": { + Type: schema.TypeString, + Computed: true, + }, + "api_id": { + Type: schema.TypeString, + Required: true, + }, + "api_key_selection_expression": { + Type: schema.TypeString, + Computed: true, + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "cors_configuration": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allow_credentials": { + Type: schema.TypeBool, + Computed: true, + }, + "allow_headers": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: hashStringCaseInsensitive, + }, + "allow_methods": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: hashStringCaseInsensitive, + }, + "allow_origins": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: hashStringCaseInsensitive, + }, + "expose_headers": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: hashStringCaseInsensitive, + }, + "max_age": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "execution_arn": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "protocol_type": { + Type: schema.TypeString, + Computed: true, + }, + "route_selection_expression": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsSchemaComputed(), + "version": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceAwsAwsApiGatewayV2ApiRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigatewayv2conn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + d.SetId(d.Get("api_id").(string)) + + input := &apigatewayv2.GetApiInput{ + ApiId: aws.String(d.Id()), + } + + output, err := conn.GetApi(input) + + if err != nil { + return fmt.Errorf("error reading API Gateway v2 API (%s): %s", d.Id(), err) + } + + d.Set("api_endpoint", output.ApiEndpoint) + d.Set("api_key_selection_expression", output.ApiKeySelectionExpression) + apiArn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Service: "apigateway", + Region: meta.(*AWSClient).region, + Resource: fmt.Sprintf("/apis/%s", d.Id()), + }.String() + d.Set("arn", apiArn) + if err := d.Set("cors_configuration", flattenApiGateway2CorsConfiguration(output.CorsConfiguration)); err != nil { + return fmt.Errorf("error setting cors_configuration: %s", err) + } + d.Set("description", output.Description) + executionArn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Service: "execute-api", + Region: meta.(*AWSClient).region, + AccountID: meta.(*AWSClient).accountid, + Resource: d.Id(), + }.String() + d.Set("execution_arn", executionArn) + d.Set("name", output.Name) + d.Set("protocol_type", output.ProtocolType) + d.Set("route_selection_expression", output.RouteSelectionExpression) + if err := d.Set("tags", keyvaluetags.Apigatewayv2KeyValueTags(output.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + d.Set("version", output.Version) + + return nil +} diff --git a/aws/data_source_aws_apigatewayv2_api_test.go b/aws/data_source_aws_apigatewayv2_api_test.go new file mode 100644 index 00000000000..24e8e96f8fb --- /dev/null +++ b/aws/data_source_aws_apigatewayv2_api_test.go @@ -0,0 +1,127 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccAWSAPIGatewayV2ApiDataSource_Http(t *testing.T) { + dataSourceName := "data.aws_apigatewayv2_api.test" + resourceName := "aws_apigatewayv2_api.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGatewayV2ApiDataSourceConfigHttp(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "api_endpoint", resourceName, "api_endpoint"), + resource.TestCheckResourceAttrPair(dataSourceName, "api_key_selection_expression", resourceName, "api_key_selection_expression"), + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "cors_configuration.#", resourceName, "cors_configuration.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "cors_configuration.0.allow_credentials", resourceName, "cors_configuration.0.allow_credentials"), + resource.TestCheckResourceAttrPair(dataSourceName, "cors_configuration.0.allow_headers.#", resourceName, "cors_configuration.0.allow_headers.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "cors_configuration.0.allow_methods.#", resourceName, "cors_configuration.0.allow_methods.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "cors_configuration.0.allow_origins.#", resourceName, "cors_configuration.0.allow_origins.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "cors_configuration.0.expose_headers.#", resourceName, "cors_configuration.0.expose_headers.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "cors_configuration.0.max_age", resourceName, "cors_configuration.0.max_age"), + resource.TestCheckResourceAttrPair(dataSourceName, "description", resourceName, "description"), + resource.TestCheckResourceAttrPair(dataSourceName, "execution_arn", resourceName, "execution_arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "protocol_type", resourceName, "protocol_type"), + resource.TestCheckResourceAttrPair(dataSourceName, "route_selection_expression", resourceName, "route_selection_expression"), + resource.TestCheckResourceAttrPair(dataSourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttrPair(dataSourceName, "tags.Key1", resourceName, "tags.Key1"), + resource.TestCheckResourceAttrPair(dataSourceName, "tags.Key2", resourceName, "tags.Key2"), + resource.TestCheckResourceAttrPair(dataSourceName, "version", resourceName, "version"), + ), + }, + }, + }) +} + +func TestAccAWSAPIGatewayV2ApiDataSource_WebSocket(t *testing.T) { + dataSourceName := "data.aws_apigatewayv2_api.test" + resourceName := "aws_apigatewayv2_api.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGatewayV2ApiDataSourceConfigWebSocket(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "api_endpoint", resourceName, "api_endpoint"), + resource.TestCheckResourceAttrPair(dataSourceName, "api_key_selection_expression", resourceName, "api_key_selection_expression"), + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "cors_configuration.#", resourceName, "cors_configuration.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "description", resourceName, "description"), + resource.TestCheckResourceAttrPair(dataSourceName, "execution_arn", resourceName, "execution_arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "protocol_type", resourceName, "protocol_type"), + resource.TestCheckResourceAttrPair(dataSourceName, "route_selection_expression", resourceName, "route_selection_expression"), + resource.TestCheckResourceAttrPair(dataSourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttrPair(dataSourceName, "tags.Key1", resourceName, "tags.Key1"), + resource.TestCheckResourceAttrPair(dataSourceName, "tags.Key2", resourceName, "tags.Key2"), + resource.TestCheckResourceAttrPair(dataSourceName, "version", resourceName, "version"), + ), + }, + }, + }) +} + +func testAccAWSAPIGatewayV2ApiDataSourceConfigHttp(rName string) string { + return fmt.Sprintf(` +resource "aws_apigatewayv2_api" "test" { + description = "test description" + name = %[1]q + protocol_type = "HTTP" + version = "v1" + + cors_configuration { + allow_headers = ["Authorization"] + allow_methods = ["GET", "put"] + allow_origins = ["https://www.example.com"] + } + + tags = { + Key1 = "Value1h" + Key2 = "Value2h" + } +} + +data "aws_apigatewayv2_api" "test" { + api_id = aws_apigatewayv2_api.test.id +} +`, rName) +} + +func testAccAWSAPIGatewayV2ApiDataSourceConfigWebSocket(rName string) string { + return fmt.Sprintf(` +resource "aws_apigatewayv2_api" "test" { + api_key_selection_expression = "$context.authorizer.usageIdentifierKey" + description = "test description" + name = %[1]q + protocol_type = "WEBSOCKET" + route_selection_expression = "$request.body.service" + version = "v1" + + tags = { + Key1 = "Value1ws" + Key2 = "Value2ws" + } +} + +data "aws_apigatewayv2_api" "test" { + api_id = aws_apigatewayv2_api.test.id +} +`, rName) +} diff --git a/aws/data_source_aws_apigatewayv2_apis.go b/aws/data_source_aws_apigatewayv2_apis.go new file mode 100644 index 00000000000..223bc756a59 --- /dev/null +++ b/aws/data_source_aws_apigatewayv2_apis.go @@ -0,0 +1,105 @@ +package aws + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +func dataSourceAwsApiGatewayV2Apis() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsAwsApiGatewayV2ApisRead, + + Schema: map[string]*schema.Schema{ + "ids": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + "protocol_type": { + Type: schema.TypeString, + Optional: true, + }, + "tags": tagsSchema(), + }, + } +} + +func dataSourceAwsAwsApiGatewayV2ApisRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigatewayv2conn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + tagsToMatch := keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().IgnoreConfig(ignoreTagsConfig) + + var ids []*string + + err := ListAllApiGatewayV2Apis(conn, func(page *apigatewayv2.GetApisOutput, isLast bool) bool { + if page == nil { + return !isLast + } + + for _, api := range page.Items { + if v, ok := d.GetOk("name"); ok && v.(string) != aws.StringValue(api.Name) { + continue + } + + if v, ok := d.GetOk("protocol_type"); ok && v.(string) != aws.StringValue(api.ProtocolType) { + continue + } + + if len(tagsToMatch) > 0 && !keyvaluetags.Apigatewayv2KeyValueTags(api.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).ContainsAll(tagsToMatch) { + continue + } + + ids = append(ids, api.ApiId) + } + + return !isLast + }) + + if err != nil { + return fmt.Errorf("error listing API Gateway v2 APIs: %w", err) + } + + d.SetId(resource.UniqueId()) + + if err := d.Set("ids", flattenStringSet(ids)); err != nil { + return fmt.Errorf("error setting ids: %w", err) + } + + return nil +} + +// +// These can be moved to a per-service package like "aws/internal/service/apigatewayv2/lister" in the future. +// + +func ListAllApiGatewayV2Apis(conn *apigatewayv2.ApiGatewayV2, fn func(*apigatewayv2.GetApisOutput, bool) bool) error { + return ListApiGatewayV2ApisPages(conn, &apigatewayv2.GetApisInput{}, fn) +} + +func ListApiGatewayV2ApisPages(conn *apigatewayv2.ApiGatewayV2, input *apigatewayv2.GetApisInput, fn func(*apigatewayv2.GetApisOutput, bool) bool) error { + for { + output, err := conn.GetApis(input) + if err != nil { + return err + } + + lastPage := aws.StringValue(output.NextToken) == "" + if !fn(output, lastPage) || lastPage { + break + } + + input.NextToken = output.NextToken + } + return nil +} diff --git a/aws/data_source_aws_apigatewayv2_apis_test.go b/aws/data_source_aws_apigatewayv2_apis_test.go new file mode 100644 index 00000000000..fe273de3587 --- /dev/null +++ b/aws/data_source_aws_apigatewayv2_apis_test.go @@ -0,0 +1,170 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccAWSAPIGatewayV2ApisDataSource_Name(t *testing.T) { + dataSource1Name := "data.aws_apigatewayv2_apis.test1" + dataSource2Name := "data.aws_apigatewayv2_apis.test2" + rName1 := acctest.RandomWithPrefix("tf-acc-test") + rName2 := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGatewayV2ApisDataSourceConfigName(rName1, rName2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSource1Name, "ids.#", "1"), + resource.TestCheckResourceAttr(dataSource2Name, "ids.#", "2"), + ), + }, + }, + }) +} + +func TestAccAWSAPIGatewayV2ApisDataSource_ProtocolType(t *testing.T) { + dataSource1Name := "data.aws_apigatewayv2_apis.test1" + dataSource2Name := "data.aws_apigatewayv2_apis.test2" + rName1 := acctest.RandomWithPrefix("tf-acc-test") + rName2 := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGatewayV2ApisDataSourceConfigProtocolType(rName1, rName2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSource1Name, "ids.#", "1"), + resource.TestCheckResourceAttr(dataSource2Name, "ids.#", "1"), + ), + }, + }, + }) +} + +func TestAccAWSAPIGatewayV2ApisDataSource_Tags(t *testing.T) { + dataSource1Name := "data.aws_apigatewayv2_apis.test1" + dataSource2Name := "data.aws_apigatewayv2_apis.test2" + dataSource3Name := "data.aws_apigatewayv2_apis.test3" + rName1 := acctest.RandomWithPrefix("tf-acc-test") + rName2 := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGatewayV2ApisDataSourceConfigTags(rName1, rName2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSource1Name, "ids.#", "1"), + resource.TestCheckResourceAttr(dataSource2Name, "ids.#", "2"), + resource.TestCheckResourceAttr(dataSource3Name, "ids.#", "0"), + ), + }, + }, + }) +} + +func testAccAWSAPIGatewayV2ApisDataSourceConfigBase(rName1, rName2 string) string { + return fmt.Sprintf(` +resource "aws_apigatewayv2_api" "test1" { + name = %[1]q + protocol_type = "HTTP" + + tags = { + Name = %[1]q + } +} + +resource "aws_apigatewayv2_api" "test2" { + name = %[2]q + protocol_type = "HTTP" + + tags = { + Name = %[2]q + } +} + +resource "aws_apigatewayv2_api" "test3" { + name = %[2]q + protocol_type = "WEBSOCKET" + route_selection_expression = "$request.body.action" + + tags = { + Name = %[2]q + } +} +`, rName1, rName2) +} + +func testAccAWSAPIGatewayV2ApisDataSourceConfigName(rName1, rName2 string) string { + return composeConfig( + testAccAWSAPIGatewayV2ApisDataSourceConfigBase(rName1, rName2), + fmt.Sprintf(` +data "aws_apigatewayv2_apis" "test1" { + # Force dependency on resources. + name = element([aws_apigatewayv2_api.test1.name, aws_apigatewayv2_api.test2.name, aws_apigatewayv2_api.test3.name], 0) +} + +data "aws_apigatewayv2_apis" "test2" { + # Force dependency on resources. + name = element([aws_apigatewayv2_api.test1.name, aws_apigatewayv2_api.test2.name, aws_apigatewayv2_api.test3.name], 1) +} +`)) +} + +func testAccAWSAPIGatewayV2ApisDataSourceConfigProtocolType(rName1, rName2 string) string { + return composeConfig( + testAccAWSAPIGatewayV2ApisDataSourceConfigBase(rName1, rName2), + fmt.Sprintf(` +data "aws_apigatewayv2_apis" "test1" { + name = %[1]q + + protocol_type = element([aws_apigatewayv2_api.test1.protocol_type, aws_apigatewayv2_api.test2.protocol_type, aws_apigatewayv2_api.test3.protocol_type], 0) +} + +data "aws_apigatewayv2_apis" "test2" { + name = %[2]q + + protocol_type = element([aws_apigatewayv2_api.test1.protocol_type, aws_apigatewayv2_api.test2.protocol_type, aws_apigatewayv2_api.test3.protocol_type], 3) +} +`, rName1, rName2)) +} + +func testAccAWSAPIGatewayV2ApisDataSourceConfigTags(rName1, rName2 string) string { + return composeConfig( + testAccAWSAPIGatewayV2ApisDataSourceConfigBase(rName1, rName2), + fmt.Sprintf(` +data "aws_apigatewayv2_apis" "test1" { + tags = { + Name = element([aws_apigatewayv2_api.test1.name, aws_apigatewayv2_api.test2.name, aws_apigatewayv2_api.test3.name], 0) + } +} + +data "aws_apigatewayv2_apis" "test2" { + # Force dependency on resources. + tags = { + Name = element([aws_apigatewayv2_api.test1.name, aws_apigatewayv2_api.test2.name, aws_apigatewayv2_api.test3.name], 1) + } +} + +data "aws_apigatewayv2_apis" "test3" { + # Force dependency on resources. + tags = { + Name = element([aws_apigatewayv2_api.test1.name, aws_apigatewayv2_api.test2.name, aws_apigatewayv2_api.test3.name], 2) + Key2 = "Value2" + } +} +`)) +} diff --git a/aws/provider.go b/aws/provider.go index d07e1c7deca..0233675883b 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -175,6 +175,8 @@ func Provider() *schema.Provider { "aws_api_gateway_resource": dataSourceAwsApiGatewayResource(), "aws_api_gateway_rest_api": dataSourceAwsApiGatewayRestApi(), "aws_api_gateway_vpc_link": dataSourceAwsApiGatewayVpcLink(), + "aws_apigatewayv2_api": dataSourceAwsApiGatewayV2Api(), + "aws_apigatewayv2_apis": dataSourceAwsApiGatewayV2Apis(), "aws_arn": dataSourceAwsArn(), "aws_autoscaling_group": dataSourceAwsAutoscalingGroup(), "aws_autoscaling_groups": dataSourceAwsAutoscalingGroups(), diff --git a/website/docs/d/apigatewayv2_api.html.markdown b/website/docs/d/apigatewayv2_api.html.markdown new file mode 100644 index 00000000000..ad2ba037140 --- /dev/null +++ b/website/docs/d/apigatewayv2_api.html.markdown @@ -0,0 +1,57 @@ +--- +subcategory: "API Gateway v2 (WebSocket and HTTP APIs)" +layout: "aws" +page_title: "AWS: aws_apigatewayv2_api" +description: |- + Provides details about a specific Amazon API Gateway Version 2 API. +--- + +# Data Source: aws_apigatewayv2_api + +Provides details about a specific Amazon API Gateway Version 2 API. + +## Example Usage + +```hcl +data "aws_apigatewayv2_api" "example" { + api_id = "aabbccddee" +} +``` + +## Argument Reference + +The arguments of this data source act as filters for querying the available APIs in the current region. +The given filters must match exactly one API whose data will be exported as attributes. + +The following arguments are supported: + +* `api_id` - (Required) The API identifier. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `api_endpoint` - The URI of the API, of the form `{api-id}.execute-api.{region}.amazonaws.com`. +* `api_key_selection_expression` - An [API key selection expression](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-selection-expressions.html#apigateway-websocket-api-apikey-selection-expressions). +Applicable for WebSocket APIs. +* `arn` - The ARN of the API. +* `cors_configuration` - The cross-origin resource sharing (CORS) [configuration](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html). +Applicable for HTTP APIs. +* `description` - The description of the API. +* `execution_arn` - The ARN prefix to be used in an [`aws_lambda_permission`](/docs/providers/aws/r/lambda_permission.html)'s `source_arn` attribute +or in an [`aws_iam_policy`](/docs/providers/aws/r/iam_policy.html) to authorize access to the [`@connections` API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-how-to-call-websocket-api-connections.html). +See the [Amazon API Gateway Developer Guide](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-control-access-iam.html) for details. +* `name` - The name of the API. +* `protocol_type` - The API protocol. +* `route_selection_expression` - The [route selection expression](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-selection-expressions.html#apigateway-websocket-api-route-selection-expressions) for the API. +* `tags` - A map of resource tags. +* `version` - A version identifier for the API. + +The `cors_configuration` object supports the following: + +* `allow_credentials` - Whether credentials are included in the CORS request. +* `allow_headers` - The set of allowed HTTP headers. +* `allow_methods` - The set of allowed HTTP methods. +* `allow_origins` - The set of allowed origins. +* `expose_headers` - The set of exposed HTTP headers. +* `max_age` - The number of seconds that the browser should cache preflight request results. diff --git a/website/docs/d/apigatewayv2_apis.html.markdown b/website/docs/d/apigatewayv2_apis.html.markdown new file mode 100644 index 00000000000..0ca93231276 --- /dev/null +++ b/website/docs/d/apigatewayv2_apis.html.markdown @@ -0,0 +1,34 @@ +--- +subcategory: "API Gateway v2 (WebSocket and HTTP APIs)" +layout: "aws" +page_title: "AWS: aws_apigatewayv2_apis" +description: |- + Provides details about multiple Amazon API Gateway Version 2 APIs. +--- + +# Data Source: aws_apigatewayv2_apis + +Provides details about multiple Amazon API Gateway Version 2 APIs. + +## Example Usage + +```hcl +data "aws_apigatewayv2_apis" "example" { + protocol_type = "HTTP" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Optional) The API name. +* `protocol_type` - (Optional) The API protocol. +* `tags` - (Optional) A map of tags, each pair of which must exactly match + a pair on the desired APIs. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `ids` - Set of API identifiers. diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index 99810d6fe98..ee1f9fed757 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -241,6 +241,7 @@ for more information about connecting to alternate AWS endpoints or AWS compatib - [`aws_api_gateway_deployment` resource](/docs/providers/aws/r/api_gateway_deployment.html) - [`aws_api_gateway_rest_api` resource](/docs/providers/aws/r/api_gateway_rest_api.html) - [`aws_api_gateway_stage` resource](/docs/providers/aws/r/api_gateway_stage.html) + - [`aws_apigatewayv2_api` data source](/docs/providers/aws/d/apigatewayv2_api.html) - [`aws_apigatewayv2_api` resource](/docs/providers/aws/r/apigatewayv2_api.html) - [`aws_apigatewayv2_stage` resource](/docs/providers/aws/r/apigatewayv2_stage.html) - [`aws_athena_workgroup` resource](/docs/providers/aws/r/athena_workgroup.html) From 8d20dbba7bcd237a5ae1c7c980c742697f6418e1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Feb 2021 12:51:29 -0500 Subject: [PATCH 2/9] d/aws_apigatewayv2_api: Add 'disable_execute_api_endpoint' attribute. Acceptance test output: $ make testacc TEST=./aws/ TESTARGS='-run=TestAccAWSAPIGatewayV2ApiDataSource_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAPIGatewayV2ApiDataSource_ -timeout 120m === RUN TestAccAWSAPIGatewayV2ApiDataSource_Http === PAUSE TestAccAWSAPIGatewayV2ApiDataSource_Http === RUN TestAccAWSAPIGatewayV2ApiDataSource_WebSocket === PAUSE TestAccAWSAPIGatewayV2ApiDataSource_WebSocket === CONT TestAccAWSAPIGatewayV2ApiDataSource_Http === CONT TestAccAWSAPIGatewayV2ApiDataSource_WebSocket --- PASS: TestAccAWSAPIGatewayV2ApiDataSource_Http (13.52s) --- PASS: TestAccAWSAPIGatewayV2ApiDataSource_WebSocket (13.95s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 14.049s --- aws/data_source_aws_apigatewayv2_api.go | 5 +++++ aws/data_source_aws_apigatewayv2_api_test.go | 2 ++ website/docs/d/apigatewayv2_api.html.markdown | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/aws/data_source_aws_apigatewayv2_api.go b/aws/data_source_aws_apigatewayv2_api.go index 5c4c6c9faff..9eb63300b08 100644 --- a/aws/data_source_aws_apigatewayv2_api.go +++ b/aws/data_source_aws_apigatewayv2_api.go @@ -75,6 +75,10 @@ func dataSourceAwsApiGatewayV2Api() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "disable_execute_api_endpoint": { + Type: schema.TypeBool, + Computed: true, + }, "execution_arn": { Type: schema.TypeString, Computed: true, @@ -129,6 +133,7 @@ func dataSourceAwsAwsApiGatewayV2ApiRead(d *schema.ResourceData, meta interface{ return fmt.Errorf("error setting cors_configuration: %s", err) } d.Set("description", output.Description) + d.Set("disable_execute_api_endpoint", output.DisableExecuteApiEndpoint) executionArn := arn.ARN{ Partition: meta.(*AWSClient).partition, Service: "execute-api", diff --git a/aws/data_source_aws_apigatewayv2_api_test.go b/aws/data_source_aws_apigatewayv2_api_test.go index 24e8e96f8fb..f61c0f3bfa3 100644 --- a/aws/data_source_aws_apigatewayv2_api_test.go +++ b/aws/data_source_aws_apigatewayv2_api_test.go @@ -32,6 +32,7 @@ func TestAccAWSAPIGatewayV2ApiDataSource_Http(t *testing.T) { resource.TestCheckResourceAttrPair(dataSourceName, "cors_configuration.0.expose_headers.#", resourceName, "cors_configuration.0.expose_headers.#"), resource.TestCheckResourceAttrPair(dataSourceName, "cors_configuration.0.max_age", resourceName, "cors_configuration.0.max_age"), resource.TestCheckResourceAttrPair(dataSourceName, "description", resourceName, "description"), + resource.TestCheckResourceAttrPair(dataSourceName, "disable_execute_api_endpoint", resourceName, "disable_execute_api_endpoint"), resource.TestCheckResourceAttrPair(dataSourceName, "execution_arn", resourceName, "execution_arn"), resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), resource.TestCheckResourceAttrPair(dataSourceName, "protocol_type", resourceName, "protocol_type"), @@ -64,6 +65,7 @@ func TestAccAWSAPIGatewayV2ApiDataSource_WebSocket(t *testing.T) { resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), resource.TestCheckResourceAttrPair(dataSourceName, "cors_configuration.#", resourceName, "cors_configuration.#"), resource.TestCheckResourceAttrPair(dataSourceName, "description", resourceName, "description"), + resource.TestCheckResourceAttrPair(dataSourceName, "disable_execute_api_endpoint", resourceName, "disable_execute_api_endpoint"), resource.TestCheckResourceAttrPair(dataSourceName, "execution_arn", resourceName, "execution_arn"), resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), resource.TestCheckResourceAttrPair(dataSourceName, "protocol_type", resourceName, "protocol_type"), diff --git a/website/docs/d/apigatewayv2_api.html.markdown b/website/docs/d/apigatewayv2_api.html.markdown index ad2ba037140..7818255388c 100644 --- a/website/docs/d/apigatewayv2_api.html.markdown +++ b/website/docs/d/apigatewayv2_api.html.markdown @@ -31,13 +31,14 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: -* `api_endpoint` - The URI of the API, of the form `{api-id}.execute-api.{region}.amazonaws.com`. +* `api_endpoint` - The URI of the API, of the form `https://{api-id}.execute-api.{region}.amazonaws.com` for HTTP APIs and `wss://{api-id}.execute-api.{region}.amazonaws.com` for WebSocket APIs. * `api_key_selection_expression` - An [API key selection expression](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-selection-expressions.html#apigateway-websocket-api-apikey-selection-expressions). Applicable for WebSocket APIs. * `arn` - The ARN of the API. * `cors_configuration` - The cross-origin resource sharing (CORS) [configuration](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html). Applicable for HTTP APIs. * `description` - The description of the API. +* `disable_execute_api_endpoint` - Whether clients can invoke the API by using the default `execute-api` endpoint. * `execution_arn` - The ARN prefix to be used in an [`aws_lambda_permission`](/docs/providers/aws/r/lambda_permission.html)'s `source_arn` attribute or in an [`aws_iam_policy`](/docs/providers/aws/r/iam_policy.html) to authorize access to the [`@connections` API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-how-to-call-websocket-api-connections.html). See the [Amazon API Gateway Developer Guide](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-control-access-iam.html) for details. From ef1b017e220844bb597215c600db34cee3c1e650 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Feb 2021 13:11:41 -0500 Subject: [PATCH 3/9] d/aws_apigatewayv2_apis: Fix test configuration formatting. Acceptance test output: $ make testacc TEST=./aws/ TESTARGS='-run=TestAccAWSAPIGatewayV2ApisDataSource_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAPIGatewayV2ApisDataSource_ -timeout 120m === RUN TestAccAWSAPIGatewayV2ApisDataSource_Name --- PASS: TestAccAWSAPIGatewayV2ApisDataSource_Name (15.14s) === RUN TestAccAWSAPIGatewayV2ApisDataSource_ProtocolType --- PASS: TestAccAWSAPIGatewayV2ApisDataSource_ProtocolType (13.91s) === RUN TestAccAWSAPIGatewayV2ApisDataSource_Tags --- PASS: TestAccAWSAPIGatewayV2ApisDataSource_Tags (12.83s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 41.974s --- aws/data_source_aws_apigatewayv2_apis_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aws/data_source_aws_apigatewayv2_apis_test.go b/aws/data_source_aws_apigatewayv2_apis_test.go index fe273de3587..0ebf30e5e9d 100644 --- a/aws/data_source_aws_apigatewayv2_apis_test.go +++ b/aws/data_source_aws_apigatewayv2_apis_test.go @@ -102,7 +102,7 @@ resource "aws_apigatewayv2_api" "test3" { route_selection_expression = "$request.body.action" tags = { - Name = %[2]q + Name = %[2]q } } `, rName1, rName2) @@ -147,6 +147,7 @@ func testAccAWSAPIGatewayV2ApisDataSourceConfigTags(rName1, rName2 string) strin testAccAWSAPIGatewayV2ApisDataSourceConfigBase(rName1, rName2), fmt.Sprintf(` data "aws_apigatewayv2_apis" "test1" { + # Force dependency on resources. tags = { Name = element([aws_apigatewayv2_api.test1.name, aws_apigatewayv2_api.test2.name, aws_apigatewayv2_api.test3.name], 0) } From c96ab37a291cb135e92e478beb967f403a5a795e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Feb 2021 13:48:30 -0500 Subject: [PATCH 4/9] d/aws_apigatewayv2_apis: Generate paginated lister. --- .../service/apigatewayv2/lister/list.go | 3 ++ .../apigatewayv2/lister/list_pages_gen.go | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 aws/internal/service/apigatewayv2/lister/list.go create mode 100644 aws/internal/service/apigatewayv2/lister/list_pages_gen.go diff --git a/aws/internal/service/apigatewayv2/lister/list.go b/aws/internal/service/apigatewayv2/lister/list.go new file mode 100644 index 00000000000..c4a03d8c38c --- /dev/null +++ b/aws/internal/service/apigatewayv2/lister/list.go @@ -0,0 +1,3 @@ +//go:generate go run ../../../generators/listpages/main.go -function=GetApis github.com/aws/aws-sdk-go/service/apigatewayv2 + +package lister diff --git a/aws/internal/service/apigatewayv2/lister/list_pages_gen.go b/aws/internal/service/apigatewayv2/lister/list_pages_gen.go new file mode 100644 index 00000000000..90eba3aac46 --- /dev/null +++ b/aws/internal/service/apigatewayv2/lister/list_pages_gen.go @@ -0,0 +1,31 @@ +// Code generated by "aws/internal/generators/listpages/main.go -function=GetApis github.com/aws/aws-sdk-go/service/apigatewayv2"; DO NOT EDIT. + +package lister + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/apigatewayv2" +) + +func GetApisPages(conn *apigatewayv2.ApiGatewayV2, input *apigatewayv2.GetApisInput, fn func(*apigatewayv2.GetApisOutput, bool) bool) error { + return GetApisPagesWithContext(context.Background(), conn, input, fn) +} + +func GetApisPagesWithContext(ctx context.Context, conn *apigatewayv2.ApiGatewayV2, input *apigatewayv2.GetApisInput, fn func(*apigatewayv2.GetApisOutput, bool) bool) error { + for { + output, err := conn.GetApisWithContext(ctx, input) + if err != nil { + return err + } + + lastPage := aws.StringValue(output.NextToken) == "" + if !fn(output, lastPage) || lastPage { + break + } + + input.NextToken = output.NextToken + } + return nil +} From 579f88ba5349cbc24caa3db3b485255634ede9ab Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Feb 2021 16:17:20 -0500 Subject: [PATCH 5/9] d/aws_apigatewayv2_apis: Use internal finder package. Acceptance test output: $ make testacc TEST=./aws/ TESTARGS='-run=TestAccAWSAPIGatewayV2ApisDataSource_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAPIGatewayV2ApisDataSource_ -timeout 120m === RUN TestAccAWSAPIGatewayV2ApisDataSource_Name --- PASS: TestAccAWSAPIGatewayV2ApisDataSource_Name (13.35s) === RUN TestAccAWSAPIGatewayV2ApisDataSource_ProtocolType --- PASS: TestAccAWSAPIGatewayV2ApisDataSource_ProtocolType (13.65s) === RUN TestAccAWSAPIGatewayV2ApisDataSource_Tags --- PASS: TestAccAWSAPIGatewayV2ApisDataSource_Tags (12.78s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 39.872s --- aws/data_source_aws_apigatewayv2_apis.go | 62 +++++-------------- .../service/apigatewayv2/finder/finder.go | 29 +++++++++ 2 files changed, 45 insertions(+), 46 deletions(-) diff --git a/aws/data_source_aws_apigatewayv2_apis.go b/aws/data_source_aws_apigatewayv2_apis.go index 223bc756a59..f0eaaba26fe 100644 --- a/aws/data_source_aws_apigatewayv2_apis.go +++ b/aws/data_source_aws_apigatewayv2_apis.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/apigatewayv2/finder" ) func dataSourceAwsApiGatewayV2Apis() *schema.Resource { @@ -40,34 +41,28 @@ func dataSourceAwsAwsApiGatewayV2ApisRead(d *schema.ResourceData, meta interface tagsToMatch := keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().IgnoreConfig(ignoreTagsConfig) - var ids []*string - - err := ListAllApiGatewayV2Apis(conn, func(page *apigatewayv2.GetApisOutput, isLast bool) bool { - if page == nil { - return !isLast - } + apis, err := finder.Apis(conn, &apigatewayv2.GetApisInput{}) - for _, api := range page.Items { - if v, ok := d.GetOk("name"); ok && v.(string) != aws.StringValue(api.Name) { - continue - } + if err != nil { + return fmt.Errorf("error reading API Gateway v2 APIs: %w", err) + } - if v, ok := d.GetOk("protocol_type"); ok && v.(string) != aws.StringValue(api.ProtocolType) { - continue - } + var ids []*string - if len(tagsToMatch) > 0 && !keyvaluetags.Apigatewayv2KeyValueTags(api.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).ContainsAll(tagsToMatch) { - continue - } + for _, api := range apis { + if v, ok := d.GetOk("name"); ok && v.(string) != aws.StringValue(api.Name) { + continue + } - ids = append(ids, api.ApiId) + if v, ok := d.GetOk("protocol_type"); ok && v.(string) != aws.StringValue(api.ProtocolType) { + continue } - return !isLast - }) + if len(tagsToMatch) > 0 && !keyvaluetags.Apigatewayv2KeyValueTags(api.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).ContainsAll(tagsToMatch) { + continue + } - if err != nil { - return fmt.Errorf("error listing API Gateway v2 APIs: %w", err) + ids = append(ids, api.ApiId) } d.SetId(resource.UniqueId()) @@ -78,28 +73,3 @@ func dataSourceAwsAwsApiGatewayV2ApisRead(d *schema.ResourceData, meta interface return nil } - -// -// These can be moved to a per-service package like "aws/internal/service/apigatewayv2/lister" in the future. -// - -func ListAllApiGatewayV2Apis(conn *apigatewayv2.ApiGatewayV2, fn func(*apigatewayv2.GetApisOutput, bool) bool) error { - return ListApiGatewayV2ApisPages(conn, &apigatewayv2.GetApisInput{}, fn) -} - -func ListApiGatewayV2ApisPages(conn *apigatewayv2.ApiGatewayV2, input *apigatewayv2.GetApisInput, fn func(*apigatewayv2.GetApisOutput, bool) bool) error { - for { - output, err := conn.GetApis(input) - if err != nil { - return err - } - - lastPage := aws.StringValue(output.NextToken) == "" - if !fn(output, lastPage) || lastPage { - break - } - - input.NextToken = output.NextToken - } - return nil -} diff --git a/aws/internal/service/apigatewayv2/finder/finder.go b/aws/internal/service/apigatewayv2/finder/finder.go index 679475b6529..6401a1b4a34 100644 --- a/aws/internal/service/apigatewayv2/finder/finder.go +++ b/aws/internal/service/apigatewayv2/finder/finder.go @@ -3,6 +3,7 @@ package finder import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/apigatewayv2/lister" ) // ApiByID returns the API corresponding to the specified ID. @@ -18,3 +19,31 @@ func ApiByID(conn *apigatewayv2.ApiGatewayV2, apiID string) (*apigatewayv2.GetAp return output, nil } + +// Apis returns the APIs corresponding to the specified input. +// Returns an empty slice if no APIs are found. +func Apis(conn *apigatewayv2.ApiGatewayV2, input *apigatewayv2.GetApisInput) ([]*apigatewayv2.Api, error) { + var apis []*apigatewayv2.Api + + err := lister.GetApisPages(conn, input, func(page *apigatewayv2.GetApisOutput, isLast bool) bool { + if page == nil { + return !isLast + } + + for _, item := range page.Items { + if item == nil { + continue + } + + apis = append(apis, item) + } + + return !isLast + }) + + if err != nil { + return nil, err + } + + return apis, nil +} From 184dd6e3fa9e426ea80722b41b3b646c1a08b838 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Feb 2021 16:20:08 -0500 Subject: [PATCH 6/9] '%s' -> '%w'. --- aws/data_source_aws_apigatewayv2_api.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/data_source_aws_apigatewayv2_api.go b/aws/data_source_aws_apigatewayv2_api.go index 9eb63300b08..8dd8d0ddec8 100644 --- a/aws/data_source_aws_apigatewayv2_api.go +++ b/aws/data_source_aws_apigatewayv2_api.go @@ -117,7 +117,7 @@ func dataSourceAwsAwsApiGatewayV2ApiRead(d *schema.ResourceData, meta interface{ output, err := conn.GetApi(input) if err != nil { - return fmt.Errorf("error reading API Gateway v2 API (%s): %s", d.Id(), err) + return fmt.Errorf("error reading API Gateway v2 API (%s): %w", d.Id(), err) } d.Set("api_endpoint", output.ApiEndpoint) @@ -130,7 +130,7 @@ func dataSourceAwsAwsApiGatewayV2ApiRead(d *schema.ResourceData, meta interface{ }.String() d.Set("arn", apiArn) if err := d.Set("cors_configuration", flattenApiGateway2CorsConfiguration(output.CorsConfiguration)); err != nil { - return fmt.Errorf("error setting cors_configuration: %s", err) + return fmt.Errorf("error setting cors_configuration: %w", err) } d.Set("description", output.Description) d.Set("disable_execute_api_endpoint", output.DisableExecuteApiEndpoint) @@ -146,7 +146,7 @@ func dataSourceAwsAwsApiGatewayV2ApiRead(d *schema.ResourceData, meta interface{ d.Set("protocol_type", output.ProtocolType) d.Set("route_selection_expression", output.RouteSelectionExpression) if err := d.Set("tags", keyvaluetags.Apigatewayv2KeyValueTags(output.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { - return fmt.Errorf("error setting tags: %s", err) + return fmt.Errorf("error setting tags: %w", err) } d.Set("version", output.Version) From 47300b42f7c0438ac115335943ca1fef64f55dcc Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Feb 2021 16:45:13 -0500 Subject: [PATCH 7/9] d/aws_apigatewayv2_api: Use internal finder package. Acceptance test output: $ make testacc TEST=./aws/ TESTARGS='-run=TestAccAWSAPIGatewayV2ApiDataSource_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAPIGatewayV2ApiDataSource_ -timeout 120m === RUN TestAccAWSAPIGatewayV2ApiDataSource_Http === PAUSE TestAccAWSAPIGatewayV2ApiDataSource_Http === RUN TestAccAWSAPIGatewayV2ApiDataSource_WebSocket === PAUSE TestAccAWSAPIGatewayV2ApiDataSource_WebSocket === CONT TestAccAWSAPIGatewayV2ApiDataSource_Http === CONT TestAccAWSAPIGatewayV2ApiDataSource_WebSocket --- PASS: TestAccAWSAPIGatewayV2ApiDataSource_Http (15.20s) --- PASS: TestAccAWSAPIGatewayV2ApiDataSource_WebSocket (15.56s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 15.675s --- aws/data_source_aws_apigatewayv2_api.go | 37 ++++++++++--------- .../service/apigatewayv2/finder/finder.go | 25 +++++++++++++ 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/aws/data_source_aws_apigatewayv2_api.go b/aws/data_source_aws_apigatewayv2_api.go index 8dd8d0ddec8..958893ce5c6 100644 --- a/aws/data_source_aws_apigatewayv2_api.go +++ b/aws/data_source_aws_apigatewayv2_api.go @@ -3,11 +3,11 @@ package aws import ( "fmt" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/service/apigatewayv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/apigatewayv2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func dataSourceAwsApiGatewayV2Api() *schema.Resource { @@ -107,21 +107,22 @@ func dataSourceAwsApiGatewayV2Api() *schema.Resource { func dataSourceAwsAwsApiGatewayV2ApiRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayv2conn ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + apiID := d.Get("api_id").(string) - d.SetId(d.Get("api_id").(string)) + api, err := finder.ApiByID(conn, apiID) - input := &apigatewayv2.GetApiInput{ - ApiId: aws.String(d.Id()), + if tfresource.NotFound(err) { + return fmt.Errorf("no API Gateway v2 API matched; change the search criteria and try again") } - output, err := conn.GetApi(input) - if err != nil { - return fmt.Errorf("error reading API Gateway v2 API (%s): %w", d.Id(), err) + return fmt.Errorf("error reading API Gateway v2 API (%s): %w", apiID, err) } - d.Set("api_endpoint", output.ApiEndpoint) - d.Set("api_key_selection_expression", output.ApiKeySelectionExpression) + d.SetId(apiID) + + d.Set("api_endpoint", api.ApiEndpoint) + d.Set("api_key_selection_expression", api.ApiKeySelectionExpression) apiArn := arn.ARN{ Partition: meta.(*AWSClient).partition, Service: "apigateway", @@ -129,11 +130,11 @@ func dataSourceAwsAwsApiGatewayV2ApiRead(d *schema.ResourceData, meta interface{ Resource: fmt.Sprintf("/apis/%s", d.Id()), }.String() d.Set("arn", apiArn) - if err := d.Set("cors_configuration", flattenApiGateway2CorsConfiguration(output.CorsConfiguration)); err != nil { + if err := d.Set("cors_configuration", flattenApiGateway2CorsConfiguration(api.CorsConfiguration)); err != nil { return fmt.Errorf("error setting cors_configuration: %w", err) } - d.Set("description", output.Description) - d.Set("disable_execute_api_endpoint", output.DisableExecuteApiEndpoint) + d.Set("description", api.Description) + d.Set("disable_execute_api_endpoint", api.DisableExecuteApiEndpoint) executionArn := arn.ARN{ Partition: meta.(*AWSClient).partition, Service: "execute-api", @@ -142,13 +143,13 @@ func dataSourceAwsAwsApiGatewayV2ApiRead(d *schema.ResourceData, meta interface{ Resource: d.Id(), }.String() d.Set("execution_arn", executionArn) - d.Set("name", output.Name) - d.Set("protocol_type", output.ProtocolType) - d.Set("route_selection_expression", output.RouteSelectionExpression) - if err := d.Set("tags", keyvaluetags.Apigatewayv2KeyValueTags(output.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + d.Set("name", api.Name) + d.Set("protocol_type", api.ProtocolType) + d.Set("route_selection_expression", api.RouteSelectionExpression) + if err := d.Set("tags", keyvaluetags.Apigatewayv2KeyValueTags(api.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return fmt.Errorf("error setting tags: %w", err) } - d.Set("version", output.Version) + d.Set("version", api.Version) return nil } diff --git a/aws/internal/service/apigatewayv2/finder/finder.go b/aws/internal/service/apigatewayv2/finder/finder.go index 6401a1b4a34..949f6bd4896 100644 --- a/aws/internal/service/apigatewayv2/finder/finder.go +++ b/aws/internal/service/apigatewayv2/finder/finder.go @@ -3,20 +3,45 @@ package finder import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/apigatewayv2/lister" ) // ApiByID returns the API corresponding to the specified ID. +// Returns NotFoundError if no API is found. func ApiByID(conn *apigatewayv2.ApiGatewayV2, apiID string) (*apigatewayv2.GetApiOutput, error) { input := &apigatewayv2.GetApiInput{ ApiId: aws.String(apiID), } + return Api(conn, input) +} + +// Api returns the API corresponding to the specified input. +// Returns NotFoundError if no API is found. +func Api(conn *apigatewayv2.ApiGatewayV2, input *apigatewayv2.GetApiInput) (*apigatewayv2.GetApiOutput, error) { output, err := conn.GetApi(input) + + if tfawserr.ErrCodeEquals(err, apigatewayv2.ErrCodeNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + if err != nil { return nil, err } + // Handle any empty result. + if output == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + return output, nil } From 0ba370fa56ae53b37130c8a79637c644760c510d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Feb 2021 17:23:28 -0500 Subject: [PATCH 8/9] Fix linting errors. --- aws/data_source_aws_apigatewayv2_apis.go | 3 +-- aws/data_source_aws_apigatewayv2_apis_test.go | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/aws/data_source_aws_apigatewayv2_apis.go b/aws/data_source_aws_apigatewayv2_apis.go index f0eaaba26fe..981de6081f7 100644 --- a/aws/data_source_aws_apigatewayv2_apis.go +++ b/aws/data_source_aws_apigatewayv2_apis.go @@ -5,7 +5,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/apigatewayv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/apigatewayv2/finder" @@ -65,7 +64,7 @@ func dataSourceAwsAwsApiGatewayV2ApisRead(d *schema.ResourceData, meta interface ids = append(ids, api.ApiId) } - d.SetId(resource.UniqueId()) + d.SetId(meta.(*AWSClient).region) if err := d.Set("ids", flattenStringSet(ids)); err != nil { return fmt.Errorf("error setting ids: %w", err) diff --git a/aws/data_source_aws_apigatewayv2_apis_test.go b/aws/data_source_aws_apigatewayv2_apis_test.go index 0ebf30e5e9d..8bbe938df4b 100644 --- a/aws/data_source_aws_apigatewayv2_apis_test.go +++ b/aws/data_source_aws_apigatewayv2_apis_test.go @@ -111,7 +111,7 @@ resource "aws_apigatewayv2_api" "test3" { func testAccAWSAPIGatewayV2ApisDataSourceConfigName(rName1, rName2 string) string { return composeConfig( testAccAWSAPIGatewayV2ApisDataSourceConfigBase(rName1, rName2), - fmt.Sprintf(` + ` data "aws_apigatewayv2_apis" "test1" { # Force dependency on resources. name = element([aws_apigatewayv2_api.test1.name, aws_apigatewayv2_api.test2.name, aws_apigatewayv2_api.test3.name], 0) @@ -121,7 +121,7 @@ data "aws_apigatewayv2_apis" "test2" { # Force dependency on resources. name = element([aws_apigatewayv2_api.test1.name, aws_apigatewayv2_api.test2.name, aws_apigatewayv2_api.test3.name], 1) } -`)) +`) } func testAccAWSAPIGatewayV2ApisDataSourceConfigProtocolType(rName1, rName2 string) string { @@ -145,7 +145,7 @@ data "aws_apigatewayv2_apis" "test2" { func testAccAWSAPIGatewayV2ApisDataSourceConfigTags(rName1, rName2 string) string { return composeConfig( testAccAWSAPIGatewayV2ApisDataSourceConfigBase(rName1, rName2), - fmt.Sprintf(` + ` data "aws_apigatewayv2_apis" "test1" { # Force dependency on resources. tags = { @@ -167,5 +167,5 @@ data "aws_apigatewayv2_apis" "test3" { Key2 = "Value2" } } -`)) +`) } From 93d9c1c179d0a66702b8e63aef7bd4664141af89 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Feb 2021 17:27:27 -0500 Subject: [PATCH 9/9] Fix CHANGELOG entry. --- .changelog/13883.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/13883.txt b/.changelog/13883.txt index 07581b9f2eb..d18bc2319da 100644 --- a/.changelog/13883.txt +++ b/.changelog/13883.txt @@ -3,5 +3,5 @@ aws_apigatewayv2_api ``` ```release-note:new-data-source -aws_apigatewayv2_api +aws_apigatewayv2_apis ```