Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

providers/aws: add tags for resource_aws_autoscaling_group #13574

Merged
merged 1 commit into from
May 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 153 additions & 38 deletions builtin/providers/aws/autoscaling_tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import (
"fmt"
"log"
"regexp"
"strconv"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/autoscaling"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/schema"
)

// tagsSchema returns the schema to use for tags.
func autoscalingTagsSchema() *schema.Schema {
// autoscalingTagSchema returns the schema to use for the tag element.
func autoscalingTagSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Expand All @@ -35,11 +36,11 @@ func autoscalingTagsSchema() *schema.Schema {
},
},
},
Set: autoscalingTagsToHash,
Set: autoscalingTagToHash,
}
}

func autoscalingTagsToHash(v interface{}) int {
func autoscalingTagToHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["key"].(string)))
Expand All @@ -52,35 +53,74 @@ func autoscalingTagsToHash(v interface{}) int {
// setTags is a helper to set the tags for a resource. It expects the
// tags field to be named "tag"
func setAutoscalingTags(conn *autoscaling.AutoScaling, d *schema.ResourceData) error {
if d.HasChange("tag") {
resourceID := d.Get("name").(string)
var createTags, removeTags []*autoscaling.Tag

if d.HasChange("tag") || d.HasChange("tags") {
oraw, nraw := d.GetChange("tag")
o := setToMapByKey(oraw.(*schema.Set), "key")
n := setToMapByKey(nraw.(*schema.Set), "key")

resourceID := d.Get("name").(string)
c, r := diffAutoscalingTags(
autoscalingTagsFromMap(o, resourceID),
autoscalingTagsFromMap(n, resourceID),
resourceID)
create := autoscaling.CreateOrUpdateTagsInput{
Tags: c,
old, err := autoscalingTagsFromMap(o, resourceID)
if err != nil {
return err
}

new, err := autoscalingTagsFromMap(n, resourceID)
if err != nil {
return err
}

c, r, err := diffAutoscalingTags(old, new, resourceID)
if err != nil {
return err
}

createTags = append(createTags, c...)
removeTags = append(removeTags, r...)

oraw, nraw = d.GetChange("tags")
old, err = autoscalingTagsFromList(oraw.([]interface{}), resourceID)
if err != nil {
return err
}

new, err = autoscalingTagsFromList(nraw.([]interface{}), resourceID)
if err != nil {
return err
}

c, r, err = diffAutoscalingTags(old, new, resourceID)
if err != nil {
return err
}

createTags = append(createTags, c...)
removeTags = append(removeTags, r...)
}

// Set tags
if len(removeTags) > 0 {
log.Printf("[DEBUG] Removing autoscaling tags: %#v", removeTags)

remove := autoscaling.DeleteTagsInput{
Tags: r,
Tags: removeTags,
}

if _, err := conn.DeleteTags(&remove); err != nil {
return err
}
}

if len(createTags) > 0 {
log.Printf("[DEBUG] Creating autoscaling tags: %#v", createTags)

// Set tags
if len(r) > 0 {
log.Printf("[DEBUG] Removing autoscaling tags: %#v", r)
if _, err := conn.DeleteTags(&remove); err != nil {
return err
}
create := autoscaling.CreateOrUpdateTagsInput{
Tags: createTags,
}
if len(c) > 0 {
log.Printf("[DEBUG] Creating autoscaling tags: %#v", c)
if _, err := conn.CreateOrUpdateTags(&create); err != nil {
return err
}

if _, err := conn.CreateOrUpdateTags(&create); err != nil {
return err
}
}

Expand All @@ -90,11 +130,12 @@ func setAutoscalingTags(conn *autoscaling.AutoScaling, d *schema.ResourceData) e
// diffTags takes our tags locally and the ones remotely and returns
// the set of tags that must be created, and the set of tags that must
// be destroyed.
func diffAutoscalingTags(oldTags, newTags []*autoscaling.Tag, resourceID string) ([]*autoscaling.Tag, []*autoscaling.Tag) {
func diffAutoscalingTags(oldTags, newTags []*autoscaling.Tag, resourceID string) ([]*autoscaling.Tag, []*autoscaling.Tag, error) {
// First, we're creating everything we have
create := make(map[string]interface{})
for _, t := range newTags {
tag := map[string]interface{}{
"key": *t.Key,
"value": *t.Value,
"propagate_at_launch": *t.PropagateAtLaunch,
}
Expand All @@ -112,34 +153,107 @@ func diffAutoscalingTags(oldTags, newTags []*autoscaling.Tag, resourceID string)
}
}

return autoscalingTagsFromMap(create, resourceID), remove
createTags, err := autoscalingTagsFromMap(create, resourceID)
if err != nil {
return nil, nil, err
}

return createTags, remove, nil
}

func autoscalingTagsFromList(vs []interface{}, resourceID string) ([]*autoscaling.Tag, error) {
result := make([]*autoscaling.Tag, 0, len(vs))
for _, tag := range vs {
attr, ok := tag.(map[string]interface{})
if !ok {
continue
}

t, err := autoscalingTagFromMap(attr, resourceID)
if err != nil {
return nil, err
}

if t != nil {
result = append(result, t)
}
}
return result, nil
}

// tagsFromMap returns the tags for the given map of data.
func autoscalingTagsFromMap(m map[string]interface{}, resourceID string) []*autoscaling.Tag {
func autoscalingTagsFromMap(m map[string]interface{}, resourceID string) ([]*autoscaling.Tag, error) {
result := make([]*autoscaling.Tag, 0, len(m))
for k, v := range m {
attr := v.(map[string]interface{})
t := &autoscaling.Tag{
Key: aws.String(k),
Value: aws.String(attr["value"].(string)),
PropagateAtLaunch: aws.Bool(attr["propagate_at_launch"].(bool)),
ResourceId: aws.String(resourceID),
ResourceType: aws.String("auto-scaling-group"),
}
if !tagIgnoredAutoscaling(t) {
for _, v := range m {
attr, ok := v.(map[string]interface{})
if !ok {
continue
}

t, err := autoscalingTagFromMap(attr, resourceID)
if err != nil {
return nil, err
}

if t != nil {
result = append(result, t)
}
}

return result
return result, nil
}

func autoscalingTagFromMap(attr map[string]interface{}, resourceID string) (*autoscaling.Tag, error) {
if _, ok := attr["key"]; !ok {
return nil, fmt.Errorf("%s: invalid tag attributes: key missing", resourceID)
}

if _, ok := attr["value"]; !ok {
return nil, fmt.Errorf("%s: invalid tag attributes: value missing", resourceID)
}

if _, ok := attr["propagate_at_launch"]; !ok {
return nil, fmt.Errorf("%s: invalid tag attributes: propagate_at_launch missing", resourceID)
}

var propagateAtLaunch bool
var err error

if v, ok := attr["propagate_at_launch"].(bool); ok {
propagateAtLaunch = v
}

if v, ok := attr["propagate_at_launch"].(string); ok {
if propagateAtLaunch, err = strconv.ParseBool(v); err != nil {
return nil, fmt.Errorf(
"%s: invalid tag attribute: invalid value for propagate_at_launch: %s",
resourceID,
v,
)
}
}

t := &autoscaling.Tag{
Key: aws.String(attr["key"].(string)),
Value: aws.String(attr["value"].(string)),
PropagateAtLaunch: aws.Bool(propagateAtLaunch),
ResourceId: aws.String(resourceID),
ResourceType: aws.String("auto-scaling-group"),
}

if tagIgnoredAutoscaling(t) {
return nil, nil
}

return t, nil
}

// autoscalingTagsToMap turns the list of tags into a map.
func autoscalingTagsToMap(ts []*autoscaling.Tag) map[string]interface{} {
tags := make(map[string]interface{})
for _, t := range ts {
tag := map[string]interface{}{
"key": *t.Key,
"value": *t.Value,
"propagate_at_launch": *t.PropagateAtLaunch,
}
Expand All @@ -154,6 +268,7 @@ func autoscalingTagDescriptionsToMap(ts *[]*autoscaling.TagDescription) map[stri
tags := make(map[string]map[string]interface{})
for _, t := range *ts {
tag := map[string]interface{}{
"key": *t.Key,
"value": *t.Value,
"propagate_at_launch": *t.PropagateAtLaunch,
}
Expand Down
24 changes: 21 additions & 3 deletions builtin/providers/aws/autoscaling_tags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,28 @@ func TestDiffAutoscalingTags(t *testing.T) {
{
Old: map[string]interface{}{
"Name": map[string]interface{}{
"key": "Name",
"value": "bar",
"propagate_at_launch": true,
},
},
New: map[string]interface{}{
"DifferentTag": map[string]interface{}{
"key": "DifferentTag",
"value": "baz",
"propagate_at_launch": true,
},
},
Create: map[string]interface{}{
"DifferentTag": map[string]interface{}{
"key": "DifferentTag",
"value": "baz",
"propagate_at_launch": true,
},
},
Remove: map[string]interface{}{
"Name": map[string]interface{}{
"key": "Name",
"value": "bar",
"propagate_at_launch": true,
},
Expand All @@ -48,24 +52,28 @@ func TestDiffAutoscalingTags(t *testing.T) {
{
Old: map[string]interface{}{
"Name": map[string]interface{}{
"key": "Name",
"value": "bar",
"propagate_at_launch": true,
},
},
New: map[string]interface{}{
"Name": map[string]interface{}{
"key": "Name",
"value": "baz",
"propagate_at_launch": false,
},
},
Create: map[string]interface{}{
"Name": map[string]interface{}{
"key": "Name",
"value": "baz",
"propagate_at_launch": false,
},
},
Remove: map[string]interface{}{
"Name": map[string]interface{}{
"key": "Name",
"value": "bar",
"propagate_at_launch": true,
},
Expand All @@ -76,10 +84,20 @@ func TestDiffAutoscalingTags(t *testing.T) {
var resourceID = "sample"

for i, tc := range cases {
awsTagsOld := autoscalingTagsFromMap(tc.Old, resourceID)
awsTagsNew := autoscalingTagsFromMap(tc.New, resourceID)
awsTagsOld, err := autoscalingTagsFromMap(tc.Old, resourceID)
if err != nil {
t.Fatalf("%d: unexpected error convertig old tags: %v", i, err)
}

awsTagsNew, err := autoscalingTagsFromMap(tc.New, resourceID)
if err != nil {
t.Fatalf("%d: unexpected error convertig new tags: %v", i, err)
}

c, r := diffAutoscalingTags(awsTagsOld, awsTagsNew, resourceID)
c, r, err := diffAutoscalingTags(awsTagsOld, awsTagsNew, resourceID)
if err != nil {
t.Fatalf("%d: unexpected error diff'ing tags: %v", i, err)
}

cm := autoscalingTagsToMap(c)
rm := autoscalingTagsToMap(r)
Expand Down
2 changes: 1 addition & 1 deletion builtin/providers/aws/import_aws_autoscaling_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func TestAccAWSAutoScalingGroup_importBasic(t *testing.T) {
CheckDestroy: testAccCheckAWSAutoScalingGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAWSAutoScalingGroupConfig(randName),
Config: testAccAWSAutoScalingGroupImport(randName),
},

resource.TestStep{
Expand Down
Loading