Reorganizes blockstorage v1 testing infrastructure
* Removes empty integration package * Fixes and expands blockstorage rehaviors, client and config. * Renames volumes_api models to move them into the models namespace. Change-Id: Ieba9f0b62c3abb15e2375b871e4f598ef4852f50
This commit is contained in:
		@@ -1,26 +0,0 @@
 | 
			
		||||
"""
 | 
			
		||||
Copyright 2013 Rackspace
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from cafe.engine.behaviors import BaseBehavior, behavior
 | 
			
		||||
 | 
			
		||||
from cloudcafe.compute.servers_api.client import ServersClient
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ComputeBlockStorageBehaviors(BaseBehavior):
 | 
			
		||||
 | 
			
		||||
    @behavior(ServersClient)
 | 
			
		||||
    def attach_volume_to_server(*args, **kwargs):
 | 
			
		||||
        pass
 | 
			
		||||
@@ -19,8 +19,7 @@ from time import time, sleep
 | 
			
		||||
from cafe.engine.behaviors import BaseBehavior, behavior
 | 
			
		||||
from cloudcafe.blockstorage.v1.volumes_api.client import VolumesClient
 | 
			
		||||
from cloudcafe.blockstorage.v1.volumes_api.config import VolumesAPIConfig
 | 
			
		||||
from cloudcafe.blockstorage.v1.volumes_api.models.statuses import \
 | 
			
		||||
    VolumeStatuses, SnapshotStatuses
 | 
			
		||||
from cloudcafe.blockstorage.v1.volumes_api.models import statuses
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VolumesAPIBehaviorException(Exception):
 | 
			
		||||
@@ -39,25 +38,25 @@ class VolumesAPI_Behaviors(BaseBehavior):
 | 
			
		||||
            size=None, timeout=None, min_timeout=None, max_timeout=None,
 | 
			
		||||
            wait_per_gb=None):
 | 
			
		||||
 | 
			
		||||
        if wait_per_gb is not None:
 | 
			
		||||
            if size is not None:
 | 
			
		||||
        if wait_per_gb is not None and size is not None:
 | 
			
		||||
                timeout = timeout or size * wait_per_gb
 | 
			
		||||
 | 
			
		||||
        if min_timeout is not None:
 | 
			
		||||
            timeout = timeout if timeout > min_timeout else min_timeout
 | 
			
		||||
            timeout = max(timeout, min_timeout)
 | 
			
		||||
 | 
			
		||||
        if max_timeout is not None:
 | 
			
		||||
            timeout = timeout if timeout < max_timeout else max_timeout
 | 
			
		||||
            timeout = min(timeout, max_timeout)
 | 
			
		||||
 | 
			
		||||
        return timeout
 | 
			
		||||
 | 
			
		||||
    @behavior(VolumesClient)
 | 
			
		||||
    def wait_for_volume_status(
 | 
			
		||||
            self, volume_id, expected_status, timeout, wait_period=None):
 | 
			
		||||
        ''' Waits for a specific status and returns a BehaviorResponse object
 | 
			
		||||
        when that status is observed.
 | 
			
		||||
        Note:  Shouldn't be used for transient statuses like 'deleting'.
 | 
			
		||||
        '''
 | 
			
		||||
        """ Waits for a specific status and returns None when that status is
 | 
			
		||||
        observed.
 | 
			
		||||
        Note:  Unreliable for transient statuses like 'deleting'.
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        wait_period = float(
 | 
			
		||||
            wait_period or self.config.volume_status_poll_frequency)
 | 
			
		||||
        end_time = time() + int(timeout)
 | 
			
		||||
