Explorar o código

Fixed duplicate keypair handling across all providers

Nuwan Goonasekera %!s(int64=8) %!d(string=hai) anos
pai
achega
7f3fb65c5e

+ 9 - 0
cloudbridge/cloud/interfaces/exceptions.py

@@ -69,3 +69,12 @@ class InvalidValueException(CloudBridgeBaseException):
         super(InvalidValueException, self).__init__(
             "Param %s has been given an unrecognised value %s" %
             (param, value))
+
+
+class DuplicateResourceException(CloudBridgeBaseException):
+    """
+    Marker interface for any attempt to create a CloudBridge resource that
+    already exists. For example, creating a KeyPair with the same name will
+    result in a DuplicateResourceException.
+    """
+    pass

+ 12 - 5
cloudbridge/cloud/providers/aws/services.py

@@ -23,7 +23,7 @@ from cloudbridge.cloud.base.services import BaseVMFirewallService
 from cloudbridge.cloud.base.services import BaseVMTypeService
 from cloudbridge.cloud.base.services import BaseVolumeService
 from cloudbridge.cloud.interfaces.exceptions \
-    import InvalidConfigurationException
+    import DuplicateResourceException, InvalidConfigurationException
 from cloudbridge.cloud.interfaces.resources import KeyPair
 from cloudbridge.cloud.interfaces.resources import MachineImage
 from cloudbridge.cloud.interfaces.resources import PlacementZone
@@ -103,10 +103,17 @@ class AWSKeyPairService(BaseKeyPairService):
         private_key = None
         if not public_key_material:
             public_key_material, private_key = cb_helpers.generate_key_pair()
-        kp = self.svc.create('import_key_pair', KeyName=name,
-                             PublicKeyMaterial=public_key_material)
-        kp.material = private_key
-        return kp
+        try:
+            kp = self.svc.create('import_key_pair', KeyName=name,
+                                 PublicKeyMaterial=public_key_material)
+            kp.material = private_key
+            return kp
+        except ClientError as e:
+            if e.response['Error']['Code'] == 'InvalidKeyPair.Duplicate':
+                raise DuplicateResourceException(
+                    'Keypair already exists with name {0}'.format(name))
+            else:
+                raise e
 
 
 class AWSVMFirewallService(BaseVMFirewallService):

+ 11 - 4
cloudbridge/cloud/providers/azure/services.py

@@ -14,7 +14,8 @@ from cloudbridge.cloud.base.services import BaseBucketService, \
     BaseRouterService, BaseSecurityService, BaseSnapshotService, \
     BaseStorageService, BaseSubnetService, BaseVMFirewallService, \
     BaseVMTypeService, BaseVolumeService
-from cloudbridge.cloud.interfaces import InvalidConfigurationException
+from cloudbridge.cloud.interfaces.exceptions import \
+    DuplicateResourceException, InvalidConfigurationException
 from cloudbridge.cloud.interfaces.resources import MachineImage, \
     Network, PlacementZone, Snapshot, Subnet, VMFirewall, VMType, Volume
 
@@ -175,7 +176,7 @@ class AzureKeyPairService(BaseKeyPairService):
         key_pair = self.get(name)
 
         if key_pair:
-            raise Exception(
+            raise DuplicateResourceException(
                 'Keypair already exists with name {0}'.format(name))
 
         private_key = None
@@ -467,8 +468,14 @@ class AzureInstanceService(BaseInstanceService):
             # but useless. However, this will allow an instance to be launched
             # without specifying a keypair, so users may still be able to login
             # if they have a preinstalled keypair/password baked into the image
-            key_pair = self.provider.security.key_pairs.create(
-                name="cloudbridge_temp_key_pair")
+            default_kp_name = "cb_default_key_pair"
+            default_kp = self.provider.security.key_pairs.find(
+                name=default_kp_name)
+            if default_kp:
+                return default_kp[0]
+            else:
+                key_pair = self.provider.security.key_pairs.create(
+                    name=default_kp_name)
             temp_key_pair = key_pair
 
         image = (self.provider.compute.images.get(image)

+ 11 - 9
cloudbridge/cloud/providers/openstack/services.py

@@ -26,6 +26,8 @@ from cloudbridge.cloud.base.services import BaseSubnetService
 from cloudbridge.cloud.base.services import BaseVMFirewallService
 from cloudbridge.cloud.base.services import BaseVMTypeService
 from cloudbridge.cloud.base.services import BaseVolumeService
+from cloudbridge.cloud.interfaces.exceptions \
+    import DuplicateResourceException
 from cloudbridge.cloud.interfaces.resources import KeyPair
 from cloudbridge.cloud.interfaces.resources import MachineImage
 from cloudbridge.cloud.interfaces.resources import PlacementZone
@@ -169,20 +171,20 @@ class OpenStackKeyPairService(BaseKeyPairService):
         log.debug("Creating a new key pair with the name: %s", name)
         OpenStackKeyPair.assert_valid_resource_name(name)
 
+        existing_kp = self.find(name=name)
+        if existing_kp:
+            raise DuplicateResourceException(
+                'Keypair already exists with name {0}'.format(name))
+
         private_key = None
         if not public_key_material:
             public_key_material, private_key = cb_helpers.generate_key_pair()
+
         kp = self.provider.nova.keypairs.create(name,
                                                 public_key=public_key_material)
-
-        if kp:
-            cb_kp = OpenStackKeyPair(self.provider, kp)
-            cb_kp.material = private_key
-            return cb_kp
-        else:
-            log.debug("Key Pair with the name %s already exists", name)
-            found_kps = self.find(name=name)
-            return found_kps[0] if found_kps else None
+        cb_kp = OpenStackKeyPair(self.provider, kp)
+        cb_kp.material = private_key
+        return cb_kp
 
 
 class OpenStackVMFirewallService(BaseVMFirewallService):

+ 2 - 1
test/test_security_service.py

@@ -4,6 +4,7 @@ from test.helpers import ProviderTestBase
 from test.helpers import standard_interface_tests as sit
 
 import cloudbridge.cloud.base.helpers as cb_helpers
+from cloudbridge.cloud.interfaces.exceptions import DuplicateResourceException
 from cloudbridge.cloud.interfaces.resources import KeyPair
 from cloudbridge.cloud.interfaces.resources import TrafficDirection
 from cloudbridge.cloud.interfaces.resources import VMFirewall
@@ -23,7 +24,7 @@ class CloudSecurityServiceTestCase(ProviderTestBase):
 
         def extra_tests(kp):
             # Recreating existing keypair should raise an exception
-            with self.assertRaises(Exception):
+            with self.assertRaises(DuplicateResourceException):
                 self.provider.security.key_pairs.create(name=kp.name)
 
         sit.check_crud(self, self.provider.security.key_pairs, KeyPair,