python3 - 2to3 + miscell obvious tweaks
[sfa.git] / sfa / dummy / dummydriver.py
index ab2053d..44bc767 100644 (file)
@@ -2,8 +2,8 @@ import time
 import datetime
 #
 from sfa.util.faults import MissingSfaInfo, UnknownSfaType, \
-    RecordNotFound, SfaNotImplemented, SliverDoesNotExist
-
+    RecordNotFound, SfaNotImplemented, SliverDoesNotExist, SearchFailed, \
+    UnsupportedOperation, Forbidden
 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,12 +11,11 @@ from sfa.util.xrn import Xrn, hrn_to_urn, get_leaf
 from sfa.util.cache import Cache
 
 # one would think the driver should not need to mess with the SFA db, but..
-from sfa.storage.alchemy import dbsession
-from sfa.storage.model import RegRecord
+from sfa.storage.model import RegRecord, SliverAllocation
+from sfa.trust.credential import Credential
 
 # 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
 
@@ -34,56 +33,89 @@ def list_to_dict(recs, key):
     convert a list of dictionaries into a dictionary keyed on the 
     specified dictionary key 
     """
-    return dict ( [ (rec[key],rec) for rec in recs ] )
+    return dict([(rec[key], rec) for rec in recs])
 
 #
-# DummyShell is just an xmlrpc serverproxy where methods can be sent as-is; 
-# 
+# DummyShell is just an xmlrpc serverproxy where methods can be sent as-is;
+#
+
+
 class DummyDriver (Driver):
 
-    # the cache instance is a class member so it survives across incoming requests
+    # the cache instance is a class member so it survives across incoming
+    # requests
     cache = None
 
-    def __init__ (self, config):
-        Driver.__init__ (self, config)
-        self.config = config
+    def __init__(self, api):
+        Driver.__init__(self, api)
+        config = api.config
         self.hrn = config.SFA_INTERFACE_HRN
         self.root_auth = config.SFA_REGISTRY_ROOT_AUTH
-        self.shell = DummyShell (config)
+        self.shell = DummyShell(config)
         self.testbedInfo = self.shell.GetTestbedInfo()
+
+    def check_sliver_credentials(self, creds, urns):
+        # build list of cred object hrns
+        slice_cred_names = []
+        for cred in creds:
+            slice_cred_hrn = Credential(cred=cred).get_gid_object().get_hrn()
+            slice_cred_names.append(
+                DummyXrn(xrn=slice_cred_hrn).dummy_slicename())
+
+        # look up slice name of slivers listed in urns arg
+        slice_ids = []
+        for urn in urns:
+            sliver_id_parts = Xrn(xrn=urn).get_sliver_id_parts()
+            try:
+                slice_ids.append(int(sliver_id_parts[0]))
+            except ValueError:
+                pass
+
+        if not slice_ids:
+            raise Forbidden("sliver urn not provided")
+
+        slices = self.shell.GetSlices({'slice_ids': slice_ids})
+        sliver_names = [slice['slice_name'] for slice in slices]
+
+        # make sure we have a credential for every specified sliver ierd
+        for sliver_name in sliver_names:
+            if sliver_name not in slice_cred_names:
+                msg = "Valid credential not found for target: %s" % sliver_name
+                raise Forbidden(msg)
+
     ########################################
-    ########## registry oriented
+    # registry oriented
     ########################################
 
-    def augment_records_with_testbed_info (self, sfa_records):
-        return self.fill_record_info (sfa_records)
+    def augment_records_with_testbed_info(self, sfa_records):
+        return self.fill_record_info(sfa_records)
 
-    ########## 
-    def register (self, sfa_record, hrn, pub_key):
+    ##########
+    def register(self, sfa_record, hrn, pub_key):
         type = sfa_record['type']
         dummy_record = self.sfa_fields_to_dummy_fields(type, hrn, sfa_record)
-        
+
         if type == 'authority':
             pointer = -1
 
         elif type == 'slice':
-            slices = self.shell.GetSlices({'slice_name': dummy_record['slice_name']})
+            slices = self.shell.GetSlices(
+                {'slice_name': dummy_record['slice_name']})
             if not slices:
-                 pointer = self.shell.AddSlice(dummy_record)
+                pointer = self.shell.AddSlice(dummy_record)
             else:
-                 pointer = slices[0]['slice_id']
+                pointer = slices[0]['slice_id']
 
         elif type == 'user':
-            users = self.shell.GetUsers({'email':sfa_record['email']})
+            users = self.shell.GetUsers({'email': sfa_record['email']})
             if not users:
                 pointer = self.shell.AddUser(dummy_record)
             else:
                 pointer = users[0]['user_id']
-    
+
             # Add the user's key
             if pub_key:
-                self.shell.AddUserKey({'user_id' : pointer, 'key' : pub_key})
+                self.shell.AddUserKey({'user_id': pointer, 'key': pub_key})
 
         elif type == 'node':
             nodes = self.shell.GetNodes(dummy_record['hostname'])
@@ -91,40 +123,39 @@ class DummyDriver (Driver):
                 pointer = self.shell.AddNode(dummy_record)
             else:
                 pointer = users[0]['node_id']
-    
+
         return pointer
-        
+
     ##########
-    def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
+    def update(self, old_sfa_record, new_sfa_record, hrn, new_key):
         pointer = old_sfa_record['pointer']
         type = old_sfa_record['type']
-        dummy_record=self.sfa_fields_to_dummy_fields(type, hrn, new_sfa_record)
+        dummy_record = self.sfa_fields_to_dummy_fields(
+            type, hrn, new_sfa_record)
 
         # new_key implemented for users only
-        if new_key and type not in [ 'user' ]:
+        if new_key and type not in ['user']:
             raise UnknownSfaType(type)
 
-    
         if type == "slice":
-            self.shell.UpdateSlice({'slice_id': pointer, 'fields': dummy_record})
-    
+            self.shell.UpdateSlice(
+                {'slice_id': pointer, 'fields': dummy_record})
+
         elif type == "user":
             self.shell.UpdateUser({'user_id': pointer, 'fields': dummy_record})
 
             if new_key:
-                self.shell.AddUserKey({'user_id' : pointer, 'key' : new_key})
+                self.shell.AddUserKey({'user_id': pointer, 'key': new_key})
 
         elif type == "node":
             self.shell.UpdateNode({'node_id': pointer, 'fields': dummy_record})
 
-
         return True
-        
 
     ##########
-    def remove (self, sfa_record):
-        type=sfa_record['type']
-        pointer=sfa_record['pointer']
+    def remove(self, sfa_record):
+        type = sfa_record['type']
+        pointer = sfa_record['pointer']
         if type == 'user':
             self.shell.DeleteUser({'user_id': pointer})
         elif type == 'slice':
@@ -134,10 +165,6 @@ class DummyDriver (Driver):
 
         return True
 
-
-
-
-
     ##
     # Convert SFA fields to Dummy testbed fields for use when registering or updating
     # registry record in the dummy testbed
@@ -146,19 +173,19 @@ class DummyDriver (Driver):
     def sfa_fields_to_dummy_fields(self, type, hrn, sfa_record):
 
         dummy_record = {}
+
         if type == "slice":
             dummy_record["slice_name"] = hrn_to_dummy_slicename(hrn)
-        
+
         elif type == "node":
             if "hostname" not in sfa_record:
                 raise MissingSfaInfo("hostname")
             dummy_record["hostname"] = sfa_record["hostname"]
             if "type" in sfa_record:
-               dummy_record["type"] = sfa_record["type"]
+                dummy_record["type"] = sfa_record["type"]
             else:
-               dummy_record["type"] = "dummy_type"
+                dummy_record["type"] = "dummy_type"
+
         elif type == "authority":
             dummy_record["name"] = hrn
 
@@ -187,13 +214,13 @@ class DummyDriver (Driver):
         Fill in the DUMMY specific fields of a SFA record. This
         involves calling the appropriate DUMMY method to retrieve the 
         database record for the object.
-            
+
         @param record: record to fill in field (in/out param)     
         """
         # get ids by type
