Skip to content

Commit fbaac2f

Browse files
Merge pull request #598 from vossen-adobe/log_sync_progress
Add logging for user actions and umapi progress
2 parents 65c67cf + 82ac342 commit fbaac2f

File tree

5 files changed

+50
-9
lines changed

5 files changed

+50
-9
lines changed

examples/config files - basic/user-sync-config.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,13 @@ logging:
285285
# See the description of file_log_level for details of the allowed values.
286286
console_log_level: info
287287

288+
# (optional) log_progress (default value True)
289+
# Includes an indication of progress for user actions on the umapi
290+
# Useful for tracking sync progress for pulling down, creating,
291+
# or updating large numbers of users
292+
# eg: 71/100 (71.0%) match output from console
293+
log_progress: True
294+
288295
# The invocation_defaults section controls the default values used
289296
# for command-line arguments. (Of course, these cannot be used to
290297
# change defaults for how the configuration files are read.) This

user_sync/app.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,12 +310,24 @@ def init_log(logging_config):
310310
"""
311311
:type logging_config: user_sync.config.DictConfig
312312
"""
313+
314+
def progress(self, count, total, message="", *args, **kws):
315+
if self.show_progress:
316+
count = int(count)
317+
total = int(total)
318+
percent_done = round(100*count/total, 1) if total > 0 else 0
319+
message = "{0}/{1} ({2}%) {3}".format(count, total, percent_done, message)
320+
if message:
321+
self._log(logging.INFO, message, args, **kws)
322+
logging.Logger.progress = progress
323+
313324
builder = user_sync.config.OptionsBuilder(logging_config)
314325
builder.set_bool_value('log_to_file', False)
315326
builder.set_string_value('file_log_directory', 'logs')
316327
builder.set_string_value('file_log_name_format', '{:%Y-%m-%d}.log')
317328
builder.set_string_value('file_log_level', 'info')
318329
builder.set_string_value('console_log_level', 'info')
330+
builder.set_bool_value('log_progress', True)
319331
options = builder.get_options()
320332

321333
level_lookup = {
@@ -326,6 +338,7 @@ def init_log(logging_config):
326338
'critical': logging.CRITICAL
327339
}
328340

341+
logging.Logger.show_progress = bool(options['log_progress'])
329342
console_log_level = level_lookup.get(options['console_log_level'])
330343
if console_log_level is None:
331344
console_log_level = logging.INFO

user_sync/connector/umapi.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import json
2222
import logging
2323
# import helper
24+
import math
2425

2526
import jwt
2627
import six
@@ -113,16 +114,23 @@ def get_users(self):
113114

114115
def iter_users(self, in_group=None):
115116
users = {}
117+
total_count = 0
118+
page_count = 0
119+
page_size = 0
120+
page_number = 0
116121
try:
117-
if in_group:
118-
u_query = umapi_client.UsersQuery(self.connection, in_group=in_group)
119-
else:
120-
u_query = umapi_client.UsersQuery(self.connection)
121-
for u in u_query:
122+
u_query = umapi_client.UsersQuery(self.connection, in_group=in_group)
123+
for i, u in enumerate(u_query):
124+
total_count, page_count, page_size, page_number = u_query.stats()
122125
email = u['email']
123126
if not (email in users):
124127
users[email] = u
125128
yield u
129+
130+
if (i + 1) % page_size == 0:
131+
self.logger.progress(len(users), total_count)
132+
self.logger.progress(total_count, total_count)
133+
126134
except umapi_client.UnavailableError as e:
127135
raise AssertionException("Error contacting UMAPI server: %s" % e)
128136

user_sync/post_sync/manager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def remove_umapi_user_groups(self, org_id, user_key):
8383

8484
def remove_umapi_user(self, org_id, user_key):
8585
umapi_data = self.umapi_data.get(org_id)
86-
if user_key not in umapi_data:
86+
if not umapi_data or user_key not in umapi_data:
8787
return
8888
del umapi_data[user_key]
8989

user_sync/rules.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -485,11 +485,19 @@ def sync_umapi_users(self, umapi_connectors):
485485
else:
486486
primary_adds_by_user_key = self.update_umapi_users_for_connector(umapi_info, umapi_connector)
487487
# save groups for new users
488+
489+
total_users = len(primary_adds_by_user_key)
490+
491+
user_count = 0
488492
for user_key, groups_to_add in six.iteritems(primary_adds_by_user_key):
493+
user_count += 1
489494
if exclude_unmapped_users and not groups_to_add:
490495
# If user is not part of any group and ignore outcast is enabled. Do not create user.
491496
continue
492497
# We always create every user in the primary umapi, because it's believed to own the directories.
498+
if user_count % 10 == 0:
499+
self.logger.progress(user_count, total_users, 'actions completed')
500+
self.primary_users_created.add(user_key)
493501
self.create_umapi_user(user_key, groups_to_add, umapi_info, umapi_connector)
494502

495503
# then sync the secondary connectors
@@ -502,9 +510,13 @@ def sync_umapi_users(self, umapi_connectors):
502510
secondary_adds_by_user_key = umapi_info.get_desired_groups_by_user_key()
503511
else:
504512
secondary_adds_by_user_key = self.update_umapi_users_for_connector(umapi_info, umapi_connector)
513+
total_users = len(secondary_adds_by_user_key)
505514
for user_key, groups_to_add in six.iteritems(secondary_adds_by_user_key):
506515
# We only create users who have group mappings in the secondary umapi
507516
if groups_to_add:
517+
self.logger.progress(user_count, total_users,
518+
'Adding user to umapi {0} with user key: {1}'.format(umapi_name, user_key))
519+
self.secondary_users_created.add(user_key)
508520
if user_key not in self.primary_users_created:
509521
# We pushed an existing user to a secondary in order to update his groups
510522
self.updated_user_keys.add(user_key)
@@ -617,7 +629,7 @@ def manage_strays(self, umapi_connectors):
617629

618630
# all our processing is controlled by the strays in the primary organization
619631
primary_strays = self.get_stray_keys()
620-
self.action_summary['primary_strays_processed'] = len(primary_strays)
632+
self.action_summary['primary_strays_processed'] = total_strays = len(primary_strays)
621633

622634
# convenience function to get umapi Commands given a user key
623635
def get_commands(key):
@@ -661,15 +673,16 @@ def get_commands(key):
661673

662674
# finish with the primary umapi
663675
primary_connector = umapi_connectors.get_primary_connector()
664-
for user_key in primary_strays:
676+
for i, user_key in enumerate(primary_strays):
677+
per = round(100*(float(i)/float(total_strays)),3)
665678
commands = get_commands(user_key)
666679
if disentitle_strays:
667680
self.logger.info('Removing all adobe groups for Adobe-only user: %s', user_key)
668681
self.post_sync_data.remove_umapi_user_groups(None, user_key)
669682
commands.remove_all_groups()
670683
elif remove_strays or delete_strays:
671684
action = "Deleting" if delete_strays else "Removing"
672-
self.logger.info('%s Adobe-only user: %s', action, user_key)
685+
self.logger.info('(%s/%s)(%s%%) %s Adobe-only user: %s', i, total_strays, per, action, user_key)
673686
self.post_sync_data.remove_umapi_user(None, user_key)
674687
commands.remove_from_org(True if delete_strays else False)
675688
elif manage_stray_groups:

0 commit comments

Comments
 (0)