You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by al...@apache.org on 2015/03/27 12:10:05 UTC

libcloud git commit: Add state to StorageVolume

Repository: libcloud
Updated Branches:
  refs/heads/trunk b81ede37f -> 7845e08a9


Add state to StorageVolume

closes #476


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/7845e08a
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/7845e08a
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/7845e08a

Branch: refs/heads/trunk
Commit: 7845e08a9d35f2c37c468c43511cf9677fb863b9
Parents: b81ede3
Author: Allard Hoeve <al...@byte.nl>
Authored: Wed Mar 4 16:41:07 2015 +0100
Committer: Allard Hoeve <al...@byte.nl>
Committed: Fri Mar 27 12:08:20 2015 +0100

----------------------------------------------------------------------
 CHANGES.rst                                     | 12 ++++++++++
 libcloud/compute/base.py                        | 12 ++++++++--
 libcloud/compute/drivers/ec2.py                 | 20 ++++++++++++++++-
 libcloud/compute/drivers/ibm_sce.py             |  2 +-
 libcloud/compute/drivers/openstack.py           | 23 +++++++++++++++++++-
 libcloud/compute/types.py                       | 15 +++++++++++++
 .../compute/fixtures/ec2/describe_volumes.xml   |  6 ++---
 .../fixtures/openstack_v1.1/_os_volumes.json    |  2 +-
 libcloud/test/compute/test_base.py              |  6 ++++-
 libcloud/test/compute/test_ec2.py               | 15 +++++++++----
 libcloud/test/compute/test_openstack.py         |  7 ++++--
 11 files changed, 104 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/7845e08a/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index bd839d5..84e0c6b 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -20,6 +20,18 @@ Compute
   (GITHUB-488, LIBCLOUD-682)
   [Greg Hill]
 
+- StorageVolume objects now have an attribute `state` that holds a
+  state variable that is standardized state across drivers. Drivers that
+  currently support the `state` attribute are OpenStack and EC2.
+  StorageVolume objects returned by drivers that do not support the
+  attribute will have a `state` of `None`. When a provider returns a state
+  that is unknown to the driver, the state will be `UNKNOWN`. Please report
+  such states. A couple of drivers already put state fields in the `extra`
+  fields of StorageVolumes. These fields were kept for
+  backwards-compatibility and for reference.
+  (GITHUB-476)
+  [Allard Hoeve]
+
 - StorageVolume objects on EC2 and OpenStack now have a key called snapshot_id
   in their extra dicts containing the snapshot ID the volume was based on.
   (GITHUB-479)

http://git-wip-us.apache.org/repos/asf/libcloud/blob/7845e08a/libcloud/compute/base.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/base.py b/libcloud/compute/base.py
index d0c8399..4cfcf46 100644
--- a/libcloud/compute/base.py
+++ b/libcloud/compute/base.py
@@ -30,7 +30,8 @@ from libcloud.utils.py3 import b
 
 import libcloud.compute.ssh
 from libcloud.pricing import get_size_price
-from libcloud.compute.types import NodeState, DeploymentError
+from libcloud.compute.types import NodeState, StorageVolumeState,\
+    DeploymentError
 from libcloud.compute.ssh import SSHClient
 from libcloud.common.base import ConnectionKey
 from libcloud.common.base import BaseDriver
