Merge Master in geni-v3 conflict resolution
[sfa.git] / sfa / planetlab / plaggregate.py
index 733638b..c6006fb 100644 (file)
@@ -6,13 +6,13 @@ from sfa.util.sfalogging import logger
 from sfa.util.faults import SliverDoesNotExist
 from sfa.rspecs.rspec import RSpec
 from sfa.rspecs.elements.hardware_type import HardwareType
 from sfa.util.faults import SliverDoesNotExist
 from sfa.rspecs.rspec import RSpec
 from sfa.rspecs.elements.hardware_type import HardwareType
-from sfa.rspecs.elements.node import Node
+from sfa.rspecs.elements.node import NodeElement
 from sfa.rspecs.elements.link import Link
 from sfa.rspecs.elements.sliver import Sliver
 from sfa.rspecs.elements.login import Login
 from sfa.rspecs.elements.location import Location
 from sfa.rspecs.elements.interface import Interface
 from sfa.rspecs.elements.link import Link
 from sfa.rspecs.elements.sliver import Sliver
 from sfa.rspecs.elements.login import Login
 from sfa.rspecs.elements.location import Location
 from sfa.rspecs.elements.interface import Interface
-from sfa.rspecs.elements.services import Services
+from sfa.rspecs.elements.services import ServicesElement
 from sfa.rspecs.elements.pltag import PLTag
 from sfa.rspecs.elements.lease import Lease
 from sfa.rspecs.elements.granularity import Granularity
 from sfa.rspecs.elements.pltag import PLTag
 from sfa.rspecs.elements.lease import Lease
 from sfa.rspecs.elements.granularity import Granularity
@@ -21,6 +21,9 @@ from sfa.rspecs.version_manager import VersionManager
 from sfa.planetlab.plxrn import PlXrn, hostname_to_urn, hrn_to_pl_slicename, slicename_to_hrn
 from sfa.planetlab.vlink import get_tc_rate
 from sfa.planetlab.topology import Topology
 from sfa.planetlab.plxrn import PlXrn, hostname_to_urn, hrn_to_pl_slicename, slicename_to_hrn
 from sfa.planetlab.vlink import get_tc_rate
 from sfa.planetlab.topology import Topology
+from sfa.storage.alchemy import dbsession
+from sfa.storage.model import SliverAllocation
+
 
 import time
 
 
 import time
 
@@ -109,7 +112,7 @@ class PlAggregate:
             pl_initscripts[initscript['initscript_id']] = initscript
         return pl_initscripts
 
             pl_initscripts[initscript['initscript_id']] = initscript
         return pl_initscripts
 
-    def get_slivers(self, urns, options):
+    def get_slivers(self, urns, options={}):
         names = set()
         slice_ids = set()
         node_ids = []
         names = set()
         slice_ids = set()
         node_ids = []
@@ -117,44 +120,89 @@ class PlAggregate:
             xrn = PlXrn(xrn=urn)
             if xrn.type == 'sliver':
                  # id: slice_id-node_id
             xrn = PlXrn(xrn=urn)
             if xrn.type == 'sliver':
                  # id: slice_id-node_id
-                id_parts = xrn.leaf.split('-')
-                slice_ids.add(id_parts[0]) 
-                node_ids.append(id_parts[1])
+                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:  
                 names.add(xrn.pl_slicename())
             else:  
                 names.add(xrn.pl_slicename())
-            if xrn.id:
-                ids.add(xrn.id)
 
         filter = {}
         if names:
             filter['name'] = list(names)
         if slice_ids:
 
         filter = {}
         if names:
             filter['name'] = list(names)
         if slice_ids:
-            filter['slice_id'] = list(slice_ids) 
+            filter['slice_id'] = list(slice_ids)
+        # get slices
         slices = self.driver.shell.GetSlices(filter)
         slices = self.driver.shell.GetSlices(filter)
