diff --git a/aws/resource_aws_default_network_acl.go b/aws/resource_aws_default_network_acl.go index ea3ffad7196..b48ed329813 100644 --- a/aws/resource_aws_default_network_acl.go +++ b/aws/resource_aws_default_network_acl.go @@ -7,6 +7,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" "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" ) @@ -34,6 +35,10 @@ func resourceAwsDefaultNetworkAcl() *schema.Resource { }, Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, "vpc_id": { Type: schema.TypeString, Computed: true, @@ -53,7 +58,6 @@ func resourceAwsDefaultNetworkAcl() *schema.Resource { Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, // We want explicit management of Rules here, so we do not allow them to be // computed. Instead, an empty config will enforce just that; removal of the @@ -64,20 +68,27 @@ func resourceAwsDefaultNetworkAcl() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "from_port": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IsPortNumberOrZero, }, "to_port": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IsPortNumberOrZero, }, "rule_no": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 32766), }, "action": { Type: schema.TypeString, Required: true, + ValidateFunc: validation.StringInSlice([]string{ + ec2.RuleActionAllow, + ec2.RuleActionDeny, + }, true), }, "protocol": { Type: schema.TypeString, @@ -86,10 +97,18 @@ func resourceAwsDefaultNetworkAcl() *schema.Resource { "cidr_block": { Type: schema.TypeString, Optional: true, + ValidateFunc: validation.Any( + validation.StringIsEmpty, + validation.IsCIDR, + ), }, "ipv6_cidr_block": { Type: schema.TypeString, Optional: true, + ValidateFunc: validation.Any( + validation.StringIsEmpty, + validation.IsCIDR, + ), }, "icmp_type": { Type: schema.TypeInt, @@ -109,20 +128,27 @@ func resourceAwsDefaultNetworkAcl() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "from_port": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IsPortNumberOrZero, }, "to_port": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IsPortNumberOrZero, }, "rule_no": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 32766), }, "action": { Type: schema.TypeString, Required: true, + ValidateFunc: validation.StringInSlice([]string{ + ec2.RuleActionAllow, + ec2.RuleActionDeny, + }, true), }, "protocol": { Type: schema.TypeString, @@ -131,10 +157,18 @@ func resourceAwsDefaultNetworkAcl() *schema.Resource { "cidr_block": { Type: schema.TypeString, Optional: true, + ValidateFunc: validation.Any( + validation.StringIsEmpty, + validation.IsCIDR, + ), }, "ipv6_cidr_block": { Type: schema.TypeString, Optional: true, + ValidateFunc: validation.Any( + validation.StringIsEmpty, + validation.IsCIDR, + ), }, "icmp_type": { Type: schema.TypeInt, @@ -277,14 +311,14 @@ func revokeAllNetworkACLEntries(netaclId string, meta interface{}) error { for _, e := range networkAcl.Entries { // Skip the default rules added by AWS. They can be neither // configured or deleted by users. See http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_ACLs.html#default-network-acl - if *e.RuleNumber == awsDefaultAclRuleNumberIpv4 || - *e.RuleNumber == awsDefaultAclRuleNumberIpv6 { + if aws.Int64Value(e.RuleNumber) == awsDefaultAclRuleNumberIpv4 || + aws.Int64Value(e.RuleNumber) == awsDefaultAclRuleNumberIpv6 { continue } // track if this is an egress or ingress rule, for logging purposes rt := "ingress" - if *e.Egress { + if aws.BoolValue(e.Egress) { rt = "egress" } diff --git a/aws/resource_aws_default_network_acl_test.go b/aws/resource_aws_default_network_acl_test.go index 9a8068bb766..10fd1078e1a 100644 --- a/aws/resource_aws_default_network_acl_test.go +++ b/aws/resource_aws_default_network_acl_test.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "regexp" "testing" "github.com/aws/aws-sdk-go/aws" @@ -27,6 +28,7 @@ var ipv6IngressAcl = &ec2.NetworkAclEntry{ func TestAccAWSDefaultNetworkAcl_basic(t *testing.T) { var networkAcl ec2.NetworkAcl + resourceName := "aws_default_network_acl.default" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -36,13 +38,14 @@ func TestAccAWSDefaultNetworkAcl_basic(t *testing.T) { { Config: testAccAWSDefaultNetworkConfig_basic, Check: resource.ComposeTestCheckFunc( - testAccGetAWSDefaultNetworkAcl("aws_default_network_acl.default", &networkAcl), + testAccGetAWSDefaultNetworkAcl(resourceName, &networkAcl), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`network-acl/acl-.+`)), testAccCheckAWSDefaultACLAttributes(&networkAcl, []*ec2.NetworkAclEntry{}, 0, 2), - testAccCheckResourceAttrAccountID("aws_default_network_acl.default", "owner_id"), + testAccCheckResourceAttrAccountID(resourceName, "owner_id"), ), }, { - ResourceName: "aws_default_network_acl.default", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -52,6 +55,7 @@ func TestAccAWSDefaultNetworkAcl_basic(t *testing.T) { func TestAccAWSDefaultNetworkAcl_basicIpv6Vpc(t *testing.T) { var networkAcl ec2.NetworkAcl + resourceName := "aws_default_network_acl.default" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -61,12 +65,12 @@ func TestAccAWSDefaultNetworkAcl_basicIpv6Vpc(t *testing.T) { { Config: testAccAWSDefaultNetworkConfig_basicIpv6Vpc, Check: resource.ComposeTestCheckFunc( - testAccGetAWSDefaultNetworkAcl("aws_default_network_acl.default", &networkAcl), + testAccGetAWSDefaultNetworkAcl(resourceName, &networkAcl), testAccCheckAWSDefaultACLAttributes(&networkAcl, []*ec2.NetworkAclEntry{}, 0, 4), ), }, { - ResourceName: "aws_default_network_acl.default", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -79,6 +83,7 @@ func TestAccAWSDefaultNetworkAcl_deny_ingress(t *testing.T) { // not Egress. We then expect there to be 3 rules, 2 AWS defaults and 1 // additional Egress. var networkAcl ec2.NetworkAcl + resourceName := "aws_default_network_acl.default" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -88,12 +93,12 @@ func TestAccAWSDefaultNetworkAcl_deny_ingress(t *testing.T) { { Config: testAccAWSDefaultNetworkConfig_deny_ingress, Check: resource.ComposeTestCheckFunc( - testAccGetAWSDefaultNetworkAcl("aws_default_network_acl.default", &networkAcl), + testAccGetAWSDefaultNetworkAcl(resourceName, &networkAcl), testAccCheckAWSDefaultACLAttributes(&networkAcl, []*ec2.NetworkAclEntry{defaultEgressAcl}, 0, 2), ), }, { - ResourceName: "aws_default_network_acl.default", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -103,6 +108,7 @@ func TestAccAWSDefaultNetworkAcl_deny_ingress(t *testing.T) { func TestAccAWSDefaultNetworkAcl_withIpv6Ingress(t *testing.T) { var networkAcl ec2.NetworkAcl + resourceName := "aws_default_network_acl.default" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -112,12 +118,12 @@ func TestAccAWSDefaultNetworkAcl_withIpv6Ingress(t *testing.T) { { Config: testAccAWSDefaultNetworkConfig_includingIpv6Rule, Check: resource.ComposeTestCheckFunc( - testAccGetAWSDefaultNetworkAcl("aws_default_network_acl.default", &networkAcl), + testAccGetAWSDefaultNetworkAcl(resourceName, &networkAcl), testAccCheckAWSDefaultACLAttributes(&networkAcl, []*ec2.NetworkAclEntry{ipv6IngressAcl}, 0, 2), ), }, { - ResourceName: "aws_default_network_acl.default", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -127,6 +133,7 @@ func TestAccAWSDefaultNetworkAcl_withIpv6Ingress(t *testing.T) { func TestAccAWSDefaultNetworkAcl_SubnetRemoval(t *testing.T) { var networkAcl ec2.NetworkAcl + resourceName := "aws_default_network_acl.default" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -136,12 +143,12 @@ func TestAccAWSDefaultNetworkAcl_SubnetRemoval(t *testing.T) { { Config: testAccAWSDefaultNetworkConfig_Subnets, Check: resource.ComposeTestCheckFunc( - testAccGetAWSDefaultNetworkAcl("aws_default_network_acl.default", &networkAcl), + testAccGetAWSDefaultNetworkAcl(resourceName, &networkAcl), testAccCheckAWSDefaultACLAttributes(&networkAcl, []*ec2.NetworkAclEntry{}, 2, 2), ), }, { - ResourceName: "aws_default_network_acl.default", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -152,13 +159,13 @@ func TestAccAWSDefaultNetworkAcl_SubnetRemoval(t *testing.T) { { Config: testAccAWSDefaultNetworkConfig_Subnets_remove, Check: resource.ComposeTestCheckFunc( - testAccGetAWSDefaultNetworkAcl("aws_default_network_acl.default", &networkAcl), + testAccGetAWSDefaultNetworkAcl(resourceName, &networkAcl), testAccCheckAWSDefaultACLAttributes(&networkAcl, []*ec2.NetworkAclEntry{}, 2, 2), ), ExpectNonEmptyPlan: true, }, { - ResourceName: "aws_default_network_acl.default", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -168,6 +175,7 @@ func TestAccAWSDefaultNetworkAcl_SubnetRemoval(t *testing.T) { func TestAccAWSDefaultNetworkAcl_SubnetReassign(t *testing.T) { var networkAcl ec2.NetworkAcl + resourceName := "aws_default_network_acl.default" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -177,12 +185,12 @@ func TestAccAWSDefaultNetworkAcl_SubnetReassign(t *testing.T) { { Config: testAccAWSDefaultNetworkConfig_Subnets, Check: resource.ComposeTestCheckFunc( - testAccGetAWSDefaultNetworkAcl("aws_default_network_acl.default", &networkAcl), + testAccGetAWSDefaultNetworkAcl(resourceName, &networkAcl), testAccCheckAWSDefaultACLAttributes(&networkAcl, []*ec2.NetworkAclEntry{}, 2, 2), ), }, { - ResourceName: "aws_default_network_acl.default", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -202,12 +210,12 @@ func TestAccAWSDefaultNetworkAcl_SubnetReassign(t *testing.T) { { Config: testAccAWSDefaultNetworkConfig_Subnets_move, Check: resource.ComposeTestCheckFunc( - testAccGetAWSDefaultNetworkAcl("aws_default_network_acl.default", &networkAcl), + testAccGetAWSDefaultNetworkAcl(resourceName, &networkAcl), testAccCheckAWSDefaultACLAttributes(&networkAcl, []*ec2.NetworkAclEntry{}, 0, 2), ), }, { - ResourceName: "aws_default_network_acl.default", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -260,7 +268,8 @@ func testAccGetAWSDefaultNetworkAcl(n string, networkAcl *ec2.NetworkAcl) resour return err } - if len(resp.NetworkAcls) > 0 && *resp.NetworkAcls[0].NetworkAclId == rs.Primary.ID { + if len(resp.NetworkAcls) > 0 && + aws.StringValue(resp.NetworkAcls[0].NetworkAclId) == rs.Primary.ID { *networkAcl = *resp.NetworkAcls[0] return nil } diff --git a/aws/resource_aws_network_acl.go b/aws/resource_aws_network_acl.go index cf1d4848029..ed0a1ae1e7a 100644 --- a/aws/resource_aws_network_acl.go +++ b/aws/resource_aws_network_acl.go @@ -4,17 +4,17 @@ import ( "bytes" "fmt" "log" - "sort" "strconv" "strings" "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "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" ) @@ -30,6 +30,10 @@ func resourceAwsNetworkAcl() *schema.Resource { }, Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, "vpc_id": { Type: schema.TypeString, Required: true, @@ -46,7 +50,6 @@ func resourceAwsNetworkAcl() *schema.Resource { Optional: true, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, "ingress": { Type: schema.TypeSet, @@ -56,16 +59,19 @@ func resourceAwsNetworkAcl() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "from_port": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IsPortNumberOrZero, }, "to_port": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IsPortNumberOrZero, }, "rule_no": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 32766), }, "action": { Type: schema.TypeString, @@ -73,6 +79,10 @@ func resourceAwsNetworkAcl() *schema.Resource { DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { return strings.EqualFold(old, new) }, + ValidateFunc: validation.StringInSlice([]string{ + ec2.RuleActionAllow, + ec2.RuleActionDeny, + }, true), }, "protocol": { Type: schema.TypeString, @@ -81,10 +91,18 @@ func resourceAwsNetworkAcl() *schema.Resource { "cidr_block": { Type: schema.TypeString, Optional: true, + ValidateFunc: validation.Any( + validation.StringIsEmpty, + validation.IsCIDR, + ), }, "ipv6_cidr_block": { Type: schema.TypeString, Optional: true, + ValidateFunc: validation.Any( + validation.StringIsEmpty, + validation.IsCIDR, + ), }, "icmp_type": { Type: schema.TypeInt, @@ -106,16 +124,19 @@ func resourceAwsNetworkAcl() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "from_port": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IsPortNumberOrZero, }, "to_port": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IsPortNumberOrZero, }, "rule_no": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 32766), }, "action": { Type: schema.TypeString, @@ -123,6 +144,10 @@ func resourceAwsNetworkAcl() *schema.Resource { DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { return strings.EqualFold(old, new) }, + ValidateFunc: validation.StringInSlice([]string{ + ec2.RuleActionAllow, + ec2.RuleActionDeny, + }, true), }, "protocol": { Type: schema.TypeString, @@ -131,10 +156,18 @@ func resourceAwsNetworkAcl() *schema.Resource { "cidr_block": { Type: schema.TypeString, Optional: true, + ValidateFunc: validation.Any( + validation.StringIsEmpty, + validation.IsCIDR, + ), }, "ipv6_cidr_block": { Type: schema.TypeString, Optional: true, + ValidateFunc: validation.Any( + validation.StringIsEmpty, + validation.IsCIDR, + ), }, "icmp_type": { Type: schema.TypeInt, @@ -174,7 +207,7 @@ func resourceAwsNetworkAclCreate(d *schema.ResourceData, meta interface{}) error // Get the ID and store it networkAcl := resp.NetworkAcl - d.SetId(*networkAcl.NetworkAclId) + d.SetId(aws.StringValue(networkAcl.NetworkAclId)) if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { if err := keyvaluetags.Ec2CreateTags(conn, d.Id(), v); err != nil { @@ -195,12 +228,10 @@ func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error { }) if err != nil { - if ec2err, ok := err.(awserr.Error); ok { - if ec2err.Code() == "InvalidNetworkAclID.NotFound" { - log.Printf("[DEBUG] Network ACL (%s) not found", d.Id()) - d.SetId("") - return nil - } + if isAWSErr(err, "InvalidNetworkAclID.NotFound", "") { + log.Printf("[WARN] Network ACL (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil } return err } @@ -216,12 +247,12 @@ func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error { for _, e := range networkAcl.Entries { // Skip the default rules added by AWS. They can be neither // configured or deleted by users. - if *e.RuleNumber == awsDefaultAclRuleNumberIpv4 || - *e.RuleNumber == awsDefaultAclRuleNumberIpv6 { + if aws.Int64Value(e.RuleNumber) == awsDefaultAclRuleNumberIpv4 || + aws.Int64Value(e.RuleNumber) == awsDefaultAclRuleNumberIpv6 { continue } - if *e.Egress { + if aws.BoolValue(e.Egress) { egressEntries = append(egressEntries, e) } else { ingressEntries = append(ingressEntries, e) @@ -236,12 +267,11 @@ func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error { d.Set("owner_id", networkAcl.OwnerId) - var s []string + var subnetIds []*string for _, a := range networkAcl.Associations { - s = append(s, *a.SubnetId) + subnetIds = append(subnetIds, a.SubnetId) } - sort.Strings(s) - if err := d.Set("subnet_ids", s); err != nil { + if err := d.Set("subnet_ids", flattenStringSet(subnetIds)); err != nil { return err } @@ -252,6 +282,16 @@ func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error { return err } + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Service: "ec2", + Region: meta.(*AWSClient).region, + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("network-acl/%s", d.Id()), + }.String() + + d.Set("arn", arn) + return nil } @@ -369,13 +409,13 @@ func updateNetworkAclEntries(d *schema.ResourceData, entryType string, conn *ec2 // neither modified nor destroyed. They have a custom rule // number that is out of bounds for any other rule. If we // encounter it, just continue. There's no work to be done. - if *remove.RuleNumber == awsDefaultAclRuleNumberIpv4 || - *remove.RuleNumber == awsDefaultAclRuleNumberIpv6 { + if aws.Int64Value(remove.RuleNumber) == awsDefaultAclRuleNumberIpv4 || + aws.Int64Value(remove.RuleNumber) == awsDefaultAclRuleNumberIpv6 { continue } // Delete old Acl - log.Printf("[DEBUG] Destroying Network ACL Entry number (%d)", int(*remove.RuleNumber)) + log.Printf("[DEBUG] Destroying Network ACL Entry number (%d)", int(aws.Int64Value(remove.RuleNumber))) _, err := conn.DeleteNetworkAclEntry(&ec2.DeleteNetworkAclEntryInput{ NetworkAclId: aws.String(d.Id()), RuleNumber: remove.RuleNumber, @@ -395,9 +435,9 @@ func updateNetworkAclEntries(d *schema.ResourceData, entryType string, conn *ec2 // hash differently when being read out of the API. Force the user // to set from_port and to_port to 0 for these rules, to keep the // hashing consistent. - if *add.Protocol == "-1" { - to := *add.PortRange.To - from := *add.PortRange.From + if aws.StringValue(add.Protocol) == "-1" { + to := aws.Int64Value(add.PortRange.To) + from := aws.Int64Value(add.PortRange.From) expected := &expectedPortPair{ to_port: 0, from_port: 0, @@ -409,12 +449,12 @@ func updateNetworkAclEntries(d *schema.ResourceData, entryType string, conn *ec2 } } - if add.CidrBlock != nil && *add.CidrBlock != "" { + if add.CidrBlock != nil && aws.StringValue(add.CidrBlock) != "" { // AWS mutates the CIDR block into a network implied by the IP and // mask provided. This results in hashing inconsistencies between // the local config file and the state returned by the API. Error // if the user provides a CIDR block with an inappropriate mask - if err := validateCIDRBlock(*add.CidrBlock); err != nil { + if err := validateCIDRBlock(aws.StringValue(add.CidrBlock)); err != nil { return err } } @@ -429,11 +469,11 @@ func updateNetworkAclEntries(d *schema.ResourceData, entryType string, conn *ec2 IcmpTypeCode: add.IcmpTypeCode, } - if add.CidrBlock != nil && *add.CidrBlock != "" { + if add.CidrBlock != nil && aws.StringValue(add.CidrBlock) != "" { createOpts.CidrBlock = add.CidrBlock } - if add.Ipv6CidrBlock != nil && *add.Ipv6CidrBlock != "" { + if add.Ipv6CidrBlock != nil && aws.StringValue(add.Ipv6CidrBlock) != "" { createOpts.Ipv6CidrBlock = add.Ipv6CidrBlock } @@ -519,28 +559,27 @@ func cleanUpDependencyViolations(d *schema.ResourceData, conn *ec2.EC2) error { } for _, a := range associations { - log.Printf("DEBUG] Replacing Network Acl Association (%s) with Default Network ACL ID (%s)", *a.NetworkAclAssociationId, *defaultAcl.NetworkAclId) + log.Printf("DEBUG] Replacing Network Acl Association (%s) with Default Network ACL ID (%s)", + aws.StringValue(a.NetworkAclAssociationId), aws.StringValue(defaultAcl.NetworkAclId)) _, replaceErr := conn.ReplaceNetworkAclAssociation(&ec2.ReplaceNetworkAclAssociationInput{ AssociationId: a.NetworkAclAssociationId, NetworkAclId: defaultAcl.NetworkAclId, }) if replaceErr != nil { - if replaceEc2err, ok := replaceErr.(awserr.Error); ok { - // It's possible that during an attempt to replace this - // association, the Subnet in question has already been moved to - // another ACL. This can happen if you're destroying a network acl - // and simultaneously re-associating it's subnet(s) with another - // ACL; Terraform may have already re-associated the subnet(s) by - // the time we attempt to destroy them, even between the time we - // list them and then try to destroy them. In this case, the - // association we're trying to replace will no longer exist and - // this call will fail. Here we trap that error and fail - // gracefully; the association we tried to replace gone, we trust - // someone else has taken ownership. - if replaceEc2err.Code() == "InvalidAssociationID.NotFound" { - log.Printf("[WARN] Network Association (%s) no longer found; Network Association likely updated or removed externally, removing from state", *a.NetworkAclAssociationId) - continue - } + // It's possible that during an attempt to replace this + // association, the Subnet in question has already been moved to + // another ACL. This can happen if you're destroying a network acl + // and simultaneously re-associating it's subnet(s) with another + // ACL; Terraform may have already re-associated the subnet(s) by + // the time we attempt to destroy them, even between the time we + // list them and then try to destroy them. In this case, the + // association we're trying to replace will no longer exist and + // this call will fail. Here we trap that error and fail + // gracefully; the association we tried to replace gone, we trust + // someone else has taken ownership. + if isAWSErr(replaceErr, "InvalidAssociationID.NotFound", "") { + log.Printf("[WARN] Network Association (%s) no longer found; Network Association likely updated or removed externally, removing from state", aws.StringValue(a.NetworkAclAssociationId)) + continue } log.Printf("[ERR] Non retry-able error in replacing associations for Network ACL (%s): %s", d.Id(), replaceErr) return fmt.Errorf("Error replacing network ACL associations: %s", err) @@ -590,7 +629,7 @@ func resourceAwsNetworkAclEntryHash(v interface{}) int { return hashcode.String(buf.String()) } -func getDefaultNetworkAcl(vpc_id string, conn *ec2.EC2) (defaultAcl *ec2.NetworkAcl, err error) { +func getDefaultNetworkAcl(vpcId string, conn *ec2.EC2) (defaultAcl *ec2.NetworkAcl, err error) { resp, err := conn.DescribeNetworkAcls(&ec2.DescribeNetworkAclsInput{ Filters: []*ec2.Filter{ { @@ -599,7 +638,7 @@ func getDefaultNetworkAcl(vpc_id string, conn *ec2.EC2) (defaultAcl *ec2.Network }, { Name: aws.String("vpc-id"), - Values: []*string{aws.String(vpc_id)}, + Values: []*string{aws.String(vpcId)}, }, }, }) @@ -643,33 +682,33 @@ func networkAclEntriesToMapList(networkAcls []*ec2.NetworkAclEntry) []map[string result := make([]map[string]interface{}, 0, len(networkAcls)) for _, entry := range networkAcls { acl := make(map[string]interface{}) - acl["rule_no"] = *entry.RuleNumber - acl["action"] = *entry.RuleAction + acl["rule_no"] = aws.Int64Value(entry.RuleNumber) + acl["action"] = aws.StringValue(entry.RuleAction) if entry.CidrBlock != nil { - acl["cidr_block"] = *entry.CidrBlock + acl["cidr_block"] = aws.StringValue(entry.CidrBlock) } if entry.Ipv6CidrBlock != nil { - acl["ipv6_cidr_block"] = *entry.Ipv6CidrBlock + acl["ipv6_cidr_block"] = aws.StringValue(entry.Ipv6CidrBlock) } // The AWS network ACL API only speaks protocol numbers, and // that's all we record. - if _, err := strconv.Atoi(*entry.Protocol); err != nil { + if _, err := strconv.Atoi(aws.StringValue(entry.Protocol)); err != nil { // We're a protocol name. Look up the number. - acl["protocol"] = protocolIntegers()[*entry.Protocol] + acl["protocol"] = protocolIntegers()[aws.StringValue(entry.Protocol)] } else { // We're a protocol number. Pass through. - acl["protocol"] = *entry.Protocol + acl["protocol"] = aws.StringValue(entry.Protocol) } - acl["protocol"] = *entry.Protocol + acl["protocol"] = aws.StringValue(entry.Protocol) if entry.PortRange != nil { - acl["from_port"] = *entry.PortRange.From - acl["to_port"] = *entry.PortRange.To + acl["from_port"] = aws.Int64Value(entry.PortRange.From) + acl["to_port"] = aws.Int64Value(entry.PortRange.To) } if entry.IcmpTypeCode != nil { - acl["icmp_type"] = *entry.IcmpTypeCode.Type - acl["icmp_code"] = *entry.IcmpTypeCode.Code + acl["icmp_type"] = aws.Int64Value(entry.IcmpTypeCode.Type) + acl["icmp_code"] = aws.Int64Value(entry.IcmpTypeCode.Code) } result = append(result, acl) diff --git a/aws/resource_aws_network_acl_rule_test.go b/aws/resource_aws_network_acl_rule_test.go index 145025e55bd..52a198b8f62 100644 --- a/aws/resource_aws_network_acl_rule_test.go +++ b/aws/resource_aws_network_acl_rule_test.go @@ -102,7 +102,7 @@ func TestAccAWSNetworkAclRule_disappears_NetworkAcl(t *testing.T) { Config: testAccAWSNetworkAclRuleBasicConfig, Check: resource.ComposeTestCheckFunc( testAccCheckAWSNetworkAclExists(resourceName, &networkAcl), - testAccCheckAWSNetworkAclDisappears(&networkAcl), + testAccCheckResourceDisappears(testAccProvider, resourceAwsNetworkAcl(), resourceName), ), ExpectNonEmptyPlan: true, }, diff --git a/aws/resource_aws_network_acl_test.go b/aws/resource_aws_network_acl_test.go index f55382b2a06..9ab665c6e63 100644 --- a/aws/resource_aws_network_acl_test.go +++ b/aws/resource_aws_network_acl_test.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "regexp" "testing" "github.com/aws/aws-sdk-go/aws" @@ -115,6 +116,7 @@ func TestAccAWSNetworkAcl_basic(t *testing.T) { Config: testAccAWSNetworkAclEgressNIngressConfig, Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSNetworkAclExists(resourceName, &networkAcl), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`network-acl/acl-.+`)), ), }, { @@ -139,7 +141,7 @@ func TestAccAWSNetworkAcl_disappears(t *testing.T) { Config: testAccAWSNetworkAclEgressNIngressConfig, Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSNetworkAclExists(resourceName, &networkAcl), - testAccCheckAWSNetworkAclDisappears(&networkAcl), + testAccCheckResourceDisappears(testAccProvider, resourceAwsNetworkAcl(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -735,20 +737,6 @@ func testAccCheckAWSNetworkAclDestroy(s *terraform.State) error { return nil } -func testAccCheckAWSNetworkAclDisappears(networkAcl *ec2.NetworkAcl) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).ec2conn - - input := &ec2.DeleteNetworkAclInput{ - NetworkAclId: networkAcl.NetworkAclId, - } - - _, err := conn.DeleteNetworkAcl(input) - - return err - } -} - func testAccCheckAWSNetworkAclExists(n string, networkAcl *ec2.NetworkAcl) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index a4f1dc649f2..c607a30e559 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -232,6 +232,7 @@ for more information about connecting to alternate AWS endpoints or AWS compatib - [`aws_cognito_identity_pool` resource](/docs/providers/aws/r/cognito_identity_pool.html) - [`aws_cognito_user_pool` resource](/docs/providers/aws/r/cognito_user_pool.html) - [`aws_cognito_user_pools` data source](/docs/providers/aws/d/cognito_user_pools.html) + - [`aws_default_network_acl` resource](/docs/providers/aws/r/default_network_acl.html) - [`aws_default_vpc_dhcp_options`](/docs/providers/aws/r/default_vpc_dhcp_options.html) - [`aws_dms_event_subscription` resource](/docs/providers/aws/r/dms_event_subscription.html) - [`aws_dms_replication_subnet_group` resource](/docs/providers/aws/r/dms_replication_subnet_group.html) @@ -278,6 +279,7 @@ for more information about connecting to alternate AWS endpoints or AWS compatib - [`aws_key_pair` resource](/docs/providers/aws/r/key_pair.html) - [`aws_launch_template` data source](/docs/providers/aws/d/launch_template.html) - [`aws_launch_template` resource](/docs/providers/aws/r/launch_template.html) + - [`aws_network_acl` resource](/docs/providers/aws/r/network_acl.html) - [`aws_redshift_cluster` resource](/docs/providers/aws/r/redshift_cluster.html) - [`aws_redshift_event_subscription` resource](/docs/providers/aws/r/redshift_event_subscription.html) - [`aws_redshift_parameter_group` resource](/docs/providers/aws/r/redshift_parameter_group.html) diff --git a/website/docs/r/default_network_acl.html.markdown b/website/docs/r/default_network_acl.html.markdown index 34833b3bf9e..9cae2143252 100644 --- a/website/docs/r/default_network_acl.html.markdown +++ b/website/docs/r/default_network_acl.html.markdown @@ -182,6 +182,7 @@ can resume managing them via the AWS Console. In addition to all arguments above, the following attributes are exported: * `id` - The ID of the Default Network ACL +* `arn` - The ARN of the Default Network ACL * `vpc_id` - The ID of the associated VPC * `ingress` - Set of ingress rules * `egress` - Set of egress rules diff --git a/website/docs/r/network_acl.html.markdown b/website/docs/r/network_acl.html.markdown index 487f57def07..c93a6d7848c 100644 --- a/website/docs/r/network_acl.html.markdown +++ b/website/docs/r/network_acl.html.markdown @@ -80,6 +80,7 @@ valid network mask. In addition to all arguments above, the following attributes are exported: * `id` - The ID of the network ACL +* `arn` - The ARN of the network ACL * `owner_id` - The ID of the AWS account that owns the network ACL.