2014-11-26 14:44:02 +01:00
package aws
import (
2014-12-01 09:49:05 +01:00
"bytes"
2014-11-26 14:44:02 +01:00
"fmt"
"log"
2015-05-12 20:24:32 +02:00
"sort"
2015-05-06 15:22:18 +02:00
"strconv"
2014-12-03 08:34:28 +01:00
"time"
2014-11-26 14:44:02 +01:00
2015-06-03 20:36:57 +02:00
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/ec2"
2014-11-30 12:40:54 +01:00
"github.com/hashicorp/terraform/helper/hashcode"
2014-12-03 08:34:28 +01:00
"github.com/hashicorp/terraform/helper/resource"
2014-12-01 09:49:05 +01:00
"github.com/hashicorp/terraform/helper/schema"
2014-11-26 14:44:02 +01:00
)
func resourceAwsNetworkAcl ( ) * schema . Resource {
return & schema . Resource {
2014-12-01 09:49:05 +01:00
Create : resourceAwsNetworkAclCreate ,
Read : resourceAwsNetworkAclRead ,
Delete : resourceAwsNetworkAclDelete ,
Update : resourceAwsNetworkAclUpdate ,
2016-05-13 22:01:05 +02:00
Importer : & schema . ResourceImporter {
State : resourceAwsNetworkAclImportState ,
} ,
2014-11-26 14:44:02 +01:00
Schema : map [ string ] * schema . Schema {
2017-03-14 11:39:39 +01:00
"vpc_id" : {
2014-11-26 14:44:02 +01:00
Type : schema . TypeString ,
2014-12-03 08:53:18 +01:00
Required : true ,
2014-11-26 14:44:02 +01:00
ForceNew : true ,
2014-12-03 08:53:18 +01:00
Computed : false ,
2014-11-26 14:44:02 +01:00
} ,
2017-03-14 11:39:39 +01:00
"subnet_id" : {
2015-05-15 21:38:06 +02:00
Type : schema . TypeString ,
Optional : true ,
ForceNew : true ,
Computed : false ,
Deprecated : "Attribute subnet_id is deprecated on network_acl resources. Use subnet_ids instead" ,
2015-05-12 20:24:32 +02:00
} ,
2017-03-14 11:39:39 +01:00
"subnet_ids" : {
2015-05-15 00:09:50 +02:00
Type : schema . TypeSet ,
Optional : true ,
2015-05-15 17:58:59 +02:00
Computed : true ,
2015-05-15 00:09:50 +02:00
ConflictsWith : [ ] string { "subnet_id" } ,
Elem : & schema . Schema { Type : schema . TypeString } ,
Set : schema . HashString ,
2014-11-30 12:40:54 +01:00
} ,
2017-03-14 11:39:39 +01:00
"ingress" : {
2014-11-30 12:40:54 +01:00
Type : schema . TypeSet ,
Required : false ,
Optional : true ,
2015-12-22 16:58:22 +01:00
Computed : true ,
2014-11-30 12:40:54 +01:00
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
2017-03-14 11:39:39 +01:00
"from_port" : {
2014-11-30 12:40:54 +01:00
Type : schema . TypeInt ,
Required : true ,
} ,
2017-03-14 11:39:39 +01:00
"to_port" : {
2014-11-30 12:40:54 +01:00
Type : schema . TypeInt ,
Required : true ,
} ,
2017-03-14 11:39:39 +01:00
"rule_no" : {
2014-11-30 12:40:54 +01:00
Type : schema . TypeInt ,
Required : true ,
} ,
2017-03-14 11:39:39 +01:00
"action" : {
2014-11-30 12:40:54 +01:00
Type : schema . TypeString ,
Required : true ,
} ,
2017-03-14 11:39:39 +01:00
"protocol" : {
2014-11-30 12:40:54 +01:00
Type : schema . TypeString ,
Required : true ,
} ,
2017-03-14 11:39:39 +01:00
"cidr_block" : {
2014-11-30 12:40:54 +01:00
Type : schema . TypeString ,
Optional : true ,
} ,
2017-03-14 11:39:39 +01:00
"ipv6_cidr_block" : {
Type : schema . TypeString ,
Optional : true ,
} ,
"icmp_type" : {
2015-05-29 23:48:50 +02:00
Type : schema . TypeInt ,
Optional : true ,
} ,
2017-03-14 11:39:39 +01:00
"icmp_code" : {
2015-05-29 23:48:50 +02:00
Type : schema . TypeInt ,
Optional : true ,
} ,
2014-11-30 12:40:54 +01:00
} ,
} ,
Set : resourceAwsNetworkAclEntryHash ,
} ,
2017-03-14 11:39:39 +01:00
"egress" : {
2014-11-30 12:40:54 +01:00
Type : schema . TypeSet ,
Required : false ,
Optional : true ,
2015-12-22 16:58:22 +01:00
Computed : true ,
2014-11-30 12:40:54 +01:00
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
2017-03-14 11:39:39 +01:00
"from_port" : {
2014-11-30 12:40:54 +01:00
Type : schema . TypeInt ,
Required : true ,
} ,
2017-03-14 11:39:39 +01:00
"to_port" : {
2014-11-30 12:40:54 +01:00
Type : schema . TypeInt ,
Required : true ,
} ,
2017-03-14 11:39:39 +01:00
"rule_no" : {
2014-11-30 12:40:54 +01:00
Type : schema . TypeInt ,
Required : true ,
} ,
2017-03-14 11:39:39 +01:00
"action" : {
2014-11-30 12:40:54 +01:00
Type : schema . TypeString ,
Required : true ,
} ,
2017-03-14 11:39:39 +01:00
"protocol" : {
2014-11-30 12:40:54 +01:00
Type : schema . TypeString ,
Required : true ,
} ,
2017-03-14 11:39:39 +01:00
"cidr_block" : {
2014-11-30 12:40:54 +01:00
Type : schema . TypeString ,
Optional : true ,
} ,
2017-03-14 11:39:39 +01:00
"ipv6_cidr_block" : {
Type : schema . TypeString ,
Optional : true ,
} ,
"icmp_type" : {
2015-05-29 23:48:50 +02:00
Type : schema . TypeInt ,
Optional : true ,
} ,
2017-03-14 11:39:39 +01:00
"icmp_code" : {
2015-05-29 23:48:50 +02:00
Type : schema . TypeInt ,
Optional : true ,
} ,
2014-11-30 12:40:54 +01:00
} ,
} ,
Set : resourceAwsNetworkAclEntryHash ,
2014-12-01 09:49:05 +01:00
} ,
2014-12-10 11:59:00 +01:00
"tags" : tagsSchema ( ) ,
2014-11-26 14:44:02 +01:00
} ,
}
}
func resourceAwsNetworkAclCreate ( d * schema . ResourceData , meta interface { } ) error {
2014-12-01 09:49:05 +01:00
2015-04-16 22:05:55 +02:00
conn := meta . ( * AWSClient ) . ec2conn
2014-11-26 14:44:02 +01:00
// Create the Network Acl
2015-08-17 20:27:16 +02:00
createOpts := & ec2 . CreateNetworkAclInput {
VpcId : aws . String ( d . Get ( "vpc_id" ) . ( string ) ) ,
2014-11-26 14:44:02 +01:00
}
2014-12-03 08:34:28 +01:00
2014-11-26 14:44:02 +01:00
log . Printf ( "[DEBUG] Network Acl create config: %#v" , createOpts )
2015-08-17 20:27:16 +02:00
resp , err := conn . CreateNetworkAcl ( createOpts )
2014-11-26 14:44:02 +01:00
if err != nil {
return fmt . Errorf ( "Error creating network acl: %s" , err )
}
// Get the ID and store it
2015-08-17 20:27:16 +02:00
networkAcl := resp . NetworkAcl
d . SetId ( * networkAcl . NetworkAclId )
log . Printf ( "[INFO] Network Acl ID: %s" , * networkAcl . NetworkAclId )
2014-11-26 14:44:02 +01:00
2014-12-03 08:34:28 +01:00
// Update rules and subnet association once acl is created
2014-11-30 12:40:54 +01:00
return resourceAwsNetworkAclUpdate ( d , meta )
2014-11-26 14:44:02 +01:00
}
func resourceAwsNetworkAclRead ( d * schema . ResourceData , meta interface { } ) error {
2015-04-16 22:05:55 +02:00
conn := meta . ( * AWSClient ) . ec2conn
2014-11-26 14:44:02 +01:00
2015-08-17 20:27:16 +02:00
resp , err := conn . DescribeNetworkAcls ( & ec2 . DescribeNetworkAclsInput {
NetworkAclIds : [ ] * string { aws . String ( d . Id ( ) ) } ,
2015-03-11 21:01:07 +01:00
} )
2014-11-26 14:44:02 +01:00
if err != nil {
2016-04-05 18:11:16 +02:00
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
}
}
2014-11-26 14:44:02 +01:00
return err
}
if resp == nil {
return nil
}
2015-08-17 20:27:16 +02:00
networkAcl := resp . NetworkAcls [ 0 ]
var ingressEntries [ ] * ec2 . NetworkAclEntry
var egressEntries [ ] * ec2 . NetworkAclEntry
2014-11-26 14:44:02 +01:00
2014-12-03 08:34:28 +01:00
// separate the ingress and egress rules
2015-03-11 21:01:07 +01:00
for _ , e := range networkAcl . Entries {
2015-05-06 15:10:44 +02:00
// Skip the default rules added by AWS. They can be neither
// configured or deleted by users.
2016-04-18 18:02:00 +02:00
if * e . RuleNumber == awsDefaultAclRuleNumber {
2015-05-06 15:10:44 +02:00
continue
}
2015-03-11 21:01:07 +01:00
if * e . Egress == true {
2014-11-30 12:40:54 +01:00
egressEntries = append ( egressEntries , e )
2014-12-01 09:49:05 +01:00
} else {
2014-11-30 12:40:54 +01:00
ingressEntries = append ( ingressEntries , e )
}
}
2015-08-17 20:27:16 +02:00
d . Set ( "vpc_id" , networkAcl . VpcId )
2015-05-12 21:58:10 +02:00
d . Set ( "tags" , tagsToMap ( networkAcl . Tags ) )
2014-11-30 12:40:54 +01:00
2015-05-12 20:24:32 +02:00
var s [ ] string
for _ , a := range networkAcl . Associations {
2015-08-17 20:27:16 +02:00
s = append ( s , * a . SubnetId )
2015-05-12 20:24:32 +02:00
}
sort . Strings ( s )
if err := d . Set ( "subnet_ids" , s ) ; err != nil {
return err
}
2015-05-05 20:44:05 +02:00
if err := d . Set ( "ingress" , networkAclEntriesToMapList ( ingressEntries ) ) ; err != nil {
return err
}
if err := d . Set ( "egress" , networkAclEntriesToMapList ( egressEntries ) ) ; err != nil {
return err
}
2014-11-26 14:44:02 +01:00
return nil
}
func resourceAwsNetworkAclUpdate ( d * schema . ResourceData , meta interface { } ) error {
2015-04-16 22:05:55 +02:00
conn := meta . ( * AWSClient ) . ec2conn
2014-11-30 12:40:54 +01:00
d . Partial ( true )
2014-12-01 09:49:05 +01:00
if d . HasChange ( "ingress" ) {
2015-04-13 18:14:21 +02:00
err := updateNetworkAclEntries ( d , "ingress" , conn )
2014-12-01 09:49:05 +01:00
if err != nil {
2014-11-30 12:40:54 +01:00
return err
}
}
2014-12-01 09:49:05 +01:00
if d . HasChange ( "egress" ) {
2015-04-13 18:14:21 +02:00
err := updateNetworkAclEntries ( d , "egress" , conn )
2014-12-01 09:49:05 +01:00
if err != nil {
2014-11-30 12:40:54 +01:00
return err
}
}
2014-12-03 08:53:18 +01:00
if d . HasChange ( "subnet_id" ) {
//associate new subnet with the acl.
_ , n := d . GetChange ( "subnet_id" )
newSubnet := n . ( string )
2015-04-13 18:14:21 +02:00
association , err := findNetworkAclAssociation ( newSubnet , conn )
2014-12-03 08:53:18 +01:00
if err != nil {
2014-12-17 12:37:42 +01:00
return fmt . Errorf ( "Failed to update acl %s with subnet %s: %s" , d . Id ( ) , newSubnet , err )
2014-12-03 08:34:28 +01:00
}
2015-08-17 20:27:16 +02:00
_ , err = conn . ReplaceNetworkAclAssociation ( & ec2 . ReplaceNetworkAclAssociationInput {
AssociationId : association . NetworkAclAssociationId ,
NetworkAclId : aws . String ( d . Id ( ) ) ,
2015-03-11 21:01:07 +01:00
} )
2014-12-03 08:34:28 +01:00
if err != nil {
return err
}
}
2015-05-12 20:24:32 +02:00
if d . HasChange ( "subnet_ids" ) {
o , n := d . GetChange ( "subnet_ids" )
2015-05-15 00:09:50 +02:00
if o == nil {
o = new ( schema . Set )
2015-05-12 20:24:32 +02:00
}
2015-05-15 00:09:50 +02:00
if n == nil {
n = new ( schema . Set )
2015-05-12 20:24:32 +02:00
}
2015-05-15 00:09:50 +02:00
os := o . ( * schema . Set )
ns := n . ( * schema . Set )
remove := os . Difference ( ns ) . List ( )
add := ns . Difference ( os ) . List ( )
2015-05-12 20:24:32 +02:00
if len ( remove ) > 0 {
// A Network ACL is required for each subnet. In order to disassociate a
// subnet from this ACL, we must associate it with the default ACL.
defaultAcl , err := getDefaultNetworkAcl ( d . Get ( "vpc_id" ) . ( string ) , conn )
if err != nil {
return fmt . Errorf ( "Failed to find Default ACL for VPC %s" , d . Get ( "vpc_id" ) . ( string ) )
}
for _ , r := range remove {
2015-05-15 00:09:50 +02:00
association , err := findNetworkAclAssociation ( r . ( string ) , conn )
2015-05-12 20:24:32 +02:00
if err != nil {
return fmt . Errorf ( "Failed to find acl association: acl %s with subnet %s: %s" , d . Id ( ) , r , err )
}
2016-05-02 16:45:11 +02:00
log . Printf ( "DEBUG] Replacing Network Acl Association (%s) with Default Network ACL ID (%s)" , * association . NetworkAclAssociationId , * defaultAcl . NetworkAclId )
2015-08-17 20:27:16 +02:00
_ , err = conn . ReplaceNetworkAclAssociation ( & ec2 . ReplaceNetworkAclAssociationInput {
AssociationId : association . NetworkAclAssociationId ,
NetworkAclId : defaultAcl . NetworkAclId ,
2015-05-12 20:24:32 +02:00
} )
if err != nil {
return err
}
}
}
if len ( add ) > 0 {
for _ , a := range add {
2015-05-15 00:09:50 +02:00
association , err := findNetworkAclAssociation ( a . ( string ) , conn )
2015-05-12 20:24:32 +02:00
if err != nil {
return fmt . Errorf ( "Failed to find acl association: acl %s with subnet %s: %s" , d . Id ( ) , a , err )
}
2015-08-17 20:27:16 +02:00
_ , err = conn . ReplaceNetworkAclAssociation ( & ec2 . ReplaceNetworkAclAssociationInput {
AssociationId : association . NetworkAclAssociationId ,
NetworkAclId : aws . String ( d . Id ( ) ) ,
2015-05-12 20:24:32 +02:00
} )
if err != nil {
return err
}
}
}
}
2015-05-12 21:58:10 +02:00
if err := setTags ( conn , d ) ; err != nil {
2014-12-10 11:59:00 +01:00
return err
} else {
d . SetPartial ( "tags" )
}
2014-11-30 12:40:54 +01:00
d . Partial ( false )
2014-11-26 14:44:02 +01:00
return resourceAwsNetworkAclRead ( d , meta )
2014-11-30 12:40:54 +01:00
}
2015-04-13 18:14:21 +02:00
func updateNetworkAclEntries ( d * schema . ResourceData , entryType string , conn * ec2 . EC2 ) error {
2015-12-11 19:41:33 +01:00
if d . HasChange ( entryType ) {
o , n := d . GetChange ( entryType )
2015-05-06 15:10:44 +02:00
2015-12-11 19:41:33 +01:00
if o == nil {
o = new ( schema . Set )
}
if n == nil {
n = new ( schema . Set )
2015-05-06 15:10:44 +02:00
}
2015-12-11 19:41:33 +01:00
os := o . ( * schema . Set )
ns := n . ( * schema . Set )
toBeDeleted , err := expandNetworkAclEntries ( os . Difference ( ns ) . List ( ) , entryType )
2014-12-01 09:49:05 +01:00
if err != nil {
2015-12-11 19:41:33 +01:00
return err
2014-12-01 09:49:05 +01:00
}
2015-12-11 19:41:33 +01:00
for _ , remove := range toBeDeleted {
// AWS includes default rules with all network ACLs that can be
// 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.
2016-04-18 18:02:00 +02:00
if * remove . RuleNumber == awsDefaultAclRuleNumber {
2015-12-11 19:41:33 +01:00
continue
2015-05-06 15:14:33 +02:00
}
2015-12-11 19:41:33 +01:00
// Delete old Acl
2016-04-18 18:02:00 +02:00
log . Printf ( "[DEBUG] Destroying Network ACL Entry number (%d)" , int ( * remove . RuleNumber ) )
2015-12-11 19:41:33 +01:00
_ , err := conn . DeleteNetworkAclEntry ( & ec2 . DeleteNetworkAclEntryInput {
NetworkAclId : aws . String ( d . Id ( ) ) ,
RuleNumber : remove . RuleNumber ,
Egress : remove . Egress ,
} )
if err != nil {
return fmt . Errorf ( "Error deleting %s entry: %s" , entryType , err )
2015-05-06 15:14:33 +02:00
}
}
2015-12-11 19:41:33 +01:00
toBeCreated , err := expandNetworkAclEntries ( ns . Difference ( os ) . List ( ) , entryType )
if err != nil {
2015-05-06 15:16:46 +02:00
return err
}
2015-12-11 19:41:33 +01:00
for _ , add := range toBeCreated {
// Protocol -1 rules don't store ports in AWS. Thus, they'll always
// 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
expected := & expectedPortPair {
to_port : 0 ,
from_port : 0 ,
}
if ok := validatePorts ( to , from , * expected ) ; ! ok {
return fmt . Errorf (
"to_port (%d) and from_port (%d) must both be 0 to use the the 'all' \"-1\" protocol!" ,
to , from )
}
}
2015-05-06 15:16:46 +02:00
2017-03-14 11:39:39 +01:00
if add . CidrBlock != nil {
// 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 {
return err
}
2015-12-11 19:41:33 +01:00
}
2017-03-14 11:39:39 +01:00
createOpts := & ec2 . CreateNetworkAclEntryInput {
2015-12-11 19:41:33 +01:00
NetworkAclId : aws . String ( d . Id ( ) ) ,
Egress : add . Egress ,
PortRange : add . PortRange ,
Protocol : add . Protocol ,
RuleAction : add . RuleAction ,
RuleNumber : add . RuleNumber ,
IcmpTypeCode : add . IcmpTypeCode ,
2017-03-14 11:39:39 +01:00
}
if add . CidrBlock != nil {
createOpts . CidrBlock = add . CidrBlock
}
if add . Ipv6CidrBlock != nil {
createOpts . Ipv6CidrBlock = add . Ipv6CidrBlock
}
// Add new Acl entry
_ , connErr := conn . CreateNetworkAclEntry ( createOpts )
2015-12-11 19:41:33 +01:00
if connErr != nil {
return fmt . Errorf ( "Error creating %s entry: %s" , entryType , connErr )
}
2014-12-01 09:49:05 +01:00
}
2014-11-30 12:40:54 +01:00
}
return nil
2014-11-26 14:44:02 +01:00
}
func resourceAwsNetworkAclDelete ( d * schema . ResourceData , meta interface { } ) error {
2015-04-16 22:05:55 +02:00
conn := meta . ( * AWSClient ) . ec2conn
2014-11-26 14:44:02 +01:00
log . Printf ( "[INFO] Deleting Network Acl: %s" , d . Id ( ) )
2016-04-05 17:18:03 +02:00
retryErr := resource . Retry ( 5 * time . Minute , func ( ) * resource . RetryError {
2015-08-17 20:27:16 +02:00
_ , err := conn . DeleteNetworkAcl ( & ec2 . DeleteNetworkAclInput {
NetworkAclId : aws . String ( d . Id ( ) ) ,
2015-03-11 21:01:07 +01:00
} )
if err != nil {
2015-05-20 13:21:23 +02:00
ec2err := err . ( awserr . Error )
switch ec2err . Code ( ) {
2014-12-03 08:53:18 +01:00
case "InvalidNetworkAclID.NotFound" :
return nil
case "DependencyViolation" :
// In case of dependency violation, we remove the association between subnet and network acl.
// This means the subnet is attached to default acl of vpc.
2015-08-17 20:27:16 +02:00
var associations [ ] * ec2 . NetworkAclAssociation
2015-05-12 20:24:32 +02:00
if v , ok := d . GetOk ( "subnet_id" ) ; ok {
2015-05-15 17:58:59 +02:00
2015-05-12 20:24:32 +02:00
a , err := findNetworkAclAssociation ( v . ( string ) , conn )
if err != nil {
2016-03-09 23:53:32 +01:00
return resource . NonRetryableError ( err )
2015-05-12 20:24:32 +02:00
}
associations = append ( associations , a )
2015-05-15 17:58:59 +02:00
} else if v , ok := d . GetOk ( "subnet_ids" ) ; ok {
2015-05-15 00:09:50 +02:00
ids := v . ( * schema . Set ) . List ( )
2015-05-12 20:24:32 +02:00
for _ , i := range ids {
a , err := findNetworkAclAssociation ( i . ( string ) , conn )
if err != nil {
2016-03-09 23:53:32 +01:00
return resource . NonRetryableError ( err )
2015-05-12 20:24:32 +02:00
}
associations = append ( associations , a )
}
2014-12-03 08:53:18 +01:00
}
2016-04-05 17:18:03 +02:00
log . Printf ( "[DEBUG] Replacing network associations for Network ACL (%s): %s" , d . Id ( ) , associations )
2015-04-13 18:14:21 +02:00
defaultAcl , err := getDefaultNetworkAcl ( d . Get ( "vpc_id" ) . ( string ) , conn )
2014-12-03 08:53:18 +01:00
if err != nil {
2016-03-09 23:53:32 +01:00
return resource . NonRetryableError ( err )
2014-12-03 08:53:18 +01:00
}
2015-05-12 20:24:32 +02:00
for _ , a := range associations {
2016-05-02 16:45:11 +02:00
log . Printf ( "DEBUG] Replacing Network Acl Association (%s) with Default Network ACL ID (%s)" , * a . NetworkAclAssociationId , * defaultAcl . NetworkAclId )
2016-04-05 17:18:03 +02:00
_ , replaceErr := conn . ReplaceNetworkAclAssociation ( & ec2 . ReplaceNetworkAclAssociationInput {
2015-08-17 20:27:16 +02:00
AssociationId : a . NetworkAclAssociationId ,
NetworkAclId : defaultAcl . NetworkAclId ,
2015-05-12 20:24:32 +02:00
} )
2016-04-05 17:18:03 +02:00
if replaceErr != nil {
2016-05-02 16:45:11 +02:00
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
}
}
log . Printf ( "[ERR] Non retry-able error in replacing associations for Network ACL (%s): %s" , d . Id ( ) , replaceErr )
2016-04-05 17:18:03 +02:00
return resource . NonRetryableError ( replaceErr )
}
2015-05-12 20:24:32 +02:00
}
2016-04-05 17:18:03 +02:00
return resource . RetryableError ( fmt . Errorf ( "Dependencies found and cleaned up, retrying" ) )
2014-12-03 08:53:18 +01:00
default :
// Any other error, we want to quit the retry loop immediately
2016-03-09 23:53:32 +01:00
return resource . NonRetryableError ( err )
2014-12-03 08:34:28 +01:00
}
2014-11-26 14:44:02 +01:00
}
2014-12-03 08:53:18 +01:00
log . Printf ( "[Info] Deleted network ACL %s successfully" , d . Id ( ) )
2014-12-03 08:34:28 +01:00
return nil
} )
2016-04-05 17:18:03 +02:00
if retryErr != nil {
return fmt . Errorf ( "[ERR] Error destroying Network ACL (%s): %s" , d . Id ( ) , retryErr )
}
return nil
2014-11-26 14:44:02 +01:00
}
2014-11-30 12:40:54 +01:00
func resourceAwsNetworkAclEntryHash ( v interface { } ) int {
var buf bytes . Buffer
m := v . ( map [ string ] interface { } )
buf . WriteString ( fmt . Sprintf ( "%d-" , m [ "from_port" ] . ( int ) ) )
2014-12-17 12:37:42 +01:00
buf . WriteString ( fmt . Sprintf ( "%d-" , m [ "to_port" ] . ( int ) ) )
2014-11-30 12:40:54 +01:00
buf . WriteString ( fmt . Sprintf ( "%d-" , m [ "rule_no" ] . ( int ) ) )
buf . WriteString ( fmt . Sprintf ( "%s-" , m [ "action" ] . ( string ) ) )
2015-05-06 15:22:18 +02:00
// The AWS network ACL API only speaks protocol numbers, and that's
// all we store. Never hash a protocol name.
protocol := m [ "protocol" ] . ( string )
if _ , err := strconv . Atoi ( m [ "protocol" ] . ( string ) ) ; err != nil {
// We're a protocol name. Look up the number.
buf . WriteString ( fmt . Sprintf ( "%d-" , protocolIntegers ( ) [ protocol ] ) )
} else {
// We're a protocol number. Pass the value through.
buf . WriteString ( fmt . Sprintf ( "%s-" , protocol ) )
}
2017-03-14 11:39:39 +01:00
if v , ok := m [ "cidr_block" ] ; ok {
buf . WriteString ( fmt . Sprintf ( "%s-" , v . ( string ) ) )
}
if v , ok := m [ "ipv6_cidr_block" ] ; ok {
buf . WriteString ( fmt . Sprintf ( "%s-" , v . ( string ) ) )
}
2014-11-30 12:40:54 +01:00
if v , ok := m [ "ssl_certificate_id" ] ; ok {
buf . WriteString ( fmt . Sprintf ( "%s-" , v . ( string ) ) )
}
2015-05-29 23:48:50 +02:00
if v , ok := m [ "icmp_type" ] ; ok {
buf . WriteString ( fmt . Sprintf ( "%d-" , v . ( int ) ) )
}
if v , ok := m [ "icmp_code" ] ; ok {
buf . WriteString ( fmt . Sprintf ( "%d-" , v . ( int ) ) )
}
2014-11-30 12:40:54 +01:00
return hashcode . String ( buf . String ( ) )
}
2014-12-03 08:34:28 +01:00
2015-08-17 20:27:16 +02:00
func getDefaultNetworkAcl ( vpc_id string , conn * ec2 . EC2 ) ( defaultAcl * ec2 . NetworkAcl , err error ) {
resp , err := conn . DescribeNetworkAcls ( & ec2 . DescribeNetworkAclsInput {
2015-04-13 18:14:21 +02:00
Filters : [ ] * ec2 . Filter {
2017-03-14 11:39:39 +01:00
{
2015-03-11 21:01:07 +01:00
Name : aws . String ( "default" ) ,
2015-04-13 18:14:21 +02:00
Values : [ ] * string { aws . String ( "true" ) } ,
2015-03-11 21:01:07 +01:00
} ,
2017-03-14 11:39:39 +01:00
{
2015-03-11 21:01:07 +01:00
Name : aws . String ( "vpc-id" ) ,
2015-04-13 18:14:21 +02:00
Values : [ ] * string { aws . String ( vpc_id ) } ,
2015-03-11 21:01:07 +01:00
} ,
} ,
} )
2014-12-03 08:34:28 +01:00
if err != nil {
return nil , err
}
2015-08-17 20:27:16 +02:00
return resp . NetworkAcls [ 0 ] , nil
2014-12-03 08:53:18 +01:00
}
2014-12-03 08:34:28 +01:00
2015-08-17 20:27:16 +02:00
func findNetworkAclAssociation ( subnetId string , conn * ec2 . EC2 ) ( networkAclAssociation * ec2 . NetworkAclAssociation , err error ) {
resp , err := conn . DescribeNetworkAcls ( & ec2 . DescribeNetworkAclsInput {
2015-04-13 18:14:21 +02:00
Filters : [ ] * ec2 . Filter {
2017-03-14 11:39:39 +01:00
{
2015-03-11 21:01:07 +01:00
Name : aws . String ( "association.subnet-id" ) ,
2015-04-13 18:14:21 +02:00
Values : [ ] * string { aws . String ( subnetId ) } ,
2015-03-11 21:01:07 +01:00
} ,
} ,
} )
2014-12-03 08:34:28 +01:00
if err != nil {
return nil , err
}
2015-08-17 20:27:16 +02:00
if resp . NetworkAcls != nil && len ( resp . NetworkAcls ) > 0 {
for _ , association := range resp . NetworkAcls [ 0 ] . Associations {
if * association . SubnetId == subnetId {
2015-04-22 12:39:01 +02:00
return association , nil
}
2014-12-03 08:53:18 +01:00
}
}
2015-05-12 20:24:32 +02:00
return nil , fmt . Errorf ( "could not find association for subnet: %s " , subnetId )
2014-12-03 08:34:28 +01:00
}
2015-05-05 20:44:05 +02:00
// networkAclEntriesToMapList turns ingress/egress rules read from AWS into a list
// of maps.
2015-08-17 20:27:16 +02:00
func networkAclEntriesToMapList ( networkAcls [ ] * ec2 . NetworkAclEntry ) [ ] map [ string ] interface { } {
2015-05-05 20:44:05 +02:00
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
2017-03-14 11:39:39 +01:00
if entry . CidrBlock != nil {
acl [ "cidr_block" ] = * entry . CidrBlock
}
if entry . Ipv6CidrBlock != nil {
acl [ "ipv6_cidr_block" ] = * entry . Ipv6CidrBlock
}
2015-05-06 15:22:18 +02:00
// The AWS network ACL API only speaks protocol numbers, and
// that's all we record.
if _ , err := strconv . Atoi ( * entry . Protocol ) ; err != nil {
// We're a protocol name. Look up the number.
acl [ "protocol" ] = protocolIntegers ( ) [ * entry . Protocol ]
} else {
// We're a protocol number. Pass through.
acl [ "protocol" ] = * entry . Protocol
}
acl [ "protocol" ] = * entry . Protocol
2015-05-05 20:44:05 +02:00
if entry . PortRange != nil {
acl [ "from_port" ] = * entry . PortRange . From
acl [ "to_port" ] = * entry . PortRange . To
}
2015-08-17 20:27:16 +02:00
if entry . IcmpTypeCode != nil {
acl [ "icmp_type" ] = * entry . IcmpTypeCode . Type
acl [ "icmp_code" ] = * entry . IcmpTypeCode . Code
2015-05-29 23:48:50 +02:00
}
2015-05-05 20:44:05 +02:00
result = append ( result , acl )
}
return result
}