-
Notifications
You must be signed in to change notification settings - Fork 51
/
role_tags.go
123 lines (109 loc) · 3.27 KB
/
role_tags.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package sso
/*
* AWS SSO CLI
* Copyright (c) 2021-2023 Aaron Turner <synfinatic at gmail dot com>
*
* This program is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or with the authors permission any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import (
"sort"
)
// RoleTags provides an interface to find roles which match a set of tags
type RoleTags map[string]map[string]string // ARN => TagKey => Value
func (r *RoleTags) GetRoleTags(role string) map[string]string {
rtags := *r
if v, ok := rtags[role]; ok {
return v
}
return map[string]string{}
}
// GetMatchingRoles returns the roles which match all the tags
func (r *RoleTags) GetMatchingRoles(tags map[string]string) []string {
matches := []string{}
for arn, rTags := range *r {
match := map[string]bool{}
for k, v := range tags {
if check, ok := rTags[k]; ok {
if v == check {
match[k] = true
}
}
}
if len(match) == len(tags) {
matches = append(matches, arn)
}
}
return matches
}
// GetPossibleMatches is like GetMatchingRoles, but takes another key
// and a list of values and it returns the unique set of all roles which
// match the base tags and all the possible combnations of key/values
func (r *RoleTags) GetPossibleUniqueRoles(tags map[string]string, key string, values []string) []string {
allRoles := []string{} // roles before removing duplicates
for _, val := range values {
// build our list of tags to look for matches with
checkTags := map[string]string{}
for k, v := range tags {
checkTags[k] = v
}
// add this specific key/value pair
checkTags[key] = val
// add all the matches to our list
allRoles = append(allRoles, r.GetMatchingRoles(checkTags)...)
}
// remove duplicates
roles := []string{}
dedup := map[string]bool{}
for _, role := range allRoles {
if _, ok := dedup[role]; !ok {
roles = append(roles, role)
dedup[role] = true
}
}
sort.Strings(roles)
return roles
}
// UsefulTags takes a map of tag key/value pairs and returns a list
// of tag keys which result in additional filtering
func (r *RoleTags) UsefulTags(tags map[string]string) []string {
roles := r.GetMatchingRoles(tags)
uniqueTags := map[string]map[string]int{}
for _, role := range roles {
for k, v := range (*r)[role] {
if _, ok := uniqueTags[k]; !ok {
uniqueTags[k] = map[string]int{}
uniqueTags[k][v] = 1
} else {
uniqueTags[k][v] += 1
}
}
}
tagKeys := []string{}
tagMatches := map[string]bool{}
currentRoleCnt := len(roles)
for k, tags := range uniqueTags {
for _, cnt := range tags {
if cnt < currentRoleCnt {
if _, ok := tagMatches[k]; !ok {
tagKeys = append(tagKeys, k)
tagMatches[k] = true
}
}
}
}
return tagKeys
}
func (r *RoleTags) GetMatchCount(tags map[string]string) int {
return len(r.GetMatchingRoles(tags))
}