-        node_ids, slice_ids, user_ids = [], [], [] 
+        node_ids, slice_ids, user_ids = [], [], []
         type_map = {'node': node_ids, 'slice': slice_ids, 'user': user_ids}
-                  
+
         for record in records:
             for type in type_map:
                 if type == record['type']:
@@ -202,10 +229,10 @@ class DummyDriver (Driver):
         # get dummy records
         nodes, slices, users = {}, {}, {}
         if node_ids:
-            node_list = self.shell.GetNodes({'node_ids':node_ids})
+            node_list = self.shell.GetNodes({'node_ids': node_ids})
             nodes = list_to_dict(node_list, 'node_id')
         if slice_ids:
-            slice_list = self.shell.GetSlices({'slice_ids':slice_ids})
+            slice_list = self.shell.GetSlices({'slice_ids': slice_ids})
             slices = list_to_dict(slice_list, 'slice_id')
         if user_ids:
             user_list = self.shell.GetUsers({'user_ids': user_ids})
@@ -213,13 +240,12 @@ class DummyDriver (Driver):
 
         dummy_records = {'node': nodes, 'slice': slices, 'user': users}
 
-
         # fill record info
         for record in records:
             # records with pointer==-1 do not have dummy info.
             if record['pointer'] == -1:
                 continue
