github.com/ricardclau/terraform@v0.6.17-0.20160519222547-283e3ae6b5a9/builtin/providers/aws/resource_aws_elastic_beanstalk_environment.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"regexp"
     7  	"sort"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/hashicorp/terraform/helper/hashcode"
    12  	"github.com/hashicorp/terraform/helper/resource"
    13  	"github.com/hashicorp/terraform/helper/schema"
    14  
    15  	"github.com/aws/aws-sdk-go/aws"
    16  	"github.com/aws/aws-sdk-go/service/ec2"
    17  	"github.com/aws/aws-sdk-go/service/elasticbeanstalk"
    18  )
    19  
    20  func resourceAwsElasticBeanstalkOptionSetting() *schema.Resource {
    21  	return &schema.Resource{
    22  		Schema: map[string]*schema.Schema{
    23  			"namespace": &schema.Schema{
    24  				Type:     schema.TypeString,
    25  				Required: true,
    26  			},
    27  			"name": &schema.Schema{
    28  				Type:     schema.TypeString,
    29  				Required: true,
    30  			},
    31  			"value": &schema.Schema{
    32  				Type:     schema.TypeString,
    33  				Required: true,
    34  			},
    35  		},
    36  	}
    37  }
    38  
    39  func resourceAwsElasticBeanstalkEnvironment() *schema.Resource {
    40  	return &schema.Resource{
    41  		Create: resourceAwsElasticBeanstalkEnvironmentCreate,
    42  		Read:   resourceAwsElasticBeanstalkEnvironmentRead,
    43  		Update: resourceAwsElasticBeanstalkEnvironmentUpdate,
    44  		Delete: resourceAwsElasticBeanstalkEnvironmentDelete,
    45  
    46  		SchemaVersion: 1,
    47  		MigrateState:  resourceAwsElasticBeanstalkEnvironmentMigrateState,
    48  
    49  		Schema: map[string]*schema.Schema{
    50  			"name": &schema.Schema{
    51  				Type:     schema.TypeString,
    52  				Required: true,
    53  				ForceNew: true,
    54  			},
    55  			"application": &schema.Schema{
    56  				Type:     schema.TypeString,
    57  				Required: true,
    58  			},
    59  			"description": &schema.Schema{
    60  				Type:     schema.TypeString,
    61  				Optional: true,
    62  			},
    63  			"cname": &schema.Schema{
    64  				Type:     schema.TypeString,
    65  				Computed: true,
    66  			},
    67  			"cname_prefix": &schema.Schema{
    68  				Type:     schema.TypeString,
    69  				Computed: true,
    70  				Optional: true,
    71  				ForceNew: true,
    72  			},
    73  			"tier": &schema.Schema{
    74  				Type:     schema.TypeString,
    75  				Optional: true,
    76  				Default:  "WebServer",
    77  				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
    78  					value := v.(string)
    79  					switch value {
    80  					case
    81  						"Worker",
    82  						"WebServer":
    83  						return
    84  					}
    85  					errors = append(errors, fmt.Errorf("%s is not a valid tier. Valid options are WebServer or Worker", value))
    86  					return
    87  				},
    88  				ForceNew: true,
    89  			},
    90  			"setting": &schema.Schema{
    91  				Type:     schema.TypeSet,
    92  				Optional: true,
    93  				Computed: true,
    94  				Elem:     resourceAwsElasticBeanstalkOptionSetting(),
    95  				Set:      optionSettingValueHash,
    96  			},
    97  			"all_settings": &schema.Schema{
    98  				Type:     schema.TypeSet,
    99  				Computed: true,
   100  				Elem:     resourceAwsElasticBeanstalkOptionSetting(),
   101  				Set:      optionSettingValueHash,
   102  			},
   103  			"solution_stack_name": &schema.Schema{
   104  				Type:     schema.TypeString,
   105  				Optional: true,
   106  			},
   107  			"template_name": &schema.Schema{
   108  				Type:          schema.TypeString,
   109  				Optional:      true,
   110  				ConflictsWith: []string{"solution_stack_name"},
   111  			},
   112  			"wait_for_ready_timeout": &schema.Schema{
   113  				Type:     schema.TypeString,
   114  				Optional: true,
   115  				Default:  "10m",
   116  				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
   117  					value := v.(string)
   118  					duration, err := time.ParseDuration(value)
   119  					if err != nil {
   120  						errors = append(errors, fmt.Errorf(
   121  							"%q cannot be parsed as a duration: %s", k, err))
   122  					}
   123  					if duration < 0 {
   124  						errors = append(errors, fmt.Errorf(
   125  							"%q must be greater than zero", k))
   126  					}
   127  					return
   128  				},
   129  			},
   130  			"autoscaling_groups": &schema.Schema{
   131  				Type:     schema.TypeList,
   132  				Computed: true,
   133  				Elem:     &schema.Schema{Type: schema.TypeString},
   134  			},
   135  			"instances": &schema.Schema{
   136  				Type:     schema.TypeList,
   137  				Computed: true,
   138  				Elem:     &schema.Schema{Type: schema.TypeString},
   139  			},
   140  			"launch_configurations": &schema.Schema{
   141  				Type:     schema.TypeList,
   142  				Computed: true,
   143  				Elem:     &schema.Schema{Type: schema.TypeString},
   144  			},
   145  			"load_balancers": &schema.Schema{
   146  				Type:     schema.TypeList,
   147  				Computed: true,
   148  				Elem:     &schema.Schema{Type: schema.TypeString},
   149  			},
   150  			"queues": &schema.Schema{
   151  				Type:     schema.TypeList,
   152  				Computed: true,
   153  				Elem:     &schema.Schema{Type: schema.TypeString},
   154  			},
   155  			"triggers": &schema.Schema{
   156  				Type:     schema.TypeList,
   157  				Computed: true,
   158  				Elem:     &schema.Schema{Type: schema.TypeString},
   159  			},
   160  
   161  			"tags": tagsSchema(),
   162  		},
   163  	}
   164  }
   165  
   166  func resourceAwsElasticBeanstalkEnvironmentCreate(d *schema.ResourceData, meta interface{}) error {
   167  	conn := meta.(*AWSClient).elasticbeanstalkconn
   168  
   169  	// Get values from config
   170  	name := d.Get("name").(string)
   171  	cnamePrefix := d.Get("cname_prefix").(string)
   172  	tier := d.Get("tier").(string)
   173  	app := d.Get("application").(string)
   174  	desc := d.Get("description").(string)
   175  	settings := d.Get("setting").(*schema.Set)
   176  	solutionStack := d.Get("solution_stack_name").(string)
   177  	templateName := d.Get("template_name").(string)
   178  	waitForReadyTimeOut, err := time.ParseDuration(d.Get("wait_for_ready_timeout").(string))
   179  	if err != nil {
   180  		return err
   181  	}
   182  
   183  	// TODO set tags
   184  	// Note: at time of writing, you cannot view or edit Tags after creation
   185  	// d.Set("tags", tagsToMap(instance.Tags))
   186  	createOpts := elasticbeanstalk.CreateEnvironmentInput{
   187  		EnvironmentName: aws.String(name),
   188  		ApplicationName: aws.String(app),
   189  		OptionSettings:  extractOptionSettings(settings),
   190  		Tags:            tagsFromMapBeanstalk(d.Get("tags").(map[string]interface{})),
   191  	}
   192  
   193  	if desc != "" {
   194  		createOpts.Description = aws.String(desc)
   195  	}
   196  
   197  	if cnamePrefix != "" {
   198  		if tier != "WebServer" {
   199  			return fmt.Errorf("Cannont set cname_prefix for tier: %s.", tier)
   200  		}
   201  		createOpts.CNAMEPrefix = aws.String(cnamePrefix)
   202  	}
   203  
   204  	if tier != "" {
   205  		var tierType string
   206  
   207  		switch tier {
   208  		case "WebServer":
   209  			tierType = "Standard"
   210  		case "Worker":
   211  			tierType = "SQS/HTTP"
   212  		}
   213  		environmentTier := elasticbeanstalk.EnvironmentTier{
   214  			Name: aws.String(tier),
   215  			Type: aws.String(tierType),
   216  		}
   217  		createOpts.Tier = &environmentTier
   218  	}
   219  
   220  	if solutionStack != "" {
   221  		createOpts.SolutionStackName = aws.String(solutionStack)
   222  	}
   223  
   224  	if templateName != "" {
   225  		createOpts.TemplateName = aws.String(templateName)
   226  	}
   227  
   228  	log.Printf("[DEBUG] Elastic Beanstalk Environment create opts: %s", createOpts)
   229  	resp, err := conn.CreateEnvironment(&createOpts)
   230  	if err != nil {
   231  		return err
   232  	}
   233  
   234  	// Assign the application name as the resource ID
   235  	d.SetId(*resp.EnvironmentId)
   236  
   237  	stateConf := &resource.StateChangeConf{
   238  		Pending:    []string{"Launching", "Updating"},
   239  		Target:     []string{"Ready"},
   240  		Refresh:    environmentStateRefreshFunc(conn, d.Id()),
   241  		Timeout:    waitForReadyTimeOut,
   242  		Delay:      10 * time.Second,
   243  		MinTimeout: 3 * time.Second,
   244  	}
   245  
   246  	_, err = stateConf.WaitForState()
   247  	if err != nil {
   248  		return fmt.Errorf(
   249  			"Error waiting for Elastic Beanstalk Environment (%s) to become ready: %s",
   250  			d.Id(), err)
   251  	}
   252  
   253  	return resourceAwsElasticBeanstalkEnvironmentRead(d, meta)
   254  }
   255  
   256  func resourceAwsElasticBeanstalkEnvironmentUpdate(d *schema.ResourceData, meta interface{}) error {
   257  	conn := meta.(*AWSClient).elasticbeanstalkconn
   258  
   259  	envId := d.Id()
   260  	waitForReadyTimeOut, err := time.ParseDuration(d.Get("wait_for_ready_timeout").(string))
   261  	if err != nil {
   262  		return err
   263  	}
   264  
   265  	updateOpts := elasticbeanstalk.UpdateEnvironmentInput{
   266  		EnvironmentId: aws.String(envId),
   267  	}
   268  
   269  	if d.HasChange("description") {
   270  		updateOpts.Description = aws.String(d.Get("description").(string))
   271  	}
   272  
   273  	if d.HasChange("solution_stack_name") {
   274  		updateOpts.SolutionStackName = aws.String(d.Get("solution_stack_name").(string))
   275  	}
   276  
   277  	if d.HasChange("setting") {
   278  		o, n := d.GetChange("setting")
   279  		if o == nil {
   280  			o = &schema.Set{F: optionSettingValueHash}
   281  		}
   282  		if n == nil {
   283  			n = &schema.Set{F: optionSettingValueHash}
   284  		}
   285  
   286  		os := o.(*schema.Set)
   287  		ns := n.(*schema.Set)
   288  
   289  		updateOpts.OptionSettings = extractOptionSettings(ns.Difference(os))
   290  	}
   291  
   292  	if d.HasChange("template_name") {
   293  		updateOpts.TemplateName = aws.String(d.Get("template_name").(string))
   294  	}
   295  
   296  	log.Printf("[DEBUG] Elastic Beanstalk Environment update opts: %s", updateOpts)
   297  	_, err = conn.UpdateEnvironment(&updateOpts)
   298  	if err != nil {
   299  		return err
   300  	}
   301  
   302  	stateConf := &resource.StateChangeConf{
   303  		Pending:    []string{"Launching", "Updating"},
   304  		Target:     []string{"Ready"},
   305  		Refresh:    environmentStateRefreshFunc(conn, d.Id()),
   306  		Timeout:    waitForReadyTimeOut,
   307  		Delay:      10 * time.Second,
   308  		MinTimeout: 3 * time.Second,
   309  	}
   310  
   311  	_, err = stateConf.WaitForState()
   312  	if err != nil {
   313  		return fmt.Errorf(
   314  			"Error waiting for Elastic Beanstalk Environment (%s) to become ready: %s",
   315  			d.Id(), err)
   316  	}
   317  
   318  	return resourceAwsElasticBeanstalkEnvironmentRead(d, meta)
   319  }
   320  
   321  func resourceAwsElasticBeanstalkEnvironmentRead(d *schema.ResourceData, meta interface{}) error {
   322  	conn := meta.(*AWSClient).elasticbeanstalkconn
   323  
   324  	app := d.Get("application").(string)
   325  	envId := d.Id()
   326  	tier := d.Get("tier").(string)
   327  
   328  	log.Printf("[DEBUG] Elastic Beanstalk environment read %s: id %s", d.Get("name").(string), d.Id())
   329  
   330  	resp, err := conn.DescribeEnvironments(&elasticbeanstalk.DescribeEnvironmentsInput{
   331  		ApplicationName: aws.String(app),
   332  		EnvironmentIds:  []*string{aws.String(envId)},
   333  	})
   334  
   335  	if err != nil {
   336  		return err
   337  	}
   338  
   339  	if len(resp.Environments) == 0 {
   340  		log.Printf("[DEBUG] Elastic Beanstalk environment properties: could not find environment %s", d.Id())
   341  
   342  		d.SetId("")
   343  		return nil
   344  	} else if len(resp.Environments) != 1 {
   345  		return fmt.Errorf("Error reading application properties: found %d environments, expected 1", len(resp.Environments))
   346  	}
   347  
   348  	env := resp.Environments[0]
   349  
   350  	if *env.Status == "Terminated" {
   351  		log.Printf("[DEBUG] Elastic Beanstalk environment %s was terminated", d.Id())
   352  
   353  		d.SetId("")
   354  		return nil
   355  	}
   356  
   357  	resources, err := conn.DescribeEnvironmentResources(&elasticbeanstalk.DescribeEnvironmentResourcesInput{
   358  		EnvironmentId: aws.String(envId),
   359  	})
   360  
   361  	if err != nil {
   362  		return err
   363  	}
   364  
   365  	if err := d.Set("description", env.Description); err != nil {
   366  		return err
   367  	}
   368  
   369  	if err := d.Set("cname", env.CNAME); err != nil {
   370  		return err
   371  	}
   372  
   373  	if tier == "WebServer" {
   374  		beanstalkCnamePrefixRegexp := regexp.MustCompile(`(^[^.]+).\w{2}-\w{4,9}-\d.elasticbeanstalk.com$`)
   375  		var cnamePrefix string
   376  		cnamePrefixMatch := beanstalkCnamePrefixRegexp.FindStringSubmatch(*env.CNAME)
   377  
   378  		if cnamePrefixMatch == nil {
   379  			cnamePrefix = ""
   380  		} else {
   381  			cnamePrefix = cnamePrefixMatch[1]
   382  		}
   383  
   384  		if err := d.Set("cname_prefix", cnamePrefix); err != nil {
   385  			return err
   386  		}
   387  	}
   388  
   389  	if err := d.Set("autoscaling_groups", flattenBeanstalkAsg(resources.EnvironmentResources.AutoScalingGroups)); err != nil {
   390  		return err
   391  	}
   392  
   393  	if err := d.Set("instances", flattenBeanstalkInstances(resources.EnvironmentResources.Instances)); err != nil {
   394  		return err
   395  	}
   396  	if err := d.Set("launch_configurations", flattenBeanstalkLc(resources.EnvironmentResources.LaunchConfigurations)); err != nil {
   397  		return err
   398  	}
   399  	if err := d.Set("load_balancers", flattenBeanstalkElb(resources.EnvironmentResources.LoadBalancers)); err != nil {
   400  		return err
   401  	}
   402  	if err := d.Set("queues", flattenBeanstalkSqs(resources.EnvironmentResources.Queues)); err != nil {
   403  		return err
   404  	}
   405  	if err := d.Set("triggers", flattenBeanstalkTrigger(resources.EnvironmentResources.Triggers)); err != nil {
   406  		return err
   407  	}
   408  
   409  	return resourceAwsElasticBeanstalkEnvironmentSettingsRead(d, meta)
   410  }
   411  
   412  func fetchAwsElasticBeanstalkEnvironmentSettings(d *schema.ResourceData, meta interface{}) (*schema.Set, error) {
   413  	conn := meta.(*AWSClient).elasticbeanstalkconn
   414  
   415  	app := d.Get("application").(string)
   416  	name := d.Get("name").(string)
   417  
   418  	resp, err := conn.DescribeConfigurationSettings(&elasticbeanstalk.DescribeConfigurationSettingsInput{
   419  		ApplicationName: aws.String(app),
   420  		EnvironmentName: aws.String(name),
   421  	})
   422  
   423  	if err != nil {
   424  		return nil, err
   425  	}
   426  
   427  	if len(resp.ConfigurationSettings) != 1 {
   428  		return nil, fmt.Errorf("Error reading environment settings: received %d settings groups, expected 1", len(resp.ConfigurationSettings))
   429  	}
   430  
   431  	settings := &schema.Set{F: optionSettingValueHash}
   432  	for _, optionSetting := range resp.ConfigurationSettings[0].OptionSettings {
   433  		m := map[string]interface{}{}
   434  
   435  		if optionSetting.Namespace != nil {
   436  			m["namespace"] = *optionSetting.Namespace
   437  		} else {
   438  			return nil, fmt.Errorf("Error reading environment settings: option setting with no namespace: %v", optionSetting)
   439  		}
   440  
   441  		if optionSetting.OptionName != nil {
   442  			m["name"] = *optionSetting.OptionName
   443  		} else {
   444  			return nil, fmt.Errorf("Error reading environment settings: option setting with no name: %v", optionSetting)
   445  		}
   446  
   447  		if optionSetting.Value != nil {
   448  			switch *optionSetting.OptionName {
   449  			case "SecurityGroups":
   450  				m["value"] = dropGeneratedSecurityGroup(*optionSetting.Value, meta)
   451  			case "Subnets", "ELBSubnets":
   452  				m["value"] = sortValues(*optionSetting.Value)
   453  			default:
   454  				m["value"] = *optionSetting.Value
   455  			}
   456  		}
   457  
   458  		settings.Add(m)
   459  	}
   460  
   461  	return settings, nil
   462  }
   463  
   464  func resourceAwsElasticBeanstalkEnvironmentSettingsRead(d *schema.ResourceData, meta interface{}) error {
   465  	log.Printf("[DEBUG] Elastic Beanstalk environment settings read %s: id %s", d.Get("name").(string), d.Id())
   466  
   467  	allSettings, err := fetchAwsElasticBeanstalkEnvironmentSettings(d, meta)
   468  	if err != nil {
   469  		return err
   470  	}
   471  
   472  	settings := d.Get("setting").(*schema.Set)
   473  
   474  	log.Printf("[DEBUG] Elastic Beanstalk allSettings: %s", allSettings.GoString())
   475  	log.Printf("[DEBUG] Elastic Beanstalk settings: %s", settings.GoString())
   476  
   477  	// perform the set operation with only name/namespace as keys, excluding value
   478  	// this is so we override things in the settings resource data key with updated values
   479  	// from the api.  we skip values we didn't know about before because there are so many
   480  	// defaults set by the eb api that we would delete many useful defaults.
   481  	//
   482  	// there is likely a better way to do this
   483  	allSettingsKeySet := schema.NewSet(optionSettingKeyHash, allSettings.List())
   484  	settingsKeySet := schema.NewSet(optionSettingKeyHash, settings.List())
   485  	updatedSettingsKeySet := allSettingsKeySet.Intersection(settingsKeySet)
   486  
   487  	log.Printf("[DEBUG] Elastic Beanstalk updatedSettingsKeySet: %s", updatedSettingsKeySet.GoString())
   488  
   489  	updatedSettings := schema.NewSet(optionSettingValueHash, updatedSettingsKeySet.List())
   490  
   491  	log.Printf("[DEBUG] Elastic Beanstalk updatedSettings: %s", updatedSettings.GoString())
   492  
   493  	if err := d.Set("all_settings", allSettings.List()); err != nil {
   494  		return err
   495  	}
   496  
   497  	if err := d.Set("setting", updatedSettings.List()); err != nil {
   498  		return err
   499  	}
   500  
   501  	return nil
   502  }
   503  
   504  func resourceAwsElasticBeanstalkEnvironmentDelete(d *schema.ResourceData, meta interface{}) error {
   505  	conn := meta.(*AWSClient).elasticbeanstalkconn
   506  
   507  	waitForReadyTimeOut, err := time.ParseDuration(d.Get("wait_for_ready_timeout").(string))
   508  	if err != nil {
   509  		return err
   510  	}
   511  
   512  	opts := elasticbeanstalk.TerminateEnvironmentInput{
   513  		EnvironmentId:      aws.String(d.Id()),
   514  		TerminateResources: aws.Bool(true),
   515  	}
   516  
   517  	log.Printf("[DEBUG] Elastic Beanstalk Environment terminate opts: %s", opts)
   518  	_, err = conn.TerminateEnvironment(&opts)
   519  
   520  	if err != nil {
   521  		return err
   522  	}
   523  
   524  	stateConf := &resource.StateChangeConf{
   525  		Pending:    []string{"Terminating"},
   526  		Target:     []string{"Terminated"},
   527  		Refresh:    environmentStateRefreshFunc(conn, d.Id()),
   528  		Timeout:    waitForReadyTimeOut,
   529  		Delay:      10 * time.Second,
   530  		MinTimeout: 3 * time.Second,
   531  	}
   532  
   533  	_, err = stateConf.WaitForState()
   534  	if err != nil {
   535  		return fmt.Errorf(
   536  			"Error waiting for Elastic Beanstalk Environment (%s) to become terminated: %s",
   537  			d.Id(), err)
   538  	}
   539  
   540  	return nil
   541  }
   542  
   543  // environmentStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
   544  // the creation of the Beanstalk Environment
   545  func environmentStateRefreshFunc(conn *elasticbeanstalk.ElasticBeanstalk, environmentId string) resource.StateRefreshFunc {
   546  	return func() (interface{}, string, error) {
   547  		resp, err := conn.DescribeEnvironments(&elasticbeanstalk.DescribeEnvironmentsInput{
   548  			EnvironmentIds: []*string{aws.String(environmentId)},
   549  		})
   550  		if err != nil {
   551  			log.Printf("[Err] Error waiting for Elastic Beanstalk Environment state: %s", err)
   552  			return -1, "failed", fmt.Errorf("[Err] Error waiting for Elastic Beanstalk Environment state: %s", err)
   553  		}
   554  
   555  		if resp == nil || len(resp.Environments) == 0 {
   556  			// Sometimes AWS just has consistency issues and doesn't see
   557  			// our instance yet. Return an empty state.
   558  			return nil, "", nil
   559  		}
   560  
   561  		var env *elasticbeanstalk.EnvironmentDescription
   562  		for _, e := range resp.Environments {
   563  			if environmentId == *e.EnvironmentId {
   564  				env = e
   565  			}
   566  		}
   567  
   568  		if env == nil {
   569  			return -1, "failed", fmt.Errorf("[Err] Error finding Elastic Beanstalk Environment, environment not found")
   570  		}
   571  
   572  		return env, *env.Status, nil
   573  	}
   574  }
   575  
   576  // we use the following two functions to allow us to split out defaults
   577  // as they become overridden from within the template
   578  func optionSettingValueHash(v interface{}) int {
   579  	rd := v.(map[string]interface{})
   580  	namespace := rd["namespace"].(string)
   581  	optionName := rd["name"].(string)
   582  	value, _ := rd["value"].(string)
   583  	hk := fmt.Sprintf("%s:%s=%s", namespace, optionName, sortValues(value))
   584  	log.Printf("[DEBUG] Elastic Beanstalk optionSettingValueHash(%#v): %s: hk=%s,hc=%d", v, optionName, hk, hashcode.String(hk))
   585  	return hashcode.String(hk)
   586  }
   587  
   588  func optionSettingKeyHash(v interface{}) int {
   589  	rd := v.(map[string]interface{})
   590  	namespace := rd["namespace"].(string)
   591  	optionName := rd["name"].(string)
   592  	hk := fmt.Sprintf("%s:%s", namespace, optionName)
   593  	log.Printf("[DEBUG] Elastic Beanstalk optionSettingKeyHash(%#v): %s: hk=%s,hc=%d", v, optionName, hk, hashcode.String(hk))
   594  	return hashcode.String(hk)
   595  }
   596  
   597  func sortValues(v string) string {
   598  	values := strings.Split(v, ",")
   599  	sort.Strings(values)
   600  	return strings.Join(values, ",")
   601  }
   602  
   603  func extractOptionSettings(s *schema.Set) []*elasticbeanstalk.ConfigurationOptionSetting {
   604  	settings := []*elasticbeanstalk.ConfigurationOptionSetting{}
   605  
   606  	if s != nil {
   607  		for _, setting := range s.List() {
   608  			settings = append(settings, &elasticbeanstalk.ConfigurationOptionSetting{
   609  				Namespace:  aws.String(setting.(map[string]interface{})["namespace"].(string)),
   610  				OptionName: aws.String(setting.(map[string]interface{})["name"].(string)),
   611  				Value:      aws.String(setting.(map[string]interface{})["value"].(string)),
   612  			})
   613  		}
   614  	}
   615  
   616  	return settings
   617  }
   618  
   619  func dropGeneratedSecurityGroup(settingValue string, meta interface{}) string {
   620  	conn := meta.(*AWSClient).ec2conn
   621  
   622  	groups := strings.Split(settingValue, ",")
   623  
   624  	resp, err := conn.DescribeSecurityGroups(&ec2.DescribeSecurityGroupsInput{
   625  		GroupIds: aws.StringSlice(groups),
   626  	})
   627  
   628  	if err != nil {
   629  		log.Printf("[DEBUG] Elastic Beanstalk error describing SecurityGroups: %v", err)
   630  		return settingValue
   631  	}
   632  
   633  	var legitGroups []string
   634  	for _, group := range resp.SecurityGroups {
   635  		log.Printf("[DEBUG] Elastic Beanstalk SecurityGroup: %v", *group.GroupName)
   636  		if !strings.HasPrefix(*group.GroupName, "awseb") {
   637  			legitGroups = append(legitGroups, *group.GroupId)
   638  		}
   639  	}
   640  
   641  	sort.Strings(legitGroups)
   642  
   643  	return strings.Join(legitGroups, ",")
   644  }