server/checkintegrity.py
changeset 7040 9b1f9bc74f5d
parent 6931 0af44a38fe41
parent 7036 63386b35ec69
child 7398 26695dd703d8
child 7468 c202aaf71489
equal deleted inserted replaced
7025:fee3a1f28ed7 7040:9b1f9bc74f5d
    31 from logilab.common.shellutils import ProgressBar
    31 from logilab.common.shellutils import ProgressBar
    32 
    32 
    33 from cubicweb.schema import PURE_VIRTUAL_RTYPES
    33 from cubicweb.schema import PURE_VIRTUAL_RTYPES
    34 from cubicweb.server.sqlutils import SQL_PREFIX
    34 from cubicweb.server.sqlutils import SQL_PREFIX
    35 from cubicweb.server.session import security_enabled
    35 from cubicweb.server.session import security_enabled
       
    36 
       
    37 def notify_fixed(fix):
       
    38     if fix:
       
    39         print >> sys.stderr, ' [FIXED]'
       
    40     else:
       
    41         print >> sys.stderr
    36 
    42 
    37 def has_eid(session, sqlcursor, eid, eids):
    43 def has_eid(session, sqlcursor, eid, eids):
    38     """return true if the eid is a valid eid"""
    44     """return true if the eid is a valid eid"""
    39     if eid in eids:
    45     if eid in eids:
    40         return eids[eid]
    46         return eids[eid]
   165         if not has_eid(session, cursor, eid, eids):
   171         if not has_eid(session, cursor, eid, eids):
   166             msg = '  Entity with eid %s exists in the text index but in no source'
   172             msg = '  Entity with eid %s exists in the text index but in no source'
   167             print >> sys.stderr, msg % eid,
   173             print >> sys.stderr, msg % eid,
   168             if fix:
   174             if fix:
   169                 session.system_sql('DELETE FROM appears WHERE uid=%s;' % eid)
   175                 session.system_sql('DELETE FROM appears WHERE uid=%s;' % eid)
   170                 print >> sys.stderr, ' [FIXED]'
   176             notify_fixed(fix)
   171             else:
       
   172                 print >> sys.stderr
       
   173 
   177 
   174 
   178 
   175 def check_entities(schema, session, eids, fix=1):
   179 def check_entities(schema, session, eids, fix=1):
   176     """check all entities registered in the repo system table"""
   180     """check all entities registered in the repo system table"""
   177     print 'Checking entities system table'
   181     print 'Checking entities system table'
   181         if not has_eid(session, cursor, eid, eids):
   185         if not has_eid(session, cursor, eid, eids):
   182             msg = '  Entity with eid %s exists in the system table but in no source'
   186             msg = '  Entity with eid %s exists in the system table but in no source'
   183             print >> sys.stderr, msg % eid,
   187             print >> sys.stderr, msg % eid,
   184             if fix:
   188             if fix:
   185                 session.system_sql('DELETE FROM entities WHERE eid=%s;' % eid)
   189                 session.system_sql('DELETE FROM entities WHERE eid=%s;' % eid)
   186                 print >> sys.stderr, ' [FIXED]'
   190             notify_fixed(fix)
   187             else:
       
   188                 print >> sys.stderr
       
   189     print 'Checking entities tables'
   191     print 'Checking entities tables'
   190     for eschema in schema.entities():
   192     for eschema in schema.entities():
   191         if eschema.final:
   193         if eschema.final:
   192             continue
   194             continue
   193         table = SQL_PREFIX + eschema.type
   195         table = SQL_PREFIX + eschema.type
   200             if not eid in eids or not eids[eid]:
   202             if not eid in eids or not eids[eid]:
   201                 msg = '  Entity with eid %s exists in the %s table but not in the system table'
   203                 msg = '  Entity with eid %s exists in the %s table but not in the system table'
   202                 print >> sys.stderr, msg % (eid, eschema.type),
   204                 print >> sys.stderr, msg % (eid, eschema.type),
   203                 if fix:
   205                 if fix:
   204                     session.system_sql('DELETE FROM %s WHERE %s=%s;' % (table, column, eid))
   206                     session.system_sql('DELETE FROM %s WHERE %s=%s;' % (table, column, eid))
   205                     print >> sys.stderr, ' [FIXED]'
   207                 notify_fixed(fix)
   206                 else:
       
   207                     print >> sys.stderr
       
   208 
   208 
   209 
   209 
   210 def bad_related_msg(rtype, target, eid, fix):
   210 def bad_related_msg(rtype, target, eid, fix):
   211     msg = '  A relation %s with %s eid %s exists but no such entity in sources'
   211     msg = '  A relation %s with %s eid %s exists but no such entity in sources'
   212     print >> sys.stderr, msg % (rtype, target, eid),
   212     print >> sys.stderr, msg % (rtype, target, eid),
   213     if fix:
   213     notify_fixed(fix)
   214         print >> sys.stderr, ' [FIXED]'
       
   215     else:
       
   216         print >> sys.stderr
       
   217 
   214 
   218 
   215 
   219 def check_relations(schema, session, eids, fix=1):
   216 def check_relations(schema, session, eids, fix=1):
   220     """check all relations registered in the repo system table"""
   217     """check that eids referenced by relations are registered in the repo system
       
   218     table
       
   219     """
   221     print 'Checking relations'
   220     print 'Checking relations'
   222     for rschema in schema.relations():
   221     for rschema in schema.relations():
   223         if rschema.final or rschema in PURE_VIRTUAL_RTYPES:
   222         if rschema.final or rschema in PURE_VIRTUAL_RTYPES:
   224             continue
   223             continue
   225         if rschema.inlined:
   224         if rschema.inlined:
   259                 bad_related_msg(rschema, 'object', eid, fix)
   258                 bad_related_msg(rschema, 'object', eid, fix)
   260                 if fix:
   259                 if fix:
   261                     sql = 'DELETE FROM %s_relation WHERE eid_to=%s;' % (
   260                     sql = 'DELETE FROM %s_relation WHERE eid_to=%s;' % (
   262                         rschema, eid)
   261                         rschema, eid)
   263                     session.system_sql(sql)
   262                     session.system_sql(sql)
       
   263 
       
   264 
       
   265 def check_mandatory_relations(schema, session, eids, fix=1):
       
   266     """check entities missing some mandatory relation"""
       
   267     print 'Checking mandatory relations'
       
   268     for rschema in schema.relations():
       
   269         if rschema.final or rschema in PURE_VIRTUAL_RTYPES:
       
   270             continue
       
   271         smandatory = set()
       
   272         omandatory = set()
       
   273         for rdef in rschema.rdefs.values():
       
   274             if rdef.cardinality[0] in '1+':
       
   275                 smandatory.add(rdef.subject)
       
   276             if rdef.cardinality[1] in '1+':
       
   277                 omandatory.add(rdef.object)
       
   278         for role, etypes in (('subject', smandatory), ('object', omandatory)):
       
   279             for etype in etypes:
       
   280                 if role == 'subject':
       
   281                     rql = 'Any X WHERE NOT X %s Y, X is %s' % (rschema, etype)
       
   282                 else:
       
   283                     rql = 'Any X WHERE NOT Y %s X, X is %s' % (rschema, etype)
       
   284                 for entity in session.execute(rql).entities():
       
   285                     print >> sys.stderr, '%s #%s is missing mandatory %s relation %s' % (
       
   286                         entity.__regid__, entity.eid, role, rschema)
       
   287                     if fix:
       
   288                         #if entity.cw_describe()['source']['uri'] == 'system': XXX
       
   289                         entity.delete()
       
   290                     notify_fixed(fix)
       
   291 
       
   292 
       
   293 def check_mandatory_attributes(schema, session, eids, fix=1):
       
   294     """check for entities stored in the system source missing some mandatory
       
   295     attribute
       
   296     """
       
   297     print 'Checking mandatory attributes'
       
   298     for rschema in schema.relations():
       
   299         if not rschema.final or rschema in VIRTUAL_RTYPES:
       
   300             continue
       
   301         for rdef in rschema.rdefs.values():
       
   302             if rdef.cardinality[0] in '1+':
       
   303                 rql = 'Any X WHERE X %s NULL, X is %s, X cw_source S, S name "system"' % (
       
   304                     rschema, rdef.subject)
       
   305                 for entity in session.execute(rql).entities():
       
   306                     print >> sys.stderr, '%s #%s is missing mandatory attribute %s' % (
       
   307                         entity.__regid__, entity.eid, rschema)
       
   308                     if fix:
       
   309                         entity.delete()
       
   310                     notify_fixed(fix)
   264 
   311 
   265 
   312 
   266 def check_metadata(schema, session, eids, fix=1):
   313 def check_metadata(schema, session, eids, fix=1):
   267     """check entities has required metadata
   314     """check entities has required metadata
   268 
   315 
   283                 print >> sys.stderr, msg % (etype, eid, rel),
   330                 print >> sys.stderr, msg % (etype, eid, rel),
   284                 if fix:
   331                 if fix:
   285                     session.system_sql("UPDATE %s SET %s=%%(v)s WHERE %s=%s ;"
   332                     session.system_sql("UPDATE %s SET %s=%%(v)s WHERE %s=%s ;"
   286                                        % (table, column, eidcolumn, eid),
   333                                        % (table, column, eidcolumn, eid),
   287                                        {'v': default})
   334                                        {'v': default})
   288                     print >> sys.stderr, ' [FIXED]'
   335                 notify_fixed(fix)
   289                 else:
       
   290                     print >> sys.stderr
       
   291     cursor = session.system_sql('SELECT MIN(%s) FROM %sCWUser;' % (eidcolumn,
   336     cursor = session.system_sql('SELECT MIN(%s) FROM %sCWUser;' % (eidcolumn,
   292                                                                   SQL_PREFIX))
   337                                                                   SQL_PREFIX))
   293     default_user_eid = cursor.fetchone()[0]
   338     default_user_eid = cursor.fetchone()[0]
   294     assert default_user_eid is not None, 'no user defined !'
   339     assert default_user_eid is not None, 'no user defined !'
   295     for rel, default in ( ('owned_by', default_user_eid), ):
   340     for rel, default in ( ('owned_by', default_user_eid), ):
   301             msg = '  %s with eid %s has no %s relation'
   346             msg = '  %s with eid %s has no %s relation'
   302             print >> sys.stderr, msg % (etype, eid, rel),
   347             print >> sys.stderr, msg % (etype, eid, rel),
   303             if fix:
   348             if fix:
   304                 session.system_sql('INSERT INTO %s_relation VALUES (%s, %s) ;'
   349                 session.system_sql('INSERT INTO %s_relation VALUES (%s, %s) ;'
   305                                    % (rel, eid, default))
   350                                    % (rel, eid, default))
   306                 print >> sys.stderr, ' [FIXED]'
   351             notify_fixed(fix)
   307             else:
       
   308                 print >> sys.stderr
       
   309 
   352 
   310 
   353 
   311 def check(repo, cnx, checks, reindex, fix, withpb=True):
   354 def check(repo, cnx, checks, reindex, fix, withpb=True):
   312     """check integrity of instance's repository,
   355     """check integrity of instance's repository,
   313     using given user and password to locally connect to the repository
   356     using given user and password to locally connect to the repository