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:
parent
d80d253cf9
commit
22bc841971
|
@ -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.db.main import api as main_db_api
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova.limit import local as local_limit
|
from nova.limit import local as local_limit
|
||||||
|
from nova.limit import placement as placement_limit
|
||||||
from nova import objects
|
from nova import objects
|
||||||
from nova.scheduler.client import report
|
from nova.scheduler.client import report
|
||||||
from nova import utils
|
from nova import utils
|
||||||
|
@ -806,17 +807,17 @@ class UnifiedLimitsDriver(NoopQuotaDriver):
|
||||||
|
|
||||||
def get_defaults(self, context, resources):
|
def get_defaults(self, context, resources):
|
||||||
local_limits = local_limit.get_legacy_default_limits()
|
local_limits = local_limit.get_legacy_default_limits()
|
||||||
# TODO(melwitt): This is temporary when we are in a state where cores,
|
# Note we get 0 if there is no registered limit,
|
||||||
# ram, and instances quota limits are not known/enforced with unified
|
# to mirror oslo_limit behaviour when there is no registered limit
|
||||||
# limits yet. This will occur in later patches and when it does, we
|
placement_limits = placement_limit.get_legacy_default_limits()
|
||||||
# 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
|
|
||||||
quotas = {}
|
quotas = {}
|
||||||
for resource in resources.values():
|
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
|
return quotas
|
||||||
|
|
||||||
|
@ -829,21 +830,39 @@ class UnifiedLimitsDriver(NoopQuotaDriver):
|
||||||
if remains:
|
if remains:
|
||||||
raise NotImplementedError("remains")
|
raise NotImplementedError("remains")
|
||||||
|
|
||||||
local_limits = self.get_class_quotas(context, resources, quota_class)
|
local_limits = local_limit.get_legacy_default_limits()
|
||||||
local_in_use = {}
|
# 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:
|
if usages:
|
||||||
local_in_use = local_limit.get_in_use(context, project_id)
|
local_in_use = local_limit.get_in_use(context, project_id)
|
||||||
|
p_in_use = placement_limit.get_legacy_counts(context, project_id)
|
||||||
|
|
||||||
quotas = {}
|
for resource in resources.values():
|
||||||
# As we only apply limits to resources we know about,
|
# default to 0 for resources that are deprecated,
|
||||||
# we return unlimited (-1) for all other resources
|
# i.e. not in keystone or local limits, such that we
|
||||||
for resource in resources.values():
|
# are API compatible with what was returned with
|
||||||
quota = {"limit": local_limits.get(resource.name, -1)}
|
# the db driver, even though noop driver returned -1
|
||||||
if usages:
|
usage_count = 0
|
||||||
quota["in_use"] = local_in_use.get(resource.name, -1)
|
if resource.name in local_in_use:
|
||||||
quotas[resource.name] = quota
|
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,
|
def get_user_quotas(self, context, resources, project_id, user_id,
|
||||||
quota_class=None, usages=True):
|
quota_class=None, usages=True):
|
||||||
|
|
|
@ -31,6 +31,7 @@ from nova.api.openstack import wsgi
|
||||||
import nova.context
|
import nova.context
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova.limit import local as local_limit
|
from nova.limit import local as local_limit
|
||||||
|
from nova.limit import placement as placement_limit
|
||||||
from nova import objects
|
from nova import objects
|
||||||
from nova.policies import limits as l_policies
|
from nova.policies import limits as l_policies
|
||||||
from nova import quota
|
from nova import quota
|
||||||
|
@ -564,8 +565,12 @@ class UnifiedLimitsControllerTest(NoopLimitsControllerTest):
|
||||||
local_limit.SERVER_GROUP_MEMBERS: 10}
|
local_limit.SERVER_GROUP_MEMBERS: 10}
|
||||||
self.useFixture(limit_fixture.LimitFixture(reglimits, {}))
|
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")
|
@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}}
|
mock_count.return_value = {'project': {'server_groups': 9}}
|
||||||
req = fakes.HTTPRequest.blank("/")
|
req = fakes.HTTPRequest.blank("/")
|
||||||
response = self.controller.index(req)
|
response = self.controller.index(req)
|
||||||
|
@ -581,24 +586,28 @@ class UnifiedLimitsControllerTest(NoopLimitsControllerTest):
|
||||||
'maxServerGroupMembers': 10,
|
'maxServerGroupMembers': 10,
|
||||||
'maxServerGroups': 12,
|
'maxServerGroups': 12,
|
||||||
'maxServerMeta': 128,
|
'maxServerMeta': 128,
|
||||||
'maxTotalCores': -1,
|
'maxTotalCores': 2,
|
||||||
'maxTotalFloatingIps': -1,
|
'maxTotalFloatingIps': -1,
|
||||||
'maxTotalInstances': -1,
|
'maxTotalInstances': 1,
|
||||||
'maxTotalKeypairs': 100,
|
'maxTotalKeypairs': 100,
|
||||||
'maxTotalRAMSize': -1,
|
'maxTotalRAMSize': 3,
|
||||||
'totalCoresUsed': -1,
|
'totalCoresUsed': 5,
|
||||||
'totalFloatingIpsUsed': -1,
|
'totalFloatingIpsUsed': 0,
|
||||||
'totalInstancesUsed': -1,
|
'totalInstancesUsed': 4,
|
||||||
'totalRAMUsed': -1,
|
'totalRAMUsed': 6,
|
||||||
'totalSecurityGroupsUsed': -1,
|
'totalSecurityGroupsUsed': 0,
|
||||||
'totalServerGroupsUsed': 9,
|
'totalServerGroupsUsed': 9,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
self.assertEqual(expected_response, response)
|
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")
|
@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}}
|
mock_count.return_value = {'project': {'server_groups': 9}}
|
||||||
req = fakes.HTTPRequest.blank("/?tenant_id=faketenant",
|
req = fakes.HTTPRequest.blank("/?tenant_id=faketenant",
|
||||||
version='2.75')
|
version='2.75')
|
||||||
|
@ -610,13 +619,13 @@ class UnifiedLimitsControllerTest(NoopLimitsControllerTest):
|
||||||
'maxServerGroupMembers': 10,
|
'maxServerGroupMembers': 10,
|
||||||
'maxServerGroups': 12,
|
'maxServerGroups': 12,
|
||||||
'maxServerMeta': 128,
|
'maxServerMeta': 128,
|
||||||
'maxTotalCores': -1,
|
'maxTotalCores': 2,
|
||||||
'maxTotalInstances': -1,
|
'maxTotalInstances': 1,
|
||||||
'maxTotalKeypairs': 100,
|
'maxTotalKeypairs': 100,
|
||||||
'maxTotalRAMSize': -1,
|
'maxTotalRAMSize': 3,
|
||||||
'totalCoresUsed': -1,
|
'totalCoresUsed': 5,
|
||||||
'totalInstancesUsed': -1,
|
'totalInstancesUsed': 4,
|
||||||
'totalRAMUsed': -1,
|
'totalRAMUsed': 6,
|
||||||
'totalServerGroupsUsed': 9,
|
'totalServerGroupsUsed': 9,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,6 +21,7 @@ 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.limit import local as local_limit
|
from nova.limit import local as local_limit
|
||||||
|
from nova.limit import placement as placement_limit
|
||||||
from nova import objects
|
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
|
||||||
|
@ -279,20 +280,22 @@ class UnifiedLimitsQuotaClassesTest(NoopQuotaClassesTest):
|
||||||
local_limit.SERVER_GROUP_MEMBERS: 10}
|
local_limit.SERVER_GROUP_MEMBERS: 10}
|
||||||
self.useFixture(limit_fixture.LimitFixture(reglimits, {}))
|
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("")
|
req = fakes.HTTPRequest.blank("")
|
||||||
response = self.controller.show(req, "test_class")
|
response = self.controller.show(req, "test_class")
|
||||||
expected_response = {
|
expected_response = {
|
||||||
'quota_class_set': {
|
'quota_class_set': {
|
||||||
'id': 'test_class',
|
'id': 'test_class',
|
||||||
'cores': -1,
|
'cores': 2,
|
||||||
'fixed_ips': -1,
|
'fixed_ips': -1,
|
||||||
'floating_ips': -1,
|
'floating_ips': -1,
|
||||||
'ram': -1,
|
'ram': 3,
|
||||||
'injected_file_content_bytes': 10240,
|
'injected_file_content_bytes': 10240,
|
||||||
'injected_file_path_bytes': 255,
|
'injected_file_path_bytes': 255,
|
||||||
'injected_files': 5,
|
'injected_files': 5,
|
||||||
'instances': -1,
|
'instances': 1,
|
||||||
'key_pairs': 100,
|
'key_pairs': 100,
|
||||||
'metadata_items': 128,
|
'metadata_items': 128,
|
||||||
'security_group_rules': -1,
|
'security_group_rules': -1,
|
||||||
|
@ -301,15 +304,17 @@ class UnifiedLimitsQuotaClassesTest(NoopQuotaClassesTest):
|
||||||
}
|
}
|
||||||
self.assertEqual(expected_response, response)
|
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')
|
req = fakes.HTTPRequest.blank("", version='2.57')
|
||||||
response = self.controller.show(req, "default")
|
response = self.controller.show(req, "default")
|
||||||
expected_response = {
|
expected_response = {
|
||||||
'quota_class_set': {
|
'quota_class_set': {
|
||||||
'id': 'default',
|
'id': 'default',
|
||||||
'cores': -1,
|
'cores': 2,
|
||||||
'instances': -1,
|
'instances': 1,
|
||||||
'ram': -1,
|
'ram': 3,
|
||||||
'key_pairs': 100,
|
'key_pairs': 100,
|
||||||
'metadata_items': 128,
|
'metadata_items': 128,
|
||||||
'server_group_members': 10,
|
'server_group_members': 10,
|
||||||
|
@ -325,23 +330,25 @@ class UnifiedLimitsQuotaClassesTest(NoopQuotaClassesTest):
|
||||||
self.assertRaises(exception.ValidationError, self.controller.update,
|
self.assertRaises(exception.ValidationError, self.controller.update,
|
||||||
req, 'test_class', body=body)
|
req, 'test_class', body=body)
|
||||||
|
|
||||||
|
@mock.patch.object(placement_limit, "get_legacy_default_limits")
|
||||||
@mock.patch.object(objects.Quotas, "update_class")
|
@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("")
|
req = fakes.HTTPRequest.blank("")
|
||||||
body = {'quota_class_set': {'ram': 51200}}
|
body = {'quota_class_set': {'ram': 51200}}
|
||||||
response = self.controller.update(req, 'default', body=body)
|
response = self.controller.update(req, 'default', body=body)
|
||||||
expected_response = {
|
expected_response = {
|
||||||
'quota_class_set': {
|
'quota_class_set': {
|
||||||
'cores': -1,
|
'cores': 2,
|
||||||
'fixed_ips': -1,
|
'fixed_ips': -1,
|
||||||
'floating_ips': -1,
|
'floating_ips': -1,
|
||||||
'injected_file_content_bytes': 10240,
|
'injected_file_content_bytes': 10240,
|
||||||
'injected_file_path_bytes': 255,
|
'injected_file_path_bytes': 255,
|
||||||
'injected_files': 5,
|
'injected_files': 5,
|
||||||
'instances': -1,
|
'instances': 1,
|
||||||
'key_pairs': 100,
|
'key_pairs': 100,
|
||||||
'metadata_items': 128,
|
'metadata_items': 128,
|
||||||
'ram': -1,
|
'ram': 3,
|
||||||
'security_group_rules': -1,
|
'security_group_rules': -1,
|
||||||
'security_groups': -1
|
'security_groups': -1
|
||||||
}
|
}
|
||||||
|
@ -350,16 +357,18 @@ class UnifiedLimitsQuotaClassesTest(NoopQuotaClassesTest):
|
||||||
# TODO(johngarbutt) we should be proxying to keystone
|
# TODO(johngarbutt) we should be proxying to keystone
|
||||||
self.assertEqual(0, mock_update.call_count)
|
self.assertEqual(0, mock_update.call_count)
|
||||||
|
|
||||||
|
@mock.patch.object(placement_limit, "get_legacy_default_limits")
|
||||||
@mock.patch.object(objects.Quotas, "update_class")
|
@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')
|
req = fakes.HTTPRequest.blank("", version='2.57')
|
||||||
body = {'quota_class_set': {'ram': 51200}}
|
body = {'quota_class_set': {'ram': 51200}}
|
||||||
response = self.controller.update(req, 'default', body=body)
|
response = self.controller.update(req, 'default', body=body)
|
||||||
expected_response = {
|
expected_response = {
|
||||||
'quota_class_set': {
|
'quota_class_set': {
|
||||||
'cores': -1,
|
'cores': 2,
|
||||||
'instances': -1,
|
'instances': 1,
|
||||||
'ram': -1,
|
'ram': 3,
|
||||||
'key_pairs': 100,
|
'key_pairs': 100,
|
||||||
'metadata_items': 128,
|
'metadata_items': 128,
|
||||||
'server_group_members': 10,
|
'server_group_members': 10,
|
||||||
|
|
|
@ -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.db import constants as db_const
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova.limit import local as local_limit
|
from nova.limit import local as local_limit
|
||||||
|
from nova.limit import placement as placement_limit
|
||||||
from nova import objects
|
from nova import objects
|
||||||
from nova import quota
|
from nova import quota
|
||||||
from nova import test
|
from nova import test
|
||||||
|
@ -869,7 +870,8 @@ class NoopQuotaSetsTest(test.NoDBTestCase):
|
||||||
|
|
||||||
class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
|
class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
|
||||||
quota_driver = "nova.quota.UnifiedLimitsDriver"
|
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):
|
def setUp(self):
|
||||||
super(UnifiedLimitsQuotaSetsTest, self).setUp()
|
super(UnifiedLimitsQuotaSetsTest, self).setUp()
|
||||||
|
@ -882,22 +884,24 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
|
||||||
local_limit.SERVER_GROUP_MEMBERS: 10}
|
local_limit.SERVER_GROUP_MEMBERS: 10}
|
||||||
self.useFixture(limit_fixture.LimitFixture(reglimits, {}))
|
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("")
|
req = fakes.HTTPRequest.blank("")
|
||||||
response = self.controller.show(req, uuids.project_id)
|
response = self.controller.show(req, uuids.project_id)
|
||||||
expected_response = {
|
expected_response = {
|
||||||
'quota_set': {
|
'quota_set': {
|
||||||
'id': uuids.project_id,
|
'id': uuids.project_id,
|
||||||
'cores': -1,
|
'cores': 2,
|
||||||
'fixed_ips': -1,
|
'fixed_ips': -1,
|
||||||
'floating_ips': -1,
|
'floating_ips': -1,
|
||||||
'injected_file_content_bytes': 10240,
|
'injected_file_content_bytes': 10240,
|
||||||
'injected_file_path_bytes': 255,
|
'injected_file_path_bytes': 255,
|
||||||
'injected_files': 5,
|
'injected_files': 5,
|
||||||
'instances': -1,
|
'instances': 1,
|
||||||
'key_pairs': 100,
|
'key_pairs': 100,
|
||||||
'metadata_items': 128,
|
'metadata_items': 128,
|
||||||
'ram': -1,
|
'ram': 3,
|
||||||
'security_group_rules': -1,
|
'security_group_rules': -1,
|
||||||
'security_groups': -1,
|
'security_groups': -1,
|
||||||
'server_group_members': 10,
|
'server_group_members': 10,
|
||||||
|
@ -906,30 +910,37 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
|
||||||
}
|
}
|
||||||
self.assertEqual(expected_response, response)
|
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')
|
req = fakes.HTTPRequest.blank("", version='2.57')
|
||||||
response = self.controller.show(req, uuids.project_id)
|
response = self.controller.show(req, uuids.project_id)
|
||||||
expected_response = {
|
expected_response = {
|
||||||
'quota_set': {
|
'quota_set': {
|
||||||
'id': uuids.project_id,
|
'id': uuids.project_id,
|
||||||
'cores': -1,
|
'cores': 2,
|
||||||
'instances': -1,
|
'instances': 1,
|
||||||
'key_pairs': 100,
|
'key_pairs': 100,
|
||||||
'metadata_items': 128,
|
'metadata_items': 128,
|
||||||
'ram': -1,
|
'ram': 3,
|
||||||
'server_group_members': 10,
|
'server_group_members': 10,
|
||||||
'server_groups': 12}}
|
'server_groups': 12}}
|
||||||
self.assertEqual(expected_response, response)
|
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")
|
@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}}
|
mock_count.return_value = {'project': {'server_groups': 9}}
|
||||||
req = fakes.HTTPRequest.blank("")
|
req = fakes.HTTPRequest.blank("")
|
||||||
response = self.controller.detail(req, uuids.project_id)
|
response = self.controller.detail(req, uuids.project_id)
|
||||||
expected_response = {
|
expected_response = {
|
||||||
'quota_set': {
|
'quota_set': {
|
||||||
'id': uuids.project_id,
|
'id': uuids.project_id,
|
||||||
'cores': self.expected_detail,
|
'cores': {
|
||||||
|
'in_use': 5, 'limit': 2, 'reserved': 0},
|
||||||
'fixed_ips': self.expected_detail,
|
'fixed_ips': self.expected_detail,
|
||||||
'floating_ips': self.expected_detail,
|
'floating_ips': self.expected_detail,
|
||||||
'injected_file_content_bytes': {
|
'injected_file_content_bytes': {
|
||||||
|
@ -938,12 +949,14 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
|
||||||
'in_use': 0, 'limit': 255, 'reserved': 0},
|
'in_use': 0, 'limit': 255, 'reserved': 0},
|
||||||
'injected_files': {
|
'injected_files': {
|
||||||
'in_use': 0, 'limit': 5, 'reserved': 0},
|
'in_use': 0, 'limit': 5, 'reserved': 0},
|
||||||
'instances': self.expected_detail,
|
'instances': {
|
||||||
|
'in_use': 4, 'limit': 1, 'reserved': 0},
|
||||||
'key_pairs': {
|
'key_pairs': {
|
||||||
'in_use': 0, 'limit': 100, 'reserved': 0},
|
'in_use': 0, 'limit': 100, 'reserved': 0},
|
||||||
'metadata_items': {
|
'metadata_items': {
|
||||||
'in_use': 0, 'limit': 128, 'reserved': 0},
|
'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_group_rules': self.expected_detail,
|
||||||
'security_groups': self.expected_detail,
|
'security_groups': self.expected_detail,
|
||||||
'server_group_members': {
|
'server_group_members': {
|
||||||
|
@ -954,15 +967,20 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
|
||||||
}
|
}
|
||||||
self.assertEqual(expected_response, response)
|
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")
|
@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}}
|
mock_count.return_value = {'project': {'server_groups': 9}}
|
||||||
req = fakes.HTTPRequest.blank("?user_id=42")
|
req = fakes.HTTPRequest.blank("?user_id=42")
|
||||||
response = self.controller.detail(req, uuids.project_id)
|
response = self.controller.detail(req, uuids.project_id)
|
||||||
expected_response = {
|
expected_response = {
|
||||||
'quota_set': {
|
'quota_set': {
|
||||||
'id': uuids.project_id,
|
'id': uuids.project_id,
|
||||||
'cores': self.expected_detail,
|
'cores': {
|
||||||
|
'in_use': 5, 'limit': 2, 'reserved': 0},
|
||||||
'fixed_ips': self.expected_detail,
|
'fixed_ips': self.expected_detail,
|
||||||
'floating_ips': self.expected_detail,
|
'floating_ips': self.expected_detail,
|
||||||
'injected_file_content_bytes': {
|
'injected_file_content_bytes': {
|
||||||
|
@ -971,12 +989,14 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
|
||||||
'in_use': 0, 'limit': 255, 'reserved': 0},
|
'in_use': 0, 'limit': 255, 'reserved': 0},
|
||||||
'injected_files': {
|
'injected_files': {
|
||||||
'in_use': 0, 'limit': 5, 'reserved': 0},
|
'in_use': 0, 'limit': 5, 'reserved': 0},
|
||||||
'instances': self.expected_detail,
|
'instances': {
|
||||||
|
'in_use': 4, 'limit': 1, 'reserved': 0},
|
||||||
'key_pairs': {
|
'key_pairs': {
|
||||||
'in_use': 0, 'limit': 100, 'reserved': 0},
|
'in_use': 0, 'limit': 100, 'reserved': 0},
|
||||||
'metadata_items': {
|
'metadata_items': {
|
||||||
'in_use': 0, 'limit': 128, 'reserved': 0},
|
'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_group_rules': self.expected_detail,
|
||||||
'security_groups': self.expected_detail,
|
'security_groups': self.expected_detail,
|
||||||
'server_group_members': {
|
'server_group_members': {
|
||||||
|
@ -987,24 +1007,26 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
|
||||||
}
|
}
|
||||||
self.assertEqual(expected_response, response)
|
self.assertEqual(expected_response, response)
|
||||||
|
|
||||||
|
@mock.patch.object(placement_limit, "get_legacy_project_limits")
|
||||||
@mock.patch.object(objects.Quotas, "create_limit")
|
@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("")
|
req = fakes.HTTPRequest.blank("")
|
||||||
# TODO(johngarbutt) still need to implement get_settable_quotas
|
# TODO(johngarbutt) still need to implement get_settable_quotas
|
||||||
body = {'quota_set': {'server_groups': 2}}
|
body = {'quota_set': {'server_groups': 2}}
|
||||||
response = self.controller.update(req, uuids.project_id, body=body)
|
response = self.controller.update(req, uuids.project_id, body=body)
|
||||||
expected_response = {
|
expected_response = {
|
||||||
'quota_set': {
|
'quota_set': {
|
||||||
'cores': -1,
|
'cores': 2,
|
||||||
'fixed_ips': -1,
|
'fixed_ips': -1,
|
||||||
'floating_ips': -1,
|
'floating_ips': -1,
|
||||||
'injected_file_content_bytes': 10240,
|
'injected_file_content_bytes': 10240,
|
||||||
'injected_file_path_bytes': 255,
|
'injected_file_path_bytes': 255,
|
||||||
'injected_files': 5,
|
'injected_files': 5,
|
||||||
'instances': -1,
|
'instances': 1,
|
||||||
'key_pairs': 100,
|
'key_pairs': 100,
|
||||||
'metadata_items': 128,
|
'metadata_items': 128,
|
||||||
'ram': -1,
|
'ram': 3,
|
||||||
'security_group_rules': -1,
|
'security_group_rules': -1,
|
||||||
'security_groups': -1,
|
'security_groups': -1,
|
||||||
'server_group_members': 10,
|
'server_group_members': 10,
|
||||||
|
@ -1014,23 +1036,25 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
|
||||||
self.assertEqual(expected_response, response)
|
self.assertEqual(expected_response, response)
|
||||||
self.assertEqual(0, mock_create.call_count)
|
self.assertEqual(0, mock_create.call_count)
|
||||||
|
|
||||||
|
@mock.patch.object(placement_limit, "get_legacy_project_limits")
|
||||||
@mock.patch.object(objects.Quotas, "create_limit")
|
@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")
|
req = fakes.HTTPRequest.blank("?user_id=42")
|
||||||
body = {'quota_set': {'key_pairs': 52}}
|
body = {'quota_set': {'key_pairs': 52}}
|
||||||
response = self.controller.update(req, uuids.project_id, body=body)
|
response = self.controller.update(req, uuids.project_id, body=body)
|
||||||
expected_response = {
|
expected_response = {
|
||||||
'quota_set': {
|
'quota_set': {
|
||||||
'cores': -1,
|
'cores': 2,
|
||||||
'fixed_ips': -1,
|
'fixed_ips': -1,
|
||||||
'floating_ips': -1,
|
'floating_ips': -1,
|
||||||
'injected_file_content_bytes': 10240,
|
'injected_file_content_bytes': 10240,
|
||||||
'injected_file_path_bytes': 255,
|
'injected_file_path_bytes': 255,
|
||||||
'injected_files': 5,
|
'injected_files': 5,
|
||||||
'instances': -1,
|
'instances': 1,
|
||||||
'key_pairs': 100,
|
'key_pairs': 100,
|
||||||
'metadata_items': 128,
|
'metadata_items': 128,
|
||||||
'ram': -1,
|
'ram': 3,
|
||||||
'security_group_rules': -1,
|
'security_group_rules': -1,
|
||||||
'security_groups': -1,
|
'security_groups': -1,
|
||||||
'server_group_members': 10,
|
'server_group_members': 10,
|
||||||
|
@ -1040,22 +1064,24 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
|
||||||
self.assertEqual(expected_response, response)
|
self.assertEqual(expected_response, response)
|
||||||
self.assertEqual(0, mock_create.call_count)
|
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("")
|
req = fakes.HTTPRequest.blank("")
|
||||||
response = self.controller.defaults(req, uuids.project_id)
|
response = self.controller.defaults(req, uuids.project_id)
|
||||||
expected_response = {
|
expected_response = {
|
||||||
'quota_set': {
|
'quota_set': {
|
||||||
'id': uuids.project_id,
|
'id': uuids.project_id,
|
||||||
'cores': -1,
|
'cores': 2,
|
||||||
'fixed_ips': -1,
|
'fixed_ips': -1,
|
||||||
'floating_ips': -1,
|
'floating_ips': -1,
|
||||||
'injected_file_content_bytes': 10240,
|
'injected_file_content_bytes': 10240,
|
||||||
'injected_file_path_bytes': 255,
|
'injected_file_path_bytes': 255,
|
||||||
'injected_files': 5,
|
'injected_files': 5,
|
||||||
'instances': -1,
|
'instances': 1,
|
||||||
'key_pairs': 100,
|
'key_pairs': 100,
|
||||||
'metadata_items': 128,
|
'metadata_items': 128,
|
||||||
'ram': -1,
|
'ram': 3,
|
||||||
'security_group_rules': -1,
|
'security_group_rules': -1,
|
||||||
'security_groups': -1,
|
'security_groups': -1,
|
||||||
'server_group_members': 10,
|
'server_group_members': 10,
|
||||||
|
@ -1079,16 +1105,16 @@ class UnifiedLimitsQuotaSetsTest(NoopQuotaSetsTest):
|
||||||
expected_response = {
|
expected_response = {
|
||||||
'quota_set': {
|
'quota_set': {
|
||||||
'id': uuids.project_id,
|
'id': uuids.project_id,
|
||||||
'cores': -1,
|
'cores': 0,
|
||||||
'fixed_ips': -1,
|
'fixed_ips': -1,
|
||||||
'floating_ips': -1,
|
'floating_ips': -1,
|
||||||
'injected_file_content_bytes': 4,
|
'injected_file_content_bytes': 4,
|
||||||
'injected_file_path_bytes': 5,
|
'injected_file_path_bytes': 5,
|
||||||
'injected_files': 6,
|
'injected_files': 6,
|
||||||
'instances': -1,
|
'instances': 0,
|
||||||
'key_pairs': 1,
|
'key_pairs': 1,
|
||||||
'metadata_items': 7,
|
'metadata_items': 7,
|
||||||
'ram': -1,
|
'ram': 0,
|
||||||
'security_group_rules': -1,
|
'security_group_rules': -1,
|
||||||
'security_groups': -1,
|
'security_groups': -1,
|
||||||
'server_group_members': 2,
|
'server_group_members': 2,
|
||||||
|
|
|
@ -26,6 +26,7 @@ from nova import context
|
||||||
from nova.db.main import models
|
from nova.db.main import models
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova.limit import local as local_limit
|
from nova.limit import local as local_limit
|
||||||
|
from nova.limit import placement as placement_limit
|
||||||
from nova import objects
|
from nova import objects
|
||||||
from nova import quota
|
from nova import quota
|
||||||
from nova import test
|
from nova import test
|
||||||
|
@ -1990,101 +1991,109 @@ class UnifiedLimitsDriverTestCase(NoopQuotaDriverTestCase):
|
||||||
self.useFixture(limit_fixture.LimitFixture(reglimits, {}))
|
self.useFixture(limit_fixture.LimitFixture(reglimits, {}))
|
||||||
|
|
||||||
self.expected_without_dict = {
|
self.expected_without_dict = {
|
||||||
'cores': -1,
|
'cores': 2,
|
||||||
'fixed_ips': -1,
|
'fixed_ips': -1,
|
||||||
'floating_ips': -1,
|
'floating_ips': -1,
|
||||||
'injected_file_content_bytes': 10240,
|
'injected_file_content_bytes': 10240,
|
||||||
'injected_file_path_bytes': 255,
|
'injected_file_path_bytes': 255,
|
||||||
'injected_files': 5,
|
'injected_files': 5,
|
||||||
'instances': -1,
|
'instances': 1,
|
||||||
'key_pairs': 100,
|
'key_pairs': 100,
|
||||||
'metadata_items': 128,
|
'metadata_items': 128,
|
||||||
'ram': -1,
|
'ram': 0,
|
||||||
'security_group_rules': -1,
|
'security_group_rules': -1,
|
||||||
'security_groups': -1,
|
'security_groups': -1,
|
||||||
'server_group_members': 10,
|
'server_group_members': 10,
|
||||||
'server_groups': 12,
|
'server_groups': 12,
|
||||||
}
|
}
|
||||||
self.expected_without_usages = {
|
self.expected_without_usages = {
|
||||||
'cores': {'limit': -1},
|
'cores': {'limit': 2},
|
||||||
'fixed_ips': {'limit': -1},
|
'fixed_ips': {'limit': -1},
|
||||||
'floating_ips': {'limit': -1},
|
'floating_ips': {'limit': -1},
|
||||||
'injected_file_content_bytes': {'limit': 10240},
|
'injected_file_content_bytes': {'limit': 10240},
|
||||||
'injected_file_path_bytes': {'limit': 255},
|
'injected_file_path_bytes': {'limit': 255},
|
||||||
'injected_files': {'limit': 5},
|
'injected_files': {'limit': 5},
|
||||||
'instances': {'limit': -1},
|
'instances': {'limit': 1},
|
||||||
'key_pairs': {'limit': 100},
|
'key_pairs': {'limit': 100},
|
||||||
'metadata_items': {'limit': 128},
|
'metadata_items': {'limit': 128},
|
||||||
'ram': {'limit': -1},
|
'ram': {'limit': 3},
|
||||||
'security_group_rules': {'limit': -1},
|
'security_group_rules': {'limit': -1},
|
||||||
'security_groups': {'limit': -1},
|
'security_groups': {'limit': -1},
|
||||||
'server_group_members': {'limit': 10},
|
'server_group_members': {'limit': 10},
|
||||||
'server_groups': {'limit': 12}
|
'server_groups': {'limit': 12}
|
||||||
}
|
}
|
||||||
self.expected_with_usages = {
|
self.expected_with_usages = {
|
||||||
'cores': {'in_use': -1, 'limit': -1},
|
'cores': {'in_use': 5, 'limit': 2},
|
||||||
'fixed_ips': {'in_use': -1, 'limit': -1},
|
'fixed_ips': {'in_use': 0, 'limit': -1},
|
||||||
'floating_ips': {'in_use': -1, 'limit': -1},
|
'floating_ips': {'in_use': 0, 'limit': -1},
|
||||||
'injected_file_content_bytes': {'in_use': 0, 'limit': 10240},
|
'injected_file_content_bytes': {'in_use': 0, 'limit': 10240},
|
||||||
'injected_file_path_bytes': {'in_use': 0, 'limit': 255},
|
'injected_file_path_bytes': {'in_use': 0, 'limit': 255},
|
||||||
'injected_files': {'in_use': 0, 'limit': 5},
|
'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},
|
'key_pairs': {'in_use': 0, 'limit': 100},
|
||||||
'metadata_items': {'in_use': 0, 'limit': 128},
|
'metadata_items': {'in_use': 0, 'limit': 128},
|
||||||
'ram': {'in_use': -1, 'limit': -1},
|
'ram': {'in_use': 6, 'limit': 3},
|
||||||
'security_group_rules': {'in_use': -1, 'limit': -1},
|
'security_group_rules': {'in_use': 0, 'limit': -1},
|
||||||
'security_groups': {'in_use': -1, 'limit': -1},
|
'security_groups': {'in_use': 0, 'limit': -1},
|
||||||
'server_group_members': {'in_use': 0, 'limit': 10},
|
'server_group_members': {'in_use': 0, 'limit': 10},
|
||||||
'server_groups': {'in_use': 9, 'limit': 12}
|
'server_groups': {'in_use': 9, 'limit': 12}
|
||||||
}
|
}
|
||||||
|
|
||||||
def test_get_class_quotas(self):
|
@mock.patch.object(placement_limit, "get_legacy_default_limits")
|
||||||
result = self.driver.get_class_quotas(
|
def test_get_defaults(self, mock_default):
|
||||||
None, quota.QUOTAS._resources, 'default')
|
# zero for ram simulates no registered limit for ram
|
||||||
expected_limits = {
|
mock_default.return_value = {"instances": 1, "cores": 2, "ram": 0}
|
||||||
'cores': -1,
|
result = self.driver.get_defaults(None, quota.QUOTAS._resources)
|
||||||
'fixed_ips': -1,
|
self.assertEqual(self.expected_without_dict, result)
|
||||||
'floating_ips': -1,
|
mock_default.assert_called_once_with()
|
||||||
'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_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")
|
@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}}
|
mock_count.return_value = {'project': {'server_groups': 9}}
|
||||||
result = self.driver.get_project_quotas(
|
result = self.driver.get_project_quotas(
|
||||||
None, quota.QUOTAS._resources, 'test_project')
|
None, quota.QUOTAS._resources, 'test_project')
|
||||||
self.assertEqual(self.expected_with_usages, result)
|
self.assertEqual(self.expected_with_usages, result)
|
||||||
mock_count.assert_called_once_with(None, "test_project")
|
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")
|
@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(
|
result = self.driver.get_project_quotas(
|
||||||
None, quota.QUOTAS._resources, 'test_project', usages=False)
|
None, quota.QUOTAS._resources, 'test_project', usages=False)
|
||||||
self.assertEqual(self.expected_without_usages, result)
|
self.assertEqual(self.expected_without_usages, result)
|
||||||
# ensure usages not fetched when not required
|
# ensure usages not fetched when not required
|
||||||
self.assertEqual(0, mock_count.call_count)
|
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")
|
@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}}
|
mock_count.return_value = {'project': {'server_groups': 9}}
|
||||||
result = self.driver.get_user_quotas(
|
result = self.driver.get_user_quotas(
|
||||||
None, quota.QUOTAS._resources, 'test_project', 'fake_user')
|
None, quota.QUOTAS._resources, 'test_project', 'fake_user')
|
||||||
self.assertEqual(self.expected_with_usages, result)
|
self.assertEqual(self.expected_with_usages, result)
|
||||||
mock_count.assert_called_once_with(None, "test_project")
|
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")
|
@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(
|
result = self.driver.get_user_quotas(
|
||||||
None, quota.QUOTAS._resources, 'test_project', 'fake_user',
|
None, quota.QUOTAS._resources, 'test_project', 'fake_user',
|
||||||
usages=False)
|
usages=False)
|
||||||
|
|
Loading…
Reference in New Issue