@@ -15,9 +15,10 @@ package access_entry
15
15
16
16
import (
17
17
"context"
18
- "reflect"
19
18
19
+ ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare"
20
20
ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
21
+ "github.com/aws/aws-sdk-go/aws"
21
22
svcsdk "github.com/aws/aws-sdk-go/service/eks"
22
23
23
24
"github.com/aws-controllers-k8s/eks-controller/apis/v1alpha1"
@@ -87,34 +88,21 @@ func (rm *resourceManager) syncAccessPolicies(ctx context.Context, desired, late
87
88
rlog := ackrtlog .FromContext (ctx )
88
89
exit := rlog .Trace ("rm.syncAccessPolicies" )
89
90
defer func () { exit (err ) }()
90
- toAdd := []* v1alpha1.AssociateAccessPolicyInput {}
91
- toDelete := []* string {}
92
91
93
92
existingPolicies := latest .ko .Spec .AccessPolicies
93
+ desiredPolicies := desired .ko .Spec .AccessPolicies
94
94
95
- // find the policies to add
96
- for _ , p := range desired .ko .Spec .AccessPolicies {
97
- if ! exactMatchInAccessPolicies (p , existingPolicies ) {
98
- toAdd = append (toAdd , p )
99
- }
100
- }
95
+ toAdd , toDelete := computeAccessPoliciesDelta (desiredPolicies , existingPolicies )
101
96
102
- // find the policies to delete
103
- for _ , p := range existingPolicies {
104
- if ! inAccessPolicies (p , desired .ko .Spec .AccessPolicies ) {
105
- toDelete = append (toDelete , p .PolicyARN )
106
- }
107
- }
108
-
109
- // manage policies...
97
+ // remove policies first (to avoid conflicts)
110
98
for _ , p := range toDelete {
111
- rlog .Debug ("disassociating access policy from role " , "policy_arn" , * p )
99
+ rlog .Debug ("disassociating access policy from access entry " , "policy_arn" , * p )
112
100
if err = rm .disassociateAccessPolicy (ctx , desired , p ); err != nil {
113
101
return err
114
102
}
115
103
}
116
104
for _ , p := range toAdd {
117
- rlog .Debug ("associate access policy to access entry" , "policy_arn" , * p .PolicyARN )
105
+ rlog .Debug ("associating access policy to access entry" , "policy_arn" , * p .PolicyARN )
118
106
if err = rm .associateAccessPolicy (ctx , desired , p ); err != nil {
119
107
return err
120
108
}
@@ -123,28 +111,6 @@ func (rm *resourceManager) syncAccessPolicies(ctx context.Context, desired, late
123
111
return nil
124
112
}
125
113
126
- // inAccessPolicies returns true if the supplied AccessPolicy ARN exists
127
- // in the slice of AccessPolicy objects.
128
- func inAccessPolicies (policy * v1alpha1.AssociateAccessPolicyInput , policies []* v1alpha1.AssociateAccessPolicyInput ) bool {
129
- for _ , p := range policies {
130
- if p .PolicyARN == policy .PolicyARN {
131
- return false
132
- }
133
- }
134
- return false
135
- }
136
-
137
- // exactMatchInAccessPolicies returns true if the supplied AccessPolicy is in the
138
- // slice of AccessPolicy objects and the AccessScope is exactly the same.
139
- func exactMatchInAccessPolicies (policy * v1alpha1.AssociateAccessPolicyInput , policies []* v1alpha1.AssociateAccessPolicyInput ) bool {
140
- for _ , p := range policies {
141
- if p .PolicyARN == policy .PolicyARN {
142
- return reflect .DeepEqual (p .AccessScope , policy .AccessScope )
143
- }
144
- }
145
- return false
146
- }
147
-
148
114
// associateAccessPolicy adds the supplied AccessPolicy to the supplied
149
115
// AccessEntry resource.
150
116
func (rm * resourceManager ) associateAccessPolicy (
@@ -153,7 +119,7 @@ func (rm *resourceManager) associateAccessPolicy(
153
119
entry * v1alpha1.AssociateAccessPolicyInput ,
154
120
) (err error ) {
155
121
rlog := ackrtlog .FromContext (ctx )
156
- exit := rlog .Trace ("rm.addManagedPolicy " )
122
+ exit := rlog .Trace ("rm.associateAccessPolicy " )
157
123
defer func () { exit (err ) }()
158
124
159
125
input := & svcsdk.AssociateAccessPolicyInput {
@@ -190,3 +156,116 @@ func (rm *resourceManager) disassociateAccessPolicy(
190
156
rm .metrics .RecordAPICall ("UPDATE" , "DisassociateAccessPolicy" , err )
191
157
return err
192
158
}
159
+
160
+ // inAccessPolicies returns true if the supplied AccessPolicy ARN exists
161
+ // in the slice of AccessPolicy objects.
162
+ func inAccessPolicies (policy * v1alpha1.AssociateAccessPolicyInput , policies []* v1alpha1.AssociateAccessPolicyInput ) bool {
163
+ for _ , p := range policies {
164
+ if * p .PolicyARN == * policy .PolicyARN {
165
+ return true
166
+ }
167
+ }
168
+ return false
169
+ }
170
+
171
+ // equalAccessScopes returns true if the supplied AccessScope objects are
172
+ // exactly the same.
173
+ func equalAccessScopes (a , b * v1alpha1.AccessScope ) bool {
174
+ if a == nil && b == nil {
175
+ return true
176
+ }
177
+ if a == nil {
178
+ return equalZeroString (b .Type ) && len (b .Namespaces ) == 0
179
+ }
180
+ if b == nil {
181
+ return equalZeroString (b .Type ) && len (a .Namespaces ) == 0
182
+ }
183
+ return equalStrings (a .Type , b .Type ) && ackcompare .SliceStringPEqual (a .Namespaces , b .Namespaces )
184
+ }
185
+
186
+ // exactMatchInAccessPolicies returns true if the supplied AccessPolicy is in the
187
+ // slice of AccessPolicy objects and the AccessScope is exactly the same.
188
+ func exactMatchInAccessPolicies (policy * v1alpha1.AssociateAccessPolicyInput , policies []* v1alpha1.AssociateAccessPolicyInput ) bool {
189
+ for _ , p := range policies {
190
+ if p .PolicyARN == nil {
191
+ continue
192
+ }
193
+ if * p .PolicyARN == * policy .PolicyARN {
194
+ return equalAccessScopes (p .AccessScope , policy .AccessScope )
195
+ }
196
+ }
197
+ return false
198
+ }
199
+
200
+ // computeAccessPoliciesDelta returns two slices of AccessPolicy objects: one
201
+ // slice of AccessPolicy objects that are in the desired slice but not in the
202
+ // latest slice, and one slice of AccessPolicy objects that are in the latest
203
+ // slice but not in the desired slice.
204
+ func computeAccessPoliciesDelta (desired , latest []* v1alpha1.AssociateAccessPolicyInput ) (toAdd []* v1alpha1.AssociateAccessPolicyInput , toDelete []* string ) {
205
+ // useful for the toDelete elements
206
+ visited := map [string ]bool {}
207
+
208
+ // First we need to loop through the desired policies and see if they are
209
+ // in the latest policies. If they are, we need to check if the AccessScope
210
+ // is the same. If it is, we don't need to do anything. If it's not, we need
211
+ // to add the policy to the toAdd slice and remove it from the toDelete slice.
212
+ //
213
+ // The delete is necessary because the API dosen't allow us to update the
214
+ // AccessScope of an existing policy. We need to disassociate the policy and
215
+ // then reassociate it.
216
+ for _ , p := range desired {
217
+ visited [* p .PolicyARN ] = true
218
+ // If it's an exact match, we don't need to do anything.
219
+ if exactMatchInAccessPolicies (p , latest ) {
220
+ continue
221
+ }
222
+ // If it's in the latest policies, but the AccessScope is different, we
223
+ // need to remove it from the toDelete slice (update).
224
+ if inAccessPolicies (p , latest ) {
225
+ toAdd = append (toAdd , p )
226
+ toDelete = append (toDelete , p .PolicyARN )
227
+ } else {
228
+ // If it's not in the latest policies, we need to add it.
229
+ toAdd = append (toAdd , p )
230
+ }
231
+ }
232
+
233
+ // Now that we've handled the desired policies, we need to loop through the
234
+ // latest policies and see if they are in the desired policies. If they are
235
+ // not, we need to add them to the toDelete slice.
236
+ for _ , p := range latest {
237
+ // If we've already visited this policy, we don't need to do anything.
238
+ if visited [* p .PolicyARN ] {
239
+ continue
240
+ }
241
+ // If it's not in the desired policies, we need to remove it.
242
+ if ! inAccessPolicies (p , desired ) {
243
+ toDelete = append (toDelete , p .PolicyARN )
244
+ }
245
+ }
246
+ return toAdd , toDelete
247
+ }
248
+
249
+ func customPreCompare (delta * ackcompare.Delta , a , b * resource ) {
250
+ if len (a .ko .Spec .AccessPolicies ) != len (b .ko .Spec .AccessPolicies ) {
251
+ delta .Add ("Spec.AccessPolicies" , a .ko .Spec .AccessPolicies , b .ko .Spec .AccessPolicies )
252
+ } else if toAdd , toRemove := computeAccessPoliciesDelta (a .ko .Spec .AccessPolicies , b .ko .Spec .AccessPolicies ); len (toAdd ) > 0 || len (toRemove ) > 0 {
253
+ delta .Add ("Spec.AccessPolicies" , a .ko .Spec .AccessPolicies , b .ko .Spec .AccessPolicies )
254
+ }
255
+ }
256
+
257
+ // EqualStrings returns true if two strings are equal e.g., both are nil, one is
258
+ // nil and the other is empty string, or both non-zero strings are equal.
259
+ func equalStrings (a , b * string ) bool {
260
+ if a == nil {
261
+ return b == nil || * b == ""
262
+ }
263
+ if b == nil {
264
+ return * a == ""
265
+ }
266
+ return * a == * b
267
+ }
268
+
269
+ func equalZeroString (a * string ) bool {
270
+ return equalStrings (a , aws .String ("" ))
271
+ }
0 commit comments