Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New resource: aws_apigatewayv2_vpc_link #12577

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions aws/internal/service/apigatewayv2/waiter/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,26 @@ func DeploymentStatus(conn *apigatewayv2.ApiGatewayV2, apiId, deploymentId strin
return output, aws.StringValue(output.DeploymentStatus), nil
}
}

// VpcLinkStatus fetches the VPC Link and its Status
func VpcLinkStatus(conn *apigatewayv2.ApiGatewayV2, vpcLinkId string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
input := &apigatewayv2.GetVpcLinkInput{
VpcLinkId: aws.String(vpcLinkId),
}

output, err := conn.GetVpcLink(input)

if err != nil {
return nil, apigatewayv2.VpcLinkStatusFailed, err
}

// Error messages can also be contained in the response with FAILED status

if aws.StringValue(output.VpcLinkStatus) == apigatewayv2.VpcLinkStatusFailed {
return output, apigatewayv2.VpcLinkStatusFailed, fmt.Errorf("%s", aws.StringValue(output.VpcLinkStatusMessage))
}

return output, aws.StringValue(output.VpcLinkStatus), nil
}
}
42 changes: 42 additions & 0 deletions aws/internal/service/apigatewayv2/waiter/waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import (
const (
// Maximum amount of time to wait for a Deployment to return Deployed
DeploymentDeployedTimeout = 5 * time.Minute

// Maximum amount of time to wait for a VPC Link to return Available
VpcLinkAvailableTimeout = 10 * time.Minute

// Maximum amount of time to wait for a VPC Link to return Deleted
VpcLinkDeletedTimeout = 10 * time.Minute
)

// DeploymentDeployed waits for a Deployment to return Deployed
Expand All @@ -29,3 +35,39 @@ func DeploymentDeployed(conn *apigatewayv2.ApiGatewayV2, apiId, deploymentId str

return nil, err
}

// VpcLinkAvailable waits for a VPC Link to return Available
func VpcLinkAvailable(conn *apigatewayv2.ApiGatewayV2, vpcLinkId string) (*apigatewayv2.GetVpcLinkOutput, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{apigatewayv2.VpcLinkStatusPending},
Target: []string{apigatewayv2.VpcLinkStatusAvailable},
Refresh: VpcLinkStatus(conn, vpcLinkId),
Timeout: VpcLinkAvailableTimeout,
}

outputRaw, err := stateConf.WaitForState()

if v, ok := outputRaw.(*apigatewayv2.GetVpcLinkOutput); ok {
return v, err
}

return nil, err
}

// VpcLinkAvailable waits for a VPC Link to return Deleted
func VpcLinkDeleted(conn *apigatewayv2.ApiGatewayV2, vpcLinkId string) (*apigatewayv2.GetVpcLinkOutput, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{apigatewayv2.VpcLinkStatusDeleting},
Target: []string{apigatewayv2.VpcLinkStatusFailed},
Refresh: VpcLinkStatus(conn, vpcLinkId),
Timeout: VpcLinkDeletedTimeout,
}

outputRaw, err := stateConf.WaitForState()

if v, ok := outputRaw.(*apigatewayv2.GetVpcLinkOutput); ok {
return v, err
}

return nil, err
}
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ func Provider() terraform.ResourceProvider {
"aws_apigatewayv2_route": resourceAwsApiGatewayV2Route(),
"aws_apigatewayv2_route_response": resourceAwsApiGatewayV2RouteResponse(),
"aws_apigatewayv2_stage": resourceAwsApiGatewayV2Stage(),
"aws_apigatewayv2_vpc_link": resourceAwsApiGatewayV2VpcLink(),
"aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(),
"aws_appautoscaling_target": resourceAwsAppautoscalingTarget(),
"aws_appautoscaling_policy": resourceAwsAppautoscalingPolicy(),
Expand Down
164 changes: 164 additions & 0 deletions aws/resource_aws_apigatewayv2_vpc_link.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package aws

import (
"fmt"
"log"

"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/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/apigatewayv2/waiter"
)

func resourceAwsApiGatewayV2VpcLink() *schema.Resource {
return &schema.Resource{
Create: resourceAwsApiGatewayV2VpcLinkCreate,
Read: resourceAwsApiGatewayV2VpcLinkRead,
Update: resourceAwsApiGatewayV2VpcLinkUpdate,
Delete: resourceAwsApiGatewayV2VpcLinkDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},
"name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringLenBetween(1, 128),
},
"security_group_ids": {
Type: schema.TypeSet,
Required: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"subnet_ids": {
Type: schema.TypeSet,
Required: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"tags": tagsSchema(),
},
}
}

