Add volume quotas support
Add the capability to get, update and reset to default quotas in volume service. Change-Id: Ib5a996b90bb41c7ad01ac496a89478ea71a6bf2f
This commit is contained in:
parent
7f47eb2a64
commit
49ca650015
3
releasenotes/notes/volume-quotas-5b674ee8c1f71eb6.yaml
Normal file
3
releasenotes/notes/volume-quotas-5b674ee8c1f71eb6.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add new APIs, OperatorCloud.get_volume_quotas(), OperatorCloud.set_volume_quotas() and OperatorCloud.delete_volume_quotas() to manage cinder quotas for projects and users
|
@ -892,3 +892,18 @@ class NovaQuotasGet(task_manager.Task):
|
|||||||
class NovaQuotasDelete(task_manager.Task):
|
class NovaQuotasDelete(task_manager.Task):
|
||||||
def main(self, client):
|
def main(self, client):
|
||||||
return client.nova_client.quotas.delete(**self.args)
|
return client.nova_client.quotas.delete(**self.args)
|
||||||
|
|
||||||
|
|
||||||
|
class CinderQuotasSet(task_manager.Task):
|
||||||
|
def main(self, client):
|
||||||
|
return client.cinder_client.quotas.update(**self.args)
|
||||||
|
|
||||||
|
|
||||||
|
class CinderQuotasGet(task_manager.Task):
|
||||||
|
def main(self, client):
|
||||||
|
return client.cinder_client.quotas.get(**self.args)
|
||||||
|
|
||||||
|
|
||||||
|
class CinderQuotasDelete(task_manager.Task):
|
||||||
|
def main(self, client):
|
||||||
|
return client.cinder_client.quotas.delete(**self.args)
|
||||||
|
@ -15,6 +15,7 @@ import jsonpatch
|
|||||||
from ironicclient import client as ironic_client
|
from ironicclient import client as ironic_client
|
||||||
from ironicclient import exceptions as ironic_exceptions
|
from ironicclient import exceptions as ironic_exceptions
|
||||||
from novaclient import exceptions as nova_exceptions
|
from novaclient import exceptions as nova_exceptions
|
||||||
|
from cinderclient import exceptions as cinder_exceptions
|
||||||
|
|
||||||
from shade.exc import * # noqa
|
from shade.exc import * # noqa
|
||||||
from shade import openstackcloud
|
from shade import openstackcloud
|
||||||
@ -1996,3 +1997,59 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
|
|||||||
_tasks.NovaQuotasDelete(tenant_id=proj.id))
|
_tasks.NovaQuotasDelete(tenant_id=proj.id))
|
||||||
except novaclient.exceptions.BadRequest:
|
except novaclient.exceptions.BadRequest:
|
||||||
raise OpenStackCloudException("nova client call failed")
|
raise OpenStackCloudException("nova client call failed")
|
||||||
|
|
||||||
|
def set_volume_quotas(self, name_or_id, **kwargs):
|
||||||
|
""" Set a volume quota in a project
|
||||||
|
|
||||||
|
:param name_or_id: project name or id
|
||||||
|
:param kwargs: key/value pairs of quota name and quota value
|
||||||
|
|
||||||
|
:raises: OpenStackCloudException if the resource to set the
|
||||||
|
quota does not exist.
|
||||||
|
"""
|
||||||
|
|
||||||
|
proj = self.get_project(name_or_id)
|
||||||
|
if not proj:
|
||||||
|
raise OpenStackCloudException("project does not exist")
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.manager.submitTask(
|
||||||
|
_tasks.CinderQuotasSet(tenant_id=proj.id,
|
||||||
|
**kwargs))
|
||||||
|
except cinder_exceptions.BadRequest:
|
||||||
|
raise OpenStackCloudException("No valid quota or resource")
|
||||||
|
|
||||||
|
def get_volume_quotas(self, name_or_id):
|
||||||
|
""" Get volume quotas for a project
|
||||||
|
|
||||||
|
:param name_or_id: project name or id
|
||||||
|
:raises: OpenStackCloudException if it's not a valid project
|
||||||
|
|
||||||
|
:returns: Munch object with the quotas
|
||||||
|
"""
|
||||||
|
proj = self.get_project(name_or_id)
|
||||||
|
if not proj:
|
||||||
|
raise OpenStackCloudException("project does not exist")
|
||||||
|
try:
|
||||||
|
return self.manager.submitTask(
|
||||||
|
_tasks.CinderQuotasGet(tenant_id=proj.id))
|
||||||
|
except cinder_exceptions.BadRequest:
|
||||||
|
raise OpenStackCloudException("cinder client call failed")
|
||||||
|
|
||||||
|
def delete_volume_quotas(self, name_or_id):
|
||||||
|
""" Delete volume quotas for a project
|
||||||
|
|
||||||
|
:param name_or_id: project name or id
|
||||||
|
:raises: OpenStackCloudException if it's not a valid project or the
|
||||||
|
cinder client call failed
|
||||||
|
|
||||||
|
:returns: dict with the quotas
|
||||||
|
"""
|
||||||
|
proj = self.get_project(name_or_id)
|
||||||
|
if not proj:
|
||||||
|
raise OpenStackCloudException("project does not exist")
|
||||||
|
try:
|
||||||
|
return self.manager.submitTask(
|
||||||
|
_tasks.CinderQuotasDelete(tenant_id=proj.id))
|
||||||
|
except cinder_exceptions.BadRequest:
|
||||||
|
raise OpenStackCloudException("cinder client call failed")
|
||||||
|
@ -40,3 +40,23 @@ class TestComputeQuotas(base.TestCase):
|
|||||||
self.cloud.get_compute_quotas('demo')['cores'])
|
self.cloud.get_compute_quotas('demo')['cores'])
|
||||||
self.cloud.delete_compute_quotas('demo')
|
self.cloud.delete_compute_quotas('demo')
|
||||||
self.assertEqual(cores, self.cloud.get_compute_quotas('demo')['cores'])
|
self.assertEqual(cores, self.cloud.get_compute_quotas('demo')['cores'])
|
||||||
|
|
||||||
|
|
||||||
|
class TestVolumeQuotas(base.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestVolumeQuotas, self).setUp()
|
||||||
|
self.cloud = operator_cloud(cloud='devstack-admin')
|
||||||
|
if not self.cloud.has_service('volume'):
|
||||||
|
self.skipTest('volume service not supported by cloud')
|
||||||
|
|
||||||
|
def test_quotas(self):
|
||||||
|
'''Test quotas functionality'''
|
||||||
|
quotas = self.cloud.get_volume_quotas('demo')
|
||||||
|
volumes = quotas['volumes']
|
||||||
|
self.cloud.set_volume_quotas('demo', volumes=volumes + 1)
|
||||||
|
self.assertEqual(volumes + 1,
|
||||||
|
self.cloud.get_volume_quotas('demo')['volumes'])
|
||||||
|
self.cloud.delete_volume_quotas('demo')
|
||||||
|
self.assertEqual(volumes,
|
||||||
|
self.cloud.get_volume_quotas('demo')['volumes'])
|
||||||
|
@ -53,3 +53,32 @@ class TestQuotas(base.TestCase):
|
|||||||
self.cloud.delete_compute_quotas(project)
|
self.cloud.delete_compute_quotas(project)
|
||||||
|
|
||||||
mock_nova.quotas.delete.assert_called_once_with(tenant_id='project_a')
|
mock_nova.quotas.delete.assert_called_once_with(tenant_id='project_a')
|
||||||
|
|
||||||
|
@mock.patch.object(shade.OpenStackCloud, 'cinder_client')
|
||||||
|
@mock.patch.object(shade.OpenStackCloud, 'keystone_client')
|
||||||
|
def test_cinder_update_quotas(self, mock_keystone, mock_cinder):
|
||||||
|
project = fakes.FakeProject('project_a')
|
||||||
|
mock_keystone.tenants.list.return_value = [project]
|
||||||
|
self.cloud.set_volume_quotas(project, volumes=1)
|
||||||
|
|
||||||
|
mock_cinder.quotas.update.assert_called_once_with(
|
||||||
|
volumes=1, tenant_id='project_a')
|
||||||
|
|
||||||
|
@mock.patch.object(shade.OpenStackCloud, 'cinder_client')
|
||||||
|
@mock.patch.object(shade.OpenStackCloud, 'keystone_client')
|
||||||
|
def test_cinder_get_quotas(self, mock_keystone, mock_cinder):
|
||||||
|
project = fakes.FakeProject('project_a')
|
||||||
|
mock_keystone.tenants.list.return_value = [project]
|
||||||
|
self.cloud.get_volume_quotas(project)
|
||||||
|
|
||||||
|
mock_cinder.quotas.get.assert_called_once_with(tenant_id='project_a')
|
||||||
|
|
||||||
|
@mock.patch.object(shade.OpenStackCloud, 'cinder_client')
|
||||||
|
@mock.patch.object(shade.OpenStackCloud, 'keystone_client')
|
||||||
|
def test_cinder_delete_quotas(self, mock_keystone, mock_cinder):
|
||||||
|
project = fakes.FakeProject('project_a')
|
||||||
|
mock_keystone.tenants.list.return_value = [project]
|
||||||
|
self.cloud.delete_volume_quotas(project)
|
||||||
|
|
||||||
|
mock_cinder.quotas.delete.assert_called_once_with(
|
||||||
|
tenant_id='project_a')
|
||||||
|
Loading…
Reference in New Issue
Block a user