github.com/leeprovoost/terraform@v0.6.10-0.20160119085442-96f3f76118e7/builtin/providers/aws/resource_aws_network_acl_rule.go (about)

     1  package aws
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"strconv"
     8  
     9  	"github.com/aws/aws-sdk-go/aws"
    10  	"github.com/aws/aws-sdk-go/service/ec2"
    11  	"github.com/hashicorp/terraform/helper/hashcode"
    12  	"github.com/hashicorp/terraform/helper/schema"
    13  )
    14  
    15  func resourceAwsNetworkAclRule() *schema.Resource {
    16  	return &schema.Resource{
    17  		Create: resourceAwsNetworkAclRuleCreate,
    18  		Read:   resourceAwsNetworkAclRuleRead,
    19  		Delete: resourceAwsNetworkAclRuleDelete,
    20  
    21  		Schema: map[string]*schema.Schema{
    22  			"network_acl_id": &schema.Schema{
    23  				Type:     schema.TypeString,
    24  				Required: true,
    25  				ForceNew: true,
    26  			},
    27  			"rule_number": &schema.Schema{
    28  				Type:     schema.TypeInt,
    29  				Required: true,
    30  				ForceNew: true,
    31  			},
    32  			"egress": &schema.Schema{
    33  				Type:     schema.TypeBool,
    34  				Optional: true,
    35  				ForceNew: true,
    36  				Default:  false,
    37  			},
    38  			"protocol": &schema.Schema{
    39  				Type:     schema.TypeString,
    40  				Required: true,
    41  				ForceNew: true,
    42  			},
    43  			"rule_action": &schema.Schema{
    44  				Type:     schema.TypeString,
    45  				Required: true,
    46  				ForceNew: true,
    47  			},
    48  			"cidr_block": &schema.Schema{
    49  				Type:     schema.TypeString,
    50  				Required: true,
    51  				ForceNew: true,
    52  			},
    53  			"from_port": &schema.Schema{
    54  				Type:     schema.TypeInt,
    55  				Optional: true,
    56  				ForceNew: true,
    57  			},
    58  			"to_port": &schema.Schema{
    59  				Type:     schema.TypeInt,
    60  				Optional: true,
    61  				ForceNew: true,
    62  			},
    63  			"icmp_type": &schema.Schema{
    64  				Type:     schema.TypeInt,
    65  				Optional: true,
    66  				ForceNew: true,
    67  			},
    68  			"icmp_code": &schema.Schema{
    69  				Type:     schema.TypeInt,
    70  				Optional: true,
    71  				ForceNew: true,
    72  			},
    73  		},
    74  	}
    75  }
    76  
    77  func resourceAwsNetworkAclRuleCreate(d *schema.ResourceData, meta interface{}) error {
    78  	conn := meta.(*AWSClient).ec2conn
    79  
    80  	protocol := d.Get("protocol").(string)
    81  	p, protocolErr := strconv.Atoi(protocol)
    82  	if protocolErr != nil {
    83  		var ok bool
    84  		p, ok = protocolIntegers()[protocol]
    85  		if !ok {
    86  			return fmt.Errorf("Invalid Protocol %s for rule %#v", protocol, d.Get("rule_number").(int))
    87  		}
    88  	}
    89  	log.Printf("[INFO] Transformed Protocol %s into %d", protocol, p)
    90  
    91  	params := &ec2.CreateNetworkAclEntryInput{
    92  		NetworkAclId: aws.String(d.Get("network_acl_id").(string)),
    93  		Egress:       aws.Bool(d.Get("egress").(bool)),
    94  		RuleNumber:   aws.Int64(int64(d.Get("rule_number").(int))),
    95  		Protocol:     aws.String(strconv.Itoa(p)),
    96  		CidrBlock:    aws.String(d.Get("cidr_block").(string)),
    97  		RuleAction:   aws.String(d.Get("rule_action").(string)),
    98  		PortRange: &ec2.PortRange{
    99  			From: aws.Int64(int64(d.Get("from_port").(int))),
   100  			To:   aws.Int64(int64(d.Get("to_port").(int))),
   101  		},
   102  	}
   103  
   104  	// Specify additional required fields for ICMP
   105  	if p == 1 {
   106  		params.IcmpTypeCode = &ec2.IcmpTypeCode{}
   107  		if v, ok := d.GetOk("icmp_code"); ok {
   108  			params.IcmpTypeCode.Code = aws.Int64(int64(v.(int)))
   109  		}
   110  		if v, ok := d.GetOk("icmp_type"); ok {
   111  			params.IcmpTypeCode.Type = aws.Int64(int64(v.(int)))
   112  		}
   113  	}
   114  
   115  	log.Printf("[INFO] Creating Network Acl Rule: %d (%t)", d.Get("rule_number").(int), d.Get("egress").(bool))
   116  	_, err := conn.CreateNetworkAclEntry(params)
   117  	if err != nil {
   118  		return fmt.Errorf("Error Creating Network Acl Rule: %s", err.Error())
   119  	}
   120  	d.SetId(networkAclIdRuleNumberEgressHash(d.Get("network_acl_id").(string), d.Get("rule_number").(int), d.Get("egress").(bool), d.Get("protocol").(string)))
   121  	return resourceAwsNetworkAclRuleRead(d, meta)
   122  }
   123  
   124  func resourceAwsNetworkAclRuleRead(d *schema.ResourceData, meta interface{}) error {
   125  	resp, err := findNetworkAclRule(d, meta)
   126  	if err != nil {
   127  		return err
   128  	}
   129  
   130  	d.Set("rule_number", resp.RuleNumber)
   131  	d.Set("cidr_block", resp.CidrBlock)
   132  	d.Set("egress", resp.Egress)
   133  	if resp.IcmpTypeCode != nil {
   134  		d.Set("icmp_code", resp.IcmpTypeCode.Code)
   135  		d.Set("icmp_type", resp.IcmpTypeCode.Type)
   136  	}
   137  	if resp.PortRange != nil {
   138  		d.Set("from_port", resp.PortRange.From)
   139  		d.Set("to_port", resp.PortRange.To)
   140  	}
   141  
   142  	d.Set("rule_action", resp.RuleAction)
   143  
   144  	p, protocolErr := strconv.Atoi(*resp.Protocol)
   145  	log.Printf("[INFO] Converting the protocol %v", p)
   146  	if protocolErr == nil {
   147  		var ok bool
   148  		protocol, ok := protocolStrings(protocolIntegers())[p]
   149  		if !ok {
   150  			return fmt.Errorf("Invalid Protocol %s for rule %#v", *resp.Protocol, d.Get("rule_number").(int))
   151  		}
   152  		log.Printf("[INFO] Transformed Protocol %s back into %s", *resp.Protocol, protocol)
   153  		d.Set("protocol", protocol)
   154  	}
   155  
   156  	return nil
   157  }
   158  
   159  func resourceAwsNetworkAclRuleDelete(d *schema.ResourceData, meta interface{}) error {
   160  	conn := meta.(*AWSClient).ec2conn
   161  
   162  	params := &ec2.DeleteNetworkAclEntryInput{
   163  		NetworkAclId: aws.String(d.Get("network_acl_id").(string)),
   164  		RuleNumber:   aws.Int64(int64(d.Get("rule_number").(int))),
   165  		Egress:       aws.Bool(d.Get("egress").(bool)),
   166  	}
   167  
   168  	log.Printf("[INFO] Deleting Network Acl Rule: %s", d.Id())
   169  	_, err := conn.DeleteNetworkAclEntry(params)
   170  	if err != nil {
   171  		return fmt.Errorf("Error Deleting Network Acl Rule: %s", err.Error())
   172  	}
   173  
   174  	return nil
   175  }
   176  
   177  func findNetworkAclRule(d *schema.ResourceData, meta interface{}) (*ec2.NetworkAclEntry, error) {
   178  	conn := meta.(*AWSClient).ec2conn
   179  
   180  	filters := make([]*ec2.Filter, 0, 2)
   181  	ruleNumberFilter := &ec2.Filter{
   182  		Name:   aws.String("entry.rule-number"),
   183  		Values: []*string{aws.String(fmt.Sprintf("%v", d.Get("rule_number").(int)))},
   184  	}
   185  	filters = append(filters, ruleNumberFilter)
   186  	egressFilter := &ec2.Filter{
   187  		Name:   aws.String("entry.egress"),
   188  		Values: []*string{aws.String(fmt.Sprintf("%v", d.Get("egress").(bool)))},
   189  	}
   190  	filters = append(filters, egressFilter)
   191  	params := &ec2.DescribeNetworkAclsInput{
   192  		NetworkAclIds: []*string{aws.String(d.Get("network_acl_id").(string))},
   193  		Filters:       filters,
   194  	}
   195  
   196  	log.Printf("[INFO] Describing Network Acl: %s", d.Get("network_acl_id").(string))
   197  	log.Printf("[INFO] Describing Network Acl with the Filters %#v", params)
   198  	resp, err := conn.DescribeNetworkAcls(params)
   199  	if err != nil {
   200  		return nil, fmt.Errorf("Error Finding Network Acl Rule %d: %s", d.Get("rule_number").(int), err.Error())
   201  	}
   202  
   203  	if resp == nil || len(resp.NetworkAcls) != 1 || resp.NetworkAcls[0] == nil {
   204  		return nil, fmt.Errorf(
   205  			"Expected to find one Network ACL, got: %#v",
   206  			resp.NetworkAcls)
   207  	}
   208  	networkAcl := resp.NetworkAcls[0]
   209  	if networkAcl.Entries != nil {
   210  		for _, i := range networkAcl.Entries {
   211  			if *i.RuleNumber == int64(d.Get("rule_number").(int)) && *i.Egress == d.Get("egress").(bool) {
   212  				return i, nil
   213  			}
   214  		}
   215  	}
   216  	return nil, fmt.Errorf(
   217  		"Expected the Network ACL to have Entries, got: %#v",
   218  		networkAcl)
   219  
   220  }
   221  
   222  func networkAclIdRuleNumberEgressHash(networkAclId string, ruleNumber int, egress bool, protocol string) string {
   223  	var buf bytes.Buffer
   224  	buf.WriteString(fmt.Sprintf("%s-", networkAclId))
   225  	buf.WriteString(fmt.Sprintf("%d-", ruleNumber))
   226  	buf.WriteString(fmt.Sprintf("%t-", egress))
   227  	buf.WriteString(fmt.Sprintf("%s-", protocol))
   228  	return fmt.Sprintf("nacl-%d", hashcode.String(buf.String()))
   229  }