Просмотр исходного кода

Implementation for interacting with key pairs (OpenStack and AWS)

Enis Afgan 10 лет назад
Родитель
Сommit
7d3d8a8647

+ 18 - 1
cloudbridge/providers/aws/resources.py

@@ -244,7 +244,7 @@ class AWSInstance(BaseInstance):
         """
         """
         Get the name of the key pair associated with this instance.
         Get the name of the key pair associated with this instance.
         """
         """
-        return BaseKeyPair(self._ec2_instance.key_name)
+        return self._ec2_instance.key_name
 
 
     def create_image(self, name):
     def create_image(self, name):
         """
         """
@@ -418,6 +418,23 @@ class AWSSnapshot(BaseSnapshot):
                                                     self.name)
                                                     self.name)
 
 
 
 
+class AWSKeyPair(BaseKeyPair):
+
+    def __init__(self, provider, key_pair):
+        super(AWSKeyPair, self).__init__(provider, key_pair)
+
+    @property
+    def material(self):
+        """
+        Unencrypted private key.
+
+        :rtype: str
+        :return: Unencrypted private key or ``None`` if not available.
+
+        """
+        return self._key_pair.material
+
+
 class AWSContainerObject(ContainerObject):
 class AWSContainerObject(ContainerObject):
 
 
     def __init__(self, provider, key):
     def __init__(self, provider, key):

+ 71 - 12
cloudbridge/providers/aws/services.py

@@ -1,24 +1,25 @@
 """
 """
-Services implemented by this provider
+Services implemented by the AWS provider.
 """
 """
 
 
-from cloudbridge.providers.base import BaseKeyPair
-from cloudbridge.providers.base import BaseSecurityGroup
 from cloudbridge.providers.interfaces import BlockStoreService
 from cloudbridge.providers.interfaces import BlockStoreService
 from cloudbridge.providers.interfaces import ComputeService
 from cloudbridge.providers.interfaces import ComputeService
 from cloudbridge.providers.interfaces import ImageService
 from cloudbridge.providers.interfaces import ImageService
 from cloudbridge.providers.interfaces import InstanceType
 from cloudbridge.providers.interfaces import InstanceType
 from cloudbridge.providers.interfaces import KeyPair
 from cloudbridge.providers.interfaces import KeyPair
+from cloudbridge.providers.interfaces import KeyPairService
 from cloudbridge.providers.interfaces import MachineImage
 from cloudbridge.providers.interfaces import MachineImage
 from cloudbridge.providers.interfaces import ObjectStoreService
 from cloudbridge.providers.interfaces import ObjectStoreService
 from cloudbridge.providers.interfaces import PlacementZone
 from cloudbridge.providers.interfaces import PlacementZone
 from cloudbridge.providers.interfaces import SecurityGroup
 from cloudbridge.providers.interfaces import SecurityGroup
+from cloudbridge.providers.interfaces import SecurityGroupService
 from cloudbridge.providers.interfaces import SecurityService
 from cloudbridge.providers.interfaces import SecurityService
 from cloudbridge.providers.interfaces import SnapshotService
 from cloudbridge.providers.interfaces import SnapshotService
 from cloudbridge.providers.interfaces import VolumeService
 from cloudbridge.providers.interfaces import VolumeService
 
 
 from .resources import AWSContainer
 from .resources import AWSContainer
 from .resources import AWSInstance
 from .resources import AWSInstance
+from .resources import AWSKeyPair
 from .resources import AWSMachineImage
 from .resources import AWSMachineImage
 from .resources import AWSSnapshot
 from .resources import AWSSnapshot
 from .resources import AWSVolume
 from .resources import AWSVolume
@@ -29,7 +30,37 @@ class AWSSecurityService(SecurityService):
     def __init__(self, provider):
     def __init__(self, provider):
         self.provider = provider
         self.provider = provider
 
 
-    def list_key_pairs(self):
+        # Initialize provider services
+        self._key_pairs = AWSKeyPairService(provider)
+        self._security_groups = AWSSecurityGroupService(provider)
+
+    @property
+    def key_pairs(self):
+        """
+        Provides access to key pairs for this provider.
+
+        :rtype: ``object`` of :class:`.KeyPairService`
+        :return: a KeyPairService object
+        """
+        return self._key_pairs
+
+    @property
+    def security_groups(self):
+        """
+        Provides access to security groups for this provider.
+
+        :rtype: ``object`` of :class:`.SecurityGroupService`
+        :return: a SecurityGroupService object
+        """
+        return self._security_groups
+
+
+class AWSKeyPairService(KeyPairService):
+
+    def __init__(self, provider):
+        self.provider = provider
+
+    def list(self):
         """
         """
         List all key pairs associated with this account.
         List all key pairs associated with this account.
 
 
@@ -37,18 +68,46 @@ class AWSSecurityService(SecurityService):
         :return:  list of KeyPair objects
         :return:  list of KeyPair objects
         """
         """
         key_pairs = self.provider.ec2_conn.get_all_key_pairs()
         key_pairs = self.provider.ec2_conn.get_all_key_pairs()
