Update quota apis with keystone limits and usage

This makes use of the keystone APIs to get limits from Keystone when
showing the user the limits on their project.

Note we also change the default in_use amount from -1, which is what the
no op driver originally used, to 0, which matches what the db driver
typically returns for deprecated quota values, like floating ip limits.
This seems a more sane value to respond with, given we don't count the
usage for those values.

blueprint unified-limits-nova

Change-Id: I933dc135a364b14ddadc8eee67b42d8e1278a9ae
This commit is contained in:
John Garbutt 2020-03-17 17:42:10 +00:00 committed by melanie witt
parent d80d253cf9
commit 22bc841971
5 changed files with 193 additions and 121 deletions

View File

@ -29,6 +29,7 @@ from nova.db.api import models as api_models
from nova.db.main import api as main_db_api
from nova import exception
from nova.limit import local as local_limit
from nova.limit import placement as placement_limit
from nova import objects
from nova.scheduler.client import report
from nova import utils
@ -806,17 +807,17 @@ class UnifiedLimitsDriver(NoopQuotaDriver):
def get_defaults(self, context, resources):
local_limits = local_limit.get_legacy_default_limits()
# TODO(melwitt): This is temporary when we are in a state where cores,
# ram, and instances quota limits are not known/enforced with unified
# limits yet. This will occur in later patches and when it does, we
# will change the default to 0 to signal to operators that they need to
# register a limit for a resource before that resource will be
# allocated.
# Default to unlimited, as per no-op for everything that isn't
# a local limit
# Note we get 0 if there is no registered limit,
# to mirror oslo_limit behaviour when there is no registered limit
placement_limits = placement_limit.get_legacy_default_limits()
quotas = {}
for resource in resources.values():
quotas[resource.name] = local_limits.get(resource.name, -1)
if resource.name in placement_limits:
quotas[resource.name] = placement_limits[resource.name]
else:
# return -1 for things like security_group_rules
# that are neither a keystone limit or a local limit
quotas[resource.name] = local_limits.get(resource.name, -1)
return quotas
@ -829,21 +830,39 @@ class UnifiedLimitsDriver(NoopQuotaDriver):
if remains:
raise NotImplementedError("remains")
local_limits = self.get_class_quotas(context, resources, quota_class)
local_in_use = {}
local_limits = local_limit.get_legacy_default_limits()
# keystone limits always returns core, ram and instances
# if nothing set in keystone, we get back 0, i.e. don't allow
placement_limits = placement_limit.get_legacy_project_limits(
project_id)
project_quotas = {}
for resource in resources.values():
if resource.name in placement_limits:
limit = placement_limits[resource.name]
else:
# return -1 for things like security_group_rules
# that are neither a keystone limit or a local limit
limit = local_limits.get(resource.name, -1)
project_quotas[resource.name] = {"limit": limit}
if usages:
local_in_use = local_limit.get_in_use(context, project_id)
p_in_use = placement_limit.get_legacy_counts(context, project_id)
quotas = {}
# As we only apply limits to resources we know about,
# we return unlimited (-1) for all other resources
for resource in resources.values():
quota = {"limit": local_limits.get(resource.name, -1)}
if usages:
quota["in_use"] = local_in_use.get(resource.name, -1)
quotas[resource.name] = quota
for resource in resources.values():
# default to 0 for resources that are deprecated,
# i.e. not in keystone or local limits, such that we
# are API compatible with what was returned with
# the db driver, even though noop driver returned -1
usage_count = 0
if resource.name in local_in_use:
usage_count = local_in_use[resource.name]
if resource.name in p_in_use:
usage_count = p_in_use[resource.name]
project_quotas[resource.name]["in_use"] = usage_count
return quotas
return project_quotas
def get_user_quotas(self, context, resources, project_id, user_id,
quota_class=None, usages=True):

View File

