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

r/aws_ec2_carrier_gateway: New resource. #16252

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
4 changes: 4 additions & 0 deletions aws/internal/service/ec2/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ const (
ErrCodeInvalidParameterValue = "InvalidParameterValue"
)

const (
ErrCodeInvalidCarrierGatewayIDNotFound = "InvalidCarrierGatewayID.NotFound"
)

const (
ErrCodeClientVpnEndpointIdNotFound = "InvalidClientVpnEndpointId.NotFound"
ErrCodeClientVpnAuthorizationRuleNotFound = "InvalidClientVpnEndpointAuthorizationRuleNotFound"
Expand Down
19 changes: 19 additions & 0 deletions aws/internal/service/ec2/finder/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@ import (
tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2"
)

// CarrierGatewayByID returns the carrier gateway corresponding to the specified identifier.
// Returns nil and potentially an error if no carrier gateway is found.
func CarrierGatewayByID(conn *ec2.EC2, id string) (*ec2.CarrierGateway, error) {
input := &ec2.DescribeCarrierGatewaysInput{
CarrierGatewayIds: aws.StringSlice([]string{id}),
}

output, err := conn.DescribeCarrierGateways(input)
if err != nil {
return nil, err
}

if output == nil || len(output.CarrierGateways) == 0 {
return nil, nil
}

return output.CarrierGateways[0], nil
}

func ClientVpnAuthorizationRule(conn *ec2.EC2, endpointID, targetNetworkCidr, accessGroupID string) (*ec2.DescribeClientVpnAuthorizationRulesOutput, error) {
filters := map[string]string{
"destination-cidr": targetNetworkCidr,
Expand Down
30 changes: 30 additions & 0 deletions aws/internal/service/ec2/waiter/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,36 @@ import (
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder"
)

const (
carrierGatewayStateNotFound = "NotFound"
carrierGatewayStateUnknown = "Unknown"
)

// CarrierGatewayState fetches the CarrierGateway and its State
func CarrierGatewayState(conn *ec2.EC2, carrierGatewayID string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
carrierGateway, err := finder.CarrierGatewayByID(conn, carrierGatewayID)
if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidCarrierGatewayIDNotFound) {
return nil, carrierGatewayStateNotFound, nil
}
if err != nil {
return nil, carrierGatewayStateUnknown, err
}

if carrierGateway == nil {
return nil, carrierGatewayStateNotFound, nil
}

state := aws.StringValue(carrierGateway.State)

if state == ec2.CarrierGatewayStateDeleted {
return nil, carrierGatewayStateNotFound, nil
}

return carrierGateway, state, nil
}
}

// LocalGatewayRouteTableVpcAssociationState fetches the LocalGatewayRouteTableVpcAssociation and its State
func LocalGatewayRouteTableVpcAssociationState(conn *ec2.EC2, localGatewayRouteTableVpcAssociationID string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
Expand Down
40 changes: 40 additions & 0 deletions aws/internal/service/ec2/waiter/waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,46 @@ const (
InstanceAttributePropagationTimeout = 2 * time.Minute
)

const (
CarrierGatewayAvailableTimeout = 5 * time.Minute

CarrierGatewayDeletedTimeout = 5 * time.Minute
)

func CarrierGatewayAvailable(conn *ec2.EC2, carrierGatewayID string) (*ec2.CarrierGateway, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{ec2.CarrierGatewayStatePending},
Target: []string{ec2.CarrierGatewayStateAvailable},
Refresh: CarrierGatewayState(conn, carrierGatewayID),
Timeout: CarrierGatewayAvailableTimeout,
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*ec2.CarrierGateway); ok {
return output, err
}

return nil, err
}

func CarrierGatewayDeleted(conn *ec2.EC2, carrierGatewayID string) (*ec2.CarrierGateway, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{ec2.CarrierGatewayStateDeleting},
Target: []string{},
Refresh: CarrierGatewayState(conn, carrierGatewayID),
Timeout: CarrierGatewayDeletedTimeout,
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*ec2.CarrierGateway); ok {
return output, err
}

return nil, err
}

