Skip to content

Commit

Permalink
wip -- will rebase later
Browse files Browse the repository at this point in the history
  • Loading branch information
ctiwald committed Aug 25, 2015
1 parent 9b1f8f1 commit cb88985
Showing 1 changed file with 271 additions and 0 deletions.
271 changes: 271 additions & 0 deletions builtin/providers/aws/resource_aws_codedeploy_deployment_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
package aws

import (
"bytes"
"fmt"
"log"

"github.com/hashicorp/terraform/helper/hashcode"
"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 resourceAwsCodeDeployDeploymentGroup() *schema.Resource {
return &schema.Resource{
Create: resourceAwsCodeDeployDeploymentGroupCreate,
Read: resourceAwsCodeDeployDeploymentGroupRead,
//Update: resourceAwsCodeDeployDeploymentGroupUpdate,
//Delete: resourceAwsCodeDeployDeploymentGroupDelete,

Schema: map[string]*schema.Schema{
"application_name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 100 {
errors = append(errors, fmt.Errorf(
"%q cannot exceed 100 characters", k))
}
return
},
},

"deployment_group_name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 100 {
errors = append(errors, fmt.Errorf(
"%q cannot exceed 100 characters", k))
}
return
},
},

"service_role_arn": &schema.Schema{
Type: schema.TypeString,
Required: true,
},

"autoscaling_groups": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},

"deployment_config_name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 100 {
errors = append(errors, fmt.Errorf(
"%q cannot exceed 100 characters", k))
}
return
},
},

"ec2_tag_filters": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"key": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},

"type": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ValidateFunc: validateTagFilters,
},

"value": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
},
},
Set: resourceAwsCodeDeployTagFilterHash,
},

"on_premises_instance_tag_filters": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"key": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},

"type": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ValidateFunc: validateTagFilters,
},

"value": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
},
},
Set: resourceAwsCodeDeployTagFilterHash,
},
},
}
}

func resourceAwsCodeDeployDeploymentGroupCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).codedeployconn

onPremFilters := buildOnPremTagFilters(d.Get("on_premises_instance_tag_filters").(*schema.Set).List())
ec2TagFilters := buildEC2TagFilters(d.Get("on_premises_instance_tag_filters").(*schema.Set).List())

application := d.Get("application_name").(string)
deploymentGroup := d.Get("deployment_group_name").(string)

resp, err := conn.CreateDeploymentGroup(&codedeploy.CreateDeploymentGroupInput{
ApplicationName: aws.String(application),
AutoScalingGroups: expandStringList(d.Get("autoscaling_groups").(*schema.Set).List()),
DeploymentConfigName: aws.String(d.Get("deployment_config_name").(string)),
DeploymentGroupName: aws.String(deploymentGroup),
EC2TagFilters: ec2TagFilters,
OnPremisesInstanceTagFilters: onPremFilters,
ServiceRoleARN: aws.String(d.Get("service_role_arn").(string)),
})
if err != nil {
return err
}
log.Printf("[DEBUG] CodeDeploy DeploymentGroup %s created", *resp.DeploymentGroupID)

// Despite giving the deployment group a unique ID, AWS doesn't actually use it
// in API calls. Use the unique ID, application name, and deployment group name
// together as a unique identifier for this group.
d.SetId(fmt.Sprintf("%s:%s:%s", *resp.DeploymentGroupID, application, deploymentGroup))

return resourceAwsCodeDeployDeploymentGroupRead(d, meta)
}

func resourceAwsCodeDeployDeploymentGroupRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).codedeployconn

_, application, deploymentGroup := resourceAwsCodeDeployDeploymentGroupParseId(d.Id())

log.Printf("[DEBUG] Reading CodeDeploy DeploymentGroup %s for application %s", deploymentGroup, application)
resp, err := conn.GetDeploymentGroup(&codedeploy.GetDeploymentGroupInput{
ApplicationName: aws.String(d.Get("application_name")),
DeploymentGroupName: aws.String(d.Get("deployment_group_name")),
})
if err != nil {
if codedeployerr, ok := err.(awserr.Error); ok && codedeployerr.Code() == "DeploymentGroupDoesNotExistException" {
d.SetId("")
} else {
log.Printf("[ERROR] Error finding CodeDeploy deployment group: %s", err)
return err
}
}

d.Set("application_name", *resp.DeploymentGroupInfo.ApplicationName)
d.Set("autoscaling_groups", *resp.DeploymentGroupInfo.AutoscalingGroups)
d.Set("deployment_config_name", *resp.DeploymentGroupInfo.DeploymentConfigName)
d.Set("deployment_group_name", *resp.DeploymentGroupInfo.DeploymentGroupName)
d.Set("ec2_tag_filters", tagFiltersToMap(*resp.DeploymentGroupInfo.EC2TagFilters))
d.Set("on_premises_instance_tag_filters", tagFiltersToMap(*resp.DeploymentGroupInfo.OnPremisesInstanceTagFilters))
d.Set("service_role_arn", *resp.DeploymentGroupInfo.ServiceRoleARN)

return nil
}

// buildOnPremTagFilters converts raw schema lists into a list of
// codedeploy.TagFilters.
func buildOnPremTagFilters(configured []interface{}) []*codedeploy.TagFilter {
filters := make([]*codedeploy.TagFilter, len(configured))
for _, raw := range configured {
var filter codedeploy.TagFilter
m := raw.(map[string]interface{})

filter.Key = aws.String(m["key"].(string))
filter.Type = aws.String(m["type"].(string))
filter.Value = aws.String(m["value"].(string))

filters = append(filters, &filter)
}

return filters
}

// buildEC2TagFilters converts raw schema lists into a list of
// codedeploy.EC2TagFilters.
func buildEC2TagFilters(configured []interface{}) []*codedeploy.EC2TagFilter {
filters := make([]*codedeploy.EC2TagFilter, len(configured))
for _, raw := range configured {
var filter codedeploy.EC2TagFilter
m := raw.(map[string]interface{})

filter.Key = aws.String(m["key"].(string))
filter.Type = aws.String(m["type"].(string))
filter.Value = aws.String(m["value"].(string))

filters = append(filters, &filter)
}

return filters
}

// tagFiltersToMap converts lists of tag filters into a map.
func tagFiltersToMap(tagFilters []interface{}) map[string]interface{} {
result := make(map[string]string)
for _, tf := range tagFilters {
result["key"] = *tf.Key
result["value"] = *tf.Value
result["type"] = *tf.Type
}
return result
}

// validateTagFilters confirms the "value" component of a tag filter is one of
// AWS's three allowed types.
func validateTagFilters(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if value != "KEY_ONLY" ||
value != "VALUE_ONLY" ||
value != "KEY_AND_VALUE" {
errors = append(errors, fmt.Errorf(
"%q must be one of \"KEY_ONLY\", \"VALUE_ONLY\", or \"KEY_AND_VALUE\"", k))
}
return
}

func resourceAwsCodeDeployTagFilterHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})

// Nothing's actually required in tag filters, so we must check the
// presence of all values before attempting a hash.
if v, ok := m["key"]; ok {
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
}
if v, ok := m["type"]; ok {
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
}
if v, ok := m["value"]; ok {
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
}

return hashcode.String(buf.String())
}

func resourceAwsCodeDeployDeploymentGroupParseId(id string) (string, string, string) {
parts := strings.SplitN(id, ":", 3)
return parts[0], parts[1], parts[2]
}

0 comments on commit cb88985

Please sign in to comment.