Reducing code duplication in volumes clients

Change-Id: Ife73c321c5636b03b8f53bb5256f5b6da330409b
This commit is contained in:
Jose Idar
2015-05-22 15:46:12 -05:00
parent 1236b4d40d
commit 05c3581285
5 changed files with 360 additions and 248 deletions

View File

@@ -0,0 +1,210 @@
"""
Copyright 2015 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 abc
from cafe.engine.http.client import AutoMarshallingHTTPClient
class BaseVolumesClient(AutoMarshallingHTTPClient):
__metaclass__ = abc.ABCMeta
def __init__(
self, url, auth_token, serialize_format=None,
deserialize_format=None):
super(BaseVolumesClient, self).__init__(
serialize_format, deserialize_format)
self.url = url
self.auth_token = auth_token
self.default_headers['X-Auth-Token'] = auth_token
self.default_headers['Content-Type'] = 'application/{0}'.format(
self.serialize_format)
self.default_headers['Accept'] = 'application/{0}'.format(
self.deserialize_format)
@abc.abstractproperty
def request_models(self):
pass
@abc.abstractproperty
def response_models(self):
pass
@abc.abstractmethod
def create_volume(self):
pass
@abc.abstractmethod
def update_volume(self):
pass
@abc.abstractmethod
def create_snapshot(self):
pass
def list_all_volumes(self, requestslib_kwargs=None):
"""GET /volumes"""
url = '{0}/volumes'.format(self.url)
return self.request(
'GET', url,
response_entity_type=self.response_models.VolumeListResponse,
requestslib_kwargs=requestslib_kwargs)
def list_all_volumes_info(self, requestslib_kwargs=None):
"""GET /volumes/detail"""
url = '{0}/volumes/detail'.format(self.url)
return self.request(
'GET', url,
response_entity_type=self.response_models.VolumeListResponse,
requestslib_kwargs=requestslib_kwargs)
def get_volume_info(self, volume_id, requestslib_kwargs=None):
"""GET /volumes/{volume_id}"""
url = '{0}/volumes/{1}'.format(self.url, volume_id)
return self.request(
'GET', url,
response_entity_type=self.response_models.VolumeResponse,
requestslib_kwargs=requestslib_kwargs)
def delete_volume(self, volume_id, requestslib_kwargs=None):
"""DELETE /volumes/{volume_id}"""
url = '{0}/volumes/{1}'.format(self.url, volume_id)
return self.request(
'DELETE', url,
response_entity_type=self.response_models.VolumeResponse,
requestslib_kwargs=requestslib_kwargs)
# Volume Types
def list_all_volume_types(self, requestslib_kwargs=None):
"""GET /types """
url = '{0}/types'.format(self.url)
return self.request(
'GET', url,
response_entity_type=self.response_models.VolumeTypeListResponse,
requestslib_kwargs=requestslib_kwargs)
def get_volume_type_info(self, volume_type_id, requestslib_kwargs=None):
"""GET /types/{volume_type_id}"""
url = '{0}/types/{1}'.format(self.url, volume_type_id)
return self.request(
'GET', url,
response_entity_type=self.response_models.VolumeTypeResponse,
requestslib_kwargs=requestslib_kwargs)
def create_volume_type(
self, name, extra_specs=None, requestslib_kwargs=None):
""" POST /types"""
url = '{url}/types'.format(url=self.url)
request_entity = self.request_models.VolumeTypeCreateRequest(
name=name, extra_specs=extra_specs)
return self.request(
'POST', url, request_entity=request_entity,
response_entity_type=self.response_models.VolumeTypeResponse,
requestslib_kwargs=requestslib_kwargs)
def delete_volume_type(self, volume_type_id, requestslib_kwargs=None):
""" DELETE /types/{volume_type_id} """
url = '{url}/types/{volume_type_id}'.format(
url=self.url, volume_type_id=volume_type_id)
return self.request(
'DELETE', url, requestslib_kwargs=requestslib_kwargs)
def update_volume_type_extra_specs(
self, volume_type_id, extra_specs=None, requestslib_kwargs=None):
""" POST /types/{volume_type_id}/extra_specs """
extra_specs = extra_specs or dict()
url = '{url}/types/{volume_type_id}/extra_specs'.format(
url=self.url, volume_type_id=volume_type_id)
request_entity = self.request_models.VolumeTypeExtraSpecsUpdateRequest(
extra_specs=extra_specs)
return self.request(
'POST', url, request_entity=request_entity,
response_entity_type=self.response_models.VolumeTypeResponse,
requestslib_kwargs=requestslib_kwargs)
def delete_volume_type_extra_spec(
self, volume_type_id, extra_spec_key, requestslib_kwargs=None):
""" DELETE /types/{volume_type_id}/extra_specs/{extra_spec_key} """
url = '{url}/types/{vtype_id}/extra_specs/{extra_spec_key}'.format(
url=self.url, vtype_id=volume_type_id,
extra_spec_key=extra_spec_key)
return self.request(
'DELETE', url, requestslib_kwargs=requestslib_kwargs)
def list_all_snapshots(self, requestslib_kwargs=None):
"""GET /snapshots"""
url = '{0}/snapshots'.format(self.url)
return self.request(
'GET', url,
response_entity_type=
self.response_models.VolumeSnapshotListResponse,
requestslib_kwargs=requestslib_kwargs)
def list_all_snapshots_info(self, requestslib_kwargs=None):
"""GET /snapshots/detail"""
url = '{0}/snapshots/detail'.format(self.url)
return self.request(
'GET', url,
response_entity_type=
self.response_models.VolumeSnapshotListResponse,
requestslib_kwargs=requestslib_kwargs)
def get_snapshot_info(self, snapshot_id, requestslib_kwargs=None):
"""GET /snapshots/{snapshot_id}"""
url = '{0}/snapshots/{1}'.format(self.url, snapshot_id)
return self.request(
'GET', url,
response_entity_type=self.response_models.VolumeSnapshotResponse,
requestslib_kwargs=requestslib_kwargs)
def delete_snapshot(self, snapshot_id, requestslib_kwargs=None):
"""Delete /snapshots/{snapshot_id} """
url = '{0}/snapshots/{1}'.format(self.url, snapshot_id)
return self.request(
'DELETE', url,
response_entity_type=self.response_models.VolumeSnapshotResponse,
requestslib_kwargs=requestslib_kwargs)

View File

@@ -1,5 +1,5 @@
"""
Copyright 2013 Rackspace
Copyright 2015 Rackspace
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,36 +13,33 @@ 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.http.client import AutoMarshallingHTTPClient
from cloudcafe.blockstorage.volumes_api.v1.models.requests import (
VolumeRequest, VolumeSnapshotRequest)
from cloudcafe.blockstorage.volumes_api.v1.models.responses import (
VolumeResponse, VolumeSnapshotResponse, VolumeTypeResponse,
VolumeListResponse, VolumeTypeListResponse, VolumeSnapshotListResponse)
from cloudcafe.blockstorage.volumes_api.common.client import BaseVolumesClient
from cloudcafe.blockstorage.volumes_api.v1.models import \
requests as _request_models
from cloudcafe.blockstorage.volumes_api.v1.models import \
responses as _response_models
class VolumesClient(AutoMarshallingHTTPClient):
class VolumesClient(BaseVolumesClient):
def __init__(
self, url, auth_token, serialize_format=None,
deserialize_format=None):
super(VolumesClient, self).__init__(
serialize_format, deserialize_format)
url, auth_token, serialize_format, deserialize_format)
self.url = url
self.auth_token = auth_token
self.default_headers['X-Auth-Token'] = auth_token
self.default_headers['Content-Type'] = 'application/{0}'.format(
self.serialize_format)
self.default_headers['Accept'] = 'application/{0}'.format(
self.deserialize_format)
@property
def request_models(self):
return _request_models
@property
def response_models(self):
return _response_models
def create_volume(
self, size, volume_type, display_name=None,
display_description=None, name=None, description=None,
self, size, volume_type, name=None, description=None,
display_name=None, display_description=None,
availability_zone=None, metadata=None, bootable=None,
image_ref=None, snapshot_id=None, source_volid=None,
requestslib_kwargs=None):
@@ -54,7 +51,7 @@ class VolumesClient(AutoMarshallingHTTPClient):
display_name = display_name or name
display_description = display_description or description
volume_request_entity = VolumeRequest(
volume_request_entity = self.request_models.VolumeRequest(
size=size, volume_type=volume_type, display_name=display_name,
display_description=display_description, metadata=metadata,
bootable=bootable, snapshot_id=snapshot_id,
@@ -63,7 +60,7 @@ class VolumesClient(AutoMarshallingHTTPClient):
return self.request(
'POST', url,
response_entity_type=VolumeResponse,
response_entity_type=self.response_models.VolumeResponse,
request_entity=volume_request_entity,
requestslib_kwargs=requestslib_kwargs)
@@ -79,72 +76,16 @@ class VolumesClient(AutoMarshallingHTTPClient):
display_name = display_name or name
display_description = display_description or description
volume_request_entity = VolumeRequest(
volume_request_entity = self.request_models.VolumeRequest(
display_name=display_name, display_description=display_description,
metadata=metadata)
return self.request(
'PUT', url,
response_entity_type=VolumeResponse,
response_entity_type=self.response_models.VolumeResponse,
request_entity=volume_request_entity,
requestslib_kwargs=requestslib_kwargs)
def list_all_volumes(self, requestslib_kwargs=None):
"""GET /volumes"""
url = '{0}/volumes'.format(self.url)
return self.request(
'GET', url, response_entity_type=VolumeListResponse,
requestslib_kwargs=requestslib_kwargs)
def list_all_volumes_info(self, requestslib_kwargs=None):
"""GET /volumes/detail"""
url = '{0}/volumes/detail'.format(self.url)
return self.request(
'GET', url, response_entity_type=VolumeListResponse,
requestslib_kwargs=requestslib_kwargs)
def get_volume_info(self, volume_id, requestslib_kwargs=None):
"""GET /volumes/{volume_id}"""
url = '{0}/volumes/{1}'.format(self.url, volume_id)
return self.request(
'GET', url, response_entity_type=VolumeResponse,
requestslib_kwargs=requestslib_kwargs)
def delete_volume(self, volume_id, requestslib_kwargs=None):
"""DELETE /volumes/{volume_id}"""
url = '{0}/volumes/{1}'.format(self.url, volume_id)
return self.request(
'DELETE', url, response_entity_type=VolumeResponse,
requestslib_kwargs=requestslib_kwargs)
# Volume Types API
def list_all_volume_types(self, requestslib_kwargs=None):
"""GET /types """
url = '{0}/types'.format(self.url)
return self.request(
'GET', url, response_entity_type=VolumeTypeListResponse,
requestslib_kwargs=requestslib_kwargs)
def get_volume_type_info(self, volume_type_id, requestslib_kwargs=None):
"""GET /types/{volume_type_id}"""
url = '{0}/types/{1}'.format(self.url, volume_type_id)
return self.request(
'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,
name=None, description=None, force_create=False,
@@ -157,52 +98,15 @@ class VolumesClient(AutoMarshallingHTTPClient):
display_name = display_name or name
display_description = display_description or description
volume_snapshot_request_entity = VolumeSnapshotRequest(
volume_id,
force=force_create,
display_name=display_name,
display_description=display_description)
volume_snapshot_request_entity = \
self.request_models.VolumeSnapshotRequest(
volume_id,
force=force_create,
display_name=display_name,
display_description=display_description)
return self.request(
'POST', url,
response_entity_type=VolumeSnapshotResponse,
response_entity_type=self.response_models.VolumeSnapshotResponse,
request_entity=volume_snapshot_request_entity,
requestslib_kwargs=requestslib_kwargs)
def list_all_snapshots(self, requestslib_kwargs=None):
"""GET /snapshots"""
url = '{0}/snapshots'.format(self.url)
return self.request(
'GET', url, response_entity_type=VolumeSnapshotListResponse,
requestslib_kwargs=requestslib_kwargs)
def list_all_snapshots_info(self, requestslib_kwargs=None):
"""GET /snapshots/detail"""
url = '{0}/snapshots/detail'.format(self.url)
return self.request(
'GET', url, response_entity_type=VolumeSnapshotListResponse,
requestslib_kwargs=requestslib_kwargs)
def get_snapshot_info(self, snapshot_id, requestslib_kwargs=None):
"""GET /snapshots/{snapshot_id}"""
url = '{0}/snapshots/{1}'.format(self.url, snapshot_id)
return self.request(
'GET', url, response_entity_type=VolumeSnapshotResponse,
requestslib_kwargs=requestslib_kwargs)
def delete_snapshot(self, snapshot_id, requestslib_kwargs=None):
"""Delete /snapshots/{snapshot_id} """
url = '{0}/snapshots/{1}'.format(self.url, snapshot_id)
return self.request(
'DELETE', url, response_entity_type=VolumeSnapshotResponse,
requestslib_kwargs=requestslib_kwargs)

View File

@@ -128,3 +128,50 @@ class VolumeSnapshotRequest(CommonModelProperties, AutoMarshallingModel):
"display_description": self.description,
"force": str(self.force)}
return self._set_xml_etree_element(element, snapshot_attrs)
class VolumeTypeCreateRequest(AutoMarshallingModel):
def __init__(self, name, extra_specs=None):
super(VolumeTypeCreateRequest, self).__init__()
self.name = name
self.extra_specs = extra_specs
def _obj_to_json(self):
return json.dumps(self._obj_to_json_dict())
def _obj_to_json_dict(self):
attrs = {
"name": self.name,
"extra_specs": self.extra_specs}
return dict(volume_type=self._remove_empty_values(attrs))
def _obj_to_xml(self):
return ElementTree.tostring(self._obj_to_xml_ele())
def _obj_to_xml_ele(self):
element = ElementTree.Element('volume_type')
attrs = {"name": self.name}
if len(self.extra_specs.keys()) > 0:
extra_specs = ElementTree.Element('extra_specs')
for key in self.extra_specs.keys():
spec = ElementTree.Element('extra_spec')
spec.set('key', key)
spec.text = self.extra_specs[key]
extra_specs.append(spec)
element.append(extra_specs)
return self._set_xml_etree_element(element, attrs)
class VolumeTypeExtraSpecsUpdateRequest(AutoMarshallingModel):
def __init__(self, extra_specs=None):
super(VolumeTypeExtraSpecsUpdateRequest, self).__init__()
self.extra_specs = extra_specs
def _obj_to_json(self):
return json.dumps(self._obj_to_json_dict())
def _obj_to_json_dict(self):
return dict(extra_specs=self._remove_empty_values(self.extra_specs))

View File

@@ -1,5 +1,5 @@
"""
Copyright 2013 Rackspace
Copyright 2015 Rackspace
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,32 +13,29 @@ 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.http.client import AutoMarshallingHTTPClient
from cloudcafe.blockstorage.volumes_api.v2.models.requests import (
VolumeRequest, VolumeSnapshotRequest)
from cloudcafe.blockstorage.volumes_api.v2.models.responses import (
VolumeResponse, VolumeSnapshotResponse, VolumeTypeResponse,
VolumeListResponse, VolumeTypeListResponse, VolumeSnapshotListResponse)
from cloudcafe.blockstorage.volumes_api.common.client import BaseVolumesClient
from cloudcafe.blockstorage.volumes_api.v2.models import \
requests as _request_models
from cloudcafe.blockstorage.volumes_api.v2.models import \
responses as _response_models
class VolumesClient(AutoMarshallingHTTPClient):
class VolumesClient(BaseVolumesClient):
def __init__(
self, url, auth_token, serialize_format=None,
deserialize_format=None):
super(VolumesClient, self).__init__(
serialize_format, deserialize_format)
url, auth_token, serialize_format, deserialize_format)
self.url = url
self.auth_token = auth_token
self.default_headers['X-Auth-Token'] = auth_token
self.default_headers['Content-Type'] = 'application/{0}'.format(
self.serialize_format)
self.default_headers['Accept'] = 'application/{0}'.format(
self.deserialize_format)
@property
def request_models(self):
return _request_models
@property
def response_models(self):
return _response_models
def create_volume(
self, size, volume_type, name=None, description=None,
@@ -54,7 +51,7 @@ class VolumesClient(AutoMarshallingHTTPClient):
name = name or display_name
description = description or display_description
volume_request_entity = VolumeRequest(
volume_request_entity = self.request_models.VolumeRequest(
size=size, volume_type=volume_type, name=name, image_ref=image_ref,
description=description, availability_zone=availability_zone,
metadata=metadata, bootable=bootable, snapshot_id=snapshot_id,
@@ -62,7 +59,7 @@ class VolumesClient(AutoMarshallingHTTPClient):
return self.request(
'POST', url,
response_entity_type=VolumeResponse,
response_entity_type=self.response_models.VolumeResponse,
request_entity=volume_request_entity,
requestslib_kwargs=requestslib_kwargs)
@@ -78,71 +75,15 @@ class VolumesClient(AutoMarshallingHTTPClient):
name = name or display_name
description = description or display_description
volume_request_entity = VolumeRequest(
volume_request_entity = self.request_models.VolumeRequest(
name=name, description=description, metadata=metadata)
return self.request(
'PUT', url,
response_entity_type=VolumeResponse,
response_entity_type=self.response_models.VolumeResponse,
request_entity=volume_request_entity,
requestslib_kwargs=requestslib_kwargs)
def list_all_volumes(self, requestslib_kwargs=None):
"""GET /volumes"""
url = '{0}/volumes'.format(self.url)
return self.request(
'GET', url, response_entity_type=VolumeListResponse,
requestslib_kwargs=requestslib_kwargs)
def list_all_volumes_info(self, requestslib_kwargs=None):
"""GET /volumes/detail"""
url = '{0}/volumes/detail'.format(self.url)
return self.request(
'GET', url, response_entity_type=VolumeListResponse,
requestslib_kwargs=requestslib_kwargs)
def get_volume_info(self, volume_id, requestslib_kwargs=None):
"""GET /volumes/{volume_id}"""
url = '{0}/volumes/{1}'.format(self.url, volume_id)
return self.request(
'GET', url, response_entity_type=VolumeResponse,
requestslib_kwargs=requestslib_kwargs)
def delete_volume(self, volume_id, requestslib_kwargs=None):
"""DELETE /volumes/{volume_id}"""
url = '{0}/volumes/{1}'.format(self.url, volume_id)
return self.request(
'DELETE', url, response_entity_type=VolumeResponse,
requestslib_kwargs=requestslib_kwargs)
# Volume Types API
def list_all_volume_types(self, requestslib_kwargs=None):
"""GET /types """
url = '{0}/types'.format(self.url)
return self.request(
'GET', url, response_entity_type=VolumeTypeListResponse,
requestslib_kwargs=requestslib_kwargs)
def get_volume_type_info(self, volume_type_id, requestslib_kwargs=None):
"""GET /types/{volume_type_id}"""
url = '{0}/types/{1}'.format(self.url, volume_type_id)
return self.request(
'GET', url, response_entity_type=VolumeTypeResponse,
requestslib_kwargs=requestslib_kwargs)
# Volume Snapshot API
def create_snapshot(
self, volume_id, name=None, description=None,
display_name=None, display_description=None,
@@ -155,52 +96,15 @@ class VolumesClient(AutoMarshallingHTTPClient):
name = name or display_name
description = description or display_description
volume_snapshot_request_entity = VolumeSnapshotRequest(
volume_id,
force=force_create,
name=name,
description=description)
volume_snapshot_request_entity = \
self.request_models.VolumeSnapshotRequest(
volume_id,
force=force_create,
name=name,
description=description)
return self.request(
'POST', url,
response_entity_type=VolumeSnapshotResponse,
response_entity_type=self.response_models.VolumeSnapshotResponse,
request_entity=volume_snapshot_request_entity,
requestslib_kwargs=requestslib_kwargs)
def list_all_snapshots(self, requestslib_kwargs=None):
"""GET /snapshots"""
url = '{0}/snapshots'.format(self.url)
return self.request(
'GET', url, response_entity_type=VolumeSnapshotListResponse,
requestslib_kwargs=requestslib_kwargs)
def list_all_snapshots_info(self, requestslib_kwargs=None):
"""GET /snapshots/detail"""
url = '{0}/snapshots/detail'.format(self.url)
return self.request(
'GET', url, response_entity_type=VolumeSnapshotListResponse,
requestslib_kwargs=requestslib_kwargs)
def get_snapshot_info(self, snapshot_id, requestslib_kwargs=None):
"""GET /snapshots/{snapshot_id}"""
url = '{0}/snapshots/{1}'.format(self.url, snapshot_id)
return self.request(
'GET', url, response_entity_type=VolumeSnapshotResponse,
requestslib_kwargs=requestslib_kwargs)
def delete_snapshot(self, snapshot_id, requestslib_kwargs=None):
"""DELETE /snapshots/{snapshot_id}"""
url = '{0}/snapshots/{1}'.format(self.url, snapshot_id)
return self.request(
'DELETE', url, response_entity_type=VolumeSnapshotResponse,
requestslib_kwargs=requestslib_kwargs)

View File

@@ -127,3 +127,50 @@ class VolumeSnapshotRequest(CommonModelProperties, AutoMarshallingModel):
"description": self.description,
"force": str(self.force)}
return self._set_xml_etree_element(element, snapshot_attrs)
class VolumeTypeCreateRequest(AutoMarshallingModel):
def __init__(self, name, extra_specs=None):
super(VolumeTypeCreateRequest, self).__init__()
self.name = name
self.extra_specs = extra_specs
def _obj_to_json(self):
return json.dumps(self._obj_to_json_dict())
def _obj_to_json_dict(self):
attrs = {
"name": self.name,
"extra_specs": self.extra_specs}
return dict(volume_type=self._remove_empty_values(attrs))
def _obj_to_xml(self):
return ElementTree.tostring(self._obj_to_xml_ele())
def _obj_to_xml_ele(self):
element = ElementTree.Element('volume_type')
attrs = {"name": self.name}
if len(self.extra_specs.keys()) > 0:
extra_specs = ElementTree.Element('extra_specs')
for key in self.extra_specs.keys():
spec = ElementTree.Element('extra_spec')
spec.set('key', key)
spec.text = self.extra_specs[key]
extra_specs.append(spec)
element.append(extra_specs)
return self._set_xml_etree_element(element, attrs)
class VolumeTypeExtraSpecsUpdateRequest(AutoMarshallingModel):
def __init__(self, extra_specs=None):
super(VolumeTypeExtraSpecsUpdateRequest, self).__init__()
self.extra_specs = extra_specs
def _obj_to_json(self):
return json.dumps(self._obj_to_json_dict())
def _obj_to_json_dict(self):
return dict(extra_specs=self._remove_empty_values(self.extra_specs))