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: validateAwsAlbListenerActionType, }, }, }, }, }, } } 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 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")) } return } func isListenerNotFound(err error) bool { elberr, ok := err.(awserr.Error) return ok && elberr.Code() == "ListenerNotFound" }