From 2e1257f7ceb81a208916b3a65eeb084b47fb56d7 Mon Sep 17 00:00:00 2001
From: Mahendra M <mahendra.m@gmail.com>
Date: Wed, 7 Nov 2012 18:26:59 +0530
Subject: [PATCH] LIBCLOUD-255 : Driver registration and handling improvements

---
 libcloud/common/gandi.py               |    2 +-
 libcloud/compute/base.py               |    2 +-
 libcloud/compute/drivers/opennebula.py |    2 +-
 libcloud/compute/providers.py          |    4 ++
 libcloud/compute/types.py              |   98 ++++++++++++++++----------------
 libcloud/dns/providers.py              |    4 ++
 libcloud/dns/types.py                  |   12 ++--
 libcloud/loadbalancer/providers.py     |    4 ++
 libcloud/loadbalancer/types.py         |   10 ++--
 libcloud/storage/base.py               |    2 +-
 libcloud/storage/providers.py          |    4 ++
 libcloud/storage/types.py              |   28 ++++-----
 libcloud/test/test_utils.py            |   42 +++++++++++++-
 libcloud/utils/misc.py                 |   31 ++++++++++
 14 files changed, 166 insertions(+), 79 deletions(-)

diff --git libcloud/common/gandi.py libcloud/common/gandi.py
index 320c2ef..3eed567 100644
--- libcloud/common/gandi.py
+++ libcloud/common/gandi.py
@@ -172,7 +172,7 @@ class BaseObject(object):
         Note, for example, that this example will always produce the
         same UUID!
         """
-        return hashlib.sha1(b("%s:%s:%d" % \
+        return hashlib.sha1(b("%s:%s:%s" % \
             (self.uuid_prefix, self.id, self.driver.type))).hexdigest()
 
 
diff --git libcloud/compute/base.py libcloud/compute/base.py
index 3842c35..09aac36 100644
--- libcloud/compute/base.py
+++ libcloud/compute/base.py
@@ -98,7 +98,7 @@ class UuidMixin(object):
         same UUID!
         """
         if not self._uuid:
