From: Thierry Parmentelat Date: Wed, 8 Feb 2012 12:59:45 +0000 (+0100) Subject: Merge branch 'master' into sqlalchemy X-Git-Tag: sfa-2.1-2~2 X-Git-Url: http://git.onelab.eu/?p=sfa.git;a=commitdiff_plain;h=b7d6a80faf23cb019c74e65c2264e215446f84a3;hp=25dc07a3f55ef5e21c659dcaad5ad7559e8a6896 Merge branch 'master' into sqlalchemy Conflicts: sfa/importer/sfa-import-openstack.py sfa/managers/registry_manager.py sfa/openstack/nova_driver.py sfa/storage/PostgreSQL.py sfa/storage/filter.py trashed changes in PostgreSQL / filter applied changes in sfa-import-openstack.py into openstackimporter.py this is mostly manual so please double check --- diff --git a/sfa/client/sfi.py b/sfa/client/sfi.py index 9ddef9fd..e9614e90 100644 --- a/sfa/client/sfi.py +++ b/sfa/client/sfi.py @@ -1,8 +1,8 @@ -# +# # sfi.py - basic SFA command-line client # the actual binary in sfa/clientbin essentially runs main() # this module is used in sfascan -# +# import sys sys.path.append('.') @@ -12,6 +12,7 @@ import socket import datetime import codecs import pickle +import json from lxml import etree from StringIO import StringIO from optparse import OptionParser @@ -88,16 +89,28 @@ def filter_records(type, records): # save methods -def save_variable_to_file(var, filename, format="text"): - f = open(filename, "w") +def save_raw_to_file(var, filename, format="text", banner=None): + if filename == "-": + # if filename is "-", send it to stdout + f = sys.stdout + else: + f = open(filename, "w") + if banner: + f.write(banner+"\n") if format == "text": f.write(str(var)) elif format == "pickled": f.write(pickle.dumps(var)) + elif format == "json": + if hasattr(json, "dumps"): + f.write(json.dumps(var)) # python 2.6 + else: + f.write(json.write(var)) # python 2.5 else: # this should never happen print "unknown output format", format - + if banner: + f.write('\n'+banner+"\n") def save_rspec_to_file(rspec, filename): if not filename.endswith(".rspec"): @@ -289,13 +302,6 @@ class Sfi: help="output file format ([xml]|xmllist|hrnlist)", default="xml", choices=("xml", "xmllist", "hrnlist")) - if command in ("status", "version"): - parser.add_option("-o", "--output", dest="file", - help="output dictionary to file", metavar="FILE", default=None) - parser.add_option("-F", "--fileformat", dest="fileformat", type="choice", - help="output file format ([text]|pickled)", default="text", - choices=("text","pickled")) - if command in ("delegate"): parser.add_option("-u", "--user", action="store_true", dest="delegate_user", default=False, @@ -323,8 +329,13 @@ class Sfi: help="root registry", metavar="URL", default=None) parser.add_option("-s", "--sliceapi", dest="sm", default=None, metavar="URL", help="slice API - in general a SM URL, but can be used to talk to an aggregate") - parser.add_option("-R", "--raw", dest="raw", action="store_true", default=False, - help="Display raw, unparsed server response") + parser.add_option("-R", "--raw", dest="raw", default=None, + help="Save raw, unparsed server response to a file") + parser.add_option("", "--rawformat", dest="rawformat", type="choice", + help="raw file format ([text]|pickled|json)", default="text", + choices=("text","pickled","json")) + parser.add_option("", "--rawbanner", dest="rawbanner", default=None, + help="text string to write before and after raw output") parser.add_option("-d", "--dir", dest="sfi_dir", help="config & working directory - default is %default", metavar="PATH", default=Sfi.default_sfi_dir()) @@ -644,17 +655,17 @@ class Sfi: else: self.logger.critical("No such registry record file %s"%record) sys.exit(1) - + #========================================================================== # Following functions implement the commands # # Registry-related commands #========================================================================== - + def version(self, options, args): """ - display an SFA server version (GetVersion) + display an SFA server version (GetVersion) or version information about sfi itself """ if options.version_local: @@ -666,10 +677,11 @@ or version information about sfi itself server = self.sliceapi() result = server.GetVersion() version = ReturnValue.get_value(result) - pprinter = PrettyPrinter(indent=4) - pprinter.pprint(version) - if options.file: - save_variable_to_file(version, options.file, options.fileformat) + if self.options.raw: + save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner) + else: + pprinter = PrettyPrinter(indent=4) + pprinter.pprint(version) def list(self, options, args): """ @@ -785,11 +797,11 @@ or version information about sfi itself result = server.ListSlices(creds, *self.ois(server,api_options)) value = ReturnValue.get_value(result) if self.options.raw: - print result + save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner) else: display_list(value) return - + # show rspec for named slice def resources(self, options, args): """ @@ -806,9 +818,9 @@ or with an slice hrn, shows currently provisioned resources creds.append(self.my_credential_string) if options.delegate: creds.append(self.delegate_cred(cred, get_authority(self.authority))) - + # no need to check if server accepts the options argument since the options has - # been a required argument since v1 API + # been a required argument since v1 API api_options = {} # always send call_id to v2 servers api_options ['call_id'] = unique_call_id() @@ -831,18 +843,18 @@ or with an slice hrn, shows currently provisioned resources # just request the version the client wants api_options['geni_rspec_version'] = version_manager.get_version(options.rspec_version).to_dict() else: - api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'} + api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'} else: - api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'} + api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'} result = server.ListResources (creds, api_options) value = ReturnValue.get_value(result) - if options.file is None: - if self.options.raw: - print result - else: - display_rspec(value, options.format) - else: + if self.options.raw: + save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner) + if options.file is not None: save_rspec_to_file(value, options.file) + if (self.options.raw is None) and (options.file is None): + display_rspec(value, options.format) + return def create(self, options, args): @@ -868,8 +880,8 @@ or with an slice hrn, shows currently provisioned resources # delegated_cred = self.delegate_cred(slice_cred, server_version['hrn']) #elif server_version.get('urn'): # delegated_cred = self.delegate_cred(slice_cred, urn_to_hrn(server_version['urn'])) - - # rspec + + # rspec rspec_file = self.get_rspec_file(args[1]) rspec = open(rspec_file).read() @@ -894,8 +906,8 @@ or with an slice hrn, shows currently provisioned resources rspec = RSpecConverter.to_pg_rspec(rspec.toxml(), content_type='request') else: users = sfa_users_arg(user_records, slice_record) - - # do not append users, keys, or slice tags. Anything + + # do not append users, keys, or slice tags. Anything # not contained in this request will be removed from the slice # CreateSliver has supported the options argument for a while now so it should @@ -906,13 +918,13 @@ or with an slice hrn, shows currently provisioned resources result = server.CreateSliver(slice_urn, creds, rspec, users, *self.ois(server, api_options)) value = ReturnValue.get_value(result) - if options.file is None: - if self.options.raw: - print result - else: - print value - else: + if self.options.raw: + save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner) + if options.file is not None: save_rspec_to_file (value, options.file) + if (self.options.raw is None) and (options.file is None): + print value + return value def delete(self, options, args): @@ -938,7 +950,7 @@ or with an slice hrn, shows currently provisioned resources result = server.DeleteSliver(slice_urn, creds, *self.ois(server, api_options ) ) value = ReturnValue.get_value(result) if self.options.raw: - print result + save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner) else: print value return value @@ -966,11 +978,9 @@ or with an slice hrn, shows currently provisioned resources result = server.SliverStatus(slice_urn, creds, *self.ois(server,api_options)) value = ReturnValue.get_value(result) if self.options.raw: - print result + save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner) else: print value - if options.file: - save_variable_to_file(value, options.file, options.fileformat) def start(self, options, args): """ @@ -992,7 +1002,7 @@ or with an slice hrn, shows currently provisioned resources result = server.Start(slice_urn, creds) value = ReturnValue.get_value(result) if self.options.raw: - print result + save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner) else: print value return value @@ -1014,7 +1024,7 @@ or with an slice hrn, shows currently provisioned resources result = server.Stop(slice_urn, creds) value = ReturnValue.get_value(result) if self.options.raw: - print result + save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner) else: print value return value @@ -1037,7 +1047,7 @@ or with an slice hrn, shows currently provisioned resources result = server.reset_slice(creds, slice_urn) value = ReturnValue.get_value(result) if self.options.raw: - print result + save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner) else: print value return value @@ -1064,7 +1074,7 @@ or with an slice hrn, shows currently provisioned resources result = server.RenewSliver(slice_urn, creds, time, *self.ois(server,api_options)) value = ReturnValue.get_value(result) if self.options.raw: - print result + save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner) else: print value return value @@ -1087,7 +1097,7 @@ or with an slice hrn, shows currently provisioned resources result = server.Shutdown(slice_urn, creds) value = ReturnValue.get_value(result) if self.options.raw: - print result + save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner) else: print value return value diff --git a/sfa/generic/openstack.py b/sfa/generic/openstack.py index 024f2914..bac57dc7 100644 --- a/sfa/generic/openstack.py +++ b/sfa/generic/openstack.py @@ -1,10 +1,10 @@ from sfa.generic import Generic import sfa.server.sfaapi -import sfa.openstack.openstack_driver +import sfa.openstack.nova_driver import sfa.managers.registry_manager_openstack +import sfa.managers.aggregate_manager import sfa.managers.slice_manager -import sfa.managers.aggregate_manager_openstack # use pl as a model so we only redefine what's different from sfa.generic.pl import pl @@ -20,11 +20,11 @@ class openstack (pl): def registry_manager_class (self) : return sfa.managers.registry_manager_openstack.RegistryManager def aggregate_manager_class (self) : - return sfa.managers.aggregate_manager_openstack.AggregateManager + return sfa.managers.aggregate_manager.AggregateManager # driver class for server-side services, talk to the whole testbed def driver_class (self): - return sfa.openstack.openstack_driver.OpenstackDriver + return sfa.openstack.nova_driver.NovaDriver diff --git a/sfa/importer/openstackimporter.py b/sfa/importer/openstackimporter.py index 844980de..2bf1da31 100644 --- a/sfa/importer/openstackimporter.py +++ b/sfa/importer/openstackimporter.py @@ -10,7 +10,7 @@ from sfa.trust.certificate import convert_public_key, Keypair from sfa.storage.alchemy import dbsession from sfa.storage.model import RegRecord, RegAuthority, RegUser, RegSlice, RegNode -from sfa.openstack.openstack_shell import OpenstackShell +from sfa.openstack.nova_shell import NovaShell def load_keys(filename): keys = {} @@ -45,7 +45,7 @@ class OpenstackImporter: config = Config () interface_hrn = config.SFA_INTERFACE_HRN root_auth = config.SFA_REGISTRY_ROOT_AUTH - shell = OpenstackShell (config) + shell = NovaShell (config) # create dict of all existing sfa records existing_records = {} diff --git a/sfa/managers/aggregate_manager.py b/sfa/managers/aggregate_manager.py index fab2af88..90344ae5 100644 --- a/sfa/managers/aggregate_manager.py +++ b/sfa/managers/aggregate_manager.py @@ -9,7 +9,6 @@ class AggregateManager: # essentially a union of the core version, the generic version (this code) and # whatever the driver needs to expose def GetVersion(self, api, options): - xrn=Xrn(api.hrn) version = version_core() version_generic = { diff --git a/sfa/managers/registry_manager.py b/sfa/managers/registry_manager.py index ddca3ae5..f07b5615 100644 --- a/sfa/managers/registry_manager.py +++ b/sfa/managers/registry_manager.py @@ -75,8 +75,8 @@ class RegistryManager: rights = api.auth.determine_user_rights(caller_hrn, record.__dict__) # make sure caller has rights to this object if rights.is_empty(): - raise PermissionError(caller_hrn + " has no rights to " + record.hrn) - + raise PermissionError("%s has no rights to %s (%s)" % \ + (caller_hrn, object_hrn, xrn)) object_gid = GID(string=record.gid) new_cred = Credential(subject = object_gid.get_subject()) new_cred.set_gid_caller(caller_gid) diff --git a/sfa/openstack/openstack_driver.py b/sfa/openstack/nova_driver.py similarity index 84% rename from sfa/openstack/openstack_driver.py rename to sfa/openstack/nova_driver.py index 368b4080..404021be 100644 --- a/sfa/openstack/openstack_driver.py +++ b/sfa/openstack/nova_driver.py @@ -17,8 +17,7 @@ from sfa.rspecs.rspec import RSpec # the driver interface, mostly provides default behaviours from sfa.managers.driver import Driver - -from sfa.openstack.openstack_shell import OpenstackShell +from sfa.openstack.nova_shell import NovaShell from sfa.openstack.osaggregate import OSAggregate from sfa.plc.plslices import PlSlices from sfa.util.osxrn import OSXrn @@ -36,19 +35,19 @@ def list_to_dict(recs, key): # can be sent as-is; it takes care of authentication # from the global config # -class OpenstackDriver (Driver): +class NovaDriver (Driver): # the cache instance is a class member so it survives across incoming requests cache = None def __init__ (self, config): Driver.__init__ (self, config) - self.shell = OpenstackShell (config) + self.shell = NovaShell (config) self.cache=None if config.SFA_AGGREGATE_CACHING: - if OpenstackDriver.cache is None: - OpenstackDriver.cache = Cache() - self.cache = OpenstackDriver.cache + if NovaDriver.cache is None: + NovaDriver.cache = Cache() + self.cache = NovaDriver.cache ######################################## ########## registry oriented @@ -122,28 +121,29 @@ class OpenstackDriver (Driver): name = Xrn(record['hrn']).get_leaf() os_record = None if record['type'] == 'user': - os_record = self.shell.user_get(name) + os_record = self.shell.auth_manager.get_user(name) + projects = self.shell.db.project_get_by_user(name) record['slices'] = [self.hrn + "." + proj.name for \ - proj in os_record.projects] - record['roles'] = [role for role in os_record.roles] - keys = self.shell.key_pair_get_all_by_user(name) + proj in projects] + record['roles'] = self.shell.db.user_get_roles(name) + keys = self.shell.db.key_pair_get_all_by_user(name) record['keys'] = [key.public_key for key in keys] elif record['type'] == 'slice': - os_record = self.shell.project_get(name) + os_record = self.shell.auth_manager.get_project(name) record['description'] = os_record.description - record['PI'] = self.hrn + "." + os_record.project_manager + record['PI'] = [self.hrn + "." + os_record.project_manager.name] record['geni_creator'] = record['PI'] - record['researcher'] = [self.hrn + "." + user.name for \ - user in os_record.members] + record['researcher'] = [self.hrn + "." + user for \ + user in os_record.member_ids] else: continue record['geni_urn'] = hrn_to_urn(record['hrn'], record['type']) record['geni_certificate'] = record['gid'] record['name'] = os_record.name - if os_record.created_at is not None: - record['date_created'] = datetime_to_string(utcparse(os_record.created_at)) - if os_record.updated_at is not None: - record['last_updated'] = datetime_to_string(utcparse(os_record.updated_at)) + #if os_record.created_at is not None: + # record['date_created'] = datetime_to_string(utcparse(os_record.created_at)) + #if os_record.updated_at is not None: + # record['last_updated'] = datetime_to_string(utcparse(os_record.updated_at)) return records @@ -199,8 +199,8 @@ class OpenstackDriver (Driver): return slices # get data from db - slices = self.shell.project_get_all() - slice_urns = [OSXrn(name, 'slice').urn for name in slice] + projs = self.shell.auth_manager.get_projects() + slice_urns = [OSXrn(proj.name, 'slice').urn for proj in projs] # cache the result if self.cache: @@ -295,38 +295,20 @@ class OpenstackDriver (Driver): def create_sliver (self, slice_urn, slice_hrn, creds, rspec_string, users, options): - aggregate = PlAggregate(self) - slices = PlSlices(self) - peer = slices.get_peer(slice_hrn) - sfa_peer = slices.get_sfa_peer(slice_hrn) - slice_record=None - if users: - slice_record = users[0].get('slice_record', {}) - + aggregate = OSAggregate(self) + slicename = get_leaf(slice_hrn) + # parse rspec rspec = RSpec(rspec_string) requested_attributes = rspec.version.get_slice_attributes() - # ensure site record exists - site = slices.verify_site(slice_hrn, slice_record, peer, sfa_peer, options=options) # ensure slice record exists - slice = slices.verify_slice(slice_hrn, slice_record, peer, sfa_peer, options=options) + slice = aggregate.verify_slice(slicename, users, options=options) # ensure person records exists - persons = slices.verify_persons(slice_hrn, slice, users, peer, sfa_peer, options=options) - # ensure slice attributes exists - slices.verify_slice_attributes(slice, requested_attributes, options=options) - + persons = aggregate.verify_slice_users(slicename, users, options=options) # add/remove slice from nodes - requested_slivers = [node.get('component_name') for node in rspec.version.get_nodes_with_slivers()] - nodes = slices.verify_slice_nodes(slice, requested_slivers, peer) + slices.verify_instances(slicename, rspec) - # add/remove links links - slices.verify_slice_links(slice, rspec.version.get_link_requests(), nodes) - - # handle MyPLC peer association. - # only used by plc and ple. - slices.handle_peer(site, slice, persons, peer) - return aggregate.get_rspec(slice_xrn=slice_urn, version=rspec.version) def delete_sliver (self, slice_urn, slice_hrn, creds, options): @@ -336,9 +318,9 @@ class OpenstackDriver (Driver): return 1 self.shell.DeleteSliceFromNodes(slicename, slice['node_ids']) - instances = self.shell.instance_get_all_by_project(name) + instances = self.shell.db.instance_get_all_by_project(name) for instance in instances: - self.shell.instance_destroy(instance.instance_id) + self.shell.db.instance_destroy(instance.instance_id) return 1 def renew_sliver (self, slice_urn, slice_hrn, creds, expiration_time, options): @@ -349,14 +331,10 @@ class OpenstackDriver (Driver): def stop_slice (self, slice_urn, slice_hrn, creds): name = OSXrn(xrn=slice_urn).name - slice = self.shell.project_get(name) - if not slice: - return 1 - - self.shell.DeleteSliceFromNodes(slicename, slice['node_ids']) - instances = self.shell.instance_get_all_by_project(name) + slice = self.shell.get_project(name) + instances = self.shell.db.instance_get_all_by_project(name) for instance in instances: - self.shell.instance_stop(instance.instance_id) + self.shell.db.instance_stop(instance.instance_id) return 1 def reset_slice (self, slice_urn, slice_hrn, creds): diff --git a/sfa/openstack/openstack_shell.py b/sfa/openstack/nova_shell.py similarity index 55% rename from sfa/openstack/openstack_shell.py rename to sfa/openstack/nova_shell.py index a4636ae7..214bb7d1 100644 --- a/sfa/openstack/openstack_shell.py +++ b/sfa/openstack/nova_shell.py @@ -4,14 +4,34 @@ import socket from urlparse import urlparse from sfa.util.sfalogging import logger try: - from nova import flags - from nova import context from nova import db - has_nova = True + from nova import flags + from nova import context + from nova.auth.manager import AuthManager + from nova.compute.manager import ComputeManager + from nova.network.manager import NetworkManager + from nova.scheduler.manager import SchedulerManager + from nova.image.glance import GlanceImageService + has_nova = True except: has_nova = False - -class OpenstackShell: + + +class InjectContext: + """ + Wraps the module and injects the context when executing methods + """ + def __init__(self, proxy, context): + self.proxy = proxy + self.context = context + + def __getattr__(self, name): + def func(*args, **kwds): + result=getattr(self.proxy, name)(self.context, *args, **kwds) + return result + return func + +class NovaShell: """ A simple xmlrpc shell to a myplc instance This class can receive all Openstack calls to the underlying testbed @@ -26,6 +46,7 @@ class OpenstackShell: def __init__ ( self, config ) : url = config.SFA_PLC_URL # try to figure if the url is local + is_local=False hostname=urlparse(url).hostname if hostname == 'localhost': is_local=True # otherwise compare IP addresses; @@ -41,19 +62,18 @@ class OpenstackShell: if is_local and has_nova: - logger.debug('openstack access - native') + logger.debug('nova access - native') # load the config flags.FLAGS(['foo', '--flagfile=/etc/nova/nova.conf', 'foo', 'foo']) - self.auth = context.get_admin_context() - self.proxy = db + # instantiate managers + self.auth_manager = AuthManager() + self.compute_manager = ComputeManager() + self.network_manager = NetworkManager() + self.scheduler_manager = SchedulerManager() + self.db = InjectContext(db, context.get_admin_context()) + self.image_manager = InjectContext(GlanceImageService(), context.get_admin_context()) else: self.auth = None self.proxy = None - logger.debug('openstack access - REST') - raise SfaNotImplemented('openstack access - Rest') - - def __getattr__(self, name): - def func(*args, **kwds): - result=getattr(self.proxy, name)(self.auth, *args, **kwds) - return result - return func + logger.debug('nova access - REST') + raise SfaNotImplemented('nova access - Rest') diff --git a/sfa/openstack/osaggregate.py b/sfa/openstack/osaggregate.py index 6296d295..60e3d56d 100644 --- a/sfa/openstack/osaggregate.py +++ b/sfa/openstack/osaggregate.py @@ -1,8 +1,11 @@ + +from sfa.util.faults import SfaAPIError 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.sliver import Sliver from sfa.rspecs.elements.login import Login +from sfa.rspecs.elements.disk_image import DiskImage from sfa.rspecs.elements.services import Services from sfa.util.xrn import Xrn from sfa.util.osxrn import OSXrn @@ -14,28 +17,36 @@ class OSAggregate: self.driver = driver def instance_to_sliver(self, instance, slice_xrn=None): - sliver_id = None - name = None - if slice_xrn: - name = OSXrn(slice_xrn, 'slice').name - sliver_id = xrn.sliver_id(instance.instance_id, "") - - # should include: + # should include? # * instance.image_ref # * instance.kernel_id # * instance.ramdisk_id + import nova.db.sqlalchemy.models name=None - if hasattr(instance, 'name'): - name = instance.name - elif hasattr(instance, 'display_name'): - name = instance.display_name + type=None + sliver_id = None + if isinstance(instance, dict): + # this is an isntance type dict + name = instance['name'] + type = instance['name'] + elif isinstance(instance, nova.db.sqlalchemy.models.Instance): + # this is an object that describes a running instance + name = instance.display_name + type = instance.instance_type.name + else: + raise SfaAPIError("instnace must be an instance_type dict or" + \ + " a nova.db.sqlalchemy.models.Instance object") + if slice_xrn: + xrn = Xrn(slice_xrn, 'slice') + sliver_id = xrn.get_sliver_id(instance.project_id, instance.hostname, instance.id) + sliver = Sliver({'slice_id': sliver_id, 'name': name, - 'type': 'plos-' + instance['name'], + 'type': 'plos-' + type, 'tags': []}) return sliver - def get_rspec(self, slice_xrn=None, vsersion=None, options={}): + def get_rspec(self, slice_xrn=None, version=None, options={}): version_manager = VersionManager() version = version_manager.get_version(version) if not slice_xrn: @@ -44,13 +55,13 @@ class OSAggregate: else: rspec_version = version_manager._get_version(version.type, version.version, 'manifest') nodes = self.get_slice_nodes(slice_xrn) - + rspec = RSpec(version=rspec_version, user_options=options) rspec.version.add_nodes(nodes) return rspec.toxml() def get_slice_nodes(self, slice_xrn): name = OSXrn(xrn = slice_xrn).name - instances = self.driver.shell.instance_get_all_by_project(name) + instances = self.driver.shell.db.instance_get_all_by_project(name) rspec_nodes = [] for instance in instances: rspec_node = Node() @@ -65,12 +76,26 @@ class OSAggregate: def get_aggregate_nodes(self): - zones = self.driver.shell.zone_get_all() + zones = self.driver.shell.db.zone_get_all() if not zones: zones = ['cloud'] else: zones = [zone.name for zone in zones] + # available sliver/instance/vm types + instances = self.driver.shell.db.instance_type_get_all().values() + # available images + images = self.driver.shell.image_manager.detail() + disk_images = [] + for image in images: + if image['container_format'] == 'ami': + img = DiskImage() + img['name'] = image['name'] + img['description'] = image['name'] + img['os'] = image['name'] + img['version'] = image['name'] + disk_images.append(img) + rspec_nodes = [] for zone in zones: rspec_node = Node() @@ -81,9 +106,80 @@ class OSAggregate: rspec_node['exclusive'] = 'false' rspec_node['hardware_types'] = [HardwareType({'name': 'plos-pc'}), HardwareType({'name': 'pc'})] - instances = self.driver.shell.instance_type_get_all().values() - slivers = [self.instance_to_sliver(inst) for inst in instances] + slivers = [] + for instance in instances: + sliver = self.instance_to_sliver(instance) + sliver['disk_images'] = disk_images + slivers.append(sliver) + rspec_node['slivers'] = slivers rspec_nodes.append(rspec_node) - return rspec_node + return rspec_nodes + + + def verify_slice(self, slicename, users, options={}): + """ + Create the slice if it doesn't alredy exist + """ + import nova.exception.ProjectNotFound + try: + slice = self.driver.shell.auth_manager.get_project(slicename) + except nova.exception.ProjectNotFound: + # convert urns to user names + usernames = [Xrn(user['urn']).get_leaf() for user in users] + # assume that the first user is the project manager + proj_manager = usernames[0] + self.driver.shell.auth_manager.create_project(slicename, proj_manager) + + def verify_slice_users(self, slicename, users, options={}): + """ + Add requested users to the specified slice. + """ + + # There doesn't seem to be an effcient way to + # look up all the users of a project, so lets not + # attempt to remove stale users . For now lets just + # ensure that the specified users exist + for user in users: + username = Xrn(user['urn']).get_leaf() + try: + self.driver.shell.auth_manager.get_user(username) + except nova.exception.UserNotFound: + self.driver.shell.auth_manager.create_user(username) + self.verify_user_keys(username, user['keys'], options) + + def verify_user_keys(self, username, keys, options={}): + """ + Add requested keys. + """ + append = options.get('append', True) + existing_keys = self.driver.shell.db.key_pair_get_all_by_user(username) + existing_pub_keys = [key.public_key for key in existing_keys] + removed_pub_keys = set(existing_pub_keys).difference(keys) + added_pub_keys = set(keys).difference(existing_pub_keys) + + # add new keys + for public_key in added_pub_keys: + key = {} + key['user_id'] = username + key['name'] = username + key['public'] = public_key + self.driver.shell.db.key_pair_create(key) + + # remove old keys + if not append: + for key in existing_keys: + if key.public_key in removed_pub_keys: + self.driver.shell.db.key_pair_destroy(username, key.name) + + def verify_instances(self, slicename, rspec): + rsepc = RSpec(rspec) + nodes = rspec.version.get_nodes_with_slivers() + old_instances = self.driver.shell.db.instance_get_all_by_project(name) + for node in nodes: + for slivers in node.get('slivers', []): + pass + # get instance type + # get image + # start instance diff --git a/sfa/rspecs/elements/element.py b/sfa/rspecs/elements/element.py index b288cbbd..7f79e810 100644 --- a/sfa/rspecs/elements/element.py +++ b/sfa/rspecs/elements/element.py @@ -18,4 +18,4 @@ class Element(dict): elif hasattr(self.element, name): return getattr(self.element, name) else: - raise AttributeError, "class Element has not attribute %s" % name + raise AttributeError, "class Element has no attribute %s" % name diff --git a/sfa/rspecs/elements/sliver.py b/sfa/rspecs/elements/sliver.py index 8dd65425..55a3febf 100644 --- a/sfa/rspecs/elements/sliver.py +++ b/sfa/rspecs/elements/sliver.py @@ -8,4 +8,5 @@ class Sliver(Element): 'name', 'type', 'tags', + 'disk_images', ] diff --git a/sfa/rspecs/elements/versions/pgv2DiskImage.py b/sfa/rspecs/elements/versions/pgv2DiskImage.py new file mode 100644 index 00000000..51363de3 --- /dev/null +++ b/sfa/rspecs/elements/versions/pgv2DiskImage.py @@ -0,0 +1,24 @@ +from sfa.rspecs.elements.element import Element +from sfa.rspecs.elements.disk_image import DiskImage + +class PGv2DiskImage: + + @staticmethod + def add_images(xml, images): + if not images: + return + if not isinstance(images, list): + images = [images] + for image in images: + xml.add_instance('disk_image', image, DiskImage.fields) + + @staticmethod + def get_images(xml, filter={}): + xpath = './default:disk_image | ./disk_image' + image_elems = xml.xpath(xpath) + images = [] + for image_elem in image_elems: + image = DiskImage(image_elem.attrib, image_elem) + images.append(image) + return images + diff --git a/sfa/rspecs/elements/versions/pgv2SliverType.py b/sfa/rspecs/elements/versions/pgv2SliverType.py index ffa4b41a..55091f51 100644 --- a/sfa/rspecs/elements/versions/pgv2SliverType.py +++ b/sfa/rspecs/elements/versions/pgv2SliverType.py @@ -1,5 +1,6 @@ from sfa.rspecs.elements.element import Element from sfa.rspecs.elements.sliver import Sliver +from sfa.rspecs.elements.versions.pgv2DiskImage import PGv2DiskImage class PGv2SliverType: @@ -14,7 +15,10 @@ class PGv2SliverType: if sliver.get('type'): sliver_elem.set('name', sliver['type']) if sliver.get('client_id'): - sliver_elem.set('client_id', sliver['client_id']) + sliver_elem.set('client_id', sliver['client_id']) + images = sliver.get('disk_images') + if images and isinstance(images, list): + PGv2DiskImage.add_images(sliver_elem, images) PGv2SliverType.add_sliver_attributes(sliver_elem, sliver.get('tags', [])) @staticmethod @@ -39,6 +43,7 @@ class PGv2SliverType: sliver['component_id'] = xml.attrib['component_id'] if 'name' in sliver_elem.attrib: sliver['type'] = sliver_elem.attrib['name'] + sliver['images'] = PGv2DiskImage.get_images(sliver_elem) slivers.append(sliver) return slivers diff --git a/sfa/rspecs/elements/versions/sfav1Node.py b/sfa/rspecs/elements/versions/sfav1Node.py index fdf1eb2d..f50e6877 100644 --- a/sfa/rspecs/elements/versions/sfav1Node.py +++ b/sfa/rspecs/elements/versions/sfav1Node.py @@ -55,8 +55,9 @@ class SFAv1Node: if location: node_elem.add_instance('location', location, Location.fields) - for interface in node.get('interfaces', []): - node_elem.add_instance('interface', interface, ['component_id', 'client_id', 'ipv4']) + if isinstance(node.get('interfaces'), list): + for interface in node.get('interfaces', []): + node_elem.add_instance('interface', interface, ['component_id', 'client_id', 'ipv4']) #if 'bw_unallocated' in node and node['bw_unallocated']: # bw_unallocated = etree.SubElement(node_elem, 'bw_unallocated', units='kbps').text = str(int(node['bw_unallocated'])/1000) diff --git a/sfa/util/xrn.py b/sfa/util/xrn.py index fb9e864f..f48a3773 100644 --- a/sfa/util/xrn.py +++ b/sfa/util/xrn.py @@ -33,7 +33,7 @@ def hrn_to_urn(hrn,type): return Xrn(hrn, type=type).urn def hrn_authfor_hrn(parenthrn, hrn): return Xrn.hrn_is_auth_for_hrn(parenthrn, hrn) def urn_to_sliver_id(urn, slice_id, node_id, index=0): - return ":".join(map(str, [urn, slice_id, node_id, index])) + return Xrn(urn).get_sliver_id(slice_id, node_id, index) class Xrn: @@ -161,7 +161,11 @@ class Xrn: def get_authority_urn(self): self._normalize() return ':'.join( [Xrn.unescape(x) for x in self.authority] ) - + + def get_sliver_id(self, slice_id, node_id, index=0): + self._normalize() + return ":".join(map(str, [self.get_urn(), slice_id, node_id, index])) + def urn_to_hrn(self): """ compute tuple (hrn, type) from urn