Refactor Dummy Driver and make it implements AM API v3 natively
authorMohamed Larabi <mohamed.larabi@inria.fr>
Tue, 4 Jun 2013 07:52:31 +0000 (09:52 +0200)
committerMohamed Larabi <mohamed.larabi@inria.fr>
Tue, 4 Jun 2013 07:52:31 +0000 (09:52 +0200)
sfa/dummy/README.txt
sfa/dummy/dummy_testbed_api.py
sfa/dummy/dummy_testbed_api_client.py
sfa/dummy/dummyaggregate.py
sfa/dummy/dummydriver.py
sfa/dummy/dummyslices.py

index c205e4b..5436cfe 100644 (file)
@@ -19,8 +19,8 @@ STEP-BY-STEP GUIDE :
 # sfa-config-tty
 Enter command (u for usual changes, w to save, ? for help) u
 == sfa_generic_flavour : [dummy] dummy ("dummy" flavour)
-== sfa_interface_hrn : [pla] pla   (Choose your Authority name)           
-== sfa_registry_root_auth : [pla] pla (Choose your Authority name)
+== sfa_interface_hrn : [pla] topdomain   (Choose your Authority name)           
+== sfa_registry_root_auth : [pla] topdomain (Choose your Authority name)
 == sfa_registry_host : [localhost] localhost
 == sfa_aggregate_host : [localhost] localhost
 == sfa_sm_host : [localhost] localhost
@@ -44,22 +44,27 @@ SFA: Aggregate                                             [  OK  ]
 SFA: SliceMgr                                              [  OK  ]
 Enter command (u for usual changes, w to save, ? for help) q
 
-4. Add your user to the dummy testbed and attach it to a slice:
-
-Edit /usr/lib/python2.7/site-packages/sfa/dummy/dummy_testbed_api_client.py with your user info and run:
-# python /usr/lib/python2.7/site-packages/sfa/dummy/dummy_testbed_api_client.py 
-
 5. Import Dummy testbed data to SFA (users, slices, nodes):
 
 # sfaadmin.py reg import_registry
 
