Skip to content

Commit

Permalink
provider/aws: Add Elastic Beanstalk Application, Configuration Templa…
Browse files Browse the repository at this point in the history
…te, and Environment

This adds support for Elastic Beanstalk Applications, Configuration Templates,
and Environments.

This is a combined work of @catsby, @dharrisio, @Bowbaq, and @jen20
  • Loading branch information
catsby committed Mar 7, 2016
1 parent 2458bfe commit f0d3176
Show file tree
Hide file tree
Showing 19 changed files with 6,746 additions and 127 deletions.
5 changes: 5 additions & 0 deletions Godeps/Godeps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions builtin/providers/aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/aws/aws-sdk-go/service/efs"
"github.com/aws/aws-sdk-go/service/elasticache"
"github.com/aws/aws-sdk-go/service/elasticbeanstalk"
elasticsearch "github.com/aws/aws-sdk-go/service/elasticsearchservice"
"github.com/aws/aws-sdk-go/service/elb"
"github.com/aws/aws-sdk-go/service/firehose"
Expand Down Expand Up @@ -98,6 +99,7 @@ type AWSClient struct {
kinesisconn *kinesis.Kinesis
firehoseconn *firehose.Firehose
elasticacheconn *elasticache.ElastiCache
elasticbeanstalkconn *elasticbeanstalk.ElasticBeanstalk
lambdaconn *lambda.Lambda
opsworksconn *opsworks.OpsWorks
glacierconn *glacier.Glacier
Expand Down Expand Up @@ -213,6 +215,9 @@ func (c *Config) Client() (interface{}, error) {
kinesisSess := session.New(&awsKinesisConfig)
client.kinesisconn = kinesis.New(kinesisSess)

log.Println("[INFO] Initializing Elastic Beanstalk Connection")
client.elasticbeanstalkconn = elasticbeanstalk.New(sess)

authErr := c.ValidateAccountId(client.iamconn)
if authErr != nil {
errs = append(errs, authErr)
Expand Down
255 changes: 129 additions & 126 deletions builtin/providers/aws/provider.go

Large diffs are not rendered by default.

147 changes: 147 additions & 0 deletions builtin/providers/aws/resource_aws_elastic_beanstalk_application.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package aws

import (
"fmt"
"log"
"time"

"github.com/hashicorp/terraform/helper/schema"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/elasticbeanstalk"
"github.com/hashicorp/terraform/helper/resource"
)

func resourceAwsElasticBeanstalkApplication() *schema.Resource {
return &schema.Resource{
Create: resourceAwsElasticBeanstalkApplicationCreate,
Read: resourceAwsElasticBeanstalkApplicationRead,
Update: resourceAwsElasticBeanstalkApplicationUpdate,
Delete: resourceAwsElasticBeanstalkApplicationDelete,

Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"description": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: false,
},
},
}
}

func resourceAwsElasticBeanstalkApplicationCreate(d *schema.ResourceData, meta interface{}) error {
beanstalkConn := meta.(*AWSClient).elasticbeanstalkconn

// Get the name and description
name := d.Get("name").(string)
description := d.Get("description").(string)

log.Printf("[DEBUG] Elastic Beanstalk application create: %s, description: %s", name, description)

req := &elasticbeanstalk.CreateApplicationInput{
ApplicationName: aws.String(name),
Description: aws.String(description),
}

_, err := beanstalkConn.CreateApplication(req)
if err != nil {
return err
}

d.SetId(name)

return resourceAwsElasticBeanstalkApplicationRead(d, meta)
}

func resourceAwsElasticBeanstalkApplicationUpdate(d *schema.ResourceData, meta interface{}) error {
beanstalkConn := meta.(*AWSClient).elasticbeanstalkconn

if d.HasChange("description") {
if err := resourceAwsElasticBeanstalkApplicationDescriptionUpdate(beanstalkConn, d); err != nil {
return err
}
}

return resourceAwsElasticBeanstalkApplicationRead(d, meta)
}

func resourceAwsElasticBeanstalkApplicationDescriptionUpdate(beanstalkConn *elasticbeanstalk.ElasticBeanstalk, d *schema.ResourceData) error {
name := d.Get("name").(string)
description := d.Get("description").(string)

log.Printf("[DEBUG] Elastic Beanstalk application: %s, update description: %s", name, description)

_, err := beanstalkConn.UpdateApplication(&elasticbeanstalk.UpdateApplicationInput{
ApplicationName: aws.String(name),
Description: aws.String(description),
})

return err
}

func resourceAwsElasticBeanstalkApplicationRead(d *schema.ResourceData, meta interface{}) error {
a, err := getBeanstalkApplication(d, meta)
if err != nil {
return err
}
if a == nil {
return err
}

d.Set("description", a.Description)
return nil
}

func resourceAwsElasticBeanstalkApplicationDelete(d *schema.ResourceData, meta interface{}) error {
beanstalkConn := meta.(*AWSClient).elasticbeanstalkconn

a, err := getBeanstalkApplication(d, meta)
if err != nil {
return err
}
_, err = beanstalkConn.DeleteApplication(&elasticbeanstalk.DeleteApplicationInput{
ApplicationName: aws.String(d.Id()),
})

return resource.Retry(10*time.Second, func() error {
if a, _ = getBeanstalkApplication(d, meta); a != nil {
return fmt.Errorf("Beanstalk Application still exists")
}
return nil
})
}

func getBeanstalkApplication(
d *schema.ResourceData,
meta interface{}) (*elasticbeanstalk.ApplicationDescription, error) {
conn := meta.(*AWSClient).elasticbeanstalkconn

resp, err := conn.DescribeApplications(&elasticbeanstalk.DescribeApplicationsInput{
ApplicationNames: []*string{aws.String(d.Id())},
})

if err != nil {
if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() != "InvalidBeanstalkAppID.NotFound" {
log.Printf("[Err] Error reading Elastic Beanstalk Application (%s): Application not found", d.Id())
d.SetId("")
return nil, nil
}
return nil, err
}

switch {
case len(resp.Applications) > 1:
return nil, fmt.Errorf("Error %d Applications matched, expected 1", len(resp.Applications))
case len(resp.Applications) == 0:
d.SetId("")
return nil, nil
default:
return resp.Applications[0], nil
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package aws

import (
"fmt"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/elasticbeanstalk"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSBeanstalkApp_basic(t *testing.T) {
var app elasticbeanstalk.ApplicationDescription

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckBeanstalkAppDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccBeanstalkAppConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckBeanstalkAppExists("aws_elastic_beanstalk_application.tftest", &app),
),
},
},
})
}

func testAccCheckBeanstalkAppDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).elasticbeanstalkconn

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_elastic_beanstalk_application" {
continue
}

// Try to find the application
DescribeBeanstalkAppOpts := &elasticbeanstalk.DescribeApplicationsInput{
ApplicationNames: []*string{aws.String(rs.Primary.ID)},
}
resp, err := conn.DescribeApplications(DescribeBeanstalkAppOpts)
if err == nil {
if len(resp.Applications) > 0 {
return fmt.Errorf("Elastic Beanstalk Application still exists.")
}

return nil
}

// Verify the error is what we want
ec2err, ok := err.(awserr.Error)
if !ok {
return err
}
if ec2err.Code() != "InvalidBeanstalkAppID.NotFound" {
return err
}
}

return nil
}

func testAccCheckBeanstalkAppExists(n string, app *elasticbeanstalk.ApplicationDescription) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("Elastic Beanstalk app ID is not set")
}

conn := testAccProvider.Meta().(*AWSClient).elasticbeanstalkconn
DescribeBeanstalkAppOpts := &elasticbeanstalk.DescribeApplicationsInput{
ApplicationNames: []*string{aws.String(rs.Primary.ID)},
}
resp, err := conn.DescribeApplications(DescribeBeanstalkAppOpts)
if err != nil {
return err
}
if len(resp.Applications) == 0 {
return fmt.Errorf("Elastic Beanstalk Application not found.")
}

*app = *resp.Applications[0]

return nil
}
}

const testAccBeanstalkAppConfig = `
resource "aws_elastic_beanstalk_application" "tftest" {
name = "tf-test-name"
description = "tf-test-desc"
}
`
Loading

0 comments on commit f0d3176

Please sign in to comment.