Author: tomaz
Date: Wed Aug 22 04:33:49 2012
New Revision: 1375895

URL: http://svn.apache.org/viewvc?rev=1375895&view=rev
Log:
Add new methods for managing storage volumes and other extenstion methods
to the IBM SCE driver. Contributed by Sengor Kusturica, part of LIBCLOUD-242.

Added:
    libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/allocate_address.xml
    libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/attach_volume.xml
    libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/create_volume.xml
    libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/delete_address.xml
    libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/destroy_volume.xml
    libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/detach_volume.xml
    libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_addresses.xml
    
libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_storage_offerings.xml
    libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_volumes.xml
Modified:
    libcloud/trunk/CHANGES
    libcloud/trunk/libcloud/compute/drivers/ibm_sce.py
    libcloud/trunk/libcloud/test/compute/test_ibm_sce.py

Modified: libcloud/trunk/CHANGES
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/CHANGES?rev=1375895&r1=1375894&r2=1375895&view=diff
==============================================================================
--- libcloud/trunk/CHANGES (original)
+++ libcloud/trunk/CHANGES Wed Aug 22 04:33:49 2012
@@ -19,6 +19,10 @@ Changes with Apache Libcloud in developm
       LIBCLOUD-243
       [Nick Bailey]
 
+    - Add new methods for managing storage volumes and other extenstion methods
+      to the IBM SCE driver. ; LIBCLOUD-242
+      [Sengor Kusturica]
+
   *) Storage
 
     - Add the following new methods to the CloudFiles driver:

Modified: libcloud/trunk/libcloud/compute/drivers/ibm_sce.py
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/ibm_sce.py?rev=1375895&r1=1375894&r2=1375895&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/ibm_sce.py (original)
+++ libcloud/trunk/libcloud/compute/drivers/ibm_sce.py Wed Aug 22 04:33:49 2012
@@ -17,20 +17,22 @@
 Driver for IBM SmartCloud Enterprise
 
 Formerly known as:
-- IBM Developer Cloud.
+- IBM Developer Cloud
+- IBM Smart Business Development and Test on the IBM Cloud
 - IBM SmartBusiness Cloud
 """
 
 import base64
+import time
 
 from libcloud.utils.py3 import urlencode
 from libcloud.utils.py3 import b
 
 from libcloud.common.base import XmlResponse, ConnectionUserAndKey
-from libcloud.common.types import InvalidCredsError
+from libcloud.common.types import InvalidCredsError, LibcloudError
 from libcloud.compute.types import NodeState, Provider
 from libcloud.compute.base import NodeDriver, Node, NodeImage, \
-    NodeSize, NodeLocation, NodeAuthSSHKey
+    NodeSize, NodeLocation, NodeAuthSSHKey, StorageVolume
 
 HOST = 'www-147.ibm.com'
 REST_BASE = '/computecloud/enterprise/api/rest/20100331'
@@ -51,7 +53,7 @@ class IBMResponse(XmlResponse):
 
 class IBMConnection(ConnectionUserAndKey):
     """
-    Connection class for the IBM Developer Cloud driver
+    Connection class for the IBM SmartCloud Enterprise driver
     """
 
     host = HOST
@@ -69,6 +71,77 @@ class IBMConnection(ConnectionUserAndKey
         return urlencode(data)
 
 
+class IBMNodeLocation(NodeLocation):
+    """
+    Extends the base LibCloud NodeLocation to contain additional attributes
+    """
+    def __init__(self, id, name, country, driver, extra=None):
+        self.id = str(id)
+        self.name = name
+        self.country = country
+        self.driver = driver
+        self.extra = extra or {}
+
+    def __repr__(self):
+        return ('<IBMNodeLocation: id=%s, name=%s, country=%s, '
+                'driver=%s, extra=%s>' % self.id, self.name, self.country,
+                self.driver.name, self.extra)
+
+
+class VolumeState(object):
+    """
+    The SCE specific states for a storage volume
+    """
+    NEW = '0'
+    CREATING = '1'
+    DELETING = '2'
+    DELETED = '3'
+    DETACHED = '4'
+    ATTACHED = '5'
+    FAILED = '6'
+    DELETE_PENDING = '7'
+    BEING_CLONED = '8'
+    CLONING = '9'
+    ATTACHING = '10'
+    DETACHING = '11'
+    ATTACHIED = '12'
+    IMPORTING = '13'
+    TRANSFER_RETRYING = '14'
+
+
+class VolumeOffering(object):
+    """
+    An SCE specific storage volume offering class.
+    The volume offering ID is needed to create a volume.
+    Volume offering IDs are different for each data center.
+    """
+    def __init__(self, id, name, location, extra=None):
+        self.id = id
+        self.location = location
+        self.name = name
+        self.extra = extra or {}
+
+    def __repr__(self):
+        return ('<VolumeOffering: id=%s, location=%s, name=%s, extra=%s>' %
+                 self.id, self.location, self.name, self.extra)
+
+
+class Address(object):
+    """
+    A reserved IP address that can be attached to an instance.
+    Properties: id, ip, state, options(location, type, created_time, state, 
hostname, instance_ids, vlan, owner,
+    mode, offering_id)
+    """
+    def __init__(self, id, ip, state, options):
+        self.id = id
+        self.ip = ip
+        self.state = state
+        self.options = options
+
+    def __repr__(self):
+        return ('<Address: id=%s, ip=%s, state=%s, options=%s>' %
+                 self.id, self.ip, self.state, self.options)
+
 class IBMNodeDriver(NodeDriver):
     """
     Node driver for IBM SmartCloud Enterprise