+5. Create a user and a slice:
+
+# sfaadmin.py reg register -t user -x topdomain.dummy.bob -k /root/.ssh/id_rsa.pub -e bob@dummy.net
+# sfaadmin.py reg register -t slice -x topdomain.dummy.bob_slice -r topdomain.dummy.bob
+
 6. Configure you SFI client (http://svn.planet-lab.org/wiki/SFATutorialConfigureSFA#ConfigureSFAClientSFI)
+Example of sfi_config:
+[sfi]
+auth = topdomain.dummy
+user = topdomain.dummy.bob
+registry = http://localhost:12345/
+sm = http://localhost:12346/
 
 7. Make a test: 
 update the following command with your already configured Authority name. 
 
-# sfi.py list pla.dummy 
+# sfi.py list topdomain.dummy 
 
 8. Now continue testing SFA, have a look at the dummy driver code and write your testbed driver for SFA... Enjoy.
 
index f37e52c..2673166 100644 (file)
@@ -32,7 +32,7 @@ def FilterList(myfilter, mylist):
              if 'ids' in key:
                  pass
              else:
-                 if myfilter[key] != item[key]:
+                 if isinstance(myfilter[key], str) and myfilter[key] != item[key] or isinstance(myfilter[key], list) and item[key] not in myfilter[key]:
                      result.remove(item)
                      break
     return result
index e32c15b..38ba0d3 100644 (file)
@@ -5,11 +5,12 @@ import time
 dummy_url = "http://localhost:8080"
 dummy_api = xmlrpclib.ServerProxy(dummy_url)
 
-# Edit the parameters with your user info:
+# Add a user:
 my_user_id = dummy_api.AddUser({'email': 'john.doe@test.net', 'user_name': 'john.doe', 'keys': ['copy here your ssh-rsa public key']})
-# Your user will be attached with the slice named : slice2 :
+# Attach the user with the slice named : slice2 :
 dummy_api.AddUserToSlice({'slice_id': 2, 'user_id': my_user_id})
 
-
-print dummy_api.GetUsers()[-1]
-print dummy_api.GetSlices()[-1]
+# Display the list of users
+print dummy_api.GetUsers()
+# Display the list of slices
+print dummy_api.GetSlices()
index 4630033..dca47b5 100644 (file)
@@ -19,6 +19,8 @@ from sfa.rspecs.version_manager import VersionManager
 
 from sfa.dummy.dummyxrn import DummyXrn, hostname_to_urn, hrn_to_dummy_slicename, slicename_to_hrn
 
+from sfa.storage.alchemy import dbsession
+from sfa.storage.model import SliverAllocation
 import time
 
 class DummyAggregate:
@@ -51,76 +53,215 @@ class DummyAggregate:
 
         return (slice, slivers)
 
-    def get_nodes(self, slice_xrn, slice=None,slivers=[], options={}):
-        # if we are dealing with a slice that has no node just return 
-        # and empty list    
-        if slice_xrn:
-            if not slice or 'node_ids' not in slice.keys() or not slice['node_ids']:
-                return []
+    def get_nodes(self, options={}):
+        filter = {}
+        nodes = self.driver.shell.GetNodes(filter)
+        return nodes
+
+    def get_slivers(self, urns, options={}):
+        slice_names = set()
+        slice_ids = set()
+        node_ids = []
+        for urn in urns:
+            xrn = DummyXrn(xrn=urn)
+            if xrn.type == 'sliver':
+                 # id: slice_id-node_id
+                try:
+                    sliver_id_parts = xrn.get_sliver_id_parts()
+                    slice_id = int(sliver_id_parts[0])
+                    node_id = int(sliver_id_parts[1])
+                    slice_ids.add(slice_id)
+                    node_ids.append(node_id)
+                except ValueError:
+                    pass
+            else:
+                slice_names.add(xrn.dummy_slicename())
 
         filter = {}
-        if slice and 'node_ids' in slice and slice['node_ids']:
-            filter['node_ids'] = slice['node_ids']
+        if slice_names:
+            filter['slice_name'] = list(slice_names)
+        if slice_ids:
+            filter['slice_id'] = list(slice_ids)
+        # get slices
+        slices = self.driver.shell.GetSlices(filter)
+        if not slices:
+            return []
+        slice = slices[0]
+        slice['hrn'] = DummyXrn(auth=self.driver.hrn, slicename=slice['slice_name']).hrn
+
+        # get sliver users
+        users = []
+        user_ids = []
+        for slice in slices:
+            user_ids.extend(slice['user_ids'])
+        if user_ids:
+            users = self.driver.shell.GetUsers({'user_ids': user_ids})
+
+        # construct user key info
+        users_list = []
+        for user in users:
+            name = user['email'][0:user['email'].index('@')]
+            user = {
+                'login': slice['slice_name'],
+                'user_urn': Xrn('%s.%s' % (self.driver.hrn, name), type='user').urn,
+                'keys': user['keys']
+            }
+            users_list.append(user)
+
+        if node_ids:
+            node_ids = [node_id for node_id in node_ids if node_id in slice['node_ids']]
+            slice['node_ids'] = node_ids
+        nodes_dict = self.get_slice_nodes(slice, options)
+        slivers = []
+        for node in nodes_dict.values():
+            node.update(slice)
+            sliver_hrn = '%s.%s-%s' % (self.driver.hrn, slice['slice_id'], node['node_id'])
+            node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
+            node['urn'] = node['sliver_id']
+            node['services_user'] = users
+            slivers.append(node)
+        return slivers
+
+    def node_to_rspec_node(self, node, options={}):
+        rspec_node = NodeElement()
+        site=self.driver.testbedInfo
+        rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site['name'], node['hostname'])
+        rspec_node['component_name'] = node['hostname']
+        rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
+        rspec_node['authority_id'] = hrn_to_urn(DummyXrn.site_hrn(self.driver.hrn, site['name']), 'authority+sa')
+        #distinguish between Shared and Reservable nodes
+        rspec_node['exclusive'] = 'false'
 
