Merge "Adding quotas on alarms"
This commit is contained in:
commit
9af6af5e52
@ -65,6 +65,14 @@ ALARM_API_OPTS = [
|
||||
default=True,
|
||||
help='Record alarm change events.'
|
||||
),
|
||||
cfg.IntOpt('user_alarm_quota',
|
||||
default=None,
|
||||
help='Maximum number of alarms defined for a user.'
|
||||
),
|
||||
cfg.IntOpt('project_alarm_quota',
|
||||
default=None,
|
||||
help='Maximum number of alarms defined for a project.'
|
||||
),
|
||||
]
|
||||
|
||||
cfg.CONF.register_opts(ALARM_API_OPTS, group='alarm')
|
||||
@ -99,6 +107,43 @@ class AlarmNotFound(ClientSideError):
|
||||
super(AlarmNotFound, self).__init__(msg, status_code=404)
|
||||
|
||||
|
||||
class OverQuota(ClientSideError):
|
||||
def __init__(self, data):
|
||||
d = {
|
||||
'u': data.user_id,
|
||||
'p': data.project_id
|
||||
}
|
||||
super(OverQuota, self).__init__(
|
||||
_("Alarm quota exceeded for user %(u)s on project %(p)s") % d,
|
||||
status_code=403)
|
||||
|
||||
|
||||
def is_over_quota(conn, project_id, user_id):
|
||||
"""Returns False if an alarm is within the set quotas, True otherwise.
|
||||
|
||||
:param conn: a backend connection object
|
||||
:param project_id: the ID of the project setting the alarm
|
||||
:param user_id: the ID of the user setting the alarm
|
||||
"""
|
||||
|
||||
over_quota = False
|
||||
|
||||
# Start by checking for user quota
|
||||
user_alarm_quota = cfg.CONF.alarm.user_alarm_quota
|
||||
if user_alarm_quota is not None:
|
||||
user_alarms = list(conn.get_alarms(user=user_id))
|
||||
over_quota = len(user_alarms) >= user_alarm_quota
|
||||
|
||||
# If the user quota isn't reached, we check for the project quota
|
||||
if not over_quota:
|
||||
project_alarm_quota = cfg.CONF.alarm.project_alarm_quota
|
||||
if project_alarm_quota is not None:
|
||||
project_alarms = list(conn.get_alarms(project=project_id))
|
||||
over_quota = len(project_alarms) >= project_alarm_quota
|
||||
|
||||
return over_quota
|
||||
|
||||
|
||||
class AdvEnum(wtypes.wsproperty):
|
||||
"""Handle default and mandatory for wtypes.Enum."""
|
||||
def __init__(self, name, *args, **kwargs):
|
||||
@ -2106,6 +2151,10 @@ class AlarmsController(rest.RestController):
|
||||
_set_ownership('user', user_limit, 'X-User-Id')
|
||||
_set_ownership('project', project_limit, 'X-Project-Id')
|
||||
|
||||
# Check if there's room for one more alarm
|
||||
if is_over_quota(conn, data.project_id, data.user_id):
|
||||
raise OverQuota(data)
|
||||
|
||||
data.timestamp = now
|
||||
data.state_timestamp = now
|
||||
|
||||
|
@ -2001,3 +2001,118 @@ class TestAlarms(v2.FunctionalTest,
|
||||
self.assertTrue(set(['alarm_id', 'detail', 'event_id', 'on_behalf_of',
|
||||
'project_id', 'timestamp', 'type',
|
||||
'user_id']).issubset(payload.keys()))
|
||||
|
||||
|
||||
class TestAlarmsQuotas(v2.FunctionalTest,
|
||||
tests_db.MixinTestsWithBackendScenarios):
|
||||
|
||||
def setUp(self):
|
||||
super(TestAlarmsQuotas, self).setUp()
|
||||
|
||||
self.auth_headers = {'X-User-Id': str(uuid.uuid4()),
|
||||
'X-Project-Id': str(uuid.uuid4())}
|
||||
|
||||
def _test_alarm_quota(self):
|
||||
alarm = {
|
||||
'name': 'alarm',
|
||||
'type': 'threshold',
|
||||
'user_id': self.auth_headers['X-User-Id'],
|
||||
'project_id': self.auth_headers['X-Project-Id'],
|
||||
'threshold_rule': {
|
||||
'meter_name': 'testmeter',
|
||||
'query': [],
|
||||
'comparison_operator': 'le',
|
||||
'statistic': 'max',
|
||||
'threshold': 42.0,
|
||||
'period': 60,
|
||||
'evaluation_periods': 1,
|
||||
}
|
||||
}
|
||||
|
||||
resp = self.post_json('/alarms', params=alarm,
|
||||
headers=self.auth_headers)
|
||||
self.assertEqual(201, resp.status_code)
|
||||
alarms = self.get_json('/alarms')
|
||||
self.assertEqual(1, len(alarms))
|
||||
|
||||
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)
|
||||
faultstring = 'Alarm quota exceeded for user'
|
||||
self.assertIn(faultstring,
|
||||
resp.json['error_message']['faultstring'])
|
||||
|
||||
alarms = self.get_json('/alarms')
|
||||
self.assertEqual(1, len(alarms))
|
||||
|
||||
def test_alarms_quotas(self):
|
||||
self.CONF.set_override('user_alarm_quota', 1, group='alarm')
|
||||
self.CONF.set_override('project_alarm_quota', 1, group='alarm')
|
||||
self._test_alarm_quota()
|
||||
|
||||
def test_project_alarms_quotas(self):
|
||||
self.CONF.set_override('project_alarm_quota', 1, group='alarm')
|
||||
self._test_alarm_quota()
|
||||
|
||||
def test_user_alarms_quotas(self):
|
||||
self.CONF.set_override('user_alarm_quota', 1, group='alarm')
|
||||
self._test_alarm_quota()
|
||||
|
||||
def test_larger_limit_project_alarms_quotas(self):
|
||||
self.CONF.set_override('user_alarm_quota', 1, group='alarm')
|
||||
self.CONF.set_override('project_alarm_quota', 2, group='alarm')
|
||||
self._test_alarm_quota()
|
||||
|
||||
def test_larger_limit_user_alarms_quotas(self):
|
||||
self.CONF.set_override('user_alarm_quota', 2, group='alarm')
|
||||
self.CONF.set_override('project_alarm_quota', 1, group='alarm')
|
||||
self._test_alarm_quota()
|
||||
|
||||
def test_larger_limit_user_alarm_quotas_multitenant_user(self):
|
||||
self.CONF.set_override('user_alarm_quota', 2, group='alarm')
|
||||
self.CONF.set_override('project_alarm_quota', 1, group='alarm')
|
||||
|
||||
def _test(field, value):
|
||||
query = [{
|
||||
'field': field,
|
||||
'op': 'eq',
|
||||
'value': value
|
||||
}]
|
||||
alarms = self.get_json('/alarms', q=query)
|
||||
self.assertEqual(1, len(alarms))
|
||||
|
||||
alarm = {
|
||||
'name': 'alarm',
|
||||
'type': 'threshold',
|
||||
'user_id': self.auth_headers['X-User-Id'],
|
||||
'project_id': self.auth_headers['X-Project-Id'],
|
||||
'threshold_rule': {
|
||||
'meter_name': 'testmeter',
|
||||
'query': [],
|
||||
'comparison_operator': 'le',
|
||||
'statistic': 'max',
|
||||
'threshold': 42.0,
|
||||
'period': 60,
|
||||
'evaluation_periods': 1,
|
||||
}
|
||||
}
|
||||
|
||||
resp = self.post_json('/alarms', params=alarm,
|
||||
headers=self.auth_headers)
|
||||
|
||||
self.assertEqual(201, resp.status_code)
|
||||
_test('project_id', self.auth_headers['X-Project-Id'])
|
||||
|
||||
self.auth_headers['X-Project-Id'] = str(uuid.uuid4())
|
||||
alarm['name'] = 'another_user_alarm'
|
||||
alarm['project_id'] = self.auth_headers['X-Project-Id']
|
||||
resp = self.post_json('/alarms', params=alarm,
|
||||
headers=self.auth_headers)
|
||||
|
||||
self.assertEqual(201, resp.status_code)
|
||||
_test('project_id', self.auth_headers['X-Project-Id'])
|
||||
|
||||
alarms = self.get_json('/alarms')
|
||||
self.assertEqual(2, len(alarms))
|
||||
|
Loading…
x
Reference in New Issue
Block a user