Add Cinder tests for quota sets

This commit adds client for the Cinder quota API and adds
tests to list and update the quotas.

Change-Id: Ic53dbf6e6ef26c4275039091fc4db6a63f796dba
Closes-Bug: #1252774
This commit is contained in:
Sylvain Baubeau 2014-02-20 18:40:10 +01:00
parent 3db3f0742e
commit fdd3459694
5 changed files with 257 additions and 0 deletions

View File

@ -0,0 +1,99 @@
# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
#
# Author: Sylvain Baubeau <sylvain.baubeau@enovance.com>
#
# 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.
from tempest.api.volume import base
from tempest import test
QUOTA_KEYS = ['gigabytes', 'snapshots', 'volumes']
QUOTA_USAGE_KEYS = ['reserved', 'limit', 'in_use']
class VolumeQuotasAdminTestJSON(base.BaseVolumeV1AdminTest):
_interface = "json"
@classmethod
def setUpClass(cls):
super(VolumeQuotasAdminTestJSON, cls).setUpClass()
cls.admin_volume_client = cls.os_adm.volumes_client
cls.demo_tenant_id = cls.isolated_creds.get_primary_user().get(
'tenantId')
@test.attr(type='gate')
def test_list_quotas(self):
resp, quotas = self.quotas_client.get_quota_set(self.demo_tenant_id)
self.assertEqual(200, resp.status)
for key in QUOTA_KEYS:
self.assertIn(key, quotas)
@test.attr(type='gate')
def test_list_default_quotas(self):
resp, quotas = self.quotas_client.get_default_quota_set(
self.demo_tenant_id)
self.assertEqual(200, resp.status)
for key in QUOTA_KEYS:
self.assertIn(key, quotas)
@test.attr(type='gate')
def test_update_all_quota_resources_for_tenant(self):
# Admin can update all the resource quota limits for a tenant
resp, default_quota_set = self.quotas_client.get_default_quota_set(
self.demo_tenant_id)
new_quota_set = {'gigabytes': 1009,
'volumes': 11,
'snapshots': 11}
# Update limits for all quota resources
resp, quota_set = self.quotas_client.update_quota_set(
self.demo_tenant_id,
**new_quota_set)
default_quota_set.pop('id')
self.addCleanup(self.quotas_client.update_quota_set,
self.demo_tenant_id, **default_quota_set)
self.assertEqual(200, resp.status)
self.assertEqual(new_quota_set, quota_set)
@test.attr(type='gate')
def test_show_quota_usage(self):
resp, quota_usage = self.quotas_client.get_quota_usage(self.adm_tenant)
self.assertEqual(200, resp.status)
for key in QUOTA_KEYS:
self.assertIn(key, quota_usage)
for usage_key in QUOTA_USAGE_KEYS:
self.assertIn(usage_key, quota_usage[key])
@test.attr(type='gate')
def test_quota_usage(self):
resp, quota_usage = self.quotas_client.get_quota_usage(
self.demo_tenant_id)
volume = self.create_volume(size=1)
self.addCleanup(self.admin_volume_client.delete_volume,
volume['id'])
resp, new_quota_usage = self.quotas_client.get_quota_usage(
self.demo_tenant_id)
self.assertEqual(200, resp.status)
self.assertEqual(quota_usage['volumes']['in_use'] + 1,
new_quota_usage['volumes']['in_use'])
self.assertEqual(quota_usage['gigabytes']['in_use'] + 1,
new_quota_usage['gigabytes']['in_use'])
class VolumeQuotasAdminTestXML(VolumeQuotasAdminTestJSON):
_interface = "xml"

View File

@ -145,6 +145,7 @@ class BaseVolumeV1AdminTest(BaseVolumeV1Test):
cls.os_adm = clients.AdminManager(interface=cls._interface)
cls.client = cls.os_adm.volume_types_client
cls.hosts_client = cls.os_adm.volume_hosts_client
cls.quotas_client = cls.os_adm.volume_quotas_client
class BaseVolumeV2Test(BaseVolumeTest):

View File

