Improve the quota check
- Check alarm quota by considering the quota setting in DB. - Add more unit tests for quota API. Change-Id: I1af381f357b0d80f68e3ead16e158428b7a14555
This commit is contained in:
parent
223178716e
commit
90a7c6eab2
@ -105,18 +105,24 @@ def is_over_quota(conn, project_id, user_id):
|
||||
|
||||
over_quota = False
|
||||
|
||||
# Start by checking for user quota
|
||||
user_alarm_quota = pecan.request.cfg.api.user_alarm_quota
|
||||
if user_alarm_quota != -1:
|
||||
user_alarms = conn.get_alarms(user_id=user_id)
|
||||
over_quota = len(user_alarms) >= user_alarm_quota
|
||||
project_quotas = conn.get_quotas(project_id)
|
||||
project_alarms = conn.get_alarms(project_id=project_id)
|
||||
user_alarms = conn.get_alarms(user_id=user_id)
|
||||
user_default_alarm_quota = pecan.request.cfg.api.user_alarm_quota
|
||||
project_default_alarm_quota = pecan.request.cfg.api.project_alarm_quota
|
||||
|
||||
# If the user quota isn't reached, we check for the project quota
|
||||
if not over_quota:
|
||||
project_alarm_quota = pecan.request.cfg.api.project_alarm_quota
|
||||
if project_alarm_quota != -1:
|
||||
project_alarms = conn.get_alarms(project_id=project_id)
|
||||
over_quota = len(project_alarms) >= project_alarm_quota
|
||||
# 1. Check project quota
|
||||
if len(project_quotas) > 0:
|
||||
for quota in project_quotas:
|
||||
if quota.resource == 'alarms':
|
||||
over_quota = len(user_alarms) >= quota.limit
|
||||
else:
|
||||
if project_default_alarm_quota != -1:
|
||||
over_quota = len(project_alarms) >= project_default_alarm_quota
|
||||
|
||||
# 2. Check user quota
|
||||
if not over_quota and user_default_alarm_quota != -1:
|
||||
over_quota = len(user_alarms) >= user_default_alarm_quota
|
||||
|
||||
return over_quota
|
||||
|
||||
|
@ -28,7 +28,7 @@ ALLOWED_RESOURCES = ('alarms',)
|
||||
class Quota(base.Base):
|
||||
resource = wtypes.wsattr(wtypes.Enum(str, *ALLOWED_RESOURCES),
|
||||
mandatory=True)
|
||||
limit = wtypes.IntegerType(minimum=-1)
|
||||
limit = wsme.wsattr(wtypes.IntegerType(minimum=-1), mandatory=True)
|
||||
|
||||
|
||||
class Quotas(base.Base):
|
||||
@ -79,6 +79,6 @@ class QuotasController(rest.RestController):
|
||||
input_quotas.append(i.to_dict())
|
||||
|
||||
db_quotas = pecan.request.storage.set_quotas(project_id, input_quotas)
|
||||
|
||||
quotas = [Quota.from_db_model(i) for i in db_quotas]
|
||||
|
||||
return Quotas(project_id=project_id, quotas=quotas)
|
||||
|
@ -127,8 +127,10 @@ class TestAlarmsBase(v2.FunctionalTest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestAlarmsBase, self).setUp()
|
||||
self.auth_headers = {'X-User-Id': uuidutils.generate_uuid(),
|
||||
'X-Project-Id': uuidutils.generate_uuid()}
|
||||
self.project_id = uuidutils.generate_uuid()
|
||||
self.user_id = uuidutils.generate_uuid()
|
||||
self.auth_headers = {'X-User-Id': self.user_id,
|
||||
'X-Project-Id': self.project_id}
|
||||
|
||||
c = mock.Mock()
|
||||
c.capabilities.list.return_value = {'aggregation_methods': [
|
||||
@ -1955,13 +1957,13 @@ class TestAlarmsHistory(TestAlarmsBase):
|
||||
|
||||
|
||||
class TestAlarmsQuotas(TestAlarmsBase):
|
||||
|
||||
def _test_alarm_quota(self):
|
||||
alarm = {
|
||||
def setUp(self):
|
||||
super(TestAlarmsQuotas, self).setUp()
|
||||
self.alarm = {
|
||||
'name': 'alarm',
|
||||
'type': 'gnocchi_aggregation_by_metrics_threshold',
|
||||
'user_id': self.auth_headers['X-User-Id'],
|
||||
'project_id': self.auth_headers['X-Project-Id'],
|
||||
'user_id': self.user_id,
|
||||
'project_id': self.project_id,
|
||||
RULE_KEY: {
|
||||
'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
|
||||
'a1fb80f4-c242-4f57-87c6-68f47521059e'],
|
||||
@ -1973,17 +1975,29 @@ class TestAlarmsQuotas(TestAlarmsBase):
|
||||
}
|
||||
}
|
||||
|
||||
def _create_alarm(self, alarm=None):
|
||||
if not alarm:
|
||||
alarm = self.alarm
|
||||
|
||||
resp = self.post_json('/alarms', params=alarm,
|
||||
headers=self.auth_headers)
|
||||
self.assertEqual(201, resp.status_code)
|
||||
headers=self.auth_headers,
|
||||
status=201)
|
||||
|
||||
return resp
|
||||
|
||||
def _test_alarm_quota(self):
|
||||
"""Failed on the second creation."""
|
||||
resp = self._create_alarm()
|
||||
|
||||
alarms = self.get_json('/alarms', headers=self.auth_headers)
|
||||
self.assertEqual(1, len(alarms))
|
||||
|
||||
alarm = copy.copy(self.alarm)
|
||||
alarm['name'] = 'another_user_alarm'
|
||||
resp = self.post_json('/alarms', params=alarm,
|
||||
expect_errors=True,
|
||||
headers=self.auth_headers)
|
||||
self.assertEqual(403, resp.status_code)
|
||||
headers=self.auth_headers,
|
||||
status=403)
|
||||
faultstring = 'Alarm quota exceeded for user'
|
||||
self.assertIn(faultstring,
|
||||
resp.json['error_message']['faultstring'])
|
||||
@ -2063,6 +2077,83 @@ class TestAlarmsQuotas(TestAlarmsBase):
|
||||
alarms = self.get_json('/alarms', headers=self.auth_headers)
|
||||
self.assertEqual(1, len(alarms))
|
||||
|
||||
def test_overquota_by_quota_api(self):
|
||||
auth_headers = copy.copy(self.auth_headers)
|
||||
auth_headers['X-Roles'] = 'admin'
|
||||
|
||||
# Update project quota.
|
||||
self.post_json(
|
||||
'/quotas',
|
||||
{
|
||||
"project_id": self.project_id,
|
||||
"quotas": [
|
||||
{
|
||||
"resource": "alarms",
|
||||
"limit": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
headers=auth_headers,
|
||||
status=201
|
||||
)
|
||||
|
||||
self._test_alarm_quota()
|
||||
|
||||
# Update project quota back
|
||||
self.post_json(
|
||||
'/quotas',
|
||||
{
|
||||
"project_id": self.project_id,
|
||||
"quotas": [
|
||||
{
|
||||
"resource": "alarms",
|
||||
"limit": -1
|
||||
}
|
||||
]
|
||||
},
|
||||
headers=auth_headers,
|
||||
status=201
|
||||
)
|
||||
|
||||
def test_overquota_by_user_quota_config(self):
|
||||
self.CONF.set_override('user_alarm_quota', 1, 'api')
|
||||
auth_headers = copy.copy(self.auth_headers)
|
||||
auth_headers['X-Roles'] = 'admin'
|
||||
|
||||
# Update project quota.
|
||||
self.post_json(
|
||||
'/quotas',
|
||||
{
|
||||
"project_id": self.project_id,
|
||||
"quotas": [
|
||||
{
|
||||
"resource": "alarms",
|
||||
"limit": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
headers=auth_headers,
|
||||
status=201
|
||||
)
|
||||
|
||||
self._test_alarm_quota()
|
||||
|
||||
# Update project quota back
|
||||
self.post_json(
|
||||
'/quotas',
|
||||
{
|
||||
"project_id": self.project_id,
|
||||
"quotas": [
|
||||
{
|
||||
"resource": "alarms",
|
||||
"limit": -1
|
||||
}
|
||||
]
|
||||
},
|
||||
headers=auth_headers,
|
||||
status=201
|
||||
)
|
||||
|
||||
|
||||
class TestAlarmsRuleThreshold(TestAlarmsBase):
|
||||
|
||||
|
@ -100,3 +100,93 @@ class TestQuotas(v2.FunctionalTest):
|
||||
expect_errors=True,
|
||||
status=403
|
||||
)
|
||||
|
||||
def test_post_quotas_no_limit_failed(self):
|
||||
auth_headers = copy.copy(self.auth_headers)
|
||||
auth_headers['X-Roles'] = 'admin'
|
||||
|
||||
resp = self.post_json(
|
||||
'/quotas',
|
||||
{
|
||||
"project_id": self.project,
|
||||
"quotas": [
|
||||
{
|
||||
"resource": "alarms"
|
||||
}
|
||||
]
|
||||
},
|
||||
headers=auth_headers,
|
||||
expect_errors=True,
|
||||
status=400
|
||||
)
|
||||
|
||||
self.assertIn('Mandatory field missing',
|
||||
resp.json['error_message']['faultstring'])
|
||||
|
||||
def test_post_quotas_no_resource_failed(self):
|
||||
auth_headers = copy.copy(self.auth_headers)
|
||||
auth_headers['X-Roles'] = 'admin'
|
||||
|
||||
resp = self.post_json(
|
||||
'/quotas',
|
||||
{
|
||||
"project_id": self.project,
|
||||
"quotas": [
|
||||
{
|
||||
"limit": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
headers=auth_headers,
|
||||
expect_errors=True,
|
||||
status=400
|
||||
)
|
||||
|
||||
self.assertIn('Mandatory field missing',
|
||||
resp.json['error_message']['faultstring'])
|
||||
|
||||
def test_post_quotas_wrong_limit_failed(self):
|
||||
auth_headers = copy.copy(self.auth_headers)
|
||||
auth_headers['X-Roles'] = 'admin'
|
||||
|
||||
resp = self.post_json(
|
||||
'/quotas',
|
||||
{
|
||||
"project_id": self.project,
|
||||
"quotas": [
|
||||
{
|
||||
"resource": "alarms",
|
||||
"limit": -5
|
||||
}
|
||||
]
|
||||
},
|
||||
headers=auth_headers,
|
||||
expect_errors=True,
|
||||
status=400
|
||||
)
|
||||
|
||||
self.assertIn('Value should be greater or equal to -1',
|
||||
resp.json['error_message']['faultstring'])
|
||||
|
||||
def test_post_quotas_unsupported_resource_failed(self):
|
||||
auth_headers = copy.copy(self.auth_headers)
|
||||
auth_headers['X-Roles'] = 'admin'
|
||||
|
||||
resp = self.post_json(
|
||||
'/quotas',
|
||||
{
|
||||
"project_id": self.project,
|
||||
"quotas": [
|
||||
{
|
||||
"resource": "other_resource",
|
||||
"limit": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
headers=auth_headers,
|
||||
expect_errors=True,
|
||||
status=400
|
||||
)
|
||||
|
||||
self.assertIn('Value should be one of',
|
||||
resp.json['error_message']['faultstring'])
|
||||
|
Loading…
Reference in New Issue
Block a user