@@ -68,6 +69,7 @@ __all__ = [
     'NodeDriver',
 
     'StorageVolume',
+    'StorageVolumeState',
     'VolumeSnapshot',
 
     # Deprecated, moved to libcloud.utils.networking
@@ -460,7 +462,8 @@ class StorageVolume(UuidMixin):
     A base StorageVolume class to derive from.
     """
 
-    def __init__(self, id, name, size, driver, extra=None):
+    def __init__(self, id, name, size, driver,
+                 state=None, extra=None):
         """
         :param id: Storage volume ID.
         :type id: ``str``
@@ -474,6 +477,10 @@ class StorageVolume(UuidMixin):
         :param driver: Driver this image belongs to.
         :type driver: :class:`.NodeDriver`
 
+        :param state: Optional state of the StorageVolume. If not
+                      provided, will default to UNKNOWN.
+        :type state: :class:`.StorageVolumeState`
+
         :param extra: Optional provider specific attributes.
         :type extra: ``dict``
         """
@@ -482,6 +489,7 @@ class StorageVolume(UuidMixin):
         self.size = size
         self.driver = driver
         self.extra = extra
+        self.state = state
         UuidMixin.__init__(self)
 
     def list_snapshots(self):

http://git-wip-us.apache.org/repos/asf/libcloud/blob/7845e08a/libcloud/compute/drivers/ec2.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py
index b43aa88..67a4d52 100644
--- a/libcloud/compute/drivers/ec2.py
+++ b/libcloud/compute/drivers/ec2.py
@@ -41,7 +41,8 @@ from libcloud.compute.providers import Provider
 from libcloud.compute.base import Node, NodeDriver, NodeLocation, NodeSize
 from libcloud.compute.base import NodeImage, StorageVolume, VolumeSnapshot
 from libcloud.compute.base import KeyPair
-from libcloud.compute.types import NodeState, KeyPairDoesNotExistError
+from libcloud.compute.types import NodeState, KeyPairDoesNotExistError, \
+    StorageVolumeState
 
 __all__ = [
     'API_VERSION',
@@ -1996,6 +1997,17 @@ class BaseEC2NodeDriver(NodeDriver):
         'terminated': NodeState.TERMINATED
     }
 
+    # http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_Volume.html
+    VOLUME_STATE_MAP = {
+        'available': StorageVolumeState.AVAILABLE,
+        'in-use': StorageVolumeState.INUSE,
+        'error': StorageVolumeState.ERROR,
+        'creating': StorageVolumeState.CREATING,
+        'deleting': StorageVolumeState.DELETING,
+        'deleted': StorageVolumeState.DELETED,
+        'error_deleting': StorageVolumeState.ERROR
+    }
+
     def list_nodes(self, ex_node_ids=None, ex_filters=None):
         """
         List all nodes
@@ -4699,6 +4711,11 @@ class BaseEC2NodeDriver(NodeDriver):
         volId = findtext(element=element, xpath='volumeId',
                          namespace=NAMESPACE)
         size = findtext(element=element, xpath='size', namespace=NAMESPACE)
+        raw_state = findtext(element=element, xpath='status',
+                             namespace=NAMESPACE)
+
+        state = self.VOLUME_STATE_MAP.get(raw_state,
+                                          StorageVolumeState.UNKNOWN)
 
         # Get our tags
         tags = self._get_resource_tags(element)
@@ -4717,6 +4734,7 @@ class BaseEC2NodeDriver(NodeDriver):
                              name=name,
                              size=int(size),
                              driver=self,
+                             state=state,
                              extra=extra)
 
     def _to_snapshots(self, response):

http://git-wip-us.apache.org/repos/asf/libcloud/blob/7845e08a/libcloud/compute/drivers/ibm_sce.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/ibm_sce.py b/libcloud/compute/drivers/ibm_sce.py
index bcf73b9..66cbec6 100644
--- a/libcloud/compute/drivers/ibm_sce.py
+++ b/libcloud/compute/drivers/ibm_sce.py
@@ -711,7 +711,7 @@ class IBMNodeDriver(NodeDriver):
                              object.findtext('Name'),
                              object.findtext('Size'),
                              self.connection.driver,
-                             extra)
+                             extra=extra)
 
     def _to_volume_offerings(self, object):
         return [self._to_volume_offering(iType) for iType in

http://git-wip-us.apache.org/repos/asf/libcloud/blob/7845e08a/libcloud/compute/drivers/openstack.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/openstack.py b/libcloud/compute/drivers/openstack.py
index df32d2b..8e0dc9d 100644
--- a/libcloud/compute/drivers/openstack.py
+++ b/libcloud/compute/drivers/openstack.py
@@ -45,7 +45,7 @@ from libcloud.compute.base import NodeSize, NodeImage
 from libcloud.compute.base import (NodeDriver, Node, NodeLocation,
                                    StorageVolume, VolumeSnapshot)
 from libcloud.compute.base import KeyPair
-from libcloud.compute.types import NodeState, Provider
+from libcloud.compute.types import NodeState, StorageVolumeState, Provider
 from libcloud.pricing import get_size_price
 from libcloud.utils.xml import findall
 
@@ -104,6 +104,21 @@ class OpenStackNodeDriver(NodeDriver, OpenStackDriverMixin):
         'UNKNOWN': NodeState.UNKNOWN
     }
 