-        slice = slices[0]
+        if not slices:
+            return []
+        slice = slices[0]     
+        slice['hrn'] = PlXrn(auth=self.driver.hrn, slicename=slice['name']).hrn   
+
+        # get sliver users
+        persons = []
+        person_ids = []
+        for slice in slices:
+            person_ids.extend(slice['person_ids'])
+        if person_ids:
+            persons = self.driver.shell.GetPersons(person_ids)
+                 
+        # get user keys
+        keys = {}
+        key_ids = []
+        for person in persons:
+            key_ids.extend(person['key_ids'])
+        
+        if key_ids:
+            key_list = self.driver.shell.GetKeys(key_ids)
+            for key in key_list:
+                keys[key['key_id']] = key  
+
+        # construct user key info
+        users = []
+        for person in persons:
+            name = person['email'][0:person['email'].index('@')]
+            user = {
+                'login': slice['name'], 
+                'user_urn': Xrn('%s.%s' % (self.driver.hrn, name), type='user').urn,
+                'keys': [keys[k_id]['key'] for k_id in person['key_ids'] if k_id in keys]
+            }
+            users.append(user)
+
         if node_ids:
         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
         tags_dict = self.get_slice_tags(slice)
         nodes_dict = self.get_slice_nodes(slice, options)
         slivers = []
         for node in nodes_dict.values():
             slice['node_ids'] = node_ids
         tags_dict = self.get_slice_tags(slice)
         nodes_dict = self.get_slice_nodes(slice, options)
         slivers = []
         for node in nodes_dict.values():
-            node.update(slices[0]
+            node.update(slice) 
             node['tags'] = tags_dict[node['node_id']]
             sliver_hrn = '%s.%s-%s' % (self.driver.hrn, slice['slice_id'], node['node_id'])
             node['tags'] = tags_dict[node['node_id']]
             sliver_hrn = '%s.%s-%s' % (self.driver.hrn, slice['slice_id'], node['node_id'])
-            node['urn'] = PlXrn(xrn=sliver_hrn, type='sliver').get_urn() 
+            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, sites, interfaces, node_tags, pl_initscripts=[], grain=None, options={}):
             slivers.append(node)
         return slivers
 
     def node_to_rspec_node(self, node, sites, interfaces, node_tags, pl_initscripts=[], grain=None, options={}):
-        rspec_node = Node()
+        rspec_node = NodeElement()
         # xxx how to retrieve site['login_base']
         site=sites[node['site_id']]
         # xxx how to retrieve site['login_base']
         site=sites[node['site_id']]
-        rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], node['hostname'])
+        rspec_node['component_id'] = PlXrn(self.driver.hrn, hostname=node['hostname']).get_urn()
         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(PlXrn.site_hrn(self.driver.hrn, site['login_base']), 'authority+sa')
         # do not include boot state (<available> element) in the manifest rspec
         rspec_node['boot_state'] = node['boot_state']
         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(PlXrn.site_hrn(self.driver.hrn, site['login_base']), 'authority+sa')
         # do not include boot state (<available> element) in the manifest rspec
         rspec_node['boot_state'] = node['boot_state']
+        if node['boot_state'] == 'boot': 
+            rspec_node['available'] = 'true'
+        else:
+            rspec_node['available'] = 'false'
         rspec_node['exclusive'] = 'false'
         rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
                                         HardwareType({'name': 'pc'})]
         rspec_node['exclusive'] = 'false'
         rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
                                         HardwareType({'name': 'pc'})]
@@ -181,11 +229,12 @@ class PlAggregate:
                 interface['client_id'] = "%s:%s" % (node['node_id'], if_id)
             rspec_node['interfaces'].append(interface)
             if_count+=1
                 interface['client_id'] = "%s:%s" % (node['node_id'], if_id)
             rspec_node['interfaces'].append(interface)
             if_count+=1
-        tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids']]
+        tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids'] if tag_id in node_tags]
         rspec_node['tags'] = tags
         return rspec_node
 
         rspec_node['tags'] = tags
         return rspec_node
 
