Sfoglia il codice sorgente

Added implementation to wait till instance or image is ready for ec2 and
openstack

nuwan_ag 10 anni fa
parent
commit
2ea3c26dd2

+ 6 - 4
cloudbridge/providers/ec2/services.py

@@ -13,8 +13,8 @@ from cloudbridge.providers.interfaces import PlacementZone
 from cloudbridge.providers.interfaces import SecurityGroup
 from cloudbridge.providers.interfaces import SecurityService
 
-from .types import EC2Image
 from .types import EC2Instance
+from .types import EC2MachineImage
 
 
 class EC2SecurityService(SecurityService):
@@ -54,7 +54,7 @@ class EC2ImageService(ImageService):
         """
         image = self.provider.ec2_conn.get_image(id)
         if image:
-            return EC2Image(self.provider, image)
+            return EC2MachineImage(self.provider, image)
         else:
             return None
 
@@ -69,8 +69,10 @@ class EC2ImageService(ImageService):
         """
         List all images.
         """
-        images = self.provider.ec2_conn.get_all_images()
-        return [EC2Image(self.provider, image) for image in images]
+        # TODO: get_all_images returns too many images - some kind of filtering
+        # abilities are needed. Forced to "self" for now
+        images = self.provider.ec2_conn.get_all_images(owner="self")
+        return [EC2MachineImage(self.provider, image) for image in images]
 
 
 class EC2ComputeService(ComputeService):

+ 79 - 7
cloudbridge/providers/ec2/types.py

@@ -2,21 +2,31 @@
 DataTypes used by this provider
 """
 
+from cloudbridge.providers.base import BaseInstance
 from cloudbridge.providers.base import BaseKeyPair
+from cloudbridge.providers.base import BaseMachineImage
 from cloudbridge.providers.base import BaseSecurityGroup
-from cloudbridge.providers.interfaces import Instance
-from cloudbridge.providers.interfaces import MachineImage
+from cloudbridge.providers.interfaces import InstanceState
+from cloudbridge.providers.interfaces import InstanceType
+from cloudbridge.providers.interfaces import MachineImageState
 
 
-class EC2Image(MachineImage):
+class EC2MachineImage(BaseMachineImage):
+
+    IMAGE_STATE_MAP = {
+        'pending': MachineImageState.PENDING,
+        'available': MachineImageState.AVAILABLE,
+        'failed': MachineImageState.ERROR
+    }
 
     def __init__(self, provider, image):
         self.provider = provider
-        if isinstance(image, MachineImage):
+        if isinstance(image, EC2MachineImage):
             self._ec2_image = image._ec2_image
         else:
             self._ec2_image = image
 
+    @property
     def image_id(self):
         """
         Get the image identifier.
@@ -26,6 +36,7 @@ class EC2Image(MachineImage):
         """
         return self._ec2_image.id
 
+    @property
     def name(self):
         """
         Get the image name.
@@ -35,6 +46,7 @@ class EC2Image(MachineImage):
         """
         return self._ec2_image.name
 
+    @property
     def description(self):
         """
         Get the image description.
@@ -50,13 +62,54 @@ class EC2Image(MachineImage):
         """
         self._ec2_image.deregister()
 
+    @property
+    def image_state(self):
+        print "Image State", self._ec2_image.state
+        return EC2MachineImage.IMAGE_STATE_MAP.get(
+            self._ec2_image.state, MachineImageState.UNKNOWN)
+
+    def refresh(self):
+        """
+        Refreshes the state of this instance by re-querying the cloud provider
+        for its latest state.
+        """
+        self._ec2_image = self.provider.images.get_image(self.image_id)._ec2_image
+
+
+class EC2InstanceType(InstanceType):
+
+    def __init__(self, instance_type):
+        self.instance_type = instance_type
+
+    @property
+    def id(self):
+        return self.instance_type
+
+    @property
+    def name(self):
+        return self.instance_type
+
+    def __repr__(self):
+        return "<EC2InstanceType: {0}>".format(self.id)
+
 
-class EC2Instance(Instance):
+class EC2Instance(BaseInstance):
+
+    # ref: http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-lifecycle.html
+    INSTANCE_STATE_MAP = {
+        'pending': InstanceState.PENDING,
+        'running': InstanceState.RUNNING,
+        'shutting-down': InstanceState.CONFIGURING,
+        'terminated': InstanceState.TERMINATED,
+        'stopping': InstanceState.CONFIGURING,
+        'stopped': InstanceState.STOPPED
+    }
 
     def __init__(self, provider, ec2_instance):
         self.provider = provider
         self._ec2_instance = ec2_instance
 
+    @property
     def instance_id(self):
         """
         Get the instance identifier.
@@ -79,23 +132,26 @@ class EC2Instance(Instance):
         """
         self._ec2_instance.add_tag('Name', value)
 