+        rspec_node['hardware_types'] = [HardwareType({'name': 'dummy-pc'}),
+                                        HardwareType({'name': 'pc'})]
+        if site['longitude'] and site['latitude']:
+            location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
+            rspec_node['location'] = location
+        return rspec_node
+
+    def sliver_to_rspec_node(self, sliver, sliver_allocations):
+        rspec_node = self.node_to_rspec_node(sliver)
+        rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
+        # add sliver info
+        rspec_sliver = Sliver({'sliver_id': sliver['urn'],
+                         'name': sliver['slice_name'],
+                         'type': 'dummy-vserver',
+                         'tags': []})
+        rspec_node['sliver_id'] = rspec_sliver['sliver_id']
+        if sliver['urn'] in sliver_allocations:
+            rspec_node['client_id'] = sliver_allocations[sliver['urn']].client_id
+            if sliver_allocations[sliver['urn']].component_id:
+                rspec_node['component_id'] = sliver_allocations[sliver['urn']].component_id
+        rspec_node['slivers'] = [rspec_sliver]
+
+        # slivers always provide the ssh service
+        login = Login({'authentication': 'ssh-keys',
+                       'hostname': sliver['hostname'],
+                       'port':'22',
+                       'username': sliver['slice_name'],
+                       'login': sliver['slice_name']
+                      })
+        return rspec_node
+
+    def get_slice_nodes(self, slice, options={}):
+        nodes_dict = {}
+        filter = {}
+        if slice and slice.get('node_ids'):
+            filter['node_ids'] = slice['node_ids']
+        else:
+            # there are no nodes to look up
+            return nodes_dict
         nodes = self.driver.shell.GetNodes(filter)
-        
+        for node in nodes:
+            nodes_dict[node['node_id']] = node
+        return nodes_dict
+
+    def rspec_node_to_geni_sliver(self, rspec_node, sliver_allocations = {}):
+        if rspec_node['sliver_id'] in sliver_allocations:
+            # set sliver allocation and operational status
+            sliver_allocation = sliver_allocations[rspec_node['sliver_id']]
+            if sliver_allocation:
+                allocation_status = sliver_allocation.allocation_state
+                if allocation_status == 'geni_allocated':
+                    op_status =  'geni_pending_allocation'
+                elif allocation_status == 'geni_provisioned':
+                    op_status = 'geni_ready'
+                else:
+                    op_status = 'geni_unknown'
+            else:
+                allocation_status = 'geni_unallocated'
+        else:
+            allocation_status = 'geni_unallocated'
+            op_status = 'geni_failed'
+        # required fields
+        geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
+                       'geni_expires': rspec_node['expires'],
+                       'geni_allocation_status' : allocation_status,
+                       'geni_operational_status': op_status,
+                       'geni_error': '',
+                       }
+        return geni_sliver
+
+    def list_resources(self, version = None, options={}):
+
+        version_manager = VersionManager()
+        version = version_manager.get_version(version)
+        rspec_version = version_manager._get_version(version.type, version.version, 'ad')
+        rspec = RSpec(version=rspec_version, user_options=options)
+
+        # get nodes
+        nodes  = self.get_nodes(options)
+        nodes_dict = {}
+        for node in nodes:
+            nodes_dict[node['node_id']] = node
+
+        # convert nodes to rspec nodes
         rspec_nodes = []
         for node in nodes:
-            rspec_node = NodeElement()
-            # xxx how to retrieve site['login_base']
-            site=self.driver.testbedInfo
-            rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site['name'], node['hostname'])
-            rspec_node['component_name'] = node['hostname']
-            rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
-            rspec_node['authority_id'] = hrn_to_urn(DummyXrn.site_hrn(self.driver.hrn, site['name']), 'authority+sa')
-            rspec_node['exclusive'] = 'false'
-            rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
-                                            HardwareType({'name': 'pc'})]
-             # add site/interface info to nodes.
-            # assumes that sites, interfaces and tags have already been prepared.
-            if site['longitude'] and site['latitude']:  
-                location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
-                rspec_node['location'] = location
-
-            if node['node_id'] in slivers:
-                # add sliver info
-                sliver = slivers[node['node_id']]
-                rspec_node['client_id'] = node['hostname']
-                rspec_node['slivers'] = [sliver]
-                
-                # slivers always provide the ssh service
-                login = Login({'authentication': 'ssh-keys', 'hostname': node['hostname'], 'port':'22', 'username': slice['slice_name']})
-                service = ServicesElement({'login': login})
-                rspec_node['services'] = [service]
+            rspec_node = self.node_to_rspec_node(node)
             rspec_nodes.append(rspec_node)
-        return rspec_nodes
-             
+        rspec.version.add_nodes(rspec_nodes)
 
-    
-    def get_rspec(self, slice_xrn=None, version = None, options={}):
+        return rspec.toxml()
 
+    def describe(self, urns, version=None, options={}):
         version_manager = VersionManager()
         version = version_manager.get_version(version)
-        if not slice_xrn:
-            rspec_version = version_manager._get_version(version.type, version.version, 'ad')
+        rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
+        rspec = RSpec(version=rspec_version, user_options=options)
+
+        # get slivers
+        geni_slivers = []
+        slivers = self.get_slivers(urns, options)
+        if slivers:
+            rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
         else:
-            rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
+            rspec_expires = datetime_to_string(utcparse(time.time()))
+        rspec.xml.set('expires',  rspec_expires)
 
-        slice, slivers = self.get_slice_and_slivers(slice_xrn)
-        rspec = RSpec(version=rspec_version, user_options=options)
-        if slice and 'expires' in slice:
-            rspec.xml.set('expires',  datetime_to_string(utcparse(slice['expires'])))
-
-        nodes = self.get_nodes(slice_xrn, slice, slivers, options)
-        rspec.version.add_nodes(nodes)
-        # add sliver defaults
-        default_sliver = slivers.get(None, [])
-        if default_sliver:
-            default_sliver_attribs = default_sliver.get('tags', [])
-            for attrib in default_sliver_attribs:
-                 logger.info(attrib)
-                 rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
-        
-        return rspec.toxml()
+        # lookup the sliver allocations
+        geni_urn = urns[0]
+        sliver_ids = [sliver['sliver_id'] for sliver in slivers]
+        constraint = SliverAllocation.sliver_id.in_(sliver_ids)
+        sliver_allocations = dbsession.query(SliverAllocation).filter(constraint)
+        sliver_allocation_dict = {}
+        for sliver_allocation in sliver_allocations:
+            geni_urn = sliver_allocation.slice_urn
+            sliver_allocation_dict[sliver_allocation.sliver_id] = sliver_allocation
+
+        # add slivers
+        nodes_dict = {}
+        for sliver in slivers:
+            nodes_dict[sliver['node_id']] = sliver
+        rspec_nodes = []
+        for sliver in slivers:
+            rspec_node = self.sliver_to_rspec_node(sliver, sliver_allocation_dict)
+            rspec_nodes.append(rspec_node)
+            geni_sliver = self.rspec_node_to_geni_sliver(rspec_node, sliver_allocation_dict)
+            geni_slivers.append(geni_sliver)
+        rspec.version.add_nodes(rspec_nodes)
 
+        return {'geni_urn': geni_urn,
+                'geni_rspec': rspec.toxml(),
+                'geni_slivers': geni_slivers}
 
index ab2053d..0d0514e 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
@@ -12,11 +12,11 @@ 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
 
@@ -52,6 +52,34 @@ class DummyDriver (Driver):
         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
     ########################################
