misc/scripts/repair_splitbrain_ldapuser_source.py
changeset 10589 7c23b7de2b8d
parent 8568 56d9eb013feb
equal deleted inserted replaced
10588:fdaa0e4b7eaf 10589:7c23b7de2b8d
    12 
    12 
    13 However you should really REALLY understand what it does before
    13 However you should really REALLY understand what it does before
    14 deciding to apply it for you. And then ADAPT it tou your needs.
    14 deciding to apply it for you. And then ADAPT it tou your needs.
    15 
    15 
    16 """
    16 """
       
    17 from __future__ import print_function
    17 
    18 
    18 import base64
    19 import base64
    19 from collections import defaultdict
    20 from collections import defaultdict
    20 
    21 
    21 from cubicweb.server.session import hooks_control
    22 from cubicweb.server.session import hooks_control
    26 except ValueError:
    27 except ValueError:
    27     print('you should specify the source name as script argument (i.e. after --'
    28     print('you should specify the source name as script argument (i.e. after --'
    28           ' on the command line)')
    29           ' on the command line)')
    29     sys.exit(1)
    30     sys.exit(1)
    30 except KeyError:
    31 except KeyError:
    31     print '%s is not an active source' % source_name
    32     print('%s is not an active source' % source_name)
    32     sys.exit(1)
    33     sys.exit(1)
    33 
    34 
    34 # check source is reachable before doing anything
    35 # check source is reachable before doing anything
    35 if not source.get_connection().cnx:
    36 if not source.get_connection().cnx:
    36     print '%s is not reachable. Fix this before running this script' % source_name
    37     print('%s is not reachable. Fix this before running this script' % source_name)
    37     sys.exit(1)
    38     sys.exit(1)
    38 
    39 
    39 def find_dupes():
    40 def find_dupes():
    40     # XXX this retrieves entities from a source name "ldap"
    41     # XXX this retrieves entities from a source name "ldap"
    41     #     you will want to adjust
    42     #     you will want to adjust
    50 def merge_dupes(dupes, docommit=False):
    51 def merge_dupes(dupes, docommit=False):
    51     gone_eids = []
    52     gone_eids = []
    52     CWUser = schema['CWUser']
    53     CWUser = schema['CWUser']
    53     for extid, eids in dupes.items():
    54     for extid, eids in dupes.items():
    54         newest = eids.pop() # we merge everything on the newest
    55         newest = eids.pop() # we merge everything on the newest
    55         print 'merging ghosts of', extid, 'into', newest
    56         print('merging ghosts of', extid, 'into', newest)
    56         # now we merge pairwise into the newest
    57         # now we merge pairwise into the newest
    57         for old in eids:
    58         for old in eids:
    58             subst = {'old': old, 'new': newest}
    59             subst = {'old': old, 'new': newest}
    59             print '  merging', old
    60             print('  merging', old)
    60             gone_eids.append(old)
    61             gone_eids.append(old)
    61             for rschema in CWUser.subject_relations():
    62             for rschema in CWUser.subject_relations():
    62                 if rschema.final or rschema == 'identity':
    63                 if rschema.final or rschema == 'identity':
    63                     continue
    64                     continue
    64                 if CWUser.rdef(rschema, 'subject').composite == 'subject':
    65                 if CWUser.rdef(rschema, 'subject').composite == 'subject':
    81                 rql('DELETE X %s U WHERE U eid %%(old)s' % rschema, subst)
    82                 rql('DELETE X %s U WHERE U eid %%(old)s' % rschema, subst)
    82     if not docommit:
    83     if not docommit:
    83         rollback()
    84         rollback()
    84         return
    85         return
    85     commit() # XXX flushing operations is wanted rather than really committing
    86     commit() # XXX flushing operations is wanted rather than really committing
    86     print 'clean up entities table'
    87     print('clean up entities table')
    87     sql('DELETE FROM entities WHERE eid IN (%s)' % (', '.join(str(x) for x in gone_eids)))
    88     sql('DELETE FROM entities WHERE eid IN (%s)' % (', '.join(str(x) for x in gone_eids)))
    88     commit()
    89     commit()
    89 
    90 
    90 def main():
    91 def main():
    91     dupes = find_dupes()
    92     dupes = find_dupes()
    92     if not dupes:
    93     if not dupes:
    93         print 'No duplicate user'
    94         print('No duplicate user')
    94         return
    95         return
    95 
    96 
    96     print 'Found %s duplicate user instances' % len(dupes)
    97     print('Found %s duplicate user instances' % len(dupes))
    97 
    98 
    98     while True:
    99     while True:
    99         print 'Fix or dry-run? (f/d)  ... or Ctrl-C to break out'
   100         print('Fix or dry-run? (f/d)  ... or Ctrl-C to break out')
   100         answer = raw_input('> ')
   101         answer = raw_input('> ')
   101         if answer.lower() not in 'fd':
   102         if answer.lower() not in 'fd':
   102             continue
   103             continue
   103         print 'Please STOP THE APPLICATION INSTANCES (service or interactive), and press Return when done.'
   104         print('Please STOP THE APPLICATION INSTANCES (service or interactive), and press Return when done.')
   104         raw_input('<I swear all running instances and workers of the application are stopped>')
   105         raw_input('<I swear all running instances and workers of the application are stopped>')
   105         with hooks_control(session, session.HOOKS_DENY_ALL):
   106         with hooks_control(session, session.HOOKS_DENY_ALL):
   106             merge_dupes(dupes, docommit=answer=='f')
   107             merge_dupes(dupes, docommit=answer=='f')
   107 
   108 
   108 main()
   109 main()