@@ -53,6 +53,7 @@ def __init__(self, caller_options):
53
53
'max_adobe_only_users' : 200 ,
54
54
'new_account_type' : user_sync .identity_type .ENTERPRISE_IDENTITY_TYPE ,
55
55
'remove_strays' : False ,
56
+ 'strategy' : 'sync' ,
56
57
'stray_list_input_path' : None ,
57
58
'stray_list_output_path' : None ,
58
59
'test_mode' : False ,
@@ -111,6 +112,13 @@ def __init__(self, caller_options):
111
112
self .will_process_strays = (not options ['exclude_strays' ]) and (options ['stray_list_output_path' ] or
112
113
self .will_manage_strays )
113
114
115
+ # specifying a push strategy disables a lot of processing
116
+ self .sync_umapi = True
117
+ if options ['strategy' ] == 'push' :
118
+ self .sync_umapi = False
119
+ self .will_manage_strays = False
120
+ self .will_process_strays = False
121
+
114
122
# in/out variables for per-user after-mapping-hook code
115
123
self .after_mapping_hook_scope = {
116
124
# in: attributes retrieved from customer directory system (eg 'c', 'givenName')
@@ -154,15 +162,14 @@ def run(self, directory_groups, directory_connector, umapi_connectors):
154
162
load_directory_stats .log_start (logger )
155
163
self .read_desired_user_groups (directory_groups , directory_connector )
156
164
load_directory_stats .log_end (logger )
157
- should_sync_umapi_users = True
158
- else :
159
- # no directory users to sync with
160
- should_sync_umapi_users = False
161
165
162
- umapi_stats = JobStats (" Sync Umapi" , divider = "-" )
166
+ umapi_stats = JobStats (' Sync with UMAPI' if self . sync_umapi else 'Push to UMAPI' , divider = "-" )
163
167
umapi_stats .log_start (logger )
164
- if should_sync_umapi_users :
165
- self .process_umapi_users (umapi_connectors )
168
+ if directory_connector is not None :
169
+ if self .sync_umapi :
170
+ self .sync_umapi_users (umapi_connectors )
171
+ else :
172
+ self .push_umapi_users (umapi_connectors )
166
173
if self .will_process_strays :
167
174
self .process_strays (umapi_connectors )
168
175
umapi_connectors .execute_actions ()
@@ -203,15 +210,22 @@ def log_action_summary(self, umapi_connectors):
203
210
204
211
# English text description for action summary log.
205
212
# The action summary will be shown the same order as they are defined in this list
206
- action_summary_description = [
207
- ['directory_users_read' , 'Number of directory users read' ],
208
- ['directory_users_selected' , 'Number of directory users selected for input' ],
209
- ['adobe_users_read' , 'Number of Adobe users read' ],
210
- ['adobe_users_excluded' , 'Number of Adobe users excluded from updates' ],
211
- ['adobe_users_unchanged' , 'Number of non-excluded Adobe users with no changes' ],
212
- ['adobe_users_created' , 'Number of new Adobe users added' ],
213
- ['adobe_users_updated' , 'Number of matching Adobe users updated' ],
214
- ]
213
+ if self .sync_umapi :
214
+ action_summary_description = [
215
+ ['directory_users_read' , 'Number of directory users read' ],
216
+ ['directory_users_selected' , 'Number of directory users selected for input' ],
217
+ ['adobe_users_read' , 'Number of Adobe users read' ],
218
+ ['adobe_users_excluded' , 'Number of Adobe users excluded from updates' ],
219
+ ['adobe_users_unchanged' , 'Number of non-excluded Adobe users with no changes' ],
220
+ ['adobe_users_created' , 'Number of new Adobe users added' ],
221
+ ['adobe_users_updated' , 'Number of matching Adobe users updated' ],
222
+ ]
223
+ else :
224
+ action_summary_description = [
225
+ ['directory_users_read' , 'Number of directory users read' ],
226
+ ['directory_users_selected' , 'Number of directory users selected for input' ],
227
+ ['adobe_users_created' , 'Number of directory users pushed to Adobe' ],
228
+ ]
215
229
if self .will_process_strays :
216
230
if self .options ['delete_strays' ]:
217
231
action = 'deleted'
@@ -368,7 +382,7 @@ def is_directory_user_in_groups(self, directory_user, groups):
368
382
return True
369
383
return False
370
384
371
- def process_umapi_users (self , umapi_connectors ):
385
+ def sync_umapi_users (self , umapi_connectors ):
372
386
"""
373
387
This is where we actually "do the sync"; that is, where we match users on the two sides.
374
388
When we get here, we have loaded all the directory users *and* we have loaded all the adobe users,
@@ -393,7 +407,7 @@ def process_umapi_users(self, umapi_connectors):
393
407
# Handle creates for new users. This also drives adding the new user to the secondaries,
394
408
# but the secondary adobe groups will be managed below in the usual way.
395
409
for user_key , groups_to_add in six .iteritems (primary_adds_by_user_key ):
396
- self .add_umapi_user (user_key , groups_to_add , umapi_connectors )
410
+ self .add_umapi_user (user_key , groups_to_add , umapi_connectors , manage_secondary_groups = False )
397
411
# we just did a bunch of adds, we need to flush the connections before we can sync groups
398
412
umapi_connectors .execute_actions ()
399
413
@@ -408,6 +422,20 @@ def process_umapi_users(self, umapi_connectors):
408
422
self .logger .critical ("Shouldn't happen! In secondary umapi %s, the following users were not found: %s" ,
409
423
umapi_name , secondary_updates_by_user_key .keys ())
410
424
425
+ def push_umapi_users (self , umapi_connectors ):
426
+ """
427
+ This is where we push directory users to the Adobe side "as is".
428
+ :type umapi_connectors: UmapiConnectors
429
+ """
430
+ if umapi_connectors .get_secondary_connectors ():
431
+ self .logger .debug ('Pushing users to primary umapi...' )
432
+ else :
433
+ self .logger .debug ('Pushing users to umapi...' )
434
+ primary_umapi_info = self .get_umapi_info (PRIMARY_UMAPI_NAME )
435
+ # Create all the users, putting them in their groups
436
+ for user_key , groups_to_add in six .iteritems (primary_umapi_info .get_desired_groups_by_user_key ()):
437
+ self .add_umapi_user (user_key , groups_to_add , umapi_connectors , manage_secondary_groups = True )
438
+
411
439
def is_selected_user_key (self , user_key ):
412
440
"""
413
441
:type user_key: str
@@ -576,10 +604,11 @@ def create_commands_from_directory_user(self, directory_user, identity_type=None
576
604
directory_user ['username' ], directory_user ['domain' ])
577
605
return commands
578
606
579
- def add_umapi_user (self , user_key , groups_to_add , umapi_connectors ):
607
+ def add_umapi_user (self , user_key , groups_to_add , umapi_connectors , manage_secondary_groups = True ):
580
608
"""
581
- Add the user to the primary umapi with groups, and create in group-using secondaries without groups.
582
- The secondary group mappings should be taken care of by caller when the secondaries are walked.
609
+ Add the user to the primary umapi with the given groups, and create the user in any secondaries
610
+ in which he should be in a group. If directed, also add the user to those groups in the secondary.
611
+ If we are managing groups, we also remove the user from any mapped groups he shouldn't be in.
583
612
:type user_key: str
584
613
:type groups_to_add: list
585
614
:type umapi_connectors: UmapiConnectors
@@ -603,31 +632,35 @@ def add_umapi_user(self, user_key, groups_to_add, umapi_connectors):
603
632
# Enterprise users are allowed to have undefined country
604
633
country = 'UD'
605
634
else :
606
- self .logger .error ("User %s cannot be added as it has a blank country code"
607
- " and no default has been specified." , user_key )
635
+ self .logger .error ("Federated user cannot be added without a specified country code: %s" , user_key )
608
636
return
609
637
attributes ['country' ] = country
610
638
if attributes .get ('firstname' ) is None :
611
639
attributes .pop ('firstname' , None )
612
640
if attributes .get ('lastname' ) is None :
613
641
attributes .pop ('lastname' , None )
614
- attributes ['option' ] = "updateIfAlreadyExists" if update_user_info else 'ignoreIfAlreadyExists'
615
-
642
+ attributes ['option' ] = 'updateIfAlreadyExists' if update_user_info else 'ignoreIfAlreadyExists'
616
643
# add the user to primary with groups
617
644
self .logger .info ('Adding directory user with user key: %s' , user_key )
618
645
self .action_summary ['adobe_users_created' ] += 1
619
646
primary_commands .add_user (attributes )
620
647
if manage_groups :
621
648
primary_commands .add_groups (groups_to_add )
649
+ primary_commands .remove_groups (self .get_umapi_info (PRIMARY_UMAPI_NAME ).get_mapped_groups () - groups_to_add )
622
650
umapi_connectors .get_primary_connector ().send_commands (primary_commands )
623
- # add the user to secondaries without groups
651
+ # add the user to secondaries, maybe with groups
652
+ attributes ['option' ] = 'ignoreIfAlreadyExists' # can only update in the owning org
624
653
for umapi_name , umapi_connector in six .iteritems (umapi_connectors .secondary_connectors ):
625
654
secondary_umapi_info = self .get_umapi_info (umapi_name )
626
655
# only add the user to this secondary if he is in groups in this secondary
627
- if secondary_umapi_info .get_desired_groups (user_key ):
656
+ groups_to_add = secondary_umapi_info .get_desired_groups (user_key )
657
+ if groups_to_add :
628
658
self .logger .info ('Adding directory user to %s with user key: %s' , umapi_name , user_key )
629
659
secondary_commands = self .create_commands_from_directory_user (directory_user , identity_type )
630
660
secondary_commands .add_user (attributes )
661
+ if manage_secondary_groups and manage_groups :
662
+ secondary_commands .add_groups (groups_to_add )
663
+ secondary_commands .remove_groups (secondary_umapi_info .get_mapped_groups () - groups_to_add )
631
664
umapi_connector .send_commands (secondary_commands )
632
665
633
666
def update_umapi_user (self , umapi_info , user_key , umapi_connector ,
0 commit comments