Merge "Assert quota related API behavior when noop"

This commit is contained in:
Zuul 2022-02-25 09:46:27 +00:00 committed by Gerrit Code Review
commit 22a47b4662
6 changed files with 414 additions and 4 deletions

View File

@ -181,6 +181,8 @@ Possible values:
'on-demand.'),
('nova.quota.NoopQuotaDriver', 'Ignores quota and treats all '
'resources as unlimited.'),
('nova.quota.UnifiedLimitsDriver', 'Do not use. Still being '
'developed.')
],
help="""
Provides abstraction for quota checks. Users can configure a specific

View File

@ -882,13 +882,23 @@ class QuotaEngine(object):
}
# NOTE(mriedem): quota_driver is ever only supplied in tests with a
# fake driver.
self.__driver = quota_driver
self.__driver_override = quota_driver
self.__driver = None
self.__driver_name = None
@property
def _driver(self):
if self.__driver:
return self.__driver
self.__driver = importutils.import_object(CONF.quota.driver)
if self.__driver_override:
return self.__driver_override
# NOTE(johngarbutt) to allow unit tests to change the driver by
# simply overriding config, double check if we have the correct
# driver cached before we return the currently cached driver
driver_name_in_config = CONF.quota.driver
if self.__driver_name != driver_name_in_config:
self.__driver = importutils.import_object(driver_name_in_config)
self.__driver_name = driver_name_in_config
return self.__driver
def get_defaults(self, context):

View File

@ -477,3 +477,75 @@ class LimitsControllerTestV275(BaseLimitTestSuite):
self.assertRaises(
exception.ValidationError,
self.controller.index, req=req)
class NoopLimitsControllerTest(test.NoDBTestCase):
quota_driver = "nova.quota.NoopQuotaDriver"
def setUp(self):
super(NoopLimitsControllerTest, self).setUp()
self.flags(driver=self.quota_driver, group="quota")
self.controller = limits_v21.LimitsController()
# remove policy checks
patcher = self.mock_can = mock.patch('nova.context.RequestContext.can')
self.mock_can = patcher.start()
self.addCleanup(patcher.stop)
def test_index_v21(self):
req = fakes.HTTPRequest.blank("/")
response = self.controller.index(req)
expected_response = {
"limits": {
"rate": [],
"absolute": {
'maxImageMeta': -1,
'maxPersonality': -1,
'maxPersonalitySize': -1,
'maxSecurityGroupRules': -1,
'maxSecurityGroups': -1,
'maxServerGroupMembers': -1,
'maxServerGroups': -1,
'maxServerMeta': -1,
'maxTotalCores': -1,
'maxTotalFloatingIps': -1,
'maxTotalInstances': -1,
'maxTotalKeypairs': -1,
'maxTotalRAMSize': -1,
'totalCoresUsed': -1,
'totalFloatingIpsUsed': -1,
'totalInstancesUsed': -1,
'totalRAMUsed': -1,
'totalSecurityGroupsUsed': -1,
'totalServerGroupsUsed': -1,
},
},
}
self.assertEqual(expected_response, response)
def test_index_v275(self):
req = fakes.HTTPRequest.blank("/?tenant_id=faketenant",
version='2.75')
response = self.controller.index(req)
expected_response = {
"limits": {
"rate": [],
"absolute": {
'maxServerGroupMembers': -1,
'maxServerGroups': -1,
'maxServerMeta': -1,
'maxTotalCores': -1,
'maxTotalInstances': -1,
'maxTotalKeypairs': -1,
'maxTotalRAMSize': -1,
'totalCoresUsed': -1,
'totalInstancesUsed': -1,
'totalRAMUsed': -1,
'totalServerGroupsUsed': -1,
},
},
}
self.assertEqual(expected_response, response)
class UnifiedLimitsControllerTest(NoopLimitsControllerTest):
quota_driver = "nova.quota.UnifiedLimitsDriver"

View File

@ -13,11 +13,13 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import mock
import webob
from nova.api.openstack.compute import quota_classes \
as quota_classes_v21
from nova import exception
from nova import objects
from nova import test
from nova.tests.unit.api.openstack import fakes
@ -156,3 +158,107 @@ class QuotaClassSetsTestV257(QuotaClassSetsTestV250):
for resource in quota_classes_v21.FILTERED_QUOTAS_2_57:
self.quota_resources.pop(resource, None)
self.filtered_quotas.extend(quota_classes_v21.FILTERED_QUOTAS_2_57)
class NoopQuotaClassesTest(test.NoDBTestCase):
quota_driver = "nova.quota.NoopQuotaDriver"
def setUp(self):
super(NoopQuotaClassesTest, self).setUp()
self.flags(driver=self.quota_driver, group="quota")
self.controller = quota_classes_v21.QuotaClassSetsController()
def test_show_v21(self):
req = fakes.HTTPRequest.blank("")
response = self.controller.show(req, "test_class")
expected_response = {
'quota_class_set': {
'id': 'test_class',
'cores': -1,
'fixed_ips': -1,
'floating_ips': -1,
'injected_file_content_bytes': -1,
'injected_file_path_bytes': -1,
'injected_files': -1,
'instances': -1,
'key_pairs': -1,
'metadata_items': -1,
'ram': -1,
'security_group_rules': -1,
'security_groups': -1
}
}
self.assertEqual(expected_response, response)
def test_show_v257(self):
req = fakes.HTTPRequest.blank("", version='2.57')
response = self.controller.show(req, "default")
expected_response = {
'quota_class_set': {
'id': 'default',
'cores': -1,
'instances': -1,
'key_pairs': -1,
'metadata_items': -1,
'ram': -1,
'server_group_members': -1,
'server_groups': -1,
}
}
self.assertEqual(expected_response, response)
def test_update_v21_still_rejects_badrequests(self):
req = fakes.HTTPRequest.blank("")
body = {'quota_class_set': {'instances': 50, 'cores': 50,
'ram': 51200, 'unsupported': 12}}
self.assertRaises(exception.ValidationError, self.controller.update,
req, 'test_class', body=body)
@mock.patch.object(objects.Quotas, "update_class")
def test_update_v21(self, mock_update):
req = fakes.HTTPRequest.blank("")
body = {'quota_class_set': {'ram': 51200}}
response = self.controller.update(req, 'default', body=body)
expected_response = {
'quota_class_set': {
'cores': -1,
'fixed_ips': -1,
'floating_ips': -1,
'injected_file_content_bytes': -1,
'injected_file_path_bytes': -1,
'injected_files': -1,
'instances': -1,
'key_pairs': -1,
'metadata_items': -1,
'ram': -1,
'security_group_rules': -1,
'security_groups': -1
}
}
self.assertEqual(expected_response, response)
mock_update.assert_called_once_with(req.environ['nova.context'],
"default", "ram", 51200)
@mock.patch.object(objects.Quotas, "update_class")
def test_update_v257(self, mock_update):
req = fakes.HTTPRequest.blank("", version='2.57')
body = {'quota_class_set': {'ram': 51200}}
response = self.controller.update(req, 'default', body=body)
expected_response = {
'quota_class_set': {
'cores': -1,
'instances': -1,
'key_pairs': -1,
'metadata_items': -1,
'ram': -1,
'server_group_members': -1,
'server_groups': -1,
}
}
self.assertEqual(expected_response, response)
mock_update.assert_called_once_with(req.environ['nova.context'],
"default", "ram", 51200)
class UnifiedLimitsQuotaClassesTest(NoopQuotaClassesTest):
quota_driver = "nova.quota.UnifiedLimitsDriver"

View File

@ -15,11 +15,13 @@
# under the License.
import mock
from oslo_utils.fixture import uuidsentinel as uuids
import webob
from nova.api.openstack.compute import quota_sets as quotas_v21
from nova.db import constants as db_const
from nova import exception
from nova import objects
from nova import quota
from nova import test
from nova.tests.unit.api.openstack import fakes
@ -660,3 +662,208 @@ class QuotaSetsTestV275(QuotaSetsTestV257):
query_string=query_string)
self.assertRaises(exception.ValidationError, self.controller.delete,
req, 1234)
class NoopQuotaSetsTest(test.NoDBTestCase):
quota_driver = "nova.quota.NoopQuotaDriver"
def setUp(self):
super(NoopQuotaSetsTest, self).setUp()
self.flags(driver=self.quota_driver, group="quota")
self.controller = quotas_v21.QuotaSetsController()
self.stub_out('nova.api.openstack.identity.verify_project_id',
lambda ctx, project_id: True)
def test_show_v21(self):
req = fakes.HTTPRequest.blank("")
response = self.controller.show(req, uuids.project_id)
expected_response = {
'quota_set': {
'id': uuids.project_id,
'cores': -1,
'fixed_ips': -1,
'floating_ips': -1,
'injected_file_content_bytes': -1,
'injected_file_path_bytes': -1,
'injected_files': -1,
'instances': -1,
'key_pairs': -1,
'metadata_items': -1,
'ram': -1,
'security_group_rules': -1,
'security_groups': -1,
'server_group_members': -1,
'server_groups': -1,
}
}
self.assertEqual(expected_response, response)
def test_show_v257(self):
req = fakes.HTTPRequest.blank("", version='2.57')
response = self.controller.show(req, uuids.project_id)
expected_response = {
'quota_set': {
'id': uuids.project_id,
'cores': -1,
'instances': -1,
'key_pairs': -1,
'metadata_items': -1,
'ram': -1,
'server_group_members': -1,
'server_groups': -1}}
self.assertEqual(expected_response, response)
def test_detail_v21(self):
req = fakes.HTTPRequest.blank("")
response = self.controller.detail(req, uuids.project_id)
expected_detail = {'in_use': -1, 'limit': -1, 'reserved': -1}
expected_response = {
'quota_set': {
'id': uuids.project_id,
'cores': expected_detail,
'fixed_ips': expected_detail,
'floating_ips': expected_detail,
'injected_file_content_bytes': expected_detail,
'injected_file_path_bytes': expected_detail,
'injected_files': expected_detail,
'instances': expected_detail,
'key_pairs': expected_detail,
'metadata_items': expected_detail,
'ram': expected_detail,
'security_group_rules': expected_detail,
'security_groups': expected_detail,
'server_group_members': expected_detail,
'server_groups': expected_detail,
}
}
self.assertEqual(expected_response, response)
def test_detail_v21_user(self):
req = fakes.HTTPRequest.blank("?user_id=42")
response = self.controller.detail(req, uuids.project_id)
expected_detail = {'in_use': -1, 'limit': -1, 'reserved': -1}
expected_response = {
'quota_set': {
'id': uuids.project_id,
'cores': expected_detail,
'fixed_ips': expected_detail,
'floating_ips': expected_detail,
'injected_file_content_bytes': expected_detail,
'injected_file_path_bytes': expected_detail,
'injected_files': expected_detail,
'instances': expected_detail,
'key_pairs': expected_detail,
'metadata_items': expected_detail,
'ram': expected_detail,
'security_group_rules': expected_detail,
'security_groups': expected_detail,
'server_group_members': expected_detail,
'server_groups': expected_detail,
}
}
self.assertEqual(expected_response, response)
def test_update_still_rejects_badrequests(self):
req = fakes.HTTPRequest.blank("")
body = {'quota_set': {'instances': 50, 'cores': 50,
'ram': 51200, 'unsupported': 12}}
self.assertRaises(exception.ValidationError, self.controller.update,
req, uuids.project_id, body=body)
@mock.patch.object(objects.Quotas, "create_limit")
def test_update_v21(self, mock_create):
req = fakes.HTTPRequest.blank("")
body = {'quota_set': {'server_groups': 2}}
response = self.controller.update(req, uuids.project_id, body=body)
expected_response = {
'quota_set': {
'cores': -1,
'fixed_ips': -1,
'floating_ips': -1,
'injected_file_content_bytes': -1,
'injected_file_path_bytes': -1,
'injected_files': -1,
'instances': -1,
'key_pairs': -1,
'metadata_items': -1,
'ram': -1,
'security_group_rules': -1,
'security_groups': -1,
'server_group_members': -1,
'server_groups': -1,
}
}
self.assertEqual(expected_response, response)
mock_create.assert_called_once_with(req.environ['nova.context'],
uuids.project_id, "server_groups",
2, user_id=None)
@mock.patch.object(objects.Quotas, "create_limit")
def test_update_v21_user(self, mock_create):
req = fakes.HTTPRequest.blank("?user_id=42")
body = {'quota_set': {'key_pairs': 52}}
response = self.controller.update(req, uuids.project_id, body=body)
expected_response = {
'quota_set': {
'cores': -1,
'fixed_ips': -1,
'floating_ips': -1,
'injected_file_content_bytes': -1,
'injected_file_path_bytes': -1,
'injected_files': -1,
'instances': -1,
'key_pairs': -1,
'metadata_items': -1,
'ram': -1,
'security_group_rules': -1,
'security_groups': -1,
'server_group_members': -1,
'server_groups': -1,
}
}
self.assertEqual(expected_response, response)
mock_create.assert_called_once_with(req.environ['nova.context'],
uuids.project_id, "key_pairs", 52,
user_id="42")
def test_defaults_v21(self):
req = fakes.HTTPRequest.blank("")
response = self.controller.defaults(req, uuids.project_id)
expected_response = {
'quota_set': {
'id': uuids.project_id,
'cores': -1,
'fixed_ips': -1,
'floating_ips': -1,
'injected_file_content_bytes': -1,
'injected_file_path_bytes': -1,
'injected_files': -1,
'instances': -1,
'key_pairs': -1,
'metadata_items': -1,
'ram': -1,
'security_group_rules': -1,
'security_groups': -1,
'server_group_members': -1,
'server_groups': -1,
}
}
self.assertEqual(expected_response, response)
@mock.patch('nova.objects.Quotas.destroy_all_by_project')
def test_quotas_delete(self, mock_destroy_all_by_project):
req = fakes.HTTPRequest.blank("")
self.controller.delete(req, "1234")
mock_destroy_all_by_project.assert_called_once_with(
req.environ['nova.context'], "1234")
@mock.patch('nova.objects.Quotas.destroy_all_by_project_and_user')
def test_user_quotas_delete(self, mock_destroy_all_by_user):
req = fakes.HTTPRequest.blank("?user_id=42")
self.controller.delete(req, "1234")
mock_destroy_all_by_user.assert_called_once_with(
req.environ['nova.context'], "1234", "42")
class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
quota_driver = "nova.quota.UnifiedLimitsDriver"

View File

@ -340,6 +340,19 @@ class QuotaEngineTestCase(test.TestCase):
quota_obj = quota.QuotaEngine(quota_driver=FakeDriver)
self.assertEqual(quota_obj._driver, FakeDriver)
def test_init_with_flag_set(self):
quota_obj = quota.QuotaEngine()
self.assertIsInstance(quota_obj._driver, quota.DbQuotaDriver)
self.flags(group="quota", driver="nova.quota.NoopQuotaDriver")
self.assertIsInstance(quota_obj._driver, quota.NoopQuotaDriver)
self.flags(group="quota", driver="nova.quota.UnifiedLimitsDriver")
self.assertIsInstance(quota_obj._driver, quota.UnifiedLimitsDriver)
self.flags(group="quota", driver="nova.quota.DbQuotaDriver")
self.assertIsInstance(quota_obj._driver, quota.DbQuotaDriver)
def _get_quota_engine(self, driver, resources=None):
resources = resources or [
quota.AbsoluteResource('test_resource4'),