if isinstance(v, StringTypes) and v.lower() in ['true']: v=True
if isinstance(v, StringTypes) and v.lower() in ['false']: v=False
setattr(self,k,v)
- assert self.type in BUILTIN_TYPES
# in addition we provide convenience for converting to and from xml records
# for this purpose only, we need the subclasses to define 'fields' as either
fields=self.fields
if isinstance(fields,dict): fields=fields.keys()
return fields
- def load_from_xml (self, xml):
- xml_record = XML(xml)
- xml_dict = xml_record.todict()
- logger.info("load from xml, keys=%s"%xml_dict.keys())
-# for k in self.xml_fields():
- for (k,v) in xml_dict.iteritems():
- setattr(self,k,v)
def save_as_xml (self):
# xxx not sure about the scope here
##############################
-class Type (Base):
- __table__ = Table ('types', Base.metadata,
- Column ('type',String, primary_key=True),
- )
- def __init__ (self, type): self.type=type
- def __repr__ (self): return "<Type %s>"%self.type
-
-#BUILTIN_TYPES = [ 'authority', 'slice', 'node', 'user' ]
-# xxx for compat but sounds useless
-BUILTIN_TYPES = [ 'authority', 'slice', 'node', 'user',
- 'authority+sa', 'authority+am', 'authority+sm' ]
-
-def insert_builtin_types(dbsession):
- for type in BUILTIN_TYPES :
- count = dbsession.query (Type).filter_by (type=type).count()
- if count==0:
- dbsession.add (Type (type))
- dbsession.commit()
+# various kinds of records are implemented as an inheritance hierarchy
+# RegRecord is the base class for all actual variants
+# a first draft was using 'type' as the discriminator for the inheritance
+# but we had to define another more internal column (classtype) so we
+# accomodate variants in types like authority+am and the like
-##############################
class RegRecord (Base,AlchemyObj):
# xxx tmp would be 'records'
- __table__ = Table ('records', Base.metadata,
- Column ('record_id', Integer, primary_key=True),
- Column ('type', String, ForeignKey ("types.type")),
- Column ('hrn',String),
- Column ('gid',String),
- Column ('authority',String),
- Column ('peer_authority',String),
- Column ('pointer',Integer,default=-1),
- Column ('date_created',DateTime),
- Column ('last_updated',DateTime),
- )
+ __tablename__ = 'records'
+ record_id = Column (Integer, primary_key=True)
+ # this is the discriminator that tells which class to use
+ classtype = Column (String)
+ type = Column (String)
+ hrn = Column (String)
+ gid = Column (String)
+ authority = Column (String)
+ peer_authority = Column (String)
+ pointer = Column (Integer, default=-1)
+ date_created = Column (DateTime)
+ last_updated = Column (DateTime)
+ # use the 'type' column to decide which subclass the object is of
+ __mapper_args__ = { 'polymorphic_on' : classtype }
+
fields = [ 'type', 'hrn', 'gid', 'authority', 'peer_authority' ]
- def __init__ (self, type='unknown', hrn=None, gid=None, authority=None, peer_authority=None,
+ def __init__ (self, type=None, hrn=None, gid=None, authority=None, peer_authority=None,
pointer=None, dict=None):
- self.type=type
- if hrn: self.hrn=hrn
+ if type: self.type=type
+ if hrn: self.hrn=hrn
if gid:
- if isinstance(gid, StringTypes): self.gid=gid
- else: self.gid=gid.save_to_string(save_parents=True)
- if authority: self.authority=authority
- if peer_authority: self.peer_authority=peer_authority
- if pointer: self.pointer=pointer
- if dict:
- self.load_from_dict (dict)
+ if isinstance(gid, StringTypes): self.gid=gid
+ else: self.gid=gid.save_to_string(save_parents=True)
+ if authority: self.authority=authority
+ if peer_authority: self.peer_authority=peer_authority
+ if pointer: self.pointer=pointer
+ if dict: self.load_from_dict (dict)
def __repr__(self):
- result="[Record(record_id=%s, hrn=%s, type=%s, authority=%s, pointer=%s" % \
- (self.record_id, self.hrn, self.type, self.authority, self.pointer)
- if self.gid: result+=" %s..."%self.gid[:10]
- else: result+=" no-gid"
+ result="[Record id=%s, type=%s, hrn=%s, authority=%s, pointer=%s" % \
+ (self.record_id, self.type, self.hrn, self.authority, self.pointer)
+ # skip the uniform '--- BEGIN CERTIFICATE --' stuff
+ if self.gid: result+=" gid=%s..."%self.gid[28:36]
+ else: result+=" nogid"
result += "]"
return result
+ @validates ('gid')
+ def validate_gid (self, key, gid):
+ if gid is None: return
+ elif isinstance(gid, StringTypes): return gid
+ else: return gid.save_to_string(save_parents=True)
+
# xxx - there might be smarter ways to handle get/set'ing gid using validation hooks
def get_gid_object (self):
if not self.gid: return None
self.last_updated=now
##############################
-
-class User (Base):
- __table__ = Table ('users', Base.metadata,
- Column ('record_id', Integer, ForeignKey ("records.record_id"), primary_key=True),
- Column ('email', String),
- )
- def __init__ (self, email):
- self.email=email
- def __repr__ (self): return "[User(%d) email=%s>"%(self.record_id,self.email,)
+class RegUser (RegRecord):
+ __tablename__ = 'users'
+ # these objects will have type='user' in the records table
+ __mapper_args__ = { 'polymorphic_identity' : 'user' }
+ record_id = Column (Integer, ForeignKey ("records.record_id"), primary_key=True)
+ email = Column ('email', String)
+
+ # append stuff at the end of the record __repr__
+ def __repr__ (self):
+ result = RegRecord.__repr__(self).replace("Record","User")
+ result.replace ("]"," email=%s"%self.email)
+ return result
@validates('email')
def validate_email(self, key, address):
assert '@' in address
return address
-
-class Key (Base):
- __table__ = Table ('keys', Base.metadata,
- Column ('key_id', Integer, primary_key=True),
- Column ('key',String),
- )
+
+class RegAuthority (RegRecord):
+ __tablename__ = 'authorities'
+ __mapper_args__ = { 'polymorphic_identity' : 'authority' }
+ record_id = Column (Integer, ForeignKey ("records.record_id"), primary_key=True)
+
+ # no proper data yet, just hack the typename
+ def __repr__ (self):
+ return RegRecord.__repr__(self).replace("Record","Authority")
+
+class RegSlice (RegRecord):
+ __tablename__ = 'slices'
+ __mapper_args__ = { 'polymorphic_identity' : 'slice' }
+ record_id = Column (Integer, ForeignKey ("records.record_id"), primary_key=True)
+
+ def __repr__ (self):
+ return RegRecord.__repr__(self).replace("Record","Slice")
+
+class RegNode (RegRecord):
+ __tablename__ = 'nodes'
+ __mapper_args__ = { 'polymorphic_identity' : 'node' }
+ record_id = Column (Integer, ForeignKey ("records.record_id"), primary_key=True)
+
+ def __repr__ (self):
+ return RegRecord.__repr__(self).replace("Record","Node")
##############################
-#record_table = RegRecord.__table__
-#user_table = User.__table__
-#record_user_join = join (record_table, user_table)
-#
-#class UserRecord (Base):
-# __table__ = record_user_join
-# record_id = column_property (record_table.c.record_id, user_table.c.record_id)
-# user_id = user_table.c.user_id
-# def __init__ (self, gid, email):
-# self.type='user'
-# self.gid=gid
-# self.email=email
-# def __repr__ (self): return "<UserRecord %s %s>"%(self.email,self.gid)
-#
-##############################
+# although the db needs of course to be reachable,
+# the schema management functions are here and not in alchemy
+# because the actual details of the classes need to be known
def init_tables(dbsession):
logger.info("Initializing db schema and builtin types")
# the doc states we could retrieve the engine this way
# so let's import alchemy - but not from toplevel
from sfa.storage.alchemy import engine
Base.metadata.create_all(engine)
- insert_builtin_types(dbsession)
def drop_tables(dbsession):
logger.info("Dropping tables")
# same as for init_tables
from sfa.storage.alchemy import engine
Base.metadata.drop_all(engine)
+
+##############################
+# create a record of the right type from either a dict or an xml string
+def make_record (dict={}, xml=""):
+ if dict: return make_record_dict (dict)
+ elif xml: return make_record_xml (xml)
+ else: raise Exception("make_record has no input")
+
+# convert an incoming record - typically from xmlrpc - into an object
+def make_record_dict (record_dict):
+ assert ('type' in record_dict)
+ type=record_dict['type'].split('+')[0]
+ if type=='authority':
+ result=RegAuthority (dict=record_dict)
+ elif type=='user':
+ result=RegUser (dict=record_dict)
+ elif type=='slice':
+ result=RegSlice (dict=record_dict)
+ elif type=='node':
+ result=RegNode (dict=record_dict)
+ else:
+ result=RegRecord (dict=record_dict)
+ logger.info ("converting dict into Reg* with type=%s"%type)
+ logger.info ("returning=%s"%result)
+ # xxx todo
+ # register non-db attributes in an extensions field
+ return result
+
+def make_record_xml (xml):
+ xml_record = XML(xml)
+ xml_dict = xml_record.todict()
+ logger.info("load from xml, keys=%s"%xml_dict.keys())
+ return make_record_dict (xml_dict)