From 5eec8a531c2d485bf95cb01228e73b19047a0176 Mon Sep 17 00:00:00 2001 From: Sneha Somwanshi Date: Sun, 30 Nov 2014 17:10:54 +0530 Subject: [PATCH] Added CRUD operations for network acl --- .../providers/aws/resource_aws_network_acl.go | 175 +++++++++++++++++- .../aws/resource_aws_network_acl_test.go | 107 ++++++++--- 2 files changed, 256 insertions(+), 26 deletions(-) diff --git a/builtin/providers/aws/resource_aws_network_acl.go b/builtin/providers/aws/resource_aws_network_acl.go index 19025f9f42..c3f38ba259 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 f98e4b8404..26555aff19 100644 --- a/builtin/providers/aws/resource_aws_network_acl_test.go +++ b/builtin/providers/aws/resource_aws_network_acl_test.go @@ -11,35 +11,98 @@ 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 + } } +` + +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 + } } ` -// 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") +func TestAccAWSNetworkAclsIngressSneha(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.bar", &networkAcl), + ), + }, + }, + }) +} + + +func TestAccAWSNetworkAclsEgressSneha(t *testing.T) { var networkAcl ec2.NetworkAcl resource.Test(t, resource.TestCase{ @@ -48,7 +111,7 @@ func TestAccAWSNetworkAclsSneha(t *testing.T) { CheckDestroy: testAccCheckAWSNetworkAclDestroy, Steps: []resource.TestStep{ resource.TestStep{ - Config: testAccAWSNetworkAclConfig, + Config: testAccAWSNetworkAclEgressConfig, Check: resource.ComposeTestCheckFunc( testAccCheckAWSNetworkAclExists("aws_network_acl.bar", &networkAcl), ),