-        return [BaseKeyPair(kp.name) for kp in key_pairs]
+        return [AWSKeyPair(self.provider, kp) for kp in key_pairs]
+
+    def create(self, key_name):
+        """
+        Create a new key pair.
+
+        :type key_name: str
+        :param key_name: The name of the key pair to be created.
+
+        :rtype: ``object`` of :class:`.KeyPair`
+        :return:  A keypair instance or None if one was not be created.
+        """
+        kp = self.provider.ec2_conn.create_key_pair(key_name)
+        if kp:
+            return AWSKeyPair(self.provider, kp)
+        return None
 
 
-    def list_security_groups(self):
+    def delete(self, key_name):
         """
         """
-        List all security groups associated with this account.
+        Delete an existing key pair.
+
+        :type key_name: str
+        :param key_name: The name of the key pair to be deleted.
 
 
-        :rtype: ``list`` of :class:`.SecurityGroup`
-        :return:  list of SecurityGroup objects
+        :rtype: ``bool``
+        :return:  ``True`` if the key does not exist, ``False`` otherwise. Note
+                  that this implies that the key may not have been deleted by
+                  this method but instead has not existed in the first place.
         """
         """
-        groups = self.provider.ec2_conn.get_all_security_groups()
-        return [BaseSecurityGroup(group.id, group.name, group.description)
-                for group in groups]
+        for kp in self.provider.ec2_conn.get_all_key_pairs():
+            if kp.name == key_name:
+                kp.delete()
+                return True
+        return True
+
+
+class AWSSecurityGroupService(SecurityGroupService):
+
+    def __init__(self, provider):
+        self.provider = provider
 
 
 
 
 class AWSBlockStoreService(BlockStoreService):
 class AWSBlockStoreService(BlockStoreService):

+ 12 - 8
cloudbridge/providers/base.py

@@ -180,23 +180,27 @@ class BaseSnapshot(BaseObjectLifeCycleMixin, Snapshot):
 
 
 class BaseKeyPair(KeyPair):
 class BaseKeyPair(KeyPair):
 
 
-    def __init__(self, name, material=None):
-        self._name = name
-        self._material = material
+    def __init__(self, provider, key_pair):
+        self.provider = provider
+        self._key_pair = key_pair
 
 
     @property
     @property
     def name(self):
     def name(self):
         """
         """
         Return the name of this key pair.
         Return the name of this key pair.
         """
         """
-        return self._name
+        return self._key_pair.name
 
 
-    @property
-    def material(self):
+    def delete(self):
         """
         """
-        Unencrypted private key.
+        Delete this KeyPair.
+
+        :rtype: bool
+        :return: True if successful, otherwise False.
         """
         """
-        return self._material
+        # This implementation assumes the `delete` method exists across multiple
+        # providers.
+        self._key_pair.delete()
 
 
     def __repr__(self):
     def __repr__(self):
         return "<CBKeyPair: {0}>".format(self.name)
         return "<CBKeyPair: {0}>".format(self.name)

+ 1 - 1
cloudbridge/providers/interfaces/resources.py

@@ -534,7 +534,7 @@ class KeyPair(object):
         Unencrypted private key.
         Unencrypted private key.
 
 
         :rtype: str
         :rtype: str
-        :return: Unencrypted private key.
+        :return: Unencrypted private key or ``None`` if not available.
         """
         """
         raise NotImplementedError(
         raise NotImplementedError(
             'material not implemented by this provider')
             'material not implemented by this provider')

+ 7 - 2
cloudbridge/providers/interfaces/services.py

@@ -414,10 +414,13 @@ class KeyPairService(ProviderService):
         raise NotImplementedError(
         raise NotImplementedError(
             'list_key_pairs not implemented by this provider')
             'list_key_pairs not implemented by this provider')
 
 
-    def create(self):
+    def create(self, key_name):
         """
         """
         Create a new keypair.
         Create a new keypair.
 
 
+        :type key_name: str
+        :param key_name: The name of the key pair to be created.
+
         :rtype: ``object`` of :class:`.KeyPair`
         :rtype: ``object`` of :class:`.KeyPair`
         :return:  A keypair instance
         :return:  A keypair instance
         """
         """
@@ -432,7 +435,9 @@ class KeyPairService(ProviderService):
         :param key_name: The name of the key pair to be deleted.
         :param key_name: The name of the key pair to be deleted.
 
 
         :rtype: ``bool``
         :rtype: ``bool``
-        :return:  ``True`` if successful, ``False`` otherwise
+        :return:  ``True`` if the key does not exist, ``False`` otherwise. Note
+                  that this implies that the key may not have been deleted by
+                  this method but instead has not existed at all.
         """
         """
         raise NotImplementedError(
         raise NotImplementedError(
             'delete not implemented by this provider')
             'delete not implemented by this provider')

+ 20 - 1
cloudbridge/providers/openstack/resources.py

