Merge branch 'upstreammaster'
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Wed, 23 May 2012 08:22:54 +0000 (10:22 +0200)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Wed, 23 May 2012 08:22:54 +0000 (10:22 +0200)
51 files changed:
Makefile
setup.py
sfa.spec
sfa/client/sfaadmin.py [new file with mode: 0755]
sfa/client/sfi.py
sfa/clientbin/sfaadmin.py
sfa/clientbin/sfiListNodes.py
sfa/clientbin/sfiListSlivers.py
sfa/federica/fddriver.py
sfa/generic/pl.py
sfa/generic/void.py [new file with mode: 0644]
sfa/importer/__init__.py
sfa/importer/openstackimporter.py
sfa/importer/plimporter.py
sfa/managers/aggregate_manager.py
sfa/managers/aggregate_manager_eucalyptus.py
sfa/managers/aggregate_manager_max.py
sfa/managers/component_manager_pl.py
sfa/managers/driver.py
sfa/managers/registry_manager.py
sfa/managers/registry_manager_openstack.py
sfa/methods/List.py
sfa/openstack/image.py
sfa/openstack/nova_driver.py
sfa/openstack/osaggregate.py
sfa/planetlab/__init__.py [moved from sfa/plc/__init__.py with 100% similarity]
sfa/planetlab/nodemanager.py [moved from sfa/plc/nodemanager.py with 100% similarity]
sfa/planetlab/peers.py [moved from sfa/plc/peers.py with 100% similarity]
sfa/planetlab/plaggregate.py [moved from sfa/plc/plaggregate.py with 98% similarity]
sfa/planetlab/plcomponentdriver.py [moved from sfa/plc/plcomponentdriver.py with 98% similarity]
sfa/planetlab/pldriver.py [moved from sfa/plc/pldriver.py with 95% similarity]
sfa/planetlab/plshell.py [moved from sfa/plc/plshell.py with 100% similarity]
sfa/planetlab/plslices.py [moved from sfa/plc/plslices.py with 99% similarity]
sfa/planetlab/plxrn.py [moved from sfa/util/plxrn.py with 95% similarity]
sfa/planetlab/topology.py [moved from sfa/plc/topology.py with 100% similarity]
sfa/planetlab/vlink.py [moved from sfa/plc/vlink.py with 100% similarity]
sfa/rspecs/elements/versions/pgv2Link.py
sfa/rspecs/elements/versions/pgv2Node.py
sfa/rspecs/elements/versions/sfav1Node.py
sfa/rspecs/elements/versions/sfav1Sliver.py
sfa/rspecs/versions/pgv2.py
sfa/rspecs/versions/sfav1.py
sfa/server/modpython/SfaAggregateModPython.py
sfa/server/modpython/SfaRegistryModPython.py
sfa/server/modpython/SfaSliceMgrModPython.py
sfa/server/sfa_component_setup.py
sfa/storage/migrations/versions/002_authority_pis.py [new file with mode: 0644]
sfa/storage/model.py
sfa/trust/auth.py
sfa/trust/rights.py
tests/testXrn.py

index 75d79f1..8446d4a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -38,7 +38,7 @@ python-install:
        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
@@ -162,7 +162,7 @@ syncconfig:
 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/
index 5512d99..858802b 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -32,7 +32,7 @@ packages = [
     'sfa/generic',
     'sfa/managers',
     'sfa/importer',
-    'sfa/plc',
+    'sfa/planetlab',
     'sfa/rspecs',
     'sfa/rspecs/elements',
     'sfa/rspecs/elements/versions',
index 331f9f5..4d77b2c 100644 (file)
--- a/sfa.spec
+++ b/sfa.spec
@@ -1,6 +1,6 @@
 %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)" )
@@ -149,6 +149,7 @@ rm -rf $RPM_BUILD_ROOT
 /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