-    def sliver_to_rspec_node(self, sliver, sites, interfaces, node_tags, pl_initscripts):
+    def sliver_to_rspec_node(self, sliver, sites, interfaces, node_tags, \
+                             pl_initscripts, sliver_allocations):
         # get the granularity in second for the reservation system
         grain = self.driver.shell.GetLeaseGranularity()
         rspec_node = self.node_to_rspec_node(sliver, sites, interfaces, node_tags, pl_initscripts, grain)
         # get the granularity in second for the reservation system
         grain = self.driver.shell.GetLeaseGranularity()
         rspec_node = self.node_to_rspec_node(sliver, sites, interfaces, node_tags, pl_initscripts, grain)
@@ -199,12 +248,20 @@ class PlAggregate:
                          'type': 'plab-vserver',
                          'tags': []})
         rspec_node['sliver_id'] = rspec_sliver['sliver_id']
                          'type': 'plab-vserver',
                          'tags': []})
         rspec_node['sliver_id'] = rspec_sliver['sliver_id']
-        rspec_node['client_id'] = sliver['hostname']
+        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
         rspec_node['slivers'] = [rspec_sliver]
 
         # slivers always provide the ssh service
-        login = Login({'authentication': 'ssh-keys', 'hostname': sliver['hostname'], 'port':'22', 'username': sliver['name']})
-        service = Services({'login': login})
+        login = Login({'authentication': 'ssh-keys', 
+                       'hostname': sliver['hostname'], 
+                       'port':'22', 
+                       'username': sliver['name'],
+                       'login': sliver['name']
+                      })
+        service = ServicesElement({'login': login,
+                            'services_user': sliver['services_user']})
         rspec_node['services'] = [service]    
         return rspec_node      
 
         rspec_node['services'] = [service]    
         return rspec_node      
 
@@ -236,25 +293,37 @@ class PlAggregate:
             nodes_dict[node['node_id']] = node
         return nodes_dict
 
             nodes_dict[node['node_id']] = node
         return nodes_dict
 
-    def rspec_node_to_geni_sliver(self, rspec_node):
-        op_status = "geni_unknown"
-        state = rspec_node['boot_state'].lower()
-        if state == 'boot':
-            op_status = 'geni_ready'
-        else:
-            op_status =' geni_failed'
-
+    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':
+                    if rspec_node['boot_state'] == 'boot':
+                        op_status = 'geni_ready'
+                    else:
+                        op_status = 'geni_failed'
+                else:
+                    op_status = 'geni_unknown'
+            else:
+                allocation_status = 'geni_unallocated'    
         # required fields
         geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
                        'geni_expires': rspec_node['expires'],
         # required fields
         geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
                        'geni_expires': rspec_node['expires'],
-                       'geni_allocation_status': 'geni_provisioned',
+                       'geni_allocation_status' : allocation_status,
                        'geni_operational_status': op_status,
                        'geni_operational_status': op_status,
-                       'geni_error': None,
+                       'geni_error': '',
                        }
         return geni_sliver        
 
                        }
         return geni_sliver        
 
-    def get_leases(self, slice=None, options={}):
+    def get_leases(self, slice_xrn=None, slice=None, options={}):
         
         
+        if slice_xrn and not slice:
+            return []
+
         now = int(time.time())
         filter={}
         filter.update({'clip':now})
         now = int(time.time())
         filter={}
         filter.update({'clip':now})
@@ -280,10 +349,13 @@ class PlAggregate:
             site_id=lease['site_id']
             site=sites_dict[site_id]
 
             site_id=lease['site_id']
             site=sites_dict[site_id]
 
-            rspec_lease['lease_id'] = lease['lease_id']
             rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], lease['hostname'])
             rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], lease['hostname'])
