Skip to content

Commit

Permalink
Merge pull request #20688 from joeperks/f-resource_aws_ec2_client_vpn…
Browse files Browse the repository at this point in the history
…_authorization_rule-add-timeouts-support

support timeouts block for resource aws_ec2_client_vpn_authorization_rule
  • Loading branch information
ewbankkit authored Jan 31, 2022
2 parents 321215f + e4772dc commit 5af79cc
Show file tree
Hide file tree
Showing 9 changed files with 315 additions and 241 deletions.
7 changes: 7 additions & 0 deletions .changelog/20688.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:bug
resource/aws_ec2_client_vpn_authorization_rule: Don't raise an error when `InvalidClientVpnEndpointId.NotFound` is returned during refresh
```

```release-note:enhancement
resource/aws_ec2_client_vpn_authorization_rule: Configurable Create and Delete timeouts
```
143 changes: 78 additions & 65 deletions internal/service/ec2/client_vpn_authorization_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package ec2
import (
"fmt"
"log"
"strings"

"github.com/aws/aws-sdk-go/aws"
"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/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
)

Expand All @@ -18,21 +20,15 @@ func ResourceClientVPNAuthorizationRule() *schema.Resource {
Read: resourceClientVPNAuthorizationRuleRead,
Delete: resourceClientVPNAuthorizationRuleDelete,
Importer: &schema.ResourceImporter{
State: resourceClientVPNAuthorizationRuleImport,
State: schema.ImportStatePassthrough,
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(ClientVPNAuthorizationRuleCreatedTimeout),
Delete: schema.DefaultTimeout(ClientVPNAuthorizationRuleDeletedTimeout),
},

Schema: map[string]*schema.Schema{
"client_vpn_endpoint_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"target_network_cidr": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: verify.ValidCIDRNetworkAddress,
},
"access_group_id": {
Type: schema.TypeString,
Optional: true,
Expand All @@ -45,11 +41,22 @@ func ResourceClientVPNAuthorizationRule() *schema.Resource {
ForceNew: true,
ExactlyOneOf: []string{"access_group_id", "authorize_all_groups"},
},
"client_vpn_endpoint_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"description": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"target_network_cidr": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: verify.ValidCIDRNetworkAddress,
},
},
}
}
Expand All @@ -58,11 +65,11 @@ func resourceClientVPNAuthorizationRuleCreate(d *schema.ResourceData, meta inter
conn := meta.(*conns.AWSClient).EC2Conn

endpointID := d.Get("client_vpn_endpoint_id").(string)
targetNetworkCidr := d.Get("target_network_cidr").(string)
targetNetworkCIDR := d.Get("target_network_cidr").(string)

input := &ec2.AuthorizeClientVpnIngressInput{
ClientVpnEndpointId: aws.String(endpointID),
TargetNetworkCidr: aws.String(targetNetworkCidr),
TargetNetworkCidr: aws.String(targetNetworkCIDR),
}

var accessGroupID string
Expand All @@ -79,106 +86,112 @@ func resourceClientVPNAuthorizationRuleCreate(d *schema.ResourceData, meta inter
input.Description = aws.String(v.(string))
}

id := ClientVPNAuthorizationRuleCreateID(endpointID, targetNetworkCidr, accessGroupID)
id := ClientVPNAuthorizationRuleCreateResourceID(endpointID, targetNetworkCIDR, accessGroupID)

log.Printf("[DEBUG] Creating Client VPN authorization rule: %#v", input)
log.Printf("[DEBUG] Creating EC2 Client VPN Authorization Rule: %s", input)
_, err := conn.AuthorizeClientVpnIngress(input)
if err != nil {
return fmt.Errorf("error creating Client VPN authorization rule %q: %w", id, err)
}

_, err = WaitClientVPNAuthorizationRuleAuthorized(conn, id)
if err != nil {
return fmt.Errorf("error waiting for Client VPN authorization rule %q to be active: %w", id, err)
return fmt.Errorf("error authorizing EC2 Client VPN Authorization Rule (%s): %w", id, err)
}

d.SetId(id)

if _, err := WaitClientVPNAuthorizationRuleCreated(conn, endpointID, targetNetworkCIDR, accessGroupID, d.Timeout(schema.TimeoutCreate)); err != nil {
return fmt.Errorf("error waiting for EC2 Client VPN Authorization Rule (%s) create: %w", d.Id(), err)
}

return resourceClientVPNAuthorizationRuleRead(d, meta)
}

func resourceClientVPNAuthorizationRuleRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).EC2Conn

result, err := FindClientVPNAuthorizationRule(conn,
d.Get("client_vpn_endpoint_id").(string),
d.Get("target_network_cidr").(string),
d.Get("access_group_id").(string),
)
endpointID, targetNetworkCIDR, accessGroupID, err := ClientVPNAuthorizationRuleParseResourceID(d.Id())

if tfawserr.ErrMessageContains(err, ErrCodeInvalidClientVpnAuthorizationRuleNotFound, "") {
log.Printf("[WARN] EC2 Client VPN authorization rule (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}
if err != nil {
return fmt.Errorf("error reading Client VPN authorization rule: %w", err)
return err
}

if result == nil || len(result.AuthorizationRules) == 0 || result.AuthorizationRules[0] == nil {
log.Printf("[WARN] EC2 Client VPN authorization rule (%s) not found, removing from state", d.Id())
rule, err := FindClientVPNAuthorizationRuleByEndpointIDTargetNetworkCIDRAndGroupID(conn, endpointID, targetNetworkCIDR, accessGroupID)

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] EC2 Client VPN Authorization Rule (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

rule := result.AuthorizationRules[0]
d.Set("client_vpn_endpoint_id", rule.ClientVpnEndpointId)
d.Set("target_network_cidr", rule.DestinationCidr)
if err != nil {
return fmt.Errorf("error reading EC2 Client VPN Authorization Rule (%s): %w", d.Id(), err)
}

d.Set("access_group_id", rule.GroupId)
d.Set("authorize_all_groups", rule.AccessAll)
d.Set("client_vpn_endpoint_id", rule.ClientVpnEndpointId)
d.Set("description", rule.Description)
d.Set("target_network_cidr", rule.DestinationCidr)

return nil
}

func resourceClientVPNAuthorizationRuleDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).EC2Conn

endpointID, targetNetworkCIDR, accessGroupID, err := ClientVPNAuthorizationRuleParseResourceID(d.Id())

if err != nil {
return err
}

input := &ec2.RevokeClientVpnIngressInput{
ClientVpnEndpointId: aws.String(d.Get("client_vpn_endpoint_id").(string)),
TargetNetworkCidr: aws.String(d.Get("target_network_cidr").(string)),
ClientVpnEndpointId: aws.String(endpointID),
RevokeAllGroups: aws.Bool(d.Get("authorize_all_groups").(bool)),
TargetNetworkCidr: aws.String(targetNetworkCIDR),
}
if v, ok := d.GetOk("access_group_id"); ok {
input.AccessGroupId = aws.String(v.(string))
if accessGroupID != "" {
input.AccessGroupId = aws.String(accessGroupID)
}

log.Printf("[DEBUG] Deleting EC2 Client VPN Authorization Rule: %s", d.Id())
_, err = conn.RevokeClientVpnIngress(input)

if tfawserr.ErrCodeEquals(err, ErrCodeInvalidClientVpnEndpointIdNotFound, ErrCodeInvalidClientVpnAuthorizationRuleNotFound) {
return nil
}

log.Printf("[DEBUG] Revoking Client VPN authorization rule %q", d.Id())
err := deleteClientVpnAuthorizationRule(conn, input)
if err != nil {
return fmt.Errorf("error revoking Client VPN authorization rule %q: %w", d.Id(), err)
return fmt.Errorf("error revoking EC2 Client VPN Authorization Rule (%s): %w", d.Id(), err)
}

if _, err := WaitClientVPNAuthorizationRuleDeleted(conn, endpointID, targetNetworkCIDR, accessGroupID, d.Timeout(schema.TimeoutDelete)); err != nil {
return fmt.Errorf("error waiting for EC2 Client VPN Authorization Rule (%s) delete: %w", d.Id(), err)
}

return nil
}

func resourceClientVPNAuthorizationRuleImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
endpointID, targetNetworkCidr, accessGroupID, err := ClientVPNAuthorizationRuleParseID(d.Id())
if err != nil {
return nil, err
const clientVPNAuthorizationRuleIDSeparator = ","

func ClientVPNAuthorizationRuleCreateResourceID(endpointID, targetNetworkCIDR, accessGroupID string) string {
parts := []string{endpointID, targetNetworkCIDR}
if accessGroupID != "" {
parts = append(parts, accessGroupID)
}
id := strings.Join(parts, clientVPNAuthorizationRuleIDSeparator)

d.Set("client_vpn_endpoint_id", endpointID)
d.Set("target_network_cidr", targetNetworkCidr)
d.Set("access_group_id", accessGroupID)
return []*schema.ResourceData{d}, nil
return id
}

func deleteClientVpnAuthorizationRule(conn *ec2.EC2, input *ec2.RevokeClientVpnIngressInput) error {
id := ClientVPNAuthorizationRuleCreateID(
aws.StringValue(input.ClientVpnEndpointId),
aws.StringValue(input.TargetNetworkCidr),
aws.StringValue(input.AccessGroupId))
func ClientVPNAuthorizationRuleParseResourceID(id string) (string, string, string, error) {
parts := strings.Split(id, clientVPNAuthorizationRuleIDSeparator)

_, err := conn.RevokeClientVpnIngress(input)
if tfawserr.ErrMessageContains(err, ErrCodeInvalidClientVpnAuthorizationRuleNotFound, "") {
return nil
}
if err != nil {
return err
if len(parts) == 2 && parts[0] != "" && parts[1] != "" {
return parts[0], parts[1], "", nil
}

_, err = WaitClientVPNAuthorizationRuleRevoked(conn, id)
if len(parts) == 3 && parts[0] != "" && parts[1] != "" && parts[2] != "" {
return parts[0], parts[1], parts[2], nil
}

return err
return "", "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected endpoint-id%[2]starget-network-cidr or endpoint-id%[2]starget-network-cidr%[2]sgroup-id", id, clientVPNAuthorizationRuleIDSeparator)
}
Loading

0 comments on commit 5af79cc

Please sign in to comment.