@@ -226,6 +227,26 @@ fi
 [ "$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. 
diff --git a/sfa/client/sfaadmin.py b/sfa/client/sfaadmin.py
new file mode 100755 (executable)
index 0000000..1e1d675
--- /dev/null
@@ -0,0 +1,445 @@
+#!/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
index 1dd8161..ced960e 100644 (file)
@@ -219,6 +219,7 @@ class Sfi:
         ("delegate", "name"),
         ("create_gid", "[name]"),
         ("get_trusted_certs", "cred"),
+        ("config", ""),
         ]
 
     def print_command_help (self, options):
@@ -300,7 +301,9 @@ class Sfi:
            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,
@@ -455,9 +458,21 @@ class Sfi:
            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
     #
@@ -473,41 +488,41 @@ class Sfi:
     
     # 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'):
@@ -525,7 +540,7 @@ class Sfi:
         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)
@@ -690,8 +705,12 @@ or version information about sfi itself
             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"
 
@@ -1178,7 +1197,7 @@ or with an slice hrn, shows currently provisioned resources
             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:
@@ -1225,3 +1244,6 @@ or with an slice hrn, shows currently provisioned resources
             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()
index 6ce8373..ce6930b 100755 (executable)
@@ -1,390 +1,6 @@
-#!/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()
index 3de1657..17cb341 100755 (executable)
@@ -1,9 +1,12 @@
 #! /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. " + 
index c869f61..c9611d0 100755 (executable)
@@ -2,8 +2,10 @@
 
 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. " + 
index 1e16d7f..3b94756 100644 (file)
@@ -2,7 +2,7 @@ from sfa.util.sfalogging import logger
 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
 
index c8b1bc6..457a09b 100644 (file)
@@ -25,8 +25,8 @@ class pl (Generic):
 
     # 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
@@ -35,6 +35,6 @@ class pl (Generic):
         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
 
diff --git a/sfa/generic/void.py b/sfa/generic/void.py
new file mode 100644 (file)
index 0000000..6c496f4
--- /dev/null
@@ -0,0 +1,37 @@
+# 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
+
index 9fc4e2b..bc6c7f2 100644 (file)
@@ -3,12 +3,11 @@
 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
@@ -16,12 +15,19 @@ from sfa.trust.certificate import convert_public_key, Keypair
 
 
 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):
@@ -112,5 +118,3 @@ class Importer:
             if testbed_importer:
                 testbed_importer.add_options(options)
                 testbed_importer.run (options)
-
-            
index 2331fa7..b12ef03 100644 (file)
@@ -2,11 +2,13 @@ import os
 
 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):
index 8367318..ab37ac9 100644 (file)
@@ -20,7 +20,6 @@ import os
 
 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
@@ -28,7 +27,8 @@ 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
@@ -147,7 +147,7 @@ class PlImporter:
 #        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
@@ -243,6 +243,7 @@ class PlImporter:
                     pass
                 node_record.stale=False
 
+            site_pis=[]
             # import persons
             for person_id in site['person_ids']:
                 try:
@@ -318,9 +319,17 @@ class PlImporter:
                     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:
index ab3e6a8..3651b15 100644 (file)
@@ -42,7 +42,6 @@ class AggregateManager:
             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):
index 552f544..228361d 100644 (file)
@@ -17,22 +17,19 @@ from sqlobject import *
 
 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.
index 0300522..64fd0ec 100644 (file)
@@ -14,7 +14,7 @@ from sfa.util.xrn import urn_to_hrn, hrn_to_urn, Xrn
 
 from sfa.managers.aggregate_manager import AggregateManager
 
-from sfa.plc.plslices import PlSlices
+from sfa.planetlab.plslices import PlSlices
 
 class AggregateManagerMax (AggregateManager):
 
index 9630479..8518839 100644 (file)
@@ -1,10 +1,12 @@
 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'})
index f48964f..d6a81be 100644 (file)
@@ -13,12 +13,9 @@ class Driver:
     ########## 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
@@ -60,6 +57,15 @@ class Driver:
     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
     ########################################
index 518072b..03a9043 100644 (file)
@@ -9,7 +9,6 @@ from sfa.util.faults import RecordNotFound, AccountNotEnabled, PermissionError,
 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
 
@@ -53,14 +52,13 @@ class RegistryManager:
         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