@ -31,6 +31,7 @@ from nova.api.openstack import wsgi
import nova.context
from nova import exception
from nova.limit import local as local_limit
from nova.limit import placement as placement_limit
from nova import objects
from nova.policies import limits as l_policies
from nova import quota
@ -564,8 +565,12 @@ class UnifiedLimitsControllerTest(NoopLimitsControllerTest):
local_limit.SERVER_GROUP_MEMBERS: 10}
self.useFixture(limit_fixture.LimitFixture(reglimits, {}))
@mock.patch.object(placement_limit, "get_legacy_counts")
@mock.patch.object(placement_limit, "get_legacy_project_limits")
@mock.patch.object(objects.InstanceGroupList, "get_counts")
def test_index_v21(self, mock_count):
def test_index_v21(self, mock_count, mock_proj, mock_kcount):
mock_proj.return_value = {"instances": 1, "cores": 2, "ram": 3}
mock_kcount.return_value = {"instances": 4, "cores": 5, "ram": 6}
mock_count.return_value = {'project': {'server_groups': 9}}
req = fakes.HTTPRequest.blank("/")
response = self.controller.index(req)
@ -581,24 +586,28 @@ class UnifiedLimitsControllerTest(NoopLimitsControllerTest):
'maxServerGroupMembers': 10,
'maxServerGroups': 12,
'maxServerMeta': 128,
'maxTotalCores': -1,
'maxTotalCores': 2,
'maxTotalFloatingIps': -1,
'maxTotalInstances': -1,
'maxTotalInstances': 1,
'maxTotalKeypairs': 100,
'maxTotalRAMSize': -1,
'totalCoresUsed': -1,
'totalFloatingIpsUsed': -1,
'totalInstancesUsed': -1,
'totalRAMUsed': -1,
'totalSecurityGroupsUsed': -1,
'maxTotalRAMSize': 3,
'totalCoresUsed': 5,
'totalFloatingIpsUsed': 0,
'totalInstancesUsed': 4,
'totalRAMUsed': 6,
'totalSecurityGroupsUsed': 0,
'totalServerGroupsUsed': 9,
},
},
}
self.assertEqual(expected_response, response)
@mock.patch.object(placement_limit, "get_legacy_counts")
@mock.patch.object(placement_limit, "get_legacy_project_limits")
@mock.patch.object(objects.InstanceGroupList, "get_counts")
def test_index_v275(self, mock_count):
def test_index_v275(self, mock_count, mock_proj, mock_kcount):
mock_proj.return_value = {"instances": 1, "cores": 2, "ram": 3}
mock_kcount.return_value = {"instances": 4, "cores": 5, "ram": 6}
mock_count.return_value = {'project': {'server_groups': 9}}
req = fakes.HTTPRequest.blank("/?tenant_id=faketenant",
version='2.75')
@ -610,13 +619,13 @@ class UnifiedLimitsControllerTest(NoopLimitsControllerTest):
'maxServerGroupMembers': 10,
'maxServerGroups': 12,
'maxServerMeta': 128,
'maxTotalCores': -1,
'maxTotalInstances': -1,
'maxTotalCores': 2,
'maxTotalInstances': 1,
'maxTotalKeypairs': 100,
'maxTotalRAMSize': -1,
'totalCoresUsed': -1,
'totalInstancesUsed': -1,
'totalRAMUsed': -1,
'maxTotalRAMSize': 3,
'totalCoresUsed': 5,
'totalInstancesUsed': 4,
'totalRAMUsed': 6,
'totalServerGroupsUsed': 9,
},
},

View File

