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