@@ -79,7 +77,8 @@ class RegistryManager:
             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)" % \
@@ -185,10 +184,10 @@ class RegistryManager:
     
         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()
@@ -205,16 +204,26 @@ class RegistryManager:
             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
@@ -240,15 +249,18 @@ class RegistryManager:
     # subject_record describes the subject of the relationships
     # ref_record contains the target values for the various relationships we need to manage
     # (to begin with, this is just the slice x person 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
@@ -256,7 +268,7 @@ class RegistryManager:
         link_id_tuples = dbsession.query(RegRecord.pointer).filter_by(type=target_type).filter(RegRecord.hrn.in_(hrns)).all()
         # sqlalchemy returns named tuples for columns
         link_ids = [ tuple.pointer for tuple in link_id_tuples ]
-        self.driver.update_relation (subject_type, target_type, subject_id, link_ids)
+        self.driver.update_relation (subject_type, target_type, relation_name, subject_id, link_ids)
 
     def Register(self, api, record_dict):
     
@@ -302,18 +314,13 @@ class RegistryManager:
             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
@@ -329,15 +336,14 @@ class RegistryManager:
         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()
@@ -345,15 +351,11 @@ class RegistryManager:
             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):
@@ -361,10 +363,6 @@ class RegistryManager:
                 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
@@ -376,8 +374,32 @@ class RegistryManager:
             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 
     
index c940e15..cc3ff10 100644 (file)
@@ -9,7 +9,6 @@ from sfa.util.faults import RecordNotFound, AccountNotEnabled, PermissionError,
 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
 
@@ -68,7 +67,7 @@ class RegistryManager(RegistryManager):
             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)
index c023fa0..d53a0a5 100644 (file)
@@ -25,7 +25,7 @@ class List(Method):
     # 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')
 
@@ -33,4 +33,4 @@ class List(Method):
         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
index 85a64c4..2449e42 100644 (file)
@@ -1,42 +1,61 @@
 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
@@ -47,8 +66,8 @@ class Image:
                 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
index 7dee979..e4b95b0 100644 (file)
@@ -22,7 +22,7 @@ from sfa.managers.driver import Driver
 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
 
 
index d2aff6a..3de5627 100644 (file)
@@ -16,7 +16,7 @@ from sfa.rspecs.elements.services import Services
 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
 
@@ -49,7 +49,16 @@ def instance_to_sliver(instance, slice_xrn=None):
                      '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:
 
@@ -70,7 +79,7 @@ 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 = []
@@ -82,7 +91,7 @@ class OSAggregate:
             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
@@ -98,9 +107,9 @@ class OSAggregate:
         # 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:
@@ -129,21 +138,21 @@ class OSAggregate:
         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={}):
         """
@@ -209,6 +218,7 @@ class OSAggregate:
                                               
         except Exception, err:
             logger.log_exc(err)
+    
                
     def run_instances(self, slicename, rspec, keyname, pubkeys):
         """
@@ -217,12 +227,15 @@ class OSAggregate:
         # 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)
@@ -242,7 +255,7 @@ class OSAggregate:
                                            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')
@@ -250,9 +263,9 @@ class OSAggregate:
                         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, 
similarity index 100%
rename from sfa/plc/peers.py
rename to sfa/planetlab/peers.py
similarity index 98%
rename from sfa/plc/plaggregate.py
rename to sfa/planetlab/plaggregate.py
index 04fdca4..ccf6852 100644 (file)
@@ -15,9 +15,9 @@ from sfa.rspecs.elements.services import Services
 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:
similarity index 98%
rename from sfa/plc/plcomponentdriver.py
rename to sfa/planetlab/plcomponentdriver.py
index 991cdde..25f9b7a 100644 (file)
@@ -2,7 +2,7 @@ import os
 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
similarity index 95%
rename from sfa/plc/pldriver.py
rename to sfa/planetlab/pldriver.py
index 8cf21d9..76f54da 100644 (file)
@@ -23,11 +23,11 @@ from sfa.rspecs.rspec import RSpec
 # 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):
@@ -60,14 +60,6 @@ class PlDriver (Driver):
     ########## 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)
 
