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