+    # http://developer.openstack.org/api-ref-blockstorage-v2.html#volumes-v2
+    VOLUME_STATE_MAP = {
+        'creating': StorageVolumeState.CREATING,
+        'available': StorageVolumeState.AVAILABLE,
+        'attaching': StorageVolumeState.ATTACHING,
+        'in-use': StorageVolumeState.INUSE,
+        'deleting': StorageVolumeState.DELETING,
+        'error': StorageVolumeState.ERROR,
+        'error_deleting': StorageVolumeState.ERROR,
+        'backing-up': StorageVolumeState.BACKUP,
+        'restoring-backup': StorageVolumeState.BACKUP,
+        'error_restoring': StorageVolumeState.ERROR,
+        'error_extending': StorageVolumeState.ERROR,
+    }
+
     def __new__(cls, key, secret=None, secure=True, host=None, port=None,
                 api_version=DEFAULT_API_VERSION, **kwargs):
         if cls is OpenStackNodeDriver:
@@ -2090,14 +2105,20 @@ class OpenStack_1_1_NodeDriver(OpenStackNodeDriver):
     def _to_volume(self, api_node):
         if 'volume' in api_node:
             api_node = api_node['volume']
+
+        state = self.VOLUME_STATE_MAP.get(api_node['status'],
+                                          StorageVolumeState.UNKNOWN)
+
         return StorageVolume(
             id=api_node['id'],
             name=api_node['displayName'],
             size=api_node['size'],
+            state=state,
             driver=self,
             extra={
                 'description': api_node['displayDescription'],
                 'attachments': [att for att in api_node['attachments'] if att],
+                # TODO: remove in 1.18.0
                 'state': api_node.get('status', None),
                 'snapshot_id': api_node.get('snapshotId', None),
                 'location': api_node.get('availabilityZone', None),

http://git-wip-us.apache.org/repos/asf/libcloud/blob/7845e08a/libcloud/compute/types.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/types.py b/libcloud/compute/types.py
index 0aeaf4b..e59a397 100644
--- a/libcloud/compute/types.py
+++ b/libcloud/compute/types.py
@@ -223,6 +223,21 @@ class NodeState(object):
         return getattr(cls, value.upper(), None)
 
 
+class StorageVolumeState(object):
+    """
+    Standard states of a StorageVolume
+    """
+    AVAILABLE = 0
+    ERROR = 1
+    INUSE = 2
+    CREATING = 3
+    DELETING = 4
+    DELETED = 5
+    BACKUP = 6
+    ATTACHING = 7
+    UNKNOWN = 8
+
+
 class Architecture(object):
     """
     Image and size architectures.

http://git-wip-us.apache.org/repos/asf/libcloud/blob/7845e08a/libcloud/test/compute/fixtures/ec2/describe_volumes.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/ec2/describe_volumes.xml b/libcloud/test/compute/fixtures/ec2/describe_volumes.xml
index 5dde8e4..f3ab603 100644
--- a/libcloud/test/compute/fixtures/ec2/describe_volumes.xml
+++ b/libcloud/test/compute/fixtures/ec2/describe_volumes.xml
@@ -15,7 +15,7 @@
             <size>11</size>
             <snapshotId/>
             <availabilityZone>us-east-1c</availabilityZone>
-            <status>available</status>
+            <status>in-use</status>
             <createTime>2013-10-08T19:36:49.000Z</createTime>
             <attachmentSet/>
         </item>
@@ -24,7 +24,7 @@
             <size>8</size>
             <snapshotId>snap-30d37269</snapshotId>
             <availabilityZone>us-east-1d</availabilityZone>
-            <status>in-use</status>
+            <status>some-unknown-status</status>
             <createTime>2013-06-25T02:04:12.000Z</createTime>
             <attachmentSet>
                 <item>
@@ -39,4 +39,4 @@
             <volumeType>standard</volumeType>
         </item>
     </volumeSet>
-</DescribeVolumesResponse>
\ No newline at end of file
+</DescribeVolumesResponse>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/7845e08a/libcloud/test/compute/fixtures/openstack_v1.1/_os_volumes.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/openstack_v1.1/_os_volumes.json b/libcloud/test/compute/fixtures/openstack_v1.1/_os_volumes.json
index b0c1a32..4218845 100644
--- a/libcloud/test/compute/fixtures/openstack_v1.1/_os_volumes.json
+++ b/libcloud/test/compute/fixtures/openstack_v1.1/_os_volumes.json
@@ -32,7 +32,7 @@
             "metadata": {},
             "size": 50,
             "snapshotId": "01f48111-7866-4cd2-986a-e92683c4a363",
-            "status": "available",
+            "status": "some-unknown-state",
             "volumeType": "None"
         }
     ]

http://git-wip-us.apache.org/repos/asf/libcloud/blob/7845e08a/libcloud/test/compute/test_base.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_base.py b/libcloud/test/compute/test_base.py
index 84edf95..5173cf9 100644
--- a/libcloud/test/compute/test_base.py
+++ b/libcloud/test/compute/test_base.py
@@ -18,8 +18,9 @@ import unittest
 from libcloud.common.base import Response
 from libcloud.common.base import Connection, ConnectionKey, ConnectionUserAndKey
 from libcloud.common.types import LibcloudError
-from libcloud.compute.base import Node, NodeSize, NodeImage, NodeDriver
+from libcloud.compute.base import Node, NodeSize, NodeImage, NodeDriver, StorageVolume
 from libcloud.compute.base import NodeAuthSSHKey, NodeAuthPassword
+from libcloud.compute.types import StorageVolumeState
 
 from libcloud.test import MockResponse           # pylint: disable-msg=E0611
 
@@ -41,6 +42,9 @@ class BaseTests(unittest.TestCase):
     def test_base_node_image(self):
         NodeImage(id=0, name=0, driver=FakeDriver())
 
+    def test_base_storage_volume(self):
+        StorageVolume(id="0", name="0", size=10, driver=FakeDriver(), state=StorageVolumeState.AVAILABLE)
+
     def test_base_response(self):
         Response(MockResponse(status=200, body='foo'), ConnectionKey('foo'))
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/7845e08a/libcloud/test/compute/test_ec2.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_ec2.py b/libcloud/test/compute/test_ec2.py
index f74fa94..9ad0a0b 100644
--- a/libcloud/test/compute/test_ec2.py
+++ b/libcloud/test/compute/test_ec2.py
@@ -39,7 +39,7 @@ from libcloud.compute.drivers.ec2 import ExEC2AvailabilityZone
 from libcloud.compute.drivers.ec2 import EC2NetworkSubnet
 from libcloud.compute.base import Node, NodeImage, NodeSize, NodeLocation
 from libcloud.compute.base import StorageVolume, VolumeSnapshot
-from libcloud.compute.types import KeyPairDoesNotExistError
+from libcloud.compute.types import KeyPairDoesNotExistError, StorageVolumeState
 
 from libcloud.test import MockHttpTestCase, LibcloudTestCase
 from libcloud.test.compute import TestCaseMixin
@@ -772,18 +772,21 @@ class EC2Tests(LibcloudTestCase, TestCaseMixin):
         self.assertEqual('vol-10ae5e2b', volumes[0].id)
         self.assertEqual(1, volumes[0].size)
         self.assertEqual('available', volumes[0].extra['state'])
+        self.assertEqual(StorageVolumeState.AVAILABLE, volumes[0].state)
 
         self.assertEqual('vol-v24bfh75', volumes[1].id)
         self.assertEqual(11, volumes[1].size)
-        self.assertEqual('available', volumes[1].extra['state'])
         self.assertIsNone(volumes[1].extra['snapshot_id'])
+        self.assertEqual('in-use', volumes[1].extra['state'])
+        self.assertEqual(StorageVolumeState.INUSE, volumes[1].state)
 
         self.assertEqual('vol-b6c851ec', volumes[2].id)
         self.assertEqual(8, volumes[2].size)
-        self.assertEqual('in-use', volumes[2].extra['state'])
+        self.assertEqual('some-unknown-status', volumes[2].extra['state'])
         self.assertEqual('i-d334b4b3', volumes[2].extra['instance_id'])
         self.assertEqual('/dev/sda1', volumes[2].extra['device'])
         self.assertEqual('snap-30d37269', volumes[2].extra['snapshot_id'])
+        self.assertEqual(StorageVolumeState.UNKNOWN, volumes[2].state)
 
     def test_create_volume(self):
         location = self.driver.list_locations()[0]
@@ -796,6 +799,7 @@ class EC2Tests(LibcloudTestCase, TestCaseMixin):
 
     def test_destroy_volume(self):
         vol = StorageVolume(id='vol-4282672b', name='test',
+                            state=StorageVolumeState.AVAILABLE,
                             size=10, driver=self.driver)
 
         retValue = self.driver.destroy_volume(vol)
@@ -803,7 +807,8 @@ class EC2Tests(LibcloudTestCase, TestCaseMixin):
 
     def test_attach(self):
         vol = StorageVolume(id='vol-4282672b', name='test',
-                            size=10, driver=self.driver)
+                            size=10, state=StorageVolumeState.AVAILABLE,
+                            driver=self.driver)
 
         node = Node('i-4382922a', None, None, None, None, self.driver)
         retValue = self.driver.attach_volume(node, vol, '/dev/sdh')
@@ -812,6 +817,7 @@ class EC2Tests(LibcloudTestCase, TestCaseMixin):
 
     def test_detach(self):
         vol = StorageVolume(id='vol-4282672b', name='test',
+                            state=StorageVolumeState.INUSE,
                             size=10, driver=self.driver)
 
         retValue = self.driver.detach_volume(vol)
@@ -819,6 +825,7 @@ class EC2Tests(LibcloudTestCase, TestCaseMixin):
 
     def test_create_volume_snapshot(self):
         vol = StorageVolume(id='vol-4282672b', name='test',
+                            state=StorageVolumeState.AVAILABLE,
                             size=10, driver=self.driver)
         snap = self.driver.create_volume_snapshot(
             vol, 'Test snapshot')

http://git-wip-us.apache.org/repos/asf/libcloud/blob/7845e08a/libcloud/test/compute/test_openstack.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_openstack.py b/libcloud/test/compute/test_openstack.py
index f3524ec..08b2c20 100644
--- a/libcloud/test/compute/test_openstack.py
+++ b/libcloud/test/compute/test_openstack.py
@@ -34,7 +34,7 @@ from libcloud.utils.py3 import u
 
 from libcloud.common.types import InvalidCredsError, MalformedResponseError, \
     LibcloudError
-from libcloud.compute.types import Provider, KeyPairDoesNotExistError
+from libcloud.compute.types import Provider, KeyPairDoesNotExistError, StorageVolumeState
 from libcloud.compute.providers import get_driver
 from libcloud.compute.drivers.openstack import (
     OpenStack_1_0_NodeDriver, OpenStack_1_0_Response,
@@ -794,6 +794,7 @@ class OpenStack_1_1_Tests(unittest.TestCase, TestCaseMixin):
 
         self.assertEqual('cd76a3a1-c4ce-40f6-9b9f-07a61508938d', volume.id)
         self.assertEqual('test_volume_2', volume.name)
+        self.assertEqual(StorageVolumeState.AVAILABLE, volume.state)
         self.assertEqual(2, volume.size)
         self.assertEqual(volume.extra, {
             'description': '',
@@ -811,15 +812,17 @@ class OpenStack_1_1_Tests(unittest.TestCase, TestCaseMixin):
             'created_at': '2013-06-24T11:20:13.000000',
         })
 
+        # also test that unknown state resolves to StorageVolumeState.UNKNOWN
         volume = volumes[1]
         self.assertEqual('cfcec3bc-b736-4db5-9535-4c24112691b5', volume.id)
         self.assertEqual('test_volume', volume.name)
         self.assertEqual(50, volume.size)
+        self.assertEqual(StorageVolumeState.UNKNOWN, volume.state)
         self.assertEqual(volume.extra, {
             'description': 'some description',
             'attachments': [],
             'snapshot_id': '01f48111-7866-4cd2-986a-e92683c4a363',
-            'state': 'available',
+            'state': 'some-unknown-state',
             'location': 'nova',
             'volume_type': 'None',
             'metadata': {},