-           
+
             for type in dummy_records:
                 if record['type'] == type:
                     if record['pointer'] in dummy_records[type]:
@@ -228,10 +254,10 @@ class DummyDriver (Driver):
             # fill in key info
             if record['type'] == 'user':
                 record['key_ids'] = []
-                recors['keys'] = []
+                record['keys'] = []
                 for key in dummy_records['user'][record['pointer']]['keys']:
-                     record['key_ids'].append(-1)
-                     recors['keys'].append(key)
+                    record['key_ids'].append(-1)
+                    record['keys'].append(key)
 
         return records
 
@@ -257,11 +283,11 @@ class DummyDriver (Driver):
             users = list_to_dict(user_list, 'user_id')
         if slice_ids:
             slice_list = self.shell.GetSlices({'slice_ids': slice_ids})
-            slices = list_to_dict(slice_list, 'slice_id')       
+            slices = list_to_dict(slice_list, 'slice_id')
         if node_ids:
             node_list = self.shell.GetNodes({'node_ids': node_ids})
             nodes = list_to_dict(node_list, 'node_id')
-       
+
         # convert ids to hrns
         for record in records:
             # get all relevant data
@@ -273,24 +299,26 @@ class DummyDriver (Driver):
                 continue
 
             if 'user_ids' in record:
-                emails = [users[user_id]['email'] for user_id in record['user_ids'] \
-                          if user_id in  users]
+                emails = [users[user_id]['email'] for user_id in record['user_ids']
+                          if user_id in users]
                 usernames = [email.split('@')[0] for email in emails]
-                user_hrns = [".".join([auth_hrn, testbed_name, username]) for username in usernames]
-                record['users'] = user_hrns 
+                user_hrns = [".".join([auth_hrn, testbed_name, username])
+                             for username in usernames]
+                record['users'] = user_hrns
             if 'slice_ids' in record:
-                slicenames = [slices[slice_id]['slice_name'] for slice_id in record['slice_ids'] \
+                slicenames = [slices[slice_id]['slice_name'] for slice_id in record['slice_ids']
                               if slice_id in slices]
-                slice_hrns = [slicename_to_hrn(auth_hrn, slicename) for slicename in slicenames]
+                slice_hrns = [slicename_to_hrn(
+                    auth_hrn, slicename) for slicename in slicenames]
                 record['slices'] = slice_hrns
             if 'node_ids' in record:
-                hostnames = [nodes[node_id]['hostname'] for node_id in record['node_ids'] \
+                hostnames = [nodes[node_id]['hostname'] for node_id in record['node_ids']
                              if node_id in nodes]
-                node_hrns = [hostname_to_hrn(auth_hrn, login_base, hostname) for hostname in hostnames]
+                node_hrns = [hostname_to_hrn(
+                    auth_hrn, login_base, hostname) for hostname in hostnames]
                 record['nodes'] = node_hrns
 
-            
-        return records   
+        return records
 
     def fill_record_sfa_info(self, records):
 
@@ -301,14 +329,15 @@ class DummyDriver (Driver):
         user_ids = []
         for record in records:
             user_ids.extend(record.get("user_ids", []))
-        
-        # get sfa records for all records associated with these records.   
+
+        # get sfa records for all records associated with these records.
         # we'll replace pl ids (person_ids) with hrns from the sfa records
         # we obtain
-        
+
         # get the registry records
         user_list, users = [], {}
-        user_list = dbsession.query (RegRecord).filter(RegRecord.pointer.in_(user_ids))
+        user_list = self.api.dbsession().query(
+            RegRecord).filter(RegRecord.pointer.in_(user_ids))
         # create a hrns keyed on the sfa record's pointer.
         # Its possible for multiple records to have the same pointer so
         # the dict's value will be a list of hrns.
@@ -324,11 +353,12 @@ class DummyDriver (Driver):
         # fill sfa info
         for record in records:
             # skip records with no pl info (top level authorities)
-            #if record['pointer'] == -1:
-            #    continue 
+            # if record['pointer'] == -1:
+            #    continue
             sfa_info = {}
             type = record['type']
-            logger.info("fill_record_sfa_info - incoming record typed %s"%type)
+            logger.info(
+                "fill_record_sfa_info - incoming record typed %s" % type)
             if (type == "slice"):
                 # all slice users are researchers
                 record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')
@@ -336,7 +366,7 @@ class DummyDriver (Driver):
                 record['researcher'] = []
                 for user_id in record.get('user_ids', []):
                     hrns = [user.hrn for user in users[user_id]]
-                    record['researcher'].extend(hrns)                
+                    record['researcher'].extend(hrns)
 
             elif (type.startswith("authority")):
                 record['url'] = None
@@ -345,228 +375,212 @@ class DummyDriver (Driver):
             elif (type == "node"):
                 sfa_info['dns'] = record.get("hostname", "")
                 # xxx TODO: URI, LatLong, IP, DNS
-    
+
             elif (type == "user"):
                 logger.info('setting user.email')
                 sfa_info['email'] = record.get("email", "")
                 sfa_info['geni_urn'] = hrn_to_urn(record['hrn'], 'user')
-                sfa_info['geni_certificate'] = record['gid'] 
+                sfa_info['geni_certificate'] = record['gid']
                 # xxx TODO: PostalAddress, Phone
             record.update(sfa_info)
 
-
     ####################
-    def update_relation (self, subject_type, target_type, relation_name, 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' and relation_name == 'researcher':
-            subject=self.shell.GetSlices ({'slice_id': subject_id})[0]
-            if 'user_ids' not in subject.keys():
-                 subject['user_ids'] = []
+        if subject_type == 'slice' and target_type == 'user' and relation_name == 'researcher':
+            subject = self.shell.GetSlices({'slice_id': subject_id})[0]
+            if 'user_ids' not in list(subject.keys()):
+                subject['user_ids'] = []
             current_target_ids = subject['user_ids']
-            add_target_ids = list ( set (target_ids).difference(current_target_ids))
-            del_target_ids = list ( set (current_target_ids).difference(target_ids))
-            logger.debug ("subject_id = %s (type=%s)"%(subject_id,type(subject_id)))
+            add_target_ids = list(
+                set(target_ids).difference(current_target_ids))
+            del_target_ids = list(
+                set(current_target_ids).difference(target_ids))
+            logger.debug("subject_id = %s (type=%s)" %
+                         (subject_id, type(subject_id)))
             for target_id in add_target_ids:
-                self.shell.AddUserToSlice ({'user_id': target_id, 'slice_id': subject_id})
-                logger.debug ("add_target_id = %s (type=%s)"%(target_id,type(target_id)))
+                self.shell.AddUserToSlice(
+                    {'user_id': target_id, 'slice_id': subject_id})
+                logger.debug("add_target_id = %s (type=%s)" %
+                             (target_id, type(target_id)))
             for target_id in del_target_ids:
-                logger.debug ("del_target_id = %s (type=%s)"%(target_id,type(target_id)))
-                self.shell.DeleteUserFromSlice ({'user_id': target_id, 'slice_id': subject_id})
+                logger.debug("del_target_id = %s (type=%s)" %
+                             (target_id, type(target_id)))
+                self.shell.DeleteUserFromSlice(
+                    {'user_id': target_id, 'slice_id': subject_id})
         else:
-            logger.info('unexpected relation %s to maintain, %s -> %s'%(relation_name,subject_type,target_type))
+            logger.info('unexpected relation %s to maintain, %s -> %s' %
+                        (relation_name, subject_type, target_type))
 
-        
     ########################################
-    ########## aggregate oriented
+    # aggregate oriented
     ########################################
 
-    def testbed_name (self): return "dummy"
+    def testbed_name(self): return "dummy"
 
-    # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
-    def aggregate_version (self):
-        version_manager = VersionManager()
-        ad_rspec_versions = []
-        request_rspec_versions = []
-        for rspec_version in version_manager.versions:
-            if rspec_version.content_type in ['*', 'ad']:
-                ad_rspec_versions.append(rspec_version.to_dict())
-            if rspec_version.content_type in ['*', 'request']:
-                request_rspec_versions.append(rspec_version.to_dict()) 
-        return {
-            'testbed':self.testbed_name(),
-            'geni_request_rspec_versions': request_rspec_versions,
-            'geni_ad_rspec_versions': ad_rspec_versions,
-            }
-
-    def list_slices (self, creds, options):
-    
-        slices = self.shell.GetSlices()
-        slice_hrns = [slicename_to_hrn(self.hrn, slice['slice_name']) for slice in slices]
-        slice_urns = [hrn_to_urn(slice_hrn, 'slice') for slice_hrn in slice_hrns]
-    
-        return slice_urns
-        
-    # first 2 args are None in case of resource discovery
-    def list_resources (self, slice_urn, slice_hrn, creds, options):
-    
-        version_manager = VersionManager()
-        # get the rspec's return format from options
-        rspec_version = version_manager.get_version(options.get('geni_rspec_version'))
-        version_string = "rspec_%s" % (rspec_version)
-    
+    def aggregate_version(self):
+        return {}
+
+    def list_resources(self, version=None, options=None):
+        if options is None:
+            options = {}
         aggregate = DummyAggregate(self)
-        rspec =  aggregate.get_rspec(slice_xrn=slice_urn, version=rspec_version, 
-                                     options=options)
-    
+        rspec = aggregate.list_resources(version=version, options=options)
         return rspec
-    
-    def sliver_status (self, slice_urn, slice_hrn):
-        # find out where this slice is currently running
-        slice_name = hrn_to_dummy_slicename(slice_hrn)
-        
-        slices = self.shell.GetSlices({'slice_name': slice_name})
-        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_ids':slice['node_ids']})
-
-        if len(nodes) == 0:
-            raise SliverDoesNotExist("You have not allocated any slivers here") 
-
-        # get login info
-        user = {}
-        keys = []
-        if slice['user_ids']:
-            users = self.shell.GetUsers({'user_ids': slice['user_ids']})
-            for user in users:
-                 keys.extend(user['keys'])
-
-            user.update({'urn': slice_urn,
-                         'login': slice['slice_name'],
-                         'protocol': ['ssh'],
-                         'port': ['22'],
-                         'keys': keys})
-
-    
-        result = {}
-        top_level_status = 'unknown'
-        if nodes:
-            top_level_status = 'ready'
-        result['geni_urn'] = slice_urn
-        result['dummy_login'] = slice['slice_name']
-        result['dummy_expires'] = datetime_to_string(utcparse(slice['expires']))
-        result['geni_expires'] = datetime_to_string(utcparse(slice['expires']))
-        
-        resources = []
-        for node in nodes:
-            res = {}
-            res['dummy_hostname'] = node['hostname']
-            res['geni_expires'] = datetime_to_string(utcparse(slice['expires']))
-            sliver_id = Xrn(slice_urn, type='slice', id=node['node_id']).urn
-            res['geni_urn'] = sliver_id
-            res['geni_status'] = 'ready'
-            res['geni_error'] = ''
-            res['users'] = [users]  
-    
-            resources.append(res)
-            
-        result['geni_status'] = top_level_status
-        result['geni_resources'] = resources
-        return result
-
-    def create_sliver (self, slice_urn, slice_hrn, creds, rspec_string, users, options):
 
+    def describe(self, urns, version, options=None):
+        if options is None:
+            options = {}
+        aggregate = DummyAggregate(self)
+        return aggregate.describe(urns, version=version, options=options)
+
+    def status(self, urns, options=None):
+        if options is None:
+            options = {}
+        aggregate = DummyAggregate(self)
+        desc = aggregate.describe(urns, version='GENI 3')
+        status = {'geni_urn': desc['geni_urn'],
+                  'geni_slivers': desc['geni_slivers']}
+        return status
+
+    def allocate(self, urn, rspec_string, expiration, options=None):
+        if options is None:
+            options = {}
+        xrn = Xrn(urn)
         aggregate = DummyAggregate(self)
         slices = DummySlices(self)
-        sfa_peer = slices.get_sfa_peer(slice_hrn)
-        slice_record=None    
+        slice_record = None
+        users = options.get('geni_users', [])
         if users:
             slice_record = users[0].get('slice_record', {})
-    
+
         # parse rspec
         rspec = RSpec(rspec_string)
         requested_attributes = rspec.version.get_slice_attributes()
-        
+
         # ensure slice record exists
-        slice = slices.verify_slice(slice_hrn, slice_record, sfa_peer, options=options)
-        # ensure user records exists
-        #users = slices.verify_users(slice_hrn, slice, users, sfa_peer, options=options)
-        
+        slice = slices.verify_slice(
+            xrn.hrn, slice_record, expiration=expiration, options=options)
+        # ensure person records exists
+        #persons = slices.verify_persons(xrn.hrn, slice, users, peer, sfa_peer, options=options)
+
         # add/remove slice from nodes
-        requested_slivers = []
-        for node in rspec.version.get_nodes_with_slivers():
-            hostname = None
-            if node.get('component_name'):
-                hostname = node.get('component_name').strip()
-            elif node.get('component_id'):
-                hostname = xrn_to_hostname(node.get('component_id').strip())
-            if hostname:
-                requested_slivers.append(hostname)
-        requested_slivers_ids = []
-        for hostname in requested_slivers:
-            node_id = self.shell.GetNodes({'hostname': hostname})[0]['node_id']
-            requested_slivers_ids.append(node_id) 
-        nodes = slices.verify_slice_nodes(slice, requested_slivers_ids) 
-    
-        return aggregate.get_rspec(slice_xrn=slice_urn, version=rspec.version)
-
-    def delete_sliver (self, slice_urn, slice_hrn, creds, options):
-        slicename = hrn_to_dummy_slicename(slice_hrn)
-        slices = self.shell.GetSlices({'slice_name': slicename})
-        if not slices:
-            return True
-        slice = slices[0]
-        
-        try:
-            self.shell.DeleteSliceFromNodes({'slice_id': slice['slice_id'], 'node_ids': slice['node_ids']})
-            return True
-        except:
-            return False
-    
-    def renew_sliver (self, slice_urn, slice_hrn, creds, expiration_time, options):
-        slicename = hrn_to_dummy_slicename(slice_hrn)
-        slices = self.shell.GetSlices({'slice_name': slicename})
-        if not slices:
-            raise RecordNotFound(slice_hrn)
-        slice = slices[0]
+        request_nodes = rspec.version.get_nodes_with_slivers()
+        nodes = slices.verify_slice_nodes(urn, slice, request_nodes)
+
+        return aggregate.describe([xrn.get_urn()], version=rspec.version)
+
+    def provision(self, urns, options=None):
+        if options is None:
+            options = {}
+        # update users
+        slices = DummySlices(self)
+        aggregate = DummyAggregate(self)
+        slivers = aggregate.get_slivers(urns)
+        slice = slivers[0]
+        geni_users = options.get('geni_users', [])
+        #users = slices.verify_users(None, slice, geni_users, options=options)
+        # update sliver allocation states and set them to geni_provisioned
+        sliver_ids = [sliver['sliver_id'] for sliver in slivers]
+        dbsession = self.api.dbsession()
+        SliverAllocation.set_allocations(
+            sliver_ids, 'geni_provisioned', dbsession)
+        version_manager = VersionManager()
+        rspec_version = version_manager.get_version(
+            options['geni_rspec_version'])
+        return self.describe(urns, rspec_version, options=options)
+
+    def delete(self, urns, options=None):
+        if options is None:
+            options = {}
+        # collect sliver ids so we can update sliver allocation states after
+        # we remove the slivers.
+        aggregate = DummyAggregate(self)
+        slivers = aggregate.get_slivers(urns)
+        if slivers:
+            slice_id = slivers[0]['slice_id']
+            node_ids = []
+            sliver_ids = []
+            for sliver in slivers:
+                node_ids.append(sliver['node_id'])
+                sliver_ids.append(sliver['sliver_id'])
+
+            # determine if this is a peer slice
+            # xxx I wonder if this would not need to use PlSlices.get_peer instead
+            # in which case plc.peers could be deprecated as this here
+            # is the only/last call to this last method in plc.peers
+            slice_hrn = DummyXrn(auth=self.hrn, slicename=slivers[
+                                 0]['slice_name']).get_hrn()
+            try:
+                self.shell.DeleteSliceFromNodes(
+                    {'slice_id': slice_id, 'node_ids': node_ids})
+                # delete sliver allocation states
+                dbsession = self.api.dbsession()
+                SliverAllocation.delete_allocations(sliver_ids, dbsession)
+            finally:
+                pass
+
+        # prepare return struct
+        geni_slivers = []
+        for sliver in slivers:
+            geni_slivers.append(
+                {'geni_sliver_urn': sliver['sliver_id'],
+                 'geni_allocation_status': 'geni_unallocated',
+                 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
+        return geni_slivers
+
+    def renew(self, urns, expiration_time, options=None):
+        if options is None:
+            options = {}
+        aggregate = DummyAggregate(self)
+        slivers = aggregate.get_slivers(urns)
+        if not slivers:
+            raise SearchFailed(urns)
+        slice = slivers[0]
         requested_time = utcparse(expiration_time)
         record = {'expires': int(datetime_to_epoch(requested_time))}
-        try:
-            self.shell.UpdateSlice({'slice_id': slice['slice_id'], 'fields':record})
-            return True
-        except:
-            return False
-
-    # set the 'enabled' tag to True
-    def start_slice (self, slice_urn, slice_hrn, creds):
-        slicename = hrn_to_dummy_slicename(slice_hrn)
-        slices = self.shell.GetSlices({'slice_name': slicename})
-        if not slices:
-            raise RecordNotFound(slice_hrn)
-        slice_id = slices[0]['slice_id']
-        slice_enabled = slices[0]['enabled'] 
-        # just update the slice enabled tag
-        if not slice_enabled:
-            self.shell.UpdateSlice({'slice_id': slice_id, 'fields': {'enabled': True}})
-        return 1
-
-    # set the 'enabled' tag to False
-    def stop_slice (self, slice_urn, slice_hrn, creds):
-        slicename = hrn_to_pl_slicename(slice_hrn)
-        slices = self.shell.GetSlices({'slice_name': slicename})
+        self.shell.UpdateSlice(
+            {'slice_id': slice['slice_id'], 'fileds': record})
+        description = self.describe(urns, 'GENI 3', options)
+        return description['geni_slivers']
+
+    def perform_operational_action(self, urns, action, options=None):
+        if options is None:
+            options = {}
+        # Dummy doesn't support operational actions. Lets pretend like it
+        # supports start, but reject everything else.
+        action = action.lower()
+        if action not in ['geni_start']:
+            raise UnsupportedOperation(action)
+
+        # fault if sliver is not full allocated (operational status is
+        # geni_pending_allocation)
+        description = self.describe(urns, 'GENI 3', options)
+        for sliver in description['geni_slivers']:
+            if sliver['geni_operational_status'] == 'geni_pending_allocation':
+                raise UnsupportedOperation(
+                    action, "Sliver must be fully allocated (operational status is not geni_pending_allocation)")
+        #
+        # Perform Operational Action Here
+        #
+
+        geni_slivers = self.describe(urns, 'GENI 3', options)['geni_slivers']
+        return geni_slivers
+
+    def shutdown(self, xrn, options=None):
+        if options is None:
+            options = {}
+        xrn = DummyXrn(xrn=xrn, type='slice')
+        slicename = xrn.pl_slicename()
+        slices = self.shell.GetSlices({'name': slicename}, ['slice_id'])
         if not slices:
             raise RecordNotFound(slice_hrn)
         slice_id = slices[0]['slice_id']
-        slice_enabled = slices[0]['enabled']
-        # just update the slice enabled tag
-        if slice_enabled:
-            self.shell.UpdateSlice({'slice_id': slice_id, 'fields': {'enabled': False}})
+        slice_tags = self.shell.GetSliceTags(
+            {'slice_id': slice_id, 'tagname': 'enabled'})
+        if not slice_tags:
+            self.shell.AddSliceTag(slice_id, 'enabled', '0')
+        elif slice_tags[0]['value'] != "0":
+            tag_id = slice_tags[0]['slice_tag_id']
+            self.shell.UpdateSliceTag(tag_id, '0')
         return 1
-    
-    def reset_slice (self, slice_urn, slice_hrn, creds):
-        raise SfaNotImplemented ("reset_slice not available at this interface")
-    
-    def get_ticket (self, slice_urn, slice_hrn, creds, rspec_string, options):
-        raise SfaNotImplemented,"DummyDriver.get_ticket needs a rewrite"