From ee524e1beef10664533d293cb3669db5d2c5fb67 Mon Sep 17 00:00:00 2001 From: Josh Karlin Date: Mon, 12 Apr 2010 18:15:22 +0000 Subject: [PATCH] Merged trunk in from 17245:17645 --- TODO | 5 +- config/default_config.xml | 6 + setup.py | 3 +- sfa.spec | 10 +- sfa/client/sfi.py | 10 +- sfa/managers/aggregate_manager_pl.py | 10 +- sfa/managers/registry_manager_pl.py | 8 +- sfa/managers/slice_manager_pl.py | 16 +- sfa/methods/CreateSliver.py | 57 ++++++ sfa/methods/ListResources.py | 48 +++++ sfa/methods/get_credential.py | 8 +- sfa/methods/get_resources.py | 4 + sfa/methods/get_trusted_certs.py | 27 ++- sfa/plc/api.py | 93 +++++---- sfa/plc/nodes.py | 3 +- sfa/plc/slices.py | 22 +-- sfa/server/aggregate.py | 84 +------- sfa/server/interface.py | 186 ++++++++++++++++++ .../{ => modpython}/SfaAggregateModPython.py | 0 .../{ => modpython}/SfaRegistryModPython.py | 0 .../{ => modpython}/SfaSliceMgrModPython.py | 0 .../{ => modpython}/sfa.aggregate.httpd.conf | 0 .../{ => modpython}/sfa.registry.httpd.conf | 0 .../{ => modpython}/sfa.slicemgr.httpd.conf | 0 sfa/server/registry.py | 92 ++------- sfa/server/sfa-server.py | 18 +- sfa/server/sfa_component_setup.py | 60 +++++- sfa/trust/auth.py | 16 +- sfa/trust/rights.py | 11 +- sfa/util/api.py | 9 + sfa/util/record.py | 1 + sfa/util/server.py | 6 - sfa/util/table.py | 3 +- 33 files changed, 538 insertions(+), 278 deletions(-) create mode 100644 sfa/methods/CreateSliver.py create mode 100644 sfa/methods/ListResources.py create mode 100644 sfa/server/interface.py rename sfa/server/{ => modpython}/SfaAggregateModPython.py (100%) rename sfa/server/{ => modpython}/SfaRegistryModPython.py (100%) rename sfa/server/{ => modpython}/SfaSliceMgrModPython.py (100%) rename sfa/server/{ => modpython}/sfa.aggregate.httpd.conf (100%) rename sfa/server/{ => modpython}/sfa.registry.httpd.conf (100%) rename sfa/server/{ => modpython}/sfa.slicemgr.httpd.conf (100%) diff --git a/TODO b/TODO index 99db1ad4..cafce3e9 100644 --- a/TODO +++ b/TODO @@ -17,11 +17,12 @@ slices were on it and recreate them? do we make some sort of transaction log) - Registry -* sfa.plc.api.SfaAPI.fill_record_pl_info() should add the sites PIs to a slice records researchers list +* sign peer gids * update call should attempt to push updates to federated peers if the peer has a record for an object that is updated locally * api.update_membership() shoudl behave more like resolve when looking up records (attempt to resolve records at federated registeries) instead of only looking in the local registry -* support generic registry records (dont depend on postgres!) +* move db tables into db with less overhead (tokyocabinet?) +* make resolve, fill_record_info more fault tolerent. Skip records with failures - Auth Service * develop a simple service where users auth using username/passord and diff --git a/config/default_config.xml b/config/default_config.xml index 7e5dfdf3..a63b56bb 100644 --- a/config/default_config.xml +++ b/config/default_config.xml @@ -106,6 +106,12 @@ $URL$ The type of backend server for this aggregate. Some aggregates may not be myplc. + + + RSpec Schema + /etc/sfa/pl.rng + The path to the default schema + Hostname diff --git a/setup.py b/setup.py index 040c76ec..8d777927 100755 --- a/setup.py +++ b/setup.py @@ -46,7 +46,8 @@ data_files = [('/etc/sfa/', [ 'config/aggregates.xml', 'config/geni_aggregates.xml', 'config/registries.xml', 'config/default_config.xml', - 'config/sfi_config']), + 'config/sfi_config', + 'sfa/managers/pl/pl.rng']), ('/etc/sfatables/matches/', glob('sfatables/matches/*.xml')), ('/etc/sfatables/targets/', glob('sfatables/targets/*.xml')), ('/etc/init.d/', ['sfa/init.d/sfa', 'sfa/init.d/sfa-cm'])] diff --git a/sfa.spec b/sfa.spec index b5d9c42c..2e32acb8 100644 --- a/sfa.spec +++ b/sfa.spec @@ -6,7 +6,7 @@ %define name sfa %define version 0.9 -%define taglevel 10 +%define taglevel 11 %define release %{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}} %global python_sitearch %( python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)" ) @@ -154,6 +154,14 @@ chkconfig --add sfa %post cm chkconfig --add sfa-cm %changelog +* Thu Apr 08 2010 Tony Mack - sfa-0.9-11 +- SfaServer now uses a pool of threads to handle requests concurrently +- sfa.util.rspec no longer used to process/manage rspecs (deprecated). This is now handled by sfa.plc.network and is not backwards compatible +- PIs can now get a slice credential for any slice at their site without having to be a member of the slice +- Registry records for federated peers (defined in registries.xml, aggregates.xml) updated when sfa service is started +- Interfaces will try to fetch and install gids from peers listed in registries.xml/aggregates.xml if gid is not found in /etc/sfa/trusted_roots dir +- Component manager does not install gid files if slice already has them + * Thu Jan 21 2010 anil vengalil - sfa-0.9-10 - This tag is quite same as the previous one (sfa-0.9-9) except that the vini and max aggregate managers are also updated for urn support. Other features are: - - sfa-config-tty now has the same features like plc-config-tty diff --git a/sfa/client/sfi.py b/sfa/client/sfi.py index 90e1f870..9070bdb1 100755 --- a/sfa/client/sfi.py +++ b/sfa/client/sfi.py @@ -627,7 +627,7 @@ class Sfi: print "Error: Object credential", object_hrn, "does not have delegate bit set" return - records = self.registry.resolve(user_cred, args[0]) + records = self.registry.resolve(user_cred.save_to_string(save_parents=True), args[0]) records = filter_records("user", records) if not records: @@ -635,14 +635,14 @@ class Sfi: return # the gid of the user who will be delegated to - delegee_gid = records[0].get_gid_object() + delegee_gid = GID(string=records[0]['gid']) delegee_hrn = delegee_gid.get_hrn() - + # the key and hrn of the user who will be delegating user_key = Keypair(filename = self.get_key_file()) user_hrn = user_cred.get_gid_caller().get_hrn() - - dcred = Credential(subject=object_hrn + " delegated to " + delegee_hrn) + subject_string = "%s delegated to %s" % (object_hrn, delegee_hrn) + dcred = Credential(subject=subject_string) dcred.set_gid_caller(delegee_gid) dcred.set_gid_object(object_gid) privs = object_cred.get_privileges() diff --git a/sfa/managers/aggregate_manager_pl.py b/sfa/managers/aggregate_manager_pl.py index c5f57fe1..2ca9db4f 100644 --- a/sfa/managers/aggregate_manager_pl.py +++ b/sfa/managers/aggregate_manager_pl.py @@ -15,7 +15,6 @@ from sfa.util.record import SfaRecord from sfa.util.policy import Policy from sfa.util.record import * from sfa.util.sfaticket import SfaTicket -from sfa.server.registry import Registries from sfa.util.debug import log from sfa.plc.slices import Slices import sfa.plc.peers as peers @@ -56,8 +55,7 @@ def create_slice(api, xrn, xml): slices = Slices(api) peer = slices.get_peer(hrn) sfa_peer = slices.get_sfa_peer(hrn) - registries = Registries(api) - registry = registries[api.hrn] + registry = api.registries[api.hrn] credential = api.getCredential() site_id, remote_site_id = slices.verify_site(registry, credential, hrn, peer, sfa_peer) @@ -69,7 +67,8 @@ def create_slice(api, xrn, xml): slice = network.get_slice(api, hrn) current = __get_hostnames(slice.get_nodes()) - network.addRSpec(xml, "/var/www/html/schemas/pl.rng") + network.addRSpec(xml, api.config.SFA_AGGREGATE_RSPEC_SCHEMA) + request = __get_hostnames(network.nodesWithSlivers()) # remove nodes not in rspec @@ -98,8 +97,7 @@ def create_slice(api, xrn, xml): def get_ticket(api, xrn, rspec, origin_hrn=None): slice_hrn, type = urn_to_hrn(xrn) # the the slice record - registries = Registries(api) - registry = registries[api.hrn] + registry = api.registries[api.hrn] credential = api.getCredential() records = registry.resolve(credential, xrn) diff --git a/sfa/managers/registry_manager_pl.py b/sfa/managers/registry_manager_pl.py index 2108c154..18181aec 100644 --- a/sfa/managers/registry_manager_pl.py +++ b/sfa/managers/registry_manager_pl.py @@ -1,6 +1,5 @@ import types import time -from sfa.server.registry import Registries from sfa.util.prefixTree import prefixTree from sfa.util.record import SfaRecord from sfa.util.table import SfaTable @@ -77,8 +76,7 @@ def resolve(api, xrns, type=None, origin_hrn=None, full=True): # create a dict whre key is an registry hrn and its value is a # hrns at that registry (determined by the known prefix tree). xrn_dict = {} - # XX Preload this into the api module - registries = Registries(api) + registries = api.registries tree = prefixTree() registry_hrns = registries.keys() tree.load(registry_hrns) @@ -127,7 +125,7 @@ def list(api, xrn, origin_hrn=None): # load all know registry names into a prefix tree and attempt to find # the longest matching prefix records = [] - registries = Registries(api) + registries = api.registries registry_hrns = registries.keys() tree = prefixTree() tree.load(registry_hrns) @@ -368,7 +366,7 @@ def remove(api, xrn, type, origin_hrn=None): type = record['type'] credential = api.getCredential() - registries = Registries(api) + registries = api.registries # Try to remove the object from the PLCDB of federated agg. # This is attempted before removing the object from the local agg's PLCDB and sfa table diff --git a/sfa/managers/slice_manager_pl.py b/sfa/managers/slice_manager_pl.py index b3854a0e..2c824cfd 100644 --- a/sfa/managers/slice_manager_pl.py +++ b/sfa/managers/slice_manager_pl.py @@ -20,13 +20,12 @@ from sfa.util.prefixTree import prefixTree from sfa.util.rspec import * from sfa.util.sfaticket import * from sfa.util.debug import log -from sfa.server.registry import Registries -from sfa.server.aggregate import Aggregates +from sfa.util.sfalogging import logger import sfa.plc.peers as peers def delete_slice(api, xrn, origin_hrn=None): credential = api.getCredential() - aggregates = Aggregates(api) + aggregates = api.aggregates for aggregate in aggregates: success = False # request hash is optional so lets try the call without it @@ -60,7 +59,7 @@ def create_slice(api, xrn, rspec, origin_hrn=None): message = "%s (line %s)" % (error.message, error.line) raise InvalidRSpec(message) - aggs = Aggregates(api) + aggs = api.aggregates cred = api.getCredential() for agg in aggs: if agg not in [api.auth.client_cred.get_gid_caller().get_hrn()]: @@ -91,7 +90,7 @@ def get_ticket(api, xrn, rspec, origin_hrn=None): rspecs[net_hrn] = temp_rspec.toxml() # send the rspec to the appropiate aggregate/sm - aggregates = Aggregates(api) + aggregates = api.aggregates credential = api.getCredential() tickets = {} for net_hrn in rspecs: @@ -198,19 +197,22 @@ def get_rspec(api, xrn=None, origin_hrn=None): hrn, type = urn_to_hrn(xrn) rspec = None - aggs = Aggregates(api) + aggs = api.aggregates cred = api.getCredential() + + print >> log, "Aggregates = %s" % aggs for agg in aggs: if agg not in [api.auth.client_cred.get_gid_caller().get_hrn()]: try: # get the rspec from the aggregate agg_rspec = aggs[agg].get_resources(cred, xrn, origin_hrn) except: + # XX print out to some error log print >> log, "Error getting resources at aggregate %s" % agg traceback.print_exc(log) print >> log, "%s" % (traceback.format_exc()) - + continue try: tree = etree.parse(StringIO(agg_rspec)) diff --git a/sfa/methods/CreateSliver.py b/sfa/methods/CreateSliver.py new file mode 100644 index 00000000..28f644e9 --- /dev/null +++ b/sfa/methods/CreateSliver.py @@ -0,0 +1,57 @@ +from sfa.util.faults import * +from sfa.util.namespace import * +from sfa.util.method import Method +from sfa.util.parameter import Parameter, Mixed +from sfa.trust.auth import Auth +from sfa.trust.gid import GID +from sfa.trust.certificate import Certificate + +class CreateSliver(Method): + """ + Allocate resources to a slice. This operation is expected to + start the allocated resources asynchornously after the operation + has successfully completed. Callers can check on the status of + the resources using SliverStatus. + + @param slice_urn (string) URN of slice to allocate to + @param credentials ([string]) of credentials + @param rspec (string) rspec to allocate + + """ + interfaces = ['geni_am'] + accepts = [ + Parameter(str, "Slice URN"), + Parameter(type([str]), "List of credentials"), + Parameter(str, "RSpec") + ] + returns = Parameter(str, "Allocated RSpec") + + def call(self, slice_xrn, creds, rspec): + hrn, type = urn_to_hrn(slice_xrn) + + self.api.logger.info("interface: %s\ttarget-hrn: %s\tcaller-creds: %s\tmethod-name: %s"%(self.api.interface, hrn, creds, self.name)) + + # Validate that at least one of the credentials is good enough + found = False + for cred in creds: + try: + self.api.auth.check(cred, 'createslice') + found = True + break + except: + continue + + if not found: + raise InsufficientRights('CreateSliver: Credentials either did not verify, were no longer valid, or did not have appropriate privileges') + + + manager_base = 'sfa.managers' + + if self.api.interface in ['geni_am']: + mgr_type = self.api.config.SFA_GENI_AGGREGATE_TYPE + manager_module = manager_base + ".geni_am_%s" % mgr_type + manager = __import__(manager_module, fromlist=[manager_base]) + return manager.CreateSlice(self.api, slice_xrn, creds, rspec) + + return '' + diff --git a/sfa/methods/ListResources.py b/sfa/methods/ListResources.py new file mode 100644 index 00000000..11c10f7e --- /dev/null +++ b/sfa/methods/ListResources.py @@ -0,0 +1,48 @@ +from sfa.util.faults import * +from sfa.util.namespace import * +from sfa.util.method import Method +from sfa.util.parameter import Parameter, Mixed +from sfa.trust.auth import Auth +from sfa.trust.gid import GID +from sfa.trust.certificate import Certificate + +class ListResources(Method): + """ + Returns information about available resources or resources allocated to this slice + @param credential list + @param options dictionary + @return string + """ + interfaces = ['geni_am'] + accepts = [ + Parameter(type([str]), "List of credentials"), + Parameter(dict, "Options") + ] + returns = Parameter(str, "List of resources") + + def call(self, creds, options): + self.api.logger.info("interface: %s\tmethod-name: %s" % (self.api.interface, self.name)) + + # Validate that at least one of the credentials is good enough + found = False + for cred in creds: + try: + self.api.auth.check(cred, 'ListResources') + found = True + break + except: + continue + + if not found: + raise InsufficientRights('ListResources: Credentials either did not verify, were no longer valid, or did not have appropriate privileges') + + manager_base = 'sfa.managers' + + if self.api.interface in ['geni_am']: + mgr_type = self.api.config.SFA_GENI_AGGREGATE_TYPE + manager_module = manager_base + ".geni_am_%s" % mgr_type + manager = __import__(manager_module, fromlist=[manager_base]) + return manager.ListResources(self.api, creds, options) + + return '' + diff --git a/sfa/methods/get_credential.py b/sfa/methods/get_credential.py index f788eadc..14b9d1a1 100644 --- a/sfa/methods/get_credential.py +++ b/sfa/methods/get_credential.py @@ -38,11 +38,11 @@ class get_credential(Method): else: hrn, type = urn_to_hrn(xrn) - #log the call - if not origin_hrn: + #log the call + if not origin_hrn: origin_hrn = Credential(string=cred).get_gid_caller().get_hrn() - self.api.logger.info("interface: %s\tcaller-hrn: %s\ttarget-hrn: %s\tmethod-name: %s"%(self.api.interface, origin_hrn, hrn, self.name)) - + self.api.logger.info("interface: %s\tcaller-hrn: %s\ttarget-hrn: %s\tmethod-name: %s"%(self.api.interface, origin_hrn, hrn, self.name)) + self.api.logger.info("get_credential cred = %s" % cred) self.api.auth.check(cred, 'getcredential') self.api.auth.verify_object_belongs_to_me(hrn) diff --git a/sfa/methods/get_resources.py b/sfa/methods/get_resources.py index 6e93926f..39045988 100644 --- a/sfa/methods/get_resources.py +++ b/sfa/methods/get_resources.py @@ -45,7 +45,11 @@ class get_resources(Method): self.api.logger.info("interface: %s\tcaller-hrn: %s\ttarget-hrn: %s\tmethod-name: %s"%(self.api.interface, origin_hrn, hrn, self.name)) # validate the cred + self.api.logger.info("Checking for %s" % self.api.interface) + #self.api.logger.info("Credential = %s" % cred) self.api.auth.check(cred, 'listnodes') + self.api.logger.info("Checked out!") + # send the call to the right manager manager_base = 'sfa.managers' diff --git a/sfa/methods/get_trusted_certs.py b/sfa/methods/get_trusted_certs.py index 7c62240d..334734b2 100644 --- a/sfa/methods/get_trusted_certs.py +++ b/sfa/methods/get_trusted_certs.py @@ -10,22 +10,33 @@ from sfa.trust.credential import Credential class get_trusted_certs(Method): """ @param cred credential string specifying the rights of the caller - @return 1 is successful, faults otherwise + @return list of gid strings """ - interfaces = ['registry'] + interfaces = ['registry', 'aggregate', 'slicemgr'] accepts = [ - Parameter(str, "Credential string") + Mixed(Parameter(str, "Credential string"), + Parameter(None, "Credential not specified")) ] - returns = Parameter(int, "1 if successful") + returns = Parameter([str], "List of GID strings") - def call(self, cred): + def call(self, cred = None): + # If cred is not specified just return the gid for this interface. + # This is true when when a peer is attempting to initiate federation + # with this interface + print cred + if not cred: + gid_strings = [] + for gid in self.api.auth.trusted_cert_list: + if gid.get_hrn() == self.api.config.SFA_INTERFACE_HRN: + gid_strings.append(gid.save_to_string(save_parents=True)) + return gid_strings + # authenticate the cred self.api.auth.check(cred, 'gettrustedcerts') - - trusted_cert_strings = [gid.save_to_string(save_parents=True) for \ + gid_strings = [gid.save_to_string(save_parents=True) for \ gid in self.api.auth.trusted_cert_list] - return trusted_cert_strings + return gid_strings diff --git a/sfa/plc/api.py b/sfa/plc/api.py index 3f6e7293..44c38a99 100644 --- a/sfa/plc/api.py +++ b/sfa/plc/api.py @@ -23,6 +23,10 @@ from sfa.util.nodemanager import NodeManager from sfa.util.sfalogging import * def list_to_dict(recs, key): + """ + convert a list of dictionaries into a dictionary keyed on the + specified dictionary key + """ keys = [rec[key] for rec in recs] return dict(zip(keys, recs)) @@ -59,7 +63,7 @@ class SfaAPI(BaseAPI): rspec_type = self.config.get_aggregate_type() if (rspec_type == 'pl' or rspec_type == 'vini'): self.plshell = self.getPLCShell() - self.plshell_version = self.getPLCShellVersion() + self.plshell_version = "4.3" self.hrn = self.config.SFA_INTERFACE_HRN self.time_format = "%Y-%m-%d %H:%M:%S" @@ -70,35 +74,12 @@ class SfaAPI(BaseAPI): '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()) - shell.AuthCheck(self.plauth) - return shell - except ImportError: - self.plshell_type = 'xmlrpc' - # connect via xmlrpc - url = self.config.SFA_PLC_URL - shell = xmlrpclib.Server(url, verbose = 0, allow_none = True) - shell.AuthCheck(self.plauth) - return shell - - def getPLCShellVersion(self): - # We need to figure out what version of PLCAPI we are talking to. - # Some calls we need to make later will be different depending on - # the api version. - try: - # This is probably a bad way to determine api versions - # but its easy and will work for now. Lets try to make - # a call that only exists is PLCAPI.4.3. If it fails, we - # can assume the api version is 4.2 - self.plshell.GetTagTypes(self.plauth) - return '4.3' - except: - return '4.2' - + + self.plshell_type = 'xmlrpc' + # connect via xmlrpc + url = self.config.SFA_PLC_URL + shell = xmlrpclib.Server(url, verbose = 0, allow_none = True) + return shell def getCredential(self): if self.interface in ['registry']: @@ -286,7 +267,7 @@ class SfaAPI(BaseAPI): # fill record info for record in records: - # records with pointer==-1 do not have plc info associated with them. + # records with pointer==-1 do not have plc info. # for example, the top level authority records which are # authorities, but not PL "sites" if record['pointer'] == -1: @@ -382,24 +363,46 @@ class SfaAPI(BaseAPI): def fill_record_sfa_info(self, records): # get person ids - has_authority = False - has_slice = False person_ids = [] + site_ids = [] for record in records: - if record['type'] == 'authority': - has_authority = True person_ids.extend(record.get("person_ids", [])) + site_ids.extend(record.get("site_ids", [])) + if 'site_id' in record: + site_ids.append(record['site_id']) + + # get all pis from the sites we've encountered + # and store them in a dictionary keyed on site_id + site_pis = {} + if site_ids: + pi_filter = {'|roles': ['pi'], '|site_ids': site_ids} + pi_list = self.plshell.GetPersons(self.plauth, pi_filter, ['person_id', 'site_ids']) + for pi in pi_list: + # we will need the pi's hrns also + person_ids.append(pi['person_id']) + + # we also need to keep track of the sites these pis + # belong to + for site_id in pi['site_ids']: + if site_id in site_pis: + site_pis[site_id].append(pi) + else: + site_pis[site_id] = [pi] + + # get sfa records for all records associated with these records. + # we'll replace pl ids (person_ids) with hrns from the sfa records + # we obtain - # get sfa info + # get the sfa records table = self.SfaTable() person_list, persons = [], {} - pl_person_list, pl_persons = [], {} person_list = table.find({'type': 'user', 'pointer': person_ids}) persons = list_to_dict(person_list, 'pointer') - if has_authority: - pl_person_list = self.plshell.GetPersons(self.plauth, person_ids, ['person_id', 'roles']) - pl_persons = list_to_dict(pl_person_list, 'person_id') - + + # get the pl records + pl_person_list, pl_persons = [], {} + pl_person_list = self.plshell.GetPersons(self.plauth, person_ids, ['person_id', 'roles']) + pl_persons = list_to_dict(pl_person_list, 'person_id') # fill sfa info for record in records: @@ -409,10 +412,15 @@ class SfaAPI(BaseAPI): sfa_info = {} type = record['type'] if (type == "slice"): + # slice users researchers = [persons[person_id]['hrn'] for person_id in record['person_ids'] \ if person_id in persons] sfa_info['researcher'] = researchers - + # pis at the slice's site + pl_pis = site_pis[record['site_id']] + pi_ids = [pi['person_id'] for pi in pl_pis] + sfa_info['PI'] = [persons[person_id]['hrn'] for person_id in pi_ids] + elif (type == "authority"): pis, techs, admins = [], [], [] for pointer in record['person_ids']: @@ -427,7 +435,6 @@ class SfaAPI(BaseAPI): techs.append(hrn) if 'admin' in roles: admins.append(hrn) - sfa_info['PI'] = pis sfa_info['operator'] = techs sfa_info['owner'] = admins diff --git a/sfa/plc/nodes.py b/sfa/plc/nodes.py index 9c5cf628..190ee636 100644 --- a/sfa/plc/nodes.py +++ b/sfa/plc/nodes.py @@ -16,7 +16,6 @@ from sfa.util.debug import log from sfa.util.rspec import * from sfa.util.specdict import * from sfa.util.policy import Policy -from sfa.server.aggregate import Aggregates class Nodes(SimpleStorage): @@ -107,7 +106,7 @@ class Nodes(SimpleStorage): end_time = int(threshold.strftime("%s")) duration = end_time - start_time - aggregates = Aggregates(self.api) + aggregates = self.api.aggregates rspecs = {} networks = [] rspec = RSpec() diff --git a/sfa/plc/slices.py b/sfa/plc/slices.py index d8c48b7f..9730e972 100644 --- a/sfa/plc/slices.py +++ b/sfa/plc/slices.py @@ -16,8 +16,6 @@ from sfa.util.record import SfaRecord from sfa.util.policy import Policy from sfa.util.prefixTree import prefixTree from sfa.util.debug import log -from sfa.server.aggregate import Aggregates -from sfa.server.registry import Registries MAXINT = 2L**31-1 @@ -212,30 +210,17 @@ class Slices(SimpleStorage): def refresh_slices_smgr(self): slice_hrns = [] - aggregates = Aggregates(self.api) credential = self.api.getCredential() - for aggregate in aggregates: + for aggregate in self.api.aggregates: success = False - # request hash is optional so lets try the call without it try: - slices = aggregates[aggregate].get_slices(credential) + slices = self.api.aggregates[aggregate].get_slices(credential) slice_hrns.extend(slices) success = True except: print >> log, "%s" % (traceback.format_exc()) print >> log, "Error calling slices at aggregate %(aggregate)s" % locals() - # try sending the request hash if the previous call failed - if not success: - arg_list = [credential] - try: - slices = aggregates[aggregate].get_slices(credential) - slice_hrns.extend(slices) - success = True - except: - print >> log, "%s" % (traceback.format_exc()) - print >> log, "Error calling slices at aggregate %(aggregate)s" % locals() - # update timestamp and threshold timestamp = datetime.datetime.now() hr_timestamp = timestamp.strftime(self.api.time_format) @@ -420,8 +405,7 @@ class Slices(SimpleStorage): slicename = hrn_to_pl_slicename(hrn) slice = {} slice_record = None - registries = Registries(self.api) - registry = registries[self.api.hrn] + registry = self.api.registries[self.api.hrn] credential = self.api.getCredential() site_id, remote_site_id = self.verify_site(registry, credential, hrn, peer, sfa_peer) diff --git a/sfa/server/aggregate.py b/sfa/server/aggregate.py index 9295e3f5..aecc3b69 100644 --- a/sfa/server/aggregate.py +++ b/sfa/server/aggregate.py @@ -1,25 +1,13 @@ ### $Id$ ### $URL$ -import os -import sys -import datetime -import time -import xmlrpclib -from types import StringTypes, ListType from sfa.util.server import SfaServer -from sfa.util.storage import * from sfa.util.faults import * +from sfa.server.interface import Interfaces import sfa.util.xmlrpcprotocol as xmlrpcprotocol import sfa.util.soapprotocol as soapprotocol -# GeniLight client support is optional -try: - from egeni.geniLight_client import * -except ImportError: - GeniClientLight = None - class Aggregate(SfaServer): @@ -37,71 +25,19 @@ class Aggregate(SfaServer): ## # Aggregates is a dictionary of aggregate connections keyed on the aggregate hrn -class Aggregates(dict): - - required_fields = ['hrn', 'addr', 'port'] - - def __init__(self, api, file = "/etc/sfa/aggregates.xml"): - dict.__init__(self, {}) - self.api = api - self.interfaces = [] - # create default connection dict - connection_dict = {} - for field in self.required_fields: - connection_dict[field] = '' - aggregates_dict = {'aggregates': {'aggregate': [connection_dict]}} - # get possible config file locations - loaded = False - path = os.path.dirname(os.path.abspath(__file__)) - filename = file.split(os.sep)[-1] - alt_file = path + os.sep + filename - files = [file, alt_file] - - for f in files: - try: - if os.path.isfile(f): - self.aggregate_info = XmlStorage(f, aggregates_dict) - loaded = True - except: pass +class Aggregates(Interfaces): - # if file is missing, just recreate it in the right place - if not loaded: - self.aggregate_info = XmlStorage(file, aggregates_dict) - self.aggregate_info.load() - self.connectAggregates() + default_dict = {'aggregates': {'aggregate': [Interfaces.default_fields]}} + + def __init__(self, api, conf_file = "/etc/sfa/aggregates.xml"): + Interfaces.__init__(self, api, conf_file, 'ma') - def connectAggregates(self): + def get_connections(self, interfaces): """ Get connection details for the trusted peer aggregates from file and create an connection to each. """ - aggregates = self.aggregate_info['aggregates']['aggregate'] - if isinstance(aggregates, dict): - aggregates = [aggregates] - if isinstance(aggregates, list): - for aggregate in aggregates: - # make sure the required fields are present - if not set(self.required_fields).issubset(aggregate.keys()): - continue - hrn, address, port = aggregate['hrn'], aggregate['addr'], aggregate['port'] - if not hrn or not address or not port: - continue - self.interfaces.append(aggregate) - # check which client we should use - # sfa.util.xmlrpcprotocol is default - client_type = 'xmlrpcprotocol' - if aggregate.has_key('client') and aggregate['client'] in ['geniclientlight']: - client_type = 'geniclientlight' - - # create url - url = 'http://%(address)s:%(port)s' % locals() - - # create the client connection - # make sure module exists before trying to instantiate it - if client_type in ['geniclientlight'] and GeniClientLight: - self[hrn] = GeniClientLight(url, self.api.key_file, self.api.cert_file) - else: - self[hrn] = xmlrpcprotocol.get_server(url, self.api.key_file, self.api.cert_file) + connections = Interfaces.get_connections(self, interfaces) # set up a connection to the local registry address = self.api.config.SFA_AGGREGATE_HOST @@ -109,6 +45,6 @@ class Aggregates(dict): url = 'http://%(address)s:%(port)s' % locals() local_aggregate = {'hrn': self.api.hrn, 'addr': address, 'port': port} self.interfaces.append(local_aggregate) - self[self.api.hrn] = xmlrpcprotocol.get_server(url, self.api.key_file, self.api.cert_file) - + connections[self.api.hrn] = xmlrpcprotocol.get_server(url, self.api.key_file, self.api.cert_file) + return connections diff --git a/sfa/server/interface.py b/sfa/server/interface.py new file mode 100644 index 00000000..17f37c55 --- /dev/null +++ b/sfa/server/interface.py @@ -0,0 +1,186 @@ +# +### $Id: interface.py 17583 2010-04-06 15:01:08Z tmack $ +### $URL: https://svn.planet-lab.org/svn/sfa/trunk/sfa/server/interface.py $ +# + + +from sfa.util.faults import * +from sfa.util.storage import * +from sfa.util.namespace import * +from sfa.trust.gid import GID +from sfa.util.table import SfaTable +from sfa.util.record import SfaRecord +import sfa.util.xmlrpcprotocol as xmlrpcprotocol +import sfa.util.soapprotocol as soapprotocol + + +# GeniLight client support is optional +try: + from egeni.geniLight_client import * +except ImportError: + GeniClientLight = None + + +## +# In is a dictionary of registry connections keyed on the registry +# hrn + +class Interfaces(dict): + """ + Interfaces is a base class for managing information on the + peers we are federated with. It is responsible for the following: + + 1) Makes sure a record exist in the local registry for the each + fedeated peer + 2) Attepts to fetch and install trusted gids + 3) Provides connections (xmlrpc or soap) to federated peers + """ + + # fields that must be specified in the config file + default_fields = { + 'hrn': '', + 'addr': '', + 'port': '', + } + + # defined by the class + default_dict = {} + + # allowed types + types = ['sa', 'ma'] + + def __init__(self, api, conf_file, type): + if type not in self.types: + raise SfaInfaildArgument('Invalid type %s: must be in %s' % (type, self.types)) + dict.__init__(self, {}) + self.api = api + self.type = type + # load config file + self.interface_info = XmlStorage(conf_file, self.default_dict) + self.interface_info.load() + self.interfaces = self.interface_info.values()[0].values()[0] + if not isinstance(self.interfaces, list): + self.interfaces = [self.interfaces] + # get connections + self.update(self.get_connections(self.interfaces)) + + def sync_interfaces(self): + """ + Install missing trusted gids and db records for our federated + interfaces + """ + # Attempt to get any missing peer gids + # There should be a gid file in /etc/sfa/trusted_roots for every + # peer registry found in in the registries.xml config file. If there + # are any missing gids, request a new one from the peer registry. + gids_current = self.api.auth.trusted_cert_list + hrns_current = [gid.get_hrn() for gid in gids_current] + hrns_expected = [interface['hrn'] for interface in self.interfaces] + new_hrns = set(hrns_expected).difference(hrns_current) + self.get_peer_gids(new_hrns) + + # update the local db records for these registries + self.update_db_records(self.type) + + def get_peer_gids(self, new_hrns): + """ + Install trusted gids from the specified interfaces. + """ + if not new_hrns: + return + trusted_certs_dir = self.api.config.get_trustedroots_dir() + for new_hrn in new_hrns: + # the gid for this interface should already be installed + if new_hrn == self.api.config.SFA_INTERFACE_HRN: + continue + try: + # get gid from the registry + interface = self.get_connections(self.interfaces[new_hrn])[new_hrn] + trusted_gids = interface.get_trusted_certs() + # default message + message = "interface: %s\tunable to install trusted gid for %s" % \ + (self.api.interface, new_hrn) + if trusted_gids: + # the gid we want shoudl be the first one in the list, + # but lets make sure + for trusted_gid in trusted_gids: + gid = GID(string=trusted_gids[0]) + if gid.get_hrn() == new_hrn: + gid_filename = os.path.join(trusted_certs_dir, '%s.gid' % new_hrn) + gid.save_to_file(gid_filename, save_parents=True) + message = "interface: %s\tinstalled trusted gid for %s" % \ + (self.api.interface, new_hrn) + # log the message + self.api.logger.info(message) + except: + message = "interface: %s\tunable to install trusted gid for %s" % \ + (self.api.interface, new_hrn) + self.api.logger.info(message) + + # reload the trusted certs list + self.api.auth.load_trusted_certs() + + def update_db_records(self, type): + """ + Make sure there is a record in the local db for allowed registries + defined in the config file (registries.xml). Removes old records from + the db. + """ + # get hrns we expect to find + # ignore records for local interfaces + ignore_interfaces = [self.api.config.SFA_INTERFACE_HRN] + hrns_expected = [interface['hrn'] for interface in self.interfaces \ + if interface['hrn'] not in ignore_interfaces] + + # get hrns that actually exist in the db + table = SfaTable() + records = table.find({'type': type}) + hrns_found = [record['hrn'] for record in records] + + # remove old records + for record in records: + if record['hrn'] not in hrns_expected: + table.remove(record) + + # add new records + for hrn in hrns_expected: + if hrn not in hrns_found: + record = { + 'hrn': hrn, + 'type': type, + 'pointer': -1, + 'authority': get_authority(hrn), + } + record = SfaRecord(dict=record) + table.insert(record) + + + def get_connections(self, interfaces): + """ + read connection details for the trusted peer registries from file return + a dictionary of connections keyed on interface hrn. + """ + connections = {} + required_fields = self.default_fields.keys() + if not isinstance(interfaces, list): + interfaces = [interfaces] + for interface in interfaces: + # make sure the required fields are present and not null + if not all([interface.get(key) for key in required_fields]): + continue + + hrn, address, port = interface['hrn'], interface['addr'], interface['port'] + url = 'http://%(address)s:%(port)s' % locals() + + # check which client we should use + # sfa.util.xmlrpcprotocol is default + client_type = 'xmlrpcprotocol' + if interface.has_key('client') and \ + interface['client'] in ['geniclientlight'] and \ + GeniClientLight: + client_type = 'geniclientlight' + connections[hrn] = GeniClientLight(url, self.api.key_file, self.api.cert_file) + else: + connections[hrn] = xmlrpcprotocol.get_server(url, self.api.key_file, self.api.cert_file) + + return connections diff --git a/sfa/server/SfaAggregateModPython.py b/sfa/server/modpython/SfaAggregateModPython.py similarity index 100% rename from sfa/server/SfaAggregateModPython.py rename to sfa/server/modpython/SfaAggregateModPython.py diff --git a/sfa/server/SfaRegistryModPython.py b/sfa/server/modpython/SfaRegistryModPython.py similarity index 100% rename from sfa/server/SfaRegistryModPython.py rename to sfa/server/modpython/SfaRegistryModPython.py diff --git a/sfa/server/SfaSliceMgrModPython.py b/sfa/server/modpython/SfaSliceMgrModPython.py similarity index 100% rename from sfa/server/SfaSliceMgrModPython.py rename to sfa/server/modpython/SfaSliceMgrModPython.py diff --git a/sfa/server/sfa.aggregate.httpd.conf b/sfa/server/modpython/sfa.aggregate.httpd.conf similarity index 100% rename from sfa/server/sfa.aggregate.httpd.conf rename to sfa/server/modpython/sfa.aggregate.httpd.conf diff --git a/sfa/server/sfa.registry.httpd.conf b/sfa/server/modpython/sfa.registry.httpd.conf similarity index 100% rename from sfa/server/sfa.registry.httpd.conf rename to sfa/server/modpython/sfa.registry.httpd.conf diff --git a/sfa/server/sfa.slicemgr.httpd.conf b/sfa/server/modpython/sfa.slicemgr.httpd.conf similarity index 100% rename from sfa/server/sfa.slicemgr.httpd.conf rename to sfa/server/modpython/sfa.slicemgr.httpd.conf diff --git a/sfa/server/registry.py b/sfa/server/registry.py index 1902a648..5658f37d 100644 --- a/sfa/server/registry.py +++ b/sfa/server/registry.py @@ -5,26 +5,15 @@ ### $URL$ # -import tempfile -import os -import time -import sys - from sfa.util.server import SfaServer from sfa.util.faults import * -from sfa.util.storage import * +from sfa.server.interface import Interfaces import sfa.util.xmlrpcprotocol as xmlrpcprotocol import sfa.util.soapprotocol as soapprotocol -# GeniLight client support is optional -try: - from egeni.geniLight_client import * -except ImportError: - GeniClientLight = None ## # Registry is a SfaServer that serves registry and slice operations at PLC. - class Registry(SfaServer): ## # Create a new registry object. @@ -33,7 +22,7 @@ class Registry(SfaServer): # @param port the port to listen on # @param key_file private key filename of registry # @param cert_file certificate filename containing public key (could be a GID file) - + def __init__(self, ip, port, key_file, cert_file): SfaServer.__init__(self, ip, port, key_file, cert_file) self.server.interface = 'registry' @@ -43,79 +32,24 @@ class Registry(SfaServer): # Registries is a dictionary of registry connections keyed on the registry # hrn -class Registries(dict): - - required_fields = ['hrn', 'addr', 'port'] - - def __init__(self, api, file = "/etc/sfa/registries.xml"): - dict.__init__(self, {}) - self.api = api - self.interfaces = [] - - # create default connection dict - connection_dict = {} - for field in self.required_fields: - connection_dict[field] = '' - registries_dict = {'registries': {'registry': [connection_dict]}} - - # get possible config file locations - loaded = False - path = os.path.dirname(os.path.abspath(__file__)) - filename = file.split(os.sep)[-1] - alt_file = path + os.sep + filename - files = [file, alt_file] +class Registries(Interfaces): - for f in files: - try: - if os.path.isfile(f): - self.registry_info = XmlStorage(f, registries_dict) - loaded = True - except: pass + default_dict = {'registries': {'registry': [Interfaces.default_fields]}} + + def __init__(self, api, conf_file = "/etc/sfa/registries.xml"): + Interfaces.__init__(self, api, conf_file, 'sa') - # if file is missing, just recreate it in the right place - if not loaded: - self.registry_info = XmlStorage(file, registries_dict) - self.registry_info.load() - self.connectRegistries() - - def connectRegistries(self): + def get_connections(self, interfaces): """ - Get connection details for the trusted peer registries from file and - create a connection to each. + read connection details for the trusted peer registries from file return + a dictionary of connections keyed on interface hrn. """ - registries = self.registry_info['registries']['registry'] - if isinstance(registries, dict): - registries = [registries] - if isinstance(registries, list): - for registry in registries: - # make sure the required fields are present - if not set(self.required_fields).issubset(registry.keys()): - continue - hrn, address, port = registry['hrn'], registry['addr'], registry['port'] - if not hrn or not address or not port: - continue - self.interfaces.append(registry) - # check which client we should use - # sfa.util.xmlrpcprotocol is default - client_type = 'xmlrpcprotocol' - if registry.has_key('client') and registry['client'] in ['geniclientlight']: - client_type = 'geniclientlight' - - # create url - url = 'http://%(address)s:%(port)s' % locals() - - # create the client connection - # make sure module exists before trying to instantiate it - if client_type in ['geniclientlight'] and GeniClientLight: - self[hrn] = GeniClientLight(url, self.api.key_file, self.api.cert_file) - else: - self[hrn] = xmlrpcprotocol.get_server(url, self.api.key_file, self.api.cert_file) + connections = Interfaces.get_connections(self, interfaces) # set up a connection to the local registry address = self.api.config.SFA_REGISTRY_HOST port = self.api.config.SFA_REGISTRY_PORT url = 'http://%(address)s:%(port)s' % locals() local_registry = {'hrn': self.api.hrn, 'addr': address, 'port': port} - self.interfaces.append(local_registry) - self[self.api.hrn] = xmlrpcprotocol.get_server(url, self.api.key_file, self.api.cert_file) - + connections[self.api.hrn] = xmlrpcprotocol.get_server(url, self.api.key_file, self.api.cert_file) + return connections diff --git a/sfa/server/sfa-server.py b/sfa/server/sfa-server.py index 35d00be4..db78d5c8 100755 --- a/sfa/server/sfa-server.py +++ b/sfa/server/sfa-server.py @@ -43,6 +43,9 @@ from sfa.trust.certificate import Keypair, Certificate from sfa.trust.hierarchy import Hierarchy from sfa.util.config import Config from sfa.util.report import trace +from sfa.plc.api import SfaAPI +from sfa.server.registry import Registries +from sfa.server.aggregate import Aggregates # after http://www.erlenstar.demon.co.uk/unix/faq_2.html def daemon(): @@ -154,6 +157,17 @@ def init_server(options, config): manager.init_server() +def sync_interfaces(): + """ + Attempt to install missing trusted gids and db records for + our federated interfaces + """ + api = SfaAPI() + registries = Registries(api) + aggregates = Aggregates(api) + registries.sync_interfaces() + aggregates.sync_interfaces() + def main(): # xxx get rid of globals - name consistently CamelCase or under_score global AuthHierarchy @@ -184,12 +198,12 @@ def main(): config = Config() hierarchy = Hierarchy() - trusted_roots = TrustedRootList(config.get_trustedroots_dir()) server_key_file = os.path.join(hierarchy.basedir, "server.key") server_cert_file = os.path.join(hierarchy.basedir, "server.cert") init_server_key(server_key_file, server_cert_file, config, hierarchy) - init_server(options, config) + init_server(options, config) + sync_interfaces() # start registry server if (options.registry): diff --git a/sfa/server/sfa_component_setup.py b/sfa/server/sfa_component_setup.py index 227f992d..7cea637b 100755 --- a/sfa/server/sfa_component_setup.py +++ b/sfa/server/sfa_component_setup.py @@ -6,11 +6,26 @@ from optparse import OptionParser from sfa.util.config import Config import sfa.util.xmlrpcprotocol as xmlrpcprotocol from sfa.util.namespace import * +from sfa.util.faults import * from sfa.trust.certificate import Keypair, Certificate from sfa.trust.credential import Credential from sfa.trust.gid import GID from sfa.trust.hierarchy import Hierarchy +KEYDIR = "/var/lib/sfa/" +CONFDIR = "/etc/sfa/" + +def handle_gid_mismatch_exception(f): + def wrapper(*args, **kwds): + try: return f(*args, **kwds) + except ConnectionKeyGIDMismatch: + # clean regen server keypair and try again + print "cleaning keys and trying again" + clean_key_cred() + return f(args, kwds) + + return wrapper + def get_server(url=None, port=None, keyfile=None, certfile=None,verbose=False): """ returns an xmlrpc connection to the service a the specified @@ -45,6 +60,26 @@ def create_default_dirs(): for dir in all_dirs: if not os.path.exists(dir): os.makedirs(dir) + +def has_node_key(): + key_file = KEYDIR + os.sep + 'server.key' + return os.path.exists(key_file) + +def clean_key_cred(): + """ + remove the existing keypair and cred and generate new ones + """ + files = ["server.key", "server.cert", "node.cred"] + for f in files: + filepath = KEYDIR + os.sep + f + if os.path.isfile(filepath): + os.unlink(f) + + # install the new key pair + # get_credential will take care of generating the new keypair + # and credential + get_credential() + def get_node_key(registry=None, verbose=False): # this call requires no authentication, @@ -74,7 +109,8 @@ def create_server_keypair(keyfile=None, certfile=None, hrn="component", verbose= cert.set_pubkey(key) cert.sign() cert.save_to_file(certfile, save_parents=True) - + +@handle_gid_mismatch_exception def get_credential(registry=None, force=False, verbose=False): config = Config() hierarchy = Hierarchy() @@ -115,6 +151,7 @@ def get_credential(registry=None, force=False, verbose=False): return cred +@handle_gid_mismatch_exception def get_trusted_certs(registry=None, verbose=False): """ refresh our list of trusted certs. @@ -157,6 +194,7 @@ def get_trusted_certs(registry=None, verbose=False): print "Removing old gid ", gid_name os.unlink(trusted_certs_dir + os.sep + gid_name) +@handle_gid_mismatch_exception def get_gids(registry=None, verbose=False): """ Get the gid for all instantiated slices on this node and store it @@ -186,10 +224,24 @@ def get_gids(registry=None, verbose=False): api = ComponentAPI() xids_tuple = api.nodemanager.GetXIDs() slices = eval(xids_tuple[1]) - slicenames = slices.keys() - hrns = [slicename_to_hrn(interface_hrn, slicename) for slicename in slicenames] - + slicenames = slices.keys() + # generate a list of slices that dont have gids installed + slices_without_gids = [] + for slicename in slicenames: + if not os.path.isfile("/vservers/%s/etc/slice.gid" % slicename) \ + or not os.path.isfile("/vservers/%s/etc/node.gid" % slicename): + slices_without_gids.append(slicename) + + # convert slicenames to hrns + hrns = [slicename_to_hrn(interface_hrn, slicename) \ + for slicename in slices_without_gids] + + # exit if there are no gids to install + print hrns + if not hrns: + return + if verbose: print "Getting gids for slices on this node from registry" # get the gids diff --git a/sfa/trust/auth.py b/sfa/trust/auth.py index 15d3b589..06f490d5 100644 --- a/sfa/trust/auth.py +++ b/sfa/trust/auth.py @@ -27,10 +27,12 @@ class Auth: self.hierarchy = Hierarchy() if not config: self.config = Config() - self.trusted_cert_list = TrustedRootList(self.config.get_trustedroots_dir()).get_list() + self.load_trusted_certs() self.trusted_cert_file_list = TrustedRootList(self.config.get_trustedroots_dir()).get_file_list() - + def load_trusted_certs(self): + self.trusted_cert_list = TrustedRootList(self.config.get_trustedroots_dir()).get_list() + def check(self, cred, operation): """ Check the credential against the peer cert (callerGID included @@ -225,11 +227,15 @@ class Auth: pis = record.get("PI", []) operators = record.get("operator", []) if (caller_hrn == self.config.SFA_INTERFACE_HRN): - rl.add("authority,sa,ma",) + rl.add("authority") + rl.add("sa") + rl.add("ma") if (caller_hrn in pis): - rl.add("authority,sa") + rl.add("authority") + rl.add("sa") if (caller_hrn in operators): - rl.add("authority,ma") + rl.add("authority") + rl.add("ma") elif type == "user": rl.add("refresh") diff --git a/sfa/trust/rights.py b/sfa/trust/rights.py index 4ecabb9d..e3d110f0 100644 --- a/sfa/trust/rights.py +++ b/sfa/trust/rights.py @@ -30,6 +30,7 @@ privilege_table = {"authority": ["register", "remove", "update", "resolve", "lis "operator": ["gettrustedcerts", "getgids"]} + ## # Determine tje rights that an object should have. The rights are entirely # dependent on the type of the object. For example, users automatically @@ -52,11 +53,15 @@ def determine_rights(type, name): rl.add("resolve") rl.add("info") elif type == "sa": - rl.add("authority,sa") + rl.add("authority") + rl.add("sa") elif type == "ma": - rl.add("authority,ma") + rl.add("authority") + rl.add("ma") elif type == "authority": - rl.add("authority,sa,ma") + rl.add("authority") + rl.add("sa") + rl.add("ma") elif type == "slice": rl.add("refresh") rl.add("embed") diff --git a/sfa/util/api.py b/sfa/util/api.py index ad129de4..635cc43b 100644 --- a/sfa/util/api.py +++ b/sfa/util/api.py @@ -115,6 +115,7 @@ class BaseAPI: # Load configuration self.config = Config(config) self.auth = Auth(peer_cert) + self.hrn = self.config.SFA_INTERFACE_HRN self.interface = interface self.key_file = key_file self.key = Keypair(filename=self.key_file) @@ -124,6 +125,14 @@ class BaseAPI: self.source = None self.time_format = "%Y-%m-%d %H:%M:%S" self.logger=get_sfa_logger() + + # load registries + from sfa.server.registry import Registries + self.registries = Registries(self) + + # load aggregates + from sfa.server.aggregate import Aggregates + self.aggregates = Aggregates(self) def callable(self, method): diff --git a/sfa/util/record.py b/sfa/util/record.py index aad12ca6..f9eaa090 100644 --- a/sfa/util/record.py +++ b/sfa/util/record.py @@ -366,6 +366,7 @@ class SliceRecord(SfaRecord): 'url': Parameter(str, 'Slice url'), 'expires': Parameter(int, 'Date and time this slice exipres'), 'researcher': Parameter([str], 'List of users for this slice'), + 'PI': Parameter([str], 'List of PIs responsible for this slice'), 'description': Parameter([str], 'Description of this slice'), } fields.update(SfaRecord.fields) diff --git a/sfa/util/server.py b/sfa/util/server.py index 197297d3..38bbfca9 100644 --- a/sfa/util/server.py +++ b/sfa/util/server.py @@ -101,12 +101,6 @@ class SecureXMLRpcRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler): cert_file = self.server.cert_file) # get arguments request = self.rfile.read(int(self.headers["content-length"])) - # In previous versions of SimpleXMLRPCServer, _dispatch - # could be overridden in this class, instead of in - # SimpleXMLRPCDispatcher. To maintain backwards compatibility, - # check to see if a subclass implements _dispatch and dispatch - # using that method if present. - #response = self.server._marshaled_dispatch(request, getattr(self, '_dispatch', None)) remote_addr = (remote_ip, remote_port) = self.connection.getpeername() self.api.remote_addr = remote_addr response = self.api.handle(remote_addr, request) diff --git a/sfa/util/table.py b/sfa/util/table.py index d376f639..40386ee4 100644 --- a/sfa/util/table.py +++ b/sfa/util/table.py @@ -179,9 +179,8 @@ class SfaTable(list): def drop(self): try: - self.db.do('DROP TABLE IF EXISTS ' + self.tablename) + self.db.do('DROP TABLE IF EXISTS ' + self.tablename) except: - try: self.db.do('DROP TABLE ' + self.tablename) except: -- 2.47.0