Skip to content

Commit

Permalink
Add support resource tags for aws_media_store_container resource
Browse files Browse the repository at this point in the history
  • Loading branch information
teraken0509 committed Jul 17, 2019
1 parent f945137 commit 3bf1c52
Show file tree
Hide file tree
Showing 5 changed files with 342 additions and 1 deletion.
36 changes: 35 additions & 1 deletion aws/resource_aws_media_store_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package aws

import (
"fmt"
"log"
"regexp"
"time"

Expand All @@ -16,6 +17,7 @@ func resourceAwsMediaStoreContainer() *schema.Resource {
return &schema.Resource{
Create: resourceAwsMediaStoreContainerCreate,
Read: resourceAwsMediaStoreContainerRead,
Update: resourceAwsMediaStoreContainerUpdate,
Delete: resourceAwsMediaStoreContainerDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
Expand All @@ -35,6 +37,7 @@ func resourceAwsMediaStoreContainer() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"tags": tagsSchema(),
},
}
}
Expand All @@ -44,6 +47,7 @@ func resourceAwsMediaStoreContainerCreate(d *schema.ResourceData, meta interface

input := &mediastore.CreateContainerInput{
ContainerName: aws.String(d.Get("name").(string)),
Tags: tagsFromMapMediaStore(d.Get("tags").(map[string]interface{})),
}

_, err := conn.CreateContainer(input)
Expand Down Expand Up @@ -75,15 +79,45 @@ func resourceAwsMediaStoreContainerRead(d *schema.ResourceData, meta interface{}
ContainerName: aws.String(d.Id()),
}
resp, err := conn.DescribeContainer(input)
if isAWSErr(err, mediastore.ErrCodeContainerNotFoundException, "") {
log.Printf("[WARN] No Container found: %s, removing from state", d.Id())
d.SetId("")
return nil
}
if err != nil {
return err
return fmt.Errorf("Error describing media store container %s: %s", d.Id(), err)
}
d.Set("arn", resp.Container.ARN)
d.Set("name", resp.Container.Name)
d.Set("endpoint", resp.Container.Endpoint)

if err := saveTagsMediaStore(conn, d, aws.StringValue(resp.Container.ARN)); err != nil {
if isAWSErr(err, mediastore.ErrCodeContainerNotFoundException, "") {
log.Printf("[WARN] No Container found: %s, removing from state", d.Id())
d.SetId("")
return nil
}
return fmt.Errorf("Error setting tags for %s: %s", d.Id(), err)
}

return nil
}

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

if err := setTagsMediaStore(conn, d, d.Get("arn").(string)); err != nil {
if isAWSErr(err, mediastore.ErrCodeContainerNotFoundException, "") {
log.Printf("[WARN] No Container found: %s, removing from state", d.Id())
d.SetId("")
return nil
}
return fmt.Errorf("Error updating tags for %s: %s", d.Id(), err)
}

return resourceAwsMediaStoreContainerRead(d, meta)
}

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

Expand Down
59 changes: 59 additions & 0 deletions aws/resource_aws_media_store_container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,51 @@ func TestAccAWSMediaStoreContainer_basic(t *testing.T) {
})
}

func TestAccAWSMediaStoreContainer_tags(t *testing.T) {
rName := acctest.RandString(5)
resourceName := "aws_media_store_container.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSMediaStore(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAwsMediaStoreContainerDestroy,
Steps: []resource.TestStep{
{
Config: testAccMediaStoreContainerConfigWithTags(rName, "foo", "bar", "fizz", "buzz"),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsMediaStoreContainerExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "tags.%", "3"),
resource.TestCheckResourceAttr(resourceName, "tags.Name", fmt.Sprintf("tf_mediastore_%s", rName)),
resource.TestCheckResourceAttr(resourceName, "tags.foo", "bar"),
resource.TestCheckResourceAttr(resourceName, "tags.fizz", "buzz"),
),
},
{
Config: testAccMediaStoreContainerConfigWithTags(rName, "foo", "bar2", "fizz2", "buzz2"),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsMediaStoreContainerExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "tags.%", "3"),
resource.TestCheckResourceAttr(resourceName, "tags.Name", fmt.Sprintf("tf_mediastore_%s", rName)),
resource.TestCheckResourceAttr(resourceName, "tags.foo", "bar2"),
resource.TestCheckResourceAttr(resourceName, "tags.fizz2", "buzz2"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccMediaStoreContainerConfig(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsMediaStoreContainerExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "tags.%", "0"),
),
},
},
})
}

