Merge "Fix and simplify arbitrary_string. lp#1085048"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 053c36e..ed3cf6c 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -193,7 +193,7 @@
tenant_name = admin
[volume]
-# This section contains the configuration options used when executng tests
+# This section contains the configuration options used when executing tests
# against the OpenStack Block Storage API service
# The type of endpoint for a Cinder or Block Storage API service.
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 52ed6bc..8311365 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -162,8 +162,8 @@
def post(self, url, body, headers):
return self.request('POST', url, headers, body)
- def get(self, url, headers=None):
- return self.request('GET', url, headers)
+ def get(self, url, headers=None, wait=None):
+ return self.request('GET', url, headers, wait=wait)
def delete(self, url, headers=None):
return self.request('DELETE', url, headers)
@@ -186,7 +186,8 @@
def _parse_resp(self, body):
return json.loads(body)
- def request(self, method, url, headers=None, body=None, depth=0):
+ def request(self, method, url,
+ headers=None, body=None, depth=0, wait=None):
"""A simple HTTP request interface."""
if (self.token is None) or (self.base_url is None):
@@ -205,7 +206,8 @@
raise exceptions.Unauthorized()
if resp.status == 404:
- self._log(req_url, body, resp, resp_body)
+ if not wait:
+ self._log(req_url, body, resp, resp_body)
raise exceptions.NotFound(resp_body)
if resp.status == 400:
diff --git a/tempest/common/utils/data_utils.py b/tempest/common/utils/data_utils.py
index 9d422e1..22e4742 100644
--- a/tempest/common/utils/data_utils.py
+++ b/tempest/common/utils/data_utils.py
@@ -60,9 +60,7 @@
def parse_image_id(image_ref):
"""Return the image id from a given image ref"""
- temp = image_ref.rsplit('/')
- #Return the last item, which is the image id
- return temp[len(temp) - 1]
+ return image_ref.rsplit('/')[-1]
def arbitrary_string(size=4, base_text=None):
diff --git a/tempest/manager.py b/tempest/manager.py
index fda887c..59743e5 100644
--- a/tempest/manager.py
+++ b/tempest/manager.py
@@ -41,6 +41,7 @@
from tempest.services.compute.json import keypairs_client
from tempest.services.compute.json import volumes_extensions_client
from tempest.services.compute.json import console_output_client
+from tempest.services.compute.json import quotas_client
NetworkClient = network_client.NetworkClient
ImagesClient = images_client.ImagesClientJSON
@@ -54,6 +55,7 @@
VolumesExtensionsClient = volumes_extensions_client.VolumesExtensionsClientJSON
VolumesClient = volumes_client.VolumesClientJSON
ConsoleOutputsClient = console_output_client.ConsoleOutputsClient
+QuotasClient = quotas_client.QuotasClient
LOG = logging.getLogger(__name__)
@@ -233,6 +235,7 @@
self.volumes_extensions_client = VolumesExtensionsClient(*client_args)
self.volumes_client = VolumesClient(*client_args)
self.console_outputs_client = ConsoleOutputsClient(*client_args)
+ self.quotas_client = QuotasClient(*client_args)
self.network_client = NetworkClient(*client_args)
diff --git a/tempest/openstack.py b/tempest/openstack.py
index dc73bd7..fbd2f00 100644
--- a/tempest/openstack.py
+++ b/tempest/openstack.py
@@ -59,7 +59,7 @@
from tempest.services.object_storage.object_client import ObjectClient
from tempest.services.boto.clients import APIClientEC2
from tempest.services.boto.clients import ObjectClientS3
-
+from tempest.services.compute.json.quotas_client import QuotasClient
LOG = logging.getLogger(__name__)
@@ -184,6 +184,7 @@
msg = "Unsupported interface type `%s'" % interface
raise exceptions.InvalidConfiguration(msg)
self.console_outputs_client = ConsoleOutputsClient(*client_args)
+ self.quotas_client = QuotasClient(*client_args)
self.network_client = NetworkClient(*client_args)
self.account_client = AccountClient(*client_args)
self.container_client = ContainerClient(*client_args)
diff --git a/tempest/services/compute/admin/__init__.py b/tempest/services/compute/admin/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/services/compute/admin/__init__.py
diff --git a/tempest/services/compute/admin/json/__init__.py b/tempest/services/compute/admin/json/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/services/compute/admin/json/__init__.py
diff --git a/tempest/services/compute/admin/json/quotas_client.py b/tempest/services/compute/admin/json/quotas_client.py
new file mode 100644
index 0000000..625d4d4
--- /dev/null
+++ b/tempest/services/compute/admin/json/quotas_client.py
@@ -0,0 +1,79 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2012 NTT Data
+# All Rights Reserved.
+#
+# 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 json
+
+from tempest.services.compute.json.quotas_client import QuotasClient
+
+
+class AdminQuotasClient(QuotasClient):
+
+ def __init__(self, config, username, password, auth_url, tenant_name=None):
+ super(AdminQuotasClient, self).__init__(config, username, password,
+ auth_url, tenant_name)
+
+ def update_quota_set(self, tenant_id, injected_file_content_bytes=None,
+ metadata_items=None, ram=None, floating_ips=None,
+ key_pairs=None, instances=None,
+ security_group_rules=None, injected_files=None,
+ cores=None, injected_file_path_bytes=None,
+ security_groups=None):
+ """
+ Updates the tenant's quota limits for one or more resources
+ """
+ post_body = {}
+
+ if injected_file_content_bytes >= 0:
+ post_body['injected_file_content_bytes'] = \
+ injected_file_content_bytes
+
+ if metadata_items >= 0:
+ post_body['metadata_items'] = metadata_items
+
+ if ram >= 0:
+ post_body['ram'] = ram
+
+ if floating_ips >= 0:
+ post_body['floating_ips'] = floating_ips
+
+ if key_pairs >= 0:
+ post_body['key_pairs'] = key_pairs
+
+ if instances >= 0:
+ post_body['instances'] = instances
+
+ if security_group_rules >= 0:
+ post_body['security_group_rules'] = security_group_rules
+
+ if injected_files >= 0:
+ post_body['injected_files'] = injected_files
+
+ if cores >= 0:
+ post_body['cores'] = cores
+
+ if injected_file_path_bytes >= 0:
+ post_body['injected_file_path_bytes'] = injected_file_path_bytes
+
+ if security_groups >= 0:
+ post_body['security_groups'] = security_groups
+
+ post_body = json.dumps({'quota_set': post_body})
+ resp, body = self.put('os-quota-sets/%s' % str(tenant_id), post_body,
+ self.headers)
+
+ body = json.loads(body)
+ return resp, body['quota_set']
diff --git a/tempest/services/compute/json/limits_client.py b/tempest/services/compute/json/limits_client.py
index f363bf7..945477a 100644
--- a/tempest/services/compute/json/limits_client.py
+++ b/tempest/services/compute/json/limits_client.py
@@ -26,19 +26,15 @@
auth_url, tenant_name)
self.service = self.config.compute.catalog_type
- def get_limits(self):
+ def get_absolute_limits(self):
resp, body = self.get("limits")
body = json.loads(body)
- return resp, body['limits']
+ return resp, body['limits']['absolute']
- def get_max_server_meta(self):
- resp, limits_dict = self.get_limits()
- return resp, limits_dict['absolute']['maxServerMeta']
-
- def get_personality_file_limit(self):
- resp, limits_dict = self.get_limits()
- return resp, limits_dict['absolute']['maxPersonality']
-
- def get_personality_size_limit(self):
- resp, limits_dict = self.get_limits()
- return resp, limits_dict['absolute']['maxPersonalitySize']
+ def get_specific_absolute_limit(self, absolute_limit):
+ resp, body = self.get("limits")
+ body = json.loads(body)
+ if absolute_limit not in body['limits']['absolute']:
+ return None
+ else:
+ return body['limits']['absolute'][absolute_limit]
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
new file mode 100644
index 0000000..2cc417f
--- /dev/null
+++ b/tempest/services/compute/json/quotas_client.py
@@ -0,0 +1,36 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2012 NTT Data
+# All Rights Reserved.
+#
+# 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 json
+
+from tempest.common.rest_client import RestClient
+
+
+class QuotasClient(RestClient):
+
+ def __init__(self, config, username, password, auth_url, tenant_name=None):
+ super(QuotasClient, self).__init__(config, username, password,
+ auth_url, tenant_name)
+ self.service = self.config.compute.catalog_type
+
+ def get_quota_set(self, tenant_id):
+ """List the quota set for a tenant"""
+
+ url = 'os-quota-sets/%s' % str(tenant_id)
+ resp, body = self.get(url)
+ body = json.loads(body)
+ return resp, body['quota_set']
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index 5ac1124..240bcfe 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -59,10 +59,10 @@
body = json.loads(body)
return resp, body['volumes']
- def get_volume(self, volume_id):
+ def get_volume(self, volume_id, wait=None):
"""Returns the details of a single volume"""
url = "os-volumes/%s" % str(volume_id)
- resp, body = self.get(url)
+ resp, body = self.get(url, wait=wait)
body = json.loads(body)
return resp, body['volume']
@@ -111,7 +111,7 @@
def is_resource_deleted(self, id):
try:
- self.get_volume(id)
+ self.get_volume(id, wait=True)
except exceptions.NotFound:
return True
return False
diff --git a/tempest/services/compute/xml/limits_client.py b/tempest/services/compute/xml/limits_client.py
index 75142a9..229dbee 100644
--- a/tempest/services/compute/xml/limits_client.py
+++ b/tempest/services/compute/xml/limits_client.py
@@ -29,7 +29,7 @@
auth_url, tenant_name)
self.service = self.config.compute.catalog_type
- def get_limits(self):
+ def get_absolute_limits(self):
resp, body = self.get("limits", self.headers)
body = objectify.fromstring(body)
lim = NS + 'absolute'
@@ -37,23 +37,19 @@
for el in body[lim].iterchildren():
attributes = el.attrib
- if attributes['name'] == 'maxServerMeta':
- ret['maxServerMeta'] = int(attributes['value'])
- elif attributes['name'] == 'maxPersonality':
- ret['maxPersonality'] = int(attributes['value'])
- elif attributes['name'] == 'maxPersonalitySize':
- ret['maxPersonalitySize'] = int(attributes['value'])
-
+ ret[attributes['name']] = attributes['value']
return resp, ret
- def get_max_server_meta(self):
- resp, limits_dict = self.get_limits()
- return resp, limits_dict['maxServerMeta']
+ def get_specific_absolute_limit(self, absolute_limit):
+ resp, body = self.get("limits", self.headers)
+ body = objectify.fromstring(body)
+ lim = NS + 'absolute'
+ ret = {}
- def get_personality_file_limit(self):
- resp, limits_dict = self.get_limits()
- return resp, limits_dict['maxPersonality']
-
- def get_personality_size_limit(self):
- resp, limits_dict = self.get_limits()
- return resp, limits_dict['maxPersonalitySize']
+ for el in body[lim].iterchildren():
+ attributes = el.attrib
+ ret[attributes['name']] = attributes['value']
+ if absolute_limit not in ret:
+ return None
+ else:
+ return ret[absolute_limit]
diff --git a/tempest/services/compute/xml/volumes_extensions_client.py b/tempest/services/compute/xml/volumes_extensions_client.py
index 6869360..0fbc070 100644
--- a/tempest/services/compute/xml/volumes_extensions_client.py
+++ b/tempest/services/compute/xml/volumes_extensions_client.py
@@ -79,10 +79,10 @@
volumes += [self._parse_volume(vol) for vol in list(body)]
return resp, volumes
- def get_volume(self, volume_id):
+ def get_volume(self, volume_id, wait=None):
"""Returns the details of a single volume"""
url = "os-volumes/%s" % str(volume_id)
- resp, body = self.get(url, self.headers)
+ resp, body = self.get(url, self.headers, wait=wait)
body = etree.fromstring(body)
return resp, self._parse_volume(body)
@@ -139,7 +139,7 @@
def is_resource_deleted(self, id):
try:
- self.get_volume(id)
+ self.get_volume(id, wait=True)
except exceptions.NotFound:
return True
return False
diff --git a/tempest/services/volume/json/volumes_client.py b/tempest/services/volume/json/volumes_client.py
index 6f04e5e..28dae4e 100644
--- a/tempest/services/volume/json/volumes_client.py
+++ b/tempest/services/volume/json/volumes_client.py
@@ -62,10 +62,10 @@
body = json.loads(body)
return resp, body['volumes']
- def get_volume(self, volume_id):
+ def get_volume(self, volume_id, wait=None):
"""Returns the details of a single volume"""
url = "volumes/%s" % str(volume_id)
- resp, body = self.get(url)
+ resp, body = self.get(url, wait=wait)
body = json.loads(body)
return resp, body['volume']
@@ -133,7 +133,7 @@
def is_resource_deleted(self, id):
try:
- self.get_volume(id)
+ self.get_volume(id, wait=True)
except exceptions.NotFound:
return True
return False
diff --git a/tempest/services/volume/xml/volumes_client.py b/tempest/services/volume/xml/volumes_client.py
index ef5f3e9..9d2f159 100644
--- a/tempest/services/volume/xml/volumes_client.py
+++ b/tempest/services/volume/xml/volumes_client.py
@@ -82,10 +82,10 @@
volumes += [self._parse_volume(vol) for vol in list(body)]
return resp, volumes
- def get_volume(self, volume_id):
+ def get_volume(self, volume_id, wait=None):
"""Returns the details of a single volume"""
url = "volumes/%s" % str(volume_id)
- resp, body = self.get(url, self.headers)
+ resp, body = self.get(url, self.headers, wait=wait)
body = etree.fromstring(body)
return resp, self._parse_volume(body)
@@ -140,7 +140,7 @@
def is_resource_deleted(self, id):
try:
- self.get_volume(id)
+ self.get_volume(id, wait=True)
except exceptions.NotFound:
return True
return False
diff --git a/tempest/tests/boto/__init__.py b/tempest/tests/boto/__init__.py
index 3d5ea6c..11fa077 100644
--- a/tempest/tests/boto/__init__.py
+++ b/tempest/tests/boto/__init__.py
@@ -73,7 +73,6 @@
EC2_CAN_CONNECT_ERROR = "AWS credentials not set," +\
" faild to get them even by keystoneclient"
except Exception as exc:
- logging.exception(exc)
EC2_CAN_CONNECT_ERROR = str(exc)
else:
EC2_CAN_CONNECT_ERROR = None
@@ -88,7 +87,6 @@
if exc.status == 403:
_cred_sub_check(s3client.connection_data)
except Exception as exc:
- logging.exception(exc)
S3_CAN_CONNECT_ERROR = str(exc)
except keystoneclient.exceptions.Unauthorized:
S3_CAN_CONNECT_ERROR = "AWS credentials not set," +\
diff --git a/tempest/tests/boto/test_ec2_security_groups.py b/tempest/tests/boto/test_ec2_security_groups.py
index 4e978e1..3d50e8b 100644
--- a/tempest/tests/boto/test_ec2_security_groups.py
+++ b/tempest/tests/boto/test_ec2_security_groups.py
@@ -39,8 +39,8 @@
group = self.client.create_security_group(group_name,
group_description)
self.addResourceCleanUp(self.client.delete_security_group, group_name)
- groups_get = self.client.get_all_security_groups(groupnames=
- (group_name,))
+ groups_get = self.client.get_all_security_groups(
+ groupnames=(group_name,))
self.assertEqual(len(groups_get), 1)
group_get = groups_get[0]
self.assertEqual(group.name, group_get.name)
@@ -61,8 +61,8 @@
to_port=22)
self.assertTrue(success)
#TODO(afazekas): Duplicate tests
- group_get = self.client.get_all_security_groups(groupnames=
- (group_name,))[0]
+ group_get = self.client.get_all_security_groups(
+ groupnames=(group_name,))[0]
#remove listed rules
for ip_permission in group_get.rules:
for cidr in ip_permission.grants:
@@ -72,7 +72,7 @@
from_port=ip_permission.from_port,
to_port=ip_permission.to_port))
- group_get = self.client.get_all_security_groups(groupnames=
- (group_name,))[0]
+ group_get = self.client.get_all_security_groups(
+ groupnames=(group_name,))[0]
#all rules shuld be removed now
self.assertEqual(0, len(group_get.rules))
diff --git a/tempest/tests/compute/admin/test_quotas.py b/tempest/tests/compute/admin/test_quotas.py
new file mode 100644
index 0000000..98ca169
--- /dev/null
+++ b/tempest/tests/compute/admin/test_quotas.py
@@ -0,0 +1,156 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack, LLC
+# All Rights Reserved.
+#
+# 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 nose.plugins.attrib import attr
+
+from tempest.tests.compute.base import BaseComputeTest
+from tempest.services.compute.admin.json import quotas_client as adm_quotas
+from tempest import exceptions
+
+
+class QuotasTest(BaseComputeTest):
+
+ @classmethod
+ def setUpClass(cls):
+ super(QuotasTest, cls).setUpClass()
+ adm_user = cls.config.compute_admin.username
+ adm_pass = cls.config.compute_admin.password
+ adm_tenant = cls.config.compute_admin.tenant_name
+ auth_url = cls.config.identity.auth_url
+
+ cls.adm_client = adm_quotas.AdminQuotasClient(cls.config, adm_user,
+ adm_pass, auth_url,
+ adm_tenant)
+ cls.client = cls.os.quotas_client
+ cls.identity_admin_client = cls._get_identity_admin_client()
+ resp, tenants = cls.identity_admin_client.list_tenants()
+
+ if cls.config.compute.allow_tenant_isolation:
+ cls.demo_tenant_id = cls.isolated_creds[0][0]['tenantId']
+ else:
+ cls.demo_tenant_id = [tnt['id'] for tnt in tenants if tnt['name']
+ == cls.config.compute.tenant_name][0]
+
+ cls.adm_tenant_id = [tnt['id'] for tnt in tenants if tnt['name'] ==
+ cls.config.compute_admin.tenant_name][0]
+
+ cls.default_quota_set = {'injected_file_content_bytes': 10240,
+ 'metadata_items': 128, 'injected_files': 5,
+ 'ram': 51200, 'floating_ips': 10,
+ 'key_pairs': 100,
+ 'injected_file_path_bytes': 255,
+ 'instances': 10, 'security_group_rules': 20,
+ 'cores': 20, 'security_groups': 10}
+
+ @classmethod
+ def tearDown(cls):
+ for server in cls.servers:
+ try:
+ cls.servers_client.delete_server(server['id'])
+ except exceptions.NotFound:
+ continue
+
+ @attr(type='smoke')
+ def test_get_default_quotas(self):
+ """Admin can get the default resource quota set for a tenant"""
+ expected_quota_set = self.default_quota_set.copy()
+ expected_quota_set['id'] = self.demo_tenant_id
+ try:
+ resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+ self.assertEqual(200, resp.status)
+ self.assertSequenceEqual(expected_quota_set, quota_set)
+ except:
+ self.fail("Admin could not get the default quota set for a tenant")
+
+ def test_update_all_quota_resources_for_tenant(self):
+ """Admin can update all the resource quota limits for a tenant"""
+ new_quota_set = {'injected_file_content_bytes': 20480,
+ 'metadata_items': 256, 'injected_files': 10,
+ 'ram': 10240, 'floating_ips': 20, 'key_pairs': 200,
+ 'injected_file_path_bytes': 512, 'instances': 20,
+ 'security_group_rules': 20, 'cores': 2,
+ 'security_groups': 20}
+ try:
+ # Update limits for all quota resources
+ resp, quota_set = self.adm_client.update_quota_set(
+ self.demo_tenant_id,
+ **new_quota_set)
+ self.assertEqual(200, resp.status)
+ self.assertSequenceEqual(new_quota_set, quota_set)
+ except:
+ self.fail("Admin could not update quota set for the tenant")
+ finally:
+ # Reset quota resource limits to default values
+ resp, quota_set = self.adm_client.update_quota_set(
+ self.demo_tenant_id,
+ **self.default_quota_set)
+ self.assertEqual(200, resp.status, "Failed to reset quota "
+ "defaults")
+
+ def test_get_updated_quotas(self):
+ """Verify that GET shows the updated quota set"""
+ self.adm_client.update_quota_set(self.demo_tenant_id,
+ ram='5120')
+ try:
+ resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+ self.assertEqual(200, resp.status)
+ self.assertEqual(quota_set['ram'], 5120)
+ except:
+ self.fail("Could not get the update quota limit for resource")
+ finally:
+ # Reset quota resource limits to default values
+ resp, quota_set = self.adm_client.update_quota_set(
+ self.demo_tenant_id,
+ **self.default_quota_set)
+ self.assertEqual(200, resp.status, "Failed to reset quota "
+ "defaults")
+
+ def test_create_server_when_cpu_quota_is_full(self):
+ """Disallow server creation when tenant's vcpu quota is full"""
+ resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+ default_vcpu_quota = quota_set['cores']
+ vcpu_quota = 0 # Set the quota to zero to conserve resources
+
+ resp, quota_set = self.adm_client.update_quota_set(self.demo_tenant_id,
+ cores=vcpu_quota)
+ try:
+ self.create_server()
+ except exceptions.OverLimit:
+ pass
+ else:
+ self.fail("Could create servers over the VCPU quota limit")
+ finally:
+ self.adm_client.update_quota_set(self.demo_tenant_id,
+ cores=default_vcpu_quota)
+
+ def test_create_server_when_memory_quota_is_full(self):
+ """Disallow server creation when tenant's memory quota is full"""
+ resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+ default_mem_quota = quota_set['ram']
+ mem_quota = 0 # Set the quota to zero to conserve resources
+
+ self.adm_client.update_quota_set(self.demo_tenant_id,
+ ram=mem_quota)
+ try:
+ self.create_server()
+ except exceptions.OverLimit:
+ pass
+ else:
+ self.fail("Could create servers over the memory quota limit")
+ finally:
+ self.adm_client.update_quota_set(self.demo_tenant_id,
+ ram=default_mem_quota)
diff --git a/tempest/tests/compute/base.py b/tempest/tests/compute/base.py
index ebf3b54..bb2ff8b 100644
--- a/tempest/tests/compute/base.py
+++ b/tempest/tests/compute/base.py
@@ -17,14 +17,13 @@
import logging
import time
-import nose
import unittest2 as unittest
import nose
from tempest import config
-from tempest import openstack
from tempest import exceptions
+from tempest import openstack
from tempest.common.utils.data_utils import rand_name
__all__ = ['BaseComputeTest', 'BaseComputeTestJSON', 'BaseComputeTestXML',
@@ -61,6 +60,7 @@
cls.keypairs_client = os.keypairs_client
cls.security_groups_client = os.security_groups_client
cls.console_outputs_client = os.console_outputs_client
+ cls.quotas_client = os.quotas_client
cls.limits_client = os.limits_client
cls.volumes_extensions_client = os.volumes_extensions_client
cls.volumes_client = os.volumes_client
@@ -178,10 +178,12 @@
cls.clear_isolated_creds()
@classmethod
- def create_server(cls, image_id=None):
+ def create_server(cls, image_id=None, flavor=None):
"""Wrapper utility that returns a test server"""
server_name = rand_name(cls.__name__ + "-instance")
- flavor = cls.flavor_ref
+
+ if not flavor:
+ flavor = cls.flavor_ref
if not image_id:
image_id = cls.image_ref
diff --git a/tempest/tests/compute/limits/__init__.py b/tempest/tests/compute/limits/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/tests/compute/limits/__init__.py
diff --git a/tempest/tests/compute/limits/test_absolute_limits.py b/tempest/tests/compute/limits/test_absolute_limits.py
new file mode 100644
index 0000000..ede0dc2
--- /dev/null
+++ b/tempest/tests/compute/limits/test_absolute_limits.py
@@ -0,0 +1,68 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack, LLC
+# All Rights Reserved.
+#
+# 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 unittest2 as unittest
+
+from tempest.tests.compute import base
+
+
+class AbsoluteLimitsTest(object):
+
+ @staticmethod
+ def setUpClass(cls):
+ cls.client = cls.limits_client
+
+ @unittest.skip("Skipped until the Bug #1025294 is resolved")
+ def test_absLimits_get(self):
+ """
+ To check if all limits are present in the response
+ """
+ resp, absolute_limits = self.client.get_absolute_limits()
+ expected_elements = ['maxImageMeta', 'maxPersonality',
+ 'maxPersonalitySize',
+ 'maxPersonalityFilePathSize',
+ 'maxServerMeta', 'maxTotalCores',
+ 'maxTotalFloatingIps', 'maxSecurityGroups',
+ 'maxSecurityGroupRules', 'maxTotalInstances',
+ 'maxTotalKeypairs', 'maxTotalRAMSize',
+ 'maxTotalVolumeGigabytes', 'maxTotalVolumes',
+ 'totalCoresUsed', 'totalFloatingIpsUsed',
+ 'totalSecurityGroupsUsed', 'totalInstancesUsed',
+ 'totalKeyPairsUsed', 'totalRAMUsed',
+ 'totalVolumeGigabytesUsed', 'totalVolumesUsed']
+ # check whether all expected elements exist
+ missing_elements =\
+ [ele for ele in expected_elements if ele not in absolute_limits]
+ self.assertEqual(0, len(missing_elements),
+ "Failed to find element %s in absolute limits list"
+ % ', '.join(ele for ele in missing_elements))
+
+
+class AbsoluteLimitsTestJSON(base.BaseComputeTestJSON,
+ AbsoluteLimitsTest):
+ @classmethod
+ def setUpClass(cls):
+ super(AbsoluteLimitsTestJSON, cls).setUpClass()
+ AbsoluteLimitsTest.setUpClass(cls)
+
+
+class AbsoluteLimitsTestXML(base.BaseComputeTestXML,
+ AbsoluteLimitsTest):
+ @classmethod
+ def setUpClass(cls):
+ super(AbsoluteLimitsTestXML, cls).setUpClass()
+ AbsoluteLimitsTest.setUpClass(cls)
diff --git a/tempest/tests/compute/servers/test_server_personality.py b/tempest/tests/compute/servers/test_server_personality.py
index a570aec..75457d1 100644
--- a/tempest/tests/compute/servers/test_server_personality.py
+++ b/tempest/tests/compute/servers/test_server_personality.py
@@ -34,8 +34,9 @@
name = rand_name('server')
file_contents = 'This is a test file.'
personality = []
- _, max_file_limit = self.user_client.get_personality_file_limit()
- for i in range(0, max_file_limit + 1):
+ max_file_limit = \
+ self.user_client.get_specific_absolute_limit("maxPersonality")
+ for i in range(0, int(max_file_limit) + 1):
path = 'etc/test' + str(i) + '.txt'
personality.append({'path': path,
'contents': base64.b64encode(file_contents)})
@@ -57,18 +58,16 @@
name = rand_name('server')
file_contents = 'This is a test file.'
- cli_resp = self.user_client.get_personality_file_limit()
- resp, max_file_limit = cli_resp
- self.assertEqual(200, resp.status)
+ max_file_limit = \
+ self.user_client.get_specific_absolute_limit("maxPersonality")
personality = []
- for i in range(0, max_file_limit):
+ for i in range(0, int(max_file_limit)):
path = 'etc/test' + str(i) + '.txt'
personality.append({
'path': path,
'contents': base64.b64encode(file_contents),
})
-
resp, server = self.client.create_server(name, self.image_ref,
self.flavor_ref,
personality=personality)
diff --git a/tempest/tests/compute/test_quotas.py b/tempest/tests/compute/test_quotas.py
new file mode 100644
index 0000000..d07064f
--- /dev/null
+++ b/tempest/tests/compute/test_quotas.py
@@ -0,0 +1,49 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack, LLC
+# All Rights Reserved.
+#
+# 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 nose.plugins.attrib import attr
+
+from tempest.tests.compute.base import BaseComputeTest
+
+
+class QuotasTest(BaseComputeTest):
+
+ @classmethod
+ def setUpClass(cls):
+ super(QuotasTest, cls).setUpClass()
+ cls.client = cls.quotas_client
+ cls.admin_client = cls._get_identity_admin_client()
+ resp, tenants = cls.admin_client.list_tenants()
+ cls.tenant_id = [tnt['id'] for tnt in tenants if tnt['name'] ==
+ cls.client.tenant_name][0]
+
+ @attr(type='smoke')
+ def test_get_default_quotas(self):
+ """User can get the default quota set for it's tenant"""
+ expected_quota_set = {'injected_file_content_bytes': 10240,
+ 'metadata_items': 128, 'injected_files': 5,
+ 'ram': 51200, 'floating_ips': 10,
+ 'key_pairs': 100,
+ 'injected_file_path_bytes': 255, 'instances': 10,
+ 'security_group_rules': 20, 'cores': 20,
+ 'id': self.tenant_id, 'security_groups': 10}
+ try:
+ resp, quota_set = self.client.get_quota_set(self.tenant_id)
+ self.assertEqual(200, resp.status)
+ self.assertSequenceEqual(expected_quota_set, quota_set)
+ except:
+ self.fail("Quota set for tenant did not have default limits")
diff --git a/tempest/tests/compute/volumes/test_volumes_get.py b/tempest/tests/compute/volumes/test_volumes_get.py
index e80e5b9..0a207b9 100644
--- a/tempest/tests/compute/volumes/test_volumes_get.py
+++ b/tempest/tests/compute/volumes/test_volumes_get.py
@@ -26,6 +26,7 @@
@attr(type='smoke')
def test_volume_create_get_delete(self):
"""CREATE, GET, DELETE Volume"""
+ volume = None
try:
v_name = rand_name('Volume-%s-') % self._interface
metadata = {'Type': 'work'}
@@ -61,11 +62,12 @@
'from the created Volume')
finally:
- #Delete the Volume created in this method
- resp, _ = self.client.delete_volume(volume['id'])
- self.assertEqual(202, resp.status)
- #Checking if the deleted Volume still exists
- self.client.wait_for_resource_deletion(volume['id'])
+ if volume:
+ #Delete the Volume created in this method
+ resp, _ = self.client.delete_volume(volume['id'])
+ self.assertEqual(202, resp.status)
+ #Checking if the deleted Volume still exists
+ self.client.wait_for_resource_deletion(volume['id'])
@attr(type='positive')
def test_volume_get_metadata_none(self):