-            slice_hrn = slicename_to_hrn(self.driver.hrn, lease['name'])
-            slice_urn = hrn_to_urn(slice_hrn, 'slice')
+            if slice_xrn:
+                slice_urn = slice_xrn
+                slice_hrn = urn_to_hrn(slice_urn)
+            else:
+                slice_hrn = slicename_to_hrn(self.driver.hrn, lease['name'])
+                slice_urn = hrn_to_urn(slice_hrn, 'slice')
             rspec_lease['slice_id'] = slice_urn
             rspec_lease['start_time'] = lease['t_from']
             rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) / grain
             rspec_lease['slice_id'] = slice_urn
             rspec_lease['start_time'] = lease['t_from']
             rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) / grain
@@ -324,20 +396,37 @@ class PlAggregate:
             # add links
             links = self.get_links(sites, nodes_dict, interfaces)        
             rspec.version.add_links(links)
             # add links
             links = self.get_links(sites, nodes_dict, interfaces)        
             rspec.version.add_links(links)
+
+        if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'resources':
+           leases = self.get_leases(slice_xrn, slice)
+           rspec.version.add_leases(leases)
+
         return rspec.toxml()
 
     def describe(self, urns, version=None, options={}):
         version_manager = VersionManager()
         version = version_manager.get_version(version)
         rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
         return rspec.toxml()
 
     def describe(self, urns, version=None, options={}):
         version_manager = VersionManager()
         version = version_manager.get_version(version)
         rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
-        rspec = RSpec(version=version, user_options=options)
+        rspec = RSpec(version=rspec_version, user_options=options)
 
         # get slivers
         geni_slivers = []
 
         # get slivers
         geni_slivers = []
-        slivers = self.get_slivers(urns, options) 
-        if len(slivers) == 0:
-            raise SliverDoesNotExist("You have not allocated any slivers here")
-        rspec.xml.set('expires',  datetime_to_string(utcparse(slivers[0]['expires'])))
+        slivers = self.get_slivers(urns, options)
+        if slivers:
+            rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
+        else:
+            rspec_expires = datetime_to_string(utcparse(time.time()))      
+        rspec.xml.set('expires',  rspec_expires)
+
+        # 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
       
         if not options.get('list_leases') or options['list_leases'] != 'leases':
             # add slivers
       
         if not options.get('list_leases') or options['list_leases'] != 'leases':
             # add slivers
@@ -358,9 +447,12 @@ class PlAggregate:
             for sliver in slivers:
                 if sliver['slice_ids_whitelist'] and sliver['slice_id'] not in sliver['slice_ids_whitelist']:
                     continue
             for sliver in slivers:
                 if sliver['slice_ids_whitelist'] and sliver['slice_id'] not in sliver['slice_ids_whitelist']:
                     continue
-                rspec_node = self.sliver_to_rspec_node(sliver, sites, interfaces, node_tags, pl_initscripts)
-                geni_sliver = self.rspec_node_to_geni_sliver(rspec_node)
+                rspec_node = self.sliver_to_rspec_node(sliver, sites, interfaces, node_tags, 
+                                                       pl_initscripts, sliver_allocation_dict)
+                # manifest node element shouldn't contain available attribute
+                rspec_node.pop('available')
                 rspec_nodes.append(rspec_node) 
                 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)
 
                 geni_slivers.append(geni_sliver)
             rspec.version.add_nodes(rspec_nodes)
 
@@ -376,10 +468,11 @@ class PlAggregate:
             rspec.version.add_links(links)
 
         if not options.get('list_leases') or options['list_leases'] != 'resources':
             rspec.version.add_links(links)
 
         if not options.get('list_leases') or options['list_leases'] != 'resources':
-            leases = self.get_leases(slivers[0])
-            rspec.version.add_leases(leases)
+            if slivers:
+                leases = self.get_leases(slivers[0])
+                rspec.version.add_leases(leases)
 
                
 
                
-        return {'geni_urn': urns[0]
+        return {'geni_urn': geni_urn
                 'geni_rspec': rspec.toxml(),
                 'geni_slivers': geni_slivers}
                 'geni_rspec': rspec.toxml(),
                 'geni_slivers': geni_slivers}