소스 검색

Added create_instance support for openstack + basic tests.

nuwan_ag 10 년 전
부모
커밋
113a094723

+ 3 - 1
cloudbridge/providers/base.py

@@ -8,6 +8,7 @@ class BaseCloudProvider(CloudProvider):
     def __init__(self, config):
         self.config = config
 
+    @property
     def name(self):
         return str(self.__class__.__name__)
 
@@ -32,7 +33,8 @@ class BaseCloudProvider(CloudProvider):
         if isinstance(self.config, dict):
             return self.config.get(key, default_value)
         else:
-            return getattr(self.config, key) if hasattr(self.config, key) and getattr(self.config, key) else default_value
+            return getattr(self.config, key) if hasattr(
+                self.config, key) and getattr(self.config, key) else default_value
 
 
 class BaseKeyPair(KeyPair):

+ 2 - 2
cloudbridge/providers/ec2/__init__.py

@@ -148,13 +148,13 @@ class EC2Instance(Instance):
         """
         Get the image ID for this insance.
         """
-        return self._ec2_instance.id
+        return self._ec2_instance.image_id
 
     def placement_zone(self):
         """
         Get the placement zone where this instance is running.
         """
-        return self._ec2_instance.id
+        return self._ec2_instance.placement
 
     def mac_address(self):
         """

+ 32 - 5
cloudbridge/providers/interfaces.py

@@ -180,15 +180,15 @@ class ComputeService(ProviderService):
         raise NotImplementedError(
             'list_instances not implemented by this provider')
 
-    def list_instance_types(self):
+    def instance_types(self):
         """
-        List all instance types supported by this provider.
+        Provides access to all Instance type related services in this provider.
 
-        :rtype: ``list`` of :class:`.InstanceType`
-        :return: list of InstanceType objects
+        :rtype: ``object`` of :class:`.InstanceTypeService`
+        :return:  an InstanceTypeService object
         """
         raise NotImplementedError(
-            'list_instance_types not implemented by this provider')
+            'instance_types not implemented by this provider')
 
     def list_regions(self):
         """
@@ -764,12 +764,39 @@ class PlacementZone(object):
             'PlacementZone.name not implemented by this provider')
 
 
+class InstanceTypesService(object):
+
+    def list(self):
+        """
+        List all instance types.
+
+        :rtype: ``list`` of :class:`.InstanceType`
+        :return: list of InstanceType objects
+        """
+        raise NotImplementedError(
+            'InstanceTypesService.list not implemented by this provider')
+
+    def find_by_name(self, name):
+        """
+        Searches for an instance by a given list of attributes.
+
+        :rtype: ``object`` of :class:`.InstanceType`
+        :return: an Instance object
+        """
+        raise NotImplementedError(
+            'InstanceTypesService.find_instance not implemented by this provider')
+
+
 class InstanceType(object):
 
     """
     An instance type object.
     """
 
+    def id(self):
+        raise NotImplementedError(
+            'InstanceType.id not implemented by this provider')
+
     def name(self):
         raise NotImplementedError(
             'InstanceType.name not implemented by this provider')

+ 164 - 5
cloudbridge/providers/openstack/__init__.py

@@ -11,10 +11,15 @@ from keystoneclient.auth.identity import Password
 from cloudbridge.providers.base import BaseCloudProvider
 from cloudbridge.providers.base import BaseSecurityGroup
 from cloudbridge.providers.base import BaseKeyPair
-from cloudbridge.providers.interfaces import Instance
 from cloudbridge.providers.interfaces import SecurityService
 from cloudbridge.providers.interfaces import ComputeService
 from cloudbridge.providers.interfaces import KeyPair
+from cloudbridge.providers.interfaces import MachineImage
+from cloudbridge.providers.interfaces import SecurityGroup
+from cloudbridge.providers.interfaces import PlacementZone
+from cloudbridge.providers.interfaces import InstanceType
+from cloudbridge.providers.interfaces import InstanceTypesService
+from cloudbridge.providers.interfaces import Instance
 
 
 class OpenStackCloudProviderV1(BaseCloudProvider):
@@ -33,11 +38,11 @@ class OpenStackCloudProviderV1(BaseCloudProvider):
         self.nova = self._connect_nova()
         self.keystone = self._connect_keystone()
 
-        # self.Compute = EC2ComputeService(self)
-        # self.Images = EC2ImageService(self)
+        self.compute = OpenStackComputeService(self)
+        # self.images = EC2ImageService(self)
         self.security = OpenStackSecurityService(self)
-        # self.BlockStore = EC2BlockStore(self)
-        # self.ObjectStore = EC2ObjectStore(self)
+        # self.block_store = EC2BlockStore(self)
+        # self.object_store = EC2ObjectStore(self)
 
     def _connect_nova(self):
         """
@@ -85,3 +90,157 @@ class OpenStackSecurityService(SecurityService):
         """
         groups = self.provider.nova.security_groups.list()
         return [BaseSecurityGroup(group.name) for group in groups]
