renamed sfaticket from util/ to trust/
[sfa.git] / sfa / plc / api.py
index 57f8b9d..8a03a87 100644 (file)
@@ -12,7 +12,7 @@ import xmlrpclib
 from sfa.util.faults import *
 from sfa.util.api import *
 from sfa.util.config import *
-from sfa.util.sfalogging import sfa_logger
+from sfa.util.sfalogging import logger
 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
 from sfa.trust.auth import Auth
 from sfa.trust.rights import Right, Rights, determine_rights
@@ -99,30 +99,55 @@ class SfaAPI(BaseAPI):
         self.credential = None
         # Initialize the PLC shell only if SFA wraps a myPLC
         rspec_type = self.config.get_aggregate_type()
-        if (rspec_type == 'pl' or rspec_type == 'vini' or rspec_type == 'eucalyptus'):
+        if (rspec_type == 'pl' or rspec_type == 'vini' or \
+            rspec_type == 'eucalyptus' or rspec_type == 'max'):
             self.plshell = self.getPLCShell()
             self.plshell_version = "4.3"
 
         self.hrn = self.config.SFA_INTERFACE_HRN
         self.time_format = "%Y-%m-%d %H:%M:%S"
-        self.logger=sfa_logger()
 
+    
     def getPLCShell(self):
         self.plauth = {'Username': self.config.SFA_PLC_USER,
                        'AuthMethod': 'password',
                        'AuthString': self.config.SFA_PLC_PASSWORD}
-        try:
-            sys.path.append(os.path.dirname(os.path.realpath("/usr/bin/plcsh")))
-            self.plshell_type = 'direct'
-            import PLC.Shell
-            shell = PLC.Shell.Shell(globals = globals())
-        except:
-            self.plshell_type = 'xmlrpc' 
-            url = self.config.SFA_PLC_URL
-            shell = xmlrpclib.Server(url, verbose = 0, allow_none = True)
+
+        # The native shell (PLC.Shell.Shell) is more efficient than xmlrpc,
+        # but it leaves idle db connections open. use xmlrpc until we can figure
+        # out why PLC.Shell.Shell doesn't close db connection properly     
+        #try:
+        #    sys.path.append(os.path.dirname(os.path.realpath("/usr/bin/plcsh")))
+        #    self.plshell_type = 'direct'
+        #    import PLC.Shell
+        #    shell = PLC.Shell.Shell(globals = globals())
+        #except:
         
+        self.plshell_type = 'xmlrpc' 
+        url = self.config.SFA_PLC_URL
+        shell = xmlrpclib.Server(url, verbose = 0, allow_none = True)
         return shell
 
+    def get_server(self, interface, cred, timeout=30):
+        """
+        Returns a connection to the specified interface. Use the specified
+        credential to determine the caller and look for the caller's key/cert 
+        in the registry hierarchy cache. 
+        """       
+        from sfa.trust.hierarchy import Hierarchy
+        if not isinstance(cred, Credential):
+            cred_obj = Credential(string=cred)
+        else:
+            cred_obj = cred
+        caller_gid = cred_obj.get_gid_caller()
+        hierarchy = Hierarchy()
+        auth_info = hierarchy.get_auth_info(caller_gid.get_hrn())
+        key_file = auth_info.get_privkey_filename()
+        cert_file = auth_info.get_gid_filename()
+        server = interface.get_server(key_file, cert_file, timeout)
+        return server
+               
+        
     def getCredential(self):
         """
         Return a valid credential for this interface. 
@@ -136,7 +161,7 @@ class SfaAPI(BaseAPI):
             cred = Credential(filename = cred_filename)
             # make sure cred isnt expired
             if not cred.get_expiration or \
-               datetime.datetime.today() < cred.get_expiration():    
+               datetime.datetime.utcnow() < cred.get_expiration():    
                 return cred.save_to_string(save_parents=True)
 
         # get a new credential
@@ -154,25 +179,30 @@ class SfaAPI(BaseAPI):
         Attempt to find a credential delegated to us in
         the specified list of creds.
         """
+        from sfa.trust.hierarchy import Hierarchy
         if creds and not isinstance(creds, list): 
             creds = [creds]
-        delegated_creds = filter_creds_by_caller(creds,self.hrn)
-        if not delegated_creds:
-            return None
-        return delegated_creds[0]
+        hierarchy = Hierarchy()
+                
+        delegated_cred = None
+        for cred in creds:
+            if hierarchy.auth_exists(Credential(string=cred).get_gid_caller().get_hrn()):
+                delegated_cred = cred
+                break
+        return delegated_cred
  
     def __getCredential(self):
         """ 
         Get our credential from a remote registry 
         """
         from sfa.server.registry import Registries
-        registries = Registries(self)
-        registry = registries[self.hrn]
+        registries = Registries()
+        registry = registries.get_server(self.hrn, self.key_file, self.cert_file)
         cert_string=self.cert.save_to_string(save_parents=True)
         # get self credential
         self_cred = registry.GetSelfCredential(cert_string, self.hrn, 'authority')
         # get credential
-        cred = registry.GetCredential(self_cred, self.hrn, type)
+        cred = registry.GetCredential(self_cred, self.hrn, 'authority')
         return Credential(string=cred)
 
     def __getCredentialRaw(self):
@@ -188,7 +218,7 @@ class SfaAPI(BaseAPI):
             auth_hrn = hrn
         auth_info = self.auth.get_auth_info(auth_hrn)
         table = self.SfaTable()
-        records = table.findObjects(hrn)
+        records = table.findObjects({'hrn': hrn, 'type': 'authority+sa'})
         if not records:
             raise RecordNotFound
         record = records[0]
