dealing with reg-researchers vs researcher
Thierry Parmentelat [Tue, 29 Apr 2014 16:28:26 +0000 (18:28 +0200)]
register and update now expect 'reg-researchers' to be set
for legacy if instead we find 'researcher' (sic: singular) then we pretend it was 'reg-researchers'
not terribly nice but should work for that one relation, others to follow

sfa/client/sfi.py
sfa/managers/registry_manager.py
sfa/util/printable.py [new file with mode: 0644]

index 46c18df..4f38ddf 100644 (file)
@@ -31,6 +31,7 @@ from sfa.util.xrn import get_leaf, get_authority, hrn_to_urn, Xrn
 from sfa.util.config import Config
 from sfa.util.version import version_core
 from sfa.util.cache import Cache
+from sfa.util.printable import printable
 
 from sfa.storage.record import Record
 
@@ -203,8 +204,8 @@ def load_record_from_opts(options):
         record_dict['keys'] = [pubkey]
     if hasattr(options, 'slices') and options.slices:
         record_dict['slices'] = options.slices
-    if hasattr(options, 'researchers') and options.researchers is not None:
-        record_dict['researcher'] = options.researchers
+    if hasattr(options, 'reg_researchers') and options.reg_researchers is not None:
+        record_dict['reg-researchers'] = options.reg_researchers
     if hasattr(options, 'email') and options.email:
         record_dict['email'] = options.email
     if hasattr(options, 'pis') and options.pis:
@@ -421,8 +422,8 @@ class Sfi:
                               default=None)
             parser.add_option('-s', '--slices', dest='slices', metavar='<slices>', help='Set/replace slice xrns',
                               default='', type="str", action='callback', callback=optparse_listvalue_callback)
-            parser.add_option('-r', '--researchers', dest='researchers', metavar='<researchers>', 
-                              help='Set/replace slice researchers - use -r none to reset', default='', type="str", action='callback', 
+            parser.add_option('-r', '--researchers', dest='reg_researchers', metavar='<researchers>', 
+                              help='Set/replace slice researchers - use -r none to reset', default=None, type="str", action='callback', 
                               callback=optparse_listvalue_callback)
             parser.add_option('-p', '--pis', dest='pis', metavar='<PIs>', help='Set/replace Principal Investigators/Project Managers',
                               default='', type="str", action='callback', callback=optparse_listvalue_callback)
index 0958f5e..bfff502 100644 (file)
@@ -12,6 +12,8 @@ from sfa.util.xrn import Xrn, get_authority, hrn_to_urn, urn_to_hrn
 from sfa.util.version import version_core
 from sfa.util.sfalogging import logger
 
+from sfa.util.printable import printable
+
 from sfa.trust.gid import GID 
 from sfa.trust.credential import Credential
 from sfa.trust.certificate import Certificate, Keypair, convert_public_key
@@ -23,6 +25,43 @@ from sfa.storage.model import make_record, RegRecord, RegAuthority, RegUser, Reg
 # them on the xmlrpc wire
 from sqlalchemy.orm.collections import InstrumentedList
 
+### historical note -- april 2014
+# the myslice chaps rightfully complained about the following discrepency
+# they found that
+# * read operations (resolve) expose stuff like e.g. 'reg-researchers', but that
+# * write operations (register, update) need e.g. 'researcher' to be set - it ignores 'reg-researchers'
+#
+# the 'normalize' helper functions below aim at ironing this out
+# however in order to break as few as possible we essentially make sure that *both* fields are set
+# upon entering the write methods (so again register and update) because some driver code
+# might depend on the presence of, say, 'researcher'
+
+# registry calls this 'reg-researchers'
+# some drivers call this 'researcher'
+# this is even more confusing as people might use 'researchers'
+def normalize_input_researcher (record):
+    # this aims at detecting a mispelled input
+    if 'researchers' in record and 'researcher' not in record:
+        record['researcher']=record['researchers']
+        del record['researchers']
+    # this looks right, use this for both keys
+    if 'reg-researchers' in record:
+        # and issue a warning if they were both set as we're overwriting some user data here
+        if 'researcher' in record:
+            logger.warning ("normalize_input_researcher: incoming record has both values, using reg-researchers")
+        record['researcher']=record['reg-researchers']
+    # we only have one key set, duplicate for the other one
+    elif 'researcher' in record:
+        logger.warning ("normalize_input_researcher: you should use 'reg-researchers' instead ot 'researcher'")
+        record['reg-researchers']=record['researcher']
+    # if at this point we still have 'researchers' it's going to be ignored and that might be confusing
+    if 'researchers' in record:
+        logger.warning ("normalize_input_researcher: incoming record has confusing 'researchers' key - ignored - use 'reg-researchers' instead")
+
+def normalize_input_record (record):
+    normalize_input_researcher (record)
+    return record
+
 class RegistryManager:
 
     def __init__ (self, config): 
@@ -293,6 +332,10 @@ class RegistryManager:
 
     def Register(self, api, record_dict):
     
+        logger.debug("Register: entering with record_dict=%s"%printable(record_dict))
+        normalize_input_record (record_dict)
+        logger.debug("Register: normalized record_dict=%s"%printable(record_dict))
+
         dbsession=api.dbsession()
         hrn, type = record_dict['hrn'], record_dict['type']
         urn = hrn_to_urn(hrn,type)
@@ -342,7 +385,7 @@ class RegistryManager:
             if pi_hrns is not None: record.update_pis (pi_hrns, dbsession)
 
         elif isinstance (record, RegSlice):
-            researcher_hrns = getattr(record,'researcher',None)
+            researcher_hrns = getattr(record,'reg-researchers',None)
             if researcher_hrns is not None: record.update_researchers (researcher_hrns, dbsession)
         
         elif isinstance (record, RegUser):
@@ -364,6 +407,11 @@ class RegistryManager:
         return record.get_gid_object().save_to_string(save_parents=True)
     
     def Update(self, api, record_dict):
+
+        logger.debug("Update: entering with record_dict=%s"%printable(record_dict))
+        normalize_input_record (record_dict)
+        logger.debug("Update: normalized record_dict=%s"%printable(record_dict))
+
         dbsession=api.dbsession()
         assert ('type' in record_dict)
         new_record=make_record(dict=record_dict)
@@ -402,7 +450,7 @@ class RegistryManager:
 
         # update native relations
         if isinstance (record, RegSlice):
-            researcher_hrns = getattr(new_record,'researcher',None)
+            researcher_hrns = getattr(new_record,'reg-researchers',None)
             if researcher_hrns is not None: record.update_researchers (researcher_hrns, dbsession)
 
         elif isinstance (record, RegAuthority):
diff --git a/sfa/util/printable.py b/sfa/util/printable.py
new file mode 100644 (file)
index 0000000..f18c274
--- /dev/null
@@ -0,0 +1,15 @@
+# yet another way to display records...
+def beginning (foo,size=15):
+    full="%s"%foo
+    if len(full)<=size: return full
+    return full[:size-3]+'...'
+
+def printable (record_s):
+    # a list of records :
+    if isinstance (record_s,list):
+        return "[" + "\n".join( [ printable(r) for r in record_s ]) + "]"
+    if isinstance (record_s, dict):
+        return "{" + " , ".join( [ "%s:%s"%(k,beginning(v)) for k,v in record_s.iteritems() ] ) + "}"
+    if isinstance (record_s, str):
+        return record_s
+    return "unprintable [[%s]]"%record_s