@ -156,6 +156,8 @@ from tempest.services.telemetry.xml.telemetry_client import \
TelemetryClientXML
from tempest.services.volume.json.admin.volume_hosts_client import \
VolumeHostsClientJSON
from tempest.services.volume.json.admin.volume_quotas_client import \
VolumeQuotasClientJSON
from tempest.services.volume.json.admin.volume_types_client import \
VolumeTypesClientJSON
from tempest.services.volume.json.backups_client import BackupsClientJSON
@ -167,6 +169,8 @@ from tempest.services.volume.v2.json.volumes_client import VolumesV2ClientJSON
from tempest.services.volume.v2.xml.volumes_client import VolumesV2ClientXML
from tempest.services.volume.xml.admin.volume_hosts_client import \
VolumeHostsClientXML
from tempest.services.volume.xml.admin.volume_quotas_client import \
VolumeQuotasClientXML
from tempest.services.volume.xml.admin.volume_types_client import \
VolumeTypesClientXML
from tempest.services.volume.xml.backups_client import BackupsClientXML
@ -247,6 +251,8 @@ class Manager(manager.Manager):
InstanceUsagesAuditLogClientXML(self.auth_provider)
self.volume_hosts_client = VolumeHostsClientXML(
self.auth_provider)
self.volume_quotas_client = VolumeQuotasClientXML(
self.auth_provider)
self.volumes_extension_client = VolumeExtensionClientXML(
self.auth_provider)
if CONF.service_available.ceilometer:
@ -327,6 +333,8 @@ class Manager(manager.Manager):
InstanceUsagesAuditLogClientJSON(self.auth_provider)
self.volume_hosts_client = VolumeHostsClientJSON(
self.auth_provider)
self.volume_quotas_client = VolumeQuotasClientJSON(
self.auth_provider)
self.volumes_extension_client = VolumeExtensionClientJSON(
self.auth_provider)
self.hosts_v3_client = HostsV3ClientJSON(self.auth_provider)

View File

@ -0,0 +1,79 @@
# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
#
# Author: Sylvain Baubeau <sylvain.baubeau@enovance.com>
#
# 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 urllib
from tempest.openstack.common import jsonutils
from tempest.common import rest_client
from tempest import config
CONF = config.CONF
class VolumeQuotasClientJSON(rest_client.RestClient):
"""
Client class to send CRUD Volume Quotas API requests to a Cinder endpoint
"""
TYPE = "json"
def __init__(self, auth_provider):
super(VolumeQuotasClientJSON, self).__init__(auth_provider)
self.service = CONF.volume.catalog_type
self.build_interval = CONF.volume.build_interval
self.build_timeout = CONF.volume.build_timeout
def get_default_quota_set(self, tenant_id):
"""List the default volume quota set for a tenant."""
url = 'os-quota-sets/%s/defaults' % tenant_id
resp, body = self.get(url)
return resp, self._parse_resp(body)
def get_quota_set(self, tenant_id, params=None):
"""List the quota set for a tenant."""
url = 'os-quota-sets/%s' % tenant_id
if params:
url += '?%s' % urllib.urlencode(params)
resp, body = self.get(url)
return resp, self._parse_resp(body)
def get_quota_usage(self, tenant_id):
"""List the quota set for a tenant."""
resp, body = self.get_quota_set(tenant_id, params={'usage': True})
return resp, body
def update_quota_set(self, tenant_id, gigabytes=None, volumes=None,
snapshots=None):
post_body = {}
if gigabytes is not None:
post_body['gigabytes'] = gigabytes
if volumes is not None:
post_body['volumes'] = volumes
if snapshots is not None:
post_body['snapshots'] = snapshots
post_body = jsonutils.dumps({'quota_set': post_body})
resp, body = self.put('os-quota-sets/%s' % tenant_id, post_body)
return resp, self._parse_resp(body)

View File

@ -0,0 +1,70 @@
# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
#
# Author: Sylvain Baubeau <sylvain.baubeau@enovance.com>
#
# 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.
from ast import literal_eval
from lxml import etree
from tempest import config
from tempest.services.compute.xml import common as xml
from tempest.services.volume.json.admin import volume_quotas_client
CONF = config.CONF
class VolumeQuotasClientXML(volume_quotas_client.VolumeQuotasClientJSON):
"""
Client class to send CRUD Volume Quotas API requests to a Cinder endpoint
"""
TYPE = "xml"
def _format_quota(self, q):
quota = {}
for k, v in q.items():
try:
v = literal_eval(v)
except (ValueError, SyntaxError):
pass
quota[k] = v
return quota
def get_quota_usage(self, tenant_id):
"""List the quota set for a tenant."""
resp, body = self.get_quota_set(tenant_id, params={'usage': True})
return resp, self._format_quota(body)
def update_quota_set(self, tenant_id, gigabytes=None, volumes=None,
snapshots=None):
post_body = {}
element = xml.Element("quota_set")
if gigabytes is not None:
post_body['gigabytes'] = gigabytes
if volumes is not None:
post_body['volumes'] = volumes
if snapshots is not None:
post_body['snapshots'] = snapshots
xml.deep_dict_to_xml(element, post_body)
resp, body = self.put('os-quota-sets/%s' % tenant_id,
str(xml.Document(element)))
body = xml.xml_to_json(etree.fromstring(body))
return resp, self._format_quota(body)