-            self._uuid = hashlib.sha1(b('%s:%d' %
+            self._uuid = hashlib.sha1(b('%s:%s' %
                                       (self.id, self.driver.type))).hexdigest()
 
         return self._uuid
diff --git libcloud/compute/drivers/opennebula.py libcloud/compute/drivers/opennebula.py
index 36b8ec8..54b9898 100644
--- libcloud/compute/drivers/opennebula.py
+++ libcloud/compute/drivers/opennebula.py
@@ -248,7 +248,7 @@ class OpenNebulaNetwork(object):
         @rtype:  C{string}
         @return: Unique identifier for this instance.
         """
-        return hashlib.sha1(b("%s:%d" % (self.id,
+        return hashlib.sha1(b("%s:%s" % (self.id,
                                          self.driver.type))).hexdigest()
 
     def __repr__(self):
diff --git libcloud/compute/providers.py libcloud/compute/providers.py
index 310281b..2fdbf5c 100644
--- libcloud/compute/providers.py
+++ libcloud/compute/providers.py
@@ -17,6 +17,7 @@ Provider related utilities
 """
 
 from libcloud.utils.misc import get_driver as _get_provider_driver
+from libcloud.utils.misc import set_driver as _set_provider_driver
 from libcloud.compute.types import Provider, DEPRECATED_RACKSPACE_PROVIDERS
 from libcloud.compute.types import OLD_CONSTANT_TO_NEW_MAPPING
 
@@ -132,3 +133,6 @@ def get_driver(provider):
         raise Exception(msg)
 
     return _get_provider_driver(DRIVERS, provider)
+
+def set_driver(provider, module, klass):
+    return _set_provider_driver(DRIVERS, provider, module, klass)
diff --git libcloud/compute/types.py libcloud/compute/types.py
index 31af931..c1fe53a 100644
--- libcloud/compute/types.py
+++ libcloud/compute/types.py
@@ -70,55 +70,55 @@ class Provider(object):
     @cvar KTUCLOUD: kt ucloud driver
     @cvar GRIDSPOT: Gridspot driver
     """
-    DUMMY = 0
-    EC2 = 1  # deprecated name
-    EC2_US_EAST = 1
-    EC2_EU = 2  # deprecated name
-    EC2_EU_WEST = 2
-    RACKSPACE = 3
-    SLICEHOST = 4
-    GOGRID = 5
-    VPSNET = 6
-    LINODE = 7
-    VCLOUD = 8
-    RIMUHOSTING = 9
-    EC2_US_WEST = 10
-    VOXEL = 11
-    SOFTLAYER = 12
-    EUCALYPTUS = 13
-    ECP = 14
-    IBM = 15
-    OPENNEBULA = 16
-    DREAMHOST = 17
-    ELASTICHOSTS = 18
-    ELASTICHOSTS_UK1 = 19
-    ELASTICHOSTS_UK2 = 20
-    ELASTICHOSTS_US1 = 21
-    EC2_AP_SOUTHEAST = 22
-    BRIGHTBOX = 24
-    CLOUDSIGMA = 25
-    EC2_AP_NORTHEAST = 26
-    NIMBUS = 27
-    BLUEBOX = 28
-    GANDI = 29
-    OPSOURCE = 30
-    OPENSTACK = 31
-    SKALICLOUD = 32
-    SERVERLOVE = 33
-    NINEFOLD = 34
-    TERREMARK = 35
-    EC2_US_WEST_OREGON = 36
-    CLOUDSTACK = 37
-    CLOUDSIGMA_US = 38
-    EC2_SA_EAST = 39
-    LIBVIRT = 42
-    ELASTICHOSTS_US2 = 43
-    ELASTICHOSTS_CA1 = 44
-    JOYENT = 45
-    VCL = 46
-    KTUCLOUD = 47
-    GRIDSPOT = 49
-    RACKSPACE_FIRST_GEN = 51
+    DUMMY = 'dummy'
+    EC2 = 'ec2'  # deprecated name
+    EC2_US_EAST = 'ec2_us_east'
+    EC2_EU = 'ec2_eu'  # deprecated name
+    EC2_EU_WEST = 'ec2_eu_west'
+    RACKSPACE = 'rackspace'
+    SLICEHOST = 'slicehost'
+    GOGRID = 'gogrid'
+    VPSNET = 'vpsnet'
+    LINODE = 'linode'
+    VCLOUD = 'vcloud'
+    RIMUHOSTING = 'rimuhosting'
+    EC2_US_WEST = 'ec2_us_west'
+    VOXEL = 'voxel'
+    SOFTLAYER = 'softlayer'
+    EUCALYPTUS = 'eucalyptus'
+    ECP = 'ecp'
+    IBM = 'ibm'
+    OPENNEBULA = 'opennebula'
+    DREAMHOST = 'dreamhost'
+    ELASTICHOSTS = 'elastichosts'
+    ELASTICHOSTS_UK1 = 'elastichosts_uk1'
+    ELASTICHOSTS_UK2 = 'elastichosts_uk2'
+    ELASTICHOSTS_US1 = 'elastichosts_us1'
+    EC2_AP_SOUTHEAST = 'ec2_ap_southeast'
+    BRIGHTBOX = 'brightbox'
+    CLOUDSIGMA = 'cloudsigma'
+    EC2_AP_NORTHEAST = 'ec2_ap_northeast'
+    NIMBUS = 'nimbus'
+    BLUEBOX = 'bluebox'
+    GANDI = 'gandi'
+    OPSOURCE = 'opsource'
+    OPENSTACK = 'openstack'
+    SKALICLOUD = 'skalicloud'
+    SERVERLOVE = 'serverlove'
+    NINEFOLD = 'ninefold'
+    TERREMARK = 'terremark'
+    EC2_US_WEST_OREGON = 'ec2_us_west_oregon'
+    CLOUDSTACK = 'cloudstack'
+    CLOUDSIGMA_US = 'cloudsigma_us'
+    EC2_SA_EAST = 'ec2_sa_east'
+    LIBVIRT = 'libvirt'
+    ELASTICHOSTS_US2 = 'elastichosts_us2'
+    ELASTICHOSTS_CA1 = 'elastichosts_ca1'
+    JOYENT = 'joyent'
+    VCL = 'vcl'
+    KTUCLOUD = 'ktucloud'
+    GRIDSPOT = 'gridspot'
+    RACKSPACE_FIRST_GEN = 'rackspace_first_gen'
 
     # Deprecated constants
     RACKSPACE_UK = 23
diff --git libcloud/dns/providers.py libcloud/dns/providers.py
index 018b5b0..efd1e72 100644
--- libcloud/dns/providers.py
+++ libcloud/dns/providers.py
@@ -14,6 +14,7 @@
 # limitations under the License.
 
 from libcloud.utils.misc import get_driver as get_provider_driver
+from libcloud.utils.misc import set_driver as set_provider_driver
 from libcloud.dns.types import Provider
 
 DRIVERS = {
@@ -32,3 +33,6 @@ DRIVERS = {
 
 def get_driver(provider):
     return get_provider_driver(DRIVERS, provider)
+
+def set_driver(provider, module, klass):
+    return set_provider_driver(DRIVERS, provider, module, klass)
diff --git libcloud/dns/types.py libcloud/dns/types.py
index feb1bd2..2a518f4 100644
--- libcloud/dns/types.py
+++ libcloud/dns/types.py
@@ -28,12 +28,12 @@ __all__ = [
 
 
 class Provider(object):
-    DUMMY = 0
-    LINODE = 1
-    ZERIGO = 2
-    RACKSPACE_US = 3
-    RACKSPACE_UK = 4
-    ROUTE53 = 5
+    DUMMY = 'dummy'
+    LINODE = 'linode'
+    ZERIGO = 'zerigo'
+    RACKSPACE_US = 'rackspace_us'
+    RACKSPACE_UK = 'rackspace_uk'
+    ROUTE53 = 'route53'
 
 
 class RecordType(object):
diff --git libcloud/loadbalancer/providers.py libcloud/loadbalancer/providers.py
index 5e0e53f..1fb46d9 100644
--- libcloud/loadbalancer/providers.py
+++ libcloud/loadbalancer/providers.py
@@ -14,6 +14,7 @@
 # limitations under the License.
 
 from libcloud.utils.misc import get_driver as get_provider_driver
+from libcloud.utils.misc import set_driver as set_provider_driver
 from libcloud.loadbalancer.types import Provider
 
 __all__ = [
@@ -38,3 +39,6 @@ DRIVERS = {
 
 def get_driver(provider):
     return get_provider_driver(DRIVERS, provider)
+
+def set_driver(provider, module, klass):
+    return set_provider_driver(DRIVERS, provider, module, klass)
diff --git libcloud/loadbalancer/types.py libcloud/loadbalancer/types.py
index d0420cf..814b6c5 100644
--- libcloud/loadbalancer/types.py
+++ libcloud/loadbalancer/types.py
@@ -32,11 +32,11 @@ class LibcloudLBImmutableError(LibcloudLBError):
 
 
 class Provider(object):
-    RACKSPACE_US = 0
-    GOGRID = 1
-    NINEFOLD = 2
-    RACKSPACE_UK = 3
-    BRIGHTBOX = 4
+    RACKSPACE_US = 'rackspace_us'
+    GOGRID = 'gogrid'
+    NINEFOLD = 'ninefold'
+    RACKSPACE_UK = 'rackspace_uk'
+    BRIGHTBOX = 'brightbox'
 
 
 class State(object):
diff --git libcloud/storage/base.py libcloud/storage/base.py
index 4a651eb..4f74827 100644
--- libcloud/storage/base.py
+++ libcloud/storage/base.py
@@ -333,7 +333,7 @@ class StorageDriver(BaseDriver):
         @param object_name: Object name.
         @type object_name: C{str}
 
-        @param verify_hash: Verify hast
+        @param verify_hash: Verify hash
         @type verify_hash: C{bool}
 
         @param extra: (optional) Extra attributes (driver specific).
diff --git libcloud/storage/providers.py libcloud/storage/providers.py
index 18be288..732eba2 100644
--- libcloud/storage/providers.py
+++ libcloud/storage/providers.py
@@ -14,6 +14,7 @@
 # limitations under the License.
 
 from libcloud.utils.misc import get_driver as get_provider_driver
+from libcloud.utils.misc import set_driver as set_provider_driver
 from libcloud.storage.types import Provider
 
 DRIVERS = {
@@ -51,3 +52,6 @@ DRIVERS = {
 
 def get_driver(provider):
     return get_provider_driver(DRIVERS, provider)
+
+def set_driver(provider, module, klass):
+    return set_provider_driver(DRIVERS, provider, module, klass)
diff --git libcloud/storage/types.py libcloud/storage/types.py
index 0c3e645..8941f33 100644
--- libcloud/storage/types.py
+++ libcloud/storage/types.py
@@ -44,20 +44,20 @@ class Provider(object):
     @cvar NIMBUS: Nimbus.io driver
     @cvar LOCAL: Local storage driver
     """
-    DUMMY = 0
-    CLOUDFILES_US = 1
-    CLOUDFILES_UK = 2
-    S3 = 3
-    S3_US_WEST = 4
-    S3_EU_WEST = 5
-    S3_AP_SOUTHEAST = 6
-    S3_AP_NORTHEAST = 7
-    NINEFOLD = 8
-    GOOGLE_STORAGE = 9
-    S3_US_WEST_OREGON = 10
-    CLOUDFILES_SWIFT = 11
-    NIMBUS = 12
-    LOCAL = 13
+    DUMMY = 'dummy'
+    CLOUDFILES_US = 'cloudfiles_us'
+    CLOUDFILES_UK = 'cloudfiles_uk'
+    S3 = 's3'
+    S3_US_WEST = 's3_us_west'
+    S3_EU_WEST = 's3_eu_west'
+    S3_AP_SOUTHEAST = 's3_ap_southeast'
+    S3_AP_NORTHEAST = 's3_ap_northeast'
+    NINEFOLD = 'ninefold'
+    GOOGLE_STORAGE = 'google_storage'
+    S3_US_WEST_OREGON = 's3_us_west_oregon'
+    CLOUDFILES_SWIFT = 'cloudfiles_swift'
+    NIMBUS = 'nimbus'
+    LOCAL = 'local'
 
 
 class ContainerError(LibcloudError):
diff --git libcloud/test/test_utils.py libcloud/test/test_utils.py
index ed83794..994c521 100644
--- libcloud/test/test_utils.py
+++ libcloud/test/test_utils.py
@@ -24,7 +24,7 @@ warnings.simplefilter('default')
 
 import libcloud.utils.files
 
-from libcloud.utils.misc import get_driver
+from libcloud.utils.misc import get_driver, set_driver
 
 from libcloud.utils.py3 import PY3
 from libcloud.utils.py3 import StringIO
@@ -72,6 +72,46 @@ class TestUtils(unittest.TestCase):
         else:
             self.fail('Invalid provider, but an exception was not thrown')
 
+    def test_set_driver(self):
+        # Set an existing driver
+        try:
+            driver = set_driver(DRIVERS, Provider.DUMMY,
+                                'libcloud.storage.drivers.dummy',
+                                'DummyStorageDriver')
+        except AttributeError:
+            pass
+
+        # Register a new driver
+        driver = set_driver(DRIVERS, 'testingset',
+                            'libcloud.storage.drivers.dummy',
+                            'DummyStorageDriver')
+
+        self.assertTrue(driver is not None)
+
+        # Register it again
+        try:
+            set_driver(DRIVERS, 'testingset',
+                       'libcloud.storage.drivers.dummy',
+                       'DummyStorageDriver')
+        except AttributeError:
+            pass
+
+        # Register an invalid module
+        try:
+            set_driver(DRIVERS, 'testingnew',
+                       'libcloud.storage.drivers.dummy1',
+                       'DummyStorageDriver')
+        except ImportError:
+            pass
+
+        # Register an invalid class
+        try:
+            set_driver(DRIVERS, 'testingnew',
+                       'libcloud.storage.drivers.dummy',
+                       'DummyStorageDriver1')
+        except AttributeError:
+            pass
+
     def test_deprecated_warning(self):
         warnings.showwarning = show_warning
 
diff --git libcloud/utils/misc.py libcloud/utils/misc.py
index 434b3bd..88af26b 100644
--- libcloud/utils/misc.py
+++ libcloud/utils/misc.py
@@ -13,6 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import sys
+
 
 def get_driver(drivers, provider):
     """
@@ -30,6 +32,35 @@ def get_driver(drivers, provider):
     raise AttributeError('Provider %s does not exist' % (provider))
 
 
+def set_driver(drivers, provider, module, klass):
+    """
+    Sets a driver.
+
+    @param drivers: Dictionary to store providers.
+    @param provider: Id of provider to set driver for
+    @type provider: L{libcloud.types.Provider}
+    @param module: The module which contains the driver
+    @type module: L
+    @param klass: The driver class name
+    @type klass:
+    """
+
+    if provider in drivers:
+        raise AttributeError('Provider %s already registered' % (provider))
+
+    drivers[provider] = (module, klass)
+
+    # Check if this driver is valid
+    try:
+        driver = get_driver(drivers, provider)
+    except (ImportError, AttributeError):
+        exp = sys.exc_info()[1]
+        drivers.pop(provider)
+        raise exp
+
+    return driver
+
+
 def merge_valid_keys(params, valid_keys, extra):
     """
     Merge valid keys from extra into params dictionary and return
-- 
1.7.10.4