@@ -94,12 +167,14 @@ class IBMNodeDriver(NodeDriver):
         12: NodeState.PENDING,     # Deprovision Pending
         13: NodeState.PENDING,     # Restart Pending
         14: NodeState.PENDING,     # Attaching
-        15: NodeState.PENDING,      # Detaching
+        15: NodeState.PENDING,     # Detaching
     }
 
     def create_node(self, **kwargs):
         """
-        Creates a node in the IBM Developer Cloud.
+        Creates a node in the IBM SmartCloud Enterprise.
+
+        See L{NodeDriver.create_node} for more keyword args.
 
         @inherits: L{NodeDriver.create_node}
 
@@ -131,8 +206,9 @@ class IBMNodeDriver(NodeDriver):
             data.update({'publicKey': kwargs['auth'].pubkey})
         if 'ex_configurationData' in kwargs:
             configurationData = kwargs['ex_configurationData']
-            for key in configurationData.keys():
-                data.update({key: configurationData.get(key)})
+            if configurationData:
+                for key in configurationData.keys():
+                    data.update({key: configurationData.get(key)})
 
         # Send request!
         resp = self.connection.request(
@@ -142,12 +218,164 @@ class IBMNodeDriver(NodeDriver):
             data=data).object
         return self._to_nodes(resp)[0]
 
+    def create_volume(self, size, name, location, **kwargs):
+        """
+        Create a new block storage volume (virtual disk)
+
+        @param      size: Size of volume in gigabytes (required).
+                          Find out the possible sizes from the
+                          offerings/storage REST interface
+        @type       size: C{int}
+
+        @keyword    name: Name of the volume to be created (required)
+        @type       name: C{str}
+
+        @keyword    location: Which data center to create a volume in. If
+                              empty, it will fail for IBM SmartCloud Enterprise
+                              (required)
+        @type       location: L{NodeLocation}
+
+        @keyword    snapshot:  Not supported for IBM SmartCloud Enterprise
+        @type       snapshot:  C{str}
+
+        @keyword    kwargs.format:  Either RAW or EXT3 for IBM SmartCloud
+                                    Enterprise (optional)
+        @type       kwargs.format:  C{str}
+
+        @keyword    kwargs.offering_id:  The storage offering ID for IBM
+                                         SmartCloud Enterprise
+                                         Find this from the REST interface
+                                         storage/offerings. (optional)
+        @type       kwargs.offering_id:  C{str}
+
+        @keyword    kwargs.source_disk_id:  If cloning a volume, the storage
+                                            disk to make a copy from (optional)
+        @type       kwargs.source_disk_id:  C{str}
+
+        @keyword    kwargs.storage_area_id:  The id of the storage availability
+                                             area to create the volume in
+                                             (optional)
+        @type       kwargs.storage_area_id:  C{str}
+
+        @keyword    kwargs.target_location_id:  If cloning a volume, the
+                                                storage disk to make a copy
+                                                from (optional)
+        @type       kwargs.target_location_id:  C{str}
+
+        @return: The newly created L{StorageVolume}.
+        """
+        data = {}
+        data.update({'name': name})
+        data.update({'size': size})
+        data.update({'location': location})
+        if (('format' in kwargs) and (kwargs['format'] is not None)):
+            data.update({'format': kwargs['format']})
+        if (('offering_id' in kwargs) and (kwargs['offering_id'] is not None)):
+            data.update({'offeringID': kwargs['offering_id']})
+        if (('storage_area_id' in kwargs) and (kwargs['storage_area_id'] is 
not None)):
+            data.update({'storageAreaID': kwargs['storage_area_id']})
+        if 'source_disk_id' in kwargs:
+            data.update({'sourceDiskID': kwargs['source_disk_id']})
+            data.update({'type': 'clone'})
+        if 'target_location_id' in kwargs:
+            data.update({'targetLocationID': kwargs['target_location_id']})
+        resp = self.connection.request(action=REST_BASE + '/storage',
+            headers={'Content-Type': 'application/x-www-form-urlencoded'},
+            method='POST',
+            data=data).object
+        return self._to_volumes(resp)[0]
+
+    def create_image(self, name, description=None, **kwargs):
+        """
+        Create a new node image from an existing volume or image.
+
+        @param      name: Name of the image to be created (required)
+        @type       name: C{str}
+
+        @param      description: Description of the image to be created 
(optional)
+        @type       description: L{str}
+
+        @keyword    kwarge.image_id:  The ID of the source image if cloning 
the image
+        @type       kwargs.image_id:  C{str}
+
+        @keyword    kwargs.volume_id:  The ID of the storage volume if 
importing the image
+        @type       kwargs.volume_id:  C{str}
+
+        @return: The newly created L{NodeImage}.
+        """
+        data = {}
+        data.update({'name': name})
+        if description is not None:
+            data.update({'description': description})
+        if (('image_id' in kwargs) and (kwargs['image_id'] is not None)):
+            data.update({'imageId': kwargs['image_id']})
+        if (('volume_id' in kwargs) and (kwargs['volume_id'] is not None)):
+            data.update({'volumeId': kwargs['volume_id']})
+        resp = self.connection.request(action=REST_BASE + '/offerings/image',
+            headers={'Content-Type': 'application/x-www-form-urlencoded'},
+            method='POST',
+            data=data).object
+        return self._to_images(resp)[0]
+
     def destroy_node(self, node):
         url = REST_BASE + '/instances/%s' % (node.id)
         status = int(self.connection.request(action=url,
                                              method='DELETE').status)
         return status == 200
 
+    def destroy_volume(self, volume):
+        """
+        Destroys a storage volume.
+
+        @param      volume: Volume to be destroyed
+        @type       volume: L{StorageVolume}
+
+        @return: C{bool}
+        """
+        url = REST_BASE + '/storage/%s' % (volume.id)
+        status = int(self.connection.request(action=url,
+                                             method='DELETE').status)
+        return status == 200
+
+    def attach_volume(self, node, volume):
+        """
+        Attaches volume to node.
+
+        @param      node: Node to attach volume to
+        @type       node: L{Node}
+
+        @param      volume: Volume to attach
+        @type       volume: L{StorageVolume}
+
+        @return: C{bool}
+        """
+        url = REST_BASE + '/instances/%s' % (node.id)
+        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
+        data = {'storageID': volume.id, 'type': 'attach'}
+        resp = self.connection.request(action=url,
+                                       method='PUT',
+                                       headers=headers,
+                                       data=data)
+        return int(resp.status) == 200
+
+    def detach_volume(self, node, volume):
+        """
+        Detaches a volume from a node.
+
+        @param      volume: Volume to be detached
+        @type       volume: L{StorageVolume}
+
+        @returns C{bool}
+        """
+        url = REST_BASE + '/instances/%s' % (node.id)
+        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
+        data = {'storageID': volume.id, 'type': 'detach'}
+        resp = self.connection.request(action=url,
+                                       method='PUT',
+                                       headers=headers,
+                                       data=data)
+        return int(resp.status) == 200
+
     def reboot_node(self, node):
         url = REST_BASE + '/instances/%s' % (node.id)
         headers = {'Content-Type': 'application/x-www-form-urlencoded'}
@@ -167,10 +395,21 @@ class IBMNodeDriver(NodeDriver):
         return self._to_images(
             self.connection.request(REST_BASE + '/offerings/image').object)
 
+    def list_volumes(self):
+        """
+        List storage volumes.
+
+        @return: C{list} of L{StorageVolume} objects
+        """
+        return self._to_volumes(
+            self.connection.request(REST_BASE + '/storage').object)
+
     def list_sizes(self, location=None):
         """
