Add API services for Create a Volume, get QoS and tenant limits
Adding cinder services to create and update volumes and volume snapshots, return Quality of Service and tenant absolute limits. This is to support dependent patches that will create volumes for Images from the angular panel for Images. Co-Authored-By: Errol Pais<epais@thoughtworks.com> Co-Authored-By: Nathan Zeplowitz<nzeplowi@thoughtworks.com> Partially-Implements: blueprint angularize-images-table Change-Id: I4c48c09a0f20f971588b1e920a555f12e7ed4498
This commit is contained in:
parent
f97cf83475
commit
56e34bdf0c
|
@ -96,7 +96,8 @@ class VolumeSnapshot(BaseCinderAPIResourceWrapper):
|
|||
|
||||
class VolumeType(BaseCinderAPIResourceWrapper):
|
||||
|
||||
_attrs = ['id', 'name', 'extra_specs', 'created_at',
|
||||
_attrs = ['id', 'name', 'extra_specs', 'created_at', 'encryption',
|
||||
'associated_qos_spec', 'description',
|
||||
'os-extended-snapshot-attributes:project_id']
|
||||
|
||||
|
||||
|
@ -115,6 +116,11 @@ class VolumeBackup(BaseCinderAPIResourceWrapper):
|
|||
self._volume = value
|
||||
|
||||
|
||||
class QosSpecs(BaseCinderAPIResourceWrapper):
|
||||
|
||||
_attrs = ['id', 'name', 'consumer', 'specs']
|
||||
|
||||
|
||||
class VolTypeExtraSpec(object):
|
||||
def __init__(self, type_id, key, val):
|
||||
self.type_id = type_id
|
||||
|
@ -581,6 +587,10 @@ def qos_spec_get_associations(request, qos_spec_id):
|
|||
return cinderclient(request).qos_specs.get_associations(qos_spec_id)
|
||||
|
||||
|
||||
def qos_specs_list(request):
|
||||
return [QosSpecs(s) for s in qos_spec_list(request)]
|
||||
|
||||
|
||||
@memoized
|
||||
def tenant_absolute_limits(request):
|
||||
limits = cinderclient(request).limits.get().absolute
|
||||
|
|
|
@ -54,6 +54,26 @@ class Volumes(generic.View):
|
|||
)
|
||||
return {'items': [u.to_dict() for u in result]}
|
||||
|
||||
@rest_utils.ajax(data_required=True)
|
||||
def post(self, request):
|
||||
volume = api.cinder.volume_create(
|
||||
request,
|
||||
size=request.DATA['size'],
|
||||
name=request.DATA['name'],
|
||||
description=request.DATA['description'],
|
||||
volume_type=request.DATA['volume_type'],
|
||||
snapshot_id=request.DATA['snapshot_id'],
|
||||
metadata=request.DATA['metadata'],
|
||||
image_id=request.DATA['image_id'],
|
||||
availability_zone=request.DATA['availability_zone'],
|
||||
source_volid=request.DATA['source_volid']
|
||||
)
|
||||
|
||||
return rest_utils.CreatedResponse(
|
||||
'/api/cinder/volumes/%s' % volume.id,
|
||||
volume.to_dict()
|
||||
)
|
||||
|
||||
|
||||
@urls.register
|
||||
class Volume(generic.View):
|
||||
|
@ -163,3 +183,22 @@ class Extensions(generic.View):
|
|||
'updated': e.updated
|
||||
|
||||
} for e in result]}
|
||||
|
||||
|
||||
@urls.register
|
||||
class QoSSpecs(generic.View):
|
||||
url_regex = r'cinder/qosspecs/$'
|
||||
|
||||
@rest_utils.ajax()
|
||||
def get(self, request):
|
||||
result = api.cinder.qos_specs_list(request)
|
||||
return {'items': [u.to_dict() for u in result]}
|
||||
|
||||
|
||||
@urls.register
|
||||
class TenantAbsoluteLimits(generic.View):
|
||||
url_regex = r'cinder/tenantabsolutelimits/$'
|
||||
|
||||
@rest_utils.ajax()
|
||||
def get(self, request):
|
||||
return api.cinder.tenant_absolute_limits(request)
|
||||
|
|
|
@ -38,7 +38,10 @@
|
|||
getVolumeType: getVolumeType,
|
||||
getDefaultVolumeType: getDefaultVolumeType,
|
||||
getVolumeSnapshots: getVolumeSnapshots,
|
||||
getExtensions: getExtensions
|
||||
getExtensions: getExtensions,
|
||||
getQoSSpecs: getQoSSpecs,
|
||||
createVolume: createVolume,
|
||||
getAbsoluteLimits: getAbsoluteLimits
|
||||
};
|
||||
|
||||
return service;
|
||||
|
@ -63,7 +66,7 @@
|
|||
* For example, "status": "available" will show all available volumes.
|
||||
*/
|
||||
function getVolumes(params) {
|
||||
var config = (params) ? {'params': params} : {};
|
||||
var config = params ? {'params': params} : {};
|
||||
return apiService.get('/api/cinder/volumes/', config)
|
||||
.error(function () {
|
||||
toastService.add('error', gettext('Unable to retrieve the volumes.'));
|
||||
|
@ -86,6 +89,18 @@
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name horizon.app.core.openstack-service-api.cinder.createVolume
|
||||
* @description
|
||||
* Create a volume.
|
||||
*/
|
||||
function createVolume(newVolume) {
|
||||
return apiService.post('/api/cinder/volumes/', newVolume)
|
||||
.error(function () {
|
||||
toastService.add('error', gettext('Unable to create the volume.'));
|
||||
});
|
||||
}
|
||||
|
||||
// Volume Types
|
||||
|
||||
/**
|
||||
|
@ -152,7 +167,7 @@
|
|||
* snapshots.
|
||||
*/
|
||||
function getVolumeSnapshots(params) {
|
||||
var config = (params) ? {'params': params} : {};
|
||||
var config = params ? {'params': params} : {};
|
||||
return apiService.get('/api/cinder/volumesnapshots/', config)
|
||||
.error(function () {
|
||||
toastService.add('error',
|
||||
|
@ -192,5 +207,39 @@
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name horizon.app.core.openstack-service-api.cinder.getQoSSpecs
|
||||
* @description
|
||||
* Get a list of Quality of Service.
|
||||
*
|
||||
* The listing result is an object with property "items." Each item is
|
||||
* a Quality of Service Spec.
|
||||
*
|
||||
* @param {Object} params
|
||||
* Query parameters. Optional.
|
||||
*
|
||||
*/
|
||||
function getQoSSpecs(params) {
|
||||
var config = params ? {'params': params} : {};
|
||||
return apiService.get('/api/cinder/qosspecs/', config)
|
||||
.error(function () {
|
||||
toastService.add('error',
|
||||
gettext('Unable to retrieve the QoS Specs.'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name horizon.app.core.openstack-service-api.cinder.getAbsoluteLimits
|
||||
* @description
|
||||
* Get the limits for the current tenant.
|
||||
*
|
||||
*/
|
||||
function getAbsoluteLimits() {
|
||||
return apiService.get('/api/cinder/tenantabsolutelimits/')
|
||||
.error(function () {
|
||||
toastService.add('error',
|
||||
gettext('Unable to retrieve the Absolute Limits.'));
|
||||
});
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
|
|
@ -107,6 +107,33 @@
|
|||
data: { params: 'config' },
|
||||
error: 'Unable to retrieve the volume snapshots.',
|
||||
testInput: [ 'config' ]
|
||||
},
|
||||
{
|
||||
func: 'createVolume',
|
||||
method: 'post',
|
||||
path: '/api/cinder/volumes/',
|
||||
data: { params: 'config' },
|
||||
error: 'Unable to create the volume.',
|
||||
testInput: [
|
||||
{
|
||||
params: 'config'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
func: 'getQoSSpecs',
|
||||
method: 'get',
|
||||
path: '/api/cinder/qosspecs/',
|
||||
data: {},
|
||||
error: 'Unable to retrieve the QoS Specs.'
|
||||
},
|
||||
{
|
||||
func: 'getQoSSpecs',
|
||||
method: 'get',
|
||||
path: '/api/cinder/qosspecs/',
|
||||
data: { params: 'config' },
|
||||
error: 'Unable to retrieve the QoS Specs.',
|
||||
testInput: [ 'config' ]
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
@ -65,6 +65,35 @@ class CinderRestTestCase(test.TestCase):
|
|||
self.assertEqual(response.json, {"id": "one"})
|
||||
cc.volume_get.assert_called_once_with(request, '1')
|
||||
|
||||
@mock.patch.object(cinder.api, 'cinder')
|
||||
def test_volume_create(self, cc):
|
||||
mock_body = '''{
|
||||
"size": "",
|
||||
"name": "",
|
||||
"description": "",
|
||||
"volume_type": "",
|
||||
"snapshot_id": "",
|
||||
"metadata": "",
|
||||
"image_id": "",
|
||||
"availability_zone": "",
|
||||
"source_volid": ""
|
||||
}'''
|
||||
|
||||
mock_volume_create_response = {
|
||||
"size": ""
|
||||
}
|
||||
|
||||
mock_post_response = '{"size": ""}'
|
||||
|
||||
request = self.mock_rest_request(POST={}, body=mock_body)
|
||||
cc.volume_create.return_value = \
|
||||
mock.Mock(**{'to_dict.return_value': mock_volume_create_response})
|
||||
|
||||
response = cinder.Volumes().post(request)
|
||||
|
||||
self.assertStatusCode(response, 201)
|
||||
self.assertEqual(response.content.decode("utf-8"), mock_post_response)
|
||||
|
||||
#
|
||||
# Volume Types
|
||||
#
|
||||
|
@ -154,3 +183,26 @@ class CinderRestTestCase(test.TestCase):
|
|||
self.assertEqual(response.content,
|
||||
'{"items": [{"name": "foo"}, {"name": "bar"}]}')
|
||||
cc.list_extensions.assert_called_once_with(request)
|
||||
|
||||
@mock.patch.object(cinder.api, 'cinder')
|
||||
def test_qos_specs_get(self, cc):
|
||||
request = self.mock_rest_request(GET={})
|
||||
cc.qos_specs_list.return_value = [
|
||||
mock.Mock(**{'to_dict.return_value': {'id': 'one'}}),
|
||||
mock.Mock(**{'to_dict.return_value': {'id': 'two'}}),
|
||||
]
|
||||
response = cinder.QoSSpecs().get(request)
|
||||
self.assertStatusCode(response, 200)
|
||||
self.assertEqual(response.content.decode("utf-8"),
|
||||
'{"items": [{"id": "one"}, {"id": "two"}]}')
|
||||
cc.qos_specs_list.assert_called_once_with(request)
|
||||
|
||||
@mock.patch.object(cinder.api, 'cinder')
|
||||
def test_tenant_absolute_limits_get(self, cc):
|
||||
request = self.mock_rest_request(GET={})
|
||||
cc.tenant_absolute_limits.return_value = \
|
||||
{'id': 'one'}
|
||||
response = cinder.TenantAbsoluteLimits().get(request)
|
||||
self.assertStatusCode(response, 200)
|
||||
self.assertEqual(response.content.decode("utf-8"), '{"id": "one"}')
|
||||
cc.tenant_absolute_limits.assert_called_once_with(request)
|
||||
|
|
Loading…
Reference in New Issue