@@ -16,6 +16,7 @@ package userpool
1616import (
1717 "context"
1818 "reflect"
19+ "strings"
1920
2021 svcsdk "github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
2122 svcsdkapi "github.com/aws/aws-sdk-go/service/cognitoidentityprovider/cognitoidentityprovideriface"
@@ -53,6 +54,7 @@ func SetupUserPool(mgr ctrl.Manager, o controller.Options) error {
5354 e .preObserve = preObserve
5455 e .postObserve = postObserve
5556 e .preUpdate = h .preUpdate
57+ e .postUpdate = h .postUpdate
5658 e .preDelete = preDelete
5759 e .preCreate = preCreate
5860 e .postCreate = postCreate
@@ -93,7 +95,8 @@ func SetupUserPool(mgr ctrl.Manager, o controller.Options) error {
9395}
9496
9597type hooks struct {
96- client svcsdkapi.CognitoIdentityProviderAPI
98+ client svcsdkapi.CognitoIdentityProviderAPI
99+ currentCustomAttributes []* svcsdk.SchemaAttributeType
97100}
98101
99102func preObserve (_ context.Context , cr * svcapitypes.UserPool , obj * svcsdk.DescribeUserPoolInput ) error {
@@ -313,28 +316,43 @@ func arePoliciesEqual(spec *svcapitypes.UserPoolPolicyType, current *svcsdk.User
313316 return true
314317}
315318
316- func areSchemaEqual (spec []* svcapitypes.SchemaAttributeType , current []* svcsdk.SchemaAttributeType ) bool {
319+ func areSchemaEqual (spec []* svcapitypes.SchemaAttributeType , current []* svcsdk.SchemaAttributeType ) bool { //nolint:gocyclo
317320 if spec != nil && current != nil {
318- if len (spec ) > 0 && len (spec ) != len (current ) {
319- return false
320- }
321-
322- for i , s := range spec {
323- switch {
324- case pointer .StringValue (s .AttributeDataType ) != pointer .StringValue (current [i ].AttributeDataType ),
325- pointer .BoolValue (s .DeveloperOnlyAttribute ) != pointer .BoolValue (current [i ].DeveloperOnlyAttribute ),
326- pointer .BoolValue (s .Mutable ) != pointer .BoolValue (current [i ].Mutable ),
327- pointer .StringValue (s .Name ) != pointer .StringValue (current [i ].Name ),
328- pointer .StringValue (s .NumberAttributeConstraints .MaxValue ) != pointer .StringValue (current [i ].NumberAttributeConstraints .MaxValue ),
329- pointer .StringValue (s .NumberAttributeConstraints .MinValue ) != pointer .StringValue (current [i ].NumberAttributeConstraints .MinValue ),
330- pointer .BoolValue (s .Required ) != pointer .BoolValue (current [i ].Required ),
331- pointer .StringValue (s .StringAttributeConstraints .MaxLength ) != pointer .StringValue (current [i ].StringAttributeConstraints .MaxLength ),
332- pointer .StringValue (s .StringAttributeConstraints .MinLength ) != pointer .StringValue (current [i ].StringAttributeConstraints .MinLength ):
333- return false
321+ if len (spec ) == 0 {
322+ return true
323+ }
324+
325+ for _ , s := range spec {
326+ for _ , cur := range current {
327+ if * s .Name != strings .TrimPrefix (* cur .Name , "custom:" ) {
328+ continue
329+ }
330+ switch {
331+ case pointer .StringValue (s .AttributeDataType ) != pointer .StringValue (cur .AttributeDataType ),
332+ pointer .BoolValue (s .DeveloperOnlyAttribute ) != pointer .BoolValue (cur .DeveloperOnlyAttribute ),
333+ pointer .BoolValue (s .Mutable ) != pointer .BoolValue (cur .Mutable ),
334+ pointer .BoolValue (s .Required ) != pointer .BoolValue (cur .Required ),
335+ s .NumberAttributeConstraints == nil && cur .NumberAttributeConstraints != nil ,
336+ s .NumberAttributeConstraints != nil && cur .NumberAttributeConstraints == nil ,
337+ s .StringAttributeConstraints == nil && cur .StringAttributeConstraints != nil ,
338+ s .StringAttributeConstraints != nil && cur .StringAttributeConstraints == nil :
339+ return false
340+ }
341+ if s .NumberAttributeConstraints != nil && cur .NumberAttributeConstraints != nil {
342+ if pointer .StringValue (s .NumberAttributeConstraints .MaxValue ) != pointer .StringValue (cur .NumberAttributeConstraints .MaxValue ) ||
343+ pointer .StringValue (s .NumberAttributeConstraints .MinValue ) != pointer .StringValue (cur .NumberAttributeConstraints .MinValue ) {
344+ return false
345+ }
346+ }
347+ if s .StringAttributeConstraints != nil && cur .StringAttributeConstraints != nil {
348+ if pointer .StringValue (s .StringAttributeConstraints .MaxLength ) != pointer .StringValue (cur .StringAttributeConstraints .MaxLength ) ||
349+ pointer .StringValue (s .StringAttributeConstraints .MinLength ) != pointer .StringValue (cur .StringAttributeConstraints .MinLength ) {
350+ return false
351+ }
352+ }
334353 }
335354 }
336355 }
337-
338356 return true
339357}
340358
@@ -460,7 +478,7 @@ func (e *hooks) areMFAConfigEqual(cr *svcapitypes.UserPool) (bool, error) {
460478 return true , nil
461479}
462480
463- func lateInitialize (cr * svcapitypes.UserPoolParameters , resp * svcsdk.DescribeUserPoolOutput ) error {
481+ func lateInitialize (cr * svcapitypes.UserPoolParameters , resp * svcsdk.DescribeUserPoolOutput ) error { //nolint:gocyclo
464482 instance := resp .UserPool
465483
466484 cr .MFAConfiguration = pointer .LateInitialize (cr .MFAConfiguration , instance .MfaConfiguration )
@@ -500,6 +518,21 @@ func lateInitialize(cr *svcapitypes.UserPoolParameters, resp *svcsdk.DescribeUse
500518 cr .VerificationMessageTemplate .DefaultEmailOption = pointer .LateInitialize (cr .VerificationMessageTemplate .DefaultEmailOption , instance .VerificationMessageTemplate .DefaultEmailOption )
501519 }
502520
521+ if cr .Schema != nil || len (cr .Schema ) > 0 {
522+ for i , scheme := range cr .Schema {
523+ if scheme .StringAttributeConstraints != nil {
524+ continue
525+ }
526+ for _ , schemaAttribute := range instance .SchemaAttributes {
527+ if * scheme .Name == strings .TrimPrefix (* schemaAttribute .Name , "custom:" ) {
528+ cr .Schema [i ].StringAttributeConstraints = & svcapitypes.StringAttributeConstraintsType {
529+ MaxLength : schemaAttribute .StringAttributeConstraints .MaxLength ,
530+ MinLength : schemaAttribute .StringAttributeConstraints .MinLength ,
531+ }
532+ }
533+ }
534+ }
535+ }
503536 // Info: to avoid redundancy+problems, do not lateInit conflicting fields
504537 // (e.g. VerificationMessageTemplate.SmsMessage & SmsVerificationMessage)
505538
@@ -549,3 +582,56 @@ func (e *hooks) setMfaConfiguration(ctx context.Context, cr *svcapitypes.UserPoo
549582
550583 return nil
551584}
585+
586+ func (h * hooks ) postUpdate (ctx context.Context , cr * svcapitypes.UserPool , _ * svcsdk.UpdateUserPoolOutput , updateExternalUpdate managed.ExternalUpdate , updateError error ) (managed.ExternalUpdate , error ) {
587+ if updateError != nil {
588+ return updateExternalUpdate , updateError
589+ }
590+
591+ for _ , scheme := range cr .Spec .ForProvider .Schema {
592+ isNew := true
593+ for _ , schemaAttribute := range cr .Status .AtProvider .SchemaAttributes {
594+ if * scheme .Name == strings .TrimPrefix (* schemaAttribute .Name , "custom:" ) {
595+ isNew = false
596+ }
597+ }
598+ if isNew {
599+ _ , err := h .client .AddCustomAttributes (& svcsdk.AddCustomAttributesInput {
600+ CustomAttributes : []* svcsdk.SchemaAttributeType {
601+ convertSchemaAttribute (scheme ),
602+ },
603+ UserPoolId : pointer .ToOrNilIfZeroValue (meta .GetExternalName (cr )),
604+ })
605+ if err != nil {
606+ return managed.ExternalUpdate {}, err
607+ }
608+ }
609+ }
610+ return managed.ExternalUpdate {}, nil
611+ }
612+
613+ func convertSchemaAttribute (in * svcapitypes.SchemaAttributeType ) * svcsdk.SchemaAttributeType {
614+ out := & svcsdk.SchemaAttributeType {
615+ AttributeDataType : in .AttributeDataType ,
616+ DeveloperOnlyAttribute : in .DeveloperOnlyAttribute ,
617+ Mutable : in .Mutable ,
618+ Name : in .Name ,
619+ Required : in .Required ,
620+ }
621+
622+ if in .NumberAttributeConstraints != nil {
623+ out .NumberAttributeConstraints = & svcsdk.NumberAttributeConstraintsType {
624+ MaxValue : in .NumberAttributeConstraints .MaxValue ,
625+ MinValue : in .NumberAttributeConstraints .MinValue ,
626+ }
627+ }
628+
629+ if in .StringAttributeConstraints != nil {
630+ out .StringAttributeConstraints = & svcsdk.StringAttributeConstraintsType {
631+ MaxLength : in .StringAttributeConstraints .MaxLength ,
632+ MinLength : in .StringAttributeConstraints .MinLength ,
633+ }
634+ }
635+
636+ return out
637+ }
0 commit comments