diff --git a/kingbird/drivers/openstack/cinder_v2.py b/kingbird/drivers/openstack/cinder_v2.py index f2b8d7d..3b529ad 100644 --- a/kingbird/drivers/openstack/cinder_v2.py +++ b/kingbird/drivers/openstack/cinder_v2.py @@ -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 diff --git a/kingbird/drivers/openstack/sdk.py b/kingbird/drivers/openstack/sdk.py index 8b238b7..8770c39 100644 --- a/kingbird/drivers/openstack/sdk.py +++ b/kingbird/drivers/openstack/sdk.py @@ -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) diff --git a/kingbird/tests/unit/drivers/test_cinder_v2.py b/kingbird/tests/unit/drivers/test_cinder_v2.py index b150e3d..d04749c 100644 --- a/kingbird/tests/unit/drivers/test_cinder_v2.py +++ b/kingbird/tests/unit/drivers/test_cinder_v2.py @@ -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)