@@ -382,191 +410,141 @@ class DummyDriver (Driver):
 
     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)
-    
+        return {}
+
+    def list_resources (self, version=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})
 
+    def describe(self, urns, version, options={}):
+        aggregate = DummyAggregate(self)
+        return aggregate.describe(urns, version=version, options=options)
     
-        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 status (self, urns, 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={}):
+        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)
+        request_nodes = rspec.version.get_nodes_with_slivers()
+        nodes = slices.verify_slice_nodes(urn, slice, request_nodes)
 
-    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]
+        return aggregate.describe([xrn.get_urn()], version=rspec.version)
+
+    def provision(self, urns, 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]
+        SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned')
+        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={}):
+        # 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
+                SliverAllocation.delete_allocations(sliver_ids)
+            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={}):
+        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={}):
+        # 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={}):
+        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"
index d334aa2..dddf1a6 100644 (file)
@@ -1,3 +1,4 @@
+import time
 from types import StringTypes
 from collections import defaultdict
 
@@ -6,6 +7,8 @@ from sfa.util.sfalogging import logger
 from sfa.util.xrn import Xrn, get_leaf, get_authority, urn_to_hrn
 
 from sfa.rspecs.rspec import RSpec
+from sfa.storage.model import SliverAllocation
+from sfa.storage.alchemy import dbsession
 
 from sfa.dummy.dummyxrn import DummyXrn, hrn_to_dummy_slicename
 
@@ -13,7 +16,6 @@ MAXINT =  2L**31-1
 
 class DummySlices:
 
-
     def __init__(self, driver):
         self.driver = driver
 
@@ -54,21 +56,26 @@ class DummySlices:
 
         return slivers
  
-    def get_sfa_peer(self, xrn):
-        hrn, type = urn_to_hrn(xrn)
-
-        # return the authority for this hrn or None if we are the authority
-        sfa_peer = None
-        slice_authority = get_authority(hrn)
-        site_authority = get_authority(slice_authority)
 
-        if site_authority != self.driver.hrn:
-            sfa_peer = site_authority
+    def verify_slice_nodes(self, slice_urn, slice, rspec_nodes):
+
+        slivers = {}
+        for node in rspec_nodes:
+            hostname = node.get('component_name')
+            client_id = node.get('client_id')
+            component_id = node.get('component_id').strip()
+            if hostname:
+                hostname = hostname.strip()
+            elif component_id:
+                hostname = xrn_to_hostname(component_id)
+            if hostname:
+                slivers[hostname] = {'client_id': client_id, 'component_id': component_id}
+        all_nodes = self.driver.shell.GetNodes()
+        requested_slivers = []
+        for node in all_nodes:
+            if node['hostname'] in slivers.keys():
+                requested_slivers.append(node['node_id'])
 
-        return sfa_peer
-
-
-    def verify_slice_nodes(self, slice, requested_slivers):
         if 'node_ids' not in slice.keys():
             slice['node_ids']=[] 
         nodes = self.driver.shell.GetNodes({'node_ids': slice['node_ids']})
@@ -86,11 +93,25 @@ class DummySlices:
 
         except: 
             logger.log_exc('Failed to add/remove slice from nodes')
-        return nodes
 
+        slices = self.driver.shell.GetSlices({'slice_name': slice['slice_name']})
+        resulting_nodes = self.driver.shell.GetNodes({'node_ids': slices[0]['node_ids']})
+
+        # update sliver allocations
+        for node in resulting_nodes:
+            client_id = slivers[node['hostname']]['client_id']
+            component_id = slivers[node['hostname']]['component_id']
+            sliver_hrn = '%s.%s-%s' % (self.driver.hrn, slice['slice_id'], node['node_id'])
+            sliver_id = Xrn(sliver_hrn, type='sliver').urn
+            record = SliverAllocation(sliver_id=sliver_id, client_id=client_id,
+                                      component_id=component_id,
+                                      slice_urn = slice_urn,
+                                      allocation_state='geni_allocated')
+            record.sync()
+        return resulting_nodes
         
 
-    def verify_slice(self, slice_hrn, slice_record, sfa_peer, options={}):
+    def verify_slice(self, slice_hrn, slice_record, expiration, options={}):
         slicename = hrn_to_dummy_slicename(slice_hrn)
         parts = slicename.split("_")
         login_base = parts[0]