func TestAccAWSMediaStoreContainer_import(t *testing.T) {
resourceName := "aws_media_store_container.test"

Expand Down Expand Up @@ -116,3 +161,17 @@ resource "aws_media_store_container" "test" {
}
`, rName)
}

func testAccMediaStoreContainerConfigWithTags(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string {
return fmt.Sprintf(`
resource "aws_media_store_container" "test" {
name = "tf_mediastore_%[1]s"
tags = {
Name = "tf_mediastore_%[1]s"
%[2]s = %[3]q
%[4]s = %[5]q
}
}
`, rName, tagKey1, tagValue1, tagKey2, tagValue2)
}
135 changes: 135 additions & 0 deletions aws/tagsMediaStore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package aws

import (
"log"
"regexp"

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

// setTags is a helper to set the tags for a resource. It expects the
// tags field to be named "tags"
func setTagsMediaStore(conn *mediastore.MediaStore, d *schema.ResourceData, arn string) error {
if d.HasChange("tags") {
oraw, nraw := d.GetChange("tags")
o := oraw.(map[string]interface{})
n := nraw.(map[string]interface{})
create, remove := diffTagsMediaStore(tagsFromMapMediaStore(o), tagsFromMapMediaStore(n))

// Set tags
if len(remove) > 0 {
log.Printf("[DEBUG] Removing tags: %s", remove)
k := make([]*string, len(remove))
for i, t := range remove {
k[i] = t.Key
}

_, err := conn.UntagResource(&mediastore.UntagResourceInput{
Resource: aws.String(arn),
TagKeys: k,
})
if err != nil {
return err
}
}
if len(create) > 0 {
log.Printf("[DEBUG] Creating tags: %s", create)
_, err := conn.TagResource(&mediastore.TagResourceInput{
Resource: aws.String(arn),
Tags: create,
})
if err != nil {
return err
}
}
}

return nil
}

// 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 diffTagsMediaStore(oldTags, newTags []*mediastore.Tag) ([]*mediastore.Tag, []*mediastore.Tag) {
// First, we're creating everything we have
create := make(map[string]interface{})
for _, t := range newTags {
create[aws.StringValue(t.Key)] = aws.StringValue(t.Value)
}

// Build the list of what to remove
var remove []*mediastore.Tag
for _, t := range oldTags {
old, ok := create[aws.StringValue(t.Key)]
if !ok || old != aws.StringValue(t.Value) {
// Delete it!
remove = append(remove, t)
} else if ok {
delete(create, aws.StringValue(t.Key))
}
}

return tagsFromMapMediaStore(create), remove
}

// tagsFromMap returns the tags for the given map of data.
func tagsFromMapMediaStore(m map[string]interface{}) []*mediastore.Tag {
result := make([]*mediastore.Tag, 0, len(m))
for k, v := range m {
t := &mediastore.Tag{
Key: aws.String(k),
Value: aws.String(v.(string)),
}
if !tagIgnoredMediaStore(t) {
result = append(result, t)
}
}

return result
}

// tagsToMap turns the list of tags into a map.
func tagsToMapMediaStore(ts []*mediastore.Tag) map[string]string {
result := make(map[string]string)
for _, t := range ts {
if !tagIgnoredMediaStore(t) {
result[aws.StringValue(t.Key)] = aws.StringValue(t.Value)
}
}

return result
}

// compare a tag against a list of strings and checks if it should
// be ignored or not
func tagIgnoredMediaStore(t *mediastore.Tag) bool {
filter := []string{"^aws:"}
for _, v := range filter {
log.Printf("[DEBUG] Matching %v with %v\n", v, aws.StringValue(t.Key))
r, _ := regexp.MatchString(v, aws.StringValue(t.Key))
if r {
log.Printf("[DEBUG] Found AWS specific tag %s (val: %s), ignoring.\n", aws.StringValue(t.Key), aws.StringValue(t.Value))
return true
}
}
return false
}

func saveTagsMediaStore(conn *mediastore.MediaStore, d *schema.ResourceData, arn string) error {
resp, err := conn.ListTagsForResource(&mediastore.ListTagsForResourceInput{
Resource: aws.String(arn),
})

if err != nil {
return err
}

var dt []*mediastore.Tag
if len(resp.Tags) > 0 {
dt = resp.Tags
}

return d.Set("tags", tagsToMapMediaStore(dt))
}
112 changes: 112 additions & 0 deletions aws/tagsMediaStore_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package aws

import (
"reflect"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/mediastore"
)

// go test -v -run="TestDiffMediaStoreTags"
func TestDiffMediaStoreTags(t *testing.T) {
cases := []struct {
Old, New map[string]interface{}
Create, Remove map[string]string
}{
// Basic add/remove
{
Old: map[string]interface{}{
"foo": "bar",
},
New: map[string]interface{}{
"bar": "baz",
},
Create: map[string]string{
"bar": "baz",
},
Remove: map[string]string{
"foo": "bar",
},
},

// Modify
{
Old: map[string]interface{}{
"foo": "bar",
},
New: map[string]interface{}{
"foo": "baz",
},
Create: map[string]string{
"foo": "baz",
},
Remove: map[string]string{
"foo": "bar",
},
},

// Overlap
{
Old: map[string]interface{}{
"foo": "bar",
"hello": "world",
},
New: map[string]interface{}{
"foo": "baz",
"hello": "world",
},
Create: map[string]string{
"foo": "baz",
},
Remove: map[string]string{
"foo": "bar",
},
},

// Remove
{
Old: map[string]interface{}{
"foo": "bar",
"bar": "baz",
},
New: map[string]interface{}{
"foo": "bar",
},
Create: map[string]string{},
Remove: map[string]string{
"bar": "baz",
},
},
}

for i, tc := range cases {
c, r := diffTagsMediaStore(tagsFromMapMediaStore(tc.Old), tagsFromMapMediaStore(tc.New))
cm := tagsToMapMediaStore(c)
rm := tagsToMapMediaStore(r)
if !reflect.DeepEqual(cm, tc.Create) {
t.Fatalf("%d: bad create: %#v", i, cm)
}
if !reflect.DeepEqual(rm, tc.Remove) {
t.Fatalf("%d: bad remove: %#v", i, rm)
}
}
}

// go test -v -run="TestIgnoringTagsMediaStore"
func TestIgnoringTagsMediaStore(t *testing.T) {
var ignoredTags []*mediastore.Tag
ignoredTags = append(ignoredTags, &mediastore.Tag{
Key: aws.String("aws:cloudformation:logical-id"),
Value: aws.String("foo"),
})
ignoredTags = append(ignoredTags, &mediastore.Tag{
Key: aws.String("aws:foo:bar"),
Value: aws.String("baz"),
})
for _, tag := range ignoredTags {
if !tagIgnoredMediaStore(tag) {
t.Fatalf("Tag %v with value %v not ignored, but should be!", *tag.Key, *tag.Value)
}
}
}
Loading

0 comments on commit 3bf1c52

Please sign in to comment.