const (
// Maximum amount of time to wait for a LocalGatewayRouteTableVpcAssociation to return Associated
LocalGatewayRouteTableVpcAssociationAssociatedTimeout = 5 * time.Minute
Expand Down
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,7 @@ func Provider() *schema.Provider {
"aws_ebs_volume": resourceAwsEbsVolume(),
"aws_ec2_availability_zone_group": resourceAwsEc2AvailabilityZoneGroup(),
"aws_ec2_capacity_reservation": resourceAwsEc2CapacityReservation(),
"aws_ec2_carrier_gateway": resourceAwsEc2CarrierGateway(),
"aws_ec2_client_vpn_authorization_rule": resourceAwsEc2ClientVpnAuthorizationRule(),
"aws_ec2_client_vpn_endpoint": resourceAwsEc2ClientVpnEndpoint(),
"aws_ec2_client_vpn_network_association": resourceAwsEc2ClientVpnNetworkAssociation(),
Expand Down
153 changes: 153 additions & 0 deletions aws/resource_aws_ec2_carrier_gateway.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
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/ec2"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter"
)

func resourceAwsEc2CarrierGateway() *schema.Resource {
return &schema.Resource{
Create: resourceAwsEc2CarrierGatewayCreate,
Read: resourceAwsEc2CarrierGatewayRead,
Update: resourceAwsEc2CarrierGatewayUpdate,
Delete: resourceAwsEc2CarrierGatewayDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},

"owner_id": {
Type: schema.TypeString,
Computed: true,
},

"tags": tagsSchema(),

"vpc_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
},
}
}

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

input := &ec2.CreateCarrierGatewayInput{
TagSpecifications: ec2TagSpecificationsFromMap(d.Get("tags").(map[string]interface{}), "carrier-gateway"),
ewbankkit marked this conversation as resolved.
Show resolved Hide resolved
VpcId: aws.String(d.Get("vpc_id").(string)),
}

log.Printf("[DEBUG] Creating EC2 Carrier Gateway: %s", input)
output, err := conn.CreateCarrierGateway(input)

if err != nil {
return fmt.Errorf("error creating EC2 Carrier Gateway: %w", err)
}

d.SetId(aws.StringValue(output.CarrierGateway.CarrierGatewayId))

_, err = waiter.CarrierGatewayAvailable(conn, d.Id())

if err != nil {
return fmt.Errorf("error waiting for EC2 Carrier Gateway (%s) to become available: %w", d.Id(), err)
}

return resourceAwsEc2CarrierGatewayRead(d, meta)
}

func resourceAwsEc2CarrierGatewayRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn
ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig

carrierGateway, err := finder.CarrierGatewayByID(conn, d.Id())

if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidCarrierGatewayIDNotFound) {
log.Printf("[WARN] EC2 Carrier Gateway (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("error reading EC2 Carrier Gateway (%s): %w", d.Id(), err)
}

if carrierGateway == nil || aws.StringValue(carrierGateway.State) == ec2.CarrierGatewayStateDeleted {
log.Printf("[WARN] EC2 Carrier Gateway (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

arn := arn.ARN{
Partition: meta.(*AWSClient).partition,
Service: "ec2",
Region: meta.(*AWSClient).region,
AccountID: meta.(*AWSClient).accountid,
Resource: fmt.Sprintf("carrier-gateway/%s", d.Id()),
}.String()
d.Set("arn", arn)
d.Set("owner_id", carrierGateway.OwnerId)
d.Set("vpc_id", carrierGateway.VpcId)

if err := d.Set("tags", keyvaluetags.Ec2KeyValueTags(carrierGateway.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
return fmt.Errorf("error setting tags: %w", err)
}

return nil
}

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

if d.HasChange("tags") {
o, n := d.GetChange("tags")

if err := keyvaluetags.Ec2UpdateTags(conn, d.Id(), o, n); err != nil {
return fmt.Errorf("error updating EC2 Carrier Gateway (%s) tags: %w", d.Id(), err)
}
}

return resourceAwsEc2CarrierGatewayRead(d, meta)
}

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

log.Printf("[INFO] Deleting EC2 Carrier Gateway (%s)", d.Id())
_, err := conn.DeleteCarrierGateway(&ec2.DeleteCarrierGatewayInput{
CarrierGatewayId: aws.String(d.Id()),
})

if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidCarrierGatewayIDNotFound) {
return nil
}

if err != nil {
return fmt.Errorf("error deleting EC2 Carrier Gateway (%s): %w", d.Id(), err)
}

_, err = waiter.CarrierGatewayDeleted(conn, d.Id())

if err != nil {
return fmt.Errorf("error waiting for EC2 Carrier Gateway (%s) to be deleted: %w", d.Id(), err)
}

return nil
}
Loading