@@ -106,148 +127,40 @@ class DummySlices:
             if slice_record and slice_record.get('expires'):
                 requested_expires = int(datetime_to_epoch(utcparse(slice_record['expires'])))
                 if requested_expires and slice['expires'] != requested_expires:
-                    self.driver.shell.UpdateSlice( {'slice_id': slice['slice_id'], 'fields':{'expires' : requested_expires}})
+                    self.driver.shell.UpdateSlice( {'slice_id': slice['slice_id'], 'fields':{'expires' : expiration}})
        
         return slice
 
-    def verify_users(self, slice_hrn, slice_record, users, sfa_peer, options={}):
+    def verify_users(self, slice_hrn, slice_record, users, options={}):
+        slice_name = hrn_to_dummy_slicename(slice_hrn)
         users_by_email = {}
-        users_dict = {} 
-        users_by_site = {}
         for user in users:
             user['urn'] = user['urn'].lower()
             hrn, type = urn_to_hrn(user['urn'])
             username = get_leaf(hrn)
-            login_base = DummyXrn(xrn=user['urn']).dummy_login_base()
             user['username'] = username
-            user['site'] = login_base
 
             if 'email' in user:
                 user['email'] = user['email'].lower() 
                 users_by_email[user['email']] = user
-                users_dict[user['email']] = user
-            else:
-                users_by_site[user['site']].append(user)
-
+        
         # start building a list of existing users
-        existing_user_ids = []
-        existing_user_ids_filter = []
-        if users_by_email:
-            existing_user_ids_filter.extend(users_by_email.keys())
-        if users_by_site:
-            for login_base in users_by_site:
-                users = users_by_site[login_base]
-                for user in users:     
-                    existing_user_ids_filter.append(user['username']+'@geni.net')              
-        if existing_user_ids_filter:                   
-            # get existing users by email 
-            existing_users = self.driver.shell.GetPersons({'email': existing_user_ids_filter}, 
-                                                        ['person_id', 'key_ids', 'email'])
-            existing_user_ids.extend([user['email'] for user in existing_users])
-       
-        if users_by_site:
-            # get a list of user sites (based on requeste user urns
-            site_list = self.driver.shell.GetSites(users_by_site.keys(), \
-                ['site_id', 'login_base', 'person_ids'])
-            # get all existing users at these sites
-            sites = {}
-            site_user_ids = []
-            for site in site_list:
-                sites[site['site_id']] = site
-                site_user_ids.extend(site['person_ids'])
-
-            existing_site_persons_list = self.driver.shell.GetPersons(site_user_ids,  
-                                                                    ['person_id', 'key_ids', 'email', 'site_ids'])
-
-            # all requested users are either existing users or new (added) users      
-            for login_base in users_by_site:
-                requested_site_users = users_by_site[login_base]
-                for requested_user in requested_site_users:
-                    user_found = False
-                    for existing_user in existing_site_persons_list:
-                        for site_id in existing_user['site_ids']:
-                            if site_id in sites:
-                                site = sites[site_id]
-                                if login_base == site['login_base'] and \
-                                   existing_user['email'].startswith(requested_user['username']+'@'):
-                                    existing_user_ids.append(existing_user['email'])
-                                    requested_user['email'] = existing_user['email']
-                                    users_dict[existing_user['email']] = requested_user
-                                    user_found = True
-                                    break
-                        if user_found:
-                            break
-      
-                    if user_found == False:
-                        fake_email = requested_user['username'] + '@geni.net'
-                        requested_user['email'] = fake_email
-                        users_dict[fake_email] = requested_user
+        existing_users_by_email = {}
+        existing_slice_users_by_email = {}
+        existing_users = self.driver.shell.GetUsers()
+        existing_slice_users_ids = self.driver.shell.GetSlices({'slice_name': slice_name})[0]['user_ids']
+        for user in existing_users:
+            existing_users_by_email[user['email']] = user  
+           if user['user_id'] in existing_slice_users_ids:
+                existing_slice_users_by_email[user['email']] = user
                 
