From e59fb4e6ca2e6c184acbdc3c7e14d07f0b2e0a83 Mon Sep 17 00:00:00 2001 From: Christopher Tiwald Date: Sun, 19 Jul 2015 00:09:00 -0400 Subject: [PATCH] aws: Add support for "aws_codedeploy_app" resources. --- builtin/providers/aws/config.go | 5 + builtin/providers/aws/provider.go | 1 + .../aws/resource_aws_codedeploy_app.go | 127 ++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 builtin/providers/aws/resource_aws_codedeploy_app.go diff --git a/builtin/providers/aws/config.go b/builtin/providers/aws/config.go index 8b9428fbc..dfd8b1b2e 100644 --- a/builtin/providers/aws/config.go +++ b/builtin/providers/aws/config.go @@ -14,6 +14,7 @@ import ( "github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/aws/aws-sdk-go/service/cloudwatchlogs" + "github.com/aws/aws-sdk-go/service/codedeploy" "github.com/aws/aws-sdk-go/service/directoryservice" "github.com/aws/aws-sdk-go/service/dynamodb" "github.com/aws/aws-sdk-go/service/ec2" @@ -70,6 +71,7 @@ type AWSClient struct { lambdaconn *lambda.Lambda opsworksconn *opsworks.OpsWorks glacierconn *glacier.Glacier + codedeployconn *codedeploy.CodeDeploy } // Client configures and returns a fully initialized AWSClient @@ -192,6 +194,9 @@ func (c *Config) Client() (interface{}, error) { log.Println("[INFO] Initializing Glacier connection") client.glacierconn = glacier.New(awsConfig) + + log.Println("[INFO] Initializing CodeDeploy Connection") + client.codedeployconn = codedeploy.New(awsConfig) } if len(errs) > 0 { diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index f73580d0f..132fa4678 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -166,6 +166,7 @@ func Provider() terraform.ResourceProvider { "aws_cloudwatch_log_group": resourceAwsCloudWatchLogGroup(), "aws_autoscaling_lifecycle_hook": resourceAwsAutoscalingLifecycleHook(), "aws_cloudwatch_metric_alarm": resourceAwsCloudWatchMetricAlarm(), + "aws_codedeploy_app": resourceAwsCodeDeployApp(), "aws_customer_gateway": resourceAwsCustomerGateway(), "aws_db_instance": resourceAwsDbInstance(), "aws_db_parameter_group": resourceAwsDbParameterGroup(), diff --git a/builtin/providers/aws/resource_aws_codedeploy_app.go b/builtin/providers/aws/resource_aws_codedeploy_app.go new file mode 100644 index 000000000..ccf07a82d --- /dev/null +++ b/builtin/providers/aws/resource_aws_codedeploy_app.go @@ -0,0 +1,127 @@ +package aws + +import ( + "fmt" + "log" + "strings" + + "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/codedeploy" +) + +func resourceAwsCodeDeployApp() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsCodeDeployAppCreate, + Read: resourceAwsCodeDeployAppRead, + Update: resourceAwsCodeDeployUpdate, + Delete: resourceAwsCodeDeployAppDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + // The unique ID is set by AWS on create. + "unique_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + }, + } +} + +func resourceAwsCodeDeployAppCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).codedeployconn + + application := d.Get("name").(string) + log.Printf("[DEBUG] Creating CodeDeploy application %s", application) + + resp, err := conn.CreateApplication(&codedeploy.CreateApplicationInput{ + ApplicationName: aws.String(application), + }) + if err != nil { + return err + } + log.Printf("[DEBUG] CodeDeploy application %s created", *resp.ApplicationId) + + // Despite giving the application a unique ID, AWS doesn't actually use + // it in API calls. Use it and the app name to identify the resource in + // the state file. This allows us to reliably detect both when the TF + // config file changes and when the user deletes the app without removing + // it first from the TF config. + d.SetId(fmt.Sprintf("%s:%s", *resp.ApplicationId, application)) + + return resourceAwsCodeDeployAppRead(d, meta) +} + +func resourceAwsCodeDeployAppRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).codedeployconn + + _, application := resourceAwsCodeDeployAppParseId(d.Id()) + log.Printf("[DEBUG] Reading CodeDeploy application %s", application) + resp, err := conn.GetApplication(&codedeploy.GetApplicationInput{ + ApplicationName: aws.String(application), + }) + if err != nil { + if codedeployerr, ok := err.(awserr.Error); ok && codedeployerr.Code() == "ApplicationDoesNotExistException" { + d.SetId("") + return nil + } else { + log.Printf("[ERROR] Error finding CodeDeploy application: %s", err) + return err + } + } + + d.Set("name", *resp.Application.ApplicationName) + + return nil +} + +func resourceAwsCodeDeployUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).codedeployconn + + o, n := d.GetChange("name") + + _, err := conn.UpdateApplication(&codedeploy.UpdateApplicationInput{ + ApplicationName: aws.String(o.(string)), + NewApplicationName: aws.String(n.(string)), + }) + if err != nil { + return err + } + log.Printf("[DEBUG] CodeDeploy application %s updated", n) + + d.Set("name", n) + + return nil +} + +func resourceAwsCodeDeployAppDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).codedeployconn + + _, err := conn.DeleteApplication(&codedeploy.DeleteApplicationInput{ + ApplicationName: aws.String(d.Get("name").(string)), + }) + if err != nil { + if cderr, ok := err.(awserr.Error); ok && cderr.Code() == "InvalidApplicationNameException" { + d.SetId("") + return nil + } else { + log.Printf("[ERROR] Error deleting CodeDeploy application: %s", err) + return err + } + } + + return nil +} + +func resourceAwsCodeDeployAppParseId(id string) (string, string) { + parts := strings.SplitN(id, ":", 2) + return parts[0], parts[1] +}