various tweaks around using records; the client-side is still broken
Thierry Parmentelat [Wed, 18 Jan 2012 12:09:10 +0000 (13:09 +0100)]
sfa/client/sfi.py
sfa/managers/registry_manager.py
sfa/methods/GetSelfCredential.py
sfa/server/sfa-start.py
sfa/storage/persistentobjs.py
tests/testStorage.py

index 4ff43ac..6f2d5b7 100644 (file)
@@ -28,7 +28,8 @@ from sfa.util.config import Config
 from sfa.util.version import version_core
 from sfa.util.cache import Cache
 
-from sfa.storage.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
+#from sfa.storage.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
+from sfa.storage.persistentobjs import RegRecord
 
 from sfa.rspecs.rspec import RSpec
 from sfa.rspecs.rspec_converter import RSpecConverter
@@ -119,15 +120,15 @@ def save_records_to_file(filename, recordList, format="xml"):
         f = open(filename, "w")
         f.write("<recordlist>\n")
         for record in recordList:
-            record = SfaRecord(dict=record)
-            f.write('<record hrn="' + record.get_name() + '" type="' + record.get_type() + '" />\n')
+            record_obj=RegRecord (dict=record)
+            f.write('<record hrn="' + record.hrn + '" type="' + record.type + '" />\n')
         f.write("</recordlist>\n")
         f.close()
     elif format == "hrnlist":
         f = open(filename, "w")
         for record in recordList:
-            record = SfaRecord(dict=record)
-            f.write(record.get_name() + "\n")
+            record_obj=RegRecord (dict=record)
+            f.write(record.hrn + "\n")
         f.close()
     else:
         # this should never happen
@@ -135,15 +136,19 @@ def save_records_to_file(filename, recordList, format="xml"):
 
 def save_record_to_file(filename, record):
     if record['type'] in ['user']:
-        record = UserRecord(dict=record)
+        # UserRecord
+        record = RegRecord(dict=record)
     elif record['type'] in ['slice']:
-        record = SliceRecord(dict=record)
+        # SliceRecord
+        record = RegRecord(dict=record)
     elif record['type'] in ['node']:
-        record = NodeRecord(dict=record)
+        # NodeRecord
+        record = RegRecord(dict=record)
     elif record['type'] in ['authority', 'ma', 'sa']:
-        record = AuthorityRecord(dict=record)
+        # AuthorityRecord
+        record = RegRecord(dict=record)
     else:
-        record = SfaRecord(dict=record)
+        record = RegRecord(dict=record)
     str = record.save_to_string()
     f=codecs.open(filename, encoding='utf-8',mode="w")
     f.write(str)
@@ -156,7 +161,8 @@ def load_record_from_file(filename):
     f=codecs.open(filename, encoding="utf-8", mode="r")
     str = f.read()
     f.close()
-    record = SfaRecord(string=str)
+    record = RegRecord()
+    record.load_from_xml(str)
     return record
 
 
@@ -714,19 +720,24 @@ or version information about sfi itself
             self.logger.error("No record of type %s"% options.type)
         for record in records:
             if record['type'] in ['user']:
-                record = UserRecord(dict=record)
+                # UserRecord
+                record = RegRecord(dict=record)
             elif record['type'] in ['slice']:
-                record = SliceRecord(dict=record)
+                # SliceRecord
+                record = RegRecord(dict=record)
             elif record['type'] in ['node']:
-                record = NodeRecord(dict=record)
+                # NodeRecord
+                record = RegRecord(dict=record)
             elif record['type'].startswith('authority'):
-                record = AuthorityRecord(dict=record)
+                # AuthorityRecord
+                record = RegRecord(dict=record)
             else:
-                record = SfaRecord(dict=record)
+                record = RegRecord(dict=record)
+
             if (options.format == "text"): 
                 record.dump()  
             else:
-                print record.save_to_string() 
+                print record.save_as_xml() 
         if options.file:
             save_records_to_file(options.file, records, options.fileformat)
         return
@@ -739,7 +750,7 @@ or version information about sfi itself
             sys.exit(1)
         record_filepath = args[0]
         rec_file = self.get_record_file(record_filepath)
-        record = load_record_from_file(rec_file).as_dict()
+        record = load_record_from_file(rec_file).todict()
         return self.registry().Register(record, auth_cred)
     
     def update(self, options, args):
index 8ce7705..ef00d9c 100644 (file)
@@ -261,8 +261,7 @@ class RegistryManager:
             raise ExistingRecord(hrn)
            
         assert ('type' in record_dict)
-        record = RegRecord("undefined")
-        record.set_from_dict(record_dict)
+        record = RegRecord(dict=record_dict)
         record.just_created()
         record.authority = get_authority(record.hrn)
         auth_info = api.auth.get_auth_info(record.authority)
@@ -305,8 +304,7 @@ class RegistryManager:
     
     def Update(self, api, record_dict):
         assert ('type' in record_dict)
-        new_record=RegRecord(type="unknown")
-        new_record.set_from_dict(record_dict)
+        new_record=RegRecord(dict=record_dict)
         type = new_record.type
         hrn = new_record.hrn
         
