when GetCredential is called with an explicit type, do not 'guess' that we might...
[sfa.git] / sfa / managers / registry_manager.py
index 95b4ed2..b49507a 100644 (file)
@@ -19,14 +19,14 @@ from sfa.trust.gid import create_uuid
 
 from sfa.storage.model import make_record, RegRecord, RegAuthority, RegUser, RegSlice, RegKey, \
     augment_with_sfa_builtins
-from sfa.storage.alchemy import dbsession
 ### the types that we need to exclude from sqlobjects before being able to dump
 # them on the xmlrpc wire
 from sqlalchemy.orm.collections import InstrumentedList
 
 class RegistryManager:
 
-    def __init__ (self, config): pass
+    def __init__ (self, config): 
+        logger.info("Creating RegistryManager[%s]"%id(self))
 
     # The GENI GetVersion call
     def GetVersion(self, api, options):
@@ -40,19 +40,29 @@ class RegistryManager:
                              'urn':xrn.get_urn(),
                              'peers':peers})
     
-    def GetCredential(self, api, xrn, type, caller_xrn=None):
+    def GetCredential(self, api, xrn, input_type, caller_xrn=None):
         # convert xrn to hrn     
-        if type:
-            hrn = urn_to_hrn(xrn)[0]
+        if input_type:
+            hrn, _ = urn_to_hrn(xrn)
+            type = input_type
         else:
             hrn, type = urn_to_hrn(xrn)
-            
+
+        # Slivers don't have credentials but users should be able to 
+        # specify a sliver xrn and receive the slice's credential
+        # However if input_type is specified
+        if type == 'sliver' or ( not input_type and '-' in Xrn(hrn).leaf):
+            slice_xrn = api.driver.sliver_to_slice_xrn(hrn)
+            hrn = slice_xrn.hrn 
+  
         # Is this a root or sub authority
         auth_hrn = api.auth.get_authority(hrn)
         if not auth_hrn or hrn == api.config.SFA_INTERFACE_HRN:
             auth_hrn = hrn
         auth_info = api.auth.get_auth_info(auth_hrn)
+
         # get record info
+        dbsession = api.dbsession()
         record=dbsession.query(RegRecord).filter_by(type=type,hrn=hrn).first()
         if not record:
             raise RecordNotFound("hrn=%s, type=%s"%(hrn,type))
@@ -104,6 +114,7 @@ class RegistryManager:
     # the default for full, which means 'dig into the testbed as well', should be false
     def Resolve(self, api, xrns, type=None, details=False):
     
+        dbsession = api.dbsession()
         if not isinstance(xrns, types.ListType):
             # try to infer type if not set and we get a single input
             if not type:
@@ -166,7 +177,7 @@ class RegistryManager:
         if details:
             # in details mode we get as much info as we can, which involves contacting the 
             # testbed for getting implementation details about the record
-            self.driver.augment_records_with_testbed_info(local_dicts)
+            api.driver.augment_records_with_testbed_info(local_dicts)
             # also we fill the 'url' field for known authorities
             # used to be in the driver code, sounds like a poorman thing though
             def solve_neighbour_url (record):
@@ -190,6 +201,7 @@ class RegistryManager:
         return records
     
     def List (self, api, xrn, origin_hrn=None, options={}):
+        dbsession=api.dbsession()
         # load all know registry names into a prefix tree and attempt to find
         # the longest matching prefix
         hrn, type = urn_to_hrn(xrn)
@@ -257,18 +269,19 @@ class RegistryManager:
     # subject_record describes the subject of the relationships
     # ref_record contains the target values for the various relationships we need to manage
     # (to begin with, this is just the slice x person (researcher) and authority x person (pi) relationships)
-    def update_driver_relations (self, subject_obj, ref_obj):
+    def update_driver_relations (self, api, subject_obj, ref_obj):
         type=subject_obj.type
         #for (k,v) in subject_obj.__dict__.items(): print k,'=',v
         if type=='slice' and hasattr(ref_obj,'researcher'):
-            self.update_driver_relation(subject_obj, ref_obj.researcher, 'user', 'researcher')
+            self.update_driver_relation(api, subject_obj, ref_obj.researcher, 'user', 'researcher')
         elif type=='authority' and hasattr(ref_obj,'pi'):
-            self.update_driver_relation(subject_obj,ref_obj.pi, 'user', 'pi')
+            self.update_driver_relation(api, subject_obj,ref_obj.pi, 'user', 'pi')
         
     # field_key is the name of one field in the record, typically 'researcher' for a 'slice' record
     # hrns is the list of hrns that should be linked to the subject from now on
     # target_type would be e.g. 'user' in the 'slice' x 'researcher' example
-    def update_driver_relation (self, record_obj, hrns, target_type, relation_name):
+    def update_driver_relation (self, api, record_obj, hrns, target_type, relation_name):
+        dbsession=api.dbsession()
         # locate the linked objects in our db
         subject_type=record_obj.type
         subject_id=record_obj.pointer
@@ -276,10 +289,11 @@ class RegistryManager:
         link_id_tuples = dbsession.query(RegRecord.pointer).filter_by(type=target_type).filter(RegRecord.hrn.in_(hrns)).all()
         # sqlalchemy returns named tuples for columns
         link_ids = [ tuple.pointer for tuple in link_id_tuples ]
