Skip to content

Commit

Permalink
Merge pull request #8318 from hashicorp/f-aws-application-lb-rules
Browse files Browse the repository at this point in the history
provider/aws: Add aws_alb_listener_rule resource
  • Loading branch information
jen20 authored Aug 19, 2016
2 parents 0800bc2 + 417b98b commit b5e0f2e
Show file tree
Hide file tree
Showing 6 changed files with 548 additions and 2 deletions.
1 change: 1 addition & 0 deletions builtin/providers/aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ func Provider() terraform.ResourceProvider {
ResourcesMap: map[string]*schema.Resource{
"aws_alb": resourceAwsAlb(),
"aws_alb_listener": resourceAwsAlbListener(),
"aws_alb_listener_rule": resourceAwsAlbListenerRule(),
"aws_alb_target_group": resourceAwsAlbTargetGroup(),
"aws_ami": resourceAwsAmi(),
"aws_ami_copy": resourceAwsAmiCopy(),
Expand Down
4 changes: 2 additions & 2 deletions builtin/providers/aws/resource_aws_alb_listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func resourceAwsAlbListener() *schema.Resource {
"type": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validateAwsAlbListenerDefaultActionType,
ValidateFunc: validateAwsAlbListenerActionType,
},
},
},
Expand Down Expand Up @@ -247,7 +247,7 @@ func validateAwsAlbListenerProtocol(v interface{}, k string) (ws []string, error
return
}

func validateAwsAlbListenerDefaultActionType(v interface{}, k string) (ws []string, errors []error) {
func validateAwsAlbListenerActionType(v interface{}, k string) (ws []string, errors []error) {
value := strings.ToLower(v.(string))
if value != "forward" {
errors = append(errors, fmt.Errorf("%q must have the value %q", k, "forward"))
Expand Down
252 changes: 252 additions & 0 deletions builtin/providers/aws/resource_aws_alb_listener_rule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
package aws

import (
"errors"
"fmt"
"log"
"strconv"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/elbv2"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsAlbListenerRule() *schema.Resource {
return &schema.Resource{
Create: resourceAwsAlbListenerRuleCreate,
Read: resourceAwsAlbListenerRuleRead,
Update: resourceAwsAlbListenerRuleUpdate,
Delete: resourceAwsAlbListenerRuleDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},
"listener_arn": {
Type: schema.TypeString,
Required: true,
},
"priority": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validateAwsAlbListenerRulePriority,
},
"action": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"target_group_arn": {
Type: schema.TypeString,
Required: true,
},
"type": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validateAwsAlbListenerActionType,
},
},
},
},
"condition": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"field": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validateAwsListenerRuleField,
},
"values": {
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
Optional: true,
},
},
},
},
},
}
}

func resourceAwsAlbListenerRuleCreate(d *schema.ResourceData, meta interface{}) error {
elbconn := meta.(*AWSClient).elbv2conn

params := &elbv2.CreateRuleInput{
ListenerArn: aws.String(d.Get("listener_arn").(string)),
Priority: aws.Int64(int64(d.Get("priority").(int))),
}

actions := d.Get("action").([]interface{})
params.Actions = make([]*elbv2.Action, len(actions))
for i, action := range actions {
actionMap := action.(map[string]interface{})
params.Actions[i] = &elbv2.Action{
TargetGroupArn: aws.String(actionMap["target_group_arn"].(string)),
Type: aws.String(actionMap["type"].(string)),
}
}

conditions := d.Get("condition").([]interface{})
params.Conditions = make([]*elbv2.RuleCondition, len(conditions))
for i, condition := range conditions {
conditionMap := condition.(map[string]interface{})
values := conditionMap["values"].([]interface{})
params.Conditions[i] = &elbv2.RuleCondition{
Field: aws.String(conditionMap["field"].(string)),
Values: make([]*string, len(values)),
}
for j, value := range values {
params.Conditions[i].Values[j] = aws.String(value.(string))
}
}

resp, err := elbconn.CreateRule(params)
if err != nil {
return errwrap.Wrapf("Error creating ALB Listener Rule: {{err}}", err)
}

if len(resp.Rules) == 0 {
return errors.New("Error creating ALB Listener Rule: no rules returned in response")
}

d.SetId(*resp.Rules[0].RuleArn)

return resourceAwsAlbListenerRuleRead(d, meta)
}