index b8eb18a..4022008 100644 (file)
@@ -67,8 +67,7 @@ class GetSelfCredential(Method):
         if not records:
             raise RecordNotFound(hrn)
 
-        record_obj = RegRecord ('unknown')
-        record_obj.set_from_dict (records[0])
+        record_obj = RegRecord (dict=records[0])
         # xxx-local the local-only version would read 
         #record_obj = dbsession.query(RegRecord).filter_by(hrn=hrn).first()
         #if not record_obj: raise RecordNotFound(hrn)
index fe811ff..1f22215 100755 (executable)
@@ -151,12 +151,11 @@ def update_cert_records(gids):
         hrn, type = gid.get_hrn(), gid.get_type()
         record = dbsession.query(RegRecord).filter_by(hrn=hrn, type=type,pointer=-1).first()
         if not record:
-            record = RegRecord (type=type)
-            record.set_from_dict (
-                { 'hrn': hrn, 
-                  'authority': get_authority(hrn),
-                  'gid': gid.save_to_string(save_parents=True),
-                  })
+            record = RegRecord (dict= {'type':type,
+                                       'hrn': hrn, 
+                                       'authority': get_authority(hrn),
+                                       'gid': gid.save_to_string(save_parents=True),
+                                       })
             dbsession.add(record)
     dbsession.commit()
         
index a1f4cb6..db62608 100644 (file)
@@ -9,6 +9,7 @@ from sqlalchemy.orm import object_mapper
 from sqlalchemy.ext.declarative import declarative_base
 
 from sfa.util.sfalogging import logger
+from sfa.util.xml import XML 
 
 from sfa.trust.gid import GID
 
@@ -41,7 +42,7 @@ Base=declarative_base()
 # so the latter obj.todict() seems more reliable but more hacky as is relies on the form of fields, so this can probably be improved
 #
 # (*) finally for converting a dictionary into an sqlalchemy object, we provide
-# obj.set_from_dict(dict)
+# obj.load_from_dict(dict)
 
 class AlchemyObj:
     def __iter__(self): 
@@ -54,13 +55,35 @@ class AlchemyObj:
         d=self.__dict__
         keys=[k for k in d.keys() if not k.startswith('_')]
         return dict ( [ (k,d[k]) for k in keys ] )
-    def set_from_dict (self, d):
+    def load_from_dict (self, d):
         for (k,v) in d.iteritems():
             # experimental
             if isinstance(v, StringTypes):
                 if v.lower() in ['true']: v=True
                 if 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 
+    # a list or a dictionary
+    def xml_fields (self):
+        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()
+        for k in self.xml_fields():
+            if k in xml_dict:
+                setattr(self,k,xml_dict[k])
+
+    def save_as_xml (self):
+        # xxx unset fields don't get exposed, is that right ?
+        input_dict = dict( [ (key, getattr(self.key), ) for key in self.xml_fields() if getattr(self,key,None) ] )
+        xml_record=XML("<record />")
+        xml_record.parse_dict (input_dict)
+        return xml_record.toxml()
 
 ##############################
 class Type (Base):
@@ -96,7 +119,9 @@ class RegRecord (Base,AlchemyObj):
                        Column ('date_created',DateTime),
                        Column ('last_updated',DateTime),
                        )
-    def __init__ (self, type, hrn=None, gid=None, authority=None, peer_authority=None, pointer=-1):
+    fields = [ 'type', 'hrn', 'gid', 'authority', 'peer_authority' ]
+    def __init__ (self, type='unknown', hrn=None, gid=None, authority=None, peer_authority=None, 
+                  pointer=-1, dict=None):
         self.type=type
         if hrn: self.hrn=hrn
         if gid: 
@@ -104,7 +129,9 @@ class RegRecord (Base,AlchemyObj):
             else: self.gid=gid.save_to_string(save_parents=True)
         if authority: self.authority=authority
         if peer_authority: self.peer_authority=peer_authority
-        self.pointer=pointer
+        if not hasattr(self,'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" % \
@@ -114,6 +141,7 @@ class RegRecord (Base,AlchemyObj):
         result += "]"
         return result
 
+    # 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
         else: return GID(string=self.gid)
@@ -152,14 +180,20 @@ class UserRecord (Base):
         self.email=email
     def __repr__ (self): return "<UserRecord %s %s>"%(self.email,self.gid)
 
-##############################    
+##############################
 def init_tables(dbsession):
     logger.info("Initializing db schema and builtin types")
-    engine=dbsession.get_bind()
+    # the doc states we could retrieve the engine this way
+    # engine=dbsession.get_bind()
+    # however I'm getting this
+    # TypeError: get_bind() takes at least 2 arguments (1 given)
+    # 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")
-    engine=dbsession.get_bind()
+    # same as for init_tables
+    from sfa.storage.alchemy import engine
     Base.metadata.drop_all(engine)
index deb69f4..1790b73 100755 (executable)
@@ -8,7 +8,7 @@ class TestStorage(unittest.TestCase):
         pass
 
     def testCreate(self):
-        r = RegRecord('user')
+        r = RegRecord(type='authority',hrn='foo.bar')
 
 if __name__ == "__main__":
     unittest.main()