Merge branch 'master' into sqlalchemy
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Sun, 19 Feb 2012 08:29:59 +0000 (09:29 +0100)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Sun, 19 Feb 2012 08:29:59 +0000 (09:29 +0100)
Conflicts:
config/default_config.xml
sfa.spec

Removed:
sfa/server/sfa-clean-peer-records.py
sfa/storage/record.py

1  2 
config/default_config.xml
setup.py
sfa.spec
sfa/managers/registry_manager.py
sfa/openstack/nova_driver.py

@@@ -223,32 -223,6 +223,32 @@@ Thierry Parmentela
        </variablelist>
      </category>
  
 +    <!-- ======================================== -->
 +    <category id="sfa_flashpolicy">
 +      <name>SFA Flash Policy</name>
 +      <description>The settings that affect the flash policy server that will run
 +      as part of this SFA instance.</description>
 +
 +      <variablelist>
 +        <variable id="enabled" type="boolean">
 +          <name>Enable Flash Policy Server</name>
 +          <value>false</value>
 +          <description>Allows this local SFA instance to run a
 +          flash policy server.</description>
 +        </variable>
 +        <variable id="config_file" type="string">
 +          <name>Flash policy config file</name>
 +          <value>/etc/sfa/sfa_flashpolicy_config.xml</value>
 +          <description>The path to where the flash policy config file can be reached.</description>
 +        </variable>
 +        <variable id="port" type="int">
 +          <name>Flash policy port</name>
 +          <value>843</value>
 +          <description>The flash policy server port.</description>
 +        </variable>
 +      </variablelist>
 +    </category>
 +
      <!-- ======================================== -->
      <category id="sfa_plc">
        <name></name>
        </variablelist>
      </category>
  
 -
      <!-- ======================================== -->
 -    <category id="sfa_flashpolicy">
 -      <name>SFA Flash Policy</name>
 -      <description>The settings that affect the flash policy server that will run
 -      as part of this SFA instance.</description>
 +    <category id="sfa_federica">
 +      <name></name>
 +      <description>The settings that tell this SFA instance how to interact with the FEDERICA testbed.</description>
  
        <variablelist>
 -        <variable id="enabled" type="boolean">
 -          <name>Enable Flash Policy Server</name>
 -          <value>false</value>
 -          <description>Allows this local SFA instance to run a
 -          flash policy server.</description>
 -        </variable>
 -        <variable id="config_file" type="string">
 -          <name>Flash policy config file</name>
 -          <value>/etc/sfa/sfa_flashpolicy_config.xml</value>
 -          <description>The path to where the flash policy config file can be reached.</description>
 -        </variable>
 -        <variable id="port" type="int">
 -          <name>Flash policy port</name>
 -          <value>843</value>
 -          <description>The flash policy server port.</description>
 -        </variable>
 +      <variable id="user" type="string">
 +        <name>FEDERICA login name for an admin user; SFA will carry on operations under this account.</name>
 +        <value>root</value>
 +        <description></description>
 +      </variable>
 +
 +      <variable id="password" type="string">
 +        <name>Password</name>
 +        <value>rootpassword</value>
 +        <description>The PLC password for SFA_PLC_USER.</description>
 +      </variable>
 +
 +      <variable id="hostname" type="string">
 +        <name>XMLRPC hostname</name>
 +        <value>federica.net</value>
 +        <description>Hostname for the federica xmlrpc interface.</description>
 +      </variable>
 +
 +      <variable id="port" type="string">
 +        <name>XMLRPC port number</name>
 +        <value>10000</value>
 +        <description>Port number for the federica xmlrpc interface.</description>
 +      </variable>
 +
        </variablelist>
      </category>
  