-        # requested slice users        
-        requested_user_ids = users_dict.keys()
-        # existing slice users
-        existing_slice_users_filter = {'person_id': slice_record.get('person_ids', [])}
-        existing_slice_users = self.driver.shell.GetPersons(existing_slice_users_filter,
-                                                          ['person_id', 'key_ids', 'email'])
-        existing_slice_user_ids = [user['email'] for user in existing_slice_users]
-        
-        # users to be added, removed or updated
-        added_user_ids = set(requested_user_ids).difference(existing_user_ids)
-        added_slice_user_ids = set(requested_user_ids).difference(existing_slice_user_ids)
-        removed_user_ids = set(existing_slice_user_ids).difference(requested_user_ids)
-        updated_user_ids = set(existing_slice_user_ids).intersection(requested_user_ids)
-
-        # Remove stale users (only if we are not appending).
-        # Append by default.
-        append = options.get('append', True)
-        if append == False:
-            for removed_user_id in removed_user_ids:
-                self.driver.shell.DeletePersonFromSlice(removed_user_id, slice_record['name'])
-        # update_existing users
-        updated_users_list = [user for user in users_dict.values() if user['email'] in \
-          updated_user_ids]
-        self.verify_keys(existing_slice_users, updated_users_list, options)
-
-        added_persons = []
-        # add new users
-        for added_user_id in added_user_ids:
-            added_user = users_dict[added_user_id]
-            hrn, type = urn_to_hrn(added_user['urn'])  
-            person = {
-                'first_name': added_user.get('first_name', hrn),
-                'last_name': added_user.get('last_name', hrn),
-                'email': added_user_id,
-                'peer_person_id': None,
-                'keys': [],
-                'key_ids': added_user.get('key_ids', []),
-            }
-            person['person_id'] = self.driver.shell.AddPerson(person)
-            added_persons.append(person)
-           
-            # enable the account 
-            self.driver.shell.UpdatePerson(person['person_id'], {'enabled': True})
-            
-            # add person to site
-            self.driver.shell.AddPersonToSite(added_user_id, added_user['site'])
-
-            for key_string in added_user.get('keys', []):
-                key = {'key':key_string, 'key_type':'ssh'}
-                key['key_id'] = self.driver.shell.AddPersonKey(person['person_id'], key)
-                person['keys'].append(key)
-
-            # add the registry record
-#            if sfa_peer:
-#                peer_dict = {'type': 'user', 'hrn': hrn, 'peer_authority': sfa_peer, \
-#                    'pointer': person['person_id']}
-#                self.registry.register_peer_object(self.credential, peer_dict)
-    
-        for added_slice_user_id in added_slice_user_ids.union(added_user_ids):
-            # add person to the slice 
-            self.driver.shell.AddPersonToSlice(added_slice_user_id, slice_record['name'])
-            # if this is a peer record then it should already be bound to a peer.
-            # no need to return worry about it getting bound later 
-
-        return added_persons
+        add_users_by_email = set(users_by_email).difference(existing_slice_user_by_email)
+        delete_users_by_email = set(existing_slice_user_by_email).difference(users_by_email)
+        try:
+            for user in add_users_by_email: 
+                self.driver.shell.AddUser()
+        except: 
+            pass
             
 
     def verify_keys(self, old_users, new_users, options={}):
@@ -284,4 +197,3 @@ class DummySlices:
                  except:
                      pass   
 
-