@@ -79,6 +71,9 @@ class PlDriver (Driver):
         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']
@@ -95,8 +90,10 @@ class PlDriver (Driver):
                  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']
@@ -124,7 +121,7 @@ class PlDriver (Driver):
                 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)
@@ -250,7 +247,7 @@ class PlDriver (Driver):
                 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:
@@ -531,9 +528,9 @@ class PlDriver (Driver):
 
     ####################
     # 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))
@@ -545,8 +542,15 @@ class PlDriver (Driver):
             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))
 
         
     ########################################
similarity index 100%
rename from sfa/plc/plshell.py
rename to sfa/planetlab/plshell.py
similarity index 99%
rename from sfa/plc/plslices.py
rename to sfa/planetlab/plslices.py
index 9413e81..f7c8848 100644 (file)
@@ -4,11 +4,11 @@ from collections import defaultdict
 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
 
similarity index 95%
rename from sfa/util/plxrn.py
rename to sfa/planetlab/plxrn.py
index 17d0c15..6d57dcc 100644 (file)
@@ -13,8 +13,9 @@ def email_to_hrn (auth_hrn, email):
     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):
@@ -73,7 +74,6 @@ class PlXrn (Xrn):
         self._normalize()
         return self.leaf
 
-    #def hrn_to_pl_login_base(hrn):
     def pl_login_base (self):
         self._normalize()
         base = self.authority[-1]
similarity index 100%
rename from sfa/plc/vlink.py
rename to sfa/planetlab/vlink.py
index 5e0a828..1c0d3ce 100644 (file)
@@ -1,4 +1,3 @@
-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
index cae644d..9892d8c 100644 (file)
@@ -1,6 +1,6 @@
-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
@@ -12,6 +12,8 @@ from sfa.rspecs.elements.pltag import PLTag
 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):
index f50e687..d8db263 100644 (file)
@@ -1,7 +1,7 @@
 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
@@ -15,6 +15,8 @@ from sfa.rspecs.elements.versions.sfav1Sliver import SFAv1Sliver
 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
index f037533..94cecd1 100644 (file)
@@ -1,10 +1,12 @@
 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
index 3565d4e..9ac4d37 100644 (file)
@@ -1,7 +1,6 @@
 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
index 6400489..964da05 100644 (file)
@@ -3,7 +3,6 @@ from lxml import etree
 
 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
index 8c97d19..50f9f5f 100755 (executable)
@@ -12,7 +12,7 @@ import traceback
 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')
 
index 6ea2710..31d0812 100755 (executable)
@@ -12,7 +12,7 @@ import traceback
 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')
 
index 7d0e5f2..61cb161 100755 (executable)
@@ -12,7 +12,7 @@ import traceback
 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')
 
index 589a572..f75f1ca 100755 (executable)
@@ -6,14 +6,16 @@ from optparse import OptionParser
 
 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/"
 
diff --git a/sfa/storage/migrations/versions/002_authority_pis.py b/sfa/storage/migrations/versions/002_authority_pis.py
new file mode 100644 (file)
index 0000000..e234a2f
--- /dev/null
@@ -0,0 +1,28 @@
+# 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()
index 780853c..c187dcc 100644 (file)
@@ -114,6 +114,10 @@ class RegRecord (Base,AlchemyObj):
         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
@@ -144,6 +148,20 @@ class RegRecord (Base,AlchemyObj):
         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
@@ -152,6 +170,13 @@ class RegAuthority (RegRecord):
     __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
@@ -163,13 +188,15 @@ class RegAuthority (RegRecord):
     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):
@@ -182,7 +209,7 @@ 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'
@@ -191,6 +218,26 @@ class RegSlice (RegRecord):
     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'
index f6269b3..0c03279 100644 (file)
@@ -234,77 +234,60 @@ class Auth:
     
         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)
 
index eb0bb74..1b8baa4 100644 (file)
@@ -94,6 +94,8 @@ class Right:
         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.
@@ -148,6 +150,8 @@ class Rights:
         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 == []
 
index 709ce6b..f681205 100755 (executable)
@@ -4,7 +4,8 @@ import unittest
 
 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