@@ -21,6 +21,7 @@ import (
2121
2222 "github.com/aws/aws-sdk-go-v2/aws"
2323 awsiam "github.com/aws/aws-sdk-go-v2/service/iam"
24+ "github.com/aws/aws-sdk-go-v2/service/iam/types"
2425 "github.com/google/go-cmp/cmp"
2526 "github.com/pkg/errors"
2627
@@ -45,13 +46,15 @@ import (
4546const (
4647 errUnexpectedObject = "The managed resource is not an IAM User resource"
4748
48- errGet = "cannot get IAM User"
49- errCreate = "cannot create the IAM User resource"
50- errDelete = "cannot delete the IAM User resource"
51- errUpdate = "cannot update the IAM User resource"
52- errSDK = "empty IAM User received from IAM API"
53- errTag = "cannot tag the IAM User resource"
54- errUntag = "cannot remove tags from the IAM User resource"
49+ errGet = "cannot get IAM User"
50+ errCreate = "cannot create the IAM User resource"
51+ errDelete = "cannot delete the IAM User resource"
52+ errUpdateUser = "cannot update the IAM User resource"
53+ errPutUserPermissionsBoundary = "cannot update the IAM User permission boundary"
54+ errDeleteUserPermissionsBoundary = "cannot delete the IAM User permission boundary"
55+ errSDK = "empty IAM User received from IAM API"
56+ errTag = "cannot tag the IAM User resource"
57+ errUntag = "cannot remove tags from the IAM User resource"
5558
5659 errKubeUpdateFailed = "cannot late initialize IAM User"
5760)
@@ -135,16 +138,9 @@ func (e *external) Observe(ctx context.Context, mgd resource.Managed) (managed.E
135138 UserID : aws .ToString (user .UserId ),
136139 }
137140
138- crTagMap := make (map [string ]string , len (cr .Spec .ForProvider .Tags ))
139- for _ , v := range cr .Spec .ForProvider .Tags {
140- crTagMap [v .Key ] = v .Value
141- }
142- _ , _ , areTagsUpdated := iam .DiffIAMTags (crTagMap , observed .User .Tags )
143-
144141 return managed.ExternalObservation {
145- ResourceExists : true ,
146- ResourceUpToDate : aws .ToString (cr .Spec .ForProvider .Path ) == aws .ToString (user .Path ) &&
147- areTagsUpdated ,
142+ ResourceExists : true ,
143+ ResourceUpToDate : isUpToDate (cr , & user ),
148144 }, nil
149145}
150146
@@ -171,44 +167,29 @@ func (e *external) Update(ctx context.Context, mgd resource.Managed) (managed.Ex
171167 return managed.ExternalUpdate {}, errors .New (errUnexpectedObject )
172168 }
173169
174- _ , err := e .client .UpdateUser (ctx , & awsiam.UpdateUserInput {
175- NewPath : cr .Spec .ForProvider .Path ,
176- UserName : aws .String (meta .GetExternalName (cr )),
177- })
178-
179- if err != nil {
180- return managed.ExternalUpdate {}, awsclient .Wrap (err , errUpdate )
181- }
182-
183170 observed , err := e .client .GetUser (ctx , & awsiam.GetUserInput {
184171 UserName : aws .String (meta .GetExternalName (cr )),
185172 })
186173
187174 if err != nil {
188- return managed.ExternalUpdate {}, awsclient .Wrap (err , errGet )
175+ return managed.ExternalUpdate {}, awsclient .Wrap (resource . Ignore ( iam . IsErrorNotFound , err ) , errGet )
189176 }
190177
191- add , remove , _ := iam .DiffIAMTagsWithUpdates (cr .Spec .ForProvider .Tags , observed .User .Tags )
192-
193- if len (add ) > 0 {
194- if _ , err := e .client .TagUser (ctx , & awsiam.TagUserInput {
195- UserName : aws .String (meta .GetExternalName (cr )),
196- Tags : add ,
197- }); err != nil {
198- return managed.ExternalUpdate {}, awsclient .Wrap (err , errTag )
199- }
178+ // take care of changes to path (only call if necessary)
179+ err = e .updateUser (ctx , observed , cr )
180+ if err != nil {
181+ return managed.ExternalUpdate {}, err
200182 }
201183
202- if len (remove ) > 0 {
203- if _ , err := e .client .UntagUser (ctx , & awsiam.UntagUserInput {
204- TagKeys : remove ,
205- UserName : aws .String (meta .GetExternalName (cr )),
206- }); err != nil {
207- return managed.ExternalUpdate {}, awsclient .Wrap (err , errUntag )
208- }
184+ // take care of changes to PermissionBoundary (only call if necessary)
185+ err = e .updatePermissionsBoundary (ctx , observed , cr )
186+ if err != nil {
187+ return managed.ExternalUpdate {}, err
209188 }
210189
211- return managed.ExternalUpdate {}, awsclient .Wrap (err , errUpdate )
190+ // take care of changes to Tags
191+ err = e .updateTags (ctx , observed , cr )
192+ return managed.ExternalUpdate {}, err
212193}
213194
214195func (e * external ) Delete (ctx context.Context , mgd resource.Managed ) error {
@@ -258,3 +239,91 @@ func (t *tagger) Initialize(ctx context.Context, mgd resource.Managed) error {
258239 }
259240 return errors .Wrap (t .kube .Update (ctx , cr ), errKubeUpdateFailed )
260241}
242+
243+ func (e * external ) updateUser (ctx context.Context , observed * awsiam.GetUserOutput , cr * v1beta1.User ) error {
244+ if aws .ToString (observed .User .Path ) != aws .ToString (cr .Spec .ForProvider .Path ) {
245+ _ , err := e .client .UpdateUser (ctx , & awsiam.UpdateUserInput {
246+ NewPath : cr .Spec .ForProvider .Path ,
247+ UserName : aws .String (meta .GetExternalName (cr )),
248+ })
249+
250+ return awsclient .Wrap (err , errUpdateUser )
251+ }
252+
253+ return nil
254+ }
255+
256+ func (e * external ) updatePermissionsBoundary (ctx context.Context , observed * awsiam.GetUserOutput , cr * v1beta1.User ) error {
257+ boundaryArn := ""
258+ var err error
259+
260+ if observed .User .PermissionsBoundary != nil {
261+ boundaryArn = * observed .User .PermissionsBoundary .PermissionsBoundaryArn
262+ }
263+ if aws .ToString (& boundaryArn ) != aws .ToString (cr .Spec .ForProvider .PermissionsBoundary ) {
264+ // is this a delete?
265+ if aws .ToString (cr .Spec .ForProvider .PermissionsBoundary ) == "" {
266+ _ , err = e .client .DeleteUserPermissionsBoundary (ctx , & awsiam.DeleteUserPermissionsBoundaryInput {
267+ UserName : aws .String (meta .GetExternalName (cr )),
268+ })
269+
270+ return awsclient .Wrap (err , errDeleteUserPermissionsBoundary )
271+ }
272+
273+ // must be an update
274+ _ , err = e .client .PutUserPermissionsBoundary (ctx , & awsiam.PutUserPermissionsBoundaryInput {
275+ PermissionsBoundary : cr .Spec .ForProvider .PermissionsBoundary ,
276+ UserName : aws .String (meta .GetExternalName (cr )),
277+ })
278+
279+ return awsclient .Wrap (err , errPutUserPermissionsBoundary )
280+ }
281+
282+ return nil
283+ }
284+
285+ func (e * external ) updateTags (ctx context.Context , observed * awsiam.GetUserOutput , cr * v1beta1.User ) error {
286+ add , remove , _ := iam .DiffIAMTagsWithUpdates (cr .Spec .ForProvider .Tags , observed .User .Tags )
287+
288+ if len (add ) > 0 {
289+ if _ , err := e .client .TagUser (ctx , & awsiam.TagUserInput {
290+ UserName : aws .String (meta .GetExternalName (cr )),
291+ Tags : add ,
292+ }); err != nil {
293+ return awsclient .Wrap (err , errTag )
294+ }
295+ }
296+
297+ if len (remove ) > 0 {
298+ if _ , err := e .client .UntagUser (ctx , & awsiam.UntagUserInput {
299+ TagKeys : remove ,
300+ UserName : aws .String (meta .GetExternalName (cr )),
301+ }); err != nil {
302+ return awsclient .Wrap (err , errUntag )
303+ }
304+ }
305+
306+ return nil
307+ }
308+
309+ func isUpToDate (cr * v1beta1.User , user * types.User ) bool {
310+ // check path
311+ isPathUpdated := aws .ToString (cr .Spec .ForProvider .Path ) == aws .ToString (user .Path )
312+
313+ // check tags
314+ crTagMap := make (map [string ]string , len (cr .Spec .ForProvider .Tags ))
315+ for _ , v := range cr .Spec .ForProvider .Tags {
316+ crTagMap [v .Key ] = v .Value
317+ }
318+ _ , _ , areTagsUpdated := iam .DiffIAMTags (crTagMap , user .Tags )
319+
320+ // check permissions boundary
321+ boundaryArn := ""
322+ if user .PermissionsBoundary != nil {
323+ boundaryArn = * user .PermissionsBoundary .PermissionsBoundaryArn
324+ }
325+ isBoundaryUpdated :=
326+ aws .ToString (cr .Spec .ForProvider .PermissionsBoundary ) == aws .ToString (& boundaryArn )
327+
328+ return isPathUpdated && areTagsUpdated && isBoundaryUpdated
329+ }
0 commit comments