@@ -67,21 +66,24 @@ class VolumesAPI_Behaviors(BaseBehavior):
 | 
			
		||||
 | 
			
		||||
            if not resp.ok:
 | 
			
		||||
                msg = (
 | 
			
		||||
                    "get_volume_info() call failed with status_code {0} "
 | 
			
		||||
                    "while waiting for volume to reach the {1} status".format(
 | 
			
		||||
                    "wait_for_volume_status() failure: "
 | 
			
		||||
                    "get_volume_info() call failed with status_code {0} while "
 | 
			
		||||
                    "waiting for volume to reach the {1} status".format(
 | 
			
		||||
                        resp.status_code, expected_status))
 | 
			
		||||
                self._log.error(msg)
 | 
			
		||||
                raise VolumesAPIBehaviorException(msg)
 | 
			
		||||
 | 
			
		||||
            if resp.entity is None:
 | 
			
		||||
                msg = (
 | 
			
		||||
                    "wait_for_volume_status() failure: "
 | 
			
		||||
                    "get_volume_info() response body did not deserialize.")
 | 
			
		||||
                self._log.error(msg)
 | 
			
		||||
                raise VolumesAPIBehaviorException(msg)
 | 
			
		||||
 | 
			
		||||
            if resp.entity.status == expected_status:
 | 
			
		||||
                self._log.info(
 | 
			
		||||
                    'Volume status "{0}" observed as expected'.format(
 | 
			
		||||
                    "wait_for_volume_status() failure: "
 | 
			
		||||
                    'Expected Volume status "{0}" observed as expected'.format(
 | 
			
		||||
                        expected_status))
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
@@ -98,10 +100,11 @@ class VolumesAPI_Behaviors(BaseBehavior):
 | 
			
		||||
    @behavior(VolumesClient)
 | 
			
		||||
    def wait_for_snapshot_status(
 | 
			
		||||
            self, snapshot_id, expected_status, timeout, wait_period=None):
 | 
			
		||||
        ''' Waits for a specific status and returns a BehaviorResponse object
 | 
			
		||||
        when that status is observed.
 | 
			
		||||
        Note:  Shouldn't be used for transient statuses like 'deleting'.
 | 
			
		||||
        '''
 | 
			
		||||
        """ Waits for a specific status and returns None when that status is
 | 
			
		||||
        observed.
 | 
			
		||||
        Note:  Unreliable for transient statuses like 'deleting'.
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        wait_period = float(
 | 
			
		||||
            wait_period or self.config.snapshot_status_poll_frequency)
 | 
			
		||||
        end_time = time() + int(timeout)
 | 
			
		||||
@@ -111,6 +114,7 @@ class VolumesAPI_Behaviors(BaseBehavior):
 | 
			
		||||
 | 
			
		||||
            if not resp.ok:
 | 
			
		||||
                msg = (
 | 
			
		||||
                    "wait_for_snapshot_status() failure: "
 | 
			
		||||
                    "get_snapshot_info() call failed with status_code {0} "
 | 
			
		||||
                    "while waiting for snapshot status".format(
 | 
			
		||||
                        resp.status_code))
 | 
			
		||||
@@ -119,14 +123,15 @@ class VolumesAPI_Behaviors(BaseBehavior):
 | 
			
		||||
 | 
			
		||||
            if resp.entity is None:
 | 
			
		||||
                msg = (
 | 
			
		||||
                    "wait_for_snapshot_status() failure: "
 | 
			
		||||
                    "get_snapshot_info() response body did not deserialize as "
 | 
			
		||||
                    "expected")
 | 
			
		||||
                self._log.error(msg)
 | 
			
		||||
                raise VolumesAPIBehaviorException(msg)
 | 
			
		||||
 | 
			
		||||
            if resp.entity.status == expected_status:
 | 
			
		||||
                self._log.info('Snapshot status "{0}" observed'.format(
 | 
			
		||||
                    expected_status))
 | 
			
		||||
                self._log.info('Expected Snapshot status "{0}" observed'
 | 
			
		||||
                    .format(expected_status))
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
            sleep(wait_period)
 | 
			
		||||
@@ -141,19 +146,18 @@ class VolumesAPI_Behaviors(BaseBehavior):
 | 
			
		||||
 | 
			
		||||
    @behavior(VolumesClient)
 | 
			
		||||
    def create_available_volume(
 | 
			
		||||
            self, display_name, size, volume_type, display_description=None,
 | 
			
		||||
            metadata=None, availability_zone=None, timeout=None):
 | 
			
		||||
            self, size, volume_type, display_name=None,
 | 
			
		||||
            display_description=None, availability_zone=None, metadata=None,
 | 
			
		||||
            timeout=None):
 | 
			
		||||
 | 
			
		||||
        expected_status = VolumeStatuses.AVAILABLE
 | 
			
		||||
        expected_status = statuses.Volume.AVAILABLE
 | 
			
		||||
        metadata = metadata or {}
 | 
			
		||||
 | 
			
		||||
        timeout = self._calculate_timeout(
 | 
			
		||||
            size=size, timeout=timeout,
 | 
			
		||||
            max_timeout=self.config.volume_create_max_timeout)
 | 
			
		||||
        timeout = timeout or self.config.volume_create_timeout
 | 
			
		||||
 | 
			
		||||
        self._log.info("create_available_volume() is creating a volume")
 | 
			
		||||
        resp = self.client.create_volume(
 | 
			
		||||
            display_name=display_name, size=size, volume_type=volume_type,
 | 
			
		||||
            size, volume_type, display_name=display_name,
 | 
			
		||||
            display_description=display_description, metadata=metadata,
 | 
			
		||||
            availability_zone=availability_zone)
 | 
			
		||||
 | 
			
		||||
@@ -179,9 +183,9 @@ class VolumesAPI_Behaviors(BaseBehavior):
 | 
			
		||||
    @behavior(VolumesClient)
 | 
			
		||||
    def create_available_snapshot(
 | 
			
		||||
            self, volume_id, display_name=None, display_description=None,
 | 
			
		||||
            force_create='False', name=None, timeout=None):
 | 
			
		||||
            force_create=True, timeout=None):
 | 
			
		||||
 | 
			
		||||
        expected_status = SnapshotStatuses.AVAILABLE
 | 
			
		||||
        expected_status = statuses.Snapshot.AVAILABLE
 | 
			
		||||
 | 
			
		||||
        #Try and get volume size
 | 
			
		||||
        vol_size = None
 | 
			
		||||
@@ -201,11 +205,10 @@ class VolumesAPI_Behaviors(BaseBehavior):
 | 
			
		||||
        self._log.debug(
 | 
			
		||||
            "create_available_snapshot() timeout set to {0}".format(timeout))
 | 
			
		||||
 | 
			
		||||
        self._log.info("create_available_snapshot() is creating a snapshot")
 | 
			
		||||
        self._log.info("create_available_snapshot is creating a snapshot")
 | 
			
		||||
        resp = self.client.create_snapshot(
 | 
			
		||||
            volume_id, display_name=display_name,
 | 
			
		||||
            display_description=display_description,
 | 
			
		||||
            force_create=force_create, name=name)
 | 
			
		||||
            volume_id, force=force_create, display_name=display_name,
 | 
			
		||||
            display_description=display_description)
 | 
			
		||||
 | 
			
		||||
        if not resp.ok:
 | 
			
		||||
            msg = (
 | 
			
		||||
@@ -253,7 +256,7 @@ class VolumesAPI_Behaviors(BaseBehavior):
 | 
			
		||||
    @behavior(VolumesClient)
 | 
			
		||||
    def delete_volume_confirmed(
 | 
			
		||||
            self, volume_id, size=None, timeout=None, wait_period=None):
 | 
			
		||||
        '''Returns True if volume deleted, False otherwise'''
 | 
			
		||||
        """Returns True if volume deleted, False otherwise"""
 | 
			
		||||
 | 
			
		||||
        timeout = self._calculate_timeout(
 | 
			
		||||
            size=size, timeout=timeout,
 | 
			
		||||
@@ -272,7 +275,7 @@ class VolumesAPI_Behaviors(BaseBehavior):
 | 
			
		||||
        while time() < end:
 | 
			
		||||
            #issue DELETE request on volume
 | 
			
		||||
            resp = self.client.delete_volume(volume_id)
 | 
			
		||||
            if not resp.ok:
 | 
			
		||||
            if not resp.ok and resp.status_code != 404:
 | 
			
		||||
                msg = (
 | 
			
		||||
                    "delete_volume_confirmed() call to delete_volume() failed "
 | 
			
		||||
                    "with a '{0}'".format(resp.status_code))
 | 
			
		||||
@@ -309,7 +312,7 @@ class VolumesAPI_Behaviors(BaseBehavior):
 | 
			
		||||
    @behavior(VolumesClient)
 | 
			
		||||
    def delete_snapshot_confirmed(
 | 
			
		||||
            self, snapshot_id, vol_size=None, timeout=None, wait_period=None):
 | 
			
		||||
        '''Returns True if snapshot deleted, False otherwise'''
 | 
			
		||||
        """Returns True if snapshot deleted, False otherwise"""
 | 
			
		||||
 | 
			
		||||
        timeout = self._calculate_timeout(
 | 
			
		||||
            size=vol_size, timeout=timeout,
 | 
			
		||||
@@ -365,7 +368,7 @@ class VolumesAPI_Behaviors(BaseBehavior):
 | 
			
		||||
 | 
			
		||||
    @behavior(VolumesClient)
 | 
			
		||||
    def delete_volume_with_snapshots_confirmed(self, volume_id):
 | 
			
		||||
        '''Returns True if volume deleted, False otherwise'''
 | 
			
		||||
        """Returns True if volume deleted, False otherwise"""
 | 
			
		||||
 | 
			
		||||
        #Attempt to delete all snapshots associated with provided volume_id
 | 
			
		||||
        snapshots = self.list_volume_snapshots(volume_id)
 | 
			
		||||
 
 | 
			
		||||
@@ -15,14 +15,13 @@ limitations under the License.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from cafe.engine.clients.rest import AutoMarshallingRestClient
 | 
			
		||||
from cloudcafe.blockstorage.v1.volumes_api.models.requests.volumes_api import (
 | 
			
		||||
    Volume as VolumeRequest,
 | 
			
		||||
    VolumeSnapshot as VolumeSnapshotRequest)
 | 
			
		||||
from cloudcafe.blockstorage.v1.volumes_api.models.requests import (
 | 
			
		||||
    VolumeRequest,
 | 
			
		||||
    VolumeSnapshotRequest)
 | 
			
		||||
 | 
			
		||||
from cloudcafe.blockstorage.v1.volumes_api.models.responses.volumes_api import(
 | 
			
		||||
    Volume as VolumeResponse,
 | 
			
		||||
    VolumeSnapshot as VolumeSnapshotResponse,
 | 
			
		||||
    VolumeType, VolumeList, VolumeTypeList, VolumeSnapshotList)
 | 
			
		||||
from cloudcafe.blockstorage.v1.volumes_api.models.responses import(
 | 
			
		||||
    VolumeResponse, VolumeSnapshotResponse, VolumeTypeResponse,
 | 
			
		||||
    VolumeListResponse, VolumeTypeListResponse, VolumeSnapshotListResponse)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VolumesClient(AutoMarshallingRestClient):
 | 
			
		||||
@@ -36,14 +35,14 @@ class VolumesClient(AutoMarshallingRestClient):
 | 
			
		||||
        self.url = url
 | 
			
		||||
        self.auth_token = auth_token
 | 
			
		||||
        self.default_headers['X-Auth-Token'] = auth_token
 | 
			
		||||
        self.default_headers['Content-Type'] = 'application/%s' % \
 | 
			
		||||
                                               self.serialize_format
 | 
			
		||||
        self.default_headers['Accept'] = 'application/%s' % \
 | 
			
		||||
                                         self.deserialize_format
 | 
			
		||||
        self.default_headers['Content-Type'] = 'application/{0}'.format(
 | 
			
		||||
            self.serialize_format)
 | 
			
		||||
        self.default_headers['Accept'] = 'application/{0}'.format(
 | 
			
		||||
            self.deserialize_format)
 | 
			
		||||
 | 
			
		||||
    def create_volume(
 | 
			
		||||
            self, display_name, size, volume_type, availability_zone=None,
 | 
			
		||||
            metadata={}, display_description=None, snapshot_id=None,
 | 
			
		||||
            self, size, volume_type, display_name=None,
 | 
			
		||||
            display_description=None, availability_zone=None, metadata=None,
 | 
			
		||||
            requestslib_kwargs=None):
 | 
			
		||||
 | 
			
		||||
        '''POST v1/{tenant_id}/volumes'''
 | 
			
		||||
@@ -51,22 +50,22 @@ class VolumesClient(AutoMarshallingRestClient):
 | 
			
		||||
        url = '{0}/volumes'.format(self.url)
 | 
			
		||||
 | 
			
		||||
        volume_request_entity = VolumeRequest(
 | 
			
		||||
            display_name=display_name,
 | 
			
		||||
            size=size,
 | 
			
		||||
            volume_type=volume_type,
 | 
			
		||||
            display_name=display_name,
 | 
			
		||||
            display_description=display_description,
 | 
			
		||||
            metadata=metadata,
 | 
			
		||||
            availability_zone=availability_zone,
 | 
			
		||||
            snapshot_id=snapshot_id)
 | 
			
		||||
            metadata=metadata)
 | 
			
		||||
 | 
			
		||||
        return self.request(
 | 
			
		||||
            'POST', url, response_entity_type=VolumeResponse,
 | 
			
		||||
            'POST', url,
 | 
			
		||||
            response_entity_type=VolumeResponse,
 | 
			
		||||
            request_entity=volume_request_entity,
 | 
			
		||||
            requestslib_kwargs=requestslib_kwargs)
 | 
			
		||||
 | 
			
		||||
    def create_volume_from_snapshot(
 | 
			
		||||
            self, snapshot_id, size, display_name='', volume_type=None,
 | 
			
		||||
            availability_zone=None, display_description='', metadata={},
 | 
			
		||||
            self, snapshot_id, size, volume_type, display_name=None,
 | 
			
		||||
            display_description=None, availability_zone=None, metadata=None,
 | 
			
		||||
            requestslib_kwargs=None):
 | 
			
		||||
 | 
			
		||||
        '''POST v1/{tenant_id}/volumes'''
 | 
			
		||||
@@ -74,16 +73,17 @@ class VolumesClient(AutoMarshallingRestClient):
 | 
			
		||||
        url = '{0}/volumes'.format(self.url)
 | 
			
		||||
 | 
			
		||||
        volume_request_entity = VolumeRequest(
 | 
			
		||||
            display_name=display_name,
 | 
			
		||||
            size=size,
 | 
			
		||||
            volume_type=volume_type,
 | 
			
		||||
            display_name=display_name,
 | 
			
		||||
            display_description=display_description,
 | 
			
		||||
            metadata=metadata,
 | 
			
		||||
            availability_zone=availability_zone,
 | 
			
		||||
            metadata=metadata,
 | 
			
		||||
            snapshot_id=snapshot_id)
 | 
			
		||||
 | 
			
		||||
        return self.request(
 | 
			
		||||
            'POST', url, response_entity_type=VolumeResponse,
 | 
			
		||||
            'POST', url,
 | 
			
		||||
            response_entity_type=VolumeResponse,
 | 
			
		||||
            request_entity=volume_request_entity,
 | 
			
		||||
            requestslib_kwargs=requestslib_kwargs)
 | 
			
		||||
 | 
			
		||||
@@ -93,7 +93,7 @@ class VolumesClient(AutoMarshallingRestClient):
 | 
			
		||||
 | 
			
		||||
        url = '{0}/volumes'.format(self.url)
 | 
			
		||||
        return self.request(
 | 
			
		||||
            'GET', url, response_entity_type=VolumeList,
 | 
			
		||||
            'GET', url, response_entity_type=VolumeListResponse,
 | 
			
		||||
            requestslib_kwargs=requestslib_kwargs)
 | 
			
		||||
 | 
			
		||||
    def list_all_volumes_info(self, requestslib_kwargs=None):
 | 
			
		||||
@@ -102,7 +102,7 @@ class VolumesClient(AutoMarshallingRestClient):
 | 
			
		||||
 | 
			
		||||
        url = '{0}/volumes/detail'.format(self.url)
 | 
			
		||||
        return self.request(
 | 
			
		||||
            'GET', url, response_entity_type=VolumeList,
 | 
			
		||||
            'GET', url, response_entity_type=VolumeListResponse,
 | 
			
		||||
            requestslib_kwargs=requestslib_kwargs)
 | 
			
		||||
 | 
			
		||||
    def get_volume_info(self, volume_id, requestslib_kwargs=None):
 | 
			
		||||
@@ -130,7 +130,7 @@ class VolumesClient(AutoMarshallingRestClient):
 | 
			
		||||
 | 
			
		||||
        url = '{0}/types'.format(self.url)
 | 
			
		||||
        return self.request(
 | 
			
		||||
            'GET', url, response_entity_type=VolumeTypeList,
 | 
			
		||||
            'GET', url, response_entity_type=VolumeTypeListResponse,
 | 
			
		||||
            requestslib_kwargs=requestslib_kwargs)
 | 
			
		||||
 | 
			
		||||
    def get_volume_type_info(self, volume_type_id, requestslib_kwargs=None):
 | 
			
		||||
@@ -139,13 +139,13 @@ class VolumesClient(AutoMarshallingRestClient):
 | 
			
		||||
 | 
			
		||||
        url = '{0}/types/{1}'.format(self.url, volume_type_id)
 | 
			
		||||
        return self.request(
 | 
			
		||||
            'GET', url, response_entity_type=VolumeType,
 | 
			
		||||
            'GET', url, response_entity_type=VolumeTypeResponse,
 | 
			
		||||
            requestslib_kwargs=requestslib_kwargs)
 | 
			
		||||
 | 
			
		||||
#Volume Snapshot API
 | 
			
		||||
    def create_snapshot(
 | 
			
		||||
            self, volume_id, display_name=None, display_description=None,
 | 
			
		||||
            force_create=False, name=None, requestslib_kwargs=None):
 | 
			
		||||
            force_create=False, requestslib_kwargs=None):
 | 
			
		||||
 | 
			
		||||
        '''POST v1/{tenant_id}/snapshots'''
 | 
			
		||||
 | 
			
		||||
@@ -155,11 +155,11 @@ class VolumesClient(AutoMarshallingRestClient):
 | 
			
		||||
            volume_id,
 | 
			
		||||
            force=force_create,
 | 
			
		||||
            display_name=display_name,
 | 
			
		||||
            name=name,
 | 
			
		||||
            display_description=display_description)
 | 
			
		||||
 | 
			
		||||
        return self.request(
 | 
			
		||||
            'POST', url, response_entity_type=VolumeSnapshotResponse,
 | 
			
		||||
            'POST', url,
 | 
			
		||||
            response_entity_type=VolumeSnapshotResponse,
 | 
			
		||||
            request_entity=volume_snapshot_request_entity,
 | 
			
		||||
            requestslib_kwargs=requestslib_kwargs)
 | 
			
		||||
 | 
			
		||||
@@ -170,7 +170,7 @@ class VolumesClient(AutoMarshallingRestClient):
 | 
			
		||||
        url = '{0}/snapshots'.format(self.url)
 | 
			
		||||
 | 
			
		||||
        return self.request(
 | 
			
		||||
            'GET', url, response_entity_type=VolumeSnapshotList,
 | 
			
		||||
            'GET', url, response_entity_type=VolumeSnapshotListResponse,
 | 
			
		||||
            requestslib_kwargs=requestslib_kwargs)
 | 
			
		||||
 | 
			
		||||
    def list_all_snapshots_info(self, requestslib_kwargs=None):
 | 
			
		||||
@@ -179,7 +179,7 @@ class VolumesClient(AutoMarshallingRestClient):
 | 
			
		||||
 | 
			
		||||
        url = '{0}/snapshots/detail'.format(self.url)
 | 
			
		||||
        return self.request(
 | 
			
		||||
            'GET', url, response_entity_type=VolumeSnapshotList,
 | 
			
		||||
            'GET', url, response_entity_type=VolumeSnapshotListResponse,
 | 
			
		||||
            requestslib_kwargs=requestslib_kwargs)
 | 
			
		||||
 | 
			
		||||
    def get_snapshot_info(self, snapshot_id, requestslib_kwargs=None):
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ class VolumesAPIConfig(ConfigSectionInterface):
 | 
			
		||||
        return self.get("volume_status_poll_frequency", default=None)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def volume_create_max_timeout(self):
 | 
			
		||||
    def volume_create_timeout(self):
 | 
			
		||||
        return self.get("volume_create_timeout", default=None)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
@@ -79,7 +79,7 @@ class VolumesAPIConfig(ConfigSectionInterface):
 | 
			
		||||
    def snapshot_create_base_timeout(self):
 | 
			
		||||
        """Amount of time added by default to calculated snapshot create
 | 
			
		||||
        timeouts"""
 | 
			
		||||
        return self.get("snapshot_create_min_timeout", default=0)
 | 
			
		||||
        return self.get("snapshot_create_base_timeout", default=0)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def snapshot_create_wait_per_gigabyte(self):
 | 
			
		||||
 
 | 
			
		||||
@@ -20,48 +20,43 @@ from xml.etree import ElementTree
 | 
			
		||||
from cafe.engine.models.base import AutoMarshallingModel
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Volume(AutoMarshallingModel):
 | 
			
		||||
    obj_model_key = "volume"
 | 
			
		||||
class VolumeRequest(AutoMarshallingModel):
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
            self, display_name=None, size=None, volume_type=None,
 | 
			
		||||
            self, size=None, volume_type=None, display_name=None,
 | 
			
		||||
            display_description=None, metadata=None, availability_zone=None,
 | 
			
		||||
            snapshot_id=None, attachments=None):
 | 
			
		||||
 | 
			
		||||
        self.display_name = display_name
 | 
			
		||||
        self.display_description = display_description
 | 
			
		||||
        self.size = size
 | 
			
		||||
        self.volume_type = volume_type
 | 
			
		||||
        self.metadata = metadata or {}
 | 
			
		||||
        self.display_name = display_name
 | 
			
		||||
        self.display_description = display_description
 | 
			
		||||
        self.metadata = metadata or dict()
 | 
			
		||||
        self.availability_zone = availability_zone
 | 
			
		||||
        self.snapshot_id = snapshot_id
 | 
			
		||||
 | 
			
		||||
    def _obj_to_json(self):
 | 
			
		||||
        return json.dumps(self._obj_to_json_dict())
 | 
			
		||||
 | 
			
		||||
    def _obj_to_json_dict(self):
 | 
			
		||||
        sub_dict = {}
 | 
			
		||||
        sub_dict["display_name"] = self.display_name
 | 
			
		||||
        sub_dict["display_description"] = self.display_description
 | 
			
		||||
        sub_dict["size"] = self.size
 | 
			
		||||
        sub_dict["volume_type"] = self.volume_type
 | 
			
		||||
        sub_dict["metadata"] = self.metadata
 | 
			
		||||
        sub_dict["availability_zone"] = self.availability_zone
 | 
			
		||||
        sub_dict['snapshot_id'] = self.snapshot_id
 | 
			
		||||
        volume_attrs = {
 | 
			
		||||
            "size": self.size,
 | 
			
		||||
            "volume_type": self.volume_type,
 | 
			
		||||
            "display_name": self.display_name,
 | 
			
		||||
            "display_description": self.display_description,
 | 
			
		||||
            "metadata": self.metadata,
 | 
			
		||||
            "availability_zone": self.availability_zone}
 | 
			
		||||
 | 
			
		||||
        root_dict = {}
 | 
			
		||||
        root_dict[self.obj_model_key] = self._remove_empty_values(sub_dict)
 | 
			
		||||
        return root_dict
 | 
			
		||||
        return {'volume': self._remove_empty_values(volume_attrs)}
 | 
			
		||||
 | 
			
		||||
    def _obj_to_xml_ele(self):
 | 
			
		||||
        element = ElementTree.Element(self.obj_model_key)
 | 
			
		||||
        attrs = {}
 | 
			
		||||
        attrs["display_name"] = self.display_name
 | 
			
		||||
        attrs["display_description"] = self.display_description
 | 
			
		||||
        attrs["size"] = str(self.size)
 | 
			
		||||
        attrs["volume_type"] = self.volume_type
 | 
			
		||||
        attrs["availability_zone"] = self.availability_zone
 | 
			
		||||
        element = self._set_xml_etree_element(element, attrs)
 | 
			
		||||
        element = ElementTree.Element('volume')
 | 
			
		||||
        volume_attrs = {
 | 
			
		||||
            "size": self.size,
 | 
			
		||||
            "volume_type": self.volume_type,
 | 
			
		||||
            "display_name": self.display_name,
 | 
			
		||||
            "display_description": self.display_description,
 | 
			
		||||
            "availability_zone": self.availability_zone}
 | 
			
		||||
        element = self._set_xml_etree_element(element, volume_attrs)
 | 
			
		||||
 | 
			
		||||
        if len(self.metadata.keys()) > 0:
 | 
			
		||||
            metadata_element = ElementTree.Element('metadata')
 | 
			
		||||
@@ -78,44 +73,37 @@ class Volume(AutoMarshallingModel):
 | 
			
		||||
        return ElementTree.tostring(self._obj_to_xml_ele())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VolumeSnapshot(AutoMarshallingModel):
 | 
			
		||||
    obj_model_key = "snapshot"
 | 
			
		||||
class VolumeSnapshotRequest(AutoMarshallingModel):
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
            self, volume_id, force=True, display_name=None, name=None,
 | 
			
		||||
            display_description=None):
 | 
			
		||||
            self, volume_id, display_name=None,
 | 
			
		||||
            display_description=None, force=True):
 | 
			
		||||
 | 
			
		||||
        self.force = force
 | 
			
		||||
        self.display_name = display_name
 | 
			
		||||
        self.volume_id = volume_id
 | 
			
		||||
        self.name = name
 | 
			
		||||
        self.display_name = display_name
 | 
			
		||||
        self.display_description = display_description
 | 
			
		||||
        self.force = force
 | 
			
		||||
 | 
			
		||||
    def _obj_to_json(self):
 | 
			
		||||
        return json.dumps(self._obj_to_json_dict())
 | 
			
		||||
 | 
			
		||||
    def _obj_to_json_dict(self):
 | 
			
		||||
        attrs = {}
 | 
			
		||||
        attrs["snapshot"] = {}
 | 
			
		||||
        snapshot_attrs = {
 | 
			
		||||
            "volume_id": self.volume_id,
 | 
			
		||||
            "display_name": self.display_name,
 | 
			
		||||
            "display_description": self.display_description,
 | 
			
		||||
            "force": self.force}
 | 
			
		||||
 | 
			
		||||
        sub_attrs = {}
 | 
			
		||||
        sub_attrs["volume_id"] = self.volume_id
 | 
			
		||||
        sub_attrs["force"] = self.force
 | 
			
		||||
        sub_attrs["display_name"] = self.display_name
 | 
			
		||||
        sub_attrs["display_description"] = self.display_description
 | 
			
		||||
 | 
			
		||||
        attrs[self.obj_model_key] = self._remove_empty_values(sub_attrs)
 | 
			
		||||
        return self._remove_empty_values(attrs)
 | 
			
		||||
        return {"snapshot": self._remove_empty_values(snapshot_attrs)}
 | 
			
		||||
 | 
			
		||||
    def _obj_to_xml(self):
 | 
			
		||||
        return ElementTree.tostring(self._obj_to_xml_ele())
 | 
			
		||||
 | 
			
		||||
    def _obj_to_xml_ele(self):
 | 
			
		||||
        element = ElementTree.Element(self.obj_model_key)
 | 
			
		||||
        attrs = {}
 | 
			
		||||
        attrs["volume_id"] = self.volume_id
 | 
			
		||||
        attrs["force"] = str(self.force)
 | 
			
		||||
        attrs["display_name"] = self.display_name
 | 
			
		||||
        attrs["display_description"] = self.display_description
 | 
			
		||||
        element = self._set_xml_etree_element(element, attrs)
 | 
			
		||||
        return element
 | 
			
		||||
        element = ElementTree.Element('snapshot')
 | 
			
		||||
        snapshot_attrs = {
 | 
			
		||||
            "volume_id": self.volume_id,
 | 
			
		||||
            "display_name": self.display_name,
 | 
			
		||||
            "display_description": self.display_description,
 | 
			
		||||
            "force": str(self.force)}
 | 
			
		||||
        return self._set_xml_etree_element(element, snapshot_attrs)
 | 
			
		||||
@@ -1,15 +0,0 @@
 | 
			
		||||
"""
 | 
			
		||||
Copyright 2013 Rackspace
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
"""
 | 
			
		||||
@@ -83,7 +83,7 @@ class _VolumesAPIBaseListModel(AutoMarshallingListModel):
 | 
			
		||||
        return obj_list
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Volume(_VolumesAPIBaseModel):
 | 
			
		||||
class VolumeResponse(_VolumesAPIBaseModel):
 | 
			
		||||
    obj_model_key = 'volume'
 | 
			
		||||
    kwarg_map = {
 | 
			
		||||
        "id_": "id",
 | 
			
		||||
@@ -101,10 +101,8 @@ class Volume(_VolumesAPIBaseModel):
 | 
			
		||||
    def __init__(
 | 
			
		||||
            self, id_=None, display_name=None, size=None, volume_type=None,
 | 
			
		||||
            display_description=None, metadata=None, availability_zone=None,
 | 
			
		||||
            snapshot_id=None, attachments=None, created_at=None, status=None,
 | 
			
		||||
            xmlns=None):
 | 
			
		||||
            snapshot_id=None, attachments=None, created_at=None, status=None):
 | 
			
		||||
 | 
			
		||||
        #Common attributes
 | 
			
		||||
        self.id_ = id_
 | 
			
		||||
        self.display_name = display_name
 | 
			
		||||
        self.display_description = display_description
 | 
			
		||||
@@ -116,10 +114,9 @@ class Volume(_VolumesAPIBaseModel):
 | 
			
		||||
        self.attachments = attachments
 | 
			
		||||
        self.created_at = created_at
 | 
			
		||||
        self.status = status
 | 
			
		||||
        self.xmlns = xmlns
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VolumeSnapshot(_VolumesAPIBaseModel):
 | 
			
		||||
class VolumeSnapshotResponse(_VolumesAPIBaseModel):
 | 
			
		||||
    obj_model_key = 'snapshot'
 | 
			
		||||
    kwarg_map = {
 | 
			
		||||
        "id_": "id",
 | 
			
		||||
@@ -128,13 +125,11 @@ class VolumeSnapshot(_VolumesAPIBaseModel):
 | 
			
		||||
        "display_description": "display_description",
 | 
			
		||||
        "status": "status",
 | 
			
		||||
        "size": "size",
 | 
			
		||||
        "created_at": "created_at",
 | 
			
		||||
        "name": "name"}
 | 
			
		||||
        "created_at": "created_at"}
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
            self, id_=None, volume_id=None, display_name=None,
 | 
			
		||||
            display_description=None, status=None, size=None, created_at=None,
 | 
			
		||||
            name=None):
 | 
			
		||||
            display_description=None, status=None, size=None, created_at=None):
 | 
			
		||||
 | 
			
		||||
        self.id_ = id_
 | 
			
		||||
        self.volume_id = volume_id
 | 
			
		||||
@@ -143,10 +138,9 @@ class VolumeSnapshot(_VolumesAPIBaseModel):
 | 
			
		||||
        self.status = status
 | 
			
		||||
        self.size = size
 | 
			
		||||
        self.created_at = created_at
 | 
			
		||||
        self.name = name
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VolumeType(_VolumesAPIBaseModel):
 | 
			
		||||
class VolumeTypeResponse(_VolumesAPIBaseModel):
 | 
			
		||||
    obj_model_key = "volume_type"
 | 
			
		||||
    kwarg_map = {
 | 
			
		||||
        "id_": "id",
 | 
			
		||||
@@ -160,16 +154,16 @@ class VolumeType(_VolumesAPIBaseModel):
 | 
			
		||||
        self.extra_specs = extra_specs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VolumeList(_VolumesAPIBaseListModel):
 | 
			
		||||
class VolumeListResponse(_VolumesAPIBaseListModel):
 | 
			
		||||
    list_model_key = 'volumes'
 | 
			
		||||
    ObjectModel = Volume
 | 
			
		||||
    ObjectModel = VolumeResponse
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VolumeSnapshotList(_VolumesAPIBaseListModel):
 | 
			
		||||
class VolumeSnapshotListResponse(_VolumesAPIBaseListModel):
 | 
			
		||||
    list_model_key = 'snapshots'
 | 
			
		||||
    ObjectModel = VolumeSnapshot
 | 
			
		||||
    ObjectModel = VolumeSnapshotResponse
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VolumeTypeList(_VolumesAPIBaseListModel):
 | 
			
		||||
class VolumeTypeListResponse(_VolumesAPIBaseListModel):
 | 
			
		||||
    list_model_key = 'volume_types'
 | 
			
		||||
    ObjectModel = VolumeType
 | 
			
		||||
    ObjectModel = VolumeTypeResponse
 | 
			
		||||
@@ -1,15 +0,0 @@
 | 
			
		||||
"""
 | 
			
		||||
Copyright 2013 Rackspace
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
"""
 | 
			
		||||
@@ -15,15 +15,16 @@ limitations under the License.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class _CommonStatuses(object):
 | 
			
		||||
class _CommonStatus(object):
 | 
			
		||||
    AVAILABLE = "available"
 | 
			
		||||
    DELETING = "deleting"
 | 
			
		||||
    CREATING = "creating"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VolumeStatuses(_CommonStatuses):
 | 
			
		||||
class Volume(_CommonStatus):
 | 
			
		||||
    ATTACHING = "attaching"
 | 
			
		||||
    IN_USE = "in-use"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SnapshotStatuses(_CommonStatuses):
 | 
			
		||||
class Snapshot(_CommonStatus):
 | 
			
		||||
    pass
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										108
									
								
								cloudcafe/blockstorage/v2/volumes_api/models/requests.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								cloudcafe/blockstorage/v2/volumes_api/models/requests.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
"""
 | 
			
		||||
Copyright 2013 Rackspace
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
from xml.etree import ElementTree
 | 
			
		||||
 | 
			
		||||
from cafe.engine.models.base import AutoMarshallingModel
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VolumeRequest(AutoMarshallingModel):
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
            self, size=None, volume_type=None, name=None,
 | 
			
		||||
            description=None, metadata=None, availability_zone=None):
 | 
			
		||||
 | 
			
		||||
        self.size = size
 | 
			
		||||
        self.volume_type = volume_type
 | 
			
		||||
        self.name = name
 | 
			
		||||
        self.description = description
 | 
			
		||||
        self.metadata = metadata or dict()
 | 
			
		||||
        self.availability_zone = availability_zone
 | 
			
		||||
 | 
			
		||||
    def _obj_to_json(self):
 | 
			
		||||
        return json.dumps(self._obj_to_json_dict())
 | 
			
		||||
 | 
			
		||||
    def _obj_to_json_dict(self):
 | 
			
		||||
        volume_attrs = {
 | 
			
		||||
            "size": self.size,
 | 
			
		||||
            "volume_type": self.volume_type,
 | 
			
		||||
            "name": self.name,
 | 
			
		||||
            "description": self.description,
 | 
			
		||||
            "metadata": self.metadata,
 | 
			
		||||
            "availability_zone": self.availability_zone}
 | 
			
		||||
 | 
			
		||||
        return {'volume': self._remove_empty_values(volume_attrs)}
 | 
			
		||||
 | 
			
		||||
    def _obj_to_xml_ele(self):
 | 
			
		||||
        element = ElementTree.Element('volume')
 | 
			
		||||
        volume_attrs = {
 | 
			
		||||
            "size": self.size,
 | 
			
		||||
            "volume_type": self.volume_type,
 | 
			
		||||
            "name": self.name,
 | 
			
		||||
            "description": self.description,
 | 
			
		||||
            "availability_zone": self.availability_zone}
 | 
			
		||||
        element = self._set_xml_etree_element(element, volume_attrs)
 | 
			
		||||
 | 
			
		||||
        if len(self.metadata.keys()) > 0:
 | 
			
		||||
            metadata_element = ElementTree.Element('metadata')
 | 
			
		||||
            for key in self.metadata.keys():
 | 
			
		||||
                meta_element = ElementTree.Element('meta')
 | 
			
		||||
                meta_element.set('key', key)
 | 
			
		||||
                meta_element.text = self.metadata[key]
 | 
			
		||||
                metadata_element.append(meta_element)
 | 
			
		||||
            element.append(metadata_element)
 | 
			
		||||
 | 
			
		||||
        return element
 | 
			
		||||
 | 
			
		||||
    def _obj_to_xml(self):
 | 
			
		||||
        return ElementTree.tostring(self._obj_to_xml_ele())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VolumeSnapshotRequest(AutoMarshallingModel):
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
            self, volume_id, force=True, name=None,
 | 
			
		||||
            description=None):
 | 
			
		||||
 | 
			
		||||
        self.volume_id = volume_id
 | 
			
		||||
        self.name = name
 | 
			
		||||
        self.description = description
 | 
			
		||||
        self.force = force
 | 
			
		||||
 | 
			
		||||
    def _obj_to_json(self):
 | 
			
		||||
        return json.dumps(self._obj_to_json_dict())
 | 
			
		||||
 | 
			
		||||
    def _obj_to_json_dict(self):
 | 
			
		||||
        snapshot_attrs = {
 | 
			
		||||
            "volume_id": self.volume_id,
 | 
			
		||||
            "name": self.name,
 | 
			
		||||
            "description": self.description,
 | 
			
		||||
            "force": self.force}
 | 
			
		||||
 | 
			
		||||
        return {"snapshot": self._remove_empty_values(snapshot_attrs)}
 | 
			
		||||
 | 
			
		||||
    def _obj_to_xml(self):
 | 
			
		||||
        return ElementTree.tostring(self._obj_to_xml_ele())
 | 
			
		||||
 | 
			
		||||
    def _obj_to_xml_ele(self):
 | 
			
		||||
        element = ElementTree.Element('snapshot')
 | 
			
		||||
        snapshot_attrs = {
 | 
			
		||||
            "volume_id": self.volume_id,
 | 
			
		||||
            "name": self.name,
 | 
			
		||||
            "description": self.description,
 | 
			
		||||
            "force": str(self.force)}
 | 
			
		||||
        return self._set_xml_etree_element(element, snapshot_attrs)
 | 
			
		||||
		Reference in New Issue
	
	Block a user