From fb0838ce1b16178edaf0762c42329cfe155c5343 Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Mon, 15 Feb 2016 14:10:19 +0000 Subject: [PATCH] provider/aws: Add support for CloudTrail tags --- .../providers/aws/resource_aws_cloudtrail.go | 31 ++++++- builtin/providers/aws/tagsCloudtrail.go | 92 +++++++++++++++++++ 2 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 builtin/providers/aws/tagsCloudtrail.go diff --git a/builtin/providers/aws/resource_aws_cloudtrail.go b/builtin/providers/aws/resource_aws_cloudtrail.go index ed7480625b..c8c639f802 100644 --- a/builtin/providers/aws/resource_aws_cloudtrail.go +++ b/builtin/providers/aws/resource_aws_cloudtrail.go @@ -74,6 +74,7 @@ func resourceAwsCloudTrail() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "tags": tagsSchema(), }, } } @@ -118,6 +119,7 @@ func resourceAwsCloudTrailCreate(d *schema.ResourceData, meta interface{}) error log.Printf("[DEBUG] CloudTrail created: %s", t) + d.Set("arn", *t.TrailARN) d.SetId(*t.Name) // AWS CloudTrail sets newly-created trails to false. @@ -128,7 +130,7 @@ func resourceAwsCloudTrailCreate(d *schema.ResourceData, meta interface{}) error } } - return resourceAwsCloudTrailRead(d, meta) + return resourceAwsCloudTrailUpdate(d, meta) } func resourceAwsCloudTrailRead(d *schema.ResourceData, meta interface{}) error { @@ -169,6 +171,26 @@ func resourceAwsCloudTrailRead(d *schema.ResourceData, meta interface{}) error { d.Set("arn", trail.TrailARN) d.Set("home_region", trail.HomeRegion) + // Get tags + req := &cloudtrail.ListTagsInput{ + ResourceIdList: []*string{trail.TrailARN}, + } + + tagsOut, err := conn.ListTags(req) + if err != nil { + return err + } + log.Printf("[DEBUG] Received CloudTrail tags: %s", tagsOut) + + var tags []*cloudtrail.Tag + if tagsOut.ResourceTagList != nil && len(tagsOut.ResourceTagList) > 0 { + tags = tagsOut.ResourceTagList[0].TagsList + } + + if err := d.Set("tags", tagsToMapCloudtrail(tags)); err != nil { + return err + } + logstatus, err := cloudTrailGetLoggingStatus(conn, trail.Name) if err != nil { return err @@ -219,6 +241,13 @@ func resourceAwsCloudTrailUpdate(d *schema.ResourceData, meta interface{}) error return err } + if d.HasChange("tags") { + err := setTagsCloudtrail(conn, d) + if err != nil { + return err + } + } + if d.HasChange("enable_logging") { log.Printf("[DEBUG] Updating logging on CloudTrail: %s", input) err := cloudTrailSetLogging(conn, d.Get("enable_logging").(bool), *input.Name) diff --git a/builtin/providers/aws/tagsCloudtrail.go b/builtin/providers/aws/tagsCloudtrail.go new file mode 100644 index 0000000000..3599d4fe17 --- /dev/null +++ b/builtin/providers/aws/tagsCloudtrail.go @@ -0,0 +1,92 @@ +package aws + +import ( + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cloudtrail" + "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 setTagsCloudtrail(conn *cloudtrail.CloudTrail, d *schema.ResourceData) error { + if d.HasChange("tags") { + oraw, nraw := d.GetChange("tags") + o := oraw.(map[string]interface{}) + n := nraw.(map[string]interface{}) + create, remove := diffTagsCloudtrail(tagsFromMapCloudtrail(o), tagsFromMapCloudtrail(n)) + + // Set tags + if len(remove) > 0 { + input := cloudtrail.RemoveTagsInput{ + ResourceId: aws.String(d.Get("arn").(string)), + TagsList: remove, + } + log.Printf("[DEBUG] Removing CloudTrail tags: %s", input) + _, err := conn.RemoveTags(&input) + if err != nil { + return err + } + } + if len(create) > 0 { + input := cloudtrail.AddTagsInput{ + ResourceId: aws.String(d.Get("arn").(string)), + TagsList: create, + } + log.Printf("[DEBUG] Adding CloudTrail tags: %s", input) + _, err := conn.AddTags(&input) + 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 diffTagsCloudtrail(oldTags, newTags []*cloudtrail.Tag) ([]*cloudtrail.Tag, []*cloudtrail.Tag) { + // First, we're creating everything we have + create := make(map[string]interface{}) + for _, t := range newTags { + create[*t.Key] = *t.Value + } + + // Build the list of what to remove + var remove []*cloudtrail.Tag + for _, t := range oldTags { + old, ok := create[*t.Key] + if !ok || old != *t.Value { + // Delete it! + remove = append(remove, t) + } + } + + return tagsFromMapCloudtrail(create), remove +} + +// tagsFromMap returns the tags for the given map of data. +func tagsFromMapCloudtrail(m map[string]interface{}) []*cloudtrail.Tag { + var result []*cloudtrail.Tag + for k, v := range m { + result = append(result, &cloudtrail.Tag{ + Key: aws.String(k), + Value: aws.String(v.(string)), + }) + } + + return result +} + +// tagsToMap turns the list of tags into a map. +func tagsToMapCloudtrail(ts []*cloudtrail.Tag) map[string]string { + result := make(map[string]string) + for _, t := range ts { + result[*t.Key] = *t.Value + } + + return result +}