-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
271 additions
and
0 deletions.
There are no files selected for viewing
271 changes: 271 additions & 0 deletions
271
builtin/providers/aws/resource_aws_codedeploy_deployment_group.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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] | ||
} |