+    @property
     def public_ips(self):
         """
         Get all the public IP addresses for this instance.
         """
         return [self._ec2_instance.ip_address]
 
+    @property
     def private_ips(self):
         """
         Get all the private IP addresses for this instance.
         """
         return [self._ec2_instance.private_ip_address]
 
+    @property
     def instance_type(self):
         """
         Get the instance type.
         """
-        return [self._ec2_instance.instance_type]
+        return EC2InstanceType(self._ec2_instance.instance_type)
 
     def reboot(self):
         """
@@ -115,12 +171,14 @@ class EC2Instance(Instance):
         """
         return self._ec2_instance.image_id
 
+    @property
     def placement_zone(self):
         """
         Get the placement zone where this instance is running.
         """
         return self._ec2_instance.placement
 
+    @property
     def mac_address(self):
         """
         Get the MAC address for this instance.
@@ -128,12 +186,14 @@ class EC2Instance(Instance):
         raise NotImplementedError(
             'mac_address not implemented by this provider')
 
+    @property
     def security_group_ids(self):
         """
         Get the security group IDs associated with this instance.
         """
         return [BaseSecurityGroup(group.name) for group in self._ec2_instance.groups]
 
+    @property
     def key_pair_name(self):
         """
         Get the name of the key pair associated with this instance.
@@ -146,4 +206,16 @@ class EC2Instance(Instance):
         """
         image_id = self._ec2_instance.create_image(name)
         image = self.provider.images.get_image(image_id)
-        return EC2Image(self.provider, image)
+        return EC2MachineImage(self.provider, image)
+
+    @property
+    def instance_state(self):
+        return EC2Instance.INSTANCE_STATE_MAP.get(
+            self._ec2_instance.state, InstanceState.UNKNOWN)
+
+    def refresh(self):
+        """
+        Refreshes the state of this instance by re-querying the cloud provider
+        for its latest state.
+        """
+        self._ec2_instance.update()

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

@@ -14,9 +14,9 @@ from cloudbridge.providers.interfaces import PlacementZone
 from cloudbridge.providers.interfaces import SecurityGroup
 from cloudbridge.providers.interfaces import SecurityService
 
-from .types import OpenStackImage
 from .types import OpenStackInstance
 from .types import OpenStackInstanceType
+from .types import OpenStackMachineImage
 
 
 class OpenStackSecurityService(SecurityService):
@@ -56,7 +56,7 @@ class OpenStackImageService(ImageService):
         """
         image = self.provider.nova.images.get(id)
         if image:
-            return OpenStackImage(self.provider, image)
+            return OpenStackMachineImage(self.provider, image)
         else:
             return None
 
@@ -72,7 +72,7 @@ class OpenStackImageService(ImageService):
         List all images.
         """
         images = self.provider.nova.images.list()
-        return [OpenStackImage(self.provider, image) for image in images]
+        return [OpenStackMachineImage(self.provider, image) for image in images]
 
 
 class OpenStackInstanceTypesService(InstanceTypesService):
@@ -122,3 +122,10 @@ class OpenStackComputeService(ComputeService):
                                                         userdata=user_data
                                                         )
         return OpenStackInstance(self.provider, os_instance)
+
+    def get_instance(self, id):
+        """
+        Returns an instance given its id.
+        """
+        os_instance = self.provider.nova.servers.get(id)
+        return OpenStackInstance(self.provider, os_instance)

+ 78 - 7
cloudbridge/providers/openstack/types.py

@@ -2,22 +2,35 @@
 DataTypes used by this provider
 """
 
+from cloudbridge.providers.base import BaseInstance
 from cloudbridge.providers.base import BaseKeyPair
+from cloudbridge.providers.base import BaseMachineImage
 from cloudbridge.providers.base import BaseSecurityGroup
-from cloudbridge.providers.interfaces import Instance
+from cloudbridge.providers.interfaces import InstanceState
 from cloudbridge.providers.interfaces import InstanceType
-from cloudbridge.providers.interfaces import MachineImage
+from cloudbridge.providers.interfaces import MachineImageState
 
 
-class OpenStackImage(MachineImage):
+class OpenStackMachineImage(BaseMachineImage):
+
+    # ref: http://docs.openstack.org/developer/glance/statuses.html
+    IMAGE_STATE_MAP = {
+        'QUEUED': MachineImageState.PENDING,
+        'SAVING': MachineImageState.PENDING,
+        'ACTIVE': MachineImageState.AVAILABLE,
+        'KILLED': MachineImageState.ERROR,
+        'DELETED': MachineImageState.ERROR,
+        'PENDING_DELETE': MachineImageState.ERROR
+    }
 
     def __init__(self, provider, os_image):
         self.provider = provider
-        if isinstance(os_image, MachineImage):
+        if isinstance(os_image, OpenStackMachineImage):
             self._os_image = os_image._os_image
         else:
             self._os_image = os_image
 
