checkpointing - in the middle of the move towards xrn vs namespace
[sfa.git] / sfa / managers / aggregate_manager_eucalyptus.py
index 41985ca..3d2018b 100644 (file)
@@ -1,9 +1,7 @@
 from __future__ import with_statement 
-from sfa.util.faults import *
-from sfa.util.namespace import *
-from sfa.util.rspec import RSpec
-from sfa.server.registry import Registries
-from sfa.plc.nodes import *
+
+import sys
+import os
 
 import boto
 from boto.ec2.regioninfo import RegionInfo
@@ -13,8 +11,10 @@ from xmlbuilder import XMLBuilder
 from lxml import etree as ET
 from sqlobject import *
 
-import sys
-import os
+from sfa.util.faults import *
+from sfa.util.xrn import urn_to_hrn
+from sfa.util.rspec import RSpec
+from sfa.server.registry import Registries
 
 ##
 # The data structure used to represent a cloud.
@@ -334,9 +334,17 @@ class ZoneResultParser(object):
 
         return clusterList
 
-def get_rspec(api, xrn, origin_hrn):
+def get_rspec(api, creds, options): 
     global cloud
-    hrn = urn_to_hrn(xrn)[0]
+    # get slice's hrn from options
+    xrn = options.get('geni_slice_urn', None)
+    hrn, type = urn_to_hrn(xrn)
+
+    # get hrn of the original caller
+    origin_hrn = options.get('origin_hrn', None)
+    if not origin_hrn:
+        origin_hrn = Credential(string=creds[0]).get_gid_caller().get_hrn()
+
     conn = getEucaConnection()
 
     if not conn:
@@ -365,12 +373,21 @@ def get_rspec(api, xrn, origin_hrn):
             # Get the instances that belong to the given slice from sqlite3
             # XXX use getOne() in production because the slice's hrn is supposed
             # to be unique. For testing, uniqueness is turned off in the db.
-            theSlice = list(Slice.select(Slice.q.slice_hrn == hrn))[-1]
+            # If the slice isn't found in the database, create a record for the 
+            # slice.
+            matchedSlices = list(Slice.select(Slice.q.slice_hrn == hrn))
+            if matchedSlices:
+                theSlice = matchedSlices[-1]
+            else:
+                theSlice = Slice(slice_hrn = hrn)
             for instance in theSlice.instances:
                 instanceId.append(instance.instance_id)
 
             # Get the information about those instances using their ids.
-            reservations = conn.get_all_instances(instanceId)
+            if len(instanceId) > 0:
+                reservations = conn.get_all_instances(instanceId)
+            else:
+                reservations = []
             for reservation in reservations:
                 for instance in reservation.instances:
                     instances.append(instance)
@@ -396,12 +413,17 @@ def get_rspec(api, xrn, origin_hrn):
 
     rspec = EucaRSpecBuilder(cloud).toXML()
 
+    # Remove the instances records so next time they won't 
+    # show up.
+    if 'instances' in cloud:
+        del cloud['instances']
+
     return rspec
 
 """
 Hook called via 'sfi.py create'
 """
-def create_slice(api, xrn, xml):
+def create_slice(api, xrn, creds, xml, users):
     global cloud
     hrn = urn_to_hrn(xrn)[0]
 
@@ -410,12 +432,6 @@ def create_slice(api, xrn, xml):
         print >>sys.stderr, 'Error: Cannot create a connection to Eucalyptus'
         return False
 
-    # Get the slice from db or create one.
-    # XXX: For testing purposes, I'll just create the slice.
-    #s = Slice.select(Slice.q.slice_hrn == hrn).getOne(None)
-    #if s is None:
-    s = Slice(slice_hrn = hrn)
-
     # Validate RSpec
     schemaXML = ET.parse(EUCALYPTUS_RSPEC_SCHEMA)
     rspecValidator = ET.RelaxNG(schemaXML)
@@ -423,9 +439,31 @@ def create_slice(api, xrn, xml):
     if not rspecValidator(rspecXML):
         error = rspecValidator.error_log.last_error
         message = '%s (line %s)' % (error.message, error.line) 
-        raise InvalidRSpec(message)
+        # XXX: InvalidRSpec is new. Currently, I am not working with Trunk code.
+        #raise InvalidRSpec(message)
+        raise Exception(message)
 
-    # Process the RSpec
+    # Get the slice from db or create one.
+    s = Slice.select(Slice.q.slice_hrn == hrn).getOne(None)
+    if s is None:
+        s = Slice(slice_hrn = hrn)
+
+    # Process any changes in existing instance allocation
+    pendingRmInst = []
+    for sliceInst in s.instances:
+        pendingRmInst.append(sliceInst.instance_id)
+    existingInstGroup = rspecXML.findall('.//euca_instances')
+    for instGroup in existingInstGroup:
+        for existingInst in instGroup:
+            if existingInst.get('id') in pendingRmInst:
+                pendingRmInst.remove(existingInst.get('id'))
+    for inst in pendingRmInst:
+        print >>sys.stderr, 'Instance %s will be terminated' % inst
+        dbInst = EucaInstance.select(EucaInstance.q.instance_id == inst).getOne(None)
+        dbInst.destroySelf()
+    conn.terminate_instances(pendingRmInst)
+
+    # Process new instance requests
     requests = rspecXML.findall('.//request')
     for req in requests:
         vmTypeElement = req.getparent()
@@ -457,13 +495,13 @@ def create_slice(api, xrn, xml):
 def main():
     init_server()
 
-    #theRSpec = None
-    #with open(sys.argv[1]) as xml:
-        #theRSpec = xml.read()
-    #create_slice(None, 'planetcloud.pc.test', theRSpec)
+    theRSpec = None
+    with open(sys.argv[1]) as xml:
+        theRSpec = xml.read()
+    create_slice(None, 'planetcloud.pc.test', theRSpec)
 
-    rspec = get_rspec('euca', 'planetcloud.pc.test', 'planetcloud.pc.marcoy')
-    print rspec
+    #rspec = get_rspec('euca', 'planetcloud.pc.test', 'planetcloud.pc.marcoy')
+    #print rspec
 
 if __name__ == "__main__":
     main()