From 64134dd906f1df526ec2bb1f6f5781c1a13afc5c Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Sat, 2 Dec 2017 00:31:39 +0900 Subject: [PATCH 1/8] WIP --- aws/provider.go | 1 + aws/resource_aws_api_gateway_vpc_link.go | 212 +++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 aws/resource_aws_api_gateway_vpc_link.go diff --git a/aws/provider.go b/aws/provider.go index 56400620eed..08873c804ad 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -259,6 +259,7 @@ func Provider() terraform.ResourceProvider { "aws_api_gateway_stage": resourceAwsApiGatewayStage(), "aws_api_gateway_usage_plan": resourceAwsApiGatewayUsagePlan(), "aws_api_gateway_usage_plan_key": resourceAwsApiGatewayUsagePlanKey(), + "aws_api_gateway_vpc_link": resourceAwsApiGatewayVpcLink(), "aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(), "aws_appautoscaling_target": resourceAwsAppautoscalingTarget(), "aws_appautoscaling_policy": resourceAwsAppautoscalingPolicy(), diff --git a/aws/resource_aws_api_gateway_vpc_link.go b/aws/resource_aws_api_gateway_vpc_link.go new file mode 100644 index 00000000000..a76afafdf2b --- /dev/null +++ b/aws/resource_aws_api_gateway_vpc_link.go @@ -0,0 +1,212 @@ +package aws + +import ( + "fmt" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/apigateway" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsApiGatewayVpcLink() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsApiGatewayVpcLinkCreate, + Read: resourceAwsApiGatewayVpcLinkRead, + Update: resourceAwsApiGatewayVpcLinkUpdate, + Delete: resourceAwsApiGatewayVpcLinkDelete, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "target_arns": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + }, + } +} + +func resourceAwsApiGatewayVpcLinkCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigateway + + input := &apigateway.CreateVpcLinkInput{ + Name: aws.String(d.Get("name").(string)), + TargetArns: expandStringSet(d.Get("target_arns").(*schema.Set)), + } + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) + } + + resp, err := conn.CreateVpcLink(input) + if err != nil { + return err + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{apigateway.VpcLinkStatusPending}, + Target: []string{apigateway.VpcLinkStatusAvailable}, + Refresh: apigatewayVpcLinkRefreshStatusFunc(conn, *resp.Id), + Timeout: 10 * time.Minute, + Delay: 10 * time.Second, + MinTimeout: 3 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf("[WARN] Error waiting for APIGateway Vpc Link status to be \"%s\": %s", apigateway.VpcLinkStatusAvailable, err) + } + + d.SetId(*resp.Id) + return nil +} + +func resourceAwsApiGatewayVpcLinkRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigateway + + input := &apigateway.GetVpcLinkInput{ + VpcLinkId: aws.String(d.Id()), + } + + resp, err := conn.GetVpcLink(input) + if err != nil { + if ecrerr, ok := err.(awserr.Error); ok { + switch ecrerr.Code() { + case apigateway.ErrCodeNotFoundException: + d.SetId("") + return nil + } + } + return err + } + + d.Set("name", resp.Name) + d.Set("description", resp.Description) + d.Set("target_arns", schema.NewSet(schema.HashString, flattenStringList(resp.TargetArns))) + return nil +} + +func resourceAwsApiGatewayVpcLinkUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigateway + + operations := make([]*apigateway.PatchOperation, 0) + + if d.HasChange("name") { + operations = append(operations, &apigateway.PatchOperation{ + Op: aws.String("replace"), + Path: aws.String("/name"), + Value: aws.String(d.Get("name").(string)), + }) + } + + if d.HasChange("description") { + operations = append(operations, &apigateway.PatchOperation{ + Op: aws.String("replace"), + Path: aws.String("/description"), + Value: aws.String(d.Get("description").(string)), + }) + } + + if d.HasChange("target_arns") { + o, n := d.GetChange("target_arns") + prefix := "targetArns" + + os := o.(*schema.Set) + ns := n.(*schema.Set) + adddiff := ns.Difference(os).List() + remdiff := os.Difference(ns).List() + + for _, v := range remdiff { + operations = append(operations, &apigateway.PatchOperation{ + Op: aws.String("remove"), + Path: aws.String(fmt.Sprintf("/%s/%s", prefix, escapeJsonPointer(v.(string)))), + }) + } + + for _, v := range adddiff { + operations = append(operations, &apigateway.PatchOperation{ + Op: aws.String("add"), + Path: aws.String(fmt.Sprintf("/%s/%s", prefix, escapeJsonPointer(v.(string)))), + }) + } + } + + input := &apigateway.UpdateVpcLinkInput{ + VpcLinkId: aws.String(d.Id()), + PatchOperations: operations, + } + + _, err := conn.UpdateVpcLink(input) + if err != nil { + if ecrerr, ok := err.(awserr.Error); ok { + switch ecrerr.Code() { + case apigateway.ErrCodeNotFoundException: + d.SetId("") + return nil + } + } + return err + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{apigateway.VpcLinkStatusPending}, + Target: []string{apigateway.VpcLinkStatusAvailable}, + Refresh: apigatewayVpcLinkRefreshStatusFunc(conn, d.Id()), + Timeout: 10 * time.Minute, + Delay: 10 * time.Second, + MinTimeout: 3 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf("[WARN] Error waiting for APIGateway Vpc Link status to be \"%s\": %s", apigateway.VpcLinkStatusAvailable, err) + } + + return nil +} + +func resourceAwsApiGatewayVpcLinkDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigateway + + input := &apigateway.DeleteVpcLinkInput{ + VpcLinkId: aws.String(d.Id()), + } + + _, err := conn.DeleteVpcLink(input) + if err != nil { + if ecrerr, ok := err.(awserr.Error); ok { + switch ecrerr.Code() { + case apigateway.ErrCodeNotFoundException: + d.SetId("") + return nil + } + } + return err + } + + d.SetId("") + return nil +} + +func apigatewayVpcLinkRefreshStatusFunc(conn *apigateway.APIGateway, vl string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + input := &apigateway.GetVpcLinkInput{ + VpcLinkId: aws.String(vl), + } + resp, err := conn.GetVpcLink(input) + if err != nil { + return nil, "failed", err + } + return resp, *resp.Status, nil + } +} From 93bf79d1058fb4d0fcaf9ee712767fe69f1e8fa3 Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Sat, 2 Dec 2017 14:28:37 +0900 Subject: [PATCH 2/8] Add acctest, docs --- aws/resource_aws_api_gateway_vpc_link.go | 35 +---- aws/resource_aws_api_gateway_vpc_link_test.go | 144 ++++++++++++++++++ website/aws.erb | 3 + .../docs/r/api_gateway_vpc_link.html.markdown | 45 ++++++ 4 files changed, 197 insertions(+), 30 deletions(-) create mode 100644 aws/resource_aws_api_gateway_vpc_link_test.go create mode 100644 website/docs/r/api_gateway_vpc_link.html.markdown diff --git a/aws/resource_aws_api_gateway_vpc_link.go b/aws/resource_aws_api_gateway_vpc_link.go index a76afafdf2b..ca0937dd1b2 100644 --- a/aws/resource_aws_api_gateway_vpc_link.go +++ b/aws/resource_aws_api_gateway_vpc_link.go @@ -27,11 +27,10 @@ func resourceAwsApiGatewayVpcLink() *schema.Resource { Type: schema.TypeString, Optional: true, }, - "target_arns": { - Type: schema.TypeSet, + "target_arn": { + Type: schema.TypeString, Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + ForceNew: true, }, }, } @@ -42,7 +41,7 @@ func resourceAwsApiGatewayVpcLinkCreate(d *schema.ResourceData, meta interface{} input := &apigateway.CreateVpcLinkInput{ Name: aws.String(d.Get("name").(string)), - TargetArns: expandStringSet(d.Get("target_arns").(*schema.Set)), + TargetArns: []*string{aws.String(d.Get("target_arn").(string))}, } if v, ok := d.GetOk("description"); ok { input.Description = aws.String(v.(string)) @@ -92,7 +91,7 @@ func resourceAwsApiGatewayVpcLinkRead(d *schema.ResourceData, meta interface{}) d.Set("name", resp.Name) d.Set("description", resp.Description) - d.Set("target_arns", schema.NewSet(schema.HashString, flattenStringList(resp.TargetArns))) + d.Set("target_arn", resp.TargetArns[0]) return nil } @@ -117,30 +116,6 @@ func resourceAwsApiGatewayVpcLinkUpdate(d *schema.ResourceData, meta interface{} }) } - if d.HasChange("target_arns") { - o, n := d.GetChange("target_arns") - prefix := "targetArns" - - os := o.(*schema.Set) - ns := n.(*schema.Set) - adddiff := ns.Difference(os).List() - remdiff := os.Difference(ns).List() - - for _, v := range remdiff { - operations = append(operations, &apigateway.PatchOperation{ - Op: aws.String("remove"), - Path: aws.String(fmt.Sprintf("/%s/%s", prefix, escapeJsonPointer(v.(string)))), - }) - } - - for _, v := range adddiff { - operations = append(operations, &apigateway.PatchOperation{ - Op: aws.String("add"), - Path: aws.String(fmt.Sprintf("/%s/%s", prefix, escapeJsonPointer(v.(string)))), - }) - } - } - input := &apigateway.UpdateVpcLinkInput{ VpcLinkId: aws.String(d.Id()), PatchOperations: operations, diff --git a/aws/resource_aws_api_gateway_vpc_link_test.go b/aws/resource_aws_api_gateway_vpc_link_test.go new file mode 100644 index 00000000000..6fca137dd75 --- /dev/null +++ b/aws/resource_aws_api_gateway_vpc_link_test.go @@ -0,0 +1,144 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/apigateway" + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAwsAPIGatewayVpcLink_basic(t *testing.T) { + rName := acctest.RandString(5) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsAPIGatewayVpcLinkDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAPIGatewayVpcLinkConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsAPIGatewayVpcLinkExists("aws_api_gateway_vpc_link.test"), + resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "name", fmt.Sprintf("tf-apigateway-%s", rName)), + resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "description", "test"), + ), + }, + { + Config: testAccAPIGatewayVpcLinkConfig_Update(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsAPIGatewayVpcLinkExists("aws_api_gateway_vpc_link.test"), + resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "name", fmt.Sprintf("tf-apigateway-update-%s", rName)), + resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "description", "test update"), + ), + }, + }, + }) +} + +func testAccCheckAwsAPIGatewayVpcLinkDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).apigateway + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_api_gateway_vpc_link" { + continue + } + + input := &apigateway.GetVpcLinkInput{ + VpcLinkId: aws.String(rs.Primary.ID), + } + + resp, err := conn.GetVpcLink(input) + if err != nil { + if ecrerr, ok := err.(awserr.Error); ok { + switch ecrerr.Code() { + case apigateway.ErrCodeNotFoundException: + return nil + } + } + return err + } + + if *resp.Status != apigateway.VpcLinkStatusDeleting { + return fmt.Errorf("APIGateway VPC Link (%s) not deleted", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckAwsAPIGatewayVpcLinkExists(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + return nil + } +} + +func testAccAPIGatewayVpcLinkConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_lb" "test_a" { + name = "tf-lb-a-%s" + internal = true + load_balancer_type = "network" + + subnet_mapping { + subnet_id = "${aws_subnet.test.id}" + } +} + +resource "aws_vpc" "test" { + cidr_block = "10.10.0.0/16" +} + +resource "aws_subnet" "test" { + vpc_id = "${aws_vpc.test.id}" + cidr_block = "10.10.0.0/21" + map_public_ip_on_launch = true + availability_zone = "us-west-2a" +} + +resource "aws_api_gateway_vpc_link" "test" { + name = "tf-apigateway-%s" + description = "test" + target_arn = "${aws_lb.test_a.arn}" +} +`, rName, rName) +} + +func testAccAPIGatewayVpcLinkConfig_Update(rName string) string { + return fmt.Sprintf(` +resource "aws_lb" "test_a" { + name = "tf-lb-a-%s" + internal = true + load_balancer_type = "network" + + subnet_mapping { + subnet_id = "${aws_subnet.test.id}" + } +} + +resource "aws_vpc" "test" { + cidr_block = "10.10.0.0/16" +} + +resource "aws_subnet" "test" { + vpc_id = "${aws_vpc.test.id}" + cidr_block = "10.10.0.0/21" + map_public_ip_on_launch = true + availability_zone = "us-west-2a" +} + +resource "aws_api_gateway_vpc_link" "test" { + name = "tf-apigateway-update-%s" + description = "test update" + target_arn = "${aws_lb.test_a.arn}" +} +`, rName, rName) +} diff --git a/website/aws.erb b/website/aws.erb index 4c8b9ebb329..cc9ba359742 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -286,6 +286,9 @@ > aws_api_gateway_usage_plan_key + > + aws_api_gateway_vpc_link + diff --git a/website/docs/r/api_gateway_vpc_link.html.markdown b/website/docs/r/api_gateway_vpc_link.html.markdown new file mode 100644 index 00000000000..4ff6499fe0c --- /dev/null +++ b/website/docs/r/api_gateway_vpc_link.html.markdown @@ -0,0 +1,45 @@ +--- +layout: "aws" +page_title: "AWS: aws_api_gateway_vpc_link" +sidebar_current: "docs-aws-resource-api-gateway-vpc-link" +description: |- + Provides an API Gateway VPC Link. +--- + +# aws_api_gateway_usage_plan + +Provides an API Gateway VPC Link. + +## Example Usage + +```hcl +resource "aws_lb" "example" { + name = "example" + internal = true + load_balancer_type = "network" + + subnet_mapping { + subnet_id = "12345" + } +} + +resource "aws_api_gateway_vpc_link" "example" { + name = "example" + description = "example description" + target_arn = "${aws_lb.example.arn}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name used to label and identify the VPC link. +* `description` - (Optional) The description of the VPC link. +* `target_arn` - (Required, ForceNew) The ARN of network load balancer of the VPC targeted by the VPC link. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The identifier of the VpcLink. From 0bbcedc461a8140f75e59a3240fc5bbf6fefe68a Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Mon, 4 Dec 2017 20:53:28 +0900 Subject: [PATCH 3/8] Reflect reviews except one --- aws/resource_aws_api_gateway_vpc_link.go | 32 +++++++------------ aws/resource_aws_api_gateway_vpc_link_test.go | 8 ++--- .../docs/r/api_gateway_vpc_link.html.markdown | 2 +- 3 files changed, 14 insertions(+), 28 deletions(-) diff --git a/aws/resource_aws_api_gateway_vpc_link.go b/aws/resource_aws_api_gateway_vpc_link.go index ca0937dd1b2..b6695bd575c 100644 --- a/aws/resource_aws_api_gateway_vpc_link.go +++ b/aws/resource_aws_api_gateway_vpc_link.go @@ -5,7 +5,6 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/apigateway" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" @@ -56,7 +55,7 @@ func resourceAwsApiGatewayVpcLinkCreate(d *schema.ResourceData, meta interface{} Pending: []string{apigateway.VpcLinkStatusPending}, Target: []string{apigateway.VpcLinkStatusAvailable}, Refresh: apigatewayVpcLinkRefreshStatusFunc(conn, *resp.Id), - Timeout: 10 * time.Minute, + Timeout: 5 * time.Minute, Delay: 10 * time.Second, MinTimeout: 3 * time.Second, } @@ -79,12 +78,9 @@ func resourceAwsApiGatewayVpcLinkRead(d *schema.ResourceData, meta interface{}) resp, err := conn.GetVpcLink(input) if err != nil { - if ecrerr, ok := err.(awserr.Error); ok { - switch ecrerr.Code() { - case apigateway.ErrCodeNotFoundException: - d.SetId("") - return nil - } + if isAWSErr(err, apigateway.ErrCodeNotFoundException, "") { + d.SetId("") + return nil } return err } @@ -123,12 +119,9 @@ func resourceAwsApiGatewayVpcLinkUpdate(d *schema.ResourceData, meta interface{} _, err := conn.UpdateVpcLink(input) if err != nil { - if ecrerr, ok := err.(awserr.Error); ok { - switch ecrerr.Code() { - case apigateway.ErrCodeNotFoundException: - d.SetId("") - return nil - } + if isAWSErr(err, apigateway.ErrCodeNotFoundException, "") { + d.SetId("") + return nil } return err } @@ -137,7 +130,7 @@ func resourceAwsApiGatewayVpcLinkUpdate(d *schema.ResourceData, meta interface{} Pending: []string{apigateway.VpcLinkStatusPending}, Target: []string{apigateway.VpcLinkStatusAvailable}, Refresh: apigatewayVpcLinkRefreshStatusFunc(conn, d.Id()), - Timeout: 10 * time.Minute, + Timeout: 5 * time.Minute, Delay: 10 * time.Second, MinTimeout: 3 * time.Second, } @@ -159,12 +152,9 @@ func resourceAwsApiGatewayVpcLinkDelete(d *schema.ResourceData, meta interface{} _, err := conn.DeleteVpcLink(input) if err != nil { - if ecrerr, ok := err.(awserr.Error); ok { - switch ecrerr.Code() { - case apigateway.ErrCodeNotFoundException: - d.SetId("") - return nil - } + if isAWSErr(err, apigateway.ErrCodeNotFoundException, "") { + d.SetId("") + return nil } return err } diff --git a/aws/resource_aws_api_gateway_vpc_link_test.go b/aws/resource_aws_api_gateway_vpc_link_test.go index 6fca137dd75..41dd8d2fccb 100644 --- a/aws/resource_aws_api_gateway_vpc_link_test.go +++ b/aws/resource_aws_api_gateway_vpc_link_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/apigateway" "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" @@ -53,11 +52,8 @@ func testAccCheckAwsAPIGatewayVpcLinkDestroy(s *terraform.State) error { resp, err := conn.GetVpcLink(input) if err != nil { - if ecrerr, ok := err.(awserr.Error); ok { - switch ecrerr.Code() { - case apigateway.ErrCodeNotFoundException: - return nil - } + if isAWSErr(err, apigateway.ErrCodeNotFoundException, "") { + return nil } return err } diff --git a/website/docs/r/api_gateway_vpc_link.html.markdown b/website/docs/r/api_gateway_vpc_link.html.markdown index 4ff6499fe0c..54d79cf7e9e 100644 --- a/website/docs/r/api_gateway_vpc_link.html.markdown +++ b/website/docs/r/api_gateway_vpc_link.html.markdown @@ -6,7 +6,7 @@ description: |- Provides an API Gateway VPC Link. --- -# aws_api_gateway_usage_plan +# aws_api_gateway_vpc_link Provides an API Gateway VPC Link. From 1b405246c3adc8e9e2fb4b84ac63dde093f03c94 Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Fri, 5 Jan 2018 10:47:33 +0900 Subject: [PATCH 4/8] wip --- aws/resource_aws_api_gateway_vpc_link.go | 2 ++ aws/resource_aws_api_gateway_vpc_link_test.go | 12 ++---------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/aws/resource_aws_api_gateway_vpc_link.go b/aws/resource_aws_api_gateway_vpc_link.go index b6695bd575c..ac2c90c3e24 100644 --- a/aws/resource_aws_api_gateway_vpc_link.go +++ b/aws/resource_aws_api_gateway_vpc_link.go @@ -159,6 +159,8 @@ func resourceAwsApiGatewayVpcLinkDelete(d *schema.ResourceData, meta interface{} return err } + time.Sleep(60 * time.Second) + d.SetId("") return nil } diff --git a/aws/resource_aws_api_gateway_vpc_link_test.go b/aws/resource_aws_api_gateway_vpc_link_test.go index 41dd8d2fccb..9359c0065e2 100644 --- a/aws/resource_aws_api_gateway_vpc_link_test.go +++ b/aws/resource_aws_api_gateway_vpc_link_test.go @@ -83,10 +83,7 @@ resource "aws_lb" "test_a" { name = "tf-lb-a-%s" internal = true load_balancer_type = "network" - - subnet_mapping { - subnet_id = "${aws_subnet.test.id}" - } + subnets = ["${aws_subnet.test.id}"] } resource "aws_vpc" "test" { @@ -96,7 +93,6 @@ resource "aws_vpc" "test" { resource "aws_subnet" "test" { vpc_id = "${aws_vpc.test.id}" cidr_block = "10.10.0.0/21" - map_public_ip_on_launch = true availability_zone = "us-west-2a" } @@ -114,10 +110,7 @@ resource "aws_lb" "test_a" { name = "tf-lb-a-%s" internal = true load_balancer_type = "network" - - subnet_mapping { - subnet_id = "${aws_subnet.test.id}" - } + subnets = ["${aws_subnet.test.id}"] } resource "aws_vpc" "test" { @@ -127,7 +120,6 @@ resource "aws_vpc" "test" { resource "aws_subnet" "test" { vpc_id = "${aws_vpc.test.id}" cidr_block = "10.10.0.0/21" - map_public_ip_on_launch = true availability_zone = "us-west-2a" } From 19ab2626a70d465b933597800f6af3756c46686e Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Sat, 6 Jan 2018 10:15:51 +0900 Subject: [PATCH 5/8] wip --- aws/resource_aws_api_gateway_vpc_link.go | 27 +++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_api_gateway_vpc_link.go b/aws/resource_aws_api_gateway_vpc_link.go index ac2c90c3e24..4c0b563bbb8 100644 --- a/aws/resource_aws_api_gateway_vpc_link.go +++ b/aws/resource_aws_api_gateway_vpc_link.go @@ -56,7 +56,6 @@ func resourceAwsApiGatewayVpcLinkCreate(d *schema.ResourceData, meta interface{} Target: []string{apigateway.VpcLinkStatusAvailable}, Refresh: apigatewayVpcLinkRefreshStatusFunc(conn, *resp.Id), Timeout: 5 * time.Minute, - Delay: 10 * time.Second, MinTimeout: 3 * time.Second, } @@ -131,7 +130,6 @@ func resourceAwsApiGatewayVpcLinkUpdate(d *schema.ResourceData, meta interface{} Target: []string{apigateway.VpcLinkStatusAvailable}, Refresh: apigatewayVpcLinkRefreshStatusFunc(conn, d.Id()), Timeout: 5 * time.Minute, - Delay: 10 * time.Second, MinTimeout: 3 * time.Second, } @@ -159,7 +157,30 @@ func resourceAwsApiGatewayVpcLinkDelete(d *schema.ResourceData, meta interface{} return err } - time.Sleep(60 * time.Second) + stateConf := resource.StateChangeConf{ + Pending: []string{apigateway.VpcLinkStatusPending, + apigateway.VpcLinkStatusAvailable, + apigateway.VpcLinkStatusDeleting}, + Target: []string{"deleted"}, + Timeout: 3 * time.Minute, + MinTimeout: 1 * time.Second, + Refresh: func() (interface{}, string, error) { + resp, err := conn.GetVpcLink(&apigateway.GetVpcLinkInput{ + VpcLinkId: aws.String(d.Id()), + }) + if err != nil { + if isAWSErr(err, apigateway.ErrCodeNotFoundException, "") { + return nil, "deleted", nil + } + return nil, "failed", err + } + return resp, *resp.Status, nil + }, + } + + if _, err := stateConf.WaitForState(); err != nil { + return err + } d.SetId("") return nil From 70a63550b951d75b418e95a8d6939a1b4ee97dbd Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Sat, 6 Jan 2018 16:06:09 +0900 Subject: [PATCH 6/8] Modify --- aws/resource_aws_api_gateway_vpc_link.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_api_gateway_vpc_link.go b/aws/resource_aws_api_gateway_vpc_link.go index 4c0b563bbb8..4b7efbf03fb 100644 --- a/aws/resource_aws_api_gateway_vpc_link.go +++ b/aws/resource_aws_api_gateway_vpc_link.go @@ -55,7 +55,7 @@ func resourceAwsApiGatewayVpcLinkCreate(d *schema.ResourceData, meta interface{} Pending: []string{apigateway.VpcLinkStatusPending}, Target: []string{apigateway.VpcLinkStatusAvailable}, Refresh: apigatewayVpcLinkRefreshStatusFunc(conn, *resp.Id), - Timeout: 5 * time.Minute, + Timeout: 8 * time.Minute, MinTimeout: 3 * time.Second, } @@ -129,7 +129,7 @@ func resourceAwsApiGatewayVpcLinkUpdate(d *schema.ResourceData, meta interface{} Pending: []string{apigateway.VpcLinkStatusPending}, Target: []string{apigateway.VpcLinkStatusAvailable}, Refresh: apigatewayVpcLinkRefreshStatusFunc(conn, d.Id()), - Timeout: 5 * time.Minute, + Timeout: 8 * time.Minute, MinTimeout: 3 * time.Second, } @@ -162,7 +162,7 @@ func resourceAwsApiGatewayVpcLinkDelete(d *schema.ResourceData, meta interface{} apigateway.VpcLinkStatusAvailable, apigateway.VpcLinkStatusDeleting}, Target: []string{"deleted"}, - Timeout: 3 * time.Minute, + Timeout: 5 * time.Minute, MinTimeout: 1 * time.Second, Refresh: func() (interface{}, string, error) { resp, err := conn.GetVpcLink(&apigateway.GetVpcLinkInput{ @@ -170,7 +170,7 @@ func resourceAwsApiGatewayVpcLinkDelete(d *schema.ResourceData, meta interface{} }) if err != nil { if isAWSErr(err, apigateway.ErrCodeNotFoundException, "") { - return nil, "deleted", nil + return 1, "deleted", nil } return nil, "failed", err } From d18c6bf2fe080987c00d5da8c0952016cf54497c Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Sat, 10 Feb 2018 17:14:16 +0900 Subject: [PATCH 7/8] updates --- aws/resource_aws_api_gateway_vpc_link.go | 22 +++--- aws/resource_aws_api_gateway_vpc_link_test.go | 67 ++++++++++--------- .../docs/r/api_gateway_vpc_link.html.markdown | 2 +- 3 files changed, 51 insertions(+), 40 deletions(-) diff --git a/aws/resource_aws_api_gateway_vpc_link.go b/aws/resource_aws_api_gateway_vpc_link.go index 4b7efbf03fb..e63835bf5c1 100644 --- a/aws/resource_aws_api_gateway_vpc_link.go +++ b/aws/resource_aws_api_gateway_vpc_link.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "log" "time" "github.com/aws/aws-sdk-go/aws" @@ -26,10 +27,11 @@ func resourceAwsApiGatewayVpcLink() *schema.Resource { Type: schema.TypeString, Optional: true, }, - "target_arn": { - Type: schema.TypeString, + "target_arns": { + Type: schema.TypeSet, Required: true, ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, }, }, } @@ -40,7 +42,7 @@ func resourceAwsApiGatewayVpcLinkCreate(d *schema.ResourceData, meta interface{} input := &apigateway.CreateVpcLinkInput{ Name: aws.String(d.Get("name").(string)), - TargetArns: []*string{aws.String(d.Get("target_arn").(string))}, + TargetArns: expandStringList(d.Get("target_arns").(*schema.Set).List()), } if v, ok := d.GetOk("description"); ok { input.Description = aws.String(v.(string)) @@ -51,6 +53,8 @@ func resourceAwsApiGatewayVpcLinkCreate(d *schema.ResourceData, meta interface{} return err } + d.SetId(*resp.Id) + stateConf := &resource.StateChangeConf{ Pending: []string{apigateway.VpcLinkStatusPending}, Target: []string{apigateway.VpcLinkStatusAvailable}, @@ -61,10 +65,10 @@ func resourceAwsApiGatewayVpcLinkCreate(d *schema.ResourceData, meta interface{} _, err = stateConf.WaitForState() if err != nil { + d.SetId("") return fmt.Errorf("[WARN] Error waiting for APIGateway Vpc Link status to be \"%s\": %s", apigateway.VpcLinkStatusAvailable, err) } - d.SetId(*resp.Id) return nil } @@ -78,6 +82,7 @@ func resourceAwsApiGatewayVpcLinkRead(d *schema.ResourceData, meta interface{}) resp, err := conn.GetVpcLink(input) if err != nil { if isAWSErr(err, apigateway.ErrCodeNotFoundException, "") { + log.Printf("[WARN] VPC Link %s not found, removing from state", d.Id()) d.SetId("") return nil } @@ -86,7 +91,7 @@ func resourceAwsApiGatewayVpcLinkRead(d *schema.ResourceData, meta interface{}) d.Set("name", resp.Name) d.Set("description", resp.Description) - d.Set("target_arn", resp.TargetArns[0]) + d.Set("target_arn", flattenStringList(resp.TargetArns)) return nil } @@ -119,6 +124,7 @@ func resourceAwsApiGatewayVpcLinkUpdate(d *schema.ResourceData, meta interface{} _, err := conn.UpdateVpcLink(input) if err != nil { if isAWSErr(err, apigateway.ErrCodeNotFoundException, "") { + log.Printf("[WARN] VPC Link %s not found, removing from state", d.Id()) d.SetId("") return nil } @@ -151,7 +157,6 @@ func resourceAwsApiGatewayVpcLinkDelete(d *schema.ResourceData, meta interface{} _, err := conn.DeleteVpcLink(input) if err != nil { if isAWSErr(err, apigateway.ErrCodeNotFoundException, "") { - d.SetId("") return nil } return err @@ -161,7 +166,7 @@ func resourceAwsApiGatewayVpcLinkDelete(d *schema.ResourceData, meta interface{} Pending: []string{apigateway.VpcLinkStatusPending, apigateway.VpcLinkStatusAvailable, apigateway.VpcLinkStatusDeleting}, - Target: []string{"deleted"}, + Target: []string{""}, Timeout: 5 * time.Minute, MinTimeout: 1 * time.Second, Refresh: func() (interface{}, string, error) { @@ -170,7 +175,7 @@ func resourceAwsApiGatewayVpcLinkDelete(d *schema.ResourceData, meta interface{} }) if err != nil { if isAWSErr(err, apigateway.ErrCodeNotFoundException, "") { - return 1, "deleted", nil + return 1, "", nil } return nil, "failed", err } @@ -182,7 +187,6 @@ func resourceAwsApiGatewayVpcLinkDelete(d *schema.ResourceData, meta interface{} return err } - d.SetId("") return nil } diff --git a/aws/resource_aws_api_gateway_vpc_link_test.go b/aws/resource_aws_api_gateway_vpc_link_test.go index 9359c0065e2..d98fdaebfc9 100644 --- a/aws/resource_aws_api_gateway_vpc_link_test.go +++ b/aws/resource_aws_api_gateway_vpc_link_test.go @@ -24,6 +24,7 @@ func TestAccAwsAPIGatewayVpcLink_basic(t *testing.T) { testAccCheckAwsAPIGatewayVpcLinkExists("aws_api_gateway_vpc_link.test"), resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "name", fmt.Sprintf("tf-apigateway-%s", rName)), resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "description", "test"), + resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "target_arns.#", "2"), ), }, { @@ -32,6 +33,7 @@ func TestAccAwsAPIGatewayVpcLink_basic(t *testing.T) { testAccCheckAwsAPIGatewayVpcLinkExists("aws_api_gateway_vpc_link.test"), resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "name", fmt.Sprintf("tf-apigateway-update-%s", rName)), resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "description", "test update"), + resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "target_arns.#", "2"), ), }, }, @@ -50,7 +52,7 @@ func testAccCheckAwsAPIGatewayVpcLinkDestroy(s *terraform.State) error { VpcLinkId: aws.String(rs.Primary.ID), } - resp, err := conn.GetVpcLink(input) + _, err := conn.GetVpcLink(input) if err != nil { if isAWSErr(err, apigateway.ErrCodeNotFoundException, "") { return nil @@ -58,9 +60,7 @@ func testAccCheckAwsAPIGatewayVpcLinkDestroy(s *terraform.State) error { return err } - if *resp.Status != apigateway.VpcLinkStatusDeleting { - return fmt.Errorf("APIGateway VPC Link (%s) not deleted", rs.Primary.ID) - } + return fmt.Errorf("Expected VPC Link to be destroyed, %s found", rs.Primary.ID) } return nil @@ -68,19 +68,37 @@ func testAccCheckAwsAPIGatewayVpcLinkDestroy(s *terraform.State) error { func testAccCheckAwsAPIGatewayVpcLinkExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { - _, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[name] if !ok { return fmt.Errorf("Not found: %s", name) } + conn := testAccProvider.Meta().(*AWSClient).apigateway + + input := &apigateway.GetVpcLinkInput{ + VpcLinkId: aws.String(rs.Primary.ID), + } + + _, err := conn.GetVpcLink(input) + if err != nil { + return err + } + return nil } } -func testAccAPIGatewayVpcLinkConfig(rName string) string { +func testAccAPIGatewayVpcLinkConfig_basis(rName string) string { return fmt.Sprintf(` resource "aws_lb" "test_a" { - name = "tf-lb-a-%s" + name = "tf-lb-%s" + internal = true + load_balancer_type = "network" + subnets = ["${aws_subnet.test.id}"] +} + +resource "aws_lb" "test_b" { + name = "tf-lb-%s" internal = true load_balancer_type = "network" subnets = ["${aws_subnet.test.id}"] @@ -90,43 +108,32 @@ resource "aws_vpc" "test" { cidr_block = "10.10.0.0/16" } +data "aws_availability_zones" "test" {} + resource "aws_subnet" "test" { vpc_id = "${aws_vpc.test.id}" cidr_block = "10.10.0.0/21" - availability_zone = "us-west-2a" + availability_zone = "${data.aws_availability_zones.test.names[0]}" +} +`, rName, rName) } +func testAccAPIGatewayVpcLinkConfig(rName string) string { + return testAccAPIGatewayVpcLinkConfig_basis(rName) + fmt.Sprintf(` resource "aws_api_gateway_vpc_link" "test" { name = "tf-apigateway-%s" description = "test" - target_arn = "${aws_lb.test_a.arn}" + target_arns = ["${aws_lb.test_a.arn}","${aws_lb.test_b.arn}"] } -`, rName, rName) +`, rName) } func testAccAPIGatewayVpcLinkConfig_Update(rName string) string { - return fmt.Sprintf(` -resource "aws_lb" "test_a" { - name = "tf-lb-a-%s" - internal = true - load_balancer_type = "network" - subnets = ["${aws_subnet.test.id}"] -} - -resource "aws_vpc" "test" { - cidr_block = "10.10.0.0/16" -} - -resource "aws_subnet" "test" { - vpc_id = "${aws_vpc.test.id}" - cidr_block = "10.10.0.0/21" - availability_zone = "us-west-2a" -} - + return testAccAPIGatewayVpcLinkConfig_basis(rName) + fmt.Sprintf(` resource "aws_api_gateway_vpc_link" "test" { name = "tf-apigateway-update-%s" description = "test update" - target_arn = "${aws_lb.test_a.arn}" + target_arns = ["${aws_lb.test_a.arn}","${aws_lb.test_b.arn}"] } -`, rName, rName) +`, rName) } diff --git a/website/docs/r/api_gateway_vpc_link.html.markdown b/website/docs/r/api_gateway_vpc_link.html.markdown index 54d79cf7e9e..2463aadbdd7 100644 --- a/website/docs/r/api_gateway_vpc_link.html.markdown +++ b/website/docs/r/api_gateway_vpc_link.html.markdown @@ -36,7 +36,7 @@ The following arguments are supported: * `name` - (Required) The name used to label and identify the VPC link. * `description` - (Optional) The description of the VPC link. -* `target_arn` - (Required, ForceNew) The ARN of network load balancer of the VPC targeted by the VPC link. +* `target_arn` - (Required, ForceNew) The ARN of a network load balancer in the VPC targeted by the VPC link. ## Attributes Reference From c91d3134b4477a909ad746724c96bd70cf6a02e7 Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Fri, 16 Feb 2018 22:40:56 +0900 Subject: [PATCH 8/8] reflect reviews --- aws/resource_aws_api_gateway_vpc_link.go | 1 + aws/resource_aws_api_gateway_vpc_link_test.go | 17 +++++------------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/aws/resource_aws_api_gateway_vpc_link.go b/aws/resource_aws_api_gateway_vpc_link.go index e63835bf5c1..8911e5dcbba 100644 --- a/aws/resource_aws_api_gateway_vpc_link.go +++ b/aws/resource_aws_api_gateway_vpc_link.go @@ -29,6 +29,7 @@ func resourceAwsApiGatewayVpcLink() *schema.Resource { }, "target_arns": { Type: schema.TypeSet, + MaxItems: 1, Required: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, diff --git a/aws/resource_aws_api_gateway_vpc_link_test.go b/aws/resource_aws_api_gateway_vpc_link_test.go index d98fdaebfc9..d1a03805b62 100644 --- a/aws/resource_aws_api_gateway_vpc_link_test.go +++ b/aws/resource_aws_api_gateway_vpc_link_test.go @@ -24,7 +24,7 @@ func TestAccAwsAPIGatewayVpcLink_basic(t *testing.T) { testAccCheckAwsAPIGatewayVpcLinkExists("aws_api_gateway_vpc_link.test"), resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "name", fmt.Sprintf("tf-apigateway-%s", rName)), resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "description", "test"), - resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "target_arns.#", "2"), + resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "target_arns.#", "1"), ), }, { @@ -33,7 +33,7 @@ func TestAccAwsAPIGatewayVpcLink_basic(t *testing.T) { testAccCheckAwsAPIGatewayVpcLinkExists("aws_api_gateway_vpc_link.test"), resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "name", fmt.Sprintf("tf-apigateway-update-%s", rName)), resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "description", "test update"), - resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "target_arns.#", "2"), + resource.TestCheckResourceAttr("aws_api_gateway_vpc_link.test", "target_arns.#", "1"), ), }, }, @@ -97,13 +97,6 @@ resource "aws_lb" "test_a" { subnets = ["${aws_subnet.test.id}"] } -resource "aws_lb" "test_b" { - name = "tf-lb-%s" - internal = true - load_balancer_type = "network" - subnets = ["${aws_subnet.test.id}"] -} - resource "aws_vpc" "test" { cidr_block = "10.10.0.0/16" } @@ -115,7 +108,7 @@ resource "aws_subnet" "test" { cidr_block = "10.10.0.0/21" availability_zone = "${data.aws_availability_zones.test.names[0]}" } -`, rName, rName) +`, rName) } func testAccAPIGatewayVpcLinkConfig(rName string) string { @@ -123,7 +116,7 @@ func testAccAPIGatewayVpcLinkConfig(rName string) string { resource "aws_api_gateway_vpc_link" "test" { name = "tf-apigateway-%s" description = "test" - target_arns = ["${aws_lb.test_a.arn}","${aws_lb.test_b.arn}"] + target_arns = ["${aws_lb.test_a.arn}"] } `, rName) } @@ -133,7 +126,7 @@ func testAccAPIGatewayVpcLinkConfig_Update(rName string) string { resource "aws_api_gateway_vpc_link" "test" { name = "tf-apigateway-update-%s" description = "test update" - target_arns = ["${aws_lb.test_a.arn}","${aws_lb.test_b.arn}"] + target_arns = ["${aws_lb.test_a.arn}"] } `, rName) }