func resourceAwsAlbListenerRuleRead(d *schema.ResourceData, meta interface{}) error {
elbconn := meta.(*AWSClient).elbv2conn

resp, err := elbconn.DescribeRules(&elbv2.DescribeRulesInput{
RuleArns: []*string{aws.String(d.Id())},
})
if err != nil {
if isRuleNotFound(err) {
log.Printf("[WARN] DescribeRules - removing %s from state", d.Id())
d.SetId("")
return nil
}
return errwrap.Wrapf(fmt.Sprintf("Error retrieving Rules for listener %s: {{err}}", d.Id()), err)
}

if len(resp.Rules) != 1 {
return fmt.Errorf("Error retrieving Rule %q", d.Id())
}

rule := resp.Rules[0]

d.Set("arn", rule.RuleArn)
if priority, err := strconv.Atoi(*rule.Priority); err != nil {
return errwrap.Wrapf("Cannot convert rule priority %q to int: {{err}}", err)
} else {
d.Set("priority", priority)
}

actions := make([]interface{}, len(rule.Actions))
for i, action := range rule.Actions {
actionMap := make(map[string]interface{})
actionMap["target_group_arn"] = *action.TargetGroupArn
actionMap["type"] = *action.Type
actions[i] = actionMap
}
d.Set("action", actions)

conditions := make([]interface{}, len(rule.Conditions))
for i, condition := range rule.Conditions {
conditionMap := make(map[string]interface{})
conditionMap["field"] = *condition.Field
conditionValues := make([]string, len(condition.Values))
for k, value := range condition.Values {
conditionValues[k] = *value
}
conditionMap["values"] = conditionValues
conditions[i] = conditionMap
}
d.Set("condition", conditions)

return nil
}

func resourceAwsAlbListenerRuleUpdate(d *schema.ResourceData, meta interface{}) error {
elbconn := meta.(*AWSClient).elbv2conn

params := &elbv2.ModifyRuleInput{
RuleArn: aws.String(d.Id()),
}

actions := d.Get("action").([]interface{})
params.Actions = make([]*elbv2.Action, len(actions))
for i, action := range actions {
actionMap := action.(map[string]interface{})
params.Actions[i] = &elbv2.Action{
TargetGroupArn: aws.String(actionMap["target_group_arn"].(string)),
Type: aws.String(actionMap["type"].(string)),
}
}

conditions := d.Get("condition").([]interface{})
params.Conditions = make([]*elbv2.RuleCondition, len(conditions))
for i, condition := range conditions {
conditionMap := condition.(map[string]interface{})
values := conditionMap["values"].([]interface{})
params.Conditions[i] = &elbv2.RuleCondition{
Field: aws.String(conditionMap["field"].(string)),
Values: make([]*string, len(values)),
}
for j, value := range values {
params.Conditions[i].Values[j] = aws.String(value.(string))
}
}

resp, err := elbconn.ModifyRule(params)
if err != nil {
return errwrap.Wrapf("Error modifying ALB Listener Rule: {{err}}", err)
}

if len(resp.Rules) == 0 {
return errors.New("Error modifying creating ALB Listener Rule: no rules returned in response")
}

return resourceAwsAlbListenerRuleRead(d, meta)
}

func resourceAwsAlbListenerRuleDelete(d *schema.ResourceData, meta interface{}) error {
elbconn := meta.(*AWSClient).elbv2conn

_, err := elbconn.DeleteRule(&elbv2.DeleteRuleInput{
RuleArn: aws.String(d.Id()),
})
if err != nil && !isRuleNotFound(err) {
return errwrap.Wrapf("Error deleting ALB Listener Rule: {{err}}", err)
}
return nil
}

func validateAwsAlbListenerRulePriority(v interface{}, k string) (ws []string, errors []error) {
value := v.(int)
if value < 1 || value > 99999 {
errors = append(errors, fmt.Errorf("%q must be in the range 1-99999", k))
}
return
}

func validateAwsListenerRuleField(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 64 {
errors = append(errors, fmt.Errorf("%q must be a maximum of 64 characters", k))
}
return
}

func isRuleNotFound(err error) bool {
elberr, ok := err.(awserr.Error)
return ok && elberr.Code() == "RuleNotFound"
}
Loading

0 comments on commit b5e0f2e

Please sign in to comment.