--
+     <!-- ======================================== -->
+     <category id="sfa_nova">
+       <name>SFA Flash Policy</name>
+       <description>The settings that affect how SFA connects to 
+                    the Nova/EC2 API</description>
+       <variablelist>
+         <variable id="user" type="string">
+           <name>Sfa nova user</name>
+           <value>novaadmin</value>
+           <description>Account/context to use when performing 
+                        administrative nova operations</description>
+         </variable>
+         <variable id="api_url" type="string">
+           <name>Nova API url</name>
+           <value>127.0.0.1</value>
+           <description>The Nova/EC2 API url </description>
+         </variable>
+         <variable id="api_port" type="int">
+           <name>Nova API Port</name>
+           <value>8773</value>
+           <description>The Nova/EC2 API port.</description>
+         </variable>
+       </variablelist>
+     </category>
  
    </variables>
  
diff --combined setup.py
+++ b/setup.py
@@@ -13,11 -13,10 +13,10 @@@ scripts = glob("sfa/clientbin/*.py") + 
      [ 
      'config/sfa-config-tty',
      'config/gen-sfa-cm-config.py',
 -    'sfa/importer/sfa-import-plc.py', 
 -    'sfa/importer/sfa-nuke-plc.py', 
 +    'sfa/importer/sfa-import.py', 
 +    'sfa/importer/sfa-nuke.py', 
      'sfa/server/sfa-ca.py', 
      'sfa/server/sfa-start.py', 
-     'sfa/server/sfa-clean-peer-records.py', 
      'sfa/server/sfa_component_setup.py', 
      'sfatables/sfatables',
      'keyconvert/keyconvert.py',
@@@ -64,8 -63,7 +63,8 @@@ data_files = [ ('/etc/sfa/', [ 'config/
                 ('/etc/sfatables/matches/', glob('sfatables/matches/*.xml')),
                 ('/etc/sfatables/targets/', glob('sfatables/targets/*.xml')),
                 ('/etc/init.d/', [ "init.d/%s"%x for x in initscripts ]),
 -               ('/usr/share/sfa/', [ 'sfa/storage/sfa.sql' ] ),
 +               ('/usr/share/sfa/migrations', glob('sfa/storage/migrations/*.*') ),
 +               ('/usr/share/sfa/migrations/versions', glob('sfa/storage/migrations/versions/*') ),
                 ('/usr/share/sfa/examples/', glob('sfa/examples/*' ) + [ 'cron.d/sfa.cron' ] ),
                ]
  
diff --combined sfa.spec
+++ b/sfa.spec
@@@ -1,6 -1,6 +1,6 @@@
  %define name sfa
 -%define version 2.0
 -%define taglevel 10
 +%define version 2.1
 +%define taglevel 2
  
  %define release %{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}}
  %global python_sitearch       %( python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)" )
@@@ -24,10 -24,7 +24,10 @@@ URL: %{SCMURL
  Summary: the SFA python libraries
  Group: Applications/System
  BuildRequires: make
 +
 +Requires: myplc-config
  Requires: python >= 2.5
 +Requires: pyOpenSSL >= 0.7
  Requires: m2crypto
  Requires: xmlsec1-openssl-devel
  Requires: libxslt-python
@@@ -43,10 -40,8 +43,10 @@@ Requires: python-dateuti
  Requires: postgresql >= 8.2, postgresql-server >= 8.2
  Requires: postgresql-python
  Requires: python-psycopg2
 -Requires: pyOpenSSL >= 0.7
 -Requires: myplc-config
 +# f8=0.4 - f12=0.5 f14=0.6 f16=0.7
 +Requires: python-sqlalchemy
 +Requires: python-migrate
 +# the eucalyptus aggregate uses this module
  Requires: python-xmlbuilder
   
  # python 2.5 has uuid module added, for python 2.4 we still need it.
@@@ -153,7 -148,7 +153,7 @@@ rm -rf $RPM_BUILD_ROO
  %config /etc/sfa/default_config.xml
  %config (noreplace) /etc/sfa/aggregates.xml
  %config (noreplace) /etc/sfa/registries.xml
 -/usr/share/sfa/sfa.sql
 +/usr/share/sfa/migrations
  /usr/share/sfa/examples
  /var/www/html/wsdl/*.wsdl
  
  /etc/sfa/xml.xsd
  /etc/sfa/protogeni-rspec-common.xsd
  /etc/sfa/topology
 -%{_bindir}/sfa-import-plc.py*
 -%{_bindir}/sfa-nuke-plc.py*
 +%{_bindir}/sfa-import.py*
 +%{_bindir}/sfa-nuke.py*
- %{_bindir}/sfa-clean-peer-records.py*
  %{_bindir}/gen-sfa-cm-config.py*
  %{_bindir}/sfa-ca.py*
  
  %files tests
  %{_datadir}/sfa/tests
  
 -### sfa-plc installs the 'sfa' service
 -%post plc
 +### sfa installs the 'sfa' service
 +%post 
  chkconfig --add sfa
  
 -%preun plc
 +%preun 
  if [ "$1" = 0 ] ; then
    /sbin/service sfa stop || :
    /sbin/chkconfig --del sfa || :
  fi
  
 -%postun plc
 -[ "$1" -ge "1" ] && service sfa restart
 +%postun
 +[ "$1" -ge "1" ] && { service sfa dbdump ; service sfa restart ; }
  
  ### sfa-cm installs the 'sfa-cm' service
  %post cm
  [ "$1" -ge "1" ] && service sfa-cm restart || :
  
  %changelog
 +* Wed Feb 08 2012 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - sfa-2.1-2
 +- registry database has user's keys and mail (known as v0 for migrate)
 +- pl importer properly maintains user's keys and mail
 +- pl driver now to handle 'role' when adding person record (exp.)
 +- first draft of federica driver with config section
 +- SFA_GENERIC_FLAVOUR in usual variables for sfa-config-tty
 +- plus, from master as of tag merged-in-sfa-2.1-2:
 +- disk_image revisited
 +- new nova_shell nova_driver & various tweaks for openstack
 +
 +* Fri Jan 27 2012 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - sfa-2.1-1
 +- uses sqlalchemy and related migrate
 +- thorough migration and upgrade scheme
 +- sfa-import.py and sfa-nuke.py (no more -plc), uses FLAVOUR
 +- trashed dbinfo stuff in auth hierarchy
 +- data model still has little more than plain records
 +- checkpoint tag, not yet intended for release
 +
  * Wed Jan 25 2012 Tony Mack <tmack@cs.princeton.edu> - sfa-2.0-10
  - client: added -R --raw sfi cmdline option that displays raw server response.
  - client: request GENI RSpec by default. 
@@@ -1,4 -1,5 +1,4 @@@
  import types
 -import time 
  # for get_key_from_incoming_ip
  import tempfile
  import os
@@@ -18,8 -19,8 +18,8 @@@ from sfa.trust.credential import Creden
  from sfa.trust.certificate import Certificate, Keypair, convert_public_key
  from sfa.trust.gid import create_uuid
  
 -from sfa.storage.record import SfaRecord
 -from sfa.storage.table import SfaTable
 +from sfa.storage.model import make_record, RegRecord, RegAuthority, RegUser, RegSlice, RegKey
 +from sfa.storage.alchemy import dbsession
  
  class RegistryManager:
  
          auth_hrn = api.auth.get_authority(hrn)
          if not auth_hrn or hrn == api.config.SFA_INTERFACE_HRN:
              auth_hrn = hrn
 -        # get record info
          auth_info = api.auth.get_auth_info(auth_hrn)
 -        table = SfaTable()
 -        records = table.findObjects({'type': type, 'hrn': hrn})
 -        if not records:
 -            raise RecordNotFound(hrn)
 -        record = records[0]
 +        # get record info
 +        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
 -        self.driver.augment_records_with_testbed_info (record)
 -        if not self.driver.is_enabled (record):
 -              raise AccountNotEnabled(": PlanetLab account %s is not enabled. Please contact your site PI" %(record['email']))
 +        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))
      
          # get the callers gid
          # if this is a self cred the record's gid is the caller's gid
              caller_hrn = caller_gid.get_hrn()
          
          object_hrn = record.get_gid_object().get_hrn()
 -        rights = api.auth.determine_user_rights(caller_hrn, record)
 +        rights = api.auth.determine_user_rights(caller_hrn, record.__dict__)
          # make sure caller has rights to this object
          if rights.is_empty():
              raise PermissionError("%s has no rights to %s (%s)" % \
                                    (caller_hrn, object_hrn, xrn))    
 -        object_gid = GID(string=record['gid'])
 +        object_gid = GID(string=record.gid)
          new_cred = Credential(subject = object_gid.get_subject())
          new_cred.set_gid_caller(caller_gid)
          new_cred.set_gid_object(object_gid)
@@@ -85,8 -86,8 +85,8 @@@
          #new_cred.set_pubkey(object_gid.get_pubkey())
          new_cred.set_privileges(rights)
          new_cred.get_privileges().delegate_all_privileges(True)
 -        if 'expires' in record:
 -            date = utcparse(record['expires'])
 +        if hasattr(record,'expires'):
 +            date = utcparse(record.expires)
              expires = datetime_to_epoch(date)
              new_cred.set_expiration(int(expires))
          auth_kind = "authority,ma,sa"
      def Resolve(self, api, xrns, type=None, full=True):
      
          if not isinstance(xrns, types.ListType):
-             xrns = [xrns]
              # try to infer type if not set and we get a single input
              if not type:
                  type = Xrn(xrns).get_type()
+             xrns = [xrns]
          hrns = [urn_to_hrn(xrn)[0] for xrn in xrns] 
 +
          # load all known registry names into a prefix tree and attempt to find
          # the longest matching prefix
 -        # create a dict where key is a registry hrn and its value is a
 -        # hrns at that registry (determined by the known prefix tree).  
 +        # create a dict where key is a registry hrn and its value is a list
 +        # of hrns at that registry (determined by the known prefix tree).  
          xrn_dict = {}
          registries = api.registries
          tree = prefixTree()
                  credential = api.getCredential()
                  interface = api.registries[registry_hrn]
                  server_proxy = api.server_proxy(interface, credential)
 -                peer_records = server_proxy.Resolve(xrns, credential)
 -                records.extend([SfaRecord(dict=record).as_dict() for record in peer_records])
 +                peer_records = server_proxy.Resolve(xrns, credential,type)
 +                # pass foreign records as-is
 +                # previous code used to read
 +                # records.extend([SfaRecord(dict=record).as_dict() for record in peer_records])
 +                # not sure why the records coming through xmlrpc had to be processed at all
 +                records.extend(peer_records)
      
          # try resolving the remaining unfound records at the local registry
          local_hrns = list ( set(hrns).difference([record['hrn'] for record in records]) )
          # 
 -        table = SfaTable()
 -        local_records = table.findObjects({'hrn': local_hrns})
 +        local_records = dbsession.query(RegRecord).filter(RegRecord.hrn.in_(local_hrns))
 +        if type:
 +            local_records = local_records.filter_by(type=type)
 +        local_records=local_records.all()
 +        logger.info("Resolve: local_records=%s (type=%s)"%(local_records,type))
 +        local_dicts = [ record.__dict__ for record in local_records ]
          
          if full:
              # in full mode we get as much info as we can, which involves contacting the 
              # testbed for getting implementation details about the record
 -            self.driver.augment_records_with_testbed_info(local_records)
 +            self.driver.augment_records_with_testbed_info(local_dicts)
              # also we fill the 'url' field for known authorities
              # used to be in the driver code, sounds like a poorman thing though
              def solve_neighbour_url (record):
 -                if not record['type'].startswith('authority'): return 
 -                hrn=record['hrn']
 +                if not record.type.startswith('authority'): return 
 +                hrn=record.hrn
                  for neighbour_dict in [ api.aggregates, api.registries ]:
                      if hrn in neighbour_dict:
 -                        record['url']=neighbour_dict[hrn].get_url()
 +                        record.url=neighbour_dict[hrn].get_url()
                          return 
 -            [ solve_neighbour_url (record) for record in local_records ]
 -                    
 -        
 +            for record in local_records: solve_neighbour_url (record)
          
 -        # convert local record objects to dicts
 -        records.extend([dict(record) for record in local_records])
 -        if type:
 -            records = filter(lambda rec: rec['type'] in [type], records)
 -    
 +        # convert local record objects to dicts for xmlrpc
 +        # xxx somehow here calling dict(record) issues a weird error
 +        # however record.todict() seems to work fine
 +        # records.extend( [ dict(record) for record in local_records ] )
 +        records.extend( [ record.todict() for record in local_records ] )    
          if not records:
              raise RecordNotFound(str(hrns))
      
          return records
      
 -    def List(self, api, xrn, origin_hrn=None):
 +    def List (self, api, xrn, origin_hrn=None):
          hrn, type = urn_to_hrn(xrn)
          # load all know registry names into a prefix tree and attempt to find
          # the longest matching prefix
 -        records = []
          registries = api.registries
          registry_hrns = registries.keys()
          tree = prefixTree()
              raise MissingAuthority(xrn)
          # if the best match (longest matching hrn) is not the local registry,
          # forward the request
 -        records = []    
 +        record_dicts = []    
          if registry_hrn != api.hrn:
              credential = api.getCredential()
              interface = api.registries[registry_hrn]
              server_proxy = api.server_proxy(interface, credential)
              record_list = server_proxy.List(xrn, credential)
 -            records = [SfaRecord(dict=record).as_dict() for record in record_list]
 +            # 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 records:
 +        if not record_dicts:
              if not api.auth.hierarchy.auth_exists(hrn):
                  raise MissingAuthority(hrn)
 +            records = dbsession.query(RegRecord).filter_by(authority=hrn)
 +            record_dicts=[ record.todict() for record in records ]
      
 -            table = SfaTable()
 -            records = table.find({'authority': hrn})
 -    
 -        return records
 +        return record_dicts
      
      
      def CreateGid(self, api, xrn, cert):
      # 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_record, ref_record):
 -        type=subject_record['type']
 +    def update_relations (self, subject_obj, ref_obj):
 +        type=subject_obj.type
          if type=='slice':
 -            self.update_relation(subject_record, 'researcher', ref_record.get('researcher'), 'user')
 +            self.update_relation(subject_obj, 'researcher', ref_obj.researcher, 'user')
          
      # 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, sfa_record, field_key, hrns, target_type):
 +    def update_relation (self, record_obj, field_key, hrns, target_type):
          # locate the linked objects in our db
 -        subject_type=sfa_record['type']
 -        subject_id=sfa_record['pointer']
 -        table = SfaTable()
 -        link_sfa_records = table.find ({'type':target_type, 'hrn': hrns})
 -        link_ids = [ rec.get('pointer') for rec in link_sfa_records ]
 +        subject_type=record_obj.type
 +        subject_id=record_obj.pointer
 +        # get the 'pointer' field of all matching records
 +        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)
 -        
  
 -    def Register(self, api, record):
 +    def Register(self, api, record_dict):
      
 -        hrn, type = record['hrn'], record['type']
 +        hrn, type = record_dict['hrn'], record_dict['type']
          urn = hrn_to_urn(hrn,type)
          # validate the type
          if type not in ['authority', 'slice', 'node', 'user']:
              raise UnknownSfaType(type) 
          
 -        # check if record already exists
 -        table = SfaTable()
 -        existing_records = table.find({'type': type, 'hrn': hrn})
 +        # check if record_dict already exists
 +        existing_records = dbsession.query(RegRecord).filter_by(type=type,hrn=hrn).all()
          if existing_records:
              raise ExistingRecord(hrn)
             
 -        record = SfaRecord(dict = record)
 -        record['authority'] = get_authority(record['hrn'])
 -        auth_info = api.auth.get_auth_info(record['authority'])
 +        assert ('type' in record_dict)
 +        # returns the right type of RegRecord according to type in record
 +        record = make_record(dict=record_dict)
 +        record.just_created()
 +        record.authority = get_authority(record.hrn)
 +        auth_info = api.auth.get_auth_info(record.authority)
          pub_key = None
          # make sure record has a gid
 -        if 'gid' not in record:
 +        if not record.gid:
              uuid = create_uuid()
              pkey = Keypair(create=True)
 -            if 'keys' in record and record['keys']:
 -                pub_key=record['keys']
 +            if getattr(record,'keys',None):
 +                pub_key=record.keys
                  # use only first key in record
 -                if isinstance(record['keys'], types.ListType):
 -                    pub_key = record['keys'][0]
 +                if isinstance(record.keys, types.ListType):
 +                    pub_key = record.keys[0]
                  pkey = convert_public_key(pub_key)
      
              gid_object = api.auth.hierarchy.create_gid(urn, uuid, pkey)
              gid = gid_object.save_to_string(save_parents=True)
 -            record['gid'] = gid
 -            record.set_gid(gid)
 +            record.gid = gid
      
 -        if type in ["authority"]:
 +        if isinstance (record, RegAuthority):
              # update the tree
              if not api.auth.hierarchy.auth_exists(hrn):
                  api.auth.hierarchy.create_auth(hrn_to_urn(hrn,'authority'))
      
              # get the GID from the newly created authority
              gid = auth_info.get_gid_object()
 -            record.set_gid(gid.save_to_string(save_parents=True))
 +            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
 +        
 +        elif isinstance (record, RegUser):
 +            # create RegKey objects for incoming keys
 +            if hasattr(record,'keys'): 
 +                logger.debug ("creating %d keys for user %s"%(len(record.keys),record.hrn))
 +                record.reg_keys = [ RegKey (key) for key in record.keys ]
 +            
          # update testbed-specific data if needed
 -        pointer = self.driver.register (record, hrn, pub_key)
 +        pointer = self.driver.register (record.__dict__, hrn, pub_key)
  
 -        record.set_pointer(pointer)
 -        record_id = table.insert(record)
 -        record['record_id'] = record_id
 +        record.pointer=pointer
 +        dbsession.add(record)
 +        dbsession.commit()
      
          # update membership for researchers, pis, owners, operators
          self.update_relations (record, record)
          return record.get_gid_object().save_to_string(save_parents=True)
      
      def Update(self, api, record_dict):
 -        new_record = SfaRecord(dict = record_dict)
 -        type = new_record['type']
 -        hrn = new_record['hrn']
 -        urn = hrn_to_urn(hrn,type)
 -        table = SfaTable()
 +        assert ('type' in record_dict)
 +        new_record=RegRecord(dict=record_dict)
 +        type = new_record.type
 +        hrn = new_record.hrn
 +        
          # make sure the record exists
 -        records = table.findObjects({'type': type, 'hrn': hrn})
 -        if not records:
 -            raise RecordNotFound(hrn)
 -        record = records[0]
 -        record['last_updated'] = time.gmtime()
 +        record = dbsession.query(RegRecord).filter_by(type=type,hrn=hrn).first()
 +        if not record:
 +            raise RecordNotFound("hrn=%s, type=%s"%(hrn,type))
 +        record.just_updated()
      
          # validate the type
          if type not in ['authority', 'slice', 'node', 'user']:
  
          # 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']
 +        pointer = record.pointer
      
          # is the a change in keys ?
          new_key=None
          if type=='user':
 -            if 'keys' in new_record and new_record['keys']:
 -                new_key=new_record['keys']
 +            if getattr(new_key,'keys',None):
 +                new_key=new_record.keys
                  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, new_record, hrn, new_key):
 +        if not self.driver.update (record.__dict__, new_record.__dict__, hrn, new_key):
              logger.warning("driver.update failed")
      
          # take new_key into account
              # update the openssl key and gid
              pkey = convert_public_key(new_key)
              uuid = create_uuid()
 +            urn = hrn_to_urn(hrn,type)
              gid_object = api.auth.hierarchy.create_gid(urn, uuid, pkey)
              gid = gid_object.save_to_string(save_parents=True)
 -            record['gid'] = gid
 -            record = SfaRecord(dict=record)
 -            table.update(record)
 +            record.gid = gid
 +            dsession.commit()
          
          # update membership for researchers, pis, owners, operators
          self.update_relations (record, new_record)
      
      # expecting an Xrn instance
      def Remove(self, api, xrn, origin_hrn=None):
 -    
 -        table = SfaTable()
 -        filter = {'hrn': xrn.get_hrn()}
          hrn=xrn.get_hrn()
          type=xrn.get_type()
 +        request=dbsession.query(RegRecord).filter_by(hrn=hrn)
          if type and type not in ['all', '*']:
 -            filter['type'] = type
 +            request=request.filter_by(type=type)
      
 -        records = table.find(filter)
 -        if not records: raise RecordNotFound(hrn)
 -        record = records[0]
 -        type = record['type']
 -        
 +        record = request.first()
 +        if not record:
 +            msg="Could not find hrn %s"%hrn
 +            if type: msg += " type=%s"%type
 +            raise RecordNotFound(msg)
 +
 +        type = record.type
          if type not in ['slice', 'user', 'node', 'authority'] :
              raise UnknownSfaType(type)
  
  
          # call testbed callback first
          # IIUC this is done on the local testbed TOO because of the refreshpeer link
 -        if not self.driver.remove(record):
 +        if not self.driver.remove(record.__dict__):
              logger.warning("driver.remove failed")
  
          # delete from sfa db
 -        table.remove(record)
 +        dbsession.delete(record)
 +        dbsession.commit()
      
          return 1
  
 -    # This is a PLC-specific thing...
 +    # This is a PLC-specific thing, won't work with other platforms
      def get_key_from_incoming_ip (self, api):
          # verify that the callers's ip address exist in the db and is an interface
          # for a node in the db
          node = nodes[0]
         
          # look up the sfa record
 -        table = SfaTable()
 -        records = table.findObjects({'type': 'node', 'pointer': node['node_id']})
 -        if not records:
 -            raise RecordNotFound("pointer:" + str(node['node_id']))  
 -        record = records[0]
 +        record=dbsession.query(RegRecord).filter_by(type='node',pointer=node['node_id']).first()
 +        if not record:
 +            raise RecordNotFound("node with pointer %s"%node['node_id'])
          
          # generate a new keypair and gid
          uuid = create_uuid()
          pkey = Keypair(create=True)
 -        urn = hrn_to_urn(record['hrn'], record['type'])
 +        urn = hrn_to_urn(record.hrn, record.type)
          gid_object = api.auth.hierarchy.create_gid(urn, uuid, pkey)
          gid = gid_object.save_to_string(save_parents=True)
 -        record['gid'] = gid
 -        record.set_gid(gid)
 +        record.gid = gid
  
          # update the record
 -        table.update(record)
 +        dbsession.commit()
    
          # attempt the scp the key
          # and gid onto the node
@@@ -3,7 -3,6 +3,7 @@@ import datetim
  #
  from sfa.util.faults import MissingSfaInfo, UnknownSfaType, \
      RecordNotFound, SfaNotImplemented, SliverDoesNotExist
 +
  from sfa.util.sfalogging import logger
  from sfa.util.defaultdict import defaultdict
  from sfa.util.sfatime import utcparse, datetime_to_string, datetime_to_epoch
@@@ -11,13 -10,12 +11,14 @@@ from sfa.util.xrn import Xrn, hrn_to_ur
  from sfa.util.cache import Cache
  # used to be used in get_ticket
  #from sfa.trust.sfaticket import SfaTicket
 +
  from sfa.rspecs.version_manager import VersionManager
  from sfa.rspecs.rspec import RSpec
 +
  # the driver interface, mostly provides default behaviours
  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.util.osxrn import OSXrn
@@@ -43,6 -41,7 +44,7 @@@ class NovaDriver (Driver)
      def __init__ (self, config):
          Driver.__init__ (self, config)
          self.shell = NovaShell (config)
+         self.euca_shell = EucaShell(config)
          self.cache=None
          if config.SFA_AGGREGATE_CACHING:
              if NovaDriver.cache is None:
      
      def sliver_status (self, slice_urn, slice_hrn):
          # find out where this slice is currently running
-         slicename = hrn_to_pl_slicename(slice_hrn)
-         
-         slices = self.shell.GetSlices([slicename], ['slice_id', 'node_ids','person_ids','name','expires'])
-         if len(slices) == 0:        
-             raise SliverDoesNotExist("%s (used %s as slicename internally)" % (slice_hrn, slicename))
-         slice = slices[0]
-         
-         # report about the local nodes only
-         nodes = self.shell.GetNodes({'node_id':slice['node_ids'],'peer_id':None},
-                               ['node_id', 'hostname', 'site_id', 'boot_state', 'last_contact'])
-         if len(nodes) == 0:
+         project_name = Xrn(slice_urn).get_leaf()
+         project = self.shell.auth_manager.get_project(project_name)
+         instances = self.shell.db.instance_get_all_by_project(project_name)
+         if len(instances) == 0:
              raise SliverDoesNotExist("You have not allocated any slivers here") 
-         site_ids = [node['site_id'] for node in nodes]
-     
+         
          result = {}
          top_level_status = 'unknown'
-         if nodes:
+         if instances:
              top_level_status = 'ready'
          result['geni_urn'] = slice_urn
-         result['pl_login'] = slice['name']
-         result['pl_expires'] = datetime_to_string(utcparse(slice['expires']))
+         result['plos_login'] = 'root' 
+         result['plos_expires'] = None
          
          resources = []
-         for node in nodes:
+         for instance in instances:
              res = {}
-             res['pl_hostname'] = node['hostname']
-             res['pl_boot_state'] = node['boot_state']
-             res['pl_last_contact'] = node['last_contact']
-             if node['last_contact'] is not None:
-                 
-                 res['pl_last_contact'] = datetime_to_string(utcparse(node['last_contact']))
-             sliver_id = urn_to_sliver_id(slice_urn, slice['slice_id'], node['node_id']) 
+             # instances are accessed by ip, not hostname. We need to report the ip
+             # somewhere so users know where to ssh to.     
+             res['plos_hostname'] = instance.hostname
+             res['plos_created_at'] = datetime_to_string(utcparse(instance.created_at))    
+             res['plos_boot_state'] = instance.vm_state
+             res['plos_sliver_type'] = instance.instance_type.name 
+             sliver_id =  Xrn(slice_urn).get_sliver_id(instance.project_id, \
+                                                       instance.hostname, instance.id)
              res['geni_urn'] = sliver_id
-             if node['boot_state'] == 'boot':
-                 res['geni_status'] = 'ready'
+             if instance.vm_state == 'running':
+                 res['boot_state'] = 'ready';
              else:
-                 res['geni_status'] = 'failed'
-                 top_level_status = 'failed' 
-                 
-             res['geni_error'] = ''
-     
+                 res['boot_state'] = 'unknown'  
              resources.append(res)
              
          result['geni_status'] = top_level_status
          # parse rspec
          rspec = RSpec(rspec_string)
          requested_attributes = rspec.version.get_slice_attributes()
+         pubkeys = []
+         for user in users:
+             pubkeys.extend(user['keys']) 
+         # assume that there is a key whos nane matches the caller's username.
+         project_key = Xrn(users[0]['urn']).get_leaf()    
          
+          
          # ensure slice record exists
-         slice = aggregate.verify_slice(slicename, users, options=options)
+         aggregate.create_project(slicename, users, options=options)
          # ensure person records exists
-         persons = aggregate.verify_slice_users(slicename, users, options=options)
+         aggregate.create_project_users(slicename, users, options=options)
          # add/remove slice from nodes
-         slices.verify_instances(slicename, rspec)    
+         aggregate.run_instances(slicename, rspec, project_key, pubkeys)    
     
          return aggregate.get_rspec(slice_xrn=slice_urn, version=rspec.version)
  
          slice = self.shell.project_get(name)
          if not slice:
              return 1
-         
-         self.shell.DeleteSliceFromNodes(slicename, slice['node_ids'])
          instances = self.shell.db.instance_get_all_by_project(name)
          for instance in instances:
              self.shell.db.instance_destroy(instance.instance_id)