github.com/mohanarpit/terraform@v0.6.16-0.20160909104007-291f29853544/builtin/providers/aws/resource_aws_alb.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strconv"
     7  
     8  	"github.com/aws/aws-sdk-go/aws"
     9  	"github.com/aws/aws-sdk-go/service/elbv2"
    10  	"github.com/hashicorp/errwrap"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  )
    13  
    14  func resourceAwsAlb() *schema.Resource {
    15  	return &schema.Resource{
    16  		Create: resourceAwsAlbCreate,
    17  		Read:   resourceAwsAlbRead,
    18  		Update: resourceAwsAlbUpdate,
    19  		Delete: resourceAwsAlbDelete,
    20  		Importer: &schema.ResourceImporter{
    21  			State: schema.ImportStatePassthrough,
    22  		},
    23  
    24  		Schema: map[string]*schema.Schema{
    25  			"arn": {
    26  				Type:     schema.TypeString,
    27  				Computed: true,
    28  			},
    29  
    30  			"name": {
    31  				Type:         schema.TypeString,
    32  				Required:     true,
    33  				ForceNew:     true,
    34  				ValidateFunc: validateElbName,
    35  			},
    36  
    37  			"internal": {
    38  				Type:     schema.TypeBool,
    39  				Optional: true,
    40  				ForceNew: true,
    41  				Computed: true,
    42  			},
    43  
    44  			"security_groups": {
    45  				Type:     schema.TypeSet,
    46  				Elem:     &schema.Schema{Type: schema.TypeString},
    47  				Computed: true,
    48  				ForceNew: true,
    49  				Optional: true,
    50  				Set:      schema.HashString,
    51  			},
    52  
    53  			"subnets": {
    54  				Type:     schema.TypeSet,
    55  				Elem:     &schema.Schema{Type: schema.TypeString},
    56  				ForceNew: true,
    57  				Required: true,
    58  				Set:      schema.HashString,
    59  			},
    60  
    61  			"access_logs": {
    62  				Type:     schema.TypeList,
    63  				Optional: true,
    64  				MaxItems: 1,
    65  				Elem: &schema.Resource{
    66  					Schema: map[string]*schema.Schema{
    67  						"bucket": {
    68  							Type:     schema.TypeString,
    69  							Required: true,
    70  						},
    71  						"prefix": {
    72  							Type:     schema.TypeString,
    73  							Optional: true,
    74  						},
    75  					},
    76  				},
    77  			},
    78  
    79  			"enable_deletion_protection": {
    80  				Type:     schema.TypeBool,
    81  				Optional: true,
    82  				Default:  false,
    83  			},
    84  
    85  			"idle_timeout": {
    86  				Type:     schema.TypeInt,
    87  				Optional: true,
    88  				Default:  60,
    89  			},
    90  
    91  			"vpc_id": {
    92  				Type:     schema.TypeString,
    93  				Computed: true,
    94  			},
    95  
    96  			"zone_id": {
    97  				Type:     schema.TypeString,
    98  				Computed: true,
    99  			},
   100  
   101  			"dns_name": {
   102  				Type:     schema.TypeString,
   103  				Computed: true,
   104  			},
   105  
   106  			"tags": tagsSchema(),
   107  		},
   108  	}
   109  }
   110  
   111  func resourceAwsAlbCreate(d *schema.ResourceData, meta interface{}) error {
   112  	elbconn := meta.(*AWSClient).elbv2conn
   113  
   114  	elbOpts := &elbv2.CreateLoadBalancerInput{
   115  		Name: aws.String(d.Get("name").(string)),
   116  		Tags: tagsFromMapELBv2(d.Get("tags").(map[string]interface{})),
   117  	}
   118  
   119  	if scheme, ok := d.GetOk("internal"); ok && scheme.(bool) {
   120  		elbOpts.Scheme = aws.String("internal")
   121  	}
   122  
   123  	if v, ok := d.GetOk("security_groups"); ok {
   124  		elbOpts.SecurityGroups = expandStringList(v.(*schema.Set).List())
   125  	}
   126  
   127  	if v, ok := d.GetOk("subnets"); ok {
   128  		elbOpts.Subnets = expandStringList(v.(*schema.Set).List())
   129  	}
   130  
   131  	log.Printf("[DEBUG] ALB create configuration: %#v", elbOpts)
   132  
   133  	resp, err := elbconn.CreateLoadBalancer(elbOpts)
   134  	if err != nil {
   135  		return errwrap.Wrapf("Error creating Application Load Balancer: {{err}}", err)
   136  	}
   137  
   138  	if len(resp.LoadBalancers) != 1 {
   139  		return fmt.Errorf("No load balancers returned following creation of %s", d.Get("name").(string))
   140  	}
   141  
   142  	d.SetId(*resp.LoadBalancers[0].LoadBalancerArn)
   143  	log.Printf("[INFO] ALB ID: %s", d.Id())
   144  
   145  	return resourceAwsAlbUpdate(d, meta)
   146  }
   147  
   148  func resourceAwsAlbRead(d *schema.ResourceData, meta interface{}) error {
   149  	elbconn := meta.(*AWSClient).elbv2conn
   150  	albArn := d.Id()
   151  
   152  	describeAlbOpts := &elbv2.DescribeLoadBalancersInput{
   153  		LoadBalancerArns: []*string{aws.String(albArn)},
   154  	}
   155  
   156  	describeResp, err := elbconn.DescribeLoadBalancers(describeAlbOpts)
   157  	if err != nil {
   158  		if isLoadBalancerNotFound(err) {
   159  			// The ALB is gone now, so just remove it from the state
   160  			log.Printf("[WARN] ALB %s not found in AWS, removing from state", d.Id())
   161  			d.SetId("")
   162  			return nil
   163  		}
   164  
   165  		return errwrap.Wrapf("Error retrieving ALB: {{err}}", err)
   166  	}
   167  	if len(describeResp.LoadBalancers) != 1 {
   168  		return fmt.Errorf("Unable to find ALB: %#v", describeResp.LoadBalancers)
   169  	}
   170  
   171  	alb := describeResp.LoadBalancers[0]
   172  
   173  	d.Set("arn", alb.LoadBalancerArn)
   174  	d.Set("name", alb.LoadBalancerName)
   175  	d.Set("internal", (alb.Scheme != nil && *alb.Scheme == "internal"))
   176  	d.Set("security_groups", flattenStringList(alb.SecurityGroups))
   177  	d.Set("subnets", flattenSubnetsFromAvailabilityZones(alb.AvailabilityZones))
   178  	d.Set("vpc_id", alb.VpcId)
   179  	d.Set("zone_id", alb.CanonicalHostedZoneId)
   180  	d.Set("dns_name", alb.DNSName)
   181  
   182  	respTags, err := elbconn.DescribeTags(&elbv2.DescribeTagsInput{
   183  		ResourceArns: []*string{alb.LoadBalancerArn},
   184  	})
   185  	if err != nil {
   186  		return errwrap.Wrapf("Error retrieving ALB Tags: {{err}}", err)
   187  	}
   188  
   189  	var et []*elbv2.Tag
   190  	if len(respTags.TagDescriptions) > 0 {
   191  		et = respTags.TagDescriptions[0].Tags
   192  	}
   193  	d.Set("tags", tagsToMapELBv2(et))
   194  
   195  	attributesResp, err := elbconn.DescribeLoadBalancerAttributes(&elbv2.DescribeLoadBalancerAttributesInput{
   196  		LoadBalancerArn: aws.String(d.Id()),
   197  	})
   198  	if err != nil {
   199  		return errwrap.Wrapf("Error retrieving ALB Attributes: {{err}}", err)
   200  	}
   201  
   202  	accessLogMap := map[string]interface{}{}
   203  	for _, attr := range attributesResp.Attributes {
   204  		switch *attr.Key {
   205  		case "access_logs.s3.bucket":
   206  			accessLogMap["bucket"] = *attr.Value
   207  		case "access_logs.s3.prefix":
   208  			accessLogMap["prefix"] = *attr.Value
   209  		case "idle_timeout.timeout_seconds":
   210  			timeout, err := strconv.Atoi(*attr.Value)
   211  			if err != nil {
   212  				return errwrap.Wrapf("Error parsing ALB timeout: {{err}}", err)
   213  			}
   214  			log.Printf("[DEBUG] Setting ALB Timeout Seconds: %d", timeout)
   215  			d.Set("idle_timeout", timeout)
   216  		case "deletion_protection.enabled":
   217  			protectionEnabled := (*attr.Value) == "true"
   218  			log.Printf("[DEBUG] Setting ALB Deletion Protection Enabled: %t", protectionEnabled)
   219  			d.Set("enable_deletion_protection", protectionEnabled)
   220  		}
   221  	}
   222  
   223  	log.Printf("[DEBUG] Setting ALB Access Logs: %#v", accessLogMap)
   224  	if accessLogMap["bucket"] != "" || accessLogMap["prefix"] != "" {
   225  		d.Set("access_logs", []interface{}{accessLogMap})
   226  	} else {
   227  		d.Set("access_logs", []interface{}{})
   228  	}
   229  
   230  	return nil
   231  }
   232  
   233  func resourceAwsAlbUpdate(d *schema.ResourceData, meta interface{}) error {
   234  	elbconn := meta.(*AWSClient).elbv2conn
   235  
   236  	if !d.IsNewResource() {
   237  		if err := setElbV2Tags(elbconn, d); err != nil {
   238  			return errwrap.Wrapf("Error Modifying Tags on ALB: {{err}}", err)
   239  		}
   240  	}
   241  
   242  	attributes := make([]*elbv2.LoadBalancerAttribute, 0)
   243  
   244  	if d.HasChange("access_logs") {
   245  		logs := d.Get("access_logs").([]interface{})
   246  		if len(logs) == 1 {
   247  			log := logs[0].(map[string]interface{})
   248  
   249  			attributes = append(attributes,
   250  				&elbv2.LoadBalancerAttribute{
   251  					Key:   aws.String("access_logs.s3.enabled"),
   252  					Value: aws.String("true"),
   253  				},
   254  				&elbv2.LoadBalancerAttribute{
   255  					Key:   aws.String("access_logs.s3.bucket"),
   256  					Value: aws.String(log["bucket"].(string)),
   257  				})
   258  
   259  			if prefix, ok := log["prefix"]; ok {
   260  				attributes = append(attributes, &elbv2.LoadBalancerAttribute{
   261  					Key:   aws.String("access_logs.s3.prefix"),
   262  					Value: aws.String(prefix.(string)),
   263  				})
   264  			}
   265  		} else if len(logs) == 0 {
   266  			attributes = append(attributes, &elbv2.LoadBalancerAttribute{
   267  				Key:   aws.String("access_logs.s3.enabled"),
   268  				Value: aws.String("false"),
   269  			})
   270  		}
   271  	}
   272  
   273  	if d.HasChange("enable_deletion_protection") {
   274  		attributes = append(attributes, &elbv2.LoadBalancerAttribute{
   275  			Key:   aws.String("deletion_protection.enabled"),
   276  			Value: aws.String(fmt.Sprintf("%t", d.Get("enable_deletion_protection").(bool))),
   277  		})
   278  	}
   279  
   280  	if d.HasChange("idle_timeout") {
   281  		attributes = append(attributes, &elbv2.LoadBalancerAttribute{
   282  			Key:   aws.String("idle_timeout.timeout_seconds"),
   283  			Value: aws.String(fmt.Sprintf("%d", d.Get("idle_timeout").(int))),
   284  		})
   285  	}
   286  
   287  	if len(attributes) != 0 {
   288  		input := &elbv2.ModifyLoadBalancerAttributesInput{
   289  			LoadBalancerArn: aws.String(d.Id()),
   290  			Attributes:      attributes,
   291  		}
   292  
   293  		log.Printf("[DEBUG] ALB Modify Load Balancer Attributes Request: %#v", input)
   294  		_, err := elbconn.ModifyLoadBalancerAttributes(input)
   295  		if err != nil {
   296  			return fmt.Errorf("Failure configuring ALB attributes: %s", err)
   297  		}
   298  	}
   299  
   300  	return resourceAwsAlbRead(d, meta)
   301  }
   302  
   303  func resourceAwsAlbDelete(d *schema.ResourceData, meta interface{}) error {
   304  	albconn := meta.(*AWSClient).elbv2conn
   305  
   306  	log.Printf("[INFO] Deleting ALB: %s", d.Id())
   307  
   308  	// Destroy the load balancer
   309  	deleteElbOpts := elbv2.DeleteLoadBalancerInput{
   310  		LoadBalancerArn: aws.String(d.Id()),
   311  	}
   312  	if _, err := albconn.DeleteLoadBalancer(&deleteElbOpts); err != nil {
   313  		return fmt.Errorf("Error deleting ALB: %s", err)
   314  	}
   315  
   316  	return nil
   317  }
   318  
   319  // flattenSubnetsFromAvailabilityZones creates a slice of strings containing the subnet IDs
   320  // for the ALB based on the AvailabilityZones structure returned by the API.
   321  func flattenSubnetsFromAvailabilityZones(availabilityZones []*elbv2.AvailabilityZone) []string {
   322  	var result []string
   323  	for _, az := range availabilityZones {
   324  		result = append(result, *az.SubnetId)
   325  	}
   326  	return result
   327  }