@@ -222,6 +252,8 @@ class SfaAPI(BaseAPI):
         except IOError:
             self.credential = self.getCredentialFromRegistry()
 
+
+
     ##
     # Convert SFA fields to PLC fields for use when registering up updating
     # registry record in the PLC database
@@ -338,8 +370,11 @@ class SfaAPI(BaseAPI):
                         break
             # fill in key info
             if record['type'] == 'user':
-                pubkeys = [keys[key_id]['key'] for key_id in record['key_ids'] if key_id in keys] 
-                record['keys'] = pubkeys
+                if 'key_ids' not in record:
+                    logger.info("user record has no 'key_ids' - need to import from myplc ?")
+                else:
+                    pubkeys = [keys[key_id]['key'] for key_id in record['key_ids'] if key_id in keys] 
+                    record['keys'] = pubkeys
 
         # fill in record hrns
         records = self.fill_record_hrns(records)   
@@ -382,7 +417,6 @@ class SfaAPI(BaseAPI):
        
         # convert ids to hrns
         for record in records:
-             
             # get all relevant data
             type = record['type']
             pointer = record['pointer']
@@ -416,7 +450,7 @@ class SfaAPI(BaseAPI):
                                if site_id in sites]
                 site_hrns = [".".join([auth_hrn, lbase]) for lbase in login_bases]
                 record['sites'] = site_hrns
-
+            
         return records   
 
     def fill_record_sfa_info(self, records):
@@ -474,44 +508,51 @@ class SfaAPI(BaseAPI):
         # fill sfa info
         for record in records:
             # skip records with no pl info (top level authorities)
-            if record['pointer'] == -1:
-                continue 
+            #if record['pointer'] == -1:
+            #    continue 
             sfa_info = {}
             type = record['type']
             if (type == "slice"):
                 # all slice users are researchers
+                record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')
                 record['PI'] = []
                 record['researcher'] = []
-                for person_id in record['person_ids']:
+                for person_id in record.get('person_ids', []):
                     hrns = [person['hrn'] for person in persons[person_id]]
                     record['researcher'].extend(hrns)                
 
                 # pis at the slice's site
-                pl_pis = site_pis[record['site_id']]
-                pi_ids = [pi['person_id'] for pi in pl_pis]
-                for person_id in pi_ids:
-                    hrns = [person['hrn'] for person in persons[person_id]]
-                    record['PI'].extend(hrns)
-                record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')
-                record['geni_creator'] = record['PI'] 
-                
-            elif (type == "authority"):
-                record['PI'] = []
-                record['operator'] = []
-                record['owner'] = []
-                for pointer in record['person_ids']:
-                    if pointer not in persons or pointer not in pl_persons:
-                        # this means there is not sfa or pl record for this user
-                        continue   
-                    hrns = [person['hrn'] for person in persons[pointer]] 
-                    roles = pl_persons[pointer]['roles']   
-                    if 'pi' in roles:
+                if 'site_id' in record and record['site_id'] in site_pis:
+                    pl_pis = site_pis[record['site_id']]
+                    pi_ids = [pi['person_id'] for pi in pl_pis]
+                    for person_id in pi_ids:
+                        hrns = [person['hrn'] for person in persons[person_id]]
                         record['PI'].extend(hrns)
-                    if 'tech' in roles:
-                        record['operator'].extend(hrns)
-                    if 'admin' in roles:
-                        record['owner'].extend(hrns)
-                    # xxx TODO: OrganizationName
+                        record['geni_creator'] = record['PI'] 
+                
+            elif (type.startswith("authority")):
+                record['url'] = None
+                if record['hrn'] in self.aggregates:
+                    
+                    record['url'] = self.aggregates[record['hrn']].get_url()
+
+                if record['pointer'] != -1:
+                    record['PI'] = []
+                    record['operator'] = []
+                    record['owner'] = []
+                    for pointer in record.get('person_ids', []):
+                        if pointer not in persons or pointer not in pl_persons:
+                            # this means there is not sfa or pl record for this user
+                            continue   
+                        hrns = [person['hrn'] for person in persons[pointer]] 
+                        roles = pl_persons[pointer]['roles']   
+                        if 'pi' in roles:
+                            record['PI'].extend(hrns)
+                        if 'tech' in roles:
+                            record['operator'].extend(hrns)
+                        if 'admin' in roles:
+                            record['owner'].extend(hrns)
+                        # xxx TODO: OrganizationName
             elif (type == "node"):
                 sfa_info['dns'] = record.get("hostname", "")
                 # xxx TODO: URI, LatLong, IP, DNS
@@ -535,12 +576,22 @@ class SfaAPI(BaseAPI):
         self.fill_record_sfa_info(records)
 
     def update_membership_list(self, oldRecord, record, listName, addFunc, delFunc):
-        # get a list of the HRNs tht are members of the old and new records
+        # get a list of the HRNs that are members of the old and new records
         if oldRecord:
             oldList = oldRecord.get(listName, [])
         else:
             oldList = []     
         newList = record.get(listName, [])
+        # ugly hack to see what's next
+        def normalize (value):
+            from types import StringTypes
+            from sfa.util.sfalogging import logger
+            if isinstance(value,StringTypes): return value
+            elif isinstance(value,dict): 
+                newvalue=value['text']
+                logger.info("Normalizing %s=>%s"%(value,newvalue))
+                return newvalue
+        newList=[normalize(v) for v in newList]
 
         # if the lists are the same, then we don't have to update anything
         if (oldList == newList):