+
+
+class OpenStackInstanceType(InstanceType):
+
+    def __init__(self, os_flavor):
+        self.os_flavor = os_flavor
+
+    @property
+    def id(self):
+        return self.os_flavor.id
+
+    @property
+    def name(self):
+        return self.os_flavor.name
+
+    def __repr__(self):
+        return "<OSInstanceType: {0}={1}>".format(self.id, self.name)
+
+
+class OpenStackInstance(Instance):
+
+    def __init__(self, provider, os_instance):
+        self.provider = provider
+        self._os_instance = os_instance
+
+    def instance_id(self):
+        """
+        Get the instance identifier.
+        """
+        return self._ec2_instance.id
+
+    @property
+    def name(self):
+        """
+        Get the instance name.
+        """
+        return self._os_instance.name
+
+    @name.setter
+    def name(self, value):
+        """
+        Set the instance name.
+        """
+        self._os_instance.name = value
+
+    def public_ips(self):
+        """
+        Get all the public IP addresses for this instance.
+        """
+        return self._os_instance.networks['public']
+
+    def private_ips(self):
+        """
+        Get all the private IP addresses for this instance.
+        """
+        return self._os_instance.networks['private']
+
+    def instance_type(self):
+        """
+        Get the instance type.
+        """
+        return OpenStackInstanceType(self._os_instance.flavor)
+
+    def reboot(self):
+        """
+        Reboot this instance (using the cloud middleware API).
+        """
+        self._os_instance.reboot()
+
+    def terminate(self):
+        """
+        Permanently terminate this instance.
+        """
+        self._os_instance.delete()
+
+    def image_id(self):
+        """
+        Get the image ID for this insance.
+        """
+        return self._os_instance.image_id
+
+    def placement_zone(self):
+        """
+        Get the placement zone where this instance is running.
+        """
+        return self._os_instance.availability_zone
+
+    def mac_address(self):
+        """
+        Get the MAC address for this instance.
+        """
+        raise NotImplementedError(
+            'mac_address not implemented by this provider')
+
+    def security_group_ids(self):
+        """
+        Get the security group IDs associated with this instance.
+        """
+        return [BaseSecurityGroup(group.name) for group in self._os_instance.security_groups]
+
+    def key_pair_name(self):
+        """
+        Get the name of the key pair associated with this instance.
+        """
+        return BaseKeyPair(self._os_instance.key_name)
+
+
+class OpenStackInstanceTypesService(InstanceTypesService):
+
+    def __init__(self, provider):
+        self.provider = provider
+
+    def list(self):
+        return [OpenStackInstanceType(f) for f in self.provider.nova.flavors.list()]
+
+    def find_by_name(self, name):
+        return next((itype for itype in self.list() if itype.name == name), None)
+
+
+class OpenStackComputeService(ComputeService):
+
+    def __init__(self, provider):
+        self.provider = provider
+        self.instance_types = OpenStackInstanceTypesService(self.provider)
+
+    def create_instance(self, name, image, instance_type, zone=None, keypair=None, security_groups=None,
+                        user_data=None, block_device_mapping=None, network_interfaces=None, **kwargs):
+        """
+        Creates a new virtual machine instance.
+        """
+        image_id = image.image_id if isinstance(image, MachineImage) else image
+        instance_size = instance_type.name if isinstance(
+            instance_type,
+            InstanceType) else self.instance_types.find_by_name(instance_type).id
+        zone_name = zone.name if isinstance(zone, PlacementZone) else zone
+        keypair_name = keypair.name if isinstance(keypair, KeyPair) else keypair
+        if security_groups:
+            if isinstance(security_groups, list) and isinstance(security_groups[0], SecurityGroup):
+                security_groups_list = [sg.name for sg in security_groups]
+            else:
+                security_groups_list = security_groups
+        else:
+            security_groups_list = None
+
+        os_instance = self.provider.nova.servers.create(name, image_id,
+                                                        instance_size,
+                                                        min_count=1,
+                                                        max_count=1,
+                                                        availability_zone=zone_name,
+                                                        key_name=keypair_name,
+                                                        security_groups=security_groups_list,
+                                                        userdata=user_data
+                                                        )
+        return OpenStackInstance(self.provider, os_instance)

+ 10 - 0
test/helpers.py

@@ -1,5 +1,15 @@
 import unittest
 from cloudbridge.providers.factory import CloudProviderFactory
+from cloudbridge.providers.factory import ProviderList
+
+
+def get_test_instance(provider):
+    instance_name = "HelloCloudBridge-{0}".format(provider.name)
+    if "EC2CloudProvider" in provider.name:
+        return provider.compute.create_instance(instance_name, "ami-d85e75b0", "t1.micro")
+    elif "OpenStackCloudProvider" in provider.name:
+        return provider.compute.create_instance(
+            "{0}-{1}".format(instance_name, provider.name), "d57696ba-5ed2-43fe-bf78-a587829973a9", "m2.xsmall")
 
 
 class ProviderTestBase(object):

+ 7 - 0
test/test_compute_service.py

@@ -1,4 +1,5 @@
 from cloudbridge.providers import interfaces
+import test.helpers
 from test.helpers import ProviderTestBase
 
 
@@ -8,6 +9,12 @@ class ProviderComputeServiceTestCase(ProviderTestBase):
         super(ProviderComputeServiceTestCase, self).__init__(
             methodName=methodName, provider=provider)
 
+    def setUp(self):
+        self.instance = test.helpers.get_test_instance(self.provider)
+
+    def tearDown(self):
+        self.instance.terminate()
+
     def test_create_instance(self):
         # Need a less dangerous test
         #         instance = self.provider.compute.create_instance(