func resourceAwsApiGatewayV2VpcLinkCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).apigatewayv2conn

req := &apigatewayv2.CreateVpcLinkInput{
Name: aws.String(d.Get("name").(string)),
SecurityGroupIds: expandStringSet(d.Get("security_group_ids").(*schema.Set)),
SubnetIds: expandStringSet(d.Get("subnet_ids").(*schema.Set)),
Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().Apigatewayv2Tags(),
}

log.Printf("[DEBUG] Creating API Gateway v2 VPC Link: %s", req)
resp, err := conn.CreateVpcLink(req)
if err != nil {
return fmt.Errorf("error creating API Gateway v2 VPC Link: %s", err)
}

d.SetId(aws.StringValue(resp.VpcLinkId))

if _, err := waiter.VpcLinkAvailable(conn, d.Id()); err != nil {
return fmt.Errorf("error waiting for API Gateway v2 deployment (%s) availability: %s", d.Id(), err)
}

return resourceAwsApiGatewayV2VpcLinkRead(d, meta)
}

func resourceAwsApiGatewayV2VpcLinkRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).apigatewayv2conn

outputRaw, _, err := waiter.VpcLinkStatus(conn, d.Id())()
if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") {
log.Printf("[WARN] API Gateway v2 VPC Link (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}
if err != nil {
return fmt.Errorf("error reading API Gateway v2 VPC Link (%s): %s", d.Id(), err)
}

output := outputRaw.(*apigatewayv2.GetVpcLinkOutput)
arn := arn.ARN{
Partition: meta.(*AWSClient).partition,
Service: "apigateway",
Region: meta.(*AWSClient).region,
Resource: fmt.Sprintf("/vpclinks/%s", d.Id()),
}.String()
d.Set("arn", arn)
d.Set("name", output.Name)
if err := d.Set("security_group_ids", flattenStringSet(output.SecurityGroupIds)); err != nil {
return fmt.Errorf("error setting security_group_ids: %s", err)
}
if err := d.Set("subnet_ids", flattenStringSet(output.SubnetIds)); err != nil {
return fmt.Errorf("error setting subnet_ids: %s", err)
}
if err := d.Set("tags", keyvaluetags.Apigatewayv2KeyValueTags(output.Tags).IgnoreAws().Map()); err != nil {
return fmt.Errorf("error setting tags: %s", err)
}

return nil
}

func resourceAwsApiGatewayV2VpcLinkUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).apigatewayv2conn

if d.HasChange("name") {
req := &apigatewayv2.UpdateVpcLinkInput{
VpcLinkId: aws.String(d.Id()),
Name: aws.String(d.Get("name").(string)),
}

log.Printf("[DEBUG] Updating API Gateway v2 VPC Link: %s", req)
_, err := conn.UpdateVpcLink(req)
if err != nil {
return fmt.Errorf("error updating API Gateway v2 VPC Link (%s): %s", d.Id(), err)
}
}

if d.HasChange("tags") {
o, n := d.GetChange("tags")
if err := keyvaluetags.Apigatewayv2UpdateTags(conn, d.Get("arn").(string), o, n); err != nil {
return fmt.Errorf("error updating API Gateway v2 VPC Link (%s) tags: %s", d.Id(), err)
}
}

return resourceAwsApiGatewayV2VpcLinkRead(d, meta)
}

func resourceAwsApiGatewayV2VpcLinkDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).apigatewayv2conn

log.Printf("[DEBUG] Deleting API Gateway v2 VPC Link (%s)", d.Id())
_, err := conn.DeleteVpcLink(&apigatewayv2.DeleteVpcLinkInput{
VpcLinkId: aws.String(d.Id()),
})
if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") {
return nil
}
if err != nil {
return fmt.Errorf("error deleting API Gateway v2 VPC Link (%s): %s", d.Id(), err)
}

_, err = waiter.VpcLinkDeleted(conn, d.Id())
if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") {
return nil
}
if err != nil {
return fmt.Errorf("error waiting for API Gateway v2 VPC Link (%s) deletion: %s", d.Id(), err)
}

return nil
}
Loading