Merge "Add Cinder tests for quota sets"
This commit is contained in:
commit
9f7e7e0596
99
tempest/api/volume/admin/test_volume_quotas.py
Normal file
99
tempest/api/volume/admin/test_volume_quotas.py
Normal 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"
|
@ -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):
|
||||
|
@ -158,6 +158,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
|
||||
@ -169,6 +171,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
|
||||
@ -249,6 +253,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:
|
||||
@ -329,6 +335,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)
|
||||
|
79
tempest/services/volume/json/admin/volume_quotas_client.py
Normal file
79
tempest/services/volume/json/admin/volume_quotas_client.py
Normal 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)
|
70
tempest/services/volume/xml/admin/volume_quotas_client.py
Normal file
70
tempest/services/volume/xml/admin/volume_quotas_client.py
Normal 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)
|
Loading…
Reference in New Issue
Block a user