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
6 changed files with 414 additions and 4 deletions

View File

@@ -181,6 +181,8 @@ Possible values:
'on-demand.'), 'on-demand.'),
('nova.quota.NoopQuotaDriver', 'Ignores quota and treats all ' ('nova.quota.NoopQuotaDriver', 'Ignores quota and treats all '
'resources as unlimited.'), 'resources as unlimited.'),
('nova.quota.UnifiedLimitsDriver', 'Do not use. Still being '
'developed.')
], ],
help=""" help="""
Provides abstraction for quota checks. Users can configure a specific 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 # NOTE(mriedem): quota_driver is ever only supplied in tests with a
# fake driver. # fake driver.
self.__driver = quota_driver self.__driver_override = quota_driver
self.__driver = None
self.__driver_name = None
@property @property
def _driver(self): def _driver(self):
if self.__driver: if self.__driver_override:
return self.__driver return self.__driver_override
self.__driver = importutils.import_object(CONF.quota.driver)
# 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 return self.__driver
def get_defaults(self, context): def get_defaults(self, context):

View File

@@ -477,3 +477,75 @@ class LimitsControllerTestV275(BaseLimitTestSuite):
self.assertRaises( self.assertRaises(
exception.ValidationError, exception.ValidationError,
self.controller.index, req=req) 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 # License for the specific language governing permissions and limitations
# under the License. # under the License.
import copy import copy
import mock
import webob import webob
from nova.api.openstack.compute import quota_classes \ from nova.api.openstack.compute import quota_classes \
as quota_classes_v21 as quota_classes_v21
from nova import exception from nova import exception
from nova import objects
from nova import test from nova import test
from nova.tests.unit.api.openstack import fakes 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: for resource in quota_classes_v21.FILTERED_QUOTAS_2_57:
self.quota_resources.pop(resource, None) self.quota_resources.pop(resource, None)
self.filtered_quotas.extend(quota_classes_v21.FILTERED_QUOTAS_2_57) 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. # under the License.
import mock import mock
from oslo_utils.fixture import uuidsentinel as uuids
import webob import webob
from nova.api.openstack.compute import quota_sets as quotas_v21 from nova.api.openstack.compute import quota_sets as quotas_v21
from nova.db import constants as db_const from nova.db import constants as db_const
from nova import exception from nova import exception
from nova import objects
from nova import quota from nova import quota
from nova import test from nova import test
from nova.tests.unit.api.openstack import fakes from nova.tests.unit.api.openstack import fakes
@@ -660,3 +662,208 @@ class QuotaSetsTestV275(QuotaSetsTestV257):
query_string=query_string) query_string=query_string)
self.assertRaises(exception.ValidationError, self.controller.delete, self.assertRaises(exception.ValidationError, self.controller.delete,
req, 1234) 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) quota_obj = quota.QuotaEngine(quota_driver=FakeDriver)
self.assertEqual(quota_obj._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): def _get_quota_engine(self, driver, resources=None):
resources = resources or [ resources = resources or [
quota.AbsoluteResource('test_resource4'), quota.AbsoluteResource('test_resource4'),