X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sfa%2Fplc%2Fapi.py;h=8a03a87c69433cbf33a576f40ae3c1524630c24d;hb=1e95f8a388325499564df5f8eb6eb1fd10ca2d42;hp=8707405a9d8a0cf20962fb4e737d18a876e9daf3;hpb=9887cc98e96651bc4dd1a1999f299800c187b520;p=sfa.git diff --git a/sfa/plc/api.py b/sfa/plc/api.py index 8707405a..8a03a87c 100644 --- a/sfa/plc/api.py +++ b/sfa/plc/api.py @@ -1,26 +1,25 @@ # # SFA XML-RPC and SOAP interfaces # -### $Id$ -### $URL$ -# import sys import os import traceback import string +import datetime import xmlrpclib -from sfa.util.sfalogging import sfa_logger -import sfa.util.xmlrpcprotocol as xmlrpcprotocol -from sfa.trust.auth import Auth -from sfa.util.config import * from sfa.util.faults import * -from sfa.trust.rights import * -from sfa.trust.credential import * -from sfa.trust.certificate import * -from sfa.util.namespace import * from sfa.util.api import * +from sfa.util.config import * +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 +from sfa.trust.credential import Credential,Keypair +from sfa.trust.certificate import Certificate +from sfa.util.xrn import get_authority, hrn_to_urn +from sfa.util.plxrn import hostname_to_hrn, hrn_to_pl_slicename, hrn_to_pl_slicename, slicename_to_hrn from sfa.util.nodemanager import NodeManager try: from collections import defaultdict @@ -100,77 +99,113 @@ 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. """ + type = 'authority' + path = self.config.SFA_DATA_DIR + filename = ".".join([self.interface, self.hrn, type, "cred"]) + cred_filename = path + os.sep + filename + cred = None + if os.path.isfile(cred_filename): + cred = Credential(filename = cred_filename) + # make sure cred isnt expired + if not cred.get_expiration or \ + datetime.datetime.utcnow() < cred.get_expiration(): + return cred.save_to_string(save_parents=True) + + # get a new credential if self.interface in ['registry']: - return self.getCredentialFromLocalRegistry() + cred = self.__getCredentialRaw() else: - return self.getCredentialFromRegistry() + cred = self.__getCredential() + cred.save_to_file(cred_filename, save_parents=True) + + return cred.save_to_string(save_parents=True) + def getDelegatedCredential(self, creds): """ 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 getCredentialFromRegistry(self): + def __getCredential(self): """ Get our credential from a remote registry """ - type = 'authority' - path = self.config.SFA_DATA_DIR - filename = ".".join([self.interface, self.hrn, type, "cred"]) - cred_filename = path + os.sep + filename - try: - credential = Credential(filename = cred_filename) - return credential.save_to_string(save_parents=True) - except IOError: - from sfa.server.registry import Registries - registries = Registries(self) - registry = registries[self.hrn] - cert_string=self.cert.save_to_string(save_parents=True) - # get self credential - self_cred = registry.GetSelfCredential(cert_string, self.hrn, type) - # get credential - cred = registry.GetCredential(self_cred, self.hrn, type) - - # save cred to file - Credential(string=cred).save_to_file(cred_filename, save_parents=True) - return cred - - def getCredentialFromLocalRegistry(self): + from sfa.server.registry import Registries + 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, 'authority') + return Credential(string=cred) + + def __getCredentialRaw(self): """ Get our current credential directly from the local registry. """ @@ -183,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] @@ -196,15 +231,10 @@ class SfaAPI(BaseAPI): r1 = determine_rights(type, hrn) new_cred.set_privileges(r1) - - auth_kind = "authority,ma,sa" - - new_cred.set_parent(self.auth.hierarchy.get_auth_cred(auth_hrn, kind=auth_kind)) - new_cred.encode() new_cred.sign() - return new_cred.save_to_string(save_parents=True) + return new_cred def loadCredential (self): @@ -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):