From cebea04ccedf8068c4c3b05307b4977c646adf5a Mon Sep 17 00:00:00 2001 From: Sneha Somwanshi Date: Wed, 26 Nov 2014 19:12:39 +0530 Subject: [PATCH 1/8] added provider for aws_network_acl --- builtin/providers/aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index d24f91611..60ae13189 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -48,6 +48,7 @@ func Provider() terraform.ResourceProvider { "aws_instance": resourceAwsInstance(), "aws_internet_gateway": resourceAwsInternetGateway(), "aws_launch_configuration": resourceAwsLaunchConfiguration(), + "aws_network_acl": resourceAwsNetworkAcl(), "aws_route53_record": resourceAwsRoute53Record(), "aws_route53_zone": resourceAwsRoute53Zone(), "aws_route_table": resourceAwsRouteTable(), From dca2d9aa4ce9cca4875f7a094ed4676b89789e0a Mon Sep 17 00:00:00 2001 From: Sneha Somwanshi Date: Wed, 26 Nov 2014 19:12:59 +0530 Subject: [PATCH 2/8] acceptance test for creating network acl --- .../aws/resource_aws_network_acl_test.go | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 builtin/providers/aws/resource_aws_network_acl_test.go diff --git a/builtin/providers/aws/resource_aws_network_acl_test.go b/builtin/providers/aws/resource_aws_network_acl_test.go new file mode 100644 index 000000000..f98e4b840 --- /dev/null +++ b/builtin/providers/aws/resource_aws_network_acl_test.go @@ -0,0 +1,115 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/terraform" + "github.com/mitchellh/goamz/ec2" + // "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/resource" + // "github.com/hashicorp/terraform/helper/schema" +) + +const testAccAWSNetworkAclConfig = ` +resource "aws_vpc" "foo" { + cidr_block = "10.2.0.0/16" +} + +resource "aws_network_acl" "bar" { + vpc_id = "${aws_vpc.foo.id}" +} +` + +// NetworkAclId string `xml:"networkAclId"` +// VpcId string `xml:"vpcId"` +// Default string `xml:"default"` +// EntrySet []NetworkAclEntry `xml:"entrySet>item"` +// AssociationSet []NetworkAclAssociation `xml:"AssociationSet>item"` +// Tags []Tag `xml:"tagSet>item"` + +// type NetworkAclEntry struct { +// RuleNumber int `xml:"ruleNumber"` +// Protocol string `xml:"protocol"` +// RuleAction string `xml:"ruleAction"` +// Egress bool `xml:"egress"` +// CidrBlock string `xml:"cidrBlock"` +// IcmpCode IcmpCode `xml:"icmpTypeCode"` +// PortRange PortRange `xml:"portRange"` +// } + +func TestAccAWSNetworkAclsSneha(t *testing.T) { + fmt.Printf("%s\n", "i am inside") + var networkAcl ec2.NetworkAcl + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSNetworkAclDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSNetworkAclConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNetworkAclExists("aws_network_acl.bar", &networkAcl), + ), + }, + }, + }) +} + +func testAccCheckAWSNetworkAclDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).ec2conn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_network" { + continue + } + + // Retrieve the network acl + resp, err := conn.NetworkAcls([]string{rs.Primary.ID}, ec2.NewFilter()) + if err == nil { + if len(resp.NetworkAcls) > 0 && resp.NetworkAcls[0].NetworkAclId == rs.Primary.ID { + return fmt.Errorf("Network Acl (%s) still exists.", rs.Primary.ID) + } + + return nil + } + + ec2err, ok := err.(*ec2.Error) + if !ok { + return err + } + // Confirm error code is what we want + if ec2err.Code != "InvalidNetworkAclID.NotFound" { + return err + } + } + + return nil +} + +func testAccCheckAWSNetworkAclExists(n string, networkAcl *ec2.NetworkAcl) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No Security Group is set") + } + conn := testAccProvider.Meta().(*AWSClient).ec2conn + + resp, err := conn.NetworkAcls([]string{rs.Primary.ID}, nil) + if err != nil { + return err + } + + if len(resp.NetworkAcls) > 0 && resp.NetworkAcls[0].NetworkAclId == rs.Primary.ID { + *networkAcl = resp.NetworkAcls[0] + return nil + } + + return fmt.Errorf("Network Acls not found") + } +} From bd9e9ec0c41ef24319960d45f07acd015514b669 Mon Sep 17 00:00:00 2001 From: Sneha Somwanshi Date: Wed, 26 Nov 2014 19:14:02 +0530 Subject: [PATCH 3/8] Add support for network acls --- .../providers/aws/resource_aws_network_acl.go | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 builtin/providers/aws/resource_aws_network_acl.go diff --git a/builtin/providers/aws/resource_aws_network_acl.go b/builtin/providers/aws/resource_aws_network_acl.go new file mode 100644 index 000000000..19025f9f4 --- /dev/null +++ b/builtin/providers/aws/resource_aws_network_acl.go @@ -0,0 +1,95 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/mitchellh/goamz/ec2" +) + +func resourceAwsNetworkAcl() *schema.Resource { + + return &schema.Resource{ + Create: resourceAwsNetworkAclCreate, + Read: resourceAwsNetworkAclRead, + Delete: resourceAwsNetworkAclDelete, + Update: resourceAwsNetworkAclUpdate, + + Schema: map[string]*schema.Schema{ + "vpc_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + }, + + }, + } +} + +func resourceAwsNetworkAclCreate(d *schema.ResourceData, meta interface{}) error { + ec2conn := meta.(*AWSClient).ec2conn + + // Create the Network Acl + createOpts := &ec2.CreateNetworkAcl{ + VpcId: d.Get("vpc_id").(string), + } + log.Printf("[DEBUG] Network Acl create config: %#v", createOpts) + resp, err := ec2conn.CreateNetworkAcl(createOpts) + if err != nil { + return fmt.Errorf("Error creating network acl: %s", err) + } + + // Get the ID and store it + networkAcl := &resp.NetworkAcl + d.SetId(networkAcl.NetworkAclId) + log.Printf("[INFO] Network Acl ID: %s", networkAcl.NetworkAclId) + + + // Update our attributes and return + return nil + // resource_aws_subnet_update_state(s, subnetRaw.(*ec2.Subnet)) +} + +func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error { + ec2conn := meta.(*AWSClient).ec2conn + + resp, err := ec2conn.NetworkAcls([]string{d.Id()}, ec2.NewFilter()) + + if err != nil { + return err + } + if resp == nil { + return nil + } + + networkAcl := &resp.NetworkAcls[0] + + d.Set("vpc_id", networkAcl.VpcId) + + return nil +} + + +func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error { + + return resourceAwsNetworkAclRead(d, meta) +} + +func resourceAwsNetworkAclDelete(d *schema.ResourceData, meta interface{}) error { + ec2conn := meta.(*AWSClient).ec2conn + + + log.Printf("[INFO] Deleting Network Acl: %s", d.Id()) + if _, err := ec2conn.DeleteNetworkAcl(d.Id()); err != nil { + ec2err, ok := err.(*ec2.Error) + if ok && ec2err.Code == "InvalidNetworkAclID.NotFound" { + return nil + } + + return fmt.Errorf("Error deleting network acl: %s", err) + } + + return nil +} From d4a887278ec6ab79975fbef6997305f5783ffac7 Mon Sep 17 00:00:00 2001 From: Sneha Somwanshi Date: Sun, 30 Nov 2014 17:08:45 +0530 Subject: [PATCH 4/8] flatten/expand operations for network_acl --- builtin/providers/aws/network_acl_entry.go | 71 +++++++++++ .../providers/aws/network_acl_entry_test.go | 120 ++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 builtin/providers/aws/network_acl_entry.go create mode 100644 builtin/providers/aws/network_acl_entry_test.go diff --git a/builtin/providers/aws/network_acl_entry.go b/builtin/providers/aws/network_acl_entry.go new file mode 100644 index 000000000..f692c3f6a --- /dev/null +++ b/builtin/providers/aws/network_acl_entry.go @@ -0,0 +1,71 @@ +package aws + +import ( + + "github.com/mitchellh/goamz/ec2" +) + +func expandNetworkAclEntries(configured []interface{}) ([]ec2.NetworkAclEntry) { + entries := make([]ec2.NetworkAclEntry, 0, len(configured)) + + for _, eRaw := range configured { + data := eRaw.(map[string]interface{}) + p := extractProtocolInteger(data["protocol"].(string)) + e := ec2.NetworkAclEntry{ + Protocol: p, + PortRange: ec2.PortRange{ + From: data["from_port"].(int), + To: data["to_port"].(int), + }, + Egress: false, + RuleAction: data["action"].(string), + RuleNumber: data["rule_no"].(int), + CidrBlock: data["cidr_block"].(string), + } + entries = append(entries, e) + } + + return entries + +} + +func flattenNetworkAclEntries(list []ec2.NetworkAclEntry) []map[string]interface{} { + entries := make([]map[string]interface{}, 0, len(list)) + + for _, entry := range list { + entries = append(entries, map[string]interface{}{ + "from_port": entry.PortRange.From, + "to_port": entry.PortRange.To, + "action": entry.RuleAction, + "rule_no": entry.RuleNumber, + "protocol": extractProtocolString(entry.Protocol), + "cidr_block": entry.CidrBlock, + }) + } + return entries + +} + +func extractProtocolInteger(protocol string) int { + return protocolIntegers()[protocol] +} + +func extractProtocolString(protocol int) string { + for key, value := range protocolIntegers() { + if value == protocol{ + return key + } + } + return "" +} + + +func protocolIntegers() map[string]int{ + var protocolIntegers = make(map[string]int) + protocolIntegers = map[string]int{ + "udp": 17, + "tcp": 6, + "icmp": 1, + } + return protocolIntegers +} diff --git a/builtin/providers/aws/network_acl_entry_test.go b/builtin/providers/aws/network_acl_entry_test.go new file mode 100644 index 000000000..c3f8405a4 --- /dev/null +++ b/builtin/providers/aws/network_acl_entry_test.go @@ -0,0 +1,120 @@ +package aws + +import ( + "reflect" + "testing" + + "github.com/mitchellh/goamz/ec2" +) + +func Test_expandNetworkAclEntryJoJo(t *testing.T) { + input := []interface{}{ + map[string]interface{}{ + "protocol": "tcp", + "from_port": 22, + "to_port": 22, + "cidr_block": "0.0.0.0/0", + "action": "deny", + "rule_no": 1, + }, + map[string]interface{}{ + "protocol": "tcp", + "from_port": 443, + "to_port": 443, + "cidr_block": "0.0.0.0/0", + "action": "deny", + "rule_no": 2, + }, + } + expanded := expandNetworkAclEntries(input) + + expected := []ec2.NetworkAclEntry{ + ec2.NetworkAclEntry{ + Protocol: 6, + PortRange: ec2.PortRange{ + From: 22, + To: 22, + }, + RuleAction: "deny", + RuleNumber: 1, + CidrBlock: "0.0.0.0/0", + Egress: false, + IcmpCode:ec2.IcmpCode{Code:0, Type:0}, + }, + ec2.NetworkAclEntry{ + Protocol: 6, + PortRange: ec2.PortRange{ + From: 443, + To: 443, + }, + RuleAction: "deny", + RuleNumber: 2, + CidrBlock: "0.0.0.0/0", + Egress: false, + IcmpCode: ec2.IcmpCode{Code:0, Type:0}, + }, + } + + if !reflect.DeepEqual(expanded, expected) { + t.Fatalf( + "Got:\n\n%#v\n\nExpected:\n\n%#v\n", + expanded[0], + expected) + } + +} + +func Test_flattenNetworkAclEntryJoJo(t *testing.T) { + + apiInput := []ec2.NetworkAclEntry{ + ec2.NetworkAclEntry{ + Protocol: 6, + PortRange: ec2.PortRange{ + From: 22, + To: 22, + }, + RuleAction: "deny", + RuleNumber: 1, + CidrBlock: "0.0.0.0/0", + }, + ec2.NetworkAclEntry{ + Protocol: 6, + PortRange: ec2.PortRange{ + From: 443, + To: 443, + }, + RuleAction: "deny", + RuleNumber: 2, + CidrBlock: "0.0.0.0/0", + }, + } + flattened := flattenNetworkAclEntries(apiInput) + + expected := []map[string]interface{}{ + map[string]interface{}{ + "protocol": "tcp", + "from_port": 22, + "to_port": 22, + "cidr_block": "0.0.0.0/0", + "action": "deny", + "rule_no": 1, + }, + map[string]interface{}{ + "protocol": "tcp", + "from_port": 443, + "to_port": 443, + "cidr_block": "0.0.0.0/0", + "action": "deny", + "rule_no": 2, + }, + } + + + if !reflect.DeepEqual(flattened, expected) { + t.Fatalf( + "Got:\n\n%#v\n\nExpected:\n\n%#v\n", + flattened, + expected) + } + +} From 5eec8a531c2d485bf95cb01228e73b19047a0176 Mon Sep 17 00:00:00 2001 From: Sneha Somwanshi Date: Sun, 30 Nov 2014 17:10:54 +0530 Subject: [PATCH 5/8] Added CRUD operations for network acl --- .../providers/aws/resource_aws_network_acl.go | 175 +++++++++++++++++- .../aws/resource_aws_network_acl_test.go | 105 ++++++++--- 2 files changed, 255 insertions(+), 25 deletions(-) diff --git a/builtin/providers/aws/resource_aws_network_acl.go b/builtin/providers/aws/resource_aws_network_acl.go index 19025f9f4..c3f38ba25 100644 --- a/builtin/providers/aws/resource_aws_network_acl.go +++ b/builtin/providers/aws/resource_aws_network_acl.go @@ -3,8 +3,10 @@ package aws import ( "fmt" "log" + "bytes" "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/hashcode" "github.com/mitchellh/goamz/ec2" ) @@ -23,12 +25,86 @@ func resourceAwsNetworkAcl() *schema.Resource { ForceNew: true, Computed: true, }, - + "subnet_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + }, + "ingress": &schema.Schema{ + Type: schema.TypeSet, + Required: false, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "from_port": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "to_port": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "rule_no": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "action": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "protocol": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "cidr_block": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + }, + }, + Set: resourceAwsNetworkAclEntryHash, + }, + "egress": &schema.Schema{ + Type: schema.TypeSet, + Required: false, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "from_port": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "to_port": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "rule_no": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "action": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "protocol": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "cidr_block": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + }, + }, + Set: resourceAwsNetworkAclEntryHash, + }, }, } } func resourceAwsNetworkAclCreate(d *schema.ResourceData, meta interface{}) error { + ec2conn := meta.(*AWSClient).ec2conn // Create the Network Acl @@ -46,10 +122,9 @@ func resourceAwsNetworkAclCreate(d *schema.ResourceData, meta interface{}) error d.SetId(networkAcl.NetworkAclId) log.Printf("[INFO] Network Acl ID: %s", networkAcl.NetworkAclId) - // Update our attributes and return - return nil - // resource_aws_subnet_update_state(s, subnetRaw.(*ec2.Subnet)) + // return nil + return resourceAwsNetworkAclUpdate(d, meta) } func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error { @@ -65,16 +140,91 @@ func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error { } networkAcl := &resp.NetworkAcls[0] + var ingressEntries []ec2.NetworkAclEntry + var egressEntries []ec2.NetworkAclEntry d.Set("vpc_id", networkAcl.VpcId) + for _, e := range networkAcl.EntrySet { + if(e.Egress == true){ + egressEntries = append(egressEntries, e) + } else{ + ingressEntries = append(ingressEntries, e) + } + } + fmt.Printf("appending ingress entries %s", ingressEntries) + + fmt.Printf("appending egress entries %s", egressEntries) + + d.Set("ingress", ingressEntries) + d.Set("egress", egressEntries) + return nil } func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error { + ec2conn := meta.(*AWSClient).ec2conn + + d.Partial(true) + + if(d.HasChange("ingress")) { + err := updateNetworkAclEntries(d, "ingress", ec2conn) + if(err != nil) { + return err + } + } + + if(d.HasChange("egress")) { + err := updateNetworkAclEntries(d, "egress", ec2conn) + if(err != nil){ + return err + } + } + + d.Partial(false) return resourceAwsNetworkAclRead(d, meta) + +} + +func updateNetworkAclEntries(d *schema.ResourceData, entryType string, ec2conn *ec2.EC2) error{ + + o, n := d.GetChange(entryType) + fmt.Printf("Old : %s", o) + fmt.Printf("Old : %s", n) + + if o == nil { + o = new(schema.Set) + } + if n == nil { + n = new(schema.Set) + } + + os := o.(*schema.Set) + ns := n.(*schema.Set) + + toBeDeleted := expandNetworkAclEntries(os.Difference(ns).List()) + toBeCreated := expandNetworkAclEntries(ns.Difference(os).List()) + fmt.Printf("to be created %s", toBeCreated) + for _, remove := range toBeDeleted { + // Revoke the old entry + _, err := ec2conn.DeleteNetworkAclEntry(d.Id(), remove.RuleNumber, remove.Egress) + if err != nil { + return fmt.Errorf("Error deleting %s entry: %s", entryType, err) + } + } + fmt.Printf("to be deleted %s", toBeDeleted) + + for _, add := range toBeCreated { + // Authorize the new entry + _, err := ec2conn.CreateNetworkAclEntry(d.Id(), &add) + fmt.Printf("$$$$#### %s", err) + if err != nil { + return fmt.Errorf("Error creating %s entry: %s", entryType, err) + } + } + return nil } func resourceAwsNetworkAclDelete(d *schema.ResourceData, meta interface{}) error { @@ -93,3 +243,20 @@ func resourceAwsNetworkAclDelete(d *schema.ResourceData, meta interface{}) error return nil } + +func resourceAwsNetworkAclEntryHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%d-", m["from_port"].(int))) + buf.WriteString(fmt.Sprintf("%s-", m["to_port"].(int))) + buf.WriteString(fmt.Sprintf("%d-", m["rule_no"].(int))) + buf.WriteString(fmt.Sprintf("%s-", m["action"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["cidr_block"].(string))) + + if v, ok := m["ssl_certificate_id"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + + return hashcode.String(buf.String()) +} diff --git a/builtin/providers/aws/resource_aws_network_acl_test.go b/builtin/providers/aws/resource_aws_network_acl_test.go index f98e4b840..26555aff1 100644 --- a/builtin/providers/aws/resource_aws_network_acl_test.go +++ b/builtin/providers/aws/resource_aws_network_acl_test.go @@ -11,35 +11,79 @@ import ( // "github.com/hashicorp/terraform/helper/schema" ) -const testAccAWSNetworkAclConfig = ` +const testAccAWSNetworkAclIngressConfig = ` resource "aws_vpc" "foo" { - cidr_block = "10.2.0.0/16" + cidr_block = "10.1.0.0/16" +} +resource "aws_subnet" "blob" { + cidr_block = "10.1.1.0/24" + vpc_id = "${aws_vpc.foo.id}" + map_public_ip_on_launch = true } - resource "aws_network_acl" "bar" { vpc_id = "${aws_vpc.foo.id}" + ingress = { + protocol = "tcp" + rule_no = 2 + action = "deny" + cidr_block = "10.2.2.3/18" + from_port = 0 + to_port = 22 + } + + ingress = { + protocol = "tcp" + rule_no = 1 + action = "deny" + cidr_block = "10.2.10.3/18" + from_port = 443 + to_port = 443 + } } ` -// NetworkAclId string `xml:"networkAclId"` -// VpcId string `xml:"vpcId"` -// Default string `xml:"default"` -// EntrySet []NetworkAclEntry `xml:"entrySet>item"` -// AssociationSet []NetworkAclAssociation `xml:"AssociationSet>item"` -// Tags []Tag `xml:"tagSet>item"` -// type NetworkAclEntry struct { -// RuleNumber int `xml:"ruleNumber"` -// Protocol string `xml:"protocol"` -// RuleAction string `xml:"ruleAction"` -// Egress bool `xml:"egress"` -// CidrBlock string `xml:"cidrBlock"` -// IcmpCode IcmpCode `xml:"icmpTypeCode"` -// PortRange PortRange `xml:"portRange"` -// } +const testAccAWSNetworkAclEgressConfig = ` +resource "aws_vpc" "foo" { + cidr_block = "10.2.0.0/16" +} +resource "aws_subnet" "blob" { + cidr_block = "10.2.0.0/24" + vpc_id = "${aws_vpc.foo.id}" + map_public_ip_on_launch = true +} +resource "aws_network_acl" "bar" { + vpc_id = "${aws_vpc.foo.id}" + egress = { + protocol = "tcp" + rule_no = 2 + action = "allow" + cidr_block = "10.2.2.3/18" + from_port = 443 + to_port = 443 + } -func TestAccAWSNetworkAclsSneha(t *testing.T) { - fmt.Printf("%s\n", "i am inside") + egress = { + protocol = "tcp" + rule_no = 1 + action = "allow" + cidr_block = "10.2.10.3/18" + from_port = 80 + to_port = 80 + } + + egress = { + protocol = "tcp" + rule_no = 3 + action = "allow" + cidr_block = "10.2.10.3/18" + from_port = 22 + to_port = 22 + } +} +` + +func TestAccAWSNetworkAclsIngressSneha(t *testing.T) { var networkAcl ec2.NetworkAcl resource.Test(t, resource.TestCase{ @@ -48,7 +92,26 @@ func TestAccAWSNetworkAclsSneha(t *testing.T) { CheckDestroy: testAccCheckAWSNetworkAclDestroy, Steps: []resource.TestStep{ resource.TestStep{ - Config: testAccAWSNetworkAclConfig, + Config: testAccAWSNetworkAclIngressConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNetworkAclExists("aws_network_acl.bar", &networkAcl), + ), + }, + }, + }) +} + + +func TestAccAWSNetworkAclsEgressSneha(t *testing.T) { + var networkAcl ec2.NetworkAcl + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSNetworkAclDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSNetworkAclEgressConfig, Check: resource.ComposeTestCheckFunc( testAccCheckAWSNetworkAclExists("aws_network_acl.bar", &networkAcl), ), From cd0f9761daabf4b1610c3884806ea37907e13bf3 Mon Sep 17 00:00:00 2001 From: Sneha Somwanshi Date: Mon, 1 Dec 2014 14:19:05 +0530 Subject: [PATCH 6/8] rearranged the tests --- builtin/providers/aws/network_acl_entry.go | 45 ++-- .../providers/aws/network_acl_entry_test.go | 97 ++++---- .../providers/aws/resource_aws_network_acl.go | 63 +++-- .../aws/resource_aws_network_acl_test.go | 222 ++++++++++++------ 4 files changed, 246 insertions(+), 181 deletions(-) diff --git a/builtin/providers/aws/network_acl_entry.go b/builtin/providers/aws/network_acl_entry.go index f692c3f6a..bf53e30b2 100644 --- a/builtin/providers/aws/network_acl_entry.go +++ b/builtin/providers/aws/network_acl_entry.go @@ -1,26 +1,24 @@ package aws import ( - "github.com/mitchellh/goamz/ec2" ) -func expandNetworkAclEntries(configured []interface{}) ([]ec2.NetworkAclEntry) { +func expandNetworkAclEntries(configured []interface{}, entryType string) []ec2.NetworkAclEntry { entries := make([]ec2.NetworkAclEntry, 0, len(configured)) - for _, eRaw := range configured { data := eRaw.(map[string]interface{}) p := extractProtocolInteger(data["protocol"].(string)) e := ec2.NetworkAclEntry{ - Protocol: p, + Protocol: p, PortRange: ec2.PortRange{ - From: data["from_port"].(int), - To: data["to_port"].(int), + From: data["from_port"].(int), + To: data["to_port"].(int), }, - Egress: false, + Egress: (entryType == "egress"), RuleAction: data["action"].(string), RuleNumber: data["rule_no"].(int), - CidrBlock: data["cidr_block"].(string), + CidrBlock: data["cidr_block"].(string), } entries = append(entries, e) } @@ -32,16 +30,16 @@ func expandNetworkAclEntries(configured []interface{}) ([]ec2.NetworkAclEntry) { func flattenNetworkAclEntries(list []ec2.NetworkAclEntry) []map[string]interface{} { entries := make([]map[string]interface{}, 0, len(list)) - for _, entry := range list { + for _, entry := range list { entries = append(entries, map[string]interface{}{ - "from_port": entry.PortRange.From, - "to_port": entry.PortRange.To, - "action": entry.RuleAction, - "rule_no": entry.RuleNumber, - "protocol": extractProtocolString(entry.Protocol), - "cidr_block": entry.CidrBlock, - }) - } + "from_port": entry.PortRange.From, + "to_port": entry.PortRange.To, + "action": entry.RuleAction, + "rule_no": entry.RuleNumber, + "protocol": extractProtocolString(entry.Protocol), + "cidr_block": entry.CidrBlock, + }) + } return entries } @@ -52,20 +50,19 @@ func extractProtocolInteger(protocol string) int { func extractProtocolString(protocol int) string { for key, value := range protocolIntegers() { - if value == protocol{ + if value == protocol { return key } } return "" } - -func protocolIntegers() map[string]int{ - var protocolIntegers = make(map[string]int) +func protocolIntegers() map[string]int { + var protocolIntegers = make(map[string]int) protocolIntegers = map[string]int{ - "udp": 17, - "tcp": 6, - "icmp": 1, + "udp": 17, + "tcp": 6, + "icmp": 1, } return protocolIntegers } diff --git a/builtin/providers/aws/network_acl_entry_test.go b/builtin/providers/aws/network_acl_entry_test.go index c3f8405a4..5c58c9c7d 100644 --- a/builtin/providers/aws/network_acl_entry_test.go +++ b/builtin/providers/aws/network_acl_entry_test.go @@ -10,110 +10,109 @@ import ( func Test_expandNetworkAclEntryJoJo(t *testing.T) { input := []interface{}{ map[string]interface{}{ - "protocol": "tcp", - "from_port": 22, - "to_port": 22, + "protocol": "tcp", + "from_port": 22, + "to_port": 22, "cidr_block": "0.0.0.0/0", - "action": "deny", - "rule_no": 1, + "action": "deny", + "rule_no": 1, }, map[string]interface{}{ - "protocol": "tcp", - "from_port": 443, - "to_port": 443, + "protocol": "tcp", + "from_port": 443, + "to_port": 443, "cidr_block": "0.0.0.0/0", - "action": "deny", - "rule_no": 2, + "action": "deny", + "rule_no": 2, }, } - expanded := expandNetworkAclEntries(input) + expanded := expandNetworkAclEntries(input, "egress") expected := []ec2.NetworkAclEntry{ ec2.NetworkAclEntry{ - Protocol: 6, + Protocol: 6, PortRange: ec2.PortRange{ - From: 22, - To: 22, + From: 22, + To: 22, }, RuleAction: "deny", RuleNumber: 1, - CidrBlock: "0.0.0.0/0", - Egress: false, - IcmpCode:ec2.IcmpCode{Code:0, Type:0}, + CidrBlock: "0.0.0.0/0", + Egress: true, + IcmpCode: ec2.IcmpCode{Code: 0, Type: 0}, }, ec2.NetworkAclEntry{ - Protocol: 6, + Protocol: 6, PortRange: ec2.PortRange{ - From: 443, - To: 443, - }, + From: 443, + To: 443, + }, RuleAction: "deny", RuleNumber: 2, - CidrBlock: "0.0.0.0/0", - Egress: false, - IcmpCode: ec2.IcmpCode{Code:0, Type:0}, + CidrBlock: "0.0.0.0/0", + Egress: true, + IcmpCode: ec2.IcmpCode{Code: 0, Type: 0}, }, - } + } if !reflect.DeepEqual(expanded, expected) { t.Fatalf( "Got:\n\n%#v\n\nExpected:\n\n%#v\n", - expanded[0], + expanded, expected) } } func Test_flattenNetworkAclEntryJoJo(t *testing.T) { - + apiInput := []ec2.NetworkAclEntry{ ec2.NetworkAclEntry{ - Protocol: 6, + Protocol: 6, PortRange: ec2.PortRange{ - From: 22, - To: 22, + From: 22, + To: 22, }, RuleAction: "deny", RuleNumber: 1, - CidrBlock: "0.0.0.0/0", + CidrBlock: "0.0.0.0/0", }, ec2.NetworkAclEntry{ - Protocol: 6, + Protocol: 6, PortRange: ec2.PortRange{ - From: 443, - To: 443, - }, + From: 443, + To: 443, + }, RuleAction: "deny", RuleNumber: 2, - CidrBlock: "0.0.0.0/0", + CidrBlock: "0.0.0.0/0", }, } flattened := flattenNetworkAclEntries(apiInput) expected := []map[string]interface{}{ - map[string]interface{}{ - "protocol": "tcp", - "from_port": 22, - "to_port": 22, + map[string]interface{}{ + "protocol": "tcp", + "from_port": 22, + "to_port": 22, "cidr_block": "0.0.0.0/0", - "action": "deny", - "rule_no": 1, + "action": "deny", + "rule_no": 1, }, map[string]interface{}{ - "protocol": "tcp", - "from_port": 443, - "to_port": 443, + "protocol": "tcp", + "from_port": 443, + "to_port": 443, "cidr_block": "0.0.0.0/0", - "action": "deny", - "rule_no": 2, + "action": "deny", + "rule_no": 2, }, } - if !reflect.DeepEqual(flattened, expected) { t.Fatalf( "Got:\n\n%#v\n\nExpected:\n\n%#v\n", - flattened, + flattened[0], expected) } diff --git a/builtin/providers/aws/resource_aws_network_acl.go b/builtin/providers/aws/resource_aws_network_acl.go index c3f38ba25..82396636b 100644 --- a/builtin/providers/aws/resource_aws_network_acl.go +++ b/builtin/providers/aws/resource_aws_network_acl.go @@ -1,22 +1,22 @@ package aws import ( + "bytes" "fmt" "log" - "bytes" - "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/schema" "github.com/mitchellh/goamz/ec2" ) func resourceAwsNetworkAcl() *schema.Resource { return &schema.Resource{ - Create: resourceAwsNetworkAclCreate, - Read: resourceAwsNetworkAclRead, - Delete: resourceAwsNetworkAclDelete, - Update: resourceAwsNetworkAclUpdate, + Create: resourceAwsNetworkAclCreate, + Read: resourceAwsNetworkAclRead, + Delete: resourceAwsNetworkAclDelete, + Update: resourceAwsNetworkAclUpdate, Schema: map[string]*schema.Schema{ "vpc_id": &schema.Schema{ @@ -98,13 +98,13 @@ func resourceAwsNetworkAcl() *schema.Resource { }, }, Set: resourceAwsNetworkAclEntryHash, - }, + }, }, } } func resourceAwsNetworkAclCreate(d *schema.ResourceData, meta interface{}) error { - + ec2conn := meta.(*AWSClient).ec2conn // Create the Network Acl @@ -123,7 +123,7 @@ func resourceAwsNetworkAclCreate(d *schema.ResourceData, meta interface{}) error log.Printf("[INFO] Network Acl ID: %s", networkAcl.NetworkAclId) // Update our attributes and return - // return nil + // return nil return resourceAwsNetworkAclUpdate(d, meta) } @@ -146,14 +146,13 @@ func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error { d.Set("vpc_id", networkAcl.VpcId) for _, e := range networkAcl.EntrySet { - if(e.Egress == true){ + if e.Egress == true { egressEntries = append(egressEntries, e) - } else{ + } else { ingressEntries = append(ingressEntries, e) } } fmt.Printf("appending ingress entries %s", ingressEntries) - fmt.Printf("appending egress entries %s", egressEntries) d.Set("ingress", ingressEntries) @@ -162,33 +161,30 @@ func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error { return nil } - func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error { ec2conn := meta.(*AWSClient).ec2conn - d.Partial(true) - if(d.HasChange("ingress")) { + if d.HasChange("ingress") { err := updateNetworkAclEntries(d, "ingress", ec2conn) - if(err != nil) { + if err != nil { return err } } - if(d.HasChange("egress")) { + if d.HasChange("egress") { err := updateNetworkAclEntries(d, "egress", ec2conn) - if(err != nil){ + if err != nil { return err } } d.Partial(false) - return resourceAwsNetworkAclRead(d, meta) } -func updateNetworkAclEntries(d *schema.ResourceData, entryType string, ec2conn *ec2.EC2) error{ +func updateNetworkAclEntries(d *schema.ResourceData, entryType string, ec2conn *ec2.EC2) error { o, n := d.GetChange(entryType) fmt.Printf("Old : %s", o) @@ -204,25 +200,25 @@ func updateNetworkAclEntries(d *schema.ResourceData, entryType string, ec2conn * os := o.(*schema.Set) ns := n.(*schema.Set) - toBeDeleted := expandNetworkAclEntries(os.Difference(ns).List()) - toBeCreated := expandNetworkAclEntries(ns.Difference(os).List()) + toBeDeleted := expandNetworkAclEntries(os.Difference(ns).List(), entryType) + toBeCreated := expandNetworkAclEntries(ns.Difference(os).List(), entryType) fmt.Printf("to be created %s", toBeCreated) for _, remove := range toBeDeleted { - // Revoke the old entry - _, err := ec2conn.DeleteNetworkAclEntry(d.Id(), remove.RuleNumber, remove.Egress) - if err != nil { - return fmt.Errorf("Error deleting %s entry: %s", entryType, err) - } + // Revoke the old entry + _, err := ec2conn.DeleteNetworkAclEntry(d.Id(), remove.RuleNumber, remove.Egress) + if err != nil { + return fmt.Errorf("Error deleting %s entry: %s", entryType, err) + } } fmt.Printf("to be deleted %s", toBeDeleted) for _, add := range toBeCreated { - // Authorize the new entry - _, err := ec2conn.CreateNetworkAclEntry(d.Id(), &add) - fmt.Printf("$$$$#### %s", err) - if err != nil { - return fmt.Errorf("Error creating %s entry: %s", entryType, err) - } + // Authorize the new entry + _, err := ec2conn.CreateNetworkAclEntry(d.Id(), &add) + fmt.Printf("$$$$#### %s", err) + if err != nil { + return fmt.Errorf("Error creating %s entry: %s", entryType, err) + } } return nil } @@ -230,7 +226,6 @@ func updateNetworkAclEntries(d *schema.ResourceData, entryType string, ec2conn * func resourceAwsNetworkAclDelete(d *schema.ResourceData, meta interface{}) error { ec2conn := meta.(*AWSClient).ec2conn - log.Printf("[INFO] Deleting Network Acl: %s", d.Id()) if _, err := ec2conn.DeleteNetworkAcl(d.Id()); err != nil { ec2err, ok := err.(*ec2.Error) diff --git a/builtin/providers/aws/resource_aws_network_acl_test.go b/builtin/providers/aws/resource_aws_network_acl_test.go index 26555aff1..b838f1781 100644 --- a/builtin/providers/aws/resource_aws_network_acl_test.go +++ b/builtin/providers/aws/resource_aws_network_acl_test.go @@ -11,79 +11,49 @@ import ( // "github.com/hashicorp/terraform/helper/schema" ) -const testAccAWSNetworkAclIngressConfig = ` -resource "aws_vpc" "foo" { - cidr_block = "10.1.0.0/16" -} -resource "aws_subnet" "blob" { - cidr_block = "10.1.1.0/24" - vpc_id = "${aws_vpc.foo.id}" - map_public_ip_on_launch = true -} -resource "aws_network_acl" "bar" { - vpc_id = "${aws_vpc.foo.id}" - ingress = { - protocol = "tcp" - rule_no = 2 - action = "deny" - cidr_block = "10.2.2.3/18" - from_port = 0 - to_port = 22 - } +func TestAccAWSNetworkAclsWithEgressAndIngressRulesSneha(t *testing.T) { + var networkAcl ec2.NetworkAcl - ingress = { - protocol = "tcp" - rule_no = 1 - action = "deny" - cidr_block = "10.2.10.3/18" - from_port = 443 - to_port = 443 - } + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSNetworkAclDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSNetworkAclEgressNIngressConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNetworkAclExists("aws_network_acl.bar", &networkAcl), + resource.TestCheckResourceAttr( + "aws_network_acl.bar", "ingress.0.protocol", "tcp"), + resource.TestCheckResourceAttr( + "aws_network_acl.bar", "ingress.0.rule_no", "1"), + resource.TestCheckResourceAttr( + "aws_network_acl.bar", "ingress.0.from_port", "80"), + resource.TestCheckResourceAttr( + "aws_network_acl.bar", "ingress.0.to_port", "80"), + resource.TestCheckResourceAttr( + "aws_network_acl.bar", "ingress.0.action", "allow"), + resource.TestCheckResourceAttr( + "aws_network_acl.bar", "ingress.0.cidr_block", "10.3.10.3/18"), + resource.TestCheckResourceAttr( + "aws_network_acl.bar", "egress.0.protocol", "tcp"), + resource.TestCheckResourceAttr( + "aws_network_acl.bar", "egress.0.rule_no", "2"), + resource.TestCheckResourceAttr( + "aws_network_acl.bar", "egress.0.from_port", "443"), + resource.TestCheckResourceAttr( + "aws_network_acl.bar", "egress.0.to_port", "443"), + resource.TestCheckResourceAttr( + "aws_network_acl.bar", "egress.0.cidr_block", "10.3.2.3/18"), + resource.TestCheckResourceAttr( + "aws_network_acl.bar", "egress.0.action", "allow"), + ), + }, + }, + }) } -` - -const testAccAWSNetworkAclEgressConfig = ` -resource "aws_vpc" "foo" { - cidr_block = "10.2.0.0/16" -} -resource "aws_subnet" "blob" { - cidr_block = "10.2.0.0/24" - vpc_id = "${aws_vpc.foo.id}" - map_public_ip_on_launch = true -} -resource "aws_network_acl" "bar" { - vpc_id = "${aws_vpc.foo.id}" - egress = { - protocol = "tcp" - rule_no = 2 - action = "allow" - cidr_block = "10.2.2.3/18" - from_port = 443 - to_port = 443 - } - - egress = { - protocol = "tcp" - rule_no = 1 - action = "allow" - cidr_block = "10.2.10.3/18" - from_port = 80 - to_port = 80 - } - - egress = { - protocol = "tcp" - rule_no = 3 - action = "allow" - cidr_block = "10.2.10.3/18" - from_port = 22 - to_port = 22 - } -} -` - -func TestAccAWSNetworkAclsIngressSneha(t *testing.T) { +func TestAccAWSNetworkAclsOnlyIngressRulesSneha(t *testing.T) { var networkAcl ec2.NetworkAcl resource.Test(t, resource.TestCase{ @@ -94,15 +64,26 @@ func TestAccAWSNetworkAclsIngressSneha(t *testing.T) { resource.TestStep{ Config: testAccAWSNetworkAclIngressConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckAWSNetworkAclExists("aws_network_acl.bar", &networkAcl), + testAccCheckAWSNetworkAclExists("aws_network_acl.foos", &networkAcl), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.protocol", "tcp"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.rule_no", "2"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.from_port", "0"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.to_port", "22"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.action", "deny"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.cidr_block", "10.2.2.3/18"), ), }, }, }) } - -func TestAccAWSNetworkAclsEgressSneha(t *testing.T) { +func TestAccAWSNetworkAclsOnlyEgressRulesSneha(t *testing.T) { var networkAcl ec2.NetworkAcl resource.Test(t, resource.TestCase{ @@ -113,7 +94,7 @@ func TestAccAWSNetworkAclsEgressSneha(t *testing.T) { resource.TestStep{ Config: testAccAWSNetworkAclEgressConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckAWSNetworkAclExists("aws_network_acl.bar", &networkAcl), + testAccCheckAWSNetworkAclExists("aws_network_acl.bond", &networkAcl), ), }, }, @@ -176,3 +157,96 @@ func testAccCheckAWSNetworkAclExists(n string, networkAcl *ec2.NetworkAcl) resou return fmt.Errorf("Network Acls not found") } } + +const testAccAWSNetworkAclIngressConfig = ` +resource "aws_vpc" "foo" { + cidr_block = "10.1.0.0/16" +} +resource "aws_subnet" "blob" { + cidr_block = "10.1.1.0/24" + vpc_id = "${aws_vpc.foo.id}" + map_public_ip_on_launch = true +} +resource "aws_network_acl" "foos" { + vpc_id = "${aws_vpc.foo.id}" + ingress = { + protocol = "tcp" + rule_no = 2 + action = "deny" + cidr_block = "10.2.2.3/18" + from_port = 0 + to_port = 22 + } +} +` + +const testAccAWSNetworkAclEgressConfig = ` +resource "aws_vpc" "foo" { + cidr_block = "10.2.0.0/16" +} +resource "aws_subnet" "blob" { + cidr_block = "10.2.0.0/24" + vpc_id = "${aws_vpc.foo.id}" + map_public_ip_on_launch = true +} +resource "aws_network_acl" "bond" { + vpc_id = "${aws_vpc.foo.id}" + egress = { + protocol = "tcp" + rule_no = 2 + action = "allow" + cidr_block = "10.2.2.3/18" + from_port = 443 + to_port = 443 + } + + egress = { + protocol = "tcp" + rule_no = 1 + action = "allow" + cidr_block = "10.2.10.3/18" + from_port = 80 + to_port = 80 + } + + egress = { + protocol = "tcp" + rule_no = 3 + action = "allow" + cidr_block = "10.2.10.3/18" + from_port = 22 + to_port = 22 + } +} +` + +const testAccAWSNetworkAclEgressNIngressConfig = ` +resource "aws_vpc" "foo" { + cidr_block = "10.3.0.0/16" +} +resource "aws_subnet" "blob" { + cidr_block = "10.3.0.0/24" + vpc_id = "${aws_vpc.foo.id}" + map_public_ip_on_launch = true +} +resource "aws_network_acl" "bar" { + vpc_id = "${aws_vpc.foo.id}" + egress = { + protocol = "tcp" + rule_no = 2 + action = "allow" + cidr_block = "10.3.2.3/18" + from_port = 443 + to_port = 443 + } + + ingress = { + protocol = "tcp" + rule_no = 1 + action = "allow" + cidr_block = "10.3.10.3/18" + from_port = 80 + to_port = 80 + } +} +` From c79e6ba08b7762444e9fd3835c79bf75217f6989 Mon Sep 17 00:00:00 2001 From: Sneha Somwanshi Date: Wed, 3 Dec 2014 13:04:28 +0530 Subject: [PATCH 7/8] handled subnet and network acl association --- .../providers/aws/network_acl_entry_test.go | 4 +- .../providers/aws/resource_aws_network_acl.go | 93 +++++++++++++++---- .../aws/resource_aws_network_acl_test.go | 29 +++++- 3 files changed, 102 insertions(+), 24 deletions(-) diff --git a/builtin/providers/aws/network_acl_entry_test.go b/builtin/providers/aws/network_acl_entry_test.go index 5c58c9c7d..0cf412dfd 100644 --- a/builtin/providers/aws/network_acl_entry_test.go +++ b/builtin/providers/aws/network_acl_entry_test.go @@ -7,7 +7,7 @@ import ( "github.com/mitchellh/goamz/ec2" ) -func Test_expandNetworkAclEntryJoJo(t *testing.T) { +func Test_expandNetworkAclEntry(t *testing.T) { input := []interface{}{ map[string]interface{}{ "protocol": "tcp", @@ -64,7 +64,7 @@ func Test_expandNetworkAclEntryJoJo(t *testing.T) { } -func Test_flattenNetworkAclEntryJoJo(t *testing.T) { +func Test_flattenNetworkAclEntry(t *testing.T) { apiInput := []ec2.NetworkAclEntry{ ec2.NetworkAclEntry{ diff --git a/builtin/providers/aws/resource_aws_network_acl.go b/builtin/providers/aws/resource_aws_network_acl.go index 82396636b..eb39e2450 100644 --- a/builtin/providers/aws/resource_aws_network_acl.go +++ b/builtin/providers/aws/resource_aws_network_acl.go @@ -4,8 +4,10 @@ import ( "bytes" "fmt" "log" + "time" "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "github.com/mitchellh/goamz/ec2" ) @@ -111,6 +113,7 @@ func resourceAwsNetworkAclCreate(d *schema.ResourceData, meta interface{}) error createOpts := &ec2.CreateNetworkAcl{ VpcId: d.Get("vpc_id").(string), } + log.Printf("[DEBUG] Network Acl create config: %#v", createOpts) resp, err := ec2conn.CreateNetworkAcl(createOpts) if err != nil { @@ -122,8 +125,7 @@ func resourceAwsNetworkAclCreate(d *schema.ResourceData, meta interface{}) error d.SetId(networkAcl.NetworkAclId) log.Printf("[INFO] Network Acl ID: %s", networkAcl.NetworkAclId) - // Update our attributes and return - // return nil + // Update rules and subnet association once acl is created return resourceAwsNetworkAclUpdate(d, meta) } @@ -143,8 +145,7 @@ func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error { var ingressEntries []ec2.NetworkAclEntry var egressEntries []ec2.NetworkAclEntry - d.Set("vpc_id", networkAcl.VpcId) - + // separate the ingress and egress rules for _, e := range networkAcl.EntrySet { if e.Egress == true { egressEntries = append(egressEntries, e) @@ -152,9 +153,8 @@ func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error { ingressEntries = append(ingressEntries, e) } } - fmt.Printf("appending ingress entries %s", ingressEntries) - fmt.Printf("appending egress entries %s", egressEntries) + d.Set("vpc_id", networkAcl.VpcId) d.Set("ingress", ingressEntries) d.Set("egress", egressEntries) @@ -179,16 +179,28 @@ func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error } } + if(d.HasChange("subnet_id")) { + association, err := findNetworkAclAssociation(d.Get("subnet_id").(string), ec2conn) + if(err != nil){ + return fmt.Errorf("Depedency voilation: Could find association: %s", d.Id(), err) + } + // change acl and subnet association if subnet_id has changed + _, err = ec2conn.ReplaceNetworkAclAssociation(association.NetworkAclAssociationId, d.Id()) + if err != nil { + return err + } + + } + d.Partial(false) return resourceAwsNetworkAclRead(d, meta) - } func updateNetworkAclEntries(d *schema.ResourceData, entryType string, ec2conn *ec2.EC2) error { o, n := d.GetChange(entryType) fmt.Printf("Old : %s", o) - fmt.Printf("Old : %s", n) + fmt.Printf("New : %s", n) if o == nil { o = new(schema.Set) @@ -204,7 +216,7 @@ func updateNetworkAclEntries(d *schema.ResourceData, entryType string, ec2conn * toBeCreated := expandNetworkAclEntries(ns.Difference(os).List(), entryType) fmt.Printf("to be created %s", toBeCreated) for _, remove := range toBeDeleted { - // Revoke the old entry + // Delete old Acl _, err := ec2conn.DeleteNetworkAclEntry(d.Id(), remove.RuleNumber, remove.Egress) if err != nil { return fmt.Errorf("Error deleting %s entry: %s", entryType, err) @@ -213,7 +225,7 @@ func updateNetworkAclEntries(d *schema.ResourceData, entryType string, ec2conn * fmt.Printf("to be deleted %s", toBeDeleted) for _, add := range toBeCreated { - // Authorize the new entry + // Add new Acl entry _, err := ec2conn.CreateNetworkAclEntry(d.Id(), &add) fmt.Printf("$$$$#### %s", err) if err != nil { @@ -227,16 +239,33 @@ func resourceAwsNetworkAclDelete(d *schema.ResourceData, meta interface{}) error ec2conn := meta.(*AWSClient).ec2conn log.Printf("[INFO] Deleting Network Acl: %s", d.Id()) - if _, err := ec2conn.DeleteNetworkAcl(d.Id()); err != nil { - ec2err, ok := err.(*ec2.Error) - if ok && ec2err.Code == "InvalidNetworkAclID.NotFound" { - return nil + return resource.Retry(5*time.Minute, func() error { + if _, err := ec2conn.DeleteNetworkAcl(d.Id()); err != nil { + ec2err := err.(*ec2.Error) + fmt.Printf("\n\n error code: %s \n", ec2err.Code) + switch ec2err.Code { + 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. + association, err := findNetworkAclAssociation(d.Get("subnet_id").(string), ec2conn) + if(err != nil){ + return fmt.Errorf("Depedency voilation: Could find association: %s", d.Id(), err) + } + defaultAcl, err := getDefaultNetworkAcl(d.Get("vpc_id").(string), ec2conn) + if(err != nil){ + return fmt.Errorf("Depedency voilation: Could not dissociate subnet from %s acl: %s", d.Id(), err) + } + _, err = ec2conn.ReplaceNetworkAclAssociation(association.NetworkAclAssociationId, defaultAcl.NetworkAclId) + return err + default: + // Any other error, we want to quit the retry loop immediately + return resource.RetryError{err} + } } - - return fmt.Errorf("Error deleting network acl: %s", err) - } - - return nil + return nil + }) } func resourceAwsNetworkAclEntryHash(v interface{}) int { @@ -255,3 +284,29 @@ func resourceAwsNetworkAclEntryHash(v interface{}) int { return hashcode.String(buf.String()) } + + +func getDefaultNetworkAcl(vpc_id string, ec2conn *ec2.EC2)(defaultAcl *ec2.NetworkAcl, err error){ + filter := ec2.NewFilter() + filter.Add("default", "true" ) + filter.Add("vpc-id", vpc_id ) + + resp, err := ec2conn.NetworkAcls([]string{}, filter) + + if err != nil { + return nil, err + } + return &resp.NetworkAcls[0], nil + } + +func findNetworkAclAssociation(subnet_id string,ec2conn *ec2.EC2)(networkAclAssociation *ec2.NetworkAclAssociation, err error){ + filter := ec2.NewFilter() + filter.Add("association.subnet-id", subnet_id ) + + resp, err := ec2conn.NetworkAcls([]string{}, filter) + + if err != nil { + return nil, err + } + return &resp.NetworkAcls[0].AssociationSet[0], nil +} diff --git a/builtin/providers/aws/resource_aws_network_acl_test.go b/builtin/providers/aws/resource_aws_network_acl_test.go index b838f1781..8e578fa09 100644 --- a/builtin/providers/aws/resource_aws_network_acl_test.go +++ b/builtin/providers/aws/resource_aws_network_acl_test.go @@ -11,7 +11,7 @@ import ( // "github.com/hashicorp/terraform/helper/schema" ) -func TestAccAWSNetworkAclsWithEgressAndIngressRulesSneha(t *testing.T) { +func TestAccAWSNetworkAclsWithEgressAndIngressRules(t *testing.T) { var networkAcl ec2.NetworkAcl resource.Test(t, resource.TestCase{ @@ -53,8 +53,9 @@ func TestAccAWSNetworkAclsWithEgressAndIngressRulesSneha(t *testing.T) { }) } -func TestAccAWSNetworkAclsOnlyIngressRulesSneha(t *testing.T) { +func TestAccAWSNetworkAclsOnlyIngressRules(t *testing.T) { var networkAcl ec2.NetworkAcl + // var subnet ec2.Subnet resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -65,6 +66,7 @@ func TestAccAWSNetworkAclsOnlyIngressRulesSneha(t *testing.T) { Config: testAccAWSNetworkAclIngressConfig, Check: resource.ComposeTestCheckFunc( testAccCheckAWSNetworkAclExists("aws_network_acl.foos", &networkAcl), + testAccCheckSubnetAssociation("aws_network_acl.foos", "aws_subnet.blob"), resource.TestCheckResourceAttr( "aws_network_acl.foos", "ingress.0.protocol", "tcp"), resource.TestCheckResourceAttr( @@ -83,7 +85,7 @@ func TestAccAWSNetworkAclsOnlyIngressRulesSneha(t *testing.T) { }) } -func TestAccAWSNetworkAclsOnlyEgressRulesSneha(t *testing.T) { +func TestAccAWSNetworkAclsOnlyEgressRules(t *testing.T) { var networkAcl ec2.NetworkAcl resource.Test(t, resource.TestCase{ @@ -158,6 +160,26 @@ func testAccCheckAWSNetworkAclExists(n string, networkAcl *ec2.NetworkAcl) resou } } +func testAccCheckSubnetAssociation(acl string, subnet string) resource.TestCheckFunc { + return func(s *terraform.State) error { + networkAcl := s.RootModule().Resources[acl] + subnet := s.RootModule().Resources[subnet] + + conn := testAccProvider.Meta().(*AWSClient).ec2conn + filter := ec2.NewFilter() + filter.Add("association.subnet-id", subnet.Primary.ID) + resp, err := conn.NetworkAcls([]string{networkAcl.Primary.ID}, filter) + + if err != nil { + return err + } + if len(resp.NetworkAcls) > 0 && resp.NetworkAcls[0].NetworkAclId == networkAcl.Primary.ID { + return nil + } + return fmt.Errorf("Network Acl %s is not associated with subnet %s", acl, subnet) + } +} + const testAccAWSNetworkAclIngressConfig = ` resource "aws_vpc" "foo" { cidr_block = "10.1.0.0/16" @@ -177,6 +199,7 @@ resource "aws_network_acl" "foos" { from_port = 0 to_port = 22 } + subnet_id = "${aws_subnet.blob.id}" } ` From 4b154b8fe76f2fe7149c8d4cd2a8af8e3f2cf194 Mon Sep 17 00:00:00 2001 From: Sneha Somwanshi Date: Wed, 3 Dec 2014 13:23:18 +0530 Subject: [PATCH 8/8] Fixed update of ingress/egress rules --- .../providers/aws/resource_aws_network_acl.go | 86 +++--- .../aws/resource_aws_network_acl_test.go | 257 +++++++++++++++--- 2 files changed, 269 insertions(+), 74 deletions(-) diff --git a/builtin/providers/aws/resource_aws_network_acl.go b/builtin/providers/aws/resource_aws_network_acl.go index eb39e2450..c26bf5f19 100644 --- a/builtin/providers/aws/resource_aws_network_acl.go +++ b/builtin/providers/aws/resource_aws_network_acl.go @@ -23,15 +23,15 @@ func resourceAwsNetworkAcl() *schema.Resource { Schema: map[string]*schema.Schema{ "vpc_id": &schema.Schema{ Type: schema.TypeString, - Optional: true, + Required: true, ForceNew: true, - Computed: true, + Computed: false, }, "subnet_id": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, - Computed: true, + Computed: false, }, "ingress": &schema.Schema{ Type: schema.TypeSet, @@ -179,17 +179,19 @@ func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error } } - if(d.HasChange("subnet_id")) { - association, err := findNetworkAclAssociation(d.Get("subnet_id").(string), ec2conn) - if(err != nil){ - return fmt.Errorf("Depedency voilation: Could find association: %s", d.Id(), err) + if d.HasChange("subnet_id") { + + //associate new subnet with the acl. + _, n := d.GetChange("subnet_id") + newSubnet := n.(string) + association, err := findNetworkAclAssociation(newSubnet, ec2conn) + if err != nil { + return fmt.Errorf("Failed to update acl %s with subnet %s: ", d.Id(), newSubnet, err) } - // change acl and subnet association if subnet_id has changed _, err = ec2conn.ReplaceNetworkAclAssociation(association.NetworkAclAssociationId, d.Id()) if err != nil { return err } - } d.Partial(false) @@ -199,8 +201,6 @@ func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error func updateNetworkAclEntries(d *schema.ResourceData, entryType string, ec2conn *ec2.EC2) error { o, n := d.GetChange(entryType) - fmt.Printf("Old : %s", o) - fmt.Printf("New : %s", n) if o == nil { o = new(schema.Set) @@ -211,10 +211,8 @@ func updateNetworkAclEntries(d *schema.ResourceData, entryType string, ec2conn * os := o.(*schema.Set) ns := n.(*schema.Set) - toBeDeleted := expandNetworkAclEntries(os.Difference(ns).List(), entryType) toBeCreated := expandNetworkAclEntries(ns.Difference(os).List(), entryType) - fmt.Printf("to be created %s", toBeCreated) for _, remove := range toBeDeleted { // Delete old Acl _, err := ec2conn.DeleteNetworkAclEntry(d.Id(), remove.RuleNumber, remove.Egress) @@ -222,12 +220,10 @@ func updateNetworkAclEntries(d *schema.ResourceData, entryType string, ec2conn * return fmt.Errorf("Error deleting %s entry: %s", entryType, err) } } - fmt.Printf("to be deleted %s", toBeDeleted) for _, add := range toBeCreated { // Add new Acl entry _, err := ec2conn.CreateNetworkAclEntry(d.Id(), &add) - fmt.Printf("$$$$#### %s", err) if err != nil { return fmt.Errorf("Error creating %s entry: %s", entryType, err) } @@ -242,28 +238,28 @@ func resourceAwsNetworkAclDelete(d *schema.ResourceData, meta interface{}) error return resource.Retry(5*time.Minute, func() error { if _, err := ec2conn.DeleteNetworkAcl(d.Id()); err != nil { ec2err := err.(*ec2.Error) - fmt.Printf("\n\n error code: %s \n", ec2err.Code) switch ec2err.Code { - 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. - association, err := findNetworkAclAssociation(d.Get("subnet_id").(string), ec2conn) - if(err != nil){ - return fmt.Errorf("Depedency voilation: Could find association: %s", d.Id(), err) - } - defaultAcl, err := getDefaultNetworkAcl(d.Get("vpc_id").(string), ec2conn) - if(err != nil){ - return fmt.Errorf("Depedency voilation: Could not dissociate subnet from %s acl: %s", d.Id(), err) - } - _, err = ec2conn.ReplaceNetworkAclAssociation(association.NetworkAclAssociationId, defaultAcl.NetworkAclId) - return err - default: - // Any other error, we want to quit the retry loop immediately - return resource.RetryError{err} + 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. + association, err := findNetworkAclAssociation(d.Get("subnet_id").(string), ec2conn) + if err != nil { + return fmt.Errorf("Depedency voilation: Can not delete acl: %s", d.Id(), err) + } + defaultAcl, err := getDefaultNetworkAcl(d.Get("vpc_id").(string), ec2conn) + if err != nil { + return fmt.Errorf("Depedency voilation: Can not delete acl %s", d.Id(), err) + } + _, err = ec2conn.ReplaceNetworkAclAssociation(association.NetworkAclAssociationId, defaultAcl.NetworkAclId) + return resource.RetryError{err} + default: + // Any other error, we want to quit the retry loop immediately + return resource.RetryError{err} } } + log.Printf("[Info] Deleted network ACL %s successfully", d.Id()) return nil }) } @@ -285,11 +281,10 @@ func resourceAwsNetworkAclEntryHash(v interface{}) int { return hashcode.String(buf.String()) } - -func getDefaultNetworkAcl(vpc_id string, ec2conn *ec2.EC2)(defaultAcl *ec2.NetworkAcl, err error){ +func getDefaultNetworkAcl(vpc_id string, ec2conn *ec2.EC2) (defaultAcl *ec2.NetworkAcl, err error) { filter := ec2.NewFilter() - filter.Add("default", "true" ) - filter.Add("vpc-id", vpc_id ) + filter.Add("default", "true") + filter.Add("vpc-id", vpc_id) resp, err := ec2conn.NetworkAcls([]string{}, filter) @@ -297,16 +292,21 @@ func getDefaultNetworkAcl(vpc_id string, ec2conn *ec2.EC2)(defaultAcl *ec2.Netwo return nil, err } return &resp.NetworkAcls[0], nil - } +} -func findNetworkAclAssociation(subnet_id string,ec2conn *ec2.EC2)(networkAclAssociation *ec2.NetworkAclAssociation, err error){ +func findNetworkAclAssociation(subnetId string, ec2conn *ec2.EC2) (networkAclAssociation *ec2.NetworkAclAssociation, err error) { filter := ec2.NewFilter() - filter.Add("association.subnet-id", subnet_id ) - + filter.Add("association.subnet-id", subnetId) + resp, err := ec2conn.NetworkAcls([]string{}, filter) if err != nil { return nil, err } - return &resp.NetworkAcls[0].AssociationSet[0], nil + for _, association := range resp.NetworkAcls[0].AssociationSet { + if association.SubnetId == subnetId { + return &association, nil + } + } + return nil, fmt.Errorf("could not find association for subnet %s ", subnetId) } diff --git a/builtin/providers/aws/resource_aws_network_acl_test.go b/builtin/providers/aws/resource_aws_network_acl_test.go index 8e578fa09..2186aa74e 100644 --- a/builtin/providers/aws/resource_aws_network_acl_test.go +++ b/builtin/providers/aws/resource_aws_network_acl_test.go @@ -55,7 +55,6 @@ func TestAccAWSNetworkAclsWithEgressAndIngressRules(t *testing.T) { func TestAccAWSNetworkAclsOnlyIngressRules(t *testing.T) { var networkAcl ec2.NetworkAcl - // var subnet ec2.Subnet resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -66,7 +65,114 @@ func TestAccAWSNetworkAclsOnlyIngressRules(t *testing.T) { Config: testAccAWSNetworkAclIngressConfig, Check: resource.ComposeTestCheckFunc( testAccCheckAWSNetworkAclExists("aws_network_acl.foos", &networkAcl), - testAccCheckSubnetAssociation("aws_network_acl.foos", "aws_subnet.blob"), + // testAccCheckSubnetAssociation("aws_network_acl.foos", "aws_subnet.blob"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.protocol", "tcp"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.rule_no", "2"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.from_port", "0"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.to_port", "22"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.action", "deny"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.cidr_block", "10.2.2.3/18"), + ), + }, + }, + }) +} + +const testAccAWSNetworkAclIngressConfig = ` +resource "aws_vpc" "foo" { + cidr_block = "10.1.0.0/16" +} +resource "aws_subnet" "blob" { + cidr_block = "10.1.1.0/24" + vpc_id = "${aws_vpc.foo.id}" + map_public_ip_on_launch = true +} +resource "aws_network_acl" "foos" { + vpc_id = "${aws_vpc.foo.id}" + ingress = { + protocol = "tcp" + rule_no = 1 + action = "deny" + cidr_block = "10.2.2.3/18" + from_port = 0 + to_port = 22 + } + ingress = { + protocol = "tcp" + rule_no = 2 + action = "deny" + cidr_block = "10.2.2.3/18" + from_port = 443 + to_port = 443 + } + subnet_id = "${aws_subnet.blob.id}" +} +` +const testAccAWSNetworkAclIngressConfigChange = ` +resource "aws_vpc" "foo" { + cidr_block = "10.1.0.0/16" +} +resource "aws_subnet" "blob" { + cidr_block = "10.1.1.0/24" + vpc_id = "${aws_vpc.foo.id}" + map_public_ip_on_launch = true +} +resource "aws_network_acl" "foos" { + vpc_id = "${aws_vpc.foo.id}" + ingress = { + protocol = "tcp" + rule_no = 1 + action = "deny" + cidr_block = "10.2.2.3/18" + from_port = 0 + to_port = 22 + } + subnet_id = "${aws_subnet.blob.id}" +} +` + +func TestAccAWSNetworkAclsOnlyIngressRulesChange(t *testing.T) { + var networkAcl ec2.NetworkAcl + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSNetworkAclDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSNetworkAclIngressConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNetworkAclExists("aws_network_acl.foos", &networkAcl), + testIngressRuleLength(&networkAcl, 2), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.protocol", "tcp"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.rule_no", "1"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.from_port", "0"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.to_port", "22"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.action", "deny"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.0.cidr_block", "10.2.2.3/18"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.1.from_port", "443"), + resource.TestCheckResourceAttr( + "aws_network_acl.foos", "ingress.1.rule_no", "2"), + ), + }, + resource.TestStep{ + Config: testAccAWSNetworkAclIngressConfigChange, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNetworkAclExists("aws_network_acl.foos", &networkAcl), + testIngressRuleLength(&networkAcl, 1), resource.TestCheckResourceAttr( "aws_network_acl.foos", "ingress.0.protocol", "tcp"), resource.TestCheckResourceAttr( @@ -103,6 +209,33 @@ func TestAccAWSNetworkAclsOnlyEgressRules(t *testing.T) { }) } + + +func TestAccNetworkAcl_SubnetChange(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSNetworkAclDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSNetworkAclSubnetConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckSubnetIsAssociatedWithAcl("aws_network_acl.bar", "aws_subnet.old"), + ), + }, + resource.TestStep{ + Config: testAccAWSNetworkAclSubnetConfigChange, + Check: resource.ComposeTestCheckFunc( + testAccCheckSubnetIsNotAssociatedWithAcl("aws_network_acl.bar", "aws_subnet.old"), + testAccCheckSubnetIsAssociatedWithAcl("aws_network_acl.bar", "aws_subnet.new"), + ), + }, + }, + }) + +} + func testAccCheckAWSNetworkAclDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).ec2conn @@ -160,48 +293,67 @@ func testAccCheckAWSNetworkAclExists(n string, networkAcl *ec2.NetworkAcl) resou } } -func testAccCheckSubnetAssociation(acl string, subnet string) resource.TestCheckFunc { +func testIngressRuleLength(networkAcl *ec2.NetworkAcl, length int) resource.TestCheckFunc { + return func(s *terraform.State) error{ + var ingressEntries []ec2.NetworkAclEntry + for _, e := range networkAcl.EntrySet { + if e.Egress == false { + ingressEntries = append(ingressEntries, e) + } + } + if len(ingressEntries) != length { + return fmt.Errorf("Invalid number of ingress entries found; count = %s", len(ingressEntries)) + } + return nil + } +} + +func testAccCheckSubnetIsAssociatedWithAcl(acl string, sub string) resource.TestCheckFunc { return func(s *terraform.State) error { - networkAcl := s.RootModule().Resources[acl] + networkAcl := s.RootModule().Resources[acl] + subnet := s.RootModule().Resources[sub] + + conn := testAccProvider.Meta().(*AWSClient).ec2conn + filter := ec2.NewFilter() + filter.Add("association.subnet-id", subnet.Primary.ID) + resp, err := conn.NetworkAcls([]string{networkAcl.Primary.ID}, filter) + + if err != nil { + return err + } + if len(resp.NetworkAcls) > 0 { + return nil + } + + r, _ := conn.NetworkAcls([]string{}, ec2.NewFilter()) + fmt.Printf("\n\nall acls\n %s\n\n", r.NetworkAcls) + conn.NetworkAcls([]string{}, filter) + + return fmt.Errorf("Network Acl %s is not associated with subnet %s", acl, sub) + } +} + +func testAccCheckSubnetIsNotAssociatedWithAcl(acl string, subnet string) resource.TestCheckFunc { + return func(s *terraform.State) error { + networkAcl := s.RootModule().Resources[acl] subnet := s.RootModule().Resources[subnet] conn := testAccProvider.Meta().(*AWSClient).ec2conn filter := ec2.NewFilter() filter.Add("association.subnet-id", subnet.Primary.ID) - resp, err := conn.NetworkAcls([]string{networkAcl.Primary.ID}, filter) + resp, err := conn.NetworkAcls([]string{networkAcl.Primary.ID}, filter) if err != nil { return err } - if len(resp.NetworkAcls) > 0 && resp.NetworkAcls[0].NetworkAclId == networkAcl.Primary.ID { - return nil - } - return fmt.Errorf("Network Acl %s is not associated with subnet %s", acl, subnet) + if len(resp.NetworkAcls) > 0 { + return fmt.Errorf("Network Acl %s is still associated with subnet %s", acl, subnet) + } + return nil } } -const testAccAWSNetworkAclIngressConfig = ` -resource "aws_vpc" "foo" { - cidr_block = "10.1.0.0/16" -} -resource "aws_subnet" "blob" { - cidr_block = "10.1.1.0/24" - vpc_id = "${aws_vpc.foo.id}" - map_public_ip_on_launch = true -} -resource "aws_network_acl" "foos" { - vpc_id = "${aws_vpc.foo.id}" - ingress = { - protocol = "tcp" - rule_no = 2 - action = "deny" - cidr_block = "10.2.2.3/18" - from_port = 0 - to_port = 22 - } - subnet_id = "${aws_subnet.blob.id}" -} -` + const testAccAWSNetworkAclEgressConfig = ` resource "aws_vpc" "foo" { @@ -273,3 +425,46 @@ resource "aws_network_acl" "bar" { } } ` +const testAccAWSNetworkAclSubnetConfig = ` +resource "aws_vpc" "foo" { + cidr_block = "10.1.0.0/16" +} +resource "aws_subnet" "old" { + cidr_block = "10.1.111.0/24" + vpc_id = "${aws_vpc.foo.id}" + map_public_ip_on_launch = true +} +resource "aws_subnet" "new" { + cidr_block = "10.1.1.0/24" + vpc_id = "${aws_vpc.foo.id}" + map_public_ip_on_launch = true +} +resource "aws_network_acl" "roll" { + vpc_id = "${aws_vpc.foo.id}" + subnet_id = "${aws_subnet.new.id}" +} +resource "aws_network_acl" "bar" { + vpc_id = "${aws_vpc.foo.id}" + subnet_id = "${aws_subnet.old.id}" +} +` + +const testAccAWSNetworkAclSubnetConfigChange = ` +resource "aws_vpc" "foo" { + cidr_block = "10.1.0.0/16" +} +resource "aws_subnet" "old" { + cidr_block = "10.1.111.0/24" + vpc_id = "${aws_vpc.foo.id}" + map_public_ip_on_launch = true +} +resource "aws_subnet" "new" { + cidr_block = "10.1.1.0/24" + vpc_id = "${aws_vpc.foo.id}" + map_public_ip_on_launch = true +} +resource "aws_network_acl" "bar" { + vpc_id = "${aws_vpc.foo.id}" + subnet_id = "${aws_subnet.new.id}" +} +`