Skip to content

Commit 74514f4

Browse files
committed
2 parents 401b224 + 319c376 commit 74514f4

6 files changed

Lines changed: 41 additions & 6 deletions

File tree

examples/example.user-sync-config.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ directory:
6666
# Default is:
6767
# user_identity_type: enterpriseID
6868

69+
limits:
70+
max_deletions_per_run: 10 # if --remove-nonexistent-users is specified, this is the most users that will be removed. Others will be left for a later run. A critical message will be logged.
71+
max_missing_users: 200 # if more than this number of user accounts are not found in the directory, user sync will abort with an error and a critical message will be logged.
72+
6973
logging:
7074
# specifies whether you wish to generate a log file
7175
# 'True' or 'False'

tests/config_test.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ def test_get_rule_options(self, mock_id_type,mock_get_dict,mock_get_string):
9595
self.assertEquals(self.conf_load.get_rule_options(), {'username_filter_regex': None,
9696
'update_user_info': True,
9797
'manage_groups': True,
98+
'max_deletions_per_run': 1,
99+
'max_missing_users': 1,
98100
'new_account_type': 'new_acc',
99101
'directory_group_filter': None,
100102
'default_country_code': 'test',

tests/helper.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,7 @@ def create_action_manager():
8585

8686
class MockGetString():
8787
def get_string(self,test1,test2):
88-
return 'test'
88+
return 'test'
89+
90+
def get_int(self,test1):
91+
return 1

user_sync/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ def main():
275275

276276
except user_sync.error.AssertionException as e:
277277
if (not e.is_reported()):
278-
logger.error(e.message)
278+
logger.critical(e.message)
279279
e.set_reported()
280280
except:
281281
try:

user_sync/config.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,11 @@ def get_rule_options(self):
319319
if (new_account_type == None):
320320
new_account_type = user_sync.identity_type.ENTERPRISE_IDENTITY_TYPE
321321
self.logger.warning("Assuming the identity type for users is: %s", new_account_type)
322-
322+
323+
limits_config = self.main_config.get_dict_config('limits')
324+
max_deletions_per_run = limits_config.get_int('max_deletions_per_run')
325+
max_missing_users = limits_config.get_int('max_missing_users')
326+
323327
options = self.options
324328
result = {
325329
'directory_group_filter': options['directory_group_filter'],
@@ -330,7 +334,9 @@ def get_rule_options(self):
330334
'remove_user_key_list': options['remove_user_key_list'],
331335
'remove_list_output_path': options['remove_list_output_path'],
332336
'remove_nonexistent_users': options['remove_nonexistent_users'],
333-
'default_country_code': default_country_code
337+
'default_country_code': default_country_code,
338+
'max_deletions_per_run': max_deletions_per_run,
339+
'max_missing_users': max_missing_users
334340
}
335341
return result
336342

@@ -501,7 +507,10 @@ def get_dict(self, key, none_allowed = False):
501507

502508
def get_string(self, key, none_allowed = False):
503509
return self.get_value(key, types.StringTypes, none_allowed)
504-
510+
511+
def get_int(self, key, none_allowed = False):
512+
return self.get_value(key, types.IntType, none_allowed)
513+
505514
def get_bool(self, key, none_allowed = False):
506515
return self.get_value(key, types.BooleanType, none_allowed)
507516

user_sync/rules.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ def __init__(self, caller_options):
4444
'remove_user_key_list': None,
4545
'remove_list_output_path': None,
4646
'remove_nonexistent_users': False,
47-
'default_country_code': None
47+
'default_country_code': None,
48+
'max_deletions_per_run': None,
49+
'max_missing_users': None
4850
}
4951
options.update(caller_options)
5052
self.options = options
@@ -234,14 +236,29 @@ def process_orphaned_dashboard_users(self):
234236
remove_list_output_path = options['remove_list_output_path']
235237
remove_nonexistent_users = options['remove_nonexistent_users']
236238

239+
max_deletions_per_run = options['max_deletions_per_run']
240+
max_missing_users = options['max_missing_users']
241+
237242
orphaned_federated_dashboard_users = list(self.iter_orphaned_federated_dashboard_users())
238243
self.logger.info('Federated orphaned users to be removed: %s', [self.get_dashboard_user_key(dashboard_user) for dashboard_user in orphaned_federated_dashboard_users])
239244

245+
number_of_orphaned_dashboard_users = len(orphaned_federated_dashboard_users)
246+
240247
if (remove_list_output_path != None):
241248
self.logger.info('Writing remove list to: %s', remove_list_output_path)
242249
self.write_remove_list(remove_list_output_path, orphaned_federated_dashboard_users)
243250
elif (remove_nonexistent_users):
251+
if number_of_orphaned_dashboard_users > max_missing_users:
252+
raise user_sync.error.AssertionException(
253+
'Unable to process orphaned users, as number of users (%s) is larger than max_missing_users setting' % number_of_orphaned_dashboard_users)
254+
orphan_count = 0
244255
for dashboard_user in orphaned_federated_dashboard_users:
256+
orphan_count += 1
257+
if orphan_count > max_deletions_per_run:
258+
self.logger.critical('Only processing %d of the %d orphaned users ' +
259+
'due to max_deletions_per_run setting', max_deletions_per_run,
260+
number_of_orphaned_dashboard_users)
261+
break
245262
user_key = self.get_dashboard_user_key(dashboard_user)
246263
remove_user_key_list.add(user_key)
247264

0 commit comments

Comments
 (0)