-        self.driver.update_relation (subject_type, target_type, relation_name, subject_id, link_ids)
+        api.driver.update_relation (subject_type, target_type, relation_name, subject_id, link_ids)
 
     def Register(self, api, record_dict):
     
+        dbsession=api.dbsession()
         hrn, type = record_dict['hrn'], record_dict['type']
         urn = hrn_to_urn(hrn,type)
         # validate the type
@@ -325,11 +339,11 @@ class RegistryManager:
 
             # locate objects for relationships
             pi_hrns = getattr(record,'pi',None)
-            if pi_hrns is not None: record.update_pis (pi_hrns)
+            if pi_hrns is not None: record.update_pis (pi_hrns, dbsession)
 
         elif isinstance (record, RegSlice):
             researcher_hrns = getattr(record,'researcher',None)
-            if researcher_hrns is not None: record.update_researchers (researcher_hrns)
+            if researcher_hrns is not None: record.update_researchers (researcher_hrns, dbsession)
         
         elif isinstance (record, RegUser):
             # create RegKey objects for incoming keys
@@ -338,18 +352,19 @@ class RegistryManager:
                 record.reg_keys = [ RegKey (key) for key in record.keys ]
             
         # update testbed-specific data if needed
-        pointer = self.driver.register (record.__dict__, hrn, pub_key)
+        pointer = api.driver.register (record.__dict__, hrn, pub_key)
 
         record.pointer=pointer
         dbsession.add(record)
         dbsession.commit()
     
         # update membership for researchers, pis, owners, operators
-        self.update_driver_relations (record, record)
+        self.update_driver_relations (api, record, record)
         
         return record.get_gid_object().save_to_string(save_parents=True)
     
     def Update(self, api, record_dict):
+        dbsession=api.dbsession()
         assert ('type' in record_dict)
         new_record=make_record(dict=record_dict)
         (type,hrn) = (new_record.type, new_record.hrn)
@@ -388,11 +403,11 @@ class RegistryManager:
         # update native relations
         if isinstance (record, RegSlice):
             researcher_hrns = getattr(new_record,'researcher',None)
-            if researcher_hrns is not None: record.update_researchers (researcher_hrns)
+            if researcher_hrns is not None: record.update_researchers (researcher_hrns, dbsession)
 
         elif isinstance (record, RegAuthority):
             pi_hrns = getattr(new_record,'pi',None)
-            if pi_hrns is not None: record.update_pis (pi_hrns)
+            if pi_hrns is not None: record.update_pis (pi_hrns, dbsession)
         
         # update the PLC information that was specified with the record
         # xxx oddly enough, without this useless statement, 
@@ -400,19 +415,24 @@ class RegistryManager:
         # anyway the driver should receive an object 
         # (and then extract __dict__ itself if needed)
         print "DO NOT REMOVE ME before driver.update, record=%s"%record
-        (pointer, new_key_pointer) = self.driver.update (record.__dict__, new_record.__dict__, hrn, new_key)
-        if new_key and new_key_pointer:    
+        new_key_pointer = -1
+        try:
+           (pointer, new_key_pointer) = api.driver.update (record.__dict__, new_record.__dict__, hrn, new_key)
+        except:
+           pass
+        if new_key and new_key_pointer:
             record.reg_keys=[ RegKey (new_key, new_key_pointer)]
             record.gid = gid
 
-        dbsession.commit();
+        dbsession.commit()
         # update membership for researchers, pis, owners, operators
-        self.update_driver_relations (record, new_record)
+        self.update_driver_relations (api, record, new_record)
         
         return 1 
     
     # expecting an Xrn instance
     def Remove(self, api, xrn, origin_hrn=None):
+        dbsession=api.dbsession()
         hrn=xrn.get_hrn()
         type=xrn.get_type()
         request=dbsession.query(RegRecord).filter_by(hrn=hrn)
@@ -444,7 +464,7 @@ class RegistryManager:
 
         # call testbed callback first
         # IIUC this is done on the local testbed TOO because of the refreshpeer link
-        if not self.driver.remove(record.__dict__):
+        if not api.driver.remove(record.__dict__):
             logger.warning("driver.remove failed")
 
         # delete from sfa db
@@ -455,13 +475,14 @@ class RegistryManager:
 
     # This is a PLC-specific thing, won't work with other platforms
     def get_key_from_incoming_ip (self, api):
+        dbsession=api.dbsession()
         # verify that the callers's ip address exist in the db and is an interface
         # for a node in the db
         (ip, port) = api.remote_addr
-        interfaces = self.driver.shell.GetInterfaces({'ip': ip}, ['node_id'])
+        interfaces = api.driver.shell.GetInterfaces({'ip': ip}, ['node_id'])
         if not interfaces:
             raise NonExistingRecord("no such ip %(ip)s" % locals())
-        nodes = self.driver.shell.GetNodes([interfaces[0]['node_id']], ['node_id', 'hostname'])
+        nodes = api.driver.shell.GetNodes([interfaces[0]['node_id']], ['node_id', 'hostname'])
         if not nodes:
             raise NonExistingRecord("no such node using ip %(ip)s" % locals())
         node = nodes[0]