-        Returns a generic list of sizes.  See list_images() for a
-        list of supported sizes for specific images.
+        Returns a generic list of sizes.  See list_images() for a list of 
supported
+        sizes for specific images.  In particular, you need to have a size that
+        matches the architecture (32-bit vs 64-bit) of the virtual machine 
image
+        operating system.
 
         @inherits: L{NodeDriver.list_sizes}
         """
@@ -195,9 +434,124 @@ class IBMNodeDriver(NodeDriver):
                      None, None, None, None, self.connection.driver)]
 
     def list_locations(self):
+        """
+        List the data center locations
+        """
         return self._to_locations(
             self.connection.request(REST_BASE + '/locations').object)
 
+    def ex_list_storage_offerings(self):
+        """
+        List the storage center offerings
+        """
+        return self._to_volume_offerings(
+            self.connection.request(REST_BASE + '/offerings/storage').object)
+
+    def ex_allocate_address(self, location_id, offering_id, vlan_id=None):
+        """
+        Allocate a new reserved IP address
+
+        @param      location_id: Target data center
+        @type       location_id: L{str}
+        @param      offering_id: Offering ID for address to create
+        @type       offering_id: L{str}
+        @param      vlan_id: ID of target VLAN
+        @type       vlan_id: L{str}
+        @return:    L{Address} object
+        """
+        url = REST_BASE + '/addresses'
+        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
+        data = {'location': location_id, 'offeringID': offering_id}
+        if vlan_id is not None:
+            data.update({'vlanID': vlan_id})
+        resp = self.connection.request(action=url,
+                                       method='POST',
+                                       headers=headers,
+                                       data=data).object
+        return self._to_addresses(resp)[0]
+
+    def ex_list_addresses(self, resource_id=None):
+        """
+        List the reserved IP addresses
+
+        @param      resource_id: If this is supplied only a single address 
will be returned (optional)
+        @type       resource_id: L{str}
+        """
+        url = REST_BASE + '/addresses'
+        if resource_id:
+            url += '/' + resource_id
+        return self._to_addresses(self.connection.request(url).object)
+
+    def ex_copy_to(self, image, volume):
+        """
+        Copies a node image to a storage volume
+
+        @param      image: source image to copy
+        @type       image: L{NodeImage}
+
+        @param      volume: Target storage volume to copy to
+        @type       volume: L{StorageVolume}
+
+        @return: C{bool} The success of the operation
+        """
+        url = REST_BASE + '/storage/%s' % (volume.id)
+        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
+        data = {'imageId': image.id}
+        resp = self.connection.request(action=url,
+                                       method='PUT',
+                                       headers=headers,
+                                       data=data)
+        return int(resp.status) == 200
+
+    def ex_delete_address(self, resource_id):
+        """
+        Delete a reserved IP address
+
+        @param      resource_id: The address to delete (required)
+        @type       resource_id: L{str}
+        """
+        url = REST_BASE + '/addresses/' + resource_id
+        status = int(self.connection.request(action=url,
+                                             method='DELETE').status)
+        return status == 200
+
+    def ex_wait_storage_state(self, volume, state=VolumeState.DETACHED,
+                              wait_period=60, timeout=1200):
+        """
+        Block until storage volume state changes to the given value
+
+        @param      volume: Storage volume.
+        @type       node: C{StorageVolume}
+
+        @param      state: The target state to wait for
+        @type       state: C{int}
+
+        @param      wait_period: How many seconds to between each loop
+                                 iteration (default is 3)
+        @type       wait_period: C{int}
+
+        @param      timeout: How many seconds to wait before timing out
+                             (default is 1200)
+        @type       timeout: C{int}
+
+        @return: C{StorageVolume}
+        """
+        start = time.time()
+        end = start + timeout
+
+        while time.time() < end:
+            volumes = self.list_volumes()
+            volumes = list([v for v in volumes if v.uuid == volume.uuid])
+
+            if (len(volumes) == 1 and volumes[0].extra['state'] == state):
+                return volumes[0]
+            else:
+                time.sleep(wait_period)
+                continue
+
+        raise LibcloudError(value='Timed out after %d seconds' % (timeout),
+                            driver=self)
+
     def _to_nodes(self, object):
         return [self._to_node(instance) for instance in
                 object.findall('Instance')]
@@ -210,16 +564,16 @@ class IBMNodeDriver(NodeDriver):
             public_ips.append(ip)
 
         return Node(
-            id=instance.findtext('ID'),
-            name=instance.findtext('Name'),
-            state=self.NODE_STATE_MAP[int(instance.findtext('Status'))],
-            public_ips=public_ips,
-            private_ips=[],
-            driver=self.connection.driver
+                    id=instance.findtext('ID'),
+                    name=instance.findtext('Name'),
+                    
state=self.NODE_STATE_MAP[int(instance.findtext('Status'))],
+                    public_ips=public_ips,
+                    private_ips=[],
+                    driver=self.connection.driver
         )
 
     def _to_images(self, object):
-    #Converts data retrieved from SCE /offerings/image REST call to a NodeImage
+        # Converts data retrieved from SCE /offerings/image REST call to a 
NodeImage
         return [self._to_image(image) for image in object.findall('Image')]
 
     def _to_image(self, image):
@@ -248,7 +602,7 @@ class IBMNodeDriver(NodeDriver):
                              'platform': platform,
                              'description': description,
                              'documentation': documentation,
-                             'supportedInstanceTypes': nodeSizes
+                             'node_sizes': nodeSizes
                          }
                          )
 
@@ -259,11 +613,31 @@ class IBMNodeDriver(NodeDriver):
     def _to_location(self, location):
         # Converts an SCE Location object to a Libcloud NodeLocation object
         name_text = location.findtext('Name')
+        description = location.findtext('Description')
+        state = location.findtext('State')
         (nameVal, separator, countryVal) = name_text.partition(',')
-        return NodeLocation(id=location.findtext('ID'),
-                            name=nameVal,
-                            country=countryVal.strip(),
-                            driver=self.connection.driver)
+        capabiltyElements = location.findall('Capabilities/Capability')
+        capabilities = {}
+        for elem in capabiltyElements:
+            capabilityID = elem.attrib['id']
+            entryElements = elem.findall('Entry')
+            entries = []
+            for entryElem in entryElements:
+                key = entryElem.attrib['key']
+                valueElements = elem.findall('Value')
+                values = []
+                for valueElem in valueElements:
+                    values.append(valueElem.text)
+                entry = {'key': key, 'values': values}
+                entries.append(entry)
+            capabilities[capabilityID] = entries
+        extra = {'description': description, 'state': state,
+                 'capabilities': capabilities}
+        return IBMNodeLocation(id=location.findtext('ID'),
+                               name=nameVal,
+                               country=countryVal.strip(),
+                               driver=self.connection.driver,
+                               extra=extra)
 
     def _to_node_sizes(self, object):
         # Converts SCE SupportedInstanceTypes object to
@@ -280,3 +654,61 @@ class IBMNodeDriver(NodeDriver):
                         None,
                         object.findtext('Price/Rate'),
                         self.connection.driver)
+
+    def _to_volumes(self, object):
+        return [self._to_volume(iType) for iType in
+                object.findall('Volume')]
+
+    def _to_volume(self, object):
+        # Converts an SCE Volume to a Libcloud StorageVolume
+        extra = {'state': object.findtext('State'),
+                'location': object.findtext('Location'),
+                'instanceID': object.findtext('instanceID'),
+                'owner': object.findtext('Owner'),
+                'format': object.findtext('Format'),
+                'createdTime': object.findtext('CreatedTime'),
+                'storageAreaID': object.findtext('StorageArea/ID')}
+        return StorageVolume(object.findtext('ID'),
+                             object.findtext('Name'),
+                             object.findtext('Size'),
+                             self.connection.driver,
+                             extra)
+
+    def _to_volume_offerings(self, object):
+        return [self._to_volume_offering(iType) for iType in
+                object.findall('Offerings')]
+
+    def _to_volume_offering(self, object):
+        # Converts an SCE DescribeVolumeOfferingsResponse/Offerings XML object
+        # to an SCE VolumeOffering
+        extra = {'label': object.findtext('Label'),
+                'supported_sizes': object.findtext('SupportedSizes'),
+                'formats': object.findall('SupportedFormats/Format/ID'),
+                'price': object.findall('Price')}
+        return VolumeOffering(object.findtext('ID'),
+                              object.findtext('Name'),
+                              object.findtext('Location'),
+                              extra)
+
+    def _to_addresses(self, object):
+        # Converts an SCE DescribeAddressesResponse XML object to a list of
+        # Address objects
+        return [self._to_address(iType) for iType in
+                object.findall('Address')]
+
+    def _to_address(self, object):
+        # Converts an SCE DescribeAddressesResponse/Address XML object to
+        # an Address object
+        extra = {'location': object.findtext('Location'),
+                'type': object.findtext('Label'),
+                'created_time': object.findtext('SupportedSizes'),
+                'hostname': object.findtext('Hostname'),
+                'instance_ids': object.findtext('InstanceID'),
+                'vlan': object.findtext('VLAN'),
+                'owner': object.findtext('owner'),
+                'mode': object.findtext('Mode'),
+                'offering_id': object.findtext('OfferingID')}
+        return Address(object.findtext('ID'),
+                       object.findtext('IP'),
+                       object.findtext('State'),
+                       extra)

Added: 
libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/allocate_address.xml
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/allocate_address.xml?rev=1375895&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/allocate_address.xml 
(added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/allocate_address.xml 
Wed Aug 22 04:33:49 2012
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" 
standalone="yes"?><ns2:AllocateAddressResponse 
xmlns:ns2="http://www.ibm.com/xmlns/b2b/cloud/api/2010-03-31";><Address><Type>RESERVED</Type><IP></IP><Hostname></Hostname><Location>141</Location><ID>292795</ID><OfferingID>20001223</OfferingID><Mode>PRIMARY</Mode><State>0</State><owner>[email protected]</owner></Address></ns2:AllocateAddressResponse>
\ No newline at end of file

Added: libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/attach_volume.xml
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/attach_volume.xml?rev=1375895&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/attach_volume.xml 
(added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/attach_volume.xml Wed 
Aug 22 04:33:49 2012
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" 
standalone="yes"?><ns2:AttachStorageResponse 
xmlns:ns2="http://www.ibm.com/xmlns/b2b/cloud/api/2010-03-31"/>
\ No newline at end of file

Added: libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/create_volume.xml
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/create_volume.xml?rev=1375895&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/create_volume.xml 
(added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/create_volume.xml Wed 
Aug 22 04:33:49 2012
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" 
standalone="yes"?><ns2:CreateVolumeResponse 
xmlns:ns2="http://www.ibm.com/xmlns/b2b/cloud/api/2010-03-31";><Volume><ID>39293</ID><Location>141</Location><OfferingID>20001208</OfferingID><Owner>[email protected]</Owner><Name>test-volume</Name><Format>raw</Format><Size>256</Size><State>0</State><ProductCodes/><CreatedTime>2012-08-20T12:25:02.792Z</CreatedTime><StorageArea><ID></ID><Name></Name><Description></Description></StorageArea><IOPrice
 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.00</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>CNT</UnitOfMeasure></IOPrice><CloneStatus>0</CloneStatus><PlatformVersion>2</PlatformVersion><SourceDiskId>0</SourceDiskId></Volume></ns2:CreateVolumeResponse>
\ No newline at end of file

Added: libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/delete_address.xml
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/delete_address.xml?rev=1375895&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/delete_address.xml 
(added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/delete_address.xml 
Wed Aug 22 04:33:49 2012
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" 
standalone="yes"?><ns2:ReleaseAddressResponse 
xmlns:ns2="http://www.ibm.com/xmlns/b2b/cloud/api/2010-03-31"/>
\ No newline at end of file

Added: libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/destroy_volume.xml
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/destroy_volume.xml?rev=1375895&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/destroy_volume.xml 
(added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/destroy_volume.xml 
Wed Aug 22 04:33:49 2012
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" 
standalone="yes"?><ns2:DeleteVolumeResponse 
xmlns:ns2="http://www.ibm.com/xmlns/b2b/cloud/api/2010-03-31"/>
\ No newline at end of file

Added: libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/detach_volume.xml
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/detach_volume.xml?rev=1375895&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/detach_volume.xml 
(added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/detach_volume.xml Wed 
Aug 22 04:33:49 2012
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" 
standalone="yes"?><ns2:DetachStorageResponse 
xmlns:ns2="http://www.ibm.com/xmlns/b2b/cloud/api/2010-03-31"/>
\ No newline at end of file

Added: libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_addresses.xml
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_addresses.xml?rev=1375895&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_addresses.xml 
(added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_addresses.xml 
Wed Aug 22 04:33:49 2012
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" 
standalone="yes"?><ns2:DescribeAddressesResponse 
xmlns:ns2="http://www.ibm.com/xmlns/b2b/cloud/api/2010-03-31";><Address><Type>RESERVED</Type><IP>170.225.160.218</IP><Hostname>vhost0218</Hostname><Location>141</Location><ID>292795</ID><OfferingID>20001223</OfferingID><Mode>PRIMARY</Mode><State>2</State><owner>[email protected]</owner></Address></ns2:DescribeAddressesResponse>
\ No newline at end of file

Added: 
libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_storage_offerings.xml
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_storage_offerings.xml?rev=1375895&view=auto
==============================================================================
--- 
libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_storage_offerings.xml
 (added)
+++ 
libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_storage_offerings.xml
 Wed Aug 22 04:33:49 2012
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" 
standalone="yes"?><ns2:DescribeVolumeOfferingsResponse 
xmlns:ns2="http://www.ibm.com/xmlns/b2b/cloud/api/2010-03-31";><Offerings><ID>20001208</ID><Location>61</Location><Name>Small</Name><Label>256
 
GiB</Label><Capacity>256</Capacity><SupportedSizes>256</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price
 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001208</ID><Location>82</Location><Name>Small</Name><Label>256
 
GiB</Label><Capacity>256</Capacity><SupportedSizes>256</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price
 CountryCode="ABC"><EffectiveDate>2011
 
-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001209</ID><Location>61</Location><Name>Medium</Name><Label>512
 
GiB</Label><Capacity>512</Capacity><SupportedSizes>512</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price
 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001209</ID><Location>82</Location><Name>Medium</Name><Label>512
 
GiB</Label><Capacity>512</Capacity><SupportedSizes>512</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price
 CountryCod
 
e="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001208</ID><Location>41</Location><Name>Small</Name><Label>256
 
GiB</Label><Capacity>256</Capacity><SupportedSizes>256</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price
 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001209</ID><Location>41</Location><Name>Medium</Name><Label>512
 
GiB</Label><Capacity>512</Capacity><SupportedSizes>512</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></Supporte
 dFormats><Price 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001208</ID><Location>121</Location><Name>Small</Name><Label>256
 
GiB</Label><Capacity>256</Capacity><SupportedSizes>256</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price
 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001209</ID><Location>121</Location><Name>Medium</Name><Label>512
 
GiB</Label><Capacity>512</Capacity><SupportedSizes>512</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>ra
 w</Label></Format></SupportedFormats><Price 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001210</ID><Location>61</Location><Name>Large</Name><Label>2048
 
GiB</Label><Capacity>2048</Capacity><SupportedSizes>2048</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price
 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001210</ID><Location>82</Location><Name>Large</Name><Label>2048
 
GiB</Label><Capacity>2048</Capacity><SupportedSizes>2048</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Forma
 t><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001210</ID><Location>41</Location><Name>Large</Name><Label>2048
 
GiB</Label><Capacity>2048</Capacity><SupportedSizes>2048</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price
 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001210</ID><Location>121</Location><Name>Large</Name><Label>2048
 
GiB</Label><Capacity>2048</Capacity><SupportedSizes>2048</SupportedSizes><SupportedFormats><Format><ID>EXT
 
3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price
 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001208</ID><Location>101</Location><Name>Small</Name><Label>256
 
GiB</Label><Capacity>256</Capacity><SupportedSizes>256</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price
 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001209</ID><Location>101</Location><Name>Medium</Name><Label>512
 GiB</Label><Capacity>512</Capacity><SupportedSizes>512</SupportedSizes><Supp
 
ortedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price
 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001208</ID><Location>141</Location><Name>Small</Name><Label>256
 
GiB</Label><Capacity>256</Capacity><SupportedSizes>256</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price
 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001209</ID><Location>141</Location><Name>Medium</Name><Label>512
 GiB</Label><Capacity>512</Capacity><SupportedSiz
 
es>512</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price
 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001210</ID><Location>101</Location><Name>Large</Name><Label>2048
 
GiB</Label><Capacity>2048</Capacity><SupportedSizes>2048</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price
 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings><Offerings><ID>20001210</ID><Location>141</Location><Name>Large</Name><Label>2048
 GiB</Label><Capac
 
ity>2048</Capacity><SupportedSizes>2048</SupportedSizes><SupportedFormats><Format><ID>EXT3</ID><Label>ext3</Label></Format><Format><ID>RAW</ID><Label>raw</Label></Format></SupportedFormats><Price
 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.0000</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>UHR</UnitOfMeasure></Price></Offerings></ns2:DescribeVolumeOfferingsResponse>
\ No newline at end of file

Added: libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_volumes.xml
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_volumes.xml?rev=1375895&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_volumes.xml 
(added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_volumes.xml Wed 
Aug 22 04:33:49 2012
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" 
standalone="yes"?><ns2:DescribeVolumesResponse 
xmlns:ns2="http://www.ibm.com/xmlns/b2b/cloud/api/2010-03-31";><Volume><ID>39281</ID><Location>141</Location><OfferingID>20001210</OfferingID><InstanceID>0</InstanceID><Owner>[email protected]</Owner><Name>libcloudvol</Name><Format>raw</Format><Size>2048</Size><State>4</State><ProductCodes/><CreatedTime>2012-08-19T13:46:50.000Z</CreatedTime><StorageArea><ID></ID><Name></Name><Description></Description></StorageArea><IOPrice
 
CountryCode="ABC"><EffectiveDate>2011-08-12T00:00:00.000Z</EffectiveDate><CurrencyCode>USD</CurrencyCode><Rate>0.00</Rate><PricePerQuantity>1</PricePerQuantity><UnitOfMeasure>CNT</UnitOfMeasure></IOPrice><CloneStatus>0</CloneStatus><PlatformVersion>2</PlatformVersion><SourceDiskId>0</SourceDiskId></Volume></ns2:DescribeVolumesResponse>
\ No newline at end of file

Modified: libcloud/trunk/libcloud/test/compute/test_ibm_sce.py
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/test_ibm_sce.py?rev=1375895&r1=1375894&r2=1375895&view=diff
==============================================================================
--- libcloud/trunk/libcloud/test/compute/test_ibm_sce.py (original)
+++ libcloud/trunk/libcloud/test/compute/test_ibm_sce.py Wed Aug 22 04:33:49 
2012
@@ -26,7 +26,7 @@ from libcloud.test.secrets import IBM_PA
 
 class IBMTests(unittest.TestCase, TestCaseMixin):
     """