@ -21,6 +21,7 @@ from nova.api.openstack.compute import quota_classes \
as quota_classes_v21
from nova import exception
from nova.limit import local as local_limit
from nova.limit import placement as placement_limit
from nova import objects
from nova import test
from nova.tests.unit.api.openstack import fakes
@ -279,20 +280,22 @@ class UnifiedLimitsQuotaClassesTest(NoopQuotaClassesTest):
local_limit.SERVER_GROUP_MEMBERS: 10}
self.useFixture(limit_fixture.LimitFixture(reglimits, {}))
def test_show_v21(self):
@mock.patch.object(placement_limit, "get_legacy_default_limits")
def test_show_v21(self, mock_default):
mock_default.return_value = {"instances": 1, "cores": 2, "ram": 3}
req = fakes.HTTPRequest.blank("")
response = self.controller.show(req, "test_class")
expected_response = {
'quota_class_set': {
'id': 'test_class',
'cores': -1,
'cores': 2,
'fixed_ips': -1,
'floating_ips': -1,
'ram': -1,
'ram': 3,
'injected_file_content_bytes': 10240,
'injected_file_path_bytes': 255,
'injected_files': 5,
'instances': -1,
'instances': 1,
'key_pairs': 100,
'metadata_items': 128,
'security_group_rules': -1,
@ -301,15 +304,17 @@ class UnifiedLimitsQuotaClassesTest(NoopQuotaClassesTest):
}
self.assertEqual(expected_response, response)
def test_show_v257(self):
@mock.patch.object(placement_limit, "get_legacy_default_limits")
def test_show_v257(self, mock_default):
mock_default.return_value = {"instances": 1, "cores": 2, "ram": 3}
req = fakes.HTTPRequest.blank("", version='2.57')
response = self.controller.show(req, "default")
expected_response = {
'quota_class_set': {
'id': 'default',
'cores': -1,
'instances': -1,
'ram': -1,
'cores': 2,
'instances': 1,
'ram': 3,
'key_pairs': 100,
'metadata_items': 128,
'server_group_members': 10,
@ -325,23 +330,25 @@ class UnifiedLimitsQuotaClassesTest(NoopQuotaClassesTest):
self.assertRaises(exception.ValidationError, self.controller.update,
req, 'test_class', body=body)
@mock.patch.object(placement_limit, "get_legacy_default_limits")
@mock.patch.object(objects.Quotas, "update_class")
def test_update_v21(self, mock_update):
def test_update_v21(self, mock_update, mock_default):
mock_default.return_value = {"instances": 1, "cores": 2, "ram": 3}
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,
'cores': 2,
'fixed_ips': -1,
'floating_ips': -1,
'injected_file_content_bytes': 10240,
'injected_file_path_bytes': 255,
'injected_files': 5,
'instances': -1,
'instances': 1,
'key_pairs': 100,
'metadata_items': 128,
'ram': -1,
'ram': 3,
'security_group_rules': -1,
'security_groups': -1
}
@ -350,16 +357,18 @@ class UnifiedLimitsQuotaClassesTest(NoopQuotaClassesTest):
# TODO(johngarbutt) we should be proxying to keystone
self.assertEqual(0, mock_update.call_count)
@mock.patch.object(placement_limit, "get_legacy_default_limits")
@mock.patch.object(objects.Quotas, "update_class")
def test_update_v257(self, mock_update):
def test_update_v257(self, mock_update, mock_default):
mock_default.return_value = {"instances": 1, "cores": 2, "ram": 3}
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,
'ram': -1,
'cores': 2,
'instances': 1,
'ram': 3,
'key_pairs': 100,
'metadata_items': 128,
'server_group_members': 10,

View File

@ -23,6 +23,7 @@ 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.limit import local as local_limit
from nova.limit import placement as placement_limit
from nova import objects
from nova import quota
from nova import test
@ -869,7 +870,8 @@ class NoopQuotaSetsTest(test.NoDBTestCase):
class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
quota_driver = "nova.quota.UnifiedLimitsDriver"
expected_detail = {'in_use': -1, 'limit': -1, 'reserved': 0}
# this matches what the db driver returns
expected_detail = {'in_use': 0, 'limit': -1, 'reserved': 0}
def setUp(self):
super(UnifiedLimitsQuotaSetsTest, self).setUp()
@ -882,22 +884,24 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
local_limit.SERVER_GROUP_MEMBERS: 10}
self.useFixture(limit_fixture.LimitFixture(reglimits, {}))
def test_show_v21(self):
@mock.patch.object(placement_limit, "get_legacy_project_limits")
def test_show_v21(self, mock_proj):
mock_proj.return_value = {"instances": 1, "cores": 2, "ram": 3}
req = fakes.HTTPRequest.blank("")
response = self.controller.show(req, uuids.project_id)
expected_response = {
'quota_set': {
'id': uuids.project_id,
'cores': -1,
'cores': 2,
'fixed_ips': -1,
'floating_ips': -1,
'injected_file_content_bytes': 10240,
'injected_file_path_bytes': 255,
'injected_files': 5,
'instances': -1,
'instances': 1,
'key_pairs': 100,
'metadata_items': 128,
'ram': -1,
'ram': 3,
'security_group_rules': -1,
'security_groups': -1,
'server_group_members': 10,
@ -906,30 +910,37 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
}
self.assertEqual(expected_response, response)
def test_show_v257(self):
@mock.patch.object(placement_limit, "get_legacy_project_limits")
def test_show_v257(self, mock_proj):
mock_proj.return_value = {"instances": 1, "cores": 2, "ram": 3}
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,
'cores': 2,
'instances': 1,
'key_pairs': 100,
'metadata_items': 128,
'ram': -1,
'ram': 3,
'server_group_members': 10,
'server_groups': 12}}
self.assertEqual(expected_response, response)
@mock.patch.object(placement_limit, "get_legacy_counts")
@mock.patch.object(placement_limit, "get_legacy_project_limits")
@mock.patch.object(objects.InstanceGroupList, "get_counts")
def test_detail_v21(self, mock_count):
def test_detail_v21(self, mock_count, mock_proj, mock_kcount):
mock_proj.return_value = {"instances": 1, "cores": 2, "ram": 3}
mock_kcount.return_value = {"instances": 4, "cores": 5, "ram": 6}
mock_count.return_value = {'project': {'server_groups': 9}}
req = fakes.HTTPRequest.blank("")
response = self.controller.detail(req, uuids.project_id)
expected_response = {
'quota_set': {
'id': uuids.project_id,
'cores': self.expected_detail,
'cores': {
'in_use': 5, 'limit': 2, 'reserved': 0},
'fixed_ips': self.expected_detail,
'floating_ips': self.expected_detail,
'injected_file_content_bytes': {
@ -938,12 +949,14 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
'in_use': 0, 'limit': 255, 'reserved': 0},
'injected_files': {
'in_use': 0, 'limit': 5, 'reserved': 0},
'instances': self.expected_detail,
'instances': {
'in_use': 4, 'limit': 1, 'reserved': 0},
'key_pairs': {
'in_use': 0, 'limit': 100, 'reserved': 0},
'metadata_items': {
'in_use': 0, 'limit': 128, 'reserved': 0},
'ram': self.expected_detail,
'ram': {
'in_use': 6, 'limit': 3, 'reserved': 0},
'security_group_rules': self.expected_detail,
'security_groups': self.expected_detail,
'server_group_members': {
@ -954,15 +967,20 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
}
self.assertEqual(expected_response, response)
@mock.patch.object(placement_limit, "get_legacy_counts")
@mock.patch.object(placement_limit, "get_legacy_project_limits")
@mock.patch.object(objects.InstanceGroupList, "get_counts")
def test_detail_v21_user(self, mock_count):
def test_detail_v21_user(self, mock_count, mock_proj, mock_kcount):
mock_proj.return_value = {"instances": 1, "cores": 2, "ram": 3}
mock_kcount.return_value = {"instances": 4, "cores": 5, "ram": 6}
mock_count.return_value = {'project': {'server_groups': 9}}
req = fakes.HTTPRequest.blank("?user_id=42")
response = self.controller.detail(req, uuids.project_id)
expected_response = {
'quota_set': {
'id': uuids.project_id,
'cores': self.expected_detail,
'cores': {
'in_use': 5, 'limit': 2, 'reserved': 0},
'fixed_ips': self.expected_detail,
'floating_ips': self.expected_detail,
'injected_file_content_bytes': {
@ -971,12 +989,14 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
'in_use': 0, 'limit': 255, 'reserved': 0},
'injected_files': {
'in_use': 0, 'limit': 5, 'reserved': 0},
'instances': self.expected_detail,
'instances': {
'in_use': 4, 'limit': 1, 'reserved': 0},
'key_pairs': {
'in_use': 0, 'limit': 100, 'reserved': 0},
'metadata_items': {
'in_use': 0, 'limit': 128, 'reserved': 0},
'ram': self.expected_detail,
'ram': {
'in_use': 6, 'limit': 3, 'reserved': 0},
'security_group_rules': self.expected_detail,
'security_groups': self.expected_detail,
'server_group_members': {
@ -987,24 +1007,26 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
}
self.assertEqual(expected_response, response)
@mock.patch.object(placement_limit, "get_legacy_project_limits")
@mock.patch.object(objects.Quotas, "create_limit")
def test_update_v21(self, mock_create):
def test_update_v21(self, mock_create, mock_proj):
mock_proj.return_value = {"instances": 1, "cores": 2, "ram": 3}
req = fakes.HTTPRequest.blank("")
# TODO(johngarbutt) still need to implement get_settable_quotas
body = {'quota_set': {'server_groups': 2}}
response = self.controller.update(req, uuids.project_id, body=body)
expected_response = {
'quota_set': {
'cores': -1,
'cores': 2,
'fixed_ips': -1,
'floating_ips': -1,
'injected_file_content_bytes': 10240,
'injected_file_path_bytes': 255,
'injected_files': 5,
'instances': -1,
'instances': 1,
'key_pairs': 100,
'metadata_items': 128,
'ram': -1,
'ram': 3,
'security_group_rules': -1,
'security_groups': -1,
'server_group_members': 10,
@ -1014,23 +1036,25 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
self.assertEqual(expected_response, response)
self.assertEqual(0, mock_create.call_count)
@mock.patch.object(placement_limit, "get_legacy_project_limits")
@mock.patch.object(objects.Quotas, "create_limit")
def test_update_v21_user(self, mock_create):
def test_update_v21_user(self, mock_create, mock_proj):
mock_proj.return_value = {"instances": 1, "cores": 2, "ram": 3}
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,
'cores': 2,
'fixed_ips': -1,
'floating_ips': -1,
'injected_file_content_bytes': 10240,
'injected_file_path_bytes': 255,
'injected_files': 5,
'instances': -1,
'instances': 1,
'key_pairs': 100,
'metadata_items': 128,
'ram': -1,
'ram': 3,
'security_group_rules': -1,
'security_groups': -1,
'server_group_members': 10,
@ -1040,22 +1064,24 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
self.assertEqual(expected_response, response)
self.assertEqual(0, mock_create.call_count)
def test_defaults_v21(self):
@mock.patch.object(placement_limit, "get_legacy_default_limits")
def test_defaults_v21(self, mock_default):
mock_default.return_value = {"instances": 1, "cores": 2, "ram": 3}
req = fakes.HTTPRequest.blank("")
response = self.controller.defaults(req, uuids.project_id)
expected_response = {
'quota_set': {
'id': uuids.project_id,
'cores': -1,
'cores': 2,
'fixed_ips': -1,
'floating_ips': -1,
'injected_file_content_bytes': 10240,
'injected_file_path_bytes': 255,
'injected_files': 5,
'instances': -1,
'instances': 1,
'key_pairs': 100,
'metadata_items': 128,
'ram': -1,
'ram': 3,
'security_group_rules': -1,
'security_groups': -1,
'server_group_members': 10,
@ -1079,16 +1105,16 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
expected_response = {
'quota_set': {
'id': uuids.project_id,
'cores': -1,
'cores': 0,
'fixed_ips': -1,
'floating_ips': -1,
'injected_file_content_bytes': 4,
'injected_file_path_bytes': 5,
'injected_files': 6,
'instances': -1,
'instances': 0,
'key_pairs': 1,
'metadata_items': 7,
'ram': -1,
'ram': 0,
'security_group_rules': -1,
'security_groups': -1,
'server_group_members': 2,

View File

@ -26,6 +26,7 @@ from nova import context
from nova.db.main import models
from nova import exception
from nova.limit import local as local_limit
from nova.limit import placement as placement_limit
from nova import objects
from nova import quota
from nova import test
@ -1990,101 +1991,109 @@ class UnifiedLimitsDriverTestCase(NoopQuotaDriverTestCase):
self.useFixture(limit_fixture.LimitFixture(reglimits, {}))
self.expected_without_dict = {
'cores': -1,
'cores': 2,
'fixed_ips': -1,
'floating_ips': -1,
'injected_file_content_bytes': 10240,
'injected_file_path_bytes': 255,
'injected_files': 5,
'instances': -1,
'instances': 1,
'key_pairs': 100,
'metadata_items': 128,
'ram': -1,
'ram': 0,
'security_group_rules': -1,
'security_groups': -1,
'server_group_members': 10,
'server_groups': 12,
}
self.expected_without_usages = {
'cores': {'limit': -1},
'cores': {'limit': 2},
'fixed_ips': {'limit': -1},
'floating_ips': {'limit': -1},
'injected_file_content_bytes': {'limit': 10240},
'injected_file_path_bytes': {'limit': 255},
'injected_files': {'limit': 5},
'instances': {'limit': -1},
'instances': {'limit': 1},
'key_pairs': {'limit': 100},
'metadata_items': {'limit': 128},
'ram': {'limit': -1},
'ram': {'limit': 3},
'security_group_rules': {'limit': -1},
'security_groups': {'limit': -1},
'server_group_members': {'limit': 10},
'server_groups': {'limit': 12}
}
self.expected_with_usages = {
'cores': {'in_use': -1, 'limit': -1},
'fixed_ips': {'in_use': -1, 'limit': -1},
'floating_ips': {'in_use': -1, 'limit': -1},
'cores': {'in_use': 5, 'limit': 2},
'fixed_ips': {'in_use': 0, 'limit': -1},
'floating_ips': {'in_use': 0, 'limit': -1},
'injected_file_content_bytes': {'in_use': 0, 'limit': 10240},
'injected_file_path_bytes': {'in_use': 0, 'limit': 255},
'injected_files': {'in_use': 0, 'limit': 5},
'instances': {'in_use': -1, 'limit': -1},
'instances': {'in_use': 4, 'limit': 1},
'key_pairs': {'in_use': 0, 'limit': 100},
'metadata_items': {'in_use': 0, 'limit': 128},
'ram': {'in_use': -1, 'limit': -1},
'security_group_rules': {'in_use': -1, 'limit': -1},
'security_groups': {'in_use': -1, 'limit': -1},
'ram': {'in_use': 6, 'limit': 3},
'security_group_rules': {'in_use': 0, 'limit': -1},
'security_groups': {'in_use': 0, 'limit': -1},
'server_group_members': {'in_use': 0, 'limit': 10},
'server_groups': {'in_use': 9, 'limit': 12}
}
def test_get_class_quotas(self):
result = self.driver.get_class_quotas(
None, quota.QUOTAS._resources, 'default')
expected_limits = {
'cores': -1,
'fixed_ips': -1,
'floating_ips': -1,
'injected_file_content_bytes': 10240,
'injected_file_path_bytes': 255,
'injected_files': 5,
'instances': -1,
'key_pairs': 100,
'metadata_items': 128,
'ram': -1,
'security_group_rules': -1,
'security_groups': -1,
'server_group_members': 10,
'server_groups': 12,
}
self.assertEqual(expected_limits, result)
@mock.patch.object(placement_limit, "get_legacy_default_limits")
def test_get_defaults(self, mock_default):
# zero for ram simulates no registered limit for ram
mock_default.return_value = {"instances": 1, "cores": 2, "ram": 0}
result = self.driver.get_defaults(None, quota.QUOTAS._resources)
self.assertEqual(self.expected_without_dict, result)
mock_default.assert_called_once_with()
@mock.patch.object(placement_limit, "get_legacy_default_limits")
def test_get_class_quotas(self, mock_default):
mock_default.return_value = {"instances": 1, "cores": 2, "ram": 0}
result = self.driver.get_class_quotas(
None, quota.QUOTAS._resources, 'test_class')
self.assertEqual(self.expected_without_dict, result)
mock_default.assert_called_once_with()
@mock.patch.object(placement_limit, "get_legacy_counts")
@mock.patch.object(placement_limit, "get_legacy_project_limits")
@mock.patch.object(objects.InstanceGroupList, "get_counts")
def test_get_project_quotas(self, mock_count):
def test_get_project_quotas(self, mock_count, mock_proj, mock_kcount):
mock_proj.return_value = {"instances": 1, "cores": 2, "ram": 3}
mock_kcount.return_value = {"instances": 4, "cores": 5, "ram": 6}
mock_count.return_value = {'project': {'server_groups': 9}}
result = self.driver.get_project_quotas(
None, quota.QUOTAS._resources, 'test_project')
self.assertEqual(self.expected_with_usages, result)
mock_count.assert_called_once_with(None, "test_project")
@mock.patch.object(placement_limit, "get_legacy_project_limits")
@mock.patch.object(objects.InstanceGroupList, "get_counts")
def test_get_project_quotas_no_usages(self, mock_count):
def test_get_project_quotas_no_usages(self, mock_count, mock_proj):
mock_proj.return_value = {"instances": 1, "cores": 2, "ram": 3}
result = self.driver.get_project_quotas(
None, quota.QUOTAS._resources, 'test_project', usages=False)
self.assertEqual(self.expected_without_usages, result)
# ensure usages not fetched when not required
self.assertEqual(0, mock_count.call_count)
mock_proj.assert_called_once_with("test_project")
@mock.patch.object(placement_limit, "get_legacy_counts")
@mock.patch.object(placement_limit, "get_legacy_project_limits")
@mock.patch.object(objects.InstanceGroupList, "get_counts")
def test_get_user_quotas(self, mock_count):
def test_get_user_quotas(self, mock_count, mock_proj, mock_kcount):
mock_proj.return_value = {"instances": 1, "cores": 2, "ram": 3}
mock_kcount.return_value = {"instances": 4, "cores": 5, "ram": 6}
mock_count.return_value = {'project': {'server_groups': 9}}
result = self.driver.get_user_quotas(
None, quota.QUOTAS._resources, 'test_project', 'fake_user')
self.assertEqual(self.expected_with_usages, result)
mock_count.assert_called_once_with(None, "test_project")
@mock.patch.object(placement_limit, "get_legacy_project_limits")
@mock.patch.object(objects.InstanceGroupList, "get_counts")
def test_get_user_quotas_no_usages(self, mock_count):
def test_get_user_quotas_no_usages(self, mock_count, mock_proj):
mock_proj.return_value = {"instances": 1, "cores": 2, "ram": 3}
result = self.driver.get_user_quotas(
None, quota.QUOTAS._resources, 'test_project', 'fake_user',
usages=False)