+    @property
     def image_id(self):
         """
         Get the image identifier.
@@ -27,6 +40,7 @@ class OpenStackImage(MachineImage):
         """
         return self._os_image.id
 
+    @property
     def name(self):
         """
         Get the image name.
@@ -36,6 +50,7 @@ class OpenStackImage(MachineImage):
         """
         return self._os_image.name
 
+    @property
     def description(self):
         """
         Get the image description.
@@ -51,6 +66,18 @@ class OpenStackImage(MachineImage):
         """
         self._os_image.delete()
 
+    @property
+    def image_state(self):
+        return OpenStackMachineImage.IMAGE_STATE_MAP.get(
+            self._os_image.status, MachineImageState.UNKNOWN)
+
+    def refresh(self):
+        """
+        Refreshes the state of this instance by re-querying the cloud provider
+        for its latest state.
+        """
+        self._os_image = self.provider.images.get_image(self.image_id)._os_image
+
 
 class OpenStackInstanceType(InstanceType):
 
@@ -69,12 +96,36 @@ class OpenStackInstanceType(InstanceType):
         return "<OSInstanceType: {0}={1}>".format(self.id, self.name)
 
 
-class OpenStackInstance(Instance):
+class OpenStackInstance(BaseInstance):
+
+    # ref: http://docs.openstack.org/developer/nova/v2/2.0_server_concepts.html
+    # and http://developer.openstack.org/api-ref-compute-v2.html
+    INSTANCE_STATE_MAP = {
+        'ACTIVE': InstanceState.RUNNING,
+        'BUILD': InstanceState.PENDING,
+        'DELETED': InstanceState.TERMINATED,
+        'ERROR': InstanceState.ERROR,
+        'HARD_REBOOT': InstanceState.REBOOTING,
+        'PASSWORD': InstanceState.PENDING,
+        'PAUSED': InstanceState.STOPPED,
+        'REBOOT': InstanceState.REBOOTING,
+        'REBUILD': InstanceState.CONFIGURING,
+        'RESCUE': InstanceState.CONFIGURING,
+        'RESIZE': InstanceState.CONFIGURING,
+        'REVERT_RESIZE': InstanceState.CONFIGURING,
+        'SOFT_DELETED': InstanceState.STOPPED,
+        'STOPPED': InstanceState.STOPPED,
+        'SUSPENDED': InstanceState.STOPPED,
+        'SHUTOFF': InstanceState.STOPPED,
+        'UNKNOWN': InstanceState.UNKNOWN,
+        'VERIFY_RESIZE': InstanceState.CONFIGURING
+    }
 
     def __init__(self, provider, os_instance):
         self.provider = provider
         self._os_instance = os_instance
 
+    @property
     def instance_id(self):
         """
         Get the instance identifier.
@@ -95,18 +146,21 @@ class OpenStackInstance(Instance):
         """
         self._os_instance.name = value
 
+    @property
     def public_ips(self):
         """
         Get all the public IP addresses for this instance.
         """
         return self._os_instance.networks['public']
 
+    @property
     def private_ips(self):
         """
         Get all the private IP addresses for this instance.
         """
         return self._os_instance.networks['private']
 
+    @property
     def instance_type(self):
         """
         Get the instance type.
@@ -125,18 +179,21 @@ class OpenStackInstance(Instance):
         """
         self._os_instance.delete()
 
+    @property
     def image_id(self):
         """
-        Get the image ID for this insance.
+        Get the image ID for this instance.
         """
         return self._os_instance.image_id
 
+    @property
     def placement_zone(self):
         """
         Get the placement zone where this instance is running.
         """
         return self._os_instance.availability_zone
 
+    @property
     def mac_address(self):
         """
         Get the MAC address for this instance.
@@ -144,12 +201,14 @@ class OpenStackInstance(Instance):
         raise NotImplementedError(
             'mac_address not implemented by this provider')
 
+    @property
     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]
 
+    @property
     def key_pair_name(self):
         """
         Get the name of the key pair associated with this instance.
@@ -161,4 +220,16 @@ class OpenStackInstance(Instance):
         Create a new image based on this instance.
         """
         image_id = self._os_instance.create_image(name)
-        return OpenStackImage(self.provider, self.provider.images.get_image(image_id))
+        return OpenStackMachineImage(self.provider, self.provider.images.get_image(image_id))
+
+    @property
+    def instance_state(self):
+        return OpenStackInstance.INSTANCE_STATE_MAP.get(
+            self._os_instance.status, InstanceState.UNKNOWN)
+
+    def refresh(self):
+        """
+        Refreshes the state of this instance by re-querying the cloud provider
+        for its latest state.
+        """
+        self._os_instance = self.provider.compute.get_instance(self.instance_id)._os_instance