@@ -259,7 +259,7 @@ class OpenStackInstance(BaseInstance):
         """
         """
         Get the name of the key pair associated with this instance.
         Get the name of the key pair associated with this instance.
         """
         """
-        return BaseKeyPair(self._os_instance.key_name)
+        return self._os_instance.key_name
 
 
     def create_image(self, name):
     def create_image(self, name):
         """
         """
@@ -458,3 +458,22 @@ class OpenStackSnapshot(BaseSnapshot):
 
 
     def __repr__(self):
     def __repr__(self):
         return "<CB-OSSnapshot: {0} ({1}>".format(self.snapshot_id, self.name)
         return "<CB-OSSnapshot: {0} ({1}>".format(self.snapshot_id, self.name)
+
+
+class OpenStackKeyPair(BaseKeyPair):
+
+    def __init__(self, provider, key_pair):
+        super(OpenStackKeyPair, self).__init__(provider, key_pair)
+
+    @property
+    def material(self):
+        """
+        Unencrypted private key.
+
+        :rtype: str
+        :return: Unencrypted private key or ``None`` if not available.
+
+        """
+        if hasattr(self._key_pair, 'private_key'):
+            return self._key_pair.private_key
+        return None

+ 37 - 3
cloudbridge/providers/openstack/services.py

@@ -1,10 +1,9 @@
 """
 """
-Services implemented by this provider
+Services implemented by the OpenStack provider.
 """
 """
 from cinderclient.exceptions import NotFound as CinderNotFound
 from cinderclient.exceptions import NotFound as CinderNotFound
 from novaclient.exceptions import NotFound as NovaNotFound
 from novaclient.exceptions import NotFound as NovaNotFound
 
 
-from cloudbridge.providers.base import BaseKeyPair
 from cloudbridge.providers.base import BaseSecurityGroup
 from cloudbridge.providers.base import BaseSecurityGroup
 from cloudbridge.providers.interfaces import BlockStoreService
 from cloudbridge.providers.interfaces import BlockStoreService
 from cloudbridge.providers.interfaces import ComputeService
 from cloudbridge.providers.interfaces import ComputeService
@@ -23,6 +22,7 @@ from cloudbridge.providers.interfaces import VolumeService
 
 
 from .resources import OpenStackInstance
 from .resources import OpenStackInstance
 from .resources import OpenStackInstanceType
 from .resources import OpenStackInstanceType
+from .resources import OpenStackKeyPair
 from .resources import OpenStackMachineImage
 from .resources import OpenStackMachineImage
 from .resources import OpenStackRegion
 from .resources import OpenStackRegion
 # from .resources import OpenStackSecurityGroup
 # from .resources import OpenStackSecurityGroup
@@ -73,7 +73,41 @@ class OpenStackKeyPairService(KeyPairService):
         :return:  list of KeyPair objects
         :return:  list of KeyPair objects
         """
         """
         key_pairs = self.provider.nova.keypairs.list()
         key_pairs = self.provider.nova.keypairs.list()
-        return [BaseKeyPair(kp.id) for kp in key_pairs]
+        return [OpenStackKeyPair(self.provider, kp) for kp in key_pairs]
+
+    def create(self, key_name):
+        """
+        Create a new key pair.
+
+        :type key_name: str
+        :param key_name: The name of the key pair to be created.
+
+        :rtype: ``object`` of :class:`.KeyPair`
+        :return:  A keypair instance or None if one was not be created.
+        """
+        kp = self.provider.nova.keypairs.create(key_name)
+        if kp:
+            return OpenStackKeyPair(self.provider, kp)
+        return None
+
+    def delete(self, key_name):
+        """
+        Delete an existing key pair.
+
+        :type key_name: str
+        :param key_name: The name of the key pair to be deleted.
+
+        :rtype: ``bool``
+        :return:  ``True`` if the key does not exist, ``False`` otherwise. Note
+                  that this implies that the key may not have been deleted by
+                  this method but instead has not existed in the first place.
+        """
+        try:
+            kp = self.provider.nova.keypairs.find(name=key_name)
+            kp.delete()
+            return True
+        except NovaNotFound:
+            return True
 
 
 
 
 class OpenStackSecurityGroupService(SecurityGroupService):
 class OpenStackSecurityGroupService(SecurityGroupService):

+ 1 - 1
test/test_provider_security_service.py

@@ -9,7 +9,7 @@ class ProviderSecurityServiceTestCase(ProviderTestBase):
             methodName=methodName, provider=provider)
             methodName=methodName, provider=provider)
 
 
     def test_list_key_pairs(self):
     def test_list_key_pairs(self):
-        key_pairs = self.provider.security.list_key_pairs()
+        key_pairs = self.provider.security.key_pairs.list()
         # Assume there's always one keypair at least
         # Assume there's always one keypair at least
         self.assertIsInstance(key_pairs[0], interfaces.KeyPair)
         self.assertIsInstance(key_pairs[0], interfaces.KeyPair)
         self.assertIsNotNone(key_pairs[0].name)
         self.assertIsNotNone(key_pairs[0].name)