@@ -19,6 +19,8 @@ import (
19
19
ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
20
20
ackutil "github.com/aws-controllers-k8s/runtime/pkg/util"
21
21
svcsdk "github.com/aws/aws-sdk-go/service/iam"
22
+
23
+ svcapitypes "github.com/aws-controllers-k8s/iam-controller/apis/v1alpha1"
22
24
)
23
25
24
26
// syncPolicies examines the PolicyARNs in the supplied Role and calls the
@@ -53,14 +55,14 @@ func (rm *resourceManager) syncPolicies(
53
55
}
54
56
55
57
for _ , p := range toAdd {
56
- rlog .Debug ("attaching policy to role" , "policy_arn" , * p )
57
- if err = rm .attachPolicy (ctx , r , p ); err != nil {
58
+ rlog .Debug ("adding policy to role" , "policy_arn" , * p )
59
+ if err = rm .addPolicy (ctx , r , p ); err != nil {
58
60
return err
59
61
}
60
62
}
61
63
for _ , p := range toDelete {
62
- rlog .Debug ("detaching policy from role" , "policy_arn" , * p )
63
- if err = rm .detachPolicy (ctx , r , p ); err != nil {
64
+ rlog .Debug ("removing policy from role" , "policy_arn" , * p )
65
+ if err = rm .removePolicy (ctx , r , p ); err != nil {
64
66
return err
65
67
}
66
68
}
@@ -97,14 +99,14 @@ func (rm *resourceManager) getPolicies(
97
99
return res , err
98
100
}
99
101
100
- // attachPolicy attaches the supplied Policy to the supplied Role resource
101
- func (rm * resourceManager ) attachPolicy (
102
+ // addPolicy adds the supplied Policy to the supplied Role resource
103
+ func (rm * resourceManager ) addPolicy (
102
104
ctx context.Context ,
103
105
r * resource ,
104
106
policyARN * string ,
105
107
) (err error ) {
106
108
rlog := ackrtlog .FromContext (ctx )
107
- exit := rlog .Trace ("rm.attachPolicy " )
109
+ exit := rlog .Trace ("rm.addPolicy " )
108
110
defer exit (err )
109
111
110
112
input := & svcsdk.AttachRolePolicyInput {}
@@ -115,14 +117,14 @@ func (rm *resourceManager) attachPolicy(
115
117
return err
116
118
}
117
119
118
- // detachPolicy detaches the supplied Policy from the supplied Role resource
119
- func (rm * resourceManager ) detachPolicy (
120
+ // removePolicy removes the supplied Policy from the supplied Role resource
121
+ func (rm * resourceManager ) removePolicy (
120
122
ctx context.Context ,
121
123
r * resource ,
122
124
policyARN * string ,
123
125
) (err error ) {
124
126
rlog := ackrtlog .FromContext (ctx )
125
- exit := rlog .Trace ("rm.detachPolicy " )
127
+ exit := rlog .Trace ("rm.removePolicy " )
126
128
defer exit (err )
127
129
128
130
input := & svcsdk.DetachRolePolicyInput {}
@@ -132,3 +134,144 @@ func (rm *resourceManager) detachPolicy(
132
134
rm .metrics .RecordAPICall ("DELETE" , "DetachRolePolicy" , err )
133
135
return err
134
136
}
137
+
138
+ // syncTags examines the Tags in the supplied Role and calls the ListRoleTags,
139
+ // TagRole and UntagRole APIs to ensure that the set of associated Tags stays
140
+ // in sync with the Role.Spec.Tags
141
+ func (rm * resourceManager ) syncTags (
142
+ ctx context.Context ,
143
+ r * resource ,
144
+ ) (err error ) {
145
+ rlog := ackrtlog .FromContext (ctx )
146
+ exit := rlog .Trace ("rm.syncTags" )
147
+ defer exit (err )
148
+ toAdd := []* svcapitypes.Tag {}
149
+ toDelete := []* svcapitypes.Tag {}
150
+
151
+ existingTags , err := rm .getTags (ctx , r )
152
+ if err != nil {
153
+ return err
154
+ }
155
+
156
+ for _ , t := range r .ko .Spec .Tags {
157
+ if ! inTags (* t .Key , * t .Value , existingTags ) {
158
+ toAdd = append (toAdd , t )
159
+ }
160
+ }
161
+
162
+ for _ , t := range existingTags {
163
+ if ! inTags (* t .Key , * t .Value , r .ko .Spec .Tags ) {
164
+ toDelete = append (toDelete , t )
165
+ }
166
+ }
167
+
168
+ for _ , t := range toAdd {
169
+ rlog .Debug ("adding tag to role" , "key" , * t .Key , "value" , * t .Value )
170
+ }
171
+ if err = rm .addTags (ctx , r , toAdd ); err != nil {
172
+ return err
173
+ }
174
+ for _ , t := range toDelete {
175
+ rlog .Debug ("removing tag from role" , "key" , * t .Key , "value" , * t .Value )
176
+ }
177
+ if err = rm .removeTags (ctx , r , toDelete ); err != nil {
178
+ return err
179
+ }
180
+
181
+ return nil
182
+ }
183
+
184
+ // inTags returns true if the supplied key and value can be found in the
185
+ // supplied list of Tag structs.
186
+ //
187
+ // TODO(jaypipes): When we finally standardize Tag handling in ACK, move this
188
+ // to the ACK common runtime/ or pkg/ repos
189
+ func inTags (
190
+ key string ,
191
+ value string ,
192
+ tags []* svcapitypes.Tag ,
193
+ ) bool {
194
+ for _ , t := range tags {
195
+ if * t .Key == key && * t .Value == value {
196
+ return true
197
+ }
198
+ }
199
+ return false
200
+ }
201
+
202
+ // getTags returns the list of Policy ARNs currently attached to the Role
203
+ func (rm * resourceManager ) getTags (
204
+ ctx context.Context ,
205
+ r * resource ,
206
+ ) ([]* svcapitypes.Tag , error ) {
207
+ var err error
208
+ var resp * svcsdk.ListRoleTagsOutput
209
+ rlog := ackrtlog .FromContext (ctx )
210
+ exit := rlog .Trace ("rm.getTags" )
211
+ defer exit (err )
212
+
213
+ input := & svcsdk.ListRoleTagsInput {}
214
+ input .RoleName = r .ko .Spec .Name
215
+ res := []* svcapitypes.Tag {}
216
+
217
+ for {
218
+ resp , err = rm .sdkapi .ListRoleTagsWithContext (ctx , input )
219
+ if err != nil || resp == nil {
220
+ break
221
+ }
222
+ for _ , t := range resp .Tags {
223
+ res = append (res , & svcapitypes.Tag {Key : t .Key , Value : t .Value })
224
+ }
225
+ if resp .IsTruncated != nil && ! * resp .IsTruncated {
226
+ break
227
+ }
228
+ }
229
+ rm .metrics .RecordAPICall ("GET" , "ListRoleTags" , err )
230
+ return res , err
231
+ }
232
+
233
+ // addTags adds the supplied Tags to the supplied Role resource
234
+ func (rm * resourceManager ) addTags (
235
+ ctx context.Context ,
236
+ r * resource ,
237
+ tags []* svcapitypes.Tag ,
238
+ ) (err error ) {
239
+ rlog := ackrtlog .FromContext (ctx )
240
+ exit := rlog .Trace ("rm.addTag" )
241
+ defer exit (err )
242
+
243
+ input := & svcsdk.TagRoleInput {}
244
+ input .RoleName = r .ko .Spec .Name
245
+ inTags := []* svcsdk.Tag {}
246
+ for _ , t := range tags {
247
+ inTags = append (inTags , & svcsdk.Tag {Key : t .Key , Value : t .Value })
248
+ }
249
+ input .Tags = inTags
250
+
251
+ _ , err = rm .sdkapi .TagRoleWithContext (ctx , input )
252
+ rm .metrics .RecordAPICall ("CREATE" , "TagRole" , err )
253
+ return err
254
+ }
255
+
256
+ // removeTags removes the supplied Tags from the supplied Role resource
257
+ func (rm * resourceManager ) removeTags (
258
+ ctx context.Context ,
259
+ r * resource ,
260
+ tags []* svcapitypes.Tag ,
261
+ ) (err error ) {
262
+ rlog := ackrtlog .FromContext (ctx )
263
+ exit := rlog .Trace ("rm.removeTag" )
264
+ defer exit (err )
265
+
266
+ input := & svcsdk.UntagRoleInput {}
267
+ input .RoleName = r .ko .Spec .Name
268
+ inTagKeys := []* string {}
269
+ for _ , t := range tags {
270
+ inTagKeys = append (inTagKeys , t .Key )
271
+ }
272
+ input .TagKeys = inTagKeys
273
+
274
+ _ , err = rm .sdkapi .UntagRoleWithContext (ctx , input )
275
+ rm .metrics .RecordAPICall ("DELETE" , "UntagRole" , err )
276
+ return err
277
+ }
0 commit comments