-    Tests the IBM Developer Cloud driver.
+    Tests the IBM SmartCloud Enterprise driver.
     """
 
     def setUp(self):
@@ -117,7 +117,7 @@ class IBMTests(unittest.TestCase, TestCa
             self.fail('test should have thrown')
 
     def test_destroy_node(self):
-        # Delete existant node
+        # Delete existent node
         nodes = self.driver.list_nodes()            # retrieves 3 nodes
         self.assertEquals(len(nodes), 3)
         IBMMockHttp.type = 'DELETE'
@@ -155,6 +155,71 @@ class IBMTests(unittest.TestCase, TestCa
         else:
             self.fail('test should have thrown')
 
+    def test_list_volumes(self):
+        ret = self.driver.list_volumes()
+        self.assertEqual(len(ret), 1)
+        self.assertEqual(ret[0].name, 'libcloudvol')
+        self.assertEqual(ret[0].extra['location'], '141')
+        self.assertEqual(ret[0].size, '2048')
+        self.assertEqual(ret[0].id, '39281')
+
+    def test_attach_volume(self):
+        vols = self.driver.list_volumes()
+        nodes = self.driver.list_nodes()
+        IBMMockHttp.type = 'ATTACH'
+        ret = self.driver.attach_volume(nodes[0], vols[0])
+        self.assertTrue(ret)
+
+    def test_create_volume(self):
+        IBMMockHttp.type = 'CREATE'
+        ret = self.driver.create_volume('256',
+                                        'test-volume',
+                                        location='141',
+                                        format='RAW',
+                                        offering_id='20001208')
+        self.assertEqual(ret.id, '39293')
+        self.assertEqual(ret.size, '256')
+        self.assertEqual(ret.name, 'test-volume')
+        self.assertEqual(ret.extra['location'], '141')
+
+    def test_destroy_volume(self):
+        vols = self.driver.list_volumes()
+        IBMMockHttp.type = 'DESTROY'
+        ret = self.driver.destroy_volume(vols[0])
+        self.assertTrue(ret)
+
+    def test_detach_volume(self):
+        nodes = self.driver.list_nodes()
+        vols = self.driver.list_volumes()
+        IBMMockHttp.type = 'DETACH'
+        ret = self.driver.detach_volume(nodes[0], vols[0])
+        self.assertTrue(ret)
+
+    def test_ex_allocate_address(self):
+        IBMMockHttp.type = 'ALLOCATE'
+        ret = self.driver.ex_allocate_address('141', '20001223')
+        self.assertEqual(ret.id, '292795')
+        self.assertEqual(ret.state, '0')
+        self.assertEqual(ret.options['location'], '141')
+
+    def test_ex_delete_address(self):
+        IBMMockHttp.type = 'DELETE'
+        ret = self.driver.ex_delete_address('292795')
+        self.assertTrue(ret)
+
+    def test_ex_list_addresses(self):
+        ret = self.driver.ex_list_addresses()
+        self.assertEqual(ret[0].ip, '170.225.160.218')
+        self.assertEqual(ret[0].options['location'], '141')
+        self.assertEqual(ret[0].id, '292795')
+        self.assertEqual(ret[0].state, '2')
+
+    def test_ex_list_storage_offerings(self):
+        ret = self.driver.ex_list_storage_offerings()
+        self.assertEqual(ret[0].name, 'Small')
+        self.assertEqual(ret[0].location, '61')
+        self.assertEqual(ret[0].id, '20001208')
+
 class IBMMockHttp(MockHttp):
     fixtures = ComputeFileFixtures('ibm_sce')
 
@@ -198,6 +263,42 @@ class IBMMockHttp(MockHttp):
     def 
_computecloud_enterprise_api_rest_20100331_instances_CREATE_INVALID(self, 
method, url, body, headers):
         return (412, 'Error 412: No DataCenter with id: 3', {}, 'Precondition 
Failed')
 
+    def _computecloud_enterprise_api_rest_20100331_storage(self, method, url, 
body, headers):
+        body = self.fixtures.load('list_volumes.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def 
_computecloud_enterprise_api_rest_20100331_instances_26557_ATTACH(self, method, 
url, body, headers):
+        body = self.fixtures.load('attach_volume.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _computecloud_enterprise_api_rest_20100331_storage_CREATE(self, 
method, url, body, headers):
+        body = self.fixtures.load('create_volume.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _computecloud_enterprise_api_rest_20100331_storage_39281_DESTROY(self, 
method, url, body, headers):
+        body = self.fixtures.load('destroy_volume.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def 
_computecloud_enterprise_api_rest_20100331_instances_26557_DETACH(self, method, 
url, body, headers):
+        body = self.fixtures.load('detach_volume.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _computecloud_enterprise_api_rest_20100331_addresses_ALLOCATE(self, 
method, url, body, headers):
+        body = self.fixtures.load('allocate_address.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def 
_computecloud_enterprise_api_rest_20100331_addresses_292795_DELETE(self, 
method, url, body, headers):
+        body = self.fixtures.load('delete_address.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _computecloud_enterprise_api_rest_20100331_addresses(self, method, 
url, body, headers):
+        body = self.fixtures.load('list_addresses.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _computecloud_enterprise_api_rest_20100331_offerings_storage(self, 
method, url, body, headers):
+        body = self.fixtures.load('list_storage_offerings.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
     # This is only to accomodate the response tests built into test\__init__.py
     def _computecloud_enterprise_api_rest_20100331_instances_26557(self, 
method, url, body, headers):
         if method == 'DELETE':


Reply via email to