X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sfa%2Fmanagers%2Faggregate_manager_eucalyptus.py;h=68669bd97d25995621b28565ecbd355fb8f82772;hb=7841ee3ce022c84fcf9a8ea17ce12d52e36b3aaa;hp=a38a6e85e8538e8b00ed167096d8d3b179c08f6b;hpb=4acf5e0267df502cbc118172b154e32d8d16fa65;p=sfa.git diff --git a/sfa/managers/aggregate_manager_eucalyptus.py b/sfa/managers/aggregate_manager_eucalyptus.py index a38a6e85..68669bd9 100644 --- a/sfa/managers/aggregate_manager_eucalyptus.py +++ b/sfa/managers/aggregate_manager_eucalyptus.py @@ -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,14 @@ 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 +from sfa.trust.credential import Credential +from sfa.plc.api import SfaAPI +from sfa.util.plxrn import hrn_to_pl_slicename, slicename_to_hrn +from sfa.util.callids import Callids ## # The data structure used to represent a cloud. @@ -28,6 +32,10 @@ cloud = {} # EUCALYPTUS_RSPEC_SCHEMA='/etc/sfa/eucalyptus.rng' +# Quick hack +sys.stderr = file('/var/log/euca_agg.log', 'a+') +api = SfaAPI() + ## # A representation of an Eucalyptus instance. This is a support class # for instance <-> slice mapping. @@ -45,8 +53,9 @@ class EucaInstance(SQLObject): # Contacts Eucalyptus and tries to reserve this instance. # # @param botoConn A connection to Eucalyptus. + # @param pubKeys A list of public keys for the instance. # - def reserveInstance(self, botoConn): + def reserveInstance(self, botoConn, pubKeys): print >>sys.stderr, 'Reserving an instance: image: %s, kernel: ' \ '%s, ramdisk: %s, type: %s, key: %s' % \ (self.image_id, self.kernel_id, self.ramdisk_id, @@ -60,7 +69,8 @@ class EucaInstance(SQLObject): kernel_id = self.kernel_id, ramdisk_id = self.ramdisk_id, instance_type = self.inst_type, - key_name = self.key_pair) + key_name = self.key_pair, + user_data = pubKeys) for instance in reservation.instances: self.instance_id = instance.id @@ -103,6 +113,16 @@ def init_server(): cloudURL = cloudURL.replace('http://', '') (cloud['ip'], parts) = cloudURL.split(':') + # Create image bundles + images = getEucaConnection().get_all_images() + cloud['images'] = images + cloud['imageBundles'] = {} + for i in images: + if i.type != 'machine' or i.kernel_id is None: continue + name = os.path.dirname(i.location) + detail = {'imageID' : i.id, 'kernelID' : i.kernel_id, 'ramdiskID' : i.ramdisk_id} + cloud['imageBundles'][name] = detail + # Initialize sqlite3 database. dbPath = '/etc/sfa/db' dbName = 'euca_aggregate.db' @@ -163,6 +183,42 @@ def getEucaConnection(): port=eucaPort, path=srvPath) +## +# Returns a string of keys that belong to the users of the given slice. +# @param sliceHRN The hunman readable name of the slice. +# @return sting() +# +def getKeysForSlice(sliceHRN): + try: + # convert hrn to slice name + plSliceName = hrn_to_pl_slicename(sliceHRN) + except IndexError, e: + print >>sys.stderr, 'Invalid slice name (%s)' % sliceHRN + return [] + + # Get the slice's information + sliceData = api.plshell.GetSlices(api.plauth, {'name':plSliceName}) + if not sliceData: + print >>sys.stderr, 'Cannot get any data for slice %s' % plSliceName + return [] + + # It should only return a list with len = 1 + sliceData = sliceData[0] + + keys = [] + person_ids = sliceData['person_ids'] + if not person_ids: + print >>sys.stderr, 'No users in slice %s' % sliceHRN + return [] + + persons = api.plshell.GetPersons(api.plauth, person_ids) + for person in persons: + pkeys = api.plshell.GetKeys(api.plauth, person['key_ids']) + for key in pkeys: + keys.append(key['key']) + + return ''.join(keys) + ## # A class that builds the RSpec for Eucalyptus. # @@ -230,8 +286,6 @@ class EucaRSpecBuilder(object): xml << str(inst[4]) with xml.disk_space(unit='GB'): xml << str(inst[5]) - if inst[0] == 'm1.small': - self.__requestXML(1, 'emi-88760F45', 'eki-F26610C6', 'cortex') if 'instances' in cloud and inst[0] in cloud['instances']: existingEucaInstances = cloud['instances'][inst[0]] with xml.euca_instances: @@ -241,8 +295,13 @@ class EucaRSpecBuilder(object): xml << eucaInst['state'] with xml.public_dns: xml << eucaInst['public_dns'] - with xml.keypair: - xml << eucaInst['key'] + + def __imageBundleXML(self, bundles): + xml = self.eucaRSpec + with xml.bundles: + for bundle in bundles.keys(): + with xml.bundle(id=bundle): + xml << '' ## # Creates the Images stanza. @@ -289,8 +348,9 @@ class EucaRSpecBuilder(object): with xml.cloud(id=cloud['name']): with xml.ipv4: xml << cloud['ip'] - self.__keyPairsXML(cloud['keypairs']) - self.__imagesXML(cloud['images']) + #self.__keyPairsXML(cloud['keypairs']) + #self.__imagesXML(cloud['images']) + self.__imageBundleXML(cloud['imageBundles']) self.__clustersXML(cloud['clusters']) return str(xml) @@ -334,9 +394,18 @@ class ZoneResultParser(object): return clusterList -def get_rspec(api, xrn, origin_hrn): +def ListResources(api, creds, options, call_id): + if Callids().already_handled(call_id): return "" global cloud - hrn = urn_to_hrn(xrn)[0] + # get slice's hrn from options + xrn = options.get('geni_slice_urn', '') + 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: @@ -353,6 +422,12 @@ def get_rspec(api, xrn, origin_hrn): # Images images = conn.get_all_images() cloud['images'] = images + cloud['imageBundles'] = {} + for i in images: + if i.type != 'machine' or i.kernel_id is None: continue + name = os.path.dirname(i.location) + detail = {'imageID' : i.id, 'kernelID' : i.kernel_id, 'ramdiskID' : i.ramdisk_id} + cloud['imageBundles'][name] = detail # Key Pairs keyPairs = conn.get_all_key_pairs() @@ -365,17 +440,26 @@ 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) - # Construct a dictory for the EucaRSpecBuilder + # Construct a dictionary for the EucaRSpecBuilder instancesDict = {} for instance in instances: instList = instancesDict.setdefault(instance.instance_type, []) @@ -396,19 +480,26 @@ 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 CreateSliver(api, xrn, creds, xml, users, call_id): + if Callids().already_handled(call_id): return "" + global cloud hrn = urn_to_hrn(xrn)[0] conn = getEucaConnection() if not conn: print >>sys.stderr, 'Error: Cannot create a connection to Eucalyptus' - return False + return "" # Validate RSpec schemaXML = ET.parse(EUCALYPTUS_RSPEC_SCHEMA) @@ -443,20 +534,24 @@ def create_slice(api, xrn, xml): # Process new instance requests requests = rspecXML.findall('.//request') + if requests: + # Get all the public keys associate with slice. + pubKeys = getKeysForSlice(s.slice_hrn) + print >>sys.stderr, "Passing the following keys to the instance:\n%s" % pubKeys + sys.stderr.flush() for req in requests: vmTypeElement = req.getparent() instType = vmTypeElement.get('name') numInst = int(req.find('instances').text) - instKernel = req.find('kernel_image').get('id') - instDiskImg = req.find('disk_image').get('id') - instKey = req.find('keypair').text - ramDiskElement = req.find('ramdisk') - ramDiskAttr = ramDiskElement.attrib - if 'id' in ramDiskAttr: - instRamDisk = ramDiskAttr['id'] - else: - instRamDisk = None + bundleName = req.find('bundle').text + if not cloud['imageBundles'][bundleName]: + print >>sys.stderr, 'Cannot find bundle %s' % bundleName + bundleInfo = cloud['imageBundles'][bundleName] + instKernel = bundleInfo['kernelID'] + instDiskImg = bundleInfo['imageID'] + instRamDisk = bundleInfo['ramdiskID'] + instKey = None # Create the instances for i in range(0, numInst): @@ -466,20 +561,23 @@ def create_slice(api, xrn, xml): ramdisk_id = instRamDisk, key_pair = instKey, inst_type = instType) - eucaInst.reserveInstance(conn) + eucaInst.reserveInstance(conn, pubKeys) - return True + # xxx - should return altered rspec + # with enough data for the client to understand what's happened + return 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() + #CreateSliver(None, 'planetcloud.pc.test', theRSpec, 'call-id-cloudtest') - #rspec = get_rspec('euca', 'planetcloud.pc.test', 'planetcloud.pc.marcoy') + #rspec = ListResources('euca', 'planetcloud.pc.test', 'planetcloud.pc.marcoy', 'test_euca') #print rspec + print getKeysForSlice('gc.gc.test1') if __name__ == "__main__": main()