-
Notifications
You must be signed in to change notification settings - Fork 9.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8268 from hashicorp/f-aws-application-lb-listener
provider/aws: Add aws_alb_listener resource
- Loading branch information
Showing
11 changed files
with
742 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,261 @@ | ||
package aws | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"log" | ||
"strings" | ||
|
||
"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 resourceAwsAlbListener() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceAwsAlbListenerCreate, | ||
Read: resourceAwsAlbListenerRead, | ||
Update: resourceAwsAlbListenerUpdate, | ||
Delete: resourceAwsAlbListenerDelete, | ||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"arn": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
|
||
"load_balancer_arn": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"port": { | ||
Type: schema.TypeInt, | ||
Required: true, | ||
ValidateFunc: validateAwsAlbListenerPort, | ||
}, | ||
|
||
"protocol": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Default: "HTTP", | ||
StateFunc: func(v interface{}) string { | ||
return strings.ToUpper(v.(string)) | ||
}, | ||
ValidateFunc: validateAwsAlbListenerProtocol, | ||
}, | ||
|
||
"ssl_policy": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
|
||
"certificate_arn": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
|
||
"default_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: validateAwsAlbListenerDefaultActionType, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceAwsAlbListenerCreate(d *schema.ResourceData, meta interface{}) error { | ||
elbconn := meta.(*AWSClient).elbv2conn | ||
|
||
params := &elbv2.CreateListenerInput{ | ||
LoadBalancerArn: aws.String(d.Get("load_balancer_arn").(string)), | ||
Port: aws.Int64(int64(d.Get("port").(int))), | ||
Protocol: aws.String(d.Get("protocol").(string)), | ||
} | ||
|
||
if sslPolicy, ok := d.GetOk("ssl_policy"); ok { | ||
params.SslPolicy = aws.String(sslPolicy.(string)) | ||
} | ||
|
||
if certificateArn, ok := d.GetOk("certificate_arn"); ok { | ||
params.Certificates = make([]*elbv2.Certificate, 1) | ||
params.Certificates[0] = &elbv2.Certificate{ | ||
CertificateArn: aws.String(certificateArn.(string)), | ||
} | ||
} | ||
|
||
if defaultActions := d.Get("default_action").([]interface{}); len(defaultActions) == 1 { | ||
params.DefaultActions = make([]*elbv2.Action, len(defaultActions)) | ||
|
||
for i, defaultAction := range defaultActions { | ||
defaultActionMap := defaultAction.(map[string]interface{}) | ||
|
||
params.DefaultActions[i] = &elbv2.Action{ | ||
TargetGroupArn: aws.String(defaultActionMap["target_group_arn"].(string)), | ||
Type: aws.String(defaultActionMap["type"].(string)), | ||
} | ||
} | ||
} | ||
|
||
resp, err := elbconn.CreateListener(params) | ||
if err != nil { | ||
return errwrap.Wrapf("Error creating ALB Listener: {{err}}", err) | ||
} | ||
|
||
if len(resp.Listeners) == 0 { | ||
return errors.New("Error creating ALB Listener: no listeners returned in response") | ||
} | ||
|
||
d.SetId(*resp.Listeners[0].ListenerArn) | ||
|
||
return resourceAwsAlbListenerRead(d, meta) | ||
} | ||
|
||
func resourceAwsAlbListenerRead(d *schema.ResourceData, meta interface{}) error { | ||
elbconn := meta.(*AWSClient).elbv2conn | ||
|
||
resp, err := elbconn.DescribeListeners(&elbv2.DescribeListenersInput{ | ||
ListenerArns: []*string{aws.String(d.Id())}, | ||
}) | ||
if err != nil { | ||
if isListenerNotFound(err) { | ||
log.Printf("[WARN] DescribeListeners - removing %s from state", d.Id()) | ||
d.SetId("") | ||
return nil | ||
} | ||
return errwrap.Wrapf("Error retrieving Listener: {{err}}", err) | ||
} | ||
|
||
if len(resp.Listeners) != 1 { | ||
return fmt.Errorf("Error retrieving Listener %q", d.Id()) | ||
} | ||
|
||
listener := resp.Listeners[0] | ||
|
||
d.Set("arn", listener.ListenerArn) | ||
d.Set("load_balancer_arn", listener.LoadBalancerArn) | ||
d.Set("port", listener.Port) | ||
d.Set("protocol", listener.Protocol) | ||
d.Set("ssl_policy", listener.SslPolicy) | ||
|
||
if listener.Certificates != nil && len(listener.Certificates) == 1 { | ||
d.Set("certificate_arn", listener.Certificates[0].CertificateArn) | ||
} | ||
|
||
defaultActions := make([]map[string]interface{}, 0) | ||
if listener.DefaultActions != nil && len(listener.DefaultActions) > 0 { | ||
for _, defaultAction := range listener.DefaultActions { | ||
action := map[string]interface{}{ | ||
"target_group_arn": *defaultAction.TargetGroupArn, | ||
"type": *defaultAction.Type, | ||
} | ||
defaultActions = append(defaultActions, action) | ||
} | ||
} | ||
d.Set("default_action", defaultActions) | ||
|
||
return nil | ||
} | ||
|
||
func resourceAwsAlbListenerUpdate(d *schema.ResourceData, meta interface{}) error { | ||
elbconn := meta.(*AWSClient).elbv2conn | ||
|
||
params := &elbv2.ModifyListenerInput{ | ||
ListenerArn: aws.String(d.Id()), | ||
Port: aws.Int64(int64(d.Get("port").(int))), | ||
Protocol: aws.String(d.Get("protocol").(string)), | ||
} | ||
|
||
if sslPolicy, ok := d.GetOk("ssl_policy"); ok { | ||
params.SslPolicy = aws.String(sslPolicy.(string)) | ||
} | ||
|
||
if certificateArn, ok := d.GetOk("certificate_arn"); ok { | ||
params.Certificates = make([]*elbv2.Certificate, 1) | ||
params.Certificates[0] = &elbv2.Certificate{ | ||
CertificateArn: aws.String(certificateArn.(string)), | ||
} | ||
} | ||
|
||
if defaultActions := d.Get("default_action").([]interface{}); len(defaultActions) == 1 { | ||
params.DefaultActions = make([]*elbv2.Action, len(defaultActions)) | ||
|
||
for i, defaultAction := range defaultActions { | ||
defaultActionMap := defaultAction.(map[string]interface{}) | ||
|
||
params.DefaultActions[i] = &elbv2.Action{ | ||
TargetGroupArn: aws.String(defaultActionMap["target_group_arn"].(string)), | ||
Type: aws.String(defaultActionMap["type"].(string)), | ||
} | ||
} | ||
} | ||
|
||
_, err := elbconn.ModifyListener(params) | ||
if err != nil { | ||
return errwrap.Wrapf("Error modifying ALB Listener: {{err}}", err) | ||
} | ||
|
||
return resourceAwsAlbListenerRead(d, meta) | ||
} | ||
|
||
func resourceAwsAlbListenerDelete(d *schema.ResourceData, meta interface{}) error { | ||
elbconn := meta.(*AWSClient).elbv2conn | ||
|
||
_, err := elbconn.DeleteListener(&elbv2.DeleteListenerInput{ | ||
ListenerArn: aws.String(d.Id()), | ||
}) | ||
if err != nil { | ||
return errwrap.Wrapf("Error deleting Listener: {{err}}", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func validateAwsAlbListenerPort(v interface{}, k string) (ws []string, errors []error) { | ||
port := v.(int) | ||
if port < 1 || port > 65536 { | ||
errors = append(errors, fmt.Errorf("%q must be a valid port number (1-65536)", k)) | ||
} | ||
return | ||
} | ||
|
||
func validateAwsAlbListenerProtocol(v interface{}, k string) (ws []string, errors []error) { | ||
value := strings.ToLower(v.(string)) | ||
if value == "http" || value == "https" { | ||
return | ||
} | ||
|
||
errors = append(errors, fmt.Errorf("%q must be either %q or %q", k, "HTTP", "HTTPS")) | ||
return | ||
} | ||
|
||
func validateAwsAlbListenerDefaultActionType(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")) | ||
} | ||
return | ||
} | ||
|
||
func isListenerNotFound(err error) bool { | ||
elberr, ok := err.(awserr.Error) | ||
return ok && elberr.Code() == "ListenerNotFound" | ||
} |
Oops, something went wrong.