Add cinder quota driver
The driver takes care of quota rebalancing. Currently the limits considered by the driver are volumes, snapshots, backups, gigabytes. Change-Id: I4b638088dd5331e1c51d14b97ebbcba173217fca
This commit is contained in:
parent
fe721d02f4
commit
30dde56e6a
|
@ -10,6 +10,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from collections import defaultdict
|
||||
from oslo_log import log
|
||||
|
||||
from cinderclient import client
|
||||
|
@ -23,21 +24,53 @@ API_VERSION = '2'
|
|||
|
||||
class CinderClient(base.DriverBase):
|
||||
'''Cinder V2 driver.'''
|
||||
def __init__(self, region, session):
|
||||
|
||||
def __init__(self, region, disabled_quotas, session):
|
||||
try:
|
||||
self.cinder_client = client.Client(API_VERSION, session=session,
|
||||
region_name=region)
|
||||
self.cinder = client.Client(API_VERSION,
|
||||
session=session,
|
||||
region_name=region)
|
||||
self.no_volumes = True if 'volumes' in disabled_quotas else False
|
||||
except exceptions.ServiceUnavailable:
|
||||
raise
|
||||
|
||||
def get_resource_usages(self, project_id):
|
||||
'''Calcualte resources usage and return the dict'''
|
||||
return {}
|
||||
'''Calcualte resources usage and return the dict
|
||||
|
||||
def update_quota_limits(self, project_id, new_quota):
|
||||
:param: project_id
|
||||
:return: resource usage dict
|
||||
'''
|
||||
if not self.no_volumes:
|
||||
try:
|
||||
usages = defaultdict(dict)
|
||||
|
||||
opts = {'all_tenants': 1, 'project_id': project_id}
|
||||
|
||||
volumes = self.cinder.volumes.list(search_opts=opts)
|
||||
snapshots = self.cinder.volume_snapshots.list(search_opts=opts)
|
||||
backups = self.cinder.backups.list(search_opts=opts)
|
||||
|
||||
usages['gigabytes'] = sum([int(v.size) for v in volumes])
|
||||
usages['volumes'] = len(volumes)
|
||||
usages['snapshots'] = len(snapshots)
|
||||
usages['backups'] = len(backups)
|
||||
return usages
|
||||
|
||||
except exceptions.InternalError:
|
||||
raise
|
||||
|
||||
def update_quota_limits(self, project_id, **new_quota):
|
||||
'''Update the limits'''
|
||||
pass
|
||||
try:
|
||||
if not self.no_volumes:
|
||||
return self.cinder.quotas.update(project_id, **new_quota)
|
||||
except exceptions.InternalError:
|
||||
raise
|
||||
|
||||
def delete_quota_limits(self, project_id):
|
||||
'''Delete/Reset the limits'''
|
||||
pass
|
||||
try:
|
||||
if not self.no_volumes:
|
||||
return self.cinder.quotas.delete(project_id)
|
||||
except exceptions.InternalError:
|
||||
raise
|
||||
|
|
|
@ -58,13 +58,13 @@ class OpenStackDriver(object):
|
|||
else:
|
||||
# Create new objects and cache them
|
||||
LOG.info(_("Creating fresh OS Clients objects"))
|
||||
self.cinder_client = CinderClient(region_name,
|
||||
self.keystone_client.session)
|
||||
self.neutron_client = NeutronClient(region_name,
|
||||
self.keystone_client.session)
|
||||
self.disabled_quotas = self._get_disabled_quotas(region_name)
|
||||
self.nova_client = NovaClient(region_name, self.disabled_quotas,
|
||||
self.keystone_client.session)
|
||||
self.cinder_client = CinderClient(region_name,
|
||||
self.keystone_client.session)
|
||||
OpenStackDriver.os_clients_dict[
|
||||
region_name] = collections.defaultdict(dict)
|
||||
OpenStackDriver.os_clients_dict[region_name][
|
||||
|
@ -124,6 +124,9 @@ class OpenStackDriver(object):
|
|||
|
||||
def _get_disabled_quotas(self, region):
|
||||
disabled_quotas = []
|
||||
if not self.keystone_client.is_service_enabled('volume') or \
|
||||
self.keystone_client.is_service_enabled('volumev2'):
|
||||
disabled_quotas.extend(consts.CINDER_QUOTA_FIELDS)
|
||||
# Neutron
|
||||
if not self.keystone_client.is_service_enabled('network'):
|
||||
disabled_quotas.extend(consts.NEUTRON_QUOTA_FIELDS)
|
||||
|
|
|
@ -11,29 +11,87 @@
|
|||
# under the License.
|
||||
|
||||
import cinderclient
|
||||
import mock
|
||||
|
||||
from kingbird.drivers.openstack import cinder_v2
|
||||
from kingbird.tests import base
|
||||
from kingbird.tests import utils
|
||||
|
||||
|
||||
class Volume(object):
|
||||
def __init__(self, id, size):
|
||||
self.id = id
|
||||
self.size = size
|
||||
|
||||
|
||||
class VolumeSnapshot(object):
|
||||
def __init__(self, volume_id):
|
||||
self.volume_id = volume_id
|
||||
|
||||
|
||||
class VolumeBackup(object):
|
||||
def __init__(self, volume_id):
|
||||
self.volume_id = volume_id
|
||||
|
||||
|
||||
volumes = [Volume("9fc1c259-1d66-470f-8525-313696d1ad46", 20),
|
||||
Volume("7f505069-ad68-48c3-a09f-16d7014ec707", 15)]
|
||||
|
||||
snapshots = [VolumeSnapshot(volumes[0].id)]
|
||||
|
||||
backups = [VolumeBackup(volumes[0].id),
|
||||
VolumeBackup(volumes[0].id),
|
||||
VolumeBackup(volumes[1].id)]
|
||||
DISABLED_QUOTAS = ["floating_ips", "fixed_ips", "security_groups"]
|
||||
|
||||
|
||||
class TestCinderClient(base.KingbirdTestCase):
|
||||
def setUp(self):
|
||||
super(TestCinderClient, self).setUp()
|
||||
self.ctx = utils.dummy_context()
|
||||
self.session = 'fake_session'
|
||||
self.project = 'fake_project'
|
||||
|
||||
def test_init(self):
|
||||
ci_client = cinder_v2.CinderClient('fake_region', self.session)
|
||||
ci_client = cinder_v2.CinderClient('fake_region', DISABLED_QUOTAS,
|
||||
self.session)
|
||||
self.assertIsNotNone(ci_client)
|
||||
self.assertIsInstance(ci_client.cinder_client,
|
||||
self.assertIsInstance(ci_client.cinder,
|
||||
cinderclient.v2.client.Client)
|
||||
|
||||
def test_get_resource_usages(self):
|
||||
pass
|
||||
@mock.patch.object(cinder_v2, 'client')
|
||||
def test_get_resource_usages(self, mock_cinderclient):
|
||||
mock_cinderclient.Client().volumes.list.return_value = volumes
|
||||
mock_cinderclient.Client().volume_snapshots.list.return_value = \
|
||||
snapshots
|
||||
mock_cinderclient.Client().backups.list.return_value = \
|
||||
backups
|
||||
cinder = cinder_v2.CinderClient('fake_region', DISABLED_QUOTAS,
|
||||
self.session)
|
||||
total_cinder_usage = cinder.get_resource_usages(self.project)
|
||||
self.assertEqual(2, total_cinder_usage['volumes'])
|
||||
self.assertEqual(1, total_cinder_usage['snapshots'])
|
||||
self.assertEqual(35, total_cinder_usage['gigabytes'])
|
||||
self.assertEqual(3, total_cinder_usage['backups'])
|
||||
|
||||
def test_update_quota_limits(self):
|
||||
pass
|
||||
@mock.patch.object(cinder_v2, 'client')
|
||||
def test_update_quota_limits(self, mock_cinderclient):
|
||||
c_client = cinder_v2.CinderClient('fake_region', DISABLED_QUOTAS,
|
||||
self.session)
|
||||
new_quota = {'volumes': 4, 'snapshots': 3}
|
||||
c_client.update_quota_limits(self.project, **new_quota)
|
||||
|
||||
def test_delete_quota_limits(self):
|
||||
pass
|
||||
mock_cinderclient.Client().quotas.update.assert_called_once_with(
|
||||
self.project, **new_quota)
|
||||
|
||||
@mock.patch.object(cinder_v2, 'client')
|
||||
def test_delete_quota_limits(self, mock_cinderclient):
|
||||
c_client = cinder_v2.CinderClient('fake_region', DISABLED_QUOTAS,
|
||||
self.session)
|
||||
new_quota = {'volumes': 4, 'snapshots': 3}
|
||||
c_client.update_quota_limits(self.project, **new_quota)
|
||||
|
||||
c_client.delete_quota_limits(self.project)
|
||||
|
||||
mock_cinderclient.Client().quotas.delete.assert_called_once_with(
|
||||
self.project)
|
||||
|
|
Loading…
Reference in New Issue