Skip to content

Commit

Permalink
Merge pull request #169 from Cox-Automotive/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
elliottzack429 authored May 12, 2022
2 parents e3495d3 + 03ffb92 commit aefa1d4
Show file tree
Hide file tree
Showing 12 changed files with 621 additions and 104 deletions.
30 changes: 30 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

Rally # (issue / story / spike)

## Type of change

_Please remove options that are not relevant._

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] Feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation

# How has this been tested?

## Steps:
1. Step 1
2. Step 2
3. Step 3
4. etc...

# Checklist / To Do:

- [ ] Run Terraform non-prod
- [ ] Run Terraform prod
- [ ] Write documentation reflecting the change
- [ ] Add param store value in non-prod
- [ ] Add param store value in prod
2 changes: 1 addition & 1 deletion docs/guides/local_installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ mkdir -p ~/.terraform.d/plugins &&

```sh
mkdir -p ~/.terraform.d/plugins/Cox-Automotive/engineering-enablement/alks/2.0.5/darwin_amd64 &&
curl -Ls https://api.github.com/repos/Cox-Automotive/terraform-provider-alks/releases | jq -r --arg release "v2.1.1" --arg arch "$(uname -s | tr A-Z a-z)" '.[] | select(.tag_name | contains($release)) | .assets[]| select(.browser_download_url | contains($arch)) | select(.browser_download_url | contains("amd64")) | .browser_download_url' |
curl -Ls https://api.github.com/repos/Cox-Automotive/terraform-provider-alks/releases | jq -r --arg release "v2.3.0" --arg arch "$(uname -s | tr A-Z a-z)" '.[] | select(.tag_name | contains($release)) | .assets[]| select(.browser_download_url | contains($arch)) | select(.browser_download_url | contains("amd64")) | .browser_download_url' |
xargs -n 1 curl -Lo ~/.terraform.d/plugins/Cox-Automotive/engineering-enablement/alks/2.0.5/darwin_amd64/terraform-provider-alks.zip &&
pushd ~/.terraform.d/plugins/Cox-Automotive/engineering-enablement/alks/2.0.5/darwin_amd64 &&
unzip ~/.terraform.d/plugins/Cox-Automotive/engineering-enablement/alks/2.0.5/darwin_amd64/terraform-provider-alks.zip -d terraform-provider-alks-tmp &&
Expand Down
12 changes: 12 additions & 0 deletions examples/alks.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
#
provider "alks" {
url = "https://alks.foo.com/rest"
default_tags { # All resources created by this provider will have these tags
tags = {
"ci:id" = "ABC1234" #If you have a colon in the key, it must be in quotes
}
}
ignore_tags { # These tags are considered external and will not be tracked or removed by the provider
keys = ["ignoreTagsWithThisKey"]
key_prefixes = ["ignoreKeysWithThisPrefx"]
}
}

# Second ALKS provider, for an account I have access to.
Expand Down Expand Up @@ -38,6 +47,9 @@ resource "alks_iamrole" "test_role" {
type = "AWS CodeBuild"
include_default_policies = false
enable_alks_access = true
tags = {
roleTagKey = "RoleTagValue"
}
}

resource "alks_iamrole" "test_dynamic_role" {
Expand Down
133 changes: 91 additions & 42 deletions iam_tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ package main
import (
"context"
"fmt"
"strings"

"github.com/Cox-Automotive/alks-go"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

type TagMap map[string]interface{}
type IgnoreTags struct {
Keys TagMap
KeyPrefixes TagMap
}

func TagsSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeMap,
Expand All @@ -25,22 +32,73 @@ func TagsSchemaComputed() *schema.Schema {
}
}

func SetTagsDiff(_ context.Context, diff *schema.ResourceDiff, meta interface{}) error {
defaultTags := meta.(*AlksClient).defaultTags
ignoredTags := meta.(*AlksClient).ignoreTags
resourceTags := (diff.Get("tags")).(map[string]interface{})
//default tag values will be overwritten by resource values if key exists in both maps
allTags := combineTagMaps(defaultTags, resourceTags)
localTags := removeIgnoredTags(allTags, *ignoredTags)

// To ensure "tags_all" is correctly computed, we explicitly set the attribute diff
// when the merger of resource-level tags onto provider-level tags results in n > 0 tags,
// otherwise we mark the attribute as "Computed" only when their is a known diff (excluding an empty map)
// or a change for "tags_all".

if len(localTags) > 0 {
if err := diff.SetNew("tags_all", localTags); err != nil {
return fmt.Errorf("error setting new tags_all diff: %w", err)
}
} else if len(diff.Get("tags_all").(map[string]interface{})) > 0 {
if err := diff.SetNewComputed("tags_all"); err != nil {
return fmt.Errorf("error setting tags_all to computed: %w", err)
}
} else if diff.HasChange("tags_all") {
if err := diff.SetNewComputed("tags_all"); err != nil {
return fmt.Errorf("error setting tags_all to computed: %w", err)
}
}

return nil
}

//Removes default tags from a map of role specific + default tags
func removeDefaultTags(allTags map[string]interface{}, defalutTags []alks.Tag) []alks.Tag {
for _, t := range defalutTags {
func removeDefaultTags(allTags TagMap, defaultTags TagMap) TagMap {
for k, v := range defaultTags {
//If the key and value of a tag returned from the role exists in the defaultTags list
//We will assume it was set as a default tag and remove it from role specific tag list
if val, ok := allTags[t.Key]; ok {
if val == t.Value {
delete(allTags, t.Key)
if val, ok := allTags[k]; ok {
if val == v {
delete(allTags, k)
}
}

}
return tagMapToSlice(allTags)
return allTags
}

func tagMapToSlice(tagMap map[string]interface{}) []alks.Tag {
func removeIgnoredTags(allTags TagMap, ignoredTags IgnoreTags) TagMap {
localMap := TagMap{}
for k, v := range allTags {
localMap[k] = v.(string)
}

for k := range allTags {
if _, ok := ignoredTags.Keys[k]; ok {
delete(localMap, k)
} else {
for kp := range ignoredTags.KeyPrefixes {
if strings.HasPrefix(k, kp) {
delete(localMap, k)
}
}
}

}
return localMap
}

func tagMapToSlice(tagMap TagMap) []alks.Tag {
tags := []alks.Tag{}
for k, v := range tagMap {
tag := alks.Tag{Key: k, Value: v.(string)}
Expand All @@ -49,52 +107,43 @@ func tagMapToSlice(tagMap map[string]interface{}) []alks.Tag {
return tags
}

func tagSliceToMap(tagSlice []alks.Tag) map[string]interface{} {
tagMap := make(map[string]interface{})
func tagSliceToMap(tagSlice []alks.Tag) TagMap {
tagMap := make(TagMap)
for _, t := range tagSlice {
tagMap[t.Key] = t.Value
}
return tagMap
}

//Combines tags defined on an individual resource with the default tags listed on the provider block
//Resource specific tags will overwrite default tags
func combineTagsWithDefault(tags []alks.Tag, defaultTags []alks.Tag) []alks.Tag {
defaultTagsMap := tagSliceToMap(defaultTags)

for _, t := range tags {
defaultTagsMap[t.Key] = t.Value
func getExternalyManagedTags(roleTags TagMap, ignoredTags IgnoreTags) TagMap {
externalTags := TagMap{}
//Loop Through ignored keys and ignored key prefixes, checking if a tag exists that should be ignored
for k := range ignoredTags.Keys {
if val, ok := roleTags[k]; ok {
externalTags[k] = val.(string)
}
}
allTags := tagMapToSlice(defaultTagsMap)

return allTags
for p := range ignoredTags.KeyPrefixes {
for k, v := range roleTags {
if strings.HasPrefix(k, p) {
externalTags[k] = v.(string)
}
}
}
return externalTags
}

func SetTagsDiff(_ context.Context, diff *schema.ResourceDiff, meta interface{}) error {
defaultTags := meta.(*AlksClient).defaultTags

resourceTags := tagMapToSlice(diff.Get("tags").(map[string]interface{}))

allTags := combineTagsWithDefault(resourceTags, defaultTags)

// To ensure "tags_all" is correctly computed, we explicitly set the attribute diff
// when the merger of resource-level tags onto provider-level tags results in n > 0 tags,
// otherwise we mark the attribute as "Computed" only when their is a known diff (excluding an empty map)
// or a change for "tags_all".
//Combine two tag maps. Values in map2 will overwrite values in map1 if they exist in both maps
func combineTagMaps(baseMap TagMap, mergeMap TagMap) TagMap {
LocalMap := TagMap{}

if len(allTags) > 0 {
if err := diff.SetNew("tags_all", tagSliceToMap(allTags)); err != nil {
return fmt.Errorf("error setting new tags_all diff: %w", err)
}
} else if len(diff.Get("tags_all").(map[string]interface{})) > 0 {
if err := diff.SetNewComputed("tags_all"); err != nil {
return fmt.Errorf("error setting tags_all to computed: %w", err)
}
} else if diff.HasChange("tags_all") {
if err := diff.SetNewComputed("tags_all"); err != nil {
return fmt.Errorf("error setting tags_all to computed: %w", err)
}
for k, v := range baseMap {
LocalMap[k] = v
}
for k, v := range mergeMap {
LocalMap[k] = v
}

return nil
return LocalMap
}
Loading

0 comments on commit aefa1d4

Please sign in to comment.