Merge branch 'master' into sqlalchemy
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Wed, 8 Feb 2012 12:59:45 +0000 (13:59 +0100)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Wed, 8 Feb 2012 12:59:45 +0000 (13:59 +0100)
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

14 files changed:
sfa/client/sfi.py
sfa/generic/openstack.py
sfa/importer/openstackimporter.py
sfa/managers/aggregate_manager.py
sfa/managers/registry_manager.py
sfa/openstack/nova_driver.py [moved from sfa/openstack/openstack_driver.py with 84% similarity]
sfa/openstack/nova_shell.py [moved from sfa/openstack/openstack_shell.py with 55% similarity]
sfa/openstack/osaggregate.py
sfa/rspecs/elements/element.py
sfa/rspecs/elements/sliver.py
sfa/rspecs/elements/versions/pgv2DiskImage.py [new file with mode: 0644]
sfa/rspecs/elements/versions/pgv2SliverType.py
sfa/rspecs/elements/versions/sfav1Node.py
sfa/util/xrn.py

index 9ddef9f..e9614e9 100644 (file)
@@ -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         
index 024f291..bac57dc 100644 (file)
@@ -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
 
 
 
index 844980d..2bf1da3 100644 (file)
@@ -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 = {}
index fab2af8..90344ae 100644 (file)
@@ -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 = {
index ddca3ae..f07b561 100644 (file)
@@ -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)
similarity index 84%
rename from sfa/openstack/openstack_driver.py
rename to sfa/openstack/nova_driver.py
index 368b408..404021b 100644 (file)
@@ -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):
similarity index 55%
rename from sfa/openstack/openstack_shell.py
rename to sfa/openstack/nova_shell.py
index a4636ae..214bb7d 100644 (file)
@@ -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')
index 6296d29..60e3d56 100644 (file)
@@ -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
index b288cbb..7f79e81 100644 (file)
@@ -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
index 8dd6542..55a3feb 100644 (file)
@@ -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 (file)
index 0000000..51363de
--- /dev/null
@@ -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
+
index ffa4b41..55091f5 100644 (file)
@@ -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
 
index fdf1eb2..f50e687 100644 (file)
@@ -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)
index fb9e864..f48a377 100644 (file)
@@ -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