github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/builtin/providers/aws/resource_aws_elb.go (about)

     1  package aws
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"regexp"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/aws/aws-sdk-go/aws"
    12  	"github.com/aws/aws-sdk-go/aws/awserr"
    13  	"github.com/aws/aws-sdk-go/service/ec2"
    14  	"github.com/aws/aws-sdk-go/service/elb"
    15  	"github.com/hashicorp/terraform/helper/hashcode"
    16  	"github.com/hashicorp/terraform/helper/resource"
    17  	"github.com/hashicorp/terraform/helper/schema"
    18  )
    19  
    20  func resourceAwsElb() *schema.Resource {
    21  	return &schema.Resource{
    22  		Create: resourceAwsElbCreate,
    23  		Read:   resourceAwsElbRead,
    24  		Update: resourceAwsElbUpdate,
    25  		Delete: resourceAwsElbDelete,
    26  
    27  		Schema: map[string]*schema.Schema{
    28  			"name": &schema.Schema{
    29  				Type:         schema.TypeString,
    30  				Optional:     true,
    31  				Computed:     true,
    32  				ForceNew:     true,
    33  				ValidateFunc: validateElbName,
    34  			},
    35  
    36  			"internal": &schema.Schema{
    37  				Type:     schema.TypeBool,
    38  				Optional: true,
    39  				ForceNew: true,
    40  				Computed: true,
    41  			},
    42  
    43  			"cross_zone_load_balancing": &schema.Schema{
    44  				Type:     schema.TypeBool,
    45  				Optional: true,
    46  			},
    47  
    48  			"availability_zones": &schema.Schema{
    49  				Type:     schema.TypeSet,
    50  				Elem:     &schema.Schema{Type: schema.TypeString},
    51  				Optional: true,
    52  				ForceNew: true,
    53  				Computed: true,
    54  				Set:      schema.HashString,
    55  			},
    56  
    57  			"instances": &schema.Schema{
    58  				Type:     schema.TypeSet,
    59  				Elem:     &schema.Schema{Type: schema.TypeString},
    60  				Optional: true,
    61  				Computed: true,
    62  				Set:      schema.HashString,
    63  			},
    64  
    65  			"security_groups": &schema.Schema{
    66  				Type:     schema.TypeSet,
    67  				Elem:     &schema.Schema{Type: schema.TypeString},
    68  				Optional: true,
    69  				Computed: true,
    70  				Set:      schema.HashString,
    71  			},
    72  
    73  			"source_security_group": &schema.Schema{
    74  				Type:     schema.TypeString,
    75  				Optional: true,
    76  				Computed: true,
    77  			},
    78  
    79  			"source_security_group_id": &schema.Schema{
    80  				Type:     schema.TypeString,
    81  				Computed: true,
    82  			},
    83  
    84  			"subnets": &schema.Schema{
    85  				Type:     schema.TypeSet,
    86  				Elem:     &schema.Schema{Type: schema.TypeString},
    87  				Optional: true,
    88  				ForceNew: true,
    89  				Computed: true,
    90  				Set:      schema.HashString,
    91  			},
    92  
    93  			"idle_timeout": &schema.Schema{
    94  				Type:     schema.TypeInt,
    95  				Optional: true,
    96  				Default:  60,
    97  			},
    98  
    99  			"connection_draining": &schema.Schema{
   100  				Type:     schema.TypeBool,
   101  				Optional: true,
   102  				Default:  false,
   103  			},
   104  
   105  			"connection_draining_timeout": &schema.Schema{
   106  				Type:     schema.TypeInt,
   107  				Optional: true,
   108  				Default:  300,
   109  			},
   110  
   111  			"access_logs": &schema.Schema{
   112  				Type:     schema.TypeSet,
   113  				Optional: true,
   114  				Elem: &schema.Resource{
   115  					Schema: map[string]*schema.Schema{
   116  						"interval": &schema.Schema{
   117  							Type:     schema.TypeInt,
   118  							Optional: true,
   119  							Default:  60,
   120  						},
   121  						"bucket": &schema.Schema{
   122  							Type:     schema.TypeString,
   123  							Required: true,
   124  						},
   125  						"bucket_prefix": &schema.Schema{
   126  							Type:     schema.TypeString,
   127  							Optional: true,
   128  						},
   129  					},
   130  				},
   131  				Set: resourceAwsElbAccessLogsHash,
   132  			},
   133  
   134  			"listener": &schema.Schema{
   135  				Type:     schema.TypeSet,
   136  				Required: true,
   137  				Elem: &schema.Resource{
   138  					Schema: map[string]*schema.Schema{
   139  						"instance_port": &schema.Schema{
   140  							Type:     schema.TypeInt,
   141  							Required: true,
   142  						},
   143  
   144  						"instance_protocol": &schema.Schema{
   145  							Type:     schema.TypeString,
   146  							Required: true,
   147  						},
   148  
   149  						"lb_port": &schema.Schema{
   150  							Type:     schema.TypeInt,
   151  							Required: true,
   152  						},
   153  
   154  						"lb_protocol": &schema.Schema{
   155  							Type:     schema.TypeString,
   156  							Required: true,
   157  						},
   158  
   159  						"ssl_certificate_id": &schema.Schema{
   160  							Type:     schema.TypeString,
   161  							Optional: true,
   162  						},
   163  					},
   164  				},
   165  				Set: resourceAwsElbListenerHash,
   166  			},
   167  
   168  			"health_check": &schema.Schema{
   169  				Type:     schema.TypeSet,
   170  				Optional: true,
   171  				Computed: true,
   172  				Elem: &schema.Resource{
   173  					Schema: map[string]*schema.Schema{
   174  						"healthy_threshold": &schema.Schema{
   175  							Type:     schema.TypeInt,
   176  							Required: true,
   177  						},
   178  
   179  						"unhealthy_threshold": &schema.Schema{
   180  							Type:     schema.TypeInt,
   181  							Required: true,
   182  						},
   183  
   184  						"target": &schema.Schema{
   185  							Type:     schema.TypeString,
   186  							Required: true,
   187  						},
   188  
   189  						"interval": &schema.Schema{
   190  							Type:     schema.TypeInt,
   191  							Required: true,
   192  						},
   193  
   194  						"timeout": &schema.Schema{
   195  							Type:     schema.TypeInt,
   196  							Required: true,
   197  						},
   198  					},
   199  				},
   200  				Set: resourceAwsElbHealthCheckHash,
   201  			},
   202  
   203  			"dns_name": &schema.Schema{
   204  				Type:     schema.TypeString,
   205  				Computed: true,
   206  			},
   207  
   208  			"zone_id": &schema.Schema{
   209  				Type:     schema.TypeString,
   210  				Computed: true,
   211  			},
   212  
   213  			"tags": tagsSchema(),
   214  		},
   215  	}
   216  }
   217  
   218  func resourceAwsElbCreate(d *schema.ResourceData, meta interface{}) error {
   219  	elbconn := meta.(*AWSClient).elbconn
   220  
   221  	// Expand the "listener" set to aws-sdk-go compat []*elb.Listener
   222  	listeners, err := expandListeners(d.Get("listener").(*schema.Set).List())
   223  	if err != nil {
   224  		return err
   225  	}
   226  
   227  	var elbName string
   228  	if v, ok := d.GetOk("name"); ok {
   229  		elbName = v.(string)
   230  	} else {
   231  		elbName = resource.PrefixedUniqueId("tf-lb-")
   232  		d.Set("name", elbName)
   233  	}
   234  
   235  	tags := tagsFromMapELB(d.Get("tags").(map[string]interface{}))
   236  	// Provision the elb
   237  	elbOpts := &elb.CreateLoadBalancerInput{
   238  		LoadBalancerName: aws.String(elbName),
   239  		Listeners:        listeners,
   240  		Tags:             tags,
   241  	}
   242  
   243  	if scheme, ok := d.GetOk("internal"); ok && scheme.(bool) {
   244  		elbOpts.Scheme = aws.String("internal")
   245  	}
   246  
   247  	if v, ok := d.GetOk("availability_zones"); ok {
   248  		elbOpts.AvailabilityZones = expandStringList(v.(*schema.Set).List())
   249  	}
   250  
   251  	if v, ok := d.GetOk("security_groups"); ok {
   252  		elbOpts.SecurityGroups = expandStringList(v.(*schema.Set).List())
   253  	}
   254  
   255  	if v, ok := d.GetOk("subnets"); ok {
   256  		elbOpts.Subnets = expandStringList(v.(*schema.Set).List())
   257  	}
   258  
   259  	log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts)
   260  	err = resource.Retry(1*time.Minute, func() error {
   261  		_, err := elbconn.CreateLoadBalancer(elbOpts)
   262  
   263  		if err != nil {
   264  			if awsErr, ok := err.(awserr.Error); ok {
   265  				// Check for IAM SSL Cert error, eventual consistancy issue
   266  				if awsErr.Code() == "CertificateNotFound" {
   267  					return fmt.Errorf("[WARN] Error creating ELB Listener with SSL Cert, retrying: %s", err)
   268  				}
   269  			}
   270  			return resource.RetryError{Err: err}
   271  		}
   272  		return nil
   273  	})
   274  
   275  	if err != nil {
   276  		return err
   277  	}
   278  
   279  	// Assign the elb's unique identifier for use later
   280  	d.SetId(elbName)
   281  	log.Printf("[INFO] ELB ID: %s", d.Id())
   282  
   283  	// Enable partial mode and record what we set
   284  	d.Partial(true)
   285  	d.SetPartial("name")
   286  	d.SetPartial("internal")
   287  	d.SetPartial("availability_zones")
   288  	d.SetPartial("listener")
   289  	d.SetPartial("security_groups")
   290  	d.SetPartial("subnets")
   291  
   292  	d.Set("tags", tagsToMapELB(tags))
   293  
   294  	return resourceAwsElbUpdate(d, meta)
   295  }
   296  
   297  func resourceAwsElbRead(d *schema.ResourceData, meta interface{}) error {
   298  	elbconn := meta.(*AWSClient).elbconn
   299  	elbName := d.Id()
   300  
   301  	// Retrieve the ELB properties for updating the state
   302  	describeElbOpts := &elb.DescribeLoadBalancersInput{
   303  		LoadBalancerNames: []*string{aws.String(elbName)},
   304  	}
   305  
   306  	describeResp, err := elbconn.DescribeLoadBalancers(describeElbOpts)
   307  	if err != nil {
   308  		if isLoadBalancerNotFound(err) {
   309  			// The ELB is gone now, so just remove it from the state
   310  			d.SetId("")
   311  			return nil
   312  		}
   313  
   314  		return fmt.Errorf("Error retrieving ELB: %s", err)
   315  	}
   316  	if len(describeResp.LoadBalancerDescriptions) != 1 {
   317  		return fmt.Errorf("Unable to find ELB: %#v", describeResp.LoadBalancerDescriptions)
   318  	}
   319  
   320  	describeAttrsOpts := &elb.DescribeLoadBalancerAttributesInput{
   321  		LoadBalancerName: aws.String(elbName),
   322  	}
   323  	describeAttrsResp, err := elbconn.DescribeLoadBalancerAttributes(describeAttrsOpts)
   324  	if err != nil {
   325  		if isLoadBalancerNotFound(err) {
   326  			// The ELB is gone now, so just remove it from the state
   327  			d.SetId("")
   328  			return nil
   329  		}
   330  
   331  		return fmt.Errorf("Error retrieving ELB: %s", err)
   332  	}
   333  
   334  	lbAttrs := describeAttrsResp.LoadBalancerAttributes
   335  
   336  	lb := describeResp.LoadBalancerDescriptions[0]
   337  
   338  	d.Set("name", *lb.LoadBalancerName)
   339  	d.Set("dns_name", *lb.DNSName)
   340  	d.Set("zone_id", *lb.CanonicalHostedZoneNameID)
   341  	d.Set("internal", *lb.Scheme == "internal")
   342  	d.Set("availability_zones", lb.AvailabilityZones)
   343  	d.Set("instances", flattenInstances(lb.Instances))
   344  	d.Set("listener", flattenListeners(lb.ListenerDescriptions))
   345  	d.Set("security_groups", lb.SecurityGroups)
   346  	if lb.SourceSecurityGroup != nil {
   347  		d.Set("source_security_group", lb.SourceSecurityGroup.GroupName)
   348  
   349  		// Manually look up the ELB Security Group ID, since it's not provided
   350  		var elbVpc string
   351  		if lb.VPCId != nil {
   352  			elbVpc = *lb.VPCId
   353  			sgId, err := sourceSGIdByName(meta, *lb.SourceSecurityGroup.GroupName, elbVpc)
   354  			if err != nil {
   355  				return fmt.Errorf("[WARN] Error looking up ELB Security Group ID: %s", err)
   356  			} else {
   357  				d.Set("source_security_group_id", sgId)
   358  			}
   359  		}
   360  	}
   361  	d.Set("subnets", lb.Subnets)
   362  	d.Set("idle_timeout", lbAttrs.ConnectionSettings.IdleTimeout)
   363  	d.Set("connection_draining", lbAttrs.ConnectionDraining.Enabled)
   364  	d.Set("connection_draining_timeout", lbAttrs.ConnectionDraining.Timeout)
   365  	if lbAttrs.AccessLog != nil {
   366  		if err := d.Set("access_logs", flattenAccessLog(lbAttrs.AccessLog)); err != nil {
   367  			return err
   368  		}
   369  	}
   370  
   371  	resp, err := elbconn.DescribeTags(&elb.DescribeTagsInput{
   372  		LoadBalancerNames: []*string{lb.LoadBalancerName},
   373  	})
   374  
   375  	var et []*elb.Tag
   376  	if len(resp.TagDescriptions) > 0 {
   377  		et = resp.TagDescriptions[0].Tags
   378  	}
   379  	d.Set("tags", tagsToMapELB(et))
   380  	// There's only one health check, so save that to state as we
   381  	// currently can
   382  	if *lb.HealthCheck.Target != "" {
   383  		d.Set("health_check", flattenHealthCheck(lb.HealthCheck))
   384  	}
   385  
   386  	return nil
   387  }
   388  
   389  func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error {
   390  	elbconn := meta.(*AWSClient).elbconn
   391  
   392  	d.Partial(true)
   393  
   394  	if d.HasChange("listener") {
   395  		o, n := d.GetChange("listener")
   396  		os := o.(*schema.Set)
   397  		ns := n.(*schema.Set)
   398  
   399  		remove, _ := expandListeners(os.Difference(ns).List())
   400  		add, _ := expandListeners(ns.Difference(os).List())
   401  
   402  		if len(remove) > 0 {
   403  			ports := make([]*int64, 0, len(remove))
   404  			for _, listener := range remove {
   405  				ports = append(ports, listener.LoadBalancerPort)
   406  			}
   407  
   408  			deleteListenersOpts := &elb.DeleteLoadBalancerListenersInput{
   409  				LoadBalancerName:  aws.String(d.Id()),
   410  				LoadBalancerPorts: ports,
   411  			}
   412  
   413  			log.Printf("[DEBUG] ELB Delete Listeners opts: %s", deleteListenersOpts)
   414  			_, err := elbconn.DeleteLoadBalancerListeners(deleteListenersOpts)
   415  			if err != nil {
   416  				return fmt.Errorf("Failure removing outdated ELB listeners: %s", err)
   417  			}
   418  		}
   419  
   420  		if len(add) > 0 {
   421  			createListenersOpts := &elb.CreateLoadBalancerListenersInput{
   422  				LoadBalancerName: aws.String(d.Id()),
   423  				Listeners:        add,
   424  			}
   425  
   426  			log.Printf("[DEBUG] ELB Create Listeners opts: %s", createListenersOpts)
   427  			_, err := elbconn.CreateLoadBalancerListeners(createListenersOpts)
   428  			if err != nil {
   429  				return fmt.Errorf("Failure adding new or updated ELB listeners: %s", err)
   430  			}
   431  		}
   432  
   433  		d.SetPartial("listener")
   434  	}
   435  
   436  	// If we currently have instances, or did have instances,
   437  	// we want to figure out what to add and remove from the load
   438  	// balancer
   439  	if d.HasChange("instances") {
   440  		o, n := d.GetChange("instances")
   441  		os := o.(*schema.Set)
   442  		ns := n.(*schema.Set)
   443  		remove := expandInstanceString(os.Difference(ns).List())
   444  		add := expandInstanceString(ns.Difference(os).List())
   445  
   446  		if len(add) > 0 {
   447  			registerInstancesOpts := elb.RegisterInstancesWithLoadBalancerInput{
   448  				LoadBalancerName: aws.String(d.Id()),
   449  				Instances:        add,
   450  			}
   451  
   452  			_, err := elbconn.RegisterInstancesWithLoadBalancer(&registerInstancesOpts)
   453  			if err != nil {
   454  				return fmt.Errorf("Failure registering instances with ELB: %s", err)
   455  			}
   456  		}
   457  		if len(remove) > 0 {
   458  			deRegisterInstancesOpts := elb.DeregisterInstancesFromLoadBalancerInput{
   459  				LoadBalancerName: aws.String(d.Id()),
   460  				Instances:        remove,
   461  			}
   462  
   463  			_, err := elbconn.DeregisterInstancesFromLoadBalancer(&deRegisterInstancesOpts)
   464  			if err != nil {
   465  				return fmt.Errorf("Failure deregistering instances from ELB: %s", err)
   466  			}
   467  		}
   468  
   469  		d.SetPartial("instances")
   470  	}
   471  
   472  	if d.HasChange("cross_zone_load_balancing") || d.HasChange("idle_timeout") || d.HasChange("access_logs") {
   473  		attrs := elb.ModifyLoadBalancerAttributesInput{
   474  			LoadBalancerName: aws.String(d.Get("name").(string)),
   475  			LoadBalancerAttributes: &elb.LoadBalancerAttributes{
   476  				CrossZoneLoadBalancing: &elb.CrossZoneLoadBalancing{
   477  					Enabled: aws.Bool(d.Get("cross_zone_load_balancing").(bool)),
   478  				},
   479  				ConnectionSettings: &elb.ConnectionSettings{
   480  					IdleTimeout: aws.Int64(int64(d.Get("idle_timeout").(int))),
   481  				},
   482  			},
   483  		}
   484  
   485  		logs := d.Get("access_logs").(*schema.Set).List()
   486  		if len(logs) > 1 {
   487  			return fmt.Errorf("Only one access logs config per ELB is supported")
   488  		} else if len(logs) == 1 {
   489  			log := logs[0].(map[string]interface{})
   490  			accessLog := &elb.AccessLog{
   491  				Enabled:      aws.Bool(true),
   492  				EmitInterval: aws.Int64(int64(log["interval"].(int))),
   493  				S3BucketName: aws.String(log["bucket"].(string)),
   494  			}
   495  
   496  			if log["bucket_prefix"] != "" {
   497  				accessLog.S3BucketPrefix = aws.String(log["bucket_prefix"].(string))
   498  			}
   499  
   500  			attrs.LoadBalancerAttributes.AccessLog = accessLog
   501  		} else if len(logs) == 0 {
   502  			// disable access logs
   503  			attrs.LoadBalancerAttributes.AccessLog = &elb.AccessLog{
   504  				Enabled: aws.Bool(false),
   505  			}
   506  		}
   507  
   508  		log.Printf("[DEBUG] ELB Modify Load Balancer Attributes Request: %#v", attrs)
   509  		_, err := elbconn.ModifyLoadBalancerAttributes(&attrs)
   510  		if err != nil {
   511  			return fmt.Errorf("Failure configuring ELB attributes: %s", err)
   512  		}
   513  
   514  		d.SetPartial("cross_zone_load_balancing")
   515  		d.SetPartial("idle_timeout")
   516  		d.SetPartial("connection_draining_timeout")
   517  	}
   518  
   519  	// We have to do these changes separately from everything else since
   520  	// they have some weird undocumented rules. You can't set the timeout
   521  	// without having connection draining to true, so we set that to true,
   522  	// set the timeout, then reset it to false if requested.
   523  	if d.HasChange("connection_draining") || d.HasChange("connection_draining_timeout") {
   524  		// We do timeout changes first since they require us to set draining
   525  		// to true for a hot second.
   526  		if d.HasChange("connection_draining_timeout") {
   527  			attrs := elb.ModifyLoadBalancerAttributesInput{
   528  				LoadBalancerName: aws.String(d.Get("name").(string)),
   529  				LoadBalancerAttributes: &elb.LoadBalancerAttributes{
   530  					ConnectionDraining: &elb.ConnectionDraining{
   531  						Enabled: aws.Bool(true),
   532  						Timeout: aws.Int64(int64(d.Get("connection_draining_timeout").(int))),
   533  					},
   534  				},
   535  			}
   536  
   537  			_, err := elbconn.ModifyLoadBalancerAttributes(&attrs)
   538  			if err != nil {
   539  				return fmt.Errorf("Failure configuring ELB attributes: %s", err)
   540  			}
   541  
   542  			d.SetPartial("connection_draining_timeout")
   543  		}
   544  
   545  		// Then we always set connection draining even if there is no change.
   546  		// This lets us reset to "false" if requested even with a timeout
   547  		// change.
   548  		attrs := elb.ModifyLoadBalancerAttributesInput{
   549  			LoadBalancerName: aws.String(d.Get("name").(string)),
   550  			LoadBalancerAttributes: &elb.LoadBalancerAttributes{
   551  				ConnectionDraining: &elb.ConnectionDraining{
   552  					Enabled: aws.Bool(d.Get("connection_draining").(bool)),
   553  				},
   554  			},
   555  		}
   556  
   557  		_, err := elbconn.ModifyLoadBalancerAttributes(&attrs)
   558  		if err != nil {
   559  			return fmt.Errorf("Failure configuring ELB attributes: %s", err)
   560  		}
   561  
   562  		d.SetPartial("connection_draining")
   563  	}
   564  
   565  	if d.HasChange("health_check") {
   566  		vs := d.Get("health_check").(*schema.Set).List()
   567  		if len(vs) > 0 {
   568  			check := vs[0].(map[string]interface{})
   569  			configureHealthCheckOpts := elb.ConfigureHealthCheckInput{
   570  				LoadBalancerName: aws.String(d.Id()),
   571  				HealthCheck: &elb.HealthCheck{
   572  					HealthyThreshold:   aws.Int64(int64(check["healthy_threshold"].(int))),
   573  					UnhealthyThreshold: aws.Int64(int64(check["unhealthy_threshold"].(int))),
   574  					Interval:           aws.Int64(int64(check["interval"].(int))),
   575  					Target:             aws.String(check["target"].(string)),
   576  					Timeout:            aws.Int64(int64(check["timeout"].(int))),
   577  				},
   578  			}
   579  			_, err := elbconn.ConfigureHealthCheck(&configureHealthCheckOpts)
   580  			if err != nil {
   581  				return fmt.Errorf("Failure configuring health check for ELB: %s", err)
   582  			}
   583  			d.SetPartial("health_check")
   584  		}
   585  	}
   586  
   587  	if d.HasChange("security_groups") {
   588  		groups := d.Get("security_groups").(*schema.Set).List()
   589  
   590  		applySecurityGroupsOpts := elb.ApplySecurityGroupsToLoadBalancerInput{
   591  			LoadBalancerName: aws.String(d.Id()),
   592  			SecurityGroups:   expandStringList(groups),
   593  		}
   594  
   595  		_, err := elbconn.ApplySecurityGroupsToLoadBalancer(&applySecurityGroupsOpts)
   596  		if err != nil {
   597  			return fmt.Errorf("Failure applying security groups to ELB: %s", err)
   598  		}
   599  
   600  		d.SetPartial("security_groups")
   601  	}
   602  
   603  	if err := setTagsELB(elbconn, d); err != nil {
   604  		return err
   605  	}
   606  
   607  	d.SetPartial("tags")
   608  	d.Partial(false)
   609  
   610  	return resourceAwsElbRead(d, meta)
   611  }
   612  
   613  func resourceAwsElbDelete(d *schema.ResourceData, meta interface{}) error {
   614  	elbconn := meta.(*AWSClient).elbconn
   615  
   616  	log.Printf("[INFO] Deleting ELB: %s", d.Id())
   617  
   618  	// Destroy the load balancer
   619  	deleteElbOpts := elb.DeleteLoadBalancerInput{
   620  		LoadBalancerName: aws.String(d.Id()),
   621  	}
   622  	if _, err := elbconn.DeleteLoadBalancer(&deleteElbOpts); err != nil {
   623  		return fmt.Errorf("Error deleting ELB: %s", err)
   624  	}
   625  
   626  	return nil
   627  }
   628  
   629  func resourceAwsElbHealthCheckHash(v interface{}) int {
   630  	var buf bytes.Buffer
   631  	m := v.(map[string]interface{})
   632  	buf.WriteString(fmt.Sprintf("%d-", m["healthy_threshold"].(int)))
   633  	buf.WriteString(fmt.Sprintf("%d-", m["unhealthy_threshold"].(int)))
   634  	buf.WriteString(fmt.Sprintf("%s-", m["target"].(string)))
   635  	buf.WriteString(fmt.Sprintf("%d-", m["interval"].(int)))
   636  	buf.WriteString(fmt.Sprintf("%d-", m["timeout"].(int)))
   637  
   638  	return hashcode.String(buf.String())
   639  }
   640  
   641  func resourceAwsElbAccessLogsHash(v interface{}) int {
   642  	var buf bytes.Buffer
   643  	m := v.(map[string]interface{})
   644  	buf.WriteString(fmt.Sprintf("%d-", m["interval"].(int)))
   645  	buf.WriteString(fmt.Sprintf("%s-",
   646  		strings.ToLower(m["bucket"].(string))))
   647  	if v, ok := m["bucket_prefix"]; ok {
   648  		buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(v.(string))))
   649  	}
   650  
   651  	return hashcode.String(buf.String())
   652  }
   653  
   654  func resourceAwsElbListenerHash(v interface{}) int {
   655  	var buf bytes.Buffer
   656  	m := v.(map[string]interface{})
   657  	buf.WriteString(fmt.Sprintf("%d-", m["instance_port"].(int)))
   658  	buf.WriteString(fmt.Sprintf("%s-",
   659  		strings.ToLower(m["instance_protocol"].(string))))
   660  	buf.WriteString(fmt.Sprintf("%d-", m["lb_port"].(int)))
   661  	buf.WriteString(fmt.Sprintf("%s-",
   662  		strings.ToLower(m["lb_protocol"].(string))))
   663  
   664  	if v, ok := m["ssl_certificate_id"]; ok {
   665  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   666  	}
   667  
   668  	return hashcode.String(buf.String())
   669  }
   670  
   671  func isLoadBalancerNotFound(err error) bool {
   672  	elberr, ok := err.(awserr.Error)
   673  	return ok && elberr.Code() == "LoadBalancerNotFound"
   674  }
   675  
   676  func validateElbName(v interface{}, k string) (ws []string, errors []error) {
   677  	value := v.(string)
   678  	if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
   679  		errors = append(errors, fmt.Errorf(
   680  			"only alphanumeric characters and hyphens allowed in %q: %q",
   681  			k, value))
   682  	}
   683  	if len(value) > 32 {
   684  		errors = append(errors, fmt.Errorf(
   685  			"%q cannot be longer than 32 characters: %q", k, value))
   686  	}
   687  	if regexp.MustCompile(`^-`).MatchString(value) {
   688  		errors = append(errors, fmt.Errorf(
   689  			"%q cannot begin with a hyphen: %q", k, value))
   690  	}
   691  	if regexp.MustCompile(`-$`).MatchString(value) {
   692  		errors = append(errors, fmt.Errorf(
   693  			"%q cannot end with a hyphen: %q", k, value))
   694  	}
   695  	return
   696  
   697  }
   698  
   699  func sourceSGIdByName(meta interface{}, sg, vpcId string) (string, error) {
   700  	conn := meta.(*AWSClient).ec2conn
   701  	var filters []*ec2.Filter
   702  	var sgFilterName, sgFilterVPCID *ec2.Filter
   703  	sgFilterName = &ec2.Filter{
   704  		Name:   aws.String("group-name"),
   705  		Values: []*string{aws.String(sg)},
   706  	}
   707  
   708  	if vpcId != "" {
   709  		sgFilterVPCID = &ec2.Filter{
   710  			Name:   aws.String("vpc-id"),
   711  			Values: []*string{aws.String(vpcId)},
   712  		}
   713  	}
   714  
   715  	filters = append(filters, sgFilterName)
   716  
   717  	if sgFilterVPCID != nil {
   718  		filters = append(filters, sgFilterVPCID)
   719  	}
   720  
   721  	req := &ec2.DescribeSecurityGroupsInput{
   722  		Filters: filters,
   723  	}
   724  	resp, err := conn.DescribeSecurityGroups(req)
   725  	if err != nil {
   726  		if ec2err, ok := err.(awserr.Error); ok {
   727  			if ec2err.Code() == "InvalidSecurityGroupID.NotFound" ||
   728  				ec2err.Code() == "InvalidGroup.NotFound" {
   729  				resp = nil
   730  				err = nil
   731  			}
   732  		}
   733  
   734  		if err != nil {
   735  			log.Printf("Error on ELB SG look up: %s", err)
   736  			return "", err
   737  		}
   738  	}
   739  
   740  	if resp == nil || len(resp.SecurityGroups) == 0 {
   741  		return "", fmt.Errorf("No security groups found for name %s and vpc id %s", sg, vpcId)
   742  	}
   743  
   744  	group := resp.SecurityGroups[0]
   745  	return *group.GroupId, nil
   746  }