chmod 444 $(DESTDIR)/etc/sfa/default_config.xml
rm -rf $(DESTDIR)/usr/lib*/python*/site-packages/*egg-info
rm -rf $(DESTDIR)/usr/lib*/python*/site-packages/sfa/storage/migrations
- (cd $(DESTDIR)/usr/bin ; ln -s sfi.py sfi; ln -s sfascan.py sfascan)
+ (cd $(DESTDIR)/usr/bin ; ln -s sfi.py sfi; ln -s sfascan.py sfascan; ln -s sfaadmin.py sfaadmin)
python-clean: version-clean
python setup.py clean
synctest: synccheck
+$(RSYNC) ./tests/ $(SSHURL)/root/tests-sfa
syncrestart: synccheck
- $(SSHCOMMAND) exec service sfa restart
+ $(SSHCOMMAND) service sfa restart
syncmig:
+$(RSYNC) ./sfa/storage/migrations $(SSHURL)/usr/share/sfa/
'sfa/generic',
'sfa/managers',
'sfa/importer',
- 'sfa/plc',
+ 'sfa/planetlab',
'sfa/rspecs',
'sfa/rspecs/elements',
'sfa/rspecs/elements/versions',
%define name sfa
%define version 2.1
-%define taglevel 5
+%define taglevel 7
%define release %{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}}
%global python_sitearch %( python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)" )
/etc/init.d/sfa
%{_bindir}/sfa-start.py*
%{_bindir}/sfaadmin.py*
+%{_bindir}/sfaadmin
%{_bindir}/keyconvert.py*
%{_bindir}/sfa-config-tty
%config /etc/sfa/default_config.xml
[ "$1" -ge "1" ] && service sfa-cm restart || :
%changelog
+* Mon May 14 2012 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - sfa-2.1-7
+- renamed sfa/plc into sfa/planetlab
+- plxrn moved in sfa/planetlab as well
+- bugfix for sfaadmin reg update --pi <>
+
+* Sat May 12 2012 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - sfa-2.1-6
+- native data model now has a authority x user (PI) relationship
+- no call to 'augment_records_with_testbed_info' for GetCredential
+- which means, registry can now be used without an underlying testbed
+- reviewed code about relationships b/w objects and related in pl driver
+- reviewed PL import wrt roles and pis
+- removed mentions to is_enabled in driver
+- small changes in update_relation* in driver interface
+- sfaadmin: can create authorities and attach pi users to them
+- sfaadmin: categories can be abbreviated
+- sfi list and sfaadmin list have a new -r/--recursive option
+- this means that List now supports an (optional) 'options' argument
+- sfi config can display config vars
+- sfaadmin code in sfa.client + /usr/bin/sfaadmin shortcut
+
* Mon Apr 16 2012 Tony Mack <tmack@cs.princeton.edu> - sfa-2.1-5
- make sync now supports vserver or lxc.
- Added slice expiration and login info to SliverStatus response.
--- /dev/null
+#!/usr/bin/python
+import os
+import sys
+import copy
+from pprint import pformat, PrettyPrinter
+from optparse import OptionParser
+
+from sfa.generic import Generic
+from sfa.util.xrn import Xrn
+from sfa.storage.record import Record
+from sfa.client.sfi import save_records_to_file
+from sfa.trust.hierarchy import Hierarchy
+from sfa.trust.gid import GID
+
+pprinter = PrettyPrinter(indent=4)
+
+def optparse_listvalue_callback(option, opt, value, parser):
+ setattr(parser.values, option.dest, value.split(','))
+
+def args(*args, **kwargs):
+ def _decorator(func):
+ func.__dict__.setdefault('options', []).insert(0, (args, kwargs))
+ return func
+ return _decorator
+
+class Commands(object):
+ def _get_commands(self):
+ available_methods = []
+ for attrib in dir(self):
+ if callable(getattr(self, attrib)) and not attrib.startswith('_'):
+ available_methods.append(attrib)
+ return available_methods
+
+
+class RegistryCommands(Commands):
+ def __init__(self, *args, **kwds):
+ self.api= Generic.the_flavour().make_api(interface='registry')
+
+ def version(self):
+ """Display the Registry version"""
+ version = self.api.manager.GetVersion(self.api, {})
+ pprinter.pprint(version)
+
+ @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='authority to list (hrn/urn - mandatory)')
+ @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
+ @args('-r', '--recursive', dest='recursive', metavar='<recursive>', help='list all child records',
+ action='store_true', default=False)
+ def list(self, xrn, type=None, recursive=False):
+ """List names registered at a given authority - possibly filtered by type"""
+ xrn = Xrn(xrn, type)
+ options = {'recursive': recursive}
+ records = self.api.manager.List(self.api, xrn.get_hrn(), options=options)
+ for record in records:
+ if not type or record['type'] == type:
+ print "%s (%s)" % (record['hrn'], record['type'])
+
+
+ @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn (mandatory)')
+ @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
+ @args('-o', '--outfile', dest='outfile', metavar='<outfile>', help='save record to file')
+ @args('-f', '--format', dest='format', metavar='<display>', type='choice',
+ choices=('text', 'xml', 'simple'), help='display record in different formats')
+ def show(self, xrn, type=None, format=None, outfile=None):
+ """Display details for a registered object"""
+ records = self.api.manager.Resolve(self.api, xrn, type, True)
+ for record in records:
+ sfa_record = Record(dict=record)
+ sfa_record.dump(format)
+ if outfile:
+ save_records_to_file(outfile, records)
+
+
+ def _record_dict(self, xrn=None, type=None,
+ url=None, description=None, email='',
+ key=None,
+ slices=[], researchers=[], pis=[]):
+ record_dict = {}
+ if xrn:
+ if type:
+ xrn = Xrn(xrn, type)
+ else:
+ xrn = Xrn(xrn)
+ record_dict['urn'] = xrn.get_urn()
+ record_dict['hrn'] = xrn.get_hrn()
+ record_dict['type'] = xrn.get_type()
+ if url:
+ record_dict['url'] = url
+ if description:
+ record_dict['description'] = description
+ if key:
+ try:
+ pubkey = open(key, 'r').read()
+ except IOError:
+ pubkey = key
+ record_dict['keys'] = [pubkey]
+ if slices:
+ record_dict['slices'] = slices
+ if researchers:
+ record_dict['researcher'] = researchers
+ if email:
+ record_dict['email'] = email
+ if pis:
+ record_dict['pi'] = pis
+ return record_dict
+
+ @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn (mandatory)')
+ @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
+ @args('-e', '--email', dest='email', default="",
+ help="email (mandatory for users)")
+ @args('-u', '--url', dest='url', metavar='<url>', default=None,
+ help="URL, useful for slices")
+ @args('-d', '--description', dest='description', metavar='<description>',
+ help='Description, useful for slices', default=None)
+ @args('-k', '--key', dest='key', metavar='<key>', help='public key string or file',
+ default=None)
+ @args('-s', '--slices', dest='slices', metavar='<slices>', help='slice xrns',
+ default='', type="str", action='callback', callback=optparse_listvalue_callback)
+ @args('-r', '--researchers', dest='researchers', metavar='<researchers>', help='slice researchers',
+ default='', type="str", action='callback', callback=optparse_listvalue_callback)
+ @args('-p', '--pis', dest='pis', metavar='<PIs>',
+ help='Principal Investigators/Project Managers ',
+ default='', type="str", action='callback', callback=optparse_listvalue_callback)
+ def register(self, xrn, type=None, url=None, description=None, key=None, slices='',
+ pis='', researchers='',email=''):
+ """Create a new Registry record"""
+ record_dict = self._record_dict(xrn=xrn, type=type, url=url, key=key,
+ slices=slices, researchers=researchers, email=email, pis=pis)
+ self.api.manager.Register(self.api, record_dict)
+
+
+ @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn (mandatory)')
+ @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
+ @args('-u', '--url', dest='url', metavar='<url>', help='URL', default=None)
+ @args('-d', '--description', dest='description', metavar='<description>',
+ help='Description', default=None)
+ @args('-k', '--key', dest='key', metavar='<key>', help='public key string or file',
+ default=None)
+ @args('-s', '--slices', dest='slices', metavar='<slices>', help='slice xrns',
+ default='', type="str", action='callback', callback=optparse_listvalue_callback)
+ @args('-r', '--researchers', dest='researchers', metavar='<researchers>', help='slice researchers',
+ default='', type="str", action='callback', callback=optparse_listvalue_callback)
+ @args('-p', '--pis', dest='pis', metavar='<PIs>',
+ help='Principal Investigators/Project Managers ',
+ default='', type="str", action='callback', callback=optparse_listvalue_callback)
+ def update(self, xrn, type=None, url=None, description=None, key=None, slices='',
+ pis='', researchers=''):
+ """Update an existing Registry record"""
+ record_dict = self._record_dict(xrn=xrn, type=type, url=url, description=description,
+ key=key, slices=slices, researchers=researchers, pis=pis)
+ self.api.manager.Update(self.api, record_dict)
+
+ @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn (mandatory)')
+ @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
+ def remove(self, xrn, type=None):
+ """Remove given object from the registry"""
+ xrn = Xrn(xrn, type)
+ self.api.manager.Remove(self.api, xrn)
+
+
+ @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn (mandatory)')
+ @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
+ def credential(self, xrn, type=None):
+ """Invoke GetCredential"""
+ cred = self.api.manager.GetCredential(self.api, xrn, type, self.api.hrn)
+ print cred
+
+
+ def import_registry(self):
+ """Run the importer"""
+ from sfa.importer import Importer
+ importer = Importer()
+ importer.run()
+
+ @args('-a', '--all', dest='all', metavar='<all>', action='store_true', default=False,
+ help='Remove all registry records and all files in %s area' % Hierarchy().basedir)
+ @args('-c', '--certs', dest='certs', metavar='<certs>', action='store_true', default=False,
+ help='Remove all cached certs/gids found in %s' % Hierarchy().basedir )
+ @args('-0', '--no-reinit', dest='reinit', metavar='<reinit>', action='store_false', default=True,
+ help='Prevents new DB schema from being installed after cleanup')
+ def nuke(self, all=False, certs=False, reinit=True):
+ """Cleanup local registry DB, plus various additional filesystem cleanups optionally"""
+ from sfa.storage.dbschema import DBSchema
+ from sfa.util.sfalogging import _SfaLogger
+ logger = _SfaLogger(logfile='/var/log/sfa_import.log', loggername='importlog')
+ logger.setLevelFromOptVerbose(self.api.config.SFA_API_LOGLEVEL)
+ logger.info("Purging SFA records from database")
+ dbschema=DBSchema()
+ dbschema.nuke()
+
+ # for convenience we re-create the schema here, so there's no need for an explicit
+ # service sfa restart
+ # however in some (upgrade) scenarios this might be wrong
+ if reinit:
+ logger.info("re-creating empty schema")
+ dbschema.init_or_upgrade()
+
+ # remove the server certificate and all gids found in /var/lib/sfa/authorities
+ if certs:
+ logger.info("Purging cached certificates")
+ for (dir, _, files) in os.walk('/var/lib/sfa/authorities'):
+ for file in files:
+ if file.endswith('.gid') or file == 'server.cert':
+ path=dir+os.sep+file
+ os.unlink(path)
+
+ # just remove all files that do not match 'server.key' or 'server.cert'
+ if all:
+ logger.info("Purging registry filesystem cache")
+ preserved_files = [ 'server.key', 'server.cert']
+ for (dir,_,files) in os.walk(Hierarchy().basedir):
+ for file in files:
+ if file in preserved_files: continue
+ path=dir+os.sep+file
+ os.unlink(path)
+
+
+class CertCommands(Commands):
+
+ def import_gid(self, xrn):
+ pass
+
+ @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn (mandatory)')
+ @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
+ @args('-o', '--outfile', dest='outfile', metavar='<outfile>', help='output file', default=None)
+ def export(self, xrn, type=None, outfile=None):
+ """Fetch an object's GID from the Registry"""
+ from sfa.storage.alchemy import dbsession
+ from sfa.storage.model import RegRecord
+ hrn = Xrn(xrn).get_hrn()
+ request=dbsession.query(RegRecord).filter_by(hrn=hrn)
+ if type: request = request.filter_by(type=type)
+ record=request.first()
+ if record:
+ gid = GID(string=record.gid)
+ else:
+ # check the authorities hierarchy
+ hierarchy = Hierarchy()
+ try:
+ auth_info = hierarchy.get_auth_info(hrn)
+ gid = auth_info.gid_object
+ except:
+ print "Record: %s not found" % hrn
+ sys.exit(1)
+ # save to file
+ if not outfile:
+ outfile = os.path.abspath('./%s.gid' % gid.get_hrn())
+ gid.save_to_file(outfile, save_parents=True)
+
+ @args('-g', '--gidfile', dest='gid', metavar='<gid>', help='path of gid file to display (mandatory)')
+ def display(self, gidfile):
+ """Print contents of a GID file"""
+ gid_path = os.path.abspath(gidfile)
+ if not gid_path or not os.path.isfile(gid_path):
+ print "No such gid file: %s" % gidfile
+ sys.exit(1)
+ gid = GID(filename=gid_path)
+ gid.dump(dump_parents=True)
+
+
+class AggregateCommands(Commands):
+
+ def __init__(self, *args, **kwds):
+ self.api= Generic.the_flavour().make_api(interface='aggregate')
+
+ def version(self):
+ """Display the Aggregate version"""
+ version = self.api.manager.GetVersion(self.api, {})
+ pprinter.pprint(version)
+
+ def slices(self):
+ """List the running slices at this Aggregate"""
+ print self.api.manager.ListSlices(self.api, [], {})
+
+ @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn (mandatory)')
+ def status(self, xrn):
+ """Display the status of a slice or slivers"""
+ urn = Xrn(xrn, 'slice').get_urn()
+ status = self.api.manager.SliverStatus(self.api, urn, [], {})
+ pprinter.pprint(status)
+
+ @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
+ @args('-r', '--rspec-version', dest='rspec_version', metavar='<rspec_version>',
+ default='GENI', help='version/format of the resulting rspec response')
+ def resources(self, xrn=None, rspec_version='GENI'):
+ """Display the available resources at an aggregate
+or the resources allocated by a slice"""
+ options = {'geni_rspec_version': rspec_version}
+ if xrn:
+ options['geni_slice_urn'] = Xrn(xrn, 'slice').get_urn()
+ print options
+ resources = self.api.manager.ListResources(self.api, [], options)
+ print resources
+
+ @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='slice hrn/urn (mandatory)')
+ @args('-r', '--rspec', dest='rspec', metavar='<rspec>', help='rspec file (mandatory)')
+ @args('-u', '--user', dest='user', metavar='<user>', help='hrn/urn of slice user (mandatory)')
+ @args('-k', '--key', dest='key', metavar='<key>', help="path to user's public key file (mandatory)")
+ def create(self, xrn, rspec, user, key):
+ """Allocate slivers"""
+ xrn = Xrn(xrn, 'slice')
+ slice_urn=xrn.get_urn()
+ rspec_string = open(rspec).read()
+ user_xrn = Xrn(user, 'user')
+ user_urn = user_xrn.get_urn()
+ user_key_string = open(key).read()
+ users = [{'urn': user_urn, 'keys': [user_key_string]}]
+ options={}
+ self.api.manager.CreateSliver(self, slice_urn, [], rspec_string, users, options)
+
+ @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='slice hrn/urn (mandatory)')
+ def delete(self, xrn):
+ """Delete slivers"""
+ self.api.manager.DeleteSliver(self.api, xrn, [], {})
+
+ @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='slice hrn/urn (mandatory)')
+ def start(self, xrn):
+ """Start slivers"""
+ self.api.manager.start_slice(self.api, xrn, [])
+
+ @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='slice hrn/urn (mandatory)')
+ def stop(self, xrn):
+ """Stop slivers"""
+ self.api.manager.stop_slice(self.api, xrn, [])
+
+ @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='slice hrn/urn (mandatory)')
+ def reset(self, xrn):
+ """Reset sliver"""
+ self.api.manager.reset_slice(self.api, xrn)
+
+
+# @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
+# @args('-r', '--rspec', dest='rspec', metavar='<rspec>', help='request rspec', default=None)
+# def ticket(self, xrn, rspec):
+# pass
+
+
+
+class SliceManagerCommands(AggregateCommands):
+
+ def __init__(self, *args, **kwds):
+ self.api= Generic.the_flavour().make_api(interface='slicemgr')
+
+
+class SfaAdmin:
+
+ CATEGORIES = {'certificate': CertCommands,
+ 'registry': RegistryCommands,
+ 'aggregate': AggregateCommands,
+ 'slicemgr': SliceManagerCommands}
+
+ def find_category (self, string):
+ for (k,v) in SfaAdmin.CATEGORIES.items():
+ if k.startswith(string): return k
+ for (k,v) in SfaAdmin.CATEGORIES.items():
+ if k.find(string) >=1: return k
+ return None
+
+ def summary_usage (self, category=None):
+ print "Usage:", self.script_name + " category action [<options>]"
+ if category and category in SfaAdmin.CATEGORIES:
+ categories=[category]
+ else:
+ categories=SfaAdmin.CATEGORIES
+ for c in categories:
+ cls=SfaAdmin.CATEGORIES[c]
+ print "==================== category=%s"%c
+ names=cls.__dict__.keys()
+ names.sort()
+ for name in names:
+ method=cls.__dict__[name]
+ if name.startswith('_'): continue
+ margin=15
+ format="%%-%ds"%margin
+ print "%-15s"%name,
+ doc=getattr(method,'__doc__',None)
+ if not doc:
+ print "<missing __doc__>"
+ continue
+ lines=[line.strip() for line in doc.split("\n")]
+ line1=lines.pop(0)
+ print line1
+ for extra_line in lines: print margin*" ",extra_line
+ sys.exit(2)
+
+ def main(self):
+ argv = copy.deepcopy(sys.argv)
+ self.script_name = argv.pop(0)
+ # ensure category is specified
+ if len(argv) < 1:
+ self.summary_usage()
+
+ # ensure category is valid
+ category_str = argv.pop(0)
+ category=self.find_category (category_str)
+ if not category:
+ self.summary_usage()
+
+ usage = "%%prog %s action [options]" % (category)
+ parser = OptionParser(usage=usage)
+ command_class = SfaAdmin.CATEGORIES.get(category, None)
+ if not command_class:
+ self.summary_usage(category)
+
+ # ensure command is valid
+ command_instance = command_class()
+ actions = command_instance._get_commands()
+ if len(argv) < 1:
+ action = '__call__'
+ else:
+ action = argv.pop(0)
+
+ if hasattr(command_instance, action):
+ command = getattr(command_instance, action)
+ else:
+ self.summary_usage(category)
+
+ # ensure options are valid
+ options = getattr(command, 'options', [])
+ usage = "%%prog %s %s [options]" % (category, action)
+ parser = OptionParser(usage=usage)
+ for arg, kwd in options:
+ parser.add_option(*arg, **kwd)
+ (opts, cmd_args) = parser.parse_args(argv)
+ cmd_kwds = vars(opts)
+
+ # dont overrride meth
+ for k, v in cmd_kwds.items():
+ if v is None:
+ del cmd_kwds[k]
+
+ # execute command
+ try:
+ #print "invoking %s *=%s **=%s"%(command.__name__,cmd_args, cmd_kwds)
+ command(*cmd_args, **cmd_kwds)
+ sys.exit(0)
+ except TypeError:
+ print "Possible wrong number of arguments supplied"
+ #import traceback
+ #traceback.print_exc()
+ print command.__doc__
+ parser.print_help()
+ #raise
+ except Exception:
+ print "Command failed, please check log for more info"
+ raise
("delegate", "name"),
("create_gid", "[name]"),
("get_trusted_certs", "cred"),
+ ("config", ""),
]
def print_command_help (self, options):
parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
help="output file format ([xml]|xmllist|hrnlist)", default="xml",
choices=("xml", "xmllist", "hrnlist"))
-
+ if command == 'list':
+ parser.add_option("-r", "--recursive", dest="recursive", action='store_true',
+ help="list all child records", default=False)
if command in ("delegate"):
parser.add_option("-u", "--user",
action="store_true", dest="delegate_user", default=False,
self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
errors += 1
+ self.config_file=config_file
if errors:
sys.exit(1)
+ def show_config (self):
+ print "From configuration file %s"%self.config_file
+ flags=[
+ ('SFI_USER','user'),
+ ('SFI_AUTH','authority'),
+ ('SFI_SM','sm_url'),
+ ('SFI_REGISTRY','reg_url'),
+ ]
+ for (external_name, internal_name) in flags:
+ print "%s='%s'"%(external_name,getattr(self,internal_name))
+
#
# Get various credential and spec files
#
# init self-signed cert, user credentials and gid
def bootstrap (self):
- bootstrap = SfaClientBootstrap (self.user, self.reg_url, self.options.sfi_dir)
+ client_bootstrap = SfaClientBootstrap (self.user, self.reg_url, self.options.sfi_dir)
# if -k is provided, use this to initialize private key
if self.options.user_private_key:
- bootstrap.init_private_key_if_missing (self.options.user_private_key)
+ client_bootstrap.init_private_key_if_missing (self.options.user_private_key)
else:
# trigger legacy compat code if needed
# the name has changed from just <leaf>.pkey to <hrn>.pkey
- if not os.path.isfile(bootstrap.private_key_filename()):
+ if not os.path.isfile(client_bootstrap.private_key_filename()):
self.logger.info ("private key not found, trying legacy name")
try:
legacy_private_key = os.path.join (self.options.sfi_dir, "%s.pkey"%get_leaf(self.user))
self.logger.debug("legacy_private_key=%s"%legacy_private_key)
- bootstrap.init_private_key_if_missing (legacy_private_key)
+ client_bootstrap.init_private_key_if_missing (legacy_private_key)
self.logger.info("Copied private key from legacy location %s"%legacy_private_key)
except:
self.logger.log_exc("Can't find private key ")
sys.exit(1)
# make it bootstrap
- bootstrap.bootstrap_my_gid()
+ client_bootstrap.bootstrap_my_gid()
# extract what's needed
- self.private_key = bootstrap.private_key()
- self.my_credential_string = bootstrap.my_credential_string ()
- self.my_gid = bootstrap.my_gid ()
- self.bootstrap = bootstrap
+ self.private_key = client_bootstrap.private_key()
+ self.my_credential_string = client_bootstrap.my_credential_string ()
+ self.my_gid = client_bootstrap.my_gid ()
+ self.client_bootstrap = client_bootstrap
def my_authority_credential_string(self):
if not self.authority:
self.logger.critical("no authority specified. Use -a or set SF_AUTH")
sys.exit(-1)
- return self.bootstrap.authority_credential_string (self.authority)
+ return self.client_bootstrap.authority_credential_string (self.authority)
def slice_credential_string(self, name):
- return self.bootstrap.slice_credential_string (name)
+ return self.client_bootstrap.slice_credential_string (name)
# xxx should be supported by sfaclientbootstrap as well
def delegate_cred(self, object_cred, hrn, type='authority'):
caller_gidfile = self.my_gid()
# the gid of the user who will be delegated to
- delegee_gid = self.bootstrap.gid(hrn,type)
+ delegee_gid = self.client_bootstrap.gid(hrn,type)
delegee_hrn = delegee_gid.get_hrn()
dcred = object_cred.delegate(delegee_gid, self.private_key, caller_gidfile)
return dcred.save_to_string(save_parents=True)
self.print_help()
sys.exit(1)
hrn = args[0]
+ opts = {}
+ if options.recursive:
+ opts['recursive'] = options.recursive
+
try:
- list = self.registry().List(hrn, self.my_credential_string)
+ list = self.registry().List(hrn, self.my_credential_string, options)
except IndexError:
raise Exception, "Not enough parameters for the 'list' command"
self.print_help()
sys.exit(1)
target_hrn = args[0]
- gid = self.registry().CreateGid(self.my_credential_string, target_hrn, self.bootstrap.my_gid_string())
+ gid = self.registry().CreateGid(self.my_credential_string, target_hrn, self.client_bootstrap.my_gid_string())
if options.file:
filename = options.file
else:
self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
return
+ def config (self, options, args):
+ "Display contents of current config"
+ self.show_config()
-#!/usr/bin/python
-import os
-import sys
-import copy
-from pprint import pformat
-from sfa.generic import Generic
-from optparse import OptionParser
-from pprint import PrettyPrinter
-from sfa.util.xrn import Xrn
-from sfa.storage.record import Record
-from sfa.client.sfi import save_records_to_file
-from sfa.trust.hierarchy import Hierarchy
-from sfa.trust.gid import GID
-
-pprinter = PrettyPrinter(indent=4)
-
-def optparse_listvalue_callback(option, opt, value, parser):
- setattr(parser.values, option.dest, value.split(','))
-
-def args(*args, **kwargs):
- def _decorator(func):
- func.__dict__.setdefault('options', []).insert(0, (args, kwargs))
- return func
- return _decorator
-
-class Commands(object):
- def _get_commands(self):
- available_methods = []
- for attrib in dir(self):
- if callable(getattr(self, attrib)) and not attrib.startswith('_'):
- available_methods.append(attrib)
- return available_methods
-
-
-class RegistryCommands(Commands):
- def __init__(self, *args, **kwds):
- self.api= Generic.the_flavour().make_api(interface='registry')
-
- def version(self):
- version = self.api.manager.GetVersion(self.api, {})
- pprinter.pprint(version)
-
- @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn')
- @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
- def list(self, xrn, type=None):
- xrn = Xrn(xrn, type)
- records = self.api.manager.List(self.api, xrn.get_hrn())
- for record in records:
- if not type or record['type'] == type:
- print "%s (%s)" % (record['hrn'], record['type'])
-
-
- @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn')
- @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
- @args('-o', '--outfile', dest='outfile', metavar='<outfile>', help='save record to file')
- @args('-f', '--format', dest='format', metavar='<display>', type='choice',
- choices=('text', 'xml', 'simple'), help='display record in different formats')
- def show(self, xrn, type=None, format=None, outfile=None):
- records = self.api.manager.Resolve(self.api, xrn, type, True)
- for record in records:
- sfa_record = Record(dict=record)
- sfa_record.dump(format)
- if outfile:
- save_records_to_file(outfile, records)
-
-
- def _record_dict(self, xrn=None, type=None, url=None, key=None, \
- description=None, slices='', researchers=''):
- record_dict = {}
- if xrn:
- if type:
- xrn = Xrn(xrn, type)
- else:
- xrn = Xrn(xrn)
- record_dict['urn'] = xrn.get_urn()
- record_dict['hrn'] = xrn.get_hrn()
- record_dict['type'] = xrn.get_type()
- if url:
- record_dict['url'] = url
- if key:
- try:
- pubkey = open(key, 'r').read()
- except IOError:
- pubkey = key
- record_dict['keys'] = [pubkey]
- if slices:
- record_dict['slices'] = slices
- if researchers:
- record_dict['researchers'] = researchers
- if description:
- record_dict['description'] = description
- return record_dict
-
- @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn')
- @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
- @args('-u', '--url', dest='url', metavar='<url>', help='URL', default=None)
- @args('-d', '--description', dest='description', metavar='<description>',
- help='Description', default=None)
- @args('-k', '--key', dest='key', metavar='<key>', help='public key string or file',
- default=None)
- @args('-s', '--slices', dest='slices', metavar='<slices>', help='slice xrns',
- default='', type="str", action='callback', callback=optparse_listvalue_callback)
- @args('-r', '--researchers', dest='researchers', metavar='<researchers>', help='slice researchers',
- default='', type="str", action='callback', callback=optparse_listvalue_callback)
- @args('-p', '--pis', dest='pis', metavar='<PIs>',
- help='Principal Investigators/Project Managers ',
- default='', type="str", action='callback', callback=optparse_listvalue_callback)
- def register(self, xrn, type=None, url=None, description=None, key=None, slices='',
- pis='', researchers=''):
- record_dict = self._record_dict(xrn=xrn, type=type, url=url, key=key,
- slices=slices, researchers=researchers)
- self.api.manager.Register(self.api, record_dict)
-
-
- @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn')
- @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
- @args('-u', '--url', dest='url', metavar='<url>', help='URL', default=None)
- @args('-d', '--description', dest='description', metavar='<description>',
- help='Description', default=None)
- @args('-k', '--key', dest='key', metavar='<key>', help='public key string or file',
- default=None)
- @args('-s', '--slices', dest='slices', metavar='<slices>', help='slice xrns',
- default='', type="str", action='callback', callback=optparse_listvalue_callback)
- @args('-r', '--researchers', dest='researchers', metavar='<researchers>', help='slice researchers',
- default='', type="str", action='callback', callback=optparse_listvalue_callback)
- @args('-p', '--pis', dest='pis', metavar='<PIs>',
- help='Principal Investigators/Project Managers ',
- default='', type="str", action='callback', callback=optparse_listvalue_callback)
- def update(self, xrn, type=None, url=None, description=None, key=None, slices='',
- pis='', researchers=''):
- record_dict = self._record_dict(xrn=xrn, type=type, url=url, description=description,
- key=key, slices=slices, researchers=researchers)
- self.api.manager.Update(self.api, record_dict)
-
- @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn')
- @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
- def remove(self, xrn, type=None):
- xrn = Xrn(xrn, type)
- self.api.manager.Remove(self.api, xrn)
-
-
- @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn')
- @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
- def credential(self, xrn, type=None):
- cred = self.api.manager.GetCredential(self.api, xrn, type, self.api.hrn)
- print cred
-
-
- def import_registry(self):
- from sfa.importer import Importer
- importer = Importer()
- importer.run()
-
- @args('-a', '--all', dest='all', metavar='<all>', action='store_true', default=False,
- help='Remove all registry records and all files in %s area' % Hierarchy().basedir)
- @args('-c', '--certs', dest='certs', metavar='<certs>', action='store_true', default=False,
- help='Remove all cached certs/gids found in %s' % Hierarchy().basedir )
- @args('-0', '--no-reinit', dest='reinit', metavar='<reinit>', action='store_false', default=True,
- help='Prevents new DB schema from being installed after cleanup')
- def nuke(self, all=False, certs=False, reinit=True):
- from sfa.storage.dbschema import DBSchema
- from sfa.util.sfalogging import _SfaLogger
- logger = _SfaLogger(logfile='/var/log/sfa_import.log', loggername='importlog')
- logger.setLevelFromOptVerbose(self.api.config.SFA_API_LOGLEVEL)
- logger.info("Purging SFA records from database")
- dbschema=DBSchema()
- dbschema.nuke()
-
- # for convenience we re-create the schema here, so there's no need for an explicit
- # service sfa restart
- # however in some (upgrade) scenarios this might be wrong
- if reinit:
- logger.info("re-creating empty schema")
- dbschema.init_or_upgrade()
-
- # remove the server certificate and all gids found in /var/lib/sfa/authorities
- if certs:
- logger.info("Purging cached certificates")
- for (dir, _, files) in os.walk('/var/lib/sfa/authorities'):
- for file in files:
- if file.endswith('.gid') or file == 'server.cert':
- path=dir+os.sep+file
- os.unlink(path)
-
- # just remove all files that do not match 'server.key' or 'server.cert'
- if all:
- logger.info("Purging registry filesystem cache")
- preserved_files = [ 'server.key', 'server.cert']
- for (dir,_,files) in os.walk(Hierarchy().basedir):
- for file in files:
- if file in preserved_files: continue
- path=dir+os.sep+file
- os.unlink(path)
-
-
-class CertCommands(Commands):
-
- def import_gid(self, xrn):
- pass
-
- @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn')
- @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
- @args('-o', '--outfile', dest='outfile', metavar='<outfile>', help='output file', default=None)
- def export(self, xrn, type=None, outfile=None):
- from sfa.storage.alchemy import dbsession
- from sfa.storage.model import RegRecord
- hrn = Xrn(xrn).get_hrn()
- request=dbsession.query(RegRecord).filter_by(hrn=hrn)
- if type: request = request.filter_by(type=type)
- record=request.first()
- if record:
- gid = GID(string=record.gid)
- else:
- # check the authorities hierarchy
- hierarchy = Hierarchy()
- try:
- auth_info = hierarchy.get_auth_info(hrn)
- gid = auth_info.gid_object
- except:
- print "Record: %s not found" % hrn
- sys.exit(1)
- # save to file
- if not outfile:
- outfile = os.path.abspath('./%s.gid' % gid.get_hrn())
- gid.save_to_file(outfile, save_parents=True)
-
- @args('-g', '--gidfile', dest='gid', metavar='<gid>', help='path of gid file to display')
- def display(self, gidfile):
- gid_path = os.path.abspath(gidfile)
- if not gid_path or not os.path.isfile(gid_path):
- print "No such gid file: %s" % gidfile
- sys.exit(1)
- gid = GID(filename=gid_path)
- gid.dump(dump_parents=True)
-
-
-class AggregateCommands(Commands):
-
- def __init__(self, *args, **kwds):
- self.api= Generic.the_flavour().make_api(interface='aggregate')
-
- def version(self):
- version = self.api.manager.GetVersion(self.api, {})
- pprinter.pprint(version)
-
- def slices(self):
- print self.api.manager.ListSlices(self.api, [], {})
-
- @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn')
- def status(self, xrn):
- urn = Xrn(xrn, 'slice').get_urn()
- status = self.api.manager.SliverStatus(self.api, urn, [], {})
- pprinter.pprint(status)
-
- @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
- @args('-r', '--rspec-version', dest='rspec_version', metavar='<rspec_version>',
- default='GENI', help='version/format of the resulting rspec response')
- def resources(self, xrn=None, rspec_version='GENI'):
- options = {'geni_rspec_version': rspec_version}
- if xrn:
- options['geni_slice_urn'] = xrn
- resources = self.api.manager.ListResources(self.api, [], options)
- print resources
-
- @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
- @args('-r', '--rspec', dest='rspec', metavar='<rspec>', help='rspec file')
- @args('-u', '--user', dest='user', metavar='<user>', help='hrn/urn of slice user')
- @args('-k', '--key', dest='key', metavar='<key>', help="path to user's public key file")
- def create(self, xrn, rspec, user, key):
- xrn = Xrn(xrn, 'slice')
- slice_urn=xrn.get_urn()
- rspec_string = open(rspec).read()
- user_xrn = Xrn(user, 'user')
- user_urn = user_xrn.get_urn()
- user_key_string = open(key).read()
- users = [{'urn': user_urn, 'keys': [user_key_string]}]
- options={}
- self.api.manager.CreateSliver(self, slice_urn, [], rspec_string, users, options)
-
- @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
- def delete(self, xrn):
- self.api.manager.DeleteSliver(self.api, xrn, [], {})
-
- @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
- def start(self, xrn):
- self.api.manager.start_slice(self.api, xrn, [])
-
- @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
- def stop(self, xrn):
- self.api.manager.stop_slice(self.api, xrn, [])
-
- @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
- def reset(self, xrn):
- self.api.manager.reset_slice(self.api, xrn)
-
-
- @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
- @args('-r', '--rspec', dest='rspec', metavar='<rspec>', help='request rspec', default=None)
- def ticket(self, xrn, rspec):
- pass
-
-
-
-class SliceManagerCommands(AggregateCommands):
-
- def __init__(self, *args, **kwds):
- self.api= Generic.the_flavour().make_api(interface='slicemgr')
-
-
-CATEGORIES = {'cert': CertCommands,
- 'registry': RegistryCommands,
- 'aggregate': AggregateCommands,
- 'slicemgr': SliceManagerCommands}
-
-def category_usage():
- print "Available categories:"
- for k in CATEGORIES:
- print "\t%s" % k
-
-def main():
- argv = copy.deepcopy(sys.argv)
- script_name = argv.pop(0)
- # ensure category is specified
- if len(argv) < 1:
- print script_name + " category action [<args>]"
- category_usage()
- sys.exit(2)
-
- # ensure category is valid
- category = argv.pop(0)
- usage = "%%prog %s action <args> [options]" % (category)
- parser = OptionParser(usage=usage)
- command_class = CATEGORIES.get(category, None)
- if not command_class:
- print "no such category %s " % category
- category_usage()
- sys.exit(2)
-
- # ensure command is valid
- command_instance = command_class()
- actions = command_instance._get_commands()
- if len(argv) < 1:
- action = '__call__'
- else:
- action = argv.pop(0)
-
- if hasattr(command_instance, action):
- command = getattr(command_instance, action)
- else:
- print script_name + " category action [<args>]"
- print "Available actions for %s category:" % category
- for k in actions:
- print "\t%s" % k
- sys.exit(2)
-
- # ensure options are valid
- options = getattr(command, 'options', [])
- usage = "%%prog %s %s <args> [options]" % (category, action)
- parser = OptionParser(usage=usage)
- for arg, kwd in options:
- parser.add_option(*arg, **kwd)
- (opts, cmd_args) = parser.parse_args(argv)
- cmd_kwds = vars(opts)
-
- # dont overrride meth
- for k, v in cmd_kwds.items():
- if v is None:
- del cmd_kwds[k]
-
- # execute commadn
- try:
- command(*cmd_args, **cmd_kwds)
- sys.exit(0)
- except TypeError:
- print "Possible wrong number of arguments supplied"
- print command.__doc__
- parser.print_help()
- #raise
- raise
- except Exception:
- print "Command failed, please check log for more info"
- raise
+#!/usr/bin/env python
+from sfa.client.sfaadmin import SfaAdmin
if __name__ == '__main__':
- main()
-
-
-
-
+ SfaAdmin().main()
#! /usr/bin/env python
import sys
+
from sfa.client.sfi_commands import Commands
+
from sfa.rspecs.rspec import RSpec
-from sfa.util.plxrn import xrn_to_hostname
+
+from sfa.planetlab.plxrn import xrn_to_hostname
command = Commands(usage="%prog [options]",
description="List all nodes in the RSpec. " +
import sys
from sfa.client.sfi_commands import Commands
+
from sfa.rspecs.rspec import RSpec
-from sfa.util.plxrn import xrn_to_hostname
+
+from sfa.planetlab.plxrn import xrn_to_hostname
command = Commands(usage="%prog [options]",
description="List all slivers in the RSpec. " +
from sfa.util.faults import SfaFault
# this is probably too big to swallow but for a starting point..
-from sfa.plc.pldriver import PlDriver
+from sfa.planetlab.pldriver import PlDriver
from sfa.federica.fdshell import FdShell
# driver class for server-side services, talk to the whole testbed
def driver_class (self):
- import sfa.plc.pldriver
- return sfa.plc.pldriver.PlDriver
+ import sfa.planetlab.pldriver
+ return sfa.planetlab.pldriver.PlDriver
# for the component mode, to be run on board planetlab nodes
# manager class
return sfa.managers.component_manager_pl
# driver_class
def component_driver_class (self):
- import sfa.plc.plcomponentdriver
- return sfa.plc.plcomponentdriver.PlComponentDriver
+ import sfa.planetlab.plcomponentdriver
+ return sfa.planetlab.plcomponentdriver.PlComponentDriver
--- /dev/null
+# This setting is designed for running a registry-only SFA instance
+
+from sfa.generic import Generic
+
+class void (Generic):
+
+ # the importer class
+ # when set to None, the importer only performs the basic stuff
+ # xxx this convention probably is confusing, since None suggests that
+ # *nothing* should be done..
+ # xxx need to refactor the importers anyway
+ def importer_class (self):
+ return None
+
+ # use the standard api class
+ def api_class (self):
+ import sfa.server.sfaapi
+ return sfa.server.sfaapi.SfaApi
+
+ # the manager classes for the server-side services
+ def registry_manager_class (self) :
+ import sfa.managers.registry_manager
+ return sfa.managers.registry_manager.RegistryManager
+ def slicemgr_manager_class (self) :
+ import sfa.managers.slice_manager
+ return sfa.managers.slice_manager.SliceManager
+ # most likely you'll want to turn OFF the aggregate in sfa-config-tty
+ # SFA_AGGREGATE_ENABLED=false
+ def aggregate_manager_class (self) :
+ import sfa.managers.aggregate_manager
+ return sfa.managers.aggregate_manager.AggregateManager
+
+ # driver class for server-side services, talk to the whole testbed
+ def driver_class (self):
+ import sfa.managers.driver
+ return sfa.managers.driver.Driver
+
import sys
from sfa.util.xrn import get_authority, hrn_to_urn
-from sfa.util.plxrn import email_to_hrn
from sfa.generic import Generic
from sfa.util.config import Config
from sfa.util.sfalogging import _SfaLogger
from sfa.trust.hierarchy import Hierarchy
-from sfa.trust.trustedroots import TrustedRoots
+#from sfa.trust.trustedroots import TrustedRoots
from sfa.trust.gid import create_uuid
from sfa.storage.alchemy import dbsession
from sfa.storage.model import RegRecord, RegAuthority, RegUser
class Importer:
- def __init__(self):
+
+ def __init__(self,auth_hierarchy=None,logger=None):
self.config = Config()
- self.logger = _SfaLogger(logfile='/var/log/sfa_import.log', loggername='importlog')
- self.logger.setLevelFromOptVerbose(self.config.SFA_API_LOGLEVEL)
- self.auth_hierarchy = Hierarchy ()
- self.TrustedRoots = TrustedRoots(self.config.get_trustedroots_dir())
+ if auth_hierarchy is not None:
+ self.auth_hierarchy=auth_hierarchy
+ else:
+ self.auth_hierarchy = Hierarchy ()
+ if logger is not None:
+ self.logger=logger
+ else:
+ self.logger = _SfaLogger(logfile='/var/log/sfa_import.log', loggername='importlog')
+ self.logger.setLevelFromOptVerbose(self.config.SFA_API_LOGLEVEL)
+# self.TrustedRoots = TrustedRoots(self.config.get_trustedroots_dir())
# check before creating a RegRecord entry as we run this over and over
def record_exists (self, type, hrn):
if testbed_importer:
testbed_importer.add_options(options)
testbed_importer.run (options)
-
-
from sfa.util.config import Config
from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn
-from sfa.util.plxrn import hostname_to_hrn, slicename_to_hrn, email_to_hrn, hrn_to_pl_slicename
+
from sfa.trust.gid import create_uuid
from sfa.trust.certificate import convert_public_key, Keypair
from sfa.storage.alchemy import dbsession
from sfa.storage.model import RegRecord, RegAuthority, RegUser, RegSlice, RegNode
+
+from sfa.planetlab.plxrn import hostname_to_hrn, slicename_to_hrn, email_to_hrn
from sfa.openstack.nova_shell import NovaShell
def load_keys(filename):
from sfa.util.config import Config
from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn
-from sfa.util.plxrn import hostname_to_hrn, slicename_to_hrn, email_to_hrn, hrn_to_pl_slicename
from sfa.trust.gid import create_uuid
from sfa.trust.certificate import convert_public_key, Keypair
from sfa.storage.alchemy import dbsession
from sfa.storage.model import RegRecord, RegAuthority, RegSlice, RegNode, RegUser, RegKey
-from sfa.plc.plshell import PlShell
+from sfa.planetlab.plshell import PlShell
+from sfa.planetlab.plxrn import hostname_to_hrn, slicename_to_hrn, email_to_hrn, hrn_to_pl_slicename
def _get_site_hrn(interface_hrn, site):
# Hardcode 'internet2' into the hrn for sites hosting
# sites_by_login_base = dict ( [ ( site['login_base'], site ) for site in sites ] )
# Get all plc users
persons = shell.GetPersons({'peer_id': None, 'enabled': True},
- ['person_id', 'email', 'key_ids', 'site_ids'])
+ ['person_id', 'email', 'key_ids', 'site_ids', 'role_ids'])
# create a hash of persons by person_id
persons_by_id = dict ( [ ( person['person_id'], person) for person in persons ] )
# Get all plc public keys
pass
node_record.stale=False
+ site_pis=[]
# import persons
for person_id in site['person_ids']:
try:
user_record.email = person['email']
dbsession.commit()
user_record.stale=False
+ # accumulate PIs - PLCAPI has a limitation that when someone has PI role
+ # this is valid for all sites she is in..
+ # PI is coded with role_id==20
+ if 20 in person['role_ids']:
+ site_pis.append (user_record)
except:
self.logger.log_exc("PlImporter: failed to import person %d %s"%(person['person_id'],person['email']))
+ # maintain the list of PIs for a given site
+ site_record.reg_pis = site_pis
+
# import slices
for slice_id in site['slice_ids']:
try:
xrn = Xrn(slice_xrn)
slice_urn=xrn.get_urn()
slice_hrn=xrn.get_hrn()
-
return self.driver.list_resources (slice_urn, slice_hrn, creds, options)
def SliverStatus (self, api, xrn, creds, options):
from sfa.util.faults import InvalidRSpec
from sfa.util.xrn import urn_to_hrn, Xrn
-from sfa.util.plxrn import hrn_to_pl_slicename, slicename_to_hrn
from sfa.util.callids import Callids
#comes with its own logging
#from sfa.util.sfalogging import logger
from sfa.util.version import version_core
+
from sfa.trust.credential import Credential
-from sfa.plc.plaggregate import PlAggregate
-# No Slice symbol in there
-#from sfa.plc.plslices import Slice, Slices
-from sfa.plc.plslices import PlSlices
+
from sfa.rspecs.version_manager import VersionManager
from sfa.rspecs.rspec import RSpec
-# not sure what this used to be nor where it is now defined
-#from sfa.rspecs.sfa_rspec import sfa_rspec_version
-# most likely this should now be
-#from sfa.rspecs.version_manager import VersionManager
+
+from sfa.planetlab.plaggregate import PlAggregate
+from sfa.planetlab.plslices import PlSlices
+from sfa.planetlab.plxrn import slicename_to_hrn
##
# Meta data of an instance.
from sfa.managers.aggregate_manager import AggregateManager
-from sfa.plc.plslices import PlSlices
+from sfa.planetlab.plslices import PlSlices
class AggregateManagerMax (AggregateManager):
import xmlrpclib
from sfa.util.faults import SliverDoesNotExist
-from sfa.util.plxrn import PlXrn
-from sfa.trust.sfaticket import SfaTicket
from sfa.util.version import version_core
+from sfa.trust.sfaticket import SfaTicket
+
+from sfa.planetlab.plxrn import PlXrn
+
def GetVersion(api, options):
return version_core({'interface':'component',
'testbed':'myplc'})
########## registry oriented
########################################
- # redefine this if you want to check again records
- # when running GetCredential
- # This is to reflect the 'enabled' user field in planetlab testbeds
- # expected retcod boolean
- def is_enabled (self, record) :
- return True
+ # NOTE: the is_enabled method is deprecated
+ # it was only making things confusing, as the (PL) import mechanism would
+ # ignore not enabled users anyway..
# the following is used in Resolve (registry) when run in full mode
# after looking up the sfa db, we wish to be able to display
def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
return True
+ # callack for register/update
+ # this allows to capture changes in the relations between objects
+ # the ids below are the ones found in the 'pointer' field
+ # this can get typically called with
+ # 'slice' 'user' 'researcher' slice_id user_ids
+ # 'authority' 'user' 'pi' authority_id user_ids
+ def update_relation (self, subject_type, target_type, relation_name, subject_id, link_ids):
+ pass
+
########################################
########## aggregate oriented
########################################
from sfa.util.sfatime import utcparse, datetime_to_epoch
from sfa.util.prefixTree import prefixTree
from sfa.util.xrn import Xrn, get_authority, hrn_to_urn, urn_to_hrn
-from sfa.util.plxrn import hrn_to_pl_login_base
from sfa.util.version import version_core
from sfa.util.sfalogging import logger
record=dbsession.query(RegRecord).filter_by(type=type,hrn=hrn).first()
if not record:
raise RecordNotFound("hrn=%s, type=%s"%(hrn,type))
-
- # verify_cancreate_credential requires that the member lists
- # (researchers, pis, etc) be filled in
- logger.debug("get credential before augment dict, keys=%s"%record.__dict__.keys())
- self.driver.augment_records_with_testbed_info (record.__dict__)
- logger.debug("get credential after augment dict, keys=%s"%record.__dict__.keys())
- if not self.driver.is_enabled (record.__dict__):
- raise AccountNotEnabled(": PlanetLab account %s is not enabled. Please contact your site PI" %(record.email))
+
+ # xxx for the record only
+ # used to call this, which was wrong, now all needed data is natively is our DB
+ # self.driver.augment_records_with_testbed_info (record.__dict__)
+ # likewise, we deprecate is_enabled which was not really useful
+ # if not self.driver.is_enabled (record.__dict__): ...
+ # xxx for the record only
# get the callers gid
# if caller_xrn is not specified assume the caller is the record
caller_gid = GID(string=caller_record.gid)
object_hrn = record.get_gid_object().get_hrn()
- rights = api.auth.determine_user_rights(caller_hrn, record.__dict__)
+ # call the builtin authorization/credential generation engine
+ rights = api.auth.determine_user_rights(caller_hrn, record)
# make sure caller has rights to this object
if rights.is_empty():
raise PermissionError("%s has no rights to %s (%s)" % \
return records
- def List (self, api, xrn, origin_hrn=None):
- hrn, type = urn_to_hrn(xrn)
+ def List (self, api, xrn, origin_hrn=None, options={}):
# load all know registry names into a prefix tree and attempt to find
# the longest matching prefix
+ hrn, type = urn_to_hrn(xrn)
registries = api.registries
registry_hrns = registries.keys()
tree = prefixTree()
credential = api.getCredential()
interface = api.registries[registry_hrn]
server_proxy = api.server_proxy(interface, credential)
- record_list = server_proxy.List(xrn, credential)
+ record_list = server_proxy.List(xrn, credential, options)
# same as above, no need to process what comes from through xmlrpc
# pass foreign records as-is
record_dicts = record_list
# if we still have not found the record yet, try the local registry
if not record_dicts:
+ recursive = False
+ if ('recursive' in options and options['recursive']):
+ recursive = True
+ elif hrn.endswith('*'):
+ hrn = hrn[:-1]
+ recursive = True
+
if not api.auth.hierarchy.auth_exists(hrn):
raise MissingAuthority(hrn)
- records = dbsession.query(RegRecord).filter_by(authority=hrn)
+ if recursive:
+ records = dbsession.query(RegRecord).filter(RegRecord.hrn.startswith(hrn))
+ else:
+ records = dbsession.query(RegRecord).filter_by(authority=hrn)
record_dicts=[ record.todict() for record in records ]
return record_dicts
# 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 relationship)
- def update_relations (self, subject_obj, ref_obj):
+ def update_driver_relations (self, subject_obj, ref_obj):
type=subject_obj.type
- if type=='slice':
- self.update_relation(subject_obj, 'researcher', ref_obj.researcher, 'user')
+ #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')
+ elif type=='authority' and hasattr(ref_obj,'pi'):
+ self.update_driver_relation(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_relation (self, record_obj, field_key, hrns, target_type):
+ def update_driver_relation (self, record_obj, hrns, target_type, relation_name):
# locate the linked objects in our db
subject_type=record_obj.type
subject_id=record_obj.pointer
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, subject_id, link_ids)
+ self.driver.update_relation (subject_type, target_type, relation_name, subject_id, link_ids)
def Register(self, api, record_dict):
gid = auth_info.get_gid_object()
record.gid=gid.save_to_string(save_parents=True)
- elif isinstance (record, RegSlice):
# locate objects for relationships
- if hasattr (record, 'researcher'):
- # we get the list of researcher hrns as
- researcher_hrns = record.researcher
- # strip that in case we have <researcher> words </researcher>
- researcher_hrns = [ x.strip() for x in researcher_hrns ]
- logger.info ("incoming researchers %s"%researcher_hrns)
- request = dbsession.query (RegUser).filter(RegUser.hrn.in_(researcher_hrns))
- logger.info ("%d incoming hrns, %d matches found"%(len(researcher_hrns),request.count()))
- researchers = dbsession.query (RegUser).filter(RegUser.hrn.in_(researcher_hrns)).all()
- record.reg_researchers = researchers
+ pi_hrns = getattr(record,'pi',None)
+ if pi_hrns is not None: record.update_pis (pi_hrns)
+
+ elif isinstance (record, RegSlice):
+ researcher_hrns = getattr(record,'researcher',None)
+ if researcher_hrns is not None: record.update_researchers (researcher_hrns)
elif isinstance (record, RegUser):
# create RegKey objects for incoming keys
dbsession.commit()
# update membership for researchers, pis, owners, operators
- self.update_relations (record, record)
+ self.update_driver_relations (record, record)
return record.get_gid_object().save_to_string(save_parents=True)
def Update(self, api, record_dict):
assert ('type' in record_dict)
- new_record=RegRecord(dict=record_dict)
- type = new_record.type
- hrn = new_record.hrn
+ new_record=make_record(dict=record_dict)
+ (type,hrn) = (new_record.type, new_record.hrn)
# make sure the record exists
record = dbsession.query(RegRecord).filter_by(type=type,hrn=hrn).first()
raise RecordNotFound("hrn=%s, type=%s"%(hrn,type))
record.just_updated()
- # validate the type
- if type not in ['authority', 'slice', 'node', 'user']:
- raise UnknownSfaType(type)
-
# Use the pointer from the existing record, not the one that the user
# gave us. This prevents the user from inserting a forged pointer
pointer = record.pointer
- # is the a change in keys ?
+ # is there a change in keys ?
new_key=None
if type=='user':
if getattr(new_key,'keys',None):
if isinstance (new_key,types.ListType):
new_key=new_key[0]
- # update the PLC information that was specified with the record
- if not self.driver.update (record.__dict__, new_record.__dict__, hrn, new_key):
- logger.warning("driver.update failed")
-
# take new_key into account
if new_key:
# update the openssl key and gid
record.gid = gid
dsession.commit()
+ # xxx should do side effects from new_record to record
+ # not too sure how to do that
+ # not too big a deal with planetlab as the driver is authoritative, but...
+
+ # 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)
+ dbsession.commit()
+
+ elif isinstance (record, RegAuthority):
+ pi_hrns = getattr(new_record,'pi',None)
+ if pi_hrns is not None: record.update_pis (pi_hrns)
+ dbsession.commit()
+
+ # update the PLC information that was specified with the record
+ # xxx oddly enough, without this statement, record.__dict__ as received by
+ # the driver seems to be off
+ # anyway the driver should receive an object
+ # (and then extract __dict__ itself if needed)
+ print "before driver.update, record=%s"%record
+ if not self.driver.update (record.__dict__, new_record.__dict__, hrn, new_key):
+ logger.warning("driver.update failed")
+
# update membership for researchers, pis, owners, operators
- self.update_relations (record, new_record)
+ self.update_driver_relations (record, new_record)
return 1
from sfa.util.sfatime import utcparse, datetime_to_epoch
from sfa.util.prefixTree import prefixTree
from sfa.util.xrn import Xrn, get_authority, hrn_to_urn, urn_to_hrn
-from sfa.util.plxrn import hrn_to_pl_login_base
from sfa.util.version import version_core
from sfa.util.sfalogging import logger
caller_gid = GID(string=caller_record.gid)
object_hrn = record.get_gid_object().get_hrn()
- rights = api.auth.determine_user_rights(caller_hrn, record.__dict__)
+ rights = api.auth.determine_user_rights(caller_hrn, record)
# make sure caller has rights to this object
if rights.is_empty():
raise PermissionError(caller_hrn + " has no rights to " + record.hrn)
# xxx used to be [SfaRecord]
returns = [Parameter(dict, "registry record")]
- def call(self, xrn, creds):
+ def call(self, xrn, creds, options={}):
hrn, type = urn_to_hrn(xrn)
valid_creds = self.api.auth.checkCredentials(creds, 'list')
origin_hrn = Credential(string=valid_creds[0]).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))
- return self.api.manager.List(self.api, xrn)
+ return self.api.manager.List(self.api, xrn, options=options)
from nova.exception import ImageNotFound
from sfa.rspecs.elements.disk_image import DiskImage
+
class Image:
+
+ def __init__(self, image={}):
+ self.id = None
+ self.container_format = None
+ self.kernel_id = None
+ self.ramdisk_id = None
+ self.properties = None
+ self.name = None
+ self.description = None
+ self.os = None
+ self.version = None
+
+ if image:
+ self.parse_image(image)
+
+ def parse_image(self, image):
+ if isinstance(image, dict):
+ self.id = image['id']
+ self.name = image['name']
+ self.container_format = image['container_format']
+ self.properties = image['properties']
+ if 'kernel_id' in self.properties:
+ self.kernel_id = self.properties['kernel_id']
+ if 'ramdisk_id' in self.properties:
+ self.ramdisk_id = self.properties['ramdisk_id']
+
+ def to_rspec_object(self):
+ img = DiskImage()
+ img['name'] = self.name
+ img['description'] = self.name
+ img['os'] = self.name
+ img['version'] = self.name
+ return img
+
+class ImageManager:
def __init__(self, driver):
self.driver = driver
@staticmethod
def disk_image_to_rspec_object(image):
- img = DiskImage()
- img['name'] = image['ami']['name']
- img['description'] = image['ami']['name']
- img['os'] = image['ami']['name']
- img['version'] = image['ami']['name']
- return img
+ img = Image(image)
+ return img.to_rspec_object()
def get_available_disk_images(self):
# get image records
disk_images = []
- for image in self.driver.shell.image_manager.detail():
- if image['container_format'] == 'ami':
- disk_images.append(self.get_machine_image_details(image))
+ for img in self.driver.shell.image_manager.detail():
+ image = Image(img)
+ if image.container_format in ['ami', 'ovf']:
+ disk_images.append(image)
return disk_images
- def get_machine_image_details(self, image):
- """
- Returns a dict that contains the ami, aki and ari details for the specified
- ami image.
- """
- disk_image = {}
- if image['container_format'] == 'ami':
- kernel_id = image['properties']['kernel_id']
- ramdisk_id = image['properties']['ramdisk_id']
- disk_image['ami'] = image
- disk_image['aki'] = self.driver.shell.image_manager.show(kernel_id)
- disk_image['ari'] = self.driver.shell.image_manager.show(ramdisk_id)
- return disk_image
-
def get_disk_image(self, id=None, name=None):
"""
Look up a image bundle using the specifeid id or name
image = self.driver.shell.image_manager.show(id)
elif name:
image = self.driver.shell.image_manager.show_by_name(name)
- if image['container_format'] == 'ami':
- disk_image = self.get_machine_image_details(image)
+ if image['container_format'] in ['ami', 'ovf']:
+ disk_image = Image(image)
except ImageNotFound:
pass
return disk_image
from sfa.openstack.nova_shell import NovaShell
from sfa.openstack.euca_shell import EucaShell
from sfa.openstack.osaggregate import OSAggregate
-from sfa.plc.plslices import PlSlices
+from sfa.planetlab.plslices import PlSlices
from sfa.util.osxrn import OSXrn
from sfa.util.xrn import Xrn
from sfa.util.osxrn import OSXrn
from sfa.rspecs.version_manager import VersionManager
-from sfa.openstack.image import Image
+from sfa.openstack.image import ImageManager
from sfa.openstack.security_group import SecurityGroup
from sfa.util.sfalogging import logger
'type': type,
'tags': []})
return sliver
-
+
+
+def ec2_id(id=None, type=None):
+ ec2_id = None
+ if type == 'ovf':
+ type = 'ami'
+ if id and type:
+ ec2_id = CloudController.image_ec2_id(id, type)
+ return ec2_id
+
class OSAggregate:
return rspec.toxml()
def get_slice_nodes(self, slice_xrn):
- image_manager = Image(self.driver)
+ image_manager = ImageManager(self.driver)
name = OSXrn(xrn = slice_xrn).name
instances = self.driver.shell.db.instance_get_all_by_project(name)
rspec_nodes = []
rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
sliver = instance_to_sliver(instance)
disk_image = image_manager.get_disk_image(instance.image_ref)
- sliver['disk_images'] = [Image.disk_image_to_rspec_object(disk_image)]
+ sliver['disk_images'] = [disk_image.to_rspec_object()]
rspec_node['slivers'] = [sliver]
rspec_nodes.append(rspec_node)
return rspec_nodes
# available sliver/instance/vm types
instances = self.driver.shell.db.instance_type_get_all().values()
# available images
- image_manager = Image(self.driver)
+ image_manager = ImageManager(self.driver)
disk_images = image_manager.get_available_disk_images()
- disk_image_objects = [Image.disk_image_to_rspec_object(image) \
+ disk_image_objects = [image.to_rspec_object() \
for image in disk_images]
rspec_nodes = []
for zone in zones:
Create the slice if it doesn't alredy exist. Create user
accounts that don't already exist
"""
- from nova.exception import ProjectNotFound
- try:
- slice = self.driver.shell.auth_manager.get_project(slicename)
- except ProjectNotFound:
- # assume that the first user is the project manager
- proj_manager = Xrn(users[0]['urn']).get_leaf()
- self.driver.shell.auth_manager.create_project(slicename, proj_manager)
-
+ from nova.exception import ProjectNotFound, UserNotFound
for user in users:
username = Xrn(user['urn']).get_leaf()
try:
self.driver.shell.auth_manager.get_user(username)
except nova.exception.UserNotFound:
self.driver.shell.auth_manager.create_user(username)
- self.verify_user_keys(username, user['keys'], options)
+ self.verify_user_keys(username, user['keys'], options)
+
+ try:
+ slice = self.driver.shell.auth_manager.get_project(slicename)
+ except ProjectNotFound:
+ # assume that the first user is the project manager
+ proj_manager = Xrn(users[0]['urn']).get_leaf()
+ self.driver.shell.auth_manager.create_project(slicename, proj_manager)
def verify_user_keys(self, username, keys, options={}):
"""
except Exception, err:
logger.log_exc(err)
+
def run_instances(self, slicename, rspec, keyname, pubkeys):
"""
# the default image to use for instnaces that dont
# explicitly request an image.
# Just choose the first available image for now.
- image_manager = Image(self.driver)
+ image_manager = ImageManager(self.driver)
available_images = image_manager.get_available_disk_images()
- default_image = available_images[0]
- default_ami_id = CloudController.image_ec2_id(default_image['ami']['id'], 'ami')
- default_aki_id = CloudController.image_ec2_id(default_image['aki']['id'], 'aki')
- default_ari_id = CloudController.image_ec2_id(default_image['ari']['id'], 'ari')
+ default_image_id = None
+ default_aki_id = None
+ default_ari_id = None
+ default_image = available_images[0]
+ default_image_id = ec2_id(default_image.id, default_image.container_format)
+ default_aki_id = ec2_id(default_image.kernel_id, 'aki')
+ default_ari_id = ec2_id(default_image.ramdisk_id, 'ari')
# get requested slivers
rspec = RSpec(rspec)
for i in xrange(6)])
group_name = slicename + random_name
self.create_security_group(group_name, fw_rules)
- ami_id = default_ami_id
+ ami_id = default_image_id
aki_id = default_aki_id
ari_id = default_ari_id
req_image = instance_type.get('disk_images')
req_image_name = req_image[0]['name']
disk_image = image_manager.get_disk_image(name=req_image_name)
if disk_image:
- ami_id = CloudController.image_ec2_id(disk_image['ami']['id'], 'ami')
- aki_id = CloudController.image_ec2_id(disk_image['aki']['id'], 'aki')
- ari_id = CloudController.image_ec2_id(disk_image['ari']['id'], 'ari')
+ ami_id = ec2_id(disk_image.id, disk_image.container_format)
+ aki_id = ec2_id(disk_image.kernel_id, 'aki')
+ ari_id = ec2_id(disk_image.ramdisk_id, 'ari')
# start the instance
self.reserve_instance(image_id=ami_id,
kernel_id=aki_id,
from sfa.rspecs.elements.pltag import PLTag
from sfa.rspecs.version_manager import VersionManager
-from sfa.util.plxrn import PlXrn, hostname_to_urn, hrn_to_pl_slicename
-from sfa.plc.vlink import get_tc_rate
-from sfa.plc.topology import Topology
+from sfa.planetlab.plxrn import PlXrn, hostname_to_urn, hrn_to_pl_slicename
+from sfa.planetlab.vlink import get_tc_rate
+from sfa.planetlab.topology import Topology
class PlAggregate:
import tempfile
from sfa.client.sfaserverproxy import SfaServerProxy
-from sfa.plc.nodemanager import NodeManager
+from sfa.planetlab.nodemanager import NodeManager
from sfa.trust.credential import Credential
from sfa.trust.certificate import Certificate, Keypair
# the driver interface, mostly provides default behaviours
from sfa.managers.driver import Driver
-from sfa.plc.plshell import PlShell
-import sfa.plc.peers as peers
-from sfa.plc.plaggregate import PlAggregate
-from sfa.plc.plslices import PlSlices
-from sfa.util.plxrn import slicename_to_hrn, hostname_to_hrn, hrn_to_pl_slicename, hrn_to_pl_login_base
+from sfa.planetlab.plshell import PlShell
+import sfa.planetlab.peers as peers
+from sfa.planetlab.plaggregate import PlAggregate
+from sfa.planetlab.plslices import PlSlices
+from sfa.planetlab.plxrn import PlXrn, slicename_to_hrn, hostname_to_hrn, hrn_to_pl_slicename
def list_to_dict(recs, key):
########## registry oriented
########################################
- ########## disabled users
- def is_enabled (self, record):
- # the incoming record was augmented already, so 'enabled' should be set
- if record['type'] == 'user':
- return record['enabled']
- # only users can be disabled
- return True
-
def augment_records_with_testbed_info (self, sfa_records):
return self.fill_record_info (sfa_records)
if type == 'authority':
sites = self.shell.GetSites([pl_record['login_base']])
if not sites:
+ # xxx when a site gets registered through SFA we need to set its max_slices
+ if 'max_slices' not in pl_record:
+ pl_record['max_slices']=2
pointer = self.shell.AddSite(pl_record)
else:
pointer = sites[0]['site_id']
pointer = slices[0]['slice_id']
elif type == 'user':
- persons = self.shell.GetPersons([sfa_record['email']])
+ persons = self.shell.GetPersons({'email':sfa_record['email']})
if not persons:
+ for key in ['first_name','last_name']:
+ if key not in sfa_record: sfa_record[key]='*from*sfa*'
pointer = self.shell.AddPerson(dict(sfa_record))
else:
pointer = persons[0]['person_id']
self.shell.AddPersonKey(pointer, {'key_type' : 'ssh', 'key' : pub_key})
elif type == 'node':
- login_base = hrn_to_pl_login_base(sfa_record['authority'])
+ login_base = PlXrn(xrn=sfa_record['authority'],type='node').pl_login_base()
nodes = self.shell.GetNodes([pl_record['hostname']])
if not nodes:
pointer = self.shell.AddNode(login_base, pl_record)
pl_record["model"] = "geni"
elif type == "authority":
- pl_record["login_base"] = hrn_to_pl_login_base(hrn)
+ pl_record["login_base"] = PlXrn(xrn=hrn,type='authority').pl_login_base()
if "name" not in sfa_record:
pl_record["name"] = hrn
if "abbreviated_name" not in sfa_record:
####################
# plcapi works by changes, compute what needs to be added/deleted
- def update_relation (self, subject_type, target_type, subject_id, target_ids):
+ def update_relation (self, subject_type, target_type, relation_name, subject_id, target_ids):
# hard-wire the code for slice/user for now, could be smarter if needed
- if subject_type =='slice' and target_type == 'user':
+ if subject_type =='slice' and target_type == 'user' and relation_name == 'researcher':
subject=self.shell.GetSlices (subject_id)[0]
current_target_ids = subject['person_ids']
add_target_ids = list ( set (target_ids).difference(current_target_ids))
for target_id in del_target_ids:
logger.debug ("del_target_id = %s (type=%s)"%(target_id,type(target_id)))
self.shell.DeletePersonFromSlice (target_id, subject_id)
+ elif subject_type == 'authority' and target_type == 'user' and relation_name == 'pi':
+ # due to the plcapi limitations this means essentially adding pi role to all people in the list
+ # it's tricky to remove any pi role here, although it might be desirable
+ persons = self.shell.GetPersons (target_ids)
+ for person in persons:
+ if 'pi' not in person['roles']:
+ self.shell.AddRoleToPerson('pi',person['person_id'])
else:
- logger.info('unexpected relation to maintain, %s -> %s'%(subject_type,target_type))
+ logger.info('unexpected relation %s to maintain, %s -> %s'%(relation_name,subject_type,target_type))
########################################
from sfa.util.sfatime import utcparse, datetime_to_epoch
from sfa.util.sfalogging import logger
from sfa.util.xrn import Xrn, get_leaf, get_authority, urn_to_hrn
-#from sfa.util.policy import Policy
-from sfa.util.plxrn import PlXrn
+
from sfa.rspecs.rspec import RSpec
-from sfa.plc.vlink import VLink
-from sfa.util.plxrn import hrn_to_pl_slicename
+
+from sfa.planetlab.vlink import VLink
+from sfa.planetlab.plxrn import PlXrn, hrn_to_pl_slicename
MAXINT = 2L**31-1
return PlXrn(auth=auth_hrn, email=email).get_hrn()
def hrn_to_pl_slicename (hrn):
return PlXrn(xrn=hrn,type='slice').pl_slicename()
-def hrn_to_pl_login_base (hrn):
- return PlXrn(xrn=hrn,type='slice').pl_login_base()
+# removed-dangerous - was used for non-slice objects
+#def hrn_to_pl_login_base (hrn):
+# return PlXrn(xrn=hrn,type='slice').pl_login_base()
def hrn_to_pl_authname (hrn):
return PlXrn(xrn=hrn,type='any').pl_authname()
def xrn_to_hostname(hrn):
self._normalize()
return self.leaf
- #def hrn_to_pl_login_base(hrn):
def pl_login_base (self):
self._normalize()
base = self.authority[-1]
-from sfa.util.plxrn import PlXrn
from sfa.util.xrn import Xrn
from sfa.rspecs.elements.element import Element
from sfa.rspecs.elements.link import Link
-from sfa.util.plxrn import PlXrn, xrn_to_hostname
from sfa.util.xrn import Xrn
from sfa.util.xml import XpathFilter
+
from sfa.rspecs.elements.node import Node
from sfa.rspecs.elements.sliver import Sliver
from sfa.rspecs.elements.location import Location
from sfa.rspecs.elements.versions.pgv2Services import PGv2Services
from sfa.rspecs.elements.versions.pgv2SliverType import PGv2SliverType
+from sfa.planetlab.plxrn import xrn_to_hostname
+
class PGv2Node:
@staticmethod
def add_nodes(xml, nodes):
from sfa.util.sfalogging import logger
from sfa.util.xml import XpathFilter
-from sfa.util.plxrn import PlXrn, xrn_to_hostname
from sfa.util.xrn import Xrn
+
from sfa.rspecs.elements.element import Element
from sfa.rspecs.elements.node import Node
from sfa.rspecs.elements.sliver import Sliver
from sfa.rspecs.elements.versions.sfav1PLTag import SFAv1PLTag
from sfa.rspecs.elements.versions.pgv2Services import PGv2Services
+from sfa.planetlab.plxrn import xrn_to_hostname
+
class SFAv1Node:
@staticmethod
from sfa.util.xrn import Xrn
-from sfa.util.plxrn import PlXrn
from sfa.util.xml import XmlElement
+
from sfa.rspecs.elements.element import Element
from sfa.rspecs.elements.sliver import Sliver
from sfa.rspecs.elements.versions.sfav1PLTag import SFAv1PLTag
+from sfa.planetlab.plxrn import PlXrn
+
class SFAv1Sliver:
@staticmethod
from copy import deepcopy
from StringIO import StringIO
from sfa.util.xrn import Xrn, urn_to_sliver_id
-from sfa.util.plxrn import hostname_to_urn, xrn_to_hostname
from sfa.rspecs.version import RSpecVersion
from sfa.rspecs.elements.versions.pgv2Link import PGv2Link
from sfa.rspecs.elements.versions.pgv2Node import PGv2Node
from sfa.util.sfalogging import logger
from sfa.util.xrn import hrn_to_urn, urn_to_hrn
-from sfa.util.plxrn import PlXrn
from sfa.rspecs.version import RSpecVersion
from sfa.rspecs.elements.element import Element
from sfa.rspecs.elements.versions.pgv2Link import PGv2Link
from mod_python import apache
from sfa.util.sfalogging import logger
-from sfa.plc.server import SfaApi
+from sfa.planetlab.server import SfaApi
api = SfaApi(interface='aggregate')
from mod_python import apache
from sfa.util.sfalogging import logger
-from sfa.plc.server import SfaApi
+from sfa.planetlab.server import SfaApi
api = SfaApi(interface='registry')
from mod_python import apache
from sfa.util.sfalogging import logger
-from sfa.plc.server import SfaApi
+from sfa.planetlab.server import SfaApi
api = SfaApi(interface='slicemgr')
from sfa.util.faults import ConnectionKeyGIDMismatch
from sfa.util.config import Config
-from sfa.client.sfaserverproxy import SfaServerProxy
-from sfa.util.plxrn import hrn_to_pl_slicename, slicename_to_hrn
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
+from sfa.client.sfaserverproxy import SfaServerProxy
+
+from sfa.planetlab.plxrn import hrn_to_pl_slicename, slicename_to_hrn
+
KEYDIR = "/var/lib/sfa/"
CONFDIR = "/etc/sfa/"
--- /dev/null
+# this move is about adding a authority x user many to many relation ship for modelling PIs
+# that is to say users who can vouch for other users in the authority, and can create slices
+
+from sqlalchemy import Table, MetaData, Column, ForeignKey
+from sqlalchemy import Integer, String
+
+metadata=MetaData()
+
+# this is needed my migrate so it can locate 'records.record_id'
+records = \
+ Table ( 'records', metadata,
+ Column ('record_id', Integer, primary_key=True),
+ )
+
+# authority x user (PIs) association
+authority_pi_table = \
+ Table ( 'authority_pi', metadata,
+ Column ('authority_id', Integer, ForeignKey ('records.record_id'), primary_key=True),
+ Column ('pi_id', Integer, ForeignKey ('records.record_id'), primary_key=True),
+ )
+
+def upgrade(migrate_engine):
+ metadata.bind = migrate_engine
+ authority_pi_table.create()
+
+def downgrade(migrate_engine):
+ metadata.bind = migrate_engine
+ authority_pi_table.drop()
result += ">"
return result
+ # shortcut - former implem. was record-based
+ def get (self, field, default):
+ return getattr(self,field,default)
+
@validates ('gid')
def validate_gid (self, key, gid):
if gid is None: return
now=datetime.now()
self.last_updated=now
+#################### cross-relations tables
+# authority x user (pis) association
+authority_pi_table = \
+ Table ( 'authority_pi', Base.metadata,
+ Column ('authority_id', Integer, ForeignKey ('records.record_id'), primary_key=True),
+ Column ('pi_id', Integer, ForeignKey ('records.record_id'), primary_key=True),
+ )
+# slice x user (researchers) association
+slice_researcher_table = \
+ Table ( 'slice_researcher', Base.metadata,
+ Column ('slice_id', Integer, ForeignKey ('records.record_id'), primary_key=True),
+ Column ('researcher_id', Integer, ForeignKey ('records.record_id'), primary_key=True),
+ )
+
##############################
# all subclasses define a convenience constructor with a default value for type,
# and when applicable a way to define local fields in a kwd=value argument
__tablename__ = 'authorities'
__mapper_args__ = { 'polymorphic_identity' : 'authority' }
record_id = Column (Integer, ForeignKey ("records.record_id"), primary_key=True)
+ #### extensions come here
+ reg_pis = relationship \
+ ('RegUser',
+ secondary=authority_pi_table,
+ primaryjoin=RegRecord.record_id==authority_pi_table.c.authority_id,
+ secondaryjoin=RegRecord.record_id==authority_pi_table.c.pi_id,
+ backref='reg_authorities_as_pi')
def __init__ (self, **kwds):
# fill in type if not previously set
def __repr__ (self):
return RegRecord.__repr__(self).replace("Record","Authority")
-####################
-# slice x user (researchers) association
-slice_researcher_table = \
- Table ( 'slice_researcher', Base.metadata,
- Column ('slice_id', Integer, ForeignKey ('records.record_id'), primary_key=True),
- Column ('researcher_id', Integer, ForeignKey ('records.record_id'), primary_key=True),
- )
+ def update_pis (self, pi_hrns):
+ # don't ruin the import of that file in a client world
+ from sfa.storage.alchemy import dbsession
+ # strip that in case we have <researcher> words </researcher>
+ pi_hrns = [ x.strip() for x in pi_hrns ]
+ request = dbsession.query (RegUser).filter(RegUser.hrn.in_(pi_hrns))
+ logger.info ("RegAuthority.update_pis: %d incoming pis, %d matches found"%(len(pi_hrns),request.count()))
+ pis = dbsession.query (RegUser).filter(RegUser.hrn.in_(pi_hrns)).all()
+ self.reg_pis = pis
####################
class RegSlice (RegRecord):
secondary=slice_researcher_table,
primaryjoin=RegRecord.record_id==slice_researcher_table.c.slice_id,
secondaryjoin=RegRecord.record_id==slice_researcher_table.c.researcher_id,
- backref="reg_slices_as_researcher")
+ backref='reg_slices_as_researcher')
def __init__ (self, **kwds):
if 'type' not in kwds: kwds['type']='slice'
def __repr__ (self):
return RegRecord.__repr__(self).replace("Record","Slice")
+ def update_researchers (self, researcher_hrns):
+ # don't ruin the import of that file in a client world
+ from sfa.storage.alchemy import dbsession
+ # strip that in case we have <researcher> words </researcher>
+ researcher_hrns = [ x.strip() for x in researcher_hrns ]
+ request = dbsession.query (RegUser).filter(RegUser.hrn.in_(researcher_hrns))
+ logger.info ("RegSlice.update_researchers: %d incoming researchers, %d matches found"%(len(researcher_hrns),request.count()))
+ researchers = dbsession.query (RegUser).filter(RegUser.hrn.in_(researcher_hrns)).all()
+ self.reg_researchers = researchers
+
+ # when dealing with credentials, we need to retrieve the PIs attached to a slice
+ def get_pis (self):
+ # don't ruin the import of that file in a client world
+ from sfa.storage.alchemy import dbsession
+ from sfa.util.xrn import get_authority
+ authority_hrn = get_authority(self.hrn)
+ auth_record = dbsession.query(RegAuthority).filter_by(hrn=authority_hrn).first()
+ return auth_record.reg_pis
+
+
####################
class RegNode (RegRecord):
__tablename__ = 'nodes'
raise PermissionError(name)
- def determine_user_rights(self, caller_hrn, record):
+ def determine_user_rights(self, caller_hrn, reg_record):
"""
Given a user credential and a record, determine what set of rights the
user should have to that record.
- This is intended to replace determine_rights() and
+ This is intended to replace determine_user_rights() and
verify_cancreate_credential()
"""
rl = Rights()
- type = record['type']
-
-
- if type=="slice":
- researchers = record.get("researcher", [])
- pis = record.get("PI", [])
- if (caller_hrn in researchers + pis):
- rl.add("refresh")
- rl.add("embed")
- rl.add("bind")
- rl.add("control")
- rl.add("info")
-
- elif type == "authority":
- pis = record.get("PI", [])
- operators = record.get("operator", [])
+ type = reg_record.type
+
+ logger.debug("entering determine_user_rights with record %s and caller_hrn %s"%(reg_record, caller_hrn))
+
+ if type == 'slice':
+ # researchers in the slice are in the DB as-is
+ researcher_hrns = [ user.hrn for user in reg_record.reg_researchers ]
+ # locating PIs attached to that slice
+ slice_pis=reg_record.get_pis()
+ pi_hrns = [ user.hrn for user in slice_pis ]
+ if (caller_hrn in researcher_hrns + pi_hrns):
+ rl.add('refresh')
+ rl.add('embed')
+ rl.add('bind')
+ rl.add('control')
+ rl.add('info')
+
+ elif type == 'authority':
+ pi_hrns = [ user.hrn for user in reg_record.reg_pis ]
if (caller_hrn == self.config.SFA_INTERFACE_HRN):
- rl.add("authority")
- rl.add("sa")
- rl.add("ma")
- if (caller_hrn in pis):
- rl.add("authority")
- rl.add("sa")
- if (caller_hrn in operators):
- rl.add("authority")
- rl.add("ma")
-
- elif type == "user":
- rl.add("refresh")
- rl.add("resolve")
- rl.add("info")
-
- elif type == "node":
- rl.add("operator")
+ rl.add('authority')
+ rl.add('sa')
+ rl.add('ma')
+ if (caller_hrn in pi_hrns):
+ rl.add('authority')
+ rl.add('sa')
+ # NOTE: for the PL implementation, this 'operators' list
+ # amounted to users with 'tech' role in that site
+ # it seems like this is not needed any longer, so for now I just drop that
+ # operator_hrns = reg_record.get('operator',[])
+ # if (caller_hrn in operator_hrns):
+ # rl.add('authority')
+ # rl.add('ma')
+
+ elif type == 'user':
+ rl.add('refresh')
+ rl.add('resolve')
+ rl.add('info')
+
+ elif type == 'node':
+ rl.add('operator')
return rl
- def verify_cancreate_credential(self, src_cred, record):
- """
- Verify that a user can retrive a particular type of credential.
- For slices, the user must be on the researcher list. For SA and
- MA the user must be on the pi and operator lists respectively
- """
-
- type = record.get_type()
- cred_object_hrn = src_cred.get_gid_object().get_hrn()
- if cred_object_hrn in [self.config.SFA_REGISTRY_ROOT_AUTH]:
- return
- if type=="slice":
- researchers = record.get("researcher", [])
- if not (cred_object_hrn in researchers):
- raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name())
- elif type == "sa":
- pis = record.get("pi", [])
- if not (cred_object_hrn in pis):
- raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name())
- elif type == "ma":
- operators = record.get("operator", [])
- if not (cred_object_hrn in operators):
- raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name())
-
def get_authority(self, hrn):
return get_authority(hrn)
self.kind = kind
self.delegate = delegate
+ def __repr__ (self): return "<Rgt:%s>"%self.kind
+
##
# Test to see if this right object is allowed to perform an operation.
# Returns True if the operation is allowed, False otherwise.
if string:
self.load_from_string(string)
+ def __repr__ (self): return "[" + " ".join( ["%s"%r for r in self.rights]) + "]"
+
def is_empty(self):
return self.rights == []
from sfa.util.faults import *
from sfa.util.xrn import Xrn
-from sfa.util.plxrn import PlXrn
+
+from sfa.planetlab.plxrn import PlXrn
verbose=False