Add quota support to octavia's l7policy and l7rule

Current octavia has no l7policy and l7rule quota definitions. But
they are necessary for some scenarios. For example, implement
product design compatible with Neutron Lbaas.

Story: 2003382
Task: 24457
Change-Id: I09ee23dcb83f5f08a56e25cc05ff77caa3ad4230
This commit is contained in:
Yang JianFeng 2018-08-10 03:16:59 +00:00
parent 3980c90403
commit 5d91913136
33 changed files with 1481 additions and 47 deletions

View File

@ -1286,6 +1286,34 @@ quota-health_monitor-optional:
in: body in: body
required: false required: false
type: integer type: integer
quota-l7policy:
description: |
The configured l7policy quota limit. A setting of ``null`` means it is
using the deployment default quota. A setting of ``-1`` means unlimited.
in: body
required: true
type: integer
quota-l7policy-optional:
description: |
The configured l7policy quota limit. A setting of ``null`` means it is
using the deployment default quota. A setting of ``-1`` means unlimited.
in: body
required: false
type: integer
quota-l7rule:
description: |
The configured l7rule quota limit. A setting of ``null`` means it is
using the deployment default quota. A setting of ``-1`` means unlimited.
in: body
required: true
type: integer
quota-l7rule-optional:
description: |
The configured l7rule quota limit. A setting of ``null`` means it is
using the deployment default quota. A setting of ``-1`` means unlimited.
in: body
required: false
type: integer
quota-listener: quota-listener:
description: | description: |
The configured listener quota limit. A setting of ``null`` means it is The configured listener quota limit. A setting of ``null`` means it is

View File

@ -1 +1 @@
curl -X PUT -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"quota":{"loadbalancer":10,"listener":-1,"member":50,"pool":-1,"healthmonitor":-1}}' http://198.51.100.10:9876/v2/lbaas/quotas/e3cd678b11784734bc366148aa37580e curl -X PUT -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"quota":{"loadbalancer":10,"listener":-1,"member":50,"pool":-1,"healthmonitor":-1,"l7policy":15,"l7rule":25}}' http://198.51.100.10:9876/v2/lbaas/quotas/e3cd678b11784734bc366148aa37580e

View File

@ -4,6 +4,8 @@
"listener": -1, "listener": -1,
"member": 50, "member": 50,
"pool": -1, "pool": -1,
"healthmonitor": -1 "healthmonitor": -1,
"l7policy": 15,
"l7rule": 25
} }
} }

View File

@ -4,6 +4,8 @@
"listener": -1, "listener": -1,
"member": 50, "member": 50,
"pool": -1, "pool": -1,
"healthmonitor": -1 "healthmonitor": -1,
"l7policy": 15,
"l7rule": 25
} }
} }

View File

@ -4,6 +4,8 @@
"listener": -1, "listener": -1,
"member": -1, "member": -1,
"pool": -1, "pool": -1,
"healthmonitor": -1 "healthmonitor": -1,
"l7policy": -1,
"l7rule": -1
} }
} }

View File

@ -6,7 +6,9 @@
"healthmonitor": -1, "healthmonitor": -1,
"listener": null, "listener": null,
"project_id": "e3cd678b11784734bc366148aa37580e", "project_id": "e3cd678b11784734bc366148aa37580e",
"pool": null "pool": null,
"l7policy": 3,
"l7rule": null
} }
] ]
} }

View File

@ -4,6 +4,8 @@
"listener": -1, "listener": -1,
"member": 50, "member": 50,
"pool": -1, "pool": -1,
"healthmonitor": -1 "healthmonitor": -1,
"l7policy": 20,
"l7rule": -1
} }
} }

View File

@ -51,6 +51,8 @@ Response Parameters
.. rest_parameters:: ../parameters.yaml .. rest_parameters:: ../parameters.yaml
- healthmonitor: quota-health_monitor - healthmonitor: quota-health_monitor
- l7policy: quota-l7policy
- l7rule: quota-l7rule
- listener: quota-listener - listener: quota-listener
- loadbalancer: quota-load_balancer - loadbalancer: quota-load_balancer
- member: quota-member - member: quota-member
@ -99,6 +101,8 @@ Response Parameters
.. rest_parameters:: ../parameters.yaml .. rest_parameters:: ../parameters.yaml
- healthmonitor: quota-health_monitor - healthmonitor: quota-health_monitor
- l7policy: quota-l7policy
- l7rule: quota-l7rule
- listener: quota-listener - listener: quota-listener
- loadbalancer: quota-load_balancer - loadbalancer: quota-load_balancer
- member: quota-member - member: quota-member
@ -156,6 +160,8 @@ Response Parameters
.. rest_parameters:: ../parameters.yaml .. rest_parameters:: ../parameters.yaml
- healthmonitor: quota-health_monitor - healthmonitor: quota-health_monitor
- l7policy: quota-l7policy
- l7rule: quota-l7rule
- listener: quota-listener - listener: quota-listener
- loadbalancer: quota-load_balancer - loadbalancer: quota-load_balancer
- member: quota-member - member: quota-member
@ -206,6 +212,8 @@ Request
.. rest_parameters:: ../parameters.yaml .. rest_parameters:: ../parameters.yaml
- healthmonitor: quota-health_monitor-optional - healthmonitor: quota-health_monitor-optional
- l7policy: quota-l7policy-optional
- l7rule: quota-l7rule-optional
- listener: quota-listener-optional - listener: quota-listener-optional
- loadbalancer: quota-load_balancer-optional - loadbalancer: quota-load_balancer-optional
- member: quota-member-optional - member: quota-member-optional
@ -230,6 +238,8 @@ Response Parameters
.. rest_parameters:: ../parameters.yaml .. rest_parameters:: ../parameters.yaml
- healthmonitor: quota-health_monitor - healthmonitor: quota-health_monitor
- l7policy: quota-l7policy
- l7rule: quota-l7rule
- listener: quota-listener - listener: quota-listener
- loadbalancer: quota-load_balancer - loadbalancer: quota-load_balancer
- member: quota-member - member: quota-member

View File

@ -588,6 +588,8 @@
# default_member_quota = -1 # default_member_quota = -1
# default_pool_quota = -1 # default_pool_quota = -1
# default_health_monitor_quota = -1 # default_health_monitor_quota = -1
# default_l7policy_quota = -1
# default_l7rule_quota = -1
[audit] [audit]
# Enable auditing of API requests. # Enable auditing of API requests.

View File

@ -119,6 +119,9 @@ class RootController(object):
self._add_a_version(versions, 'v2.17', 'v2', 'SUPPORTED', self._add_a_version(versions, 'v2.17', 'v2', 'SUPPORTED',
'2020-04-29T00:00:00Z', host_url) '2020-04-29T00:00:00Z', host_url)
# Pool TLS versions # Pool TLS versions
self._add_a_version(versions, 'v2.18', 'v2', 'CURRENT', self._add_a_version(versions, 'v2.18', 'v2', 'SUPPORTED',
'2020-04-29T01:00:00Z', host_url) '2020-04-29T01:00:00Z', host_url)
# Add quota support to octavia's l7policy and l7rule
self._add_a_version(versions, 'v2.19', 'v2', 'CURRENT',
'2020-05-12T00:00:00Z', host_url)
return {'versions': versions} return {'versions': versions}

View File

@ -184,7 +184,9 @@ class BaseController(pecan_rest.RestController):
listener=CONF.quotas.default_listener_quota, listener=CONF.quotas.default_listener_quota,
pool=CONF.quotas.default_pool_quota, pool=CONF.quotas.default_pool_quota,
health_monitor=CONF.quotas.default_health_monitor_quota, health_monitor=CONF.quotas.default_health_monitor_quota,
member=CONF.quotas.default_member_quota) member=CONF.quotas.default_member_quota,
l7policy=CONF.quotas.default_l7policy_quota,
l7rule=CONF.quotas.default_l7rule_quota)
return quotas return quotas
def _get_db_quotas(self, session, project_id): def _get_db_quotas(self, session, project_id):
@ -213,6 +215,10 @@ class BaseController(pecan_rest.RestController):
default_health_monitor_quota) default_health_monitor_quota)
if db_quotas.member is None: if db_quotas.member is None:
db_quotas.member = CONF.quotas.default_member_quota db_quotas.member = CONF.quotas.default_member_quota
if db_quotas.l7policy is None:
db_quotas.l7policy = CONF.quotas.default_l7policy_quota
if db_quotas.l7rule is None:
db_quotas.l7rule = CONF.quotas.default_l7rule_quota
return db_quotas return db_quotas
def _auth_get_all(self, context, project_id): def _auth_get_all(self, context, project_id):

View File

@ -146,6 +146,14 @@ class L7RuleController(base.BaseController):
lock_session = db_api.get_session(autocommit=False) lock_session = db_api.get_session(autocommit=False)
try: try:
if self.repositories.check_quota_met(
context.session,
lock_session,
data_models.L7Rule,
l7rule.project_id):
raise exceptions.QuotaException(
resource=data_models.L7Rule._name())
l7rule_dict = db_prepare.create_l7rule( l7rule_dict = db_prepare.create_l7rule(
l7rule.to_dict(render_unsets=True), self.l7policy_id) l7rule.to_dict(render_unsets=True), self.l7policy_id)

View File

@ -36,6 +36,10 @@ class QuotaBase(base.BaseType):
# Misspelled version, deprecated in Rocky # Misspelled version, deprecated in Rocky
health_monitor = wtypes.wsattr(wtypes.IntegerType( health_monitor = wtypes.wsattr(wtypes.IntegerType(
minimum=consts.MIN_QUOTA, maximum=consts.MAX_QUOTA)) minimum=consts.MIN_QUOTA, maximum=consts.MAX_QUOTA))
l7policy = wtypes.wsattr(wtypes.IntegerType(
minimum=consts.MIN_QUOTA, maximum=consts.MAX_QUOTA))
l7rule = wtypes.wsattr(wtypes.IntegerType(
minimum=consts.MIN_QUOTA, maximum=consts.MAX_QUOTA))
def to_dict(self, render_unsets=False): def to_dict(self, render_unsets=False):
quota_dict = super(QuotaBase, self).to_dict(render_unsets) quota_dict = super(QuotaBase, self).to_dict(render_unsets)
@ -70,6 +74,8 @@ class QuotaAllBase(base.BaseType):
healthmonitor = wtypes.wsattr(wtypes.IntegerType()) healthmonitor = wtypes.wsattr(wtypes.IntegerType())
# Misspelled version, deprecated in Rocky, remove in T # Misspelled version, deprecated in Rocky, remove in T
health_monitor = wtypes.wsattr(wtypes.IntegerType()) health_monitor = wtypes.wsattr(wtypes.IntegerType())
l7policy = wtypes.wsattr(wtypes.IntegerType())
l7rule = wtypes.wsattr(wtypes.IntegerType())
_type_to_model_map = {'loadbalancer': 'load_balancer', _type_to_model_map = {'loadbalancer': 'load_balancer',
'healthmonitor': 'health_monitor'} 'healthmonitor': 'health_monitor'}

View File

@ -721,6 +721,12 @@ quota_opts = [
cfg.IntOpt('default_health_monitor_quota', cfg.IntOpt('default_health_monitor_quota',
default=constants.QUOTA_UNLIMITED, default=constants.QUOTA_UNLIMITED,
help=_('Default per project health monitor quota.')), help=_('Default per project health monitor quota.')),
cfg.IntOpt('default_l7policy_quota',
default=constants.QUOTA_UNLIMITED,
help=_('Default per project l7policy quota.')),
cfg.IntOpt('default_l7rule_quota',
default=constants.QUOTA_UNLIMITED,
help=_('Default per project l7rule quota.')),
] ]
audit_opts = [ audit_opts = [

View File

@ -748,22 +748,30 @@ class Quotas(BaseDataModel):
pool=None, pool=None,
health_monitor=None, health_monitor=None,
member=None, member=None,
l7policy=None,
l7rule=None,
in_use_health_monitor=None, in_use_health_monitor=None,
in_use_listener=None, in_use_listener=None,
in_use_load_balancer=None, in_use_load_balancer=None,
in_use_member=None, in_use_member=None,
in_use_pool=None): in_use_pool=None,
in_use_l7policy=None,
in_use_l7rule=None):
self.project_id = project_id self.project_id = project_id
self.health_monitor = health_monitor self.health_monitor = health_monitor
self.listener = listener self.listener = listener
self.load_balancer = load_balancer self.load_balancer = load_balancer
self.pool = pool self.pool = pool
self.member = member self.member = member
self.l7policy = l7policy
self.l7rule = l7rule
self.in_use_health_monitor = in_use_health_monitor self.in_use_health_monitor = in_use_health_monitor
self.in_use_listener = in_use_listener self.in_use_listener = in_use_listener
self.in_use_load_balancer = in_use_load_balancer self.in_use_load_balancer = in_use_load_balancer
self.in_use_member = in_use_member self.in_use_member = in_use_member
self.in_use_pool = in_use_pool self.in_use_pool = in_use_pool
self.in_use_l7policy = in_use_l7policy
self.in_use_l7rule = in_use_l7rule
class Flavor(BaseDataModel): class Flavor(BaseDataModel):

View File

@ -63,6 +63,8 @@ class L7PolicyFlows(object):
requires=constants.LOADBALANCER)) requires=constants.LOADBALANCER))
delete_l7policy_flow.add(database_tasks.DeleteL7PolicyInDB( delete_l7policy_flow.add(database_tasks.DeleteL7PolicyInDB(
requires=constants.L7POLICY)) requires=constants.L7POLICY))
delete_l7policy_flow.add(database_tasks.DecrementL7policyQuota(
requires=constants.L7POLICY))
delete_l7policy_flow.add(database_tasks.MarkLBAndListenersActiveInDB( delete_l7policy_flow.add(database_tasks.MarkLBAndListenersActiveInDB(
requires=[constants.LOADBALANCER, constants.LISTENERS])) requires=[constants.LOADBALANCER, constants.LISTENERS]))

View File

@ -65,6 +65,8 @@ class L7RuleFlows(object):
requires=constants.LOADBALANCER)) requires=constants.LOADBALANCER))
delete_l7rule_flow.add(database_tasks.DeleteL7RuleInDB( delete_l7rule_flow.add(database_tasks.DeleteL7RuleInDB(
requires=constants.L7RULE)) requires=constants.L7RULE))
delete_l7rule_flow.add(database_tasks.DecrementL7ruleQuota(
requires=constants.L7RULE))
delete_l7rule_flow.add(database_tasks.MarkL7PolicyActiveInDB( delete_l7rule_flow.add(database_tasks.MarkL7PolicyActiveInDB(
requires=constants.L7POLICY)) requires=constants.L7POLICY))
delete_l7rule_flow.add(database_tasks.MarkLBAndListenersActiveInDB( delete_l7rule_flow.add(database_tasks.MarkLBAndListenersActiveInDB(

View File

@ -2671,6 +2671,142 @@ class CountPoolChildrenForQuota(BaseDatabaseTask):
return {'HM': health_mon_count, 'member': member_count} return {'HM': health_mon_count, 'member': member_count}
class DecrementL7policyQuota(BaseDatabaseTask):
"""Decrements the l7policy quota for a project.
Since sqlalchemy will likely retry by itself always revert if it fails
"""
def execute(self, l7policy):
"""Decrements the l7policy quota.
:param l7policy: The l7policy to decrement the quota on.
:returns: None
"""
LOG.debug("Decrementing l7policy quota for "
"project: %s ", l7policy.project_id)
lock_session = db_apis.get_session(autocommit=False)
try:
self.repos.decrement_quota(lock_session,
data_models.L7Policy,
l7policy.project_id)
if l7policy.l7rules:
self.repos.decrement_quota(lock_session,
data_models.L7Rule,
l7policy.project_id,
quantity=len(l7policy.l7rules))
lock_session.commit()
except Exception:
with excutils.save_and_reraise_exception():
LOG.error('Failed to decrement l7policy quota for project: '
'%(proj)s the project may have excess quota in use.',
{'proj': l7policy.project_id})
lock_session.rollback()
def revert(self, l7policy, result, *args, **kwargs):
"""Re-apply the quota
:param l7policy: The l7policy to decrement the quota on.
:returns: None
"""
LOG.warning('Reverting decrement quota for l7policy on project'
' %(proj)s Project quota counts may be incorrect.',
{'proj': l7policy.project_id})
# Increment the quota back if this task wasn't the failure
if not isinstance(result, failure.Failure):
try:
session = db_apis.get_session()
lock_session = db_apis.get_session(autocommit=False)
try:
self.repos.check_quota_met(session,
lock_session,
data_models.L7Policy,
l7policy.project_id)
lock_session.commit()
except Exception:
lock_session.rollback()
# Attempt to increment back the L7Rule quota
for i in range(len(l7policy.l7rules)):
lock_session = db_apis.get_session(autocommit=False)
try:
self.repos.check_quota_met(session,
lock_session,
data_models.L7Rule,
l7policy.project_id)
lock_session.commit()
except Exception:
lock_session.rollback()
except Exception:
# Don't fail the revert flow
pass
class DecrementL7ruleQuota(BaseDatabaseTask):
"""Decrements the l7rule quota for a project.
Since sqlalchemy will likely retry by itself always revert if it fails
"""
def execute(self, l7rule):
"""Decrements the l7rule quota.
:param l7rule: The l7rule to decrement the quota on.
:returns: None
"""
LOG.debug("Decrementing l7rule quota for "
"project: %s ", l7rule.project_id)
lock_session = db_apis.get_session(autocommit=False)
try:
self.repos.decrement_quota(lock_session,
data_models.L7Rule,
l7rule.project_id)
lock_session.commit()
except Exception:
with excutils.save_and_reraise_exception():
LOG.error('Failed to decrement l7rule quota for project: '
'%(proj)s the project may have excess quota in use.',
{'proj': l7rule.project_id})
lock_session.rollback()
def revert(self, l7rule, result, *args, **kwargs):
"""Re-apply the quota
:param l7rule: The l7rule to decrement the quota on.
:returns: None
"""
LOG.warning('Reverting decrement quota for l7rule on project %(proj)s '
'Project quota counts may be incorrect.',
{'proj': l7rule.project_id})
# Increment the quota back if this task wasn't the failure
if not isinstance(result, failure.Failure):
try:
session = db_apis.get_session()
lock_session = db_apis.get_session(autocommit=False)
try:
self.repos.check_quota_met(session,
lock_session,
data_models.L7Rule,
l7rule.project_id)
lock_session.commit()
except Exception:
lock_session.rollback()
except Exception:
# Don't fail the revert flow
pass
class UpdatePoolMembersOperatingStatusInDB(BaseDatabaseTask): class UpdatePoolMembersOperatingStatusInDB(BaseDatabaseTask):
"""Updates the members of a pool operating status. """Updates the members of a pool operating status.

View File

@ -60,6 +60,8 @@ class L7PolicyFlows(object):
requires=constants.LOADBALANCER_ID)) requires=constants.LOADBALANCER_ID))
delete_l7policy_flow.add(database_tasks.DeleteL7PolicyInDB( delete_l7policy_flow.add(database_tasks.DeleteL7PolicyInDB(
requires=constants.L7POLICY)) requires=constants.L7POLICY))
delete_l7policy_flow.add(database_tasks.DecrementL7policyQuota(
requires=constants.L7POLICY))
delete_l7policy_flow.add(database_tasks.MarkLBAndListenersActiveInDB( delete_l7policy_flow.add(database_tasks.MarkLBAndListenersActiveInDB(
requires=(constants.LOADBALANCER_ID, constants.LISTENERS))) requires=(constants.LOADBALANCER_ID, constants.LISTENERS)))

View File

@ -64,6 +64,8 @@ class L7RuleFlows(object):
requires=constants.LOADBALANCER_ID)) requires=constants.LOADBALANCER_ID))
delete_l7rule_flow.add(database_tasks.DeleteL7RuleInDB( delete_l7rule_flow.add(database_tasks.DeleteL7RuleInDB(
requires=constants.L7RULE)) requires=constants.L7RULE))
delete_l7rule_flow.add(database_tasks.DecrementL7ruleQuota(
requires=constants.L7RULE))
delete_l7rule_flow.add(database_tasks.MarkL7PolicyActiveInDB( delete_l7rule_flow.add(database_tasks.MarkL7PolicyActiveInDB(
requires=constants.L7POLICY)) requires=constants.L7POLICY))
delete_l7rule_flow.add(database_tasks.MarkLBAndListenersActiveInDB( delete_l7rule_flow.add(database_tasks.MarkLBAndListenersActiveInDB(

View File

@ -2860,6 +2860,142 @@ class CountPoolChildrenForQuota(BaseDatabaseTask):
return {'HM': health_mon_count, 'member': member_count} return {'HM': health_mon_count, 'member': member_count}
class DecrementL7policyQuota(BaseDatabaseTask):
"""Decrements the l7policy quota for a project.
Since sqlalchemy will likely retry by itself always revert if it fails
"""
def execute(self, l7policy):
"""Decrements the l7policy quota.
:param l7policy: The l7policy to decrement the quota on.
:returns: None
"""
LOG.debug("Decrementing l7policy quota for "
"project: %s ", l7policy.project_id)
lock_session = db_apis.get_session(autocommit=False)
try:
self.repos.decrement_quota(lock_session,
data_models.L7Policy,
l7policy.project_id)
if l7policy.l7rules:
self.repos.decrement_quota(lock_session,
data_models.L7Rule,
l7policy.project_id,
quantity=len(l7policy.l7rules))
lock_session.commit()
except Exception:
with excutils.save_and_reraise_exception():
LOG.error('Failed to decrement l7policy quota for project: '
'%(proj)s the project may have excess quota in use.',
{'proj': l7policy.project_id})
lock_session.rollback()
def revert(self, l7policy, result, *args, **kwargs):
"""Re-apply the quota
:param l7policy: The l7policy to decrement the quota on.
:returns: None
"""
LOG.warning('Reverting decrement quota for l7policy on project'
' %(proj)s Project quota counts may be incorrect.',
{'proj': l7policy.project_id})
# Increment the quota back if this task wasn't the failure
if not isinstance(result, failure.Failure):
try:
session = db_apis.get_session()
lock_session = db_apis.get_session(autocommit=False)
try:
self.repos.check_quota_met(session,
lock_session,
data_models.L7Policy,
l7policy.project_id)
lock_session.commit()
except Exception:
lock_session.rollback()
# Attempt to increment back the L7Rule quota
for i in range(len(l7policy.l7rules)):
lock_session = db_apis.get_session(autocommit=False)
try:
self.repos.check_quota_met(session,
lock_session,
data_models.L7Rule,
l7policy.project_id)
lock_session.commit()
except Exception:
lock_session.rollback()
except Exception:
# Don't fail the revert flow
pass
class DecrementL7ruleQuota(BaseDatabaseTask):
"""Decrements the l7rule quota for a project.
Since sqlalchemy will likely retry by itself always revert if it fails
"""
def execute(self, l7rule):
"""Decrements the l7rule quota.
:param l7rule: The l7rule to decrement the quota on.
:returns: None
"""
LOG.debug("Decrementing l7rule quota for "
"project: %s ", l7rule.project_id)
lock_session = db_apis.get_session(autocommit=False)
try:
self.repos.decrement_quota(lock_session,
data_models.L7Rule,
l7rule.project_id)
lock_session.commit()
except Exception:
with excutils.save_and_reraise_exception():
LOG.error('Failed to decrement l7rule quota for project: '
'%(proj)s the project may have excess quota in use.',
{'proj': l7rule.project_id})
lock_session.rollback()
def revert(self, l7rule, result, *args, **kwargs):
"""Re-apply the quota
:param l7rule: The l7rule to decrement the quota on.
:returns: None
"""
LOG.warning('Reverting decrement quota for l7rule on project %(proj)s '
'Project quota counts may be incorrect.',
{'proj': l7rule.project_id})
# Increment the quota back if this task wasn't the failure
if not isinstance(result, failure.Failure):
try:
session = db_apis.get_session()
lock_session = db_apis.get_session(autocommit=False)
try:
self.repos.check_quota_met(session,
lock_session,
data_models.L7Rule,
l7rule.project_id)
lock_session.commit()
except Exception:
lock_session.rollback()
except Exception:
# Don't fail the revert flow
pass
class UpdatePoolMembersOperatingStatusInDB(BaseDatabaseTask): class UpdatePoolMembersOperatingStatusInDB(BaseDatabaseTask):
"""Updates the members of a pool operating status. """Updates the members of a pool operating status.

View File

@ -0,0 +1,40 @@
# Copyright (c) 2018 China Telecom Corporation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""add l7policy and l7rule quota
Revision ID: 32e5c35b26a8
Revises: d3c8a090f3de
Create Date: 2018-08-10 09:13:59.383272
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '32e5c35b26a8'
down_revision = 'd3c8a090f3de'
def upgrade():
op.add_column(u'quotas',
sa.Column('l7policy', sa.Integer(), nullable=True))
op.add_column(u'quotas',
sa.Column('l7rule', sa.Integer(), nullable=True))
op.add_column(u'quotas',
sa.Column('in_use_l7policy', sa.Integer(), nullable=True))
op.add_column(u'quotas',
sa.Column('in_use_l7rule', sa.Integer(), nullable=True))

View File

@ -750,11 +750,15 @@ class Quotas(base_models.BASE):
load_balancer = sa.Column(sa.Integer(), nullable=True) load_balancer = sa.Column(sa.Integer(), nullable=True)
member = sa.Column(sa.Integer(), nullable=True) member = sa.Column(sa.Integer(), nullable=True)
pool = sa.Column(sa.Integer(), nullable=True) pool = sa.Column(sa.Integer(), nullable=True)
l7policy = sa.Column(sa.Integer(), nullable=True)
l7rule = sa.Column(sa.Integer(), nullable=True)
in_use_health_monitor = sa.Column(sa.Integer(), nullable=True) in_use_health_monitor = sa.Column(sa.Integer(), nullable=True)
in_use_listener = sa.Column(sa.Integer(), nullable=True) in_use_listener = sa.Column(sa.Integer(), nullable=True)
in_use_load_balancer = sa.Column(sa.Integer(), nullable=True) in_use_load_balancer = sa.Column(sa.Integer(), nullable=True)
in_use_member = sa.Column(sa.Integer(), nullable=True) in_use_member = sa.Column(sa.Integer(), nullable=True)
in_use_pool = sa.Column(sa.Integer(), nullable=True) in_use_pool = sa.Column(sa.Integer(), nullable=True)
in_use_l7policy = sa.Column(sa.Integer(), nullable=True)
in_use_l7rule = sa.Column(sa.Integer(), nullable=True)
class FlavorProfile(base_models.BASE, base_models.IdMixin, class FlavorProfile(base_models.BASE, base_models.IdMixin,

View File

@ -499,6 +499,48 @@ class Repositories(object):
quotas.in_use_member = member_count quotas.in_use_member = member_count
return False return False
return True return True
if _class == data_models.L7Policy:
# Decide which quota to use
if quotas.l7policy is None:
l7policy_quota = CONF.quotas.default_l7policy_quota
else:
l7policy_quota = quotas.l7policy
# Get the current in use count
if not quotas.in_use_l7policy:
# This is to handle the upgrade case
l7policy_count = session.query(models.L7Policy).filter(
models.L7Policy.project_id == project_id,
models.L7Policy.provisioning_status !=
consts.DELETED).count() + count
else:
l7policy_count = quotas.in_use_l7policy + count
# Decide if the quota is met
if (l7policy_count <= l7policy_quota or
l7policy_quota == consts.QUOTA_UNLIMITED):
quotas.in_use_l7policy = l7policy_count
return False
return True
if _class == data_models.L7Rule:
# Decide which quota to use
if quotas.l7rule is None:
l7rule_quota = CONF.quotas.default_l7rule_quota
else:
l7rule_quota = quotas.l7rule
# Get the current in use count
if not quotas.in_use_l7rule:
# This is to handle the upgrade case
l7rule_count = session.query(models.L7Rule).filter(
models.L7Rule.project_id == project_id,
models.L7Rule.provisioning_status !=
consts.DELETED).count() + count
else:
l7rule_count = quotas.in_use_l7rule + count
# Decide if the quota is met
if (l7rule_count <= l7rule_quota or
l7rule_quota == consts.QUOTA_UNLIMITED):
quotas.in_use_l7rule = l7rule_count
return False
return True
except db_exception.DBDeadlock: except db_exception.DBDeadlock:
LOG.warning('Quota project lock timed out for project: %(proj)s', LOG.warning('Quota project lock timed out for project: %(proj)s',
{'proj': project_id}) {'proj': project_id})
@ -584,6 +626,28 @@ class Repositories(object):
'project: %(proj)s that would cause a ' 'project: %(proj)s that would cause a '
'negative quota.', 'negative quota.',
{'clss': type(_class), 'proj': project_id}) {'clss': type(_class), 'proj': project_id})
if _class == data_models.L7Policy:
if (quotas.in_use_l7policy is not None and
quotas.in_use_l7policy > 0):
quotas.in_use_l7policy = (
quotas.in_use_l7policy - quantity)
else:
if not CONF.api_settings.auth_strategy == consts.NOAUTH:
LOG.warning('Quota decrement on %(clss)s called on '
'project: %(proj)s that would cause a '
'negative quota.',
{'clss': type(_class), 'proj': project_id})
if _class == data_models.L7Rule:
if (quotas.in_use_l7rule is not None and
quotas.in_use_l7rule > 0):
quotas.in_use_l7rule = (
quotas.in_use_l7rule - quantity)
else:
if not CONF.api_settings.auth_strategy == consts.NOAUTH:
LOG.warning('Quota decrement on %(clss)s called on '
'project: %(proj)s that would cause a '
'negative quota.',
{'clss': type(_class), 'proj': project_id})
except db_exception.DBDeadlock: except db_exception.DBDeadlock:
LOG.warning('Quota project lock timed out for project: %(proj)s', LOG.warning('Quota project lock timed out for project: %(proj)s',
{'proj': project_id}) {'proj': project_id})
@ -657,6 +721,13 @@ class Repositories(object):
self.sni.create(lock_session, **sni_container) self.sni.create(lock_session, **sni_container)
if l7policies_dict: if l7policies_dict:
for policy_dict in l7policies_dict: for policy_dict in l7policies_dict:
# Add l7policy quota check
if self.check_quota_met(session,
lock_session,
data_models.L7Policy,
lb_dict['project_id']):
raise exceptions.QuotaException(
resource=data_models.L7Policy._name())
l7rules_dict = policy_dict.pop('l7rules') l7rules_dict = policy_dict.pop('l7rules')
if policy_dict.get('redirect_pool'): if policy_dict.get('redirect_pool'):
# Add pool quota check # Add pool quota check
@ -711,6 +782,14 @@ class Repositories(object):
policy_dm = self.l7policy.create(lock_session, policy_dm = self.l7policy.create(lock_session,
**policy_dict) **policy_dict)
for rule_dict in l7rules_dict: for rule_dict in l7rules_dict:
# Add l7rule quota check
if self.check_quota_met(
session,
lock_session,
data_models.L7Rule,
lb_dict['project_id']):
raise exceptions.QuotaException(
resource=data_models.L7Rule._name())
rule_dict['l7policy_id'] = policy_dm.id rule_dict['l7policy_id'] = policy_dm.id
self.l7rule.create(lock_session, **rule_dict) self.l7rule.create(lock_session, **rule_dict)
lock_session.commit() lock_session.commit()
@ -1848,6 +1927,8 @@ class QuotasRepository(BaseRepository):
quotas.listener = None quotas.listener = None
quotas.member = None quotas.member = None
quotas.pool = None quotas.pool = None
quotas.l7policy = None
quotas.l7rule = None
session.flush() session.flush()

View File

@ -45,7 +45,7 @@ class TestRootController(base_db_test.OctaviaDBTestBase):
def test_api_versions(self): def test_api_versions(self):
versions = self._get_versions_with_config() versions = self._get_versions_with_config()
version_ids = tuple(v.get('id') for v in versions) version_ids = tuple(v.get('id') for v in versions)
self.assertEqual(19, len(version_ids)) self.assertEqual(20, len(version_ids))
self.assertIn('v2.0', version_ids) self.assertIn('v2.0', version_ids)
self.assertIn('v2.1', version_ids) self.assertIn('v2.1', version_ids)
self.assertIn('v2.2', version_ids) self.assertIn('v2.2', version_ids)
@ -65,6 +65,7 @@ class TestRootController(base_db_test.OctaviaDBTestBase):
self.assertIn('v2.16', version_ids) self.assertIn('v2.16', version_ids)
self.assertIn('v2.17', version_ids) self.assertIn('v2.17', version_ids)
self.assertIn('v2.18', version_ids) self.assertIn('v2.18', version_ids)
self.assertIn('v2.19', version_ids)
# Each version should have a 'self' 'href' to the API version URL # Each version should have a 'self' 'href' to the API version URL
# [{u'rel': u'self', u'href': u'http://localhost/v2'}] # [{u'rel': u'self', u'href': u'http://localhost/v2'}]

View File

@ -19,6 +19,7 @@ from oslo_utils import uuidutils
from octavia.common import constants from octavia.common import constants
import octavia.common.context import octavia.common.context
from octavia.common import data_models
from octavia.common import exceptions from octavia.common import exceptions
from octavia.db import repositories from octavia.db import repositories
from octavia.tests.functional.api.v2 import base from octavia.tests.functional.api.v2 import base
@ -829,6 +830,15 @@ class TestL7Rule(base.BaseAPITest):
def test_create_bad_cases_with_ssl_rule_types(self): def test_create_bad_cases_with_ssl_rule_types(self):
self._test_bad_cases_with_ssl_rule_types() self._test_bad_cases_with_ssl_rule_types()
def test_create_over_quota(self):
self.start_quota_mock(data_models.L7Rule)
l7rule = {'compare_type': 'REGEX',
'invert': False,
'type': 'PATH',
'value': '/images*',
'admin_state_up': True}
self.post(self.l7rules_path, self._build_body(l7rule), status=403)
def test_update(self): def test_update(self):
api_l7rule = self.create_l7rule( api_l7rule = self.create_l7rule(
self.l7policy_id, constants.L7RULE_TYPE_PATH, self.l7policy_id, constants.L7RULE_TYPE_PATH,

View File

@ -54,6 +54,14 @@ class TestQuotas(base.BaseAPITest):
group="quotas", group="quotas",
default_health_monitor_quota=random.randrange( default_health_monitor_quota=random.randrange(
constants.QUOTA_UNLIMITED, 9000)) constants.QUOTA_UNLIMITED, 9000))
conf.config(
group="quotas",
default_l7policy_quota=random.randrange(
constants.QUOTA_UNLIMITED, 9000))
conf.config(
group="quotas",
default_l7rule_quota=random.randrange(
constants.QUOTA_UNLIMITED, 9000))
self.project_id = uuidutils.generate_uuid() self.project_id = uuidutils.generate_uuid()
@ -65,13 +73,17 @@ class TestQuotas(base.BaseAPITest):
'pool': CONF.quotas.default_pool_quota, 'pool': CONF.quotas.default_pool_quota,
'health_monitor': 'health_monitor':
CONF.quotas.default_health_monitor_quota, CONF.quotas.default_health_monitor_quota,
'member': CONF.quotas.default_member_quota} 'member': CONF.quotas.default_member_quota,
'l7policy': CONF.quotas.default_l7policy_quota,
'l7rule': CONF.quotas.default_l7rule_quota}
self.assertEqual(expected['load_balancer'], observed['load_balancer']) self.assertEqual(expected['load_balancer'], observed['load_balancer'])
self.assertEqual(expected['listener'], observed['listener']) self.assertEqual(expected['listener'], observed['listener'])
self.assertEqual(expected['pool'], observed['pool']) self.assertEqual(expected['pool'], observed['pool'])
self.assertEqual(expected['health_monitor'], self.assertEqual(expected['health_monitor'],
observed['health_monitor']) observed['health_monitor'])
self.assertEqual(expected['member'], observed['member']) self.assertEqual(expected['member'], observed['member'])
self.assertEqual(expected['l7policy'], observed['l7policy'])
self.assertEqual(expected['l7rule'], observed['l7rule'])
def test_get_all_quotas_no_quotas(self): def test_get_all_quotas_no_quotas(self):
response = self.get(self.QUOTAS_PATH) response = self.get(self.QUOTAS_PATH)
@ -83,12 +95,14 @@ class TestQuotas(base.BaseAPITest):
project_id2 = uuidutils.generate_uuid() project_id2 = uuidutils.generate_uuid()
quota_path1 = self.QUOTA_PATH.format(project_id=project_id1) quota_path1 = self.QUOTA_PATH.format(project_id=project_id1)
quota1 = {'load_balancer': constants.QUOTA_UNLIMITED, 'listener': 30, quota1 = {'load_balancer': constants.QUOTA_UNLIMITED, 'listener': 30,
'pool': 30, 'health_monitor': 30, 'member': 30} 'pool': 30, 'health_monitor': 30, 'member': 30,
'l7policy': 30, 'l7rule': 30}
body1 = {'quota': quota1} body1 = {'quota': quota1}
self.put(quota_path1, body1, status=202) self.put(quota_path1, body1, status=202)
quota_path2 = self.QUOTA_PATH.format(project_id=project_id2) quota_path2 = self.QUOTA_PATH.format(project_id=project_id2)
quota2 = {'load_balancer': 50, 'listener': 50, 'pool': 50, quota2 = {'load_balancer': 50, 'listener': 50, 'pool': 50,
'health_monitor': 50, 'member': 50} 'health_monitor': 50, 'member': 50, 'l7policy': 50,
'l7rule': 50}
body2 = {'quota': quota2} body2 = {'quota': quota2}
self.put(quota_path2, body2, status=202) self.put(quota_path2, body2, status=202)
@ -111,12 +125,14 @@ class TestQuotas(base.BaseAPITest):
project_id2 = uuidutils.generate_uuid() project_id2 = uuidutils.generate_uuid()
quota_path1 = self.QUOTA_PATH.format(project_id=project_id1) quota_path1 = self.QUOTA_PATH.format(project_id=project_id1)
quota1 = {'load_balancer': constants.QUOTA_UNLIMITED, 'listener': 30, quota1 = {'load_balancer': constants.QUOTA_UNLIMITED, 'listener': 30,
'pool': 30, 'health_monitor': 30, 'member': 30} 'pool': 30, 'health_monitor': 30, 'member': 30,
'l7policy': 30, 'l7rule': 30}
body1 = {'quota': quota1} body1 = {'quota': quota1}
self.put(quota_path1, body1, status=202) self.put(quota_path1, body1, status=202)
quota_path2 = self.QUOTA_PATH.format(project_id=project_id2) quota_path2 = self.QUOTA_PATH.format(project_id=project_id2)
quota2 = {'loadbalancer': 50, 'listener': 50, 'pool': 50, quota2 = {'loadbalancer': 50, 'listener': 50, 'pool': 50,
'healthmonitor': 50, 'member': 50} 'healthmonitor': 50, 'member': 50, 'l7policy': 50,
'l7rule': 50}
body2 = {'quota': quota2} body2 = {'quota': quota2}
self.put(quota_path2, body2, status=202) self.put(quota_path2, body2, status=202)
@ -139,12 +155,14 @@ class TestQuotas(base.BaseAPITest):
project_id2 = uuidutils.generate_uuid() project_id2 = uuidutils.generate_uuid()
quota_path1 = self.QUOTA_PATH.format(project_id=project_id1) quota_path1 = self.QUOTA_PATH.format(project_id=project_id1)
quota1 = {'load_balancer': constants.QUOTA_UNLIMITED, 'listener': 30, quota1 = {'load_balancer': constants.QUOTA_UNLIMITED, 'listener': 30,
'pool': 30, 'health_monitor': 30, 'member': 30} 'pool': 30, 'health_monitor': 30, 'member': 30,
'l7policy': 30, 'l7rule': 30}
body1 = {'quota': quota1} body1 = {'quota': quota1}
self.put(quota_path1, body1, status=202) self.put(quota_path1, body1, status=202)
quota_path2 = self.QUOTA_PATH.format(project_id=project_id2) quota_path2 = self.QUOTA_PATH.format(project_id=project_id2)
quota2 = {'load_balancer': 50, 'listener': 50, 'pool': 50, quota2 = {'load_balancer': 50, 'listener': 50, 'pool': 50,
'health_monitor': 50, 'member': 50} 'health_monitor': 50, 'member': 50, 'l7policy': 50,
'l7rule': 50}
body2 = {'quota': quota2} body2 = {'quota': quota2}
self.put(quota_path2, body2, status=202) self.put(quota_path2, body2, status=202)
self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF)) self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
@ -160,7 +178,8 @@ class TestQuotas(base.BaseAPITest):
project_id1 = uuidutils.generate_uuid() project_id1 = uuidutils.generate_uuid()
quota_path1 = self.QUOTA_PATH.format(project_id=project_id1) quota_path1 = self.QUOTA_PATH.format(project_id=project_id1)
quota1 = {'load_balancer': constants.QUOTA_UNLIMITED, 'listener': 30, quota1 = {'load_balancer': constants.QUOTA_UNLIMITED, 'listener': 30,
'pool': 30, 'health_monitor': 30, 'member': 30} 'pool': 30, 'health_monitor': 30, 'member': 30,
'l7policy': 30, 'l7rule': 30}
body1 = {'quota': quota1} body1 = {'quota': quota1}
self.put(quota_path1, body1, status=202) self.put(quota_path1, body1, status=202)
self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF)) self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
@ -193,12 +212,14 @@ class TestQuotas(base.BaseAPITest):
project_id2 = uuidutils.generate_uuid() project_id2 = uuidutils.generate_uuid()
quota_path1 = self.QUOTA_PATH.format(project_id=project_id1) quota_path1 = self.QUOTA_PATH.format(project_id=project_id1)
quota1 = {'load_balancer': constants.QUOTA_UNLIMITED, 'listener': 30, quota1 = {'load_balancer': constants.QUOTA_UNLIMITED, 'listener': 30,
'pool': 30, 'health_monitor': 30, 'member': 30} 'pool': 30, 'health_monitor': 30, 'member': 30,
'l7policy': 30, 'l7rule': 30}
body1 = {'quota': quota1} body1 = {'quota': quota1}
self.put(quota_path1, body1, status=202) self.put(quota_path1, body1, status=202)
quota_path2 = self.QUOTA_PATH.format(project_id=project_id2) quota_path2 = self.QUOTA_PATH.format(project_id=project_id2)
quota2 = {'load_balancer': 50, 'listener': 50, 'pool': 50, quota2 = {'load_balancer': 50, 'listener': 50, 'pool': 50,
'health_monitor': 50, 'member': 50} 'health_monitor': 50, 'member': 50, 'l7policy': 50,
'l7rule': 50}
body2 = {'quota': quota2} body2 = {'quota': quota2}
self.put(quota_path2, body2, status=202) self.put(quota_path2, body2, status=202)
self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF)) self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
@ -701,7 +722,8 @@ class TestQuotas(base.BaseAPITest):
def test_custom_quotas(self): def test_custom_quotas(self):
quota_path = self.QUOTA_PATH.format(project_id=self.project_id) quota_path = self.QUOTA_PATH.format(project_id=self.project_id)
body = {'quota': {'load_balancer': 30, 'listener': 30, 'pool': 30, body = {'quota': {'load_balancer': 30, 'listener': 30, 'pool': 30,
'health_monitor': 30, 'member': 30}} 'health_monitor': 30, 'member': 30,
'l7policy': 30, 'l7rule': 30}}
self.put(quota_path, body, status=202) self.put(quota_path, body, status=202)
response = self.get(quota_path) response = self.get(quota_path)
quota_dict = response.json quota_dict = response.json
@ -710,7 +732,8 @@ class TestQuotas(base.BaseAPITest):
def test_custom_quotas_quota_admin(self): def test_custom_quotas_quota_admin(self):
quota_path = self.QUOTA_PATH.format(project_id=self.project_id) quota_path = self.QUOTA_PATH.format(project_id=self.project_id)
body = {'quota': {'load_balancer': 30, 'listener': 30, 'pool': 30, body = {'quota': {'load_balancer': 30, 'listener': 30, 'pool': 30,
'health_monitor': 30, 'member': 30}} 'health_monitor': 30, 'member': 30, 'l7policy': 30,
'l7rule': 30}}
self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF)) self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
auth_strategy = self.conf.conf.api_settings.get('auth_strategy') auth_strategy = self.conf.conf.api_settings.get('auth_strategy')
self.conf.config(group='api_settings', auth_strategy=constants.TESTING) self.conf.config(group='api_settings', auth_strategy=constants.TESTING)
@ -741,7 +764,8 @@ class TestQuotas(base.BaseAPITest):
def test_custom_quotas_not_Authorized_member(self): def test_custom_quotas_not_Authorized_member(self):
quota_path = self.QUOTA_PATH.format(project_id=self.project_id) quota_path = self.QUOTA_PATH.format(project_id=self.project_id)
body = {'quota': {'load_balancer': 30, 'listener': 30, 'pool': 30, body = {'quota': {'load_balancer': 30, 'listener': 30, 'pool': 30,
'health_monitor': 30, 'member': 30}} 'health_monitor': 30, 'member': 30, 'l7policy': 30,
'l7rule': 30}}
self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF)) self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
auth_strategy = self.conf.conf.api_settings.get('auth_strategy') auth_strategy = self.conf.conf.api_settings.get('auth_strategy')
self.conf.config(group='api_settings', auth_strategy=constants.TESTING) self.conf.config(group='api_settings', auth_strategy=constants.TESTING)
@ -770,11 +794,12 @@ class TestQuotas(base.BaseAPITest):
def test_custom_partial_quotas(self): def test_custom_partial_quotas(self):
quota_path = self.QUOTA_PATH.format(project_id=self.project_id) quota_path = self.QUOTA_PATH.format(project_id=self.project_id)
body = {'quota': {'load_balancer': 30, 'listener': None, 'pool': 30, body = {'quota': {'load_balancer': 30, 'listener': None, 'pool': 30,
'health_monitor': 30, 'member': 30}} 'health_monitor': 30, 'member': 30, 'l7policy': 30,
'l7rule': 30}}
expected_body = {'quota': { expected_body = {'quota': {
'load_balancer': 30, 'load_balancer': 30,
'listener': CONF.quotas.default_listener_quota, 'pool': 30, 'listener': CONF.quotas.default_listener_quota, 'pool': 30,
'health_monitor': 30, 'member': 30}} 'health_monitor': 30, 'member': 30, 'l7policy': 30, 'l7rule': 30}}
self.put(quota_path, body, status=202) self.put(quota_path, body, status=202)
response = self.get(quota_path) response = self.get(quota_path)
quota_dict = response.json quota_dict = response.json
@ -784,11 +809,12 @@ class TestQuotas(base.BaseAPITest):
def test_custom_missing_quotas(self): def test_custom_missing_quotas(self):
quota_path = self.QUOTA_PATH.format(project_id=self.project_id) quota_path = self.QUOTA_PATH.format(project_id=self.project_id)
body = {'quota': {'load_balancer': 30, 'pool': 30, body = {'quota': {'load_balancer': 30, 'pool': 30,
'health_monitor': 30, 'member': 30}} 'health_monitor': 30, 'member': 30,
'l7policy': 30, 'l7rule': 30}}
expected_body = {'quota': { expected_body = {'quota': {
'load_balancer': 30, 'load_balancer': 30,
'listener': CONF.quotas.default_listener_quota, 'pool': 30, 'listener': CONF.quotas.default_listener_quota, 'pool': 30,
'health_monitor': 30, 'member': 30}} 'health_monitor': 30, 'member': 30, 'l7policy': 30, 'l7rule': 30}}
self.put(quota_path, body, status=202) self.put(quota_path, body, status=202)
response = self.get(quota_path) response = self.get(quota_path)
quota_dict = response.json quota_dict = response.json
@ -798,7 +824,8 @@ class TestQuotas(base.BaseAPITest):
def test_delete_custom_quotas(self): def test_delete_custom_quotas(self):
quota_path = self.QUOTA_PATH.format(project_id=self.project_id) quota_path = self.QUOTA_PATH.format(project_id=self.project_id)
body = {'quota': {'load_balancer': 30, 'listener': 30, 'pool': 30, body = {'quota': {'load_balancer': 30, 'listener': 30, 'pool': 30,
'health_monitor': 30, 'member': 30}} 'health_monitor': 30, 'member': 30, 'l7policy': 30,
'l7rule': 30}}
self.put(quota_path, body, status=202) self.put(quota_path, body, status=202)
response = self.get(quota_path) response = self.get(quota_path)
quota_dict = response.json quota_dict = response.json
@ -811,7 +838,8 @@ class TestQuotas(base.BaseAPITest):
def test_delete_custom_quotas_admin(self): def test_delete_custom_quotas_admin(self):
quota_path = self.QUOTA_PATH.format(project_id=self.project_id) quota_path = self.QUOTA_PATH.format(project_id=self.project_id)
body = {'quota': {'load_balancer': 30, 'listener': 30, 'pool': 30, body = {'quota': {'load_balancer': 30, 'listener': 30, 'pool': 30,
'health_monitor': 30, 'member': 30}} 'health_monitor': 30, 'member': 30, 'l7policy': 30,
'l7rule': 30}}
self.put(quota_path, body, status=202) self.put(quota_path, body, status=202)
response = self.get(quota_path) response = self.get(quota_path)
quota_dict = response.json quota_dict = response.json
@ -846,7 +874,8 @@ class TestQuotas(base.BaseAPITest):
def test_delete_quotas_not_Authorized_member(self): def test_delete_quotas_not_Authorized_member(self):
quota_path = self.QUOTA_PATH.format(project_id=self.project_id) quota_path = self.QUOTA_PATH.format(project_id=self.project_id)
body = {'quota': {'load_balancer': 30, 'listener': 30, 'pool': 30, body = {'quota': {'load_balancer': 30, 'listener': 30, 'pool': 30,
'health_monitor': 30, 'member': 30}} 'health_monitor': 30, 'member': 30, 'l7policy': 30,
'l7rule': 30}}
self.put(quota_path, body, status=202) self.put(quota_path, body, status=202)
response = self.get(quota_path) response = self.get(quota_path)
quota_dict = response.json quota_dict = response.json

View File

@ -612,6 +612,9 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
l7rule = {'type': constants.L7RULE_TYPE_HOST_NAME, l7rule = {'type': constants.L7RULE_TYPE_HOST_NAME,
'compare_type': constants.L7RULE_COMPARE_TYPE_EQUAL_TO, 'compare_type': constants.L7RULE_COMPARE_TYPE_EQUAL_TO,
'value': 'localhost'} 'value': 'localhost'}
l7rule2 = {'type': constants.L7RULE_TYPE_PATH,
'compare_type': constants.L7RULE_COMPARE_TYPE_CONTAINS,
'value': 'abc'}
r_health_monitor = {'type': constants.HEALTH_MONITOR_HTTP, 'delay': 1, r_health_monitor = {'type': constants.HEALTH_MONITOR_HTTP, 'delay': 1,
'timeout': 1, 'fall_threshold': 1, 'timeout': 1, 'fall_threshold': 1,
'rise_threshold': 1, 'enabled': True} 'rise_threshold': 1, 'enabled': True}
@ -629,11 +632,16 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'redirect_pool_id': redirect_pool.get('id'), 'redirect_pool_id': redirect_pool.get('id'),
'id': uuidutils.generate_uuid()} 'id': uuidutils.generate_uuid()}
l7rule['l7policy_id'] = l7policy.get('id') l7rule['l7policy_id'] = l7policy.get('id')
l7policy2 = {'name': 'l7policy2', 'enabled': True,
'description': 'l7policy_description', 'position': 2,
'action': constants.L7POLICY_ACTION_REJECT,
'id': uuidutils.generate_uuid()}
l7rule2['l7policy_id'] = l7policy2.get('id')
listener = {'project_id': project_id, 'name': 'listener1', listener = {'project_id': project_id, 'name': 'listener1',
'description': 'listener_description', 'description': 'listener_description',
'protocol': constants.PROTOCOL_HTTP, 'protocol_port': 80, 'protocol': constants.PROTOCOL_HTTP, 'protocol_port': 80,
'connection_limit': 1, 'enabled': True, 'connection_limit': 1, 'enabled': True,
'default_pool': pool, 'l7policies': [l7policy], 'default_pool': pool, 'l7policies': [l7policy, l7policy2],
'provisioning_status': constants.PENDING_CREATE, 'provisioning_status': constants.PENDING_CREATE,
'operating_status': constants.ONLINE, 'operating_status': constants.ONLINE,
'id': uuidutils.generate_uuid()} 'id': uuidutils.generate_uuid()}
@ -646,6 +654,7 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'operating_status': constants.ONLINE, 'operating_status': constants.ONLINE,
'id': uuidutils.generate_uuid()} 'id': uuidutils.generate_uuid()}
l7policy['listener_id'] = listener.get('id') l7policy['listener_id'] = listener.get('id')
l7policy2['listener_id'] = listener.get('id')
vip = {'ip_address': '192.0.2.1', 'port_id': uuidutils.generate_uuid(), vip = {'ip_address': '192.0.2.1', 'port_id': uuidutils.generate_uuid(),
'subnet_id': uuidutils.generate_uuid()} 'subnet_id': uuidutils.generate_uuid()}
lb = {'name': 'lb1', 'description': 'desc1', 'enabled': True, lb = {'name': 'lb1', 'description': 'desc1', 'enabled': True,
@ -661,6 +670,16 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
pool['load_balancer_id'] = lb.get('id') pool['load_balancer_id'] = lb.get('id')
redirect_pool['load_balancer_id'] = lb.get('id') redirect_pool['load_balancer_id'] = lb.get('id')
lb2_l7rule = {'type': constants.L7RULE_TYPE_HOST_NAME,
'compare_type': constants.L7RULE_COMPARE_TYPE_EQUAL_TO,
'value': 'localhost'}
lb2_l7policy = {'name': 'l7policy1', 'enabled': True,
'description': 'l7policy_description', 'position': 1,
'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL,
'redirect_url': 'www.example.com',
'l7rules': [lb2_l7rule],
'id': uuidutils.generate_uuid()}
lb2_l7rule['l7policy_id'] = lb2_l7policy.get('id')
lb2_health_monitor = {'type': constants.HEALTH_MONITOR_HTTP, lb2_health_monitor = {'type': constants.HEALTH_MONITOR_HTTP,
'delay': 1, 'timeout': 1, 'fall_threshold': 1, 'delay': 1, 'timeout': 1, 'fall_threshold': 1,
'rise_threshold': 1, 'enabled': True} 'rise_threshold': 1, 'enabled': True}
@ -681,10 +700,11 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'protocol': constants.PROTOCOL_HTTP, 'protocol': constants.PROTOCOL_HTTP,
'protocol_port': 83, 'connection_limit': 1, 'protocol_port': 83, 'connection_limit': 1,
'enabled': True, 'enabled': True,
'default_pool': lb2_pool, 'default_pool': lb2_pool, 'l7policies': [lb2_l7policy],
'provisioning_status': constants.PENDING_CREATE, 'provisioning_status': constants.PENDING_CREATE,
'operating_status': constants.ONLINE, 'operating_status': constants.ONLINE,
'id': uuidutils.generate_uuid()} 'id': uuidutils.generate_uuid()}
lb2_l7policy['listener_id'] = lb2_listener.get('id')
lb2 = {'name': 'lb2', 'description': 'desc2', 'enabled': True, lb2 = {'name': 'lb2', 'description': 'desc2', 'enabled': True,
'topology': constants.TOPOLOGY_ACTIVE_STANDBY, 'topology': constants.TOPOLOGY_ACTIVE_STANDBY,
'vrrp_group': None, 'vrrp_group': None,
@ -701,7 +721,9 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'listener': 10, 'listener': 10,
'pool': 10, 'pool': 10,
'health_monitor': 10, 'health_monitor': 10,
'member': 10} 'member': 10,
'l7policy': 10,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota) self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False) lock_session = db_api.get_session(autocommit=False)
self.assertRaises( self.assertRaises(
@ -716,7 +738,9 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'listener': 0, 'listener': 0,
'pool': 10, 'pool': 10,
'health_monitor': 10, 'health_monitor': 10,
'member': 10} 'member': 10,
'l7policy': 10,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota) self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False) lock_session = db_api.get_session(autocommit=False)
self.assertRaises( self.assertRaises(
@ -731,7 +755,9 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'listener': 10, 'listener': 10,
'pool': 0, 'pool': 0,
'health_monitor': 10, 'health_monitor': 10,
'member': 10} 'member': 10,
'l7policy': 10,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota) self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False) lock_session = db_api.get_session(autocommit=False)
self.assertRaises( self.assertRaises(
@ -746,7 +772,9 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'listener': 10, 'listener': 10,
'pool': 10, 'pool': 10,
'health_monitor': 0, 'health_monitor': 0,
'member': 10} 'member': 10,
'l7policy': 10,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota) self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False) lock_session = db_api.get_session(autocommit=False)
self.assertRaises( self.assertRaises(
@ -761,7 +789,43 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'listener': 10, 'listener': 10,
'pool': 10, 'pool': 10,
'health_monitor': 10, 'health_monitor': 10,
'member': 0} 'member': 0,
'l7policy': 10,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False)
self.assertRaises(
exceptions.QuotaException,
self.repos.create_load_balancer_tree,
self.session, lock_session, copy.deepcopy(lb))
# Make sure we didn't create the load balancer anyway
self.assertIsNone(self.repos.load_balancer.get(self.session,
name='lb1'))
quota = {'load_balancer': 10,
'listener': 10,
'pool': 10,
'health_monitor': 10,
'member': 10,
'l7policy': 0,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False)
self.assertRaises(
exceptions.QuotaException,
self.repos.create_load_balancer_tree,
self.session, lock_session, copy.deepcopy(lb))
# Make sure we didn't create the load balancer anyway
self.assertIsNone(self.repos.load_balancer.get(self.session,
name='lb1'))
quota = {'load_balancer': 10,
'listener': 10,
'pool': 10,
'health_monitor': 10,
'member': 10,
'l7policy': 10,
'l7rule': 0}
self.repos.quotas.update(self.session, project_id, quota=quota) self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False) lock_session = db_api.get_session(autocommit=False)
self.assertRaises( self.assertRaises(
@ -777,7 +841,9 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'listener': 10, 'listener': 10,
'pool': 1, 'pool': 1,
'health_monitor': 10, 'health_monitor': 10,
'member': 10} 'member': 10,
'l7policy': 10,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota) self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False) lock_session = db_api.get_session(autocommit=False)
self.assertRaises( self.assertRaises(
@ -793,7 +859,9 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'listener': 10, 'listener': 10,
'pool': 10, 'pool': 10,
'health_monitor': 1, 'health_monitor': 1,
'member': 10} 'member': 10,
'l7policy': 10,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota) self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False) lock_session = db_api.get_session(autocommit=False)
self.assertRaises( self.assertRaises(
@ -809,7 +877,45 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'listener': 10, 'listener': 10,
'pool': 10, 'pool': 10,
'health_monitor': 10, 'health_monitor': 10,
'member': 1} 'member': 1,
'l7policy': 10,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False)
self.assertRaises(
exceptions.QuotaException,
self.repos.create_load_balancer_tree,
self.session, lock_session, copy.deepcopy(lb))
# Make sure we didn't create the load balancer anyway
self.assertIsNone(self.repos.load_balancer.get(self.session,
name='lb1'))
# Test quota for l7policy
quota = {'load_balancer': 10,
'listener': 10,
'pool': 10,
'health_monitor': 10,
'member': 10,
'l7policy': 1,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False)
self.assertRaises(
exceptions.QuotaException,
self.repos.create_load_balancer_tree,
self.session, lock_session, copy.deepcopy(lb))
# Make sure we didn't create the load balancer anyway
self.assertIsNone(self.repos.load_balancer.get(self.session,
name='lb1'))
# Test quota for l7rule
quota = {'load_balancer': 10,
'listener': 10,
'pool': 10,
'health_monitor': 10,
'member': 10,
'l7policy': 10,
'l7rule': 1}
self.repos.quotas.update(self.session, project_id, quota=quota) self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False) lock_session = db_api.get_session(autocommit=False)
self.assertRaises( self.assertRaises(
@ -826,7 +932,9 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'listener': 10, 'listener': 10,
'pool': 10, 'pool': 10,
'health_monitor': 10, 'health_monitor': 10,
'member': 10} 'member': 10,
'l7policy': 10,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota) self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False) lock_session = db_api.get_session(autocommit=False)
self.repos.create_load_balancer_tree(self.session, lock_session, self.repos.create_load_balancer_tree(self.session, lock_session,
@ -851,7 +959,9 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'listener': 2, 'listener': 2,
'pool': 10, 'pool': 10,
'health_monitor': 10, 'health_monitor': 10,
'member': 10} 'member': 10,
'l7policy': 10,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota) self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False) lock_session = db_api.get_session(autocommit=False)
self.assertRaises( self.assertRaises(
@ -869,7 +979,9 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'listener': 10, 'listener': 10,
'pool': 2, 'pool': 2,
'health_monitor': 10, 'health_monitor': 10,
'member': 10} 'member': 10,
'l7policy': 10,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota) self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False) lock_session = db_api.get_session(autocommit=False)
self.assertRaises( self.assertRaises(
@ -887,7 +999,9 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'listener': 10, 'listener': 10,
'pool': 10, 'pool': 10,
'health_monitor': 1, 'health_monitor': 1,
'member': 10} 'member': 10,
'l7policy': 10,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota) self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False) lock_session = db_api.get_session(autocommit=False)
self.assertRaises( self.assertRaises(
@ -905,7 +1019,49 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'listener': 10, 'listener': 10,
'pool': 10, 'pool': 10,
'health_monitor': 10, 'health_monitor': 10,
'member': 2} 'member': 2,
'l7policy': 10,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False)
self.assertRaises(
exceptions.QuotaException,
self.repos.create_load_balancer_tree,
self.session, lock_session, copy.deepcopy(lb2))
# Make sure we didn't create the load balancer anyway
self.assertIsNone(self.repos.load_balancer.get(self.session,
name='lb2'))
# ### Test l7policy quota
# Create with custom quotas and limit to two l7policy (lb has two),
# expect error of too many l7policy/over quota
quota = {'load_balancer': 10,
'listener': 10,
'pool': 10,
'health_monitor': 10,
'member': 10,
'l7policy': 2,
'l7rule': 10}
self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False)
self.assertRaises(
exceptions.QuotaException,
self.repos.create_load_balancer_tree,
self.session, lock_session, copy.deepcopy(lb2))
# Make sure we didn't create the load balancer anyway
self.assertIsNone(self.repos.load_balancer.get(self.session,
name='lb2'))
# ### Test l7rule quota
# Create with custom quotas and limit to two l7rule (lb has two),
# expect error of too many l7rule/over quota
quota = {'load_balancer': 10,
'listener': 10,
'pool': 10,
'health_monitor': 10,
'member': 10,
'l7policy': 10,
'l7rule': 2}
self.repos.quotas.update(self.session, project_id, quota=quota) self.repos.quotas.update(self.session, project_id, quota=quota)
lock_session = db_api.get_session(autocommit=False) lock_session = db_api.get_session(autocommit=False)
self.assertRaises( self.assertRaises(
@ -1665,6 +1821,314 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
self.assertEqual(2, self.repos.quotas.get( self.assertEqual(2, self.repos.quotas.get(
self.session, project_id=project_id).in_use_member) self.session, project_id=project_id).in_use_member)
# ### Test l7policy quota
# Test with no pre-existing quota record default 0
project_id = uuidutils.generate_uuid()
conf.config(group='quotas', default_l7policy_quota=0)
self.assertTrue(self.repos.check_quota_met(self.session,
self.session,
models.L7Policy,
project_id))
self.assertIsNone(self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7policy)
# Test with no pre-existing quota record default 1
project_id = uuidutils.generate_uuid()
conf.config(group='quotas', default_l7policy_quota=1)
self.assertFalse(self.repos.check_quota_met(self.session,
self.session,
models.L7Policy,
project_id))
self.assertEqual(1, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7policy)
# Test above project is now at quota
self.assertTrue(self.repos.check_quota_met(self.session,
self.session,
models.L7Policy,
project_id))
self.assertEqual(1, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7policy)
# Test with no pre-existing quota record default unlimited
project_id = uuidutils.generate_uuid()
conf.config(group='quotas',
default_l7policy_quota=constants.QUOTA_UNLIMITED)
self.assertFalse(self.repos.check_quota_met(self.session,
self.session,
models.L7Policy,
project_id))
self.assertEqual(1, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7policy)
# Test above project adding another l7policy
self.assertFalse(self.repos.check_quota_met(self.session,
self.session,
models.L7Policy,
project_id))
self.assertEqual(2, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7policy)
# Test upgrade case with pre-quota l7policy
project_id = uuidutils.generate_uuid()
conf.config(group='quotas', default_l7policy_quota=1)
lb = self.repos.load_balancer.create(
self.session, id=uuidutils.generate_uuid(),
project_id=project_id, name="lb_name",
description="lb_description",
provisioning_status=constants.ACTIVE,
operating_status=constants.ONLINE,
enabled=True)
listener = self.repos.listener.create(
self.session, protocol=constants.PROTOCOL_HTTP, protocol_port=80,
enabled=True, provisioning_status=constants.ACTIVE,
operating_status=constants.ONLINE, project_id=project_id,
load_balancer_id=lb.id)
self.repos.l7policy.create(
self.session, name='l7policy', enabled=True, position=1,
action=constants.L7POLICY_ACTION_REJECT,
provisioning_status=constants.ACTIVE, listener_id=listener.id,
operating_status=constants.ONLINE, project_id=project_id,
id=uuidutils.generate_uuid())
self.assertTrue(self.repos.check_quota_met(self.session,
self.session,
models.L7Policy,
project_id))
# Test upgrade case with pre-quota deleted l7policy
project_id = uuidutils.generate_uuid()
conf.config(group='quotas', default_l7policy_quota=1)
lb = self.repos.load_balancer.create(
self.session, id=uuidutils.generate_uuid(),
project_id=project_id, name="lb_name",
description="lb_description",
provisioning_status=constants.ACTIVE,
operating_status=constants.ONLINE,
enabled=True)
listener = self.repos.listener.create(
self.session, protocol=constants.PROTOCOL_HTTP, protocol_port=80,
enabled=True, provisioning_status=constants.ACTIVE,
operating_status=constants.ONLINE, project_id=project_id,
load_balancer_id=lb.id)
self.repos.l7policy.create(
self.session, name='l7policy', enabled=True, position=1,
action=constants.L7POLICY_ACTION_REJECT,
provisioning_status=constants.DELETED, listener_id=listener.id,
operating_status=constants.ONLINE, project_id=project_id,
id=uuidutils.generate_uuid())
self.assertFalse(self.repos.check_quota_met(self.session,
self.session,
models.L7Policy,
project_id))
self.assertEqual(1, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7policy)
# Test pre-existing quota with quota of zero
project_id = uuidutils.generate_uuid()
conf.config(group='quotas', default_l7policy_quota=10)
quota = {'l7policy': 0}
self.repos.quotas.update(self.session, project_id, quota=quota)
self.assertTrue(self.repos.check_quota_met(self.session,
self.session,
models.L7Policy,
project_id))
# Test pre-existing quota with quota of one
project_id = uuidutils.generate_uuid()
conf.config(group='quotas', default_l7policy_quota=0)
quota = {'l7policy': 1}
self.repos.quotas.update(self.session, project_id, quota=quota)
self.assertFalse(self.repos.check_quota_met(self.session,
self.session,
models.L7Policy,
project_id))
self.assertEqual(1, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7policy)
# Test above project is now at quota
self.assertTrue(self.repos.check_quota_met(self.session,
self.session,
models.L7Policy,
project_id))
self.assertEqual(1, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7policy)
# Test pre-existing quota with quota of unlimited
project_id = uuidutils.generate_uuid()
conf.config(group='quotas', default_l7policy_quota=0)
quota = {'l7policy': constants.QUOTA_UNLIMITED}
self.repos.quotas.update(self.session, project_id, quota=quota)
self.assertFalse(self.repos.check_quota_met(self.session,
self.session,
models.L7Policy,
project_id))
self.assertEqual(1, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7policy)
# Test above project adding another l7policy
self.assertFalse(self.repos.check_quota_met(self.session,
self.session,
models.L7Policy,
project_id))
self.assertEqual(2, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7policy)
# ### Test l7rule quota
# Test with no pre-existing quota record default 0
project_id = uuidutils.generate_uuid()
conf.config(group='quotas', default_l7rule_quota=0)
self.assertTrue(self.repos.check_quota_met(self.session,
self.session,
models.L7Rule,
project_id))
self.assertIsNone(self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7rule)
# Test with no pre-existing quota record default 1
project_id = uuidutils.generate_uuid()
conf.config(group='quotas', default_l7rule_quota=1)
self.assertFalse(self.repos.check_quota_met(self.session,
self.session,
models.L7Rule,
project_id))
self.assertEqual(1, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7rule)
# Test above project is now at quota
self.assertTrue(self.repos.check_quota_met(self.session,
self.session,
models.L7Rule,
project_id))
self.assertEqual(1, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7rule)
# Test with no pre-existing quota record default unlimited
project_id = uuidutils.generate_uuid()
conf.config(group='quotas',
default_l7rule_quota=constants.QUOTA_UNLIMITED)
self.assertFalse(self.repos.check_quota_met(self.session,
self.session,
models.L7Rule,
project_id))
self.assertEqual(1, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7rule)
# Test above project adding another l7rule
self.assertFalse(self.repos.check_quota_met(self.session,
self.session,
models.L7Rule,
project_id))
self.assertEqual(2, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7rule)
# Test upgrade case with pre-quota l7rule
project_id = uuidutils.generate_uuid()
conf.config(group='quotas', default_l7rule_quota=1)
lb = self.repos.load_balancer.create(
self.session, id=uuidutils.generate_uuid(),
project_id=project_id, name="lb_name",
description="lb_description",
provisioning_status=constants.ACTIVE,
operating_status=constants.ONLINE,
enabled=True)
listener = self.repos.listener.create(
self.session, protocol=constants.PROTOCOL_HTTP, protocol_port=80,
enabled=True, provisioning_status=constants.ACTIVE,
operating_status=constants.ONLINE, project_id=project_id,
load_balancer_id=lb.id)
l7policy = self.repos.l7policy.create(
self.session, name='l7policy', enabled=True, position=1,
action=constants.L7POLICY_ACTION_REJECT,
provisioning_status=constants.ACTIVE, listener_id=listener.id,
operating_status=constants.ONLINE, project_id=project_id,
id=uuidutils.generate_uuid())
self.repos.l7rule.create(
self.session, id=uuidutils.generate_uuid(),
l7policy_id=l7policy.id, type=constants.L7RULE_TYPE_HOST_NAME,
compare_type=constants.L7RULE_COMPARE_TYPE_EQUAL_TO, enabled=True,
provisioning_status=constants.ACTIVE, value='hostname',
operating_status=constants.ONLINE, project_id=project_id)
self.assertTrue(self.repos.check_quota_met(self.session,
self.session,
models.L7Rule,
project_id))
# Test upgrade case with pre-quota deleted l7rule
project_id = uuidutils.generate_uuid()
conf.config(group='quotas', default_l7policy_quota=1)
lb = self.repos.load_balancer.create(
self.session, id=uuidutils.generate_uuid(),
project_id=project_id, name="lb_name",
description="lb_description",
provisioning_status=constants.ACTIVE,
operating_status=constants.ONLINE,
enabled=True)
listener = self.repos.listener.create(
self.session, protocol=constants.PROTOCOL_HTTP, protocol_port=80,
enabled=True, provisioning_status=constants.ACTIVE,
operating_status=constants.ONLINE, project_id=project_id,
load_balancer_id=lb.id)
l7policy = self.repos.l7policy.create(
self.session, name='l7policy', enabled=True, position=1,
action=constants.L7POLICY_ACTION_REJECT,
provisioning_status=constants.ACTIVE, listener_id=listener.id,
operating_status=constants.ONLINE, project_id=project_id,
id=uuidutils.generate_uuid())
self.repos.l7rule.create(
self.session, id=uuidutils.generate_uuid(),
l7policy_id=l7policy.id, type=constants.L7RULE_TYPE_HOST_NAME,
compare_type=constants.L7RULE_COMPARE_TYPE_EQUAL_TO, enabled=True,
provisioning_status=constants.DELETED, value='hostname',
operating_status=constants.ONLINE, project_id=project_id)
self.assertFalse(self.repos.check_quota_met(self.session,
self.session,
models.L7Rule,
project_id))
self.assertEqual(1, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7rule)
# Test pre-existing quota with quota of zero
project_id = uuidutils.generate_uuid()
conf.config(group='quotas', default_l7rule_quota=10)
quota = {'l7rule': 0}
self.repos.quotas.update(self.session, project_id, quota=quota)
self.assertTrue(self.repos.check_quota_met(self.session,
self.session,
models.L7Rule,
project_id))
# Test pre-existing quota with quota of one
project_id = uuidutils.generate_uuid()
conf.config(group='quotas', default_l7rule_quota=0)
quota = {'l7rule': 1}
self.repos.quotas.update(self.session, project_id, quota=quota)
self.assertFalse(self.repos.check_quota_met(self.session,
self.session,
models.L7Rule,
project_id))
self.assertEqual(1, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7rule)
# Test above project is now at quota
self.assertTrue(self.repos.check_quota_met(self.session,
self.session,
models.L7Rule,
project_id))
self.assertEqual(1, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7rule)
# Test pre-existing quota with quota of unlimited
project_id = uuidutils.generate_uuid()
conf.config(group='quotas', default_l7rule_quota=0)
quota = {'l7rule': constants.QUOTA_UNLIMITED}
self.repos.quotas.update(self.session, project_id, quota=quota)
self.assertFalse(self.repos.check_quota_met(self.session,
self.session,
models.L7Rule,
project_id))
self.assertEqual(1, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7rule)
# Test above project adding another l7rule
self.assertFalse(self.repos.check_quota_met(self.session,
self.session,
models.L7Rule,
project_id))
self.assertEqual(2, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7rule)
def test_decrement_quota(self): def test_decrement_quota(self):
# Test decrement on non-existent quota with noauth # Test decrement on non-existent quota with noauth
project_id = uuidutils.generate_uuid() project_id = uuidutils.generate_uuid()
@ -1929,6 +2393,99 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
self.assertEqual(0, self.repos.quotas.get( self.assertEqual(0, self.repos.quotas.get(
self.session, project_id=project_id).in_use_member) self.session, project_id=project_id).in_use_member)
conf.config(group='api_settings', auth_strategy=constants.TESTING) conf.config(group='api_settings', auth_strategy=constants.TESTING)
# ### Test l7policy quota
# Test decrement on zero in use quota
project_id = uuidutils.generate_uuid()
quota = {'in_use_l7policy': 0}
self.repos.quotas.update(self.session, project_id, quota=quota)
self.repos.decrement_quota(self.session,
models.L7Policy,
project_id)
self.assertEqual(0, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7policy)
# Test decrement on zero in use quota with noauth
project_id = uuidutils.generate_uuid()
conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
conf.config(group='api_settings', auth_strategy=constants.NOAUTH)
quota = {'in_use_l7policy': 0}
self.repos.quotas.update(self.session, project_id, quota=quota)
self.repos.decrement_quota(self.session,
models.L7Policy,
project_id)
self.assertEqual(0, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7policy)
conf.config(group='api_settings', auth_strategy=constants.TESTING)
# Test decrement on in use quota
project_id = uuidutils.generate_uuid()
quota = {'in_use_l7policy': 1}
self.repos.quotas.update(self.session, project_id, quota=quota)
self.repos.decrement_quota(self.session,
models.L7Policy,
project_id)
self.assertEqual(0, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7policy)
# Test decrement on in use quota with noauth
project_id = uuidutils.generate_uuid()
conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
conf.config(group='api_settings', auth_strategy=constants.NOAUTH)
quota = {'in_use_l7policy': 1}
self.repos.quotas.update(self.session, project_id, quota=quota)
self.repos.decrement_quota(self.session,
models.L7Policy,
project_id)
self.assertEqual(0, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7policy)
conf.config(group='api_settings', auth_strategy=constants.TESTING)
# ### Test l7rule quota
# Test decrement on zero in use quota
project_id = uuidutils.generate_uuid()
quota = {'in_use_l7rule': 0}
self.repos.quotas.update(self.session, project_id, quota=quota)
self.repos.decrement_quota(self.session,
models.L7Rule,
project_id)
self.assertEqual(0, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7rule)
# Test decrement on zero in use quota with noauth
project_id = uuidutils.generate_uuid()
conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
conf.config(group='api_settings', auth_strategy=constants.NOAUTH)
quota = {'in_use_l7rule': 0}
self.repos.quotas.update(self.session, project_id, quota=quota)
self.repos.decrement_quota(self.session,
models.L7Rule,
project_id)
self.assertEqual(0, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7rule)
conf.config(group='api_settings', auth_strategy=constants.TESTING)
# Test decrement on in use quota
project_id = uuidutils.generate_uuid()
quota = {'in_use_l7rule': 1}
self.repos.quotas.update(self.session, project_id, quota=quota)
self.repos.decrement_quota(self.session,
models.L7Rule,
project_id)
self.assertEqual(0, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7rule)
# Test decrement on in use quota with noauth
project_id = uuidutils.generate_uuid()
conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
conf.config(group='api_settings', auth_strategy=constants.NOAUTH)
quota = {'in_use_l7rule': 1}
self.repos.quotas.update(self.session, project_id, quota=quota)
self.repos.decrement_quota(self.session,
models.L7Rule,
project_id)
self.assertEqual(0, self.repos.quotas.get(
self.session, project_id=project_id).in_use_l7rule)
conf.config(group='api_settings', auth_strategy=constants.TESTING)
def test_get_amphora_stats(self): def test_get_amphora_stats(self):
listener2_id = uuidutils.generate_uuid() listener2_id = uuidutils.generate_uuid()
@ -4337,12 +4894,14 @@ class TestQuotasRepository(BaseRepositoryTest):
super(TestQuotasRepository, self).setUp() super(TestQuotasRepository, self).setUp()
def update_quotas(self, project_id, load_balancer=20, listener=20, pool=20, def update_quotas(self, project_id, load_balancer=20, listener=20, pool=20,
health_monitor=20, member=20): health_monitor=20, member=20, l7policy=20, l7rule=20):
quota = {'load_balancer': load_balancer, quota = {'load_balancer': load_balancer,
'listener': listener, 'listener': listener,
'pool': pool, 'pool': pool,
'health_monitor': health_monitor, 'health_monitor': health_monitor,
'member': member} 'member': member,
'l7policy': l7policy,
'l7rule': l7rule}
quotas = self.quota_repo.update(self.session, project_id, quota=quota) quotas = self.quota_repo.update(self.session, project_id, quota=quota)
return quotas return quotas
@ -4358,6 +4917,10 @@ class TestQuotasRepository(BaseRepositoryTest):
observed.health_monitor) observed.health_monitor)
self.assertEqual(expected.member, self.assertEqual(expected.member,
observed.member) observed.member)
self.assertEqual(expected.l7policy,
observed.l7policy)
self.assertEqual(expected.l7rule,
observed.l7rule)
def test_get(self): def test_get(self):
expected = self.update_quotas(self.FAKE_UUID_1) expected = self.update_quotas(self.FAKE_UUID_1)
@ -4394,6 +4957,8 @@ class TestQuotasRepository(BaseRepositoryTest):
self.assertIsNone(observed.listener) self.assertIsNone(observed.listener)
self.assertIsNone(observed.member) self.assertIsNone(observed.member)
self.assertIsNone(observed.pool) self.assertIsNone(observed.pool)
self.assertIsNone(observed.l7policy)
self.assertIsNone(observed.l7rule)
def test_delete_non_existent(self): def test_delete_non_existent(self):
self.assertRaises(exceptions.NotFound, self.assertRaises(exceptions.NotFound,

View File

@ -0,0 +1,87 @@
# Copyright (c) 2018 China Telecom Corporation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from wsme import exc
from wsme.rest import json as wsme_json
from wsme import types as wsme_types
from octavia.api.v2.types import quotas as quota_type
from octavia.common import constants
from octavia.tests.unit.api.v2.types import base
class TestQuotaPut(base.BaseTypesTest):
_type = quota_type.QuotaPUT
def test_quota(self):
body = {'quota': {'loadbalancer': 5}}
quota = wsme_json.fromjson(self._type, body)
self.assertEqual(wsme_types.Unset, quota.quota.listener)
self.assertEqual(wsme_types.Unset, quota.quota.pool)
self.assertEqual(wsme_types.Unset, quota.quota.member)
self.assertEqual(wsme_types.Unset, quota.quota.healthmonitor)
self.assertEqual(wsme_types.Unset, quota.quota.l7policy)
self.assertEqual(wsme_types.Unset, quota.quota.l7rule)
def test_invalid_quota(self):
body = {'quota': {'loadbalancer': constants.MAX_QUOTA + 1}}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson,
self._type, body)
body = {'quota': {'loadbalancer': constants.MIN_QUOTA - 1}}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson,
self._type, body)
body = {'quota': {'listener': constants.MAX_QUOTA + 1}}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson,
self._type, body)
body = {'quota': {'listener': constants.MIN_QUOTA - 1}}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson,
self._type, body)
body = {'quota': {'pool': constants.MAX_QUOTA + 1}}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson,
self._type, body)
body = {'quota': {'pool': constants.MIN_QUOTA - 1}}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson,
self._type, body)
body = {'quota': {'member': constants.MAX_QUOTA + 1}}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson,
self._type, body)
body = {'quota': {'member': constants.MIN_QUOTA - 1}}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson,
self._type, body)
body = {'quota': {'healthmonitor': constants.MAX_QUOTA + 1}}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson,
self._type, body)
body = {'quota': {'healthmonitor': constants.MIN_QUOTA - 1}}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson,
self._type, body)
body = {'quota': {'l7policy': constants.MAX_QUOTA + 1}}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson,
self._type, body)
body = {'quota': {'l7policy': constants.MIN_QUOTA - 1}}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson,
self._type, body)
body = {'quota': {'l7rule': constants.MAX_QUOTA + 1}}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson,
self._type, body)
body = {'quota': {'l7rule': constants.MIN_QUOTA - 1}}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson,
self._type, body)

View File

@ -118,6 +118,24 @@ class TestDataModels(base.TestCase):
compute_flavor=self.COMPUTE_FLAVOR compute_flavor=self.COMPUTE_FLAVOR
) )
self.QUOTA_obj = data_models.Quotas(
project_id=self.PROJECT_ID,
load_balancer=None,
listener=None,
pool=None,
health_monitor=None,
member=None,
l7policy=None,
l7rule=None,
in_use_health_monitor=None,
in_use_listener=None,
in_use_load_balancer=None,
in_use_member=None,
in_use_pool=None,
in_use_l7policy=None,
in_use_l7rule=None
)
super(TestDataModels, self).setUp() super(TestDataModels, self).setUp()
def test_LoadBalancer_update(self): def test_LoadBalancer_update(self):
@ -417,3 +435,47 @@ class TestDataModels(base.TestCase):
test_Amp_obj.update(update_dict) test_Amp_obj.update(update_dict)
self.assertEqual(reference_Amp_obj, test_Amp_obj) self.assertEqual(reference_Amp_obj, test_Amp_obj)
def test_Quota_update(self):
new_loadbalancer_quota = 10
new_listener_quota = 11
new_pool_quota = 12
new_healthmonitor_quota = 13
new_member_quota = 14
new_l7policy_quota = 15
new_l7rule_quota = 16
update_dict = {
'load_balancer': new_loadbalancer_quota,
'listener': new_listener_quota,
'pool': new_pool_quota,
'health_monitor': new_healthmonitor_quota,
'member': new_member_quota,
'l7policy': new_l7policy_quota,
'l7rule': new_l7rule_quota
}
test_Quota_obj = copy.deepcopy(self.QUOTA_obj)
reference_Quota_obj = data_models.Quotas(
project_id=self.PROJECT_ID,
load_balancer=new_loadbalancer_quota,
listener=new_listener_quota,
pool=new_pool_quota,
health_monitor=new_healthmonitor_quota,
member=new_member_quota,
l7policy=new_l7policy_quota,
l7rule=new_l7rule_quota,
in_use_health_monitor=None,
in_use_listener=None,
in_use_load_balancer=None,
in_use_member=None,
in_use_pool=None,
in_use_l7policy=None,
in_use_l7rule=None
)
test_Quota_obj.update(update_dict)
self.assertEqual(reference_Quota_obj, test_Quota_obj)

View File

@ -56,6 +56,8 @@ class TestDatabaseTasksQuota(base.TestCase):
if data_model == data_models.Pool: if data_model == data_models.Pool:
task.execute(test_object, self.zero_pool_child_count) task.execute(test_object, self.zero_pool_child_count)
else: else:
if data_model == data_models.L7Policy:
test_object.l7rules = []
task.execute(test_object) task.execute(test_object)
mock_decrement_quota.assert_called_once_with( mock_decrement_quota.assert_called_once_with(
@ -95,6 +97,8 @@ class TestDatabaseTasksQuota(base.TestCase):
self.zero_pool_child_count, self.zero_pool_child_count,
self._tf_failure_mock) self._tf_failure_mock)
else: else:
if data_model == data_models.L7Policy:
test_object.l7rules = []
task.revert(test_object, self._tf_failure_mock) task.revert(test_object, self._tf_failure_mock)
self.assertFalse(mock_get_session.called) self.assertFalse(mock_get_session.called)
self.assertFalse(mock_check_quota_met.called) self.assertFalse(mock_check_quota_met.called)
@ -320,3 +324,92 @@ class TestDatabaseTasksQuota(base.TestCase):
result = task.execute(pool_hm_2_mem) result = task.execute(pool_hm_2_mem)
self.assertEqual({'HM': 1, 'member': 2}, result) self.assertEqual({'HM': 1, 'member': 2}, result)
def test_decrement_l7policy_quota(self):
task = database_tasks.DecrementL7policyQuota()
data_model = data_models.L7Policy
self._test_decrement_quota(task, data_model)
@mock.patch('octavia.db.repositories.Repositories.decrement_quota')
@mock.patch('octavia.db.repositories.Repositories.check_quota_met')
def test_decrement_l7policy_quota_with_children(self,
mock_check_quota_met,
mock_decrement_quota):
project_id = uuidutils.generate_uuid()
test_l7rule1 = mock.MagicMock()
test_l7rule1.project_id = project_id
test_l7rule2 = mock.MagicMock()
test_l7rule2.project_id = project_id
test_object = mock.MagicMock()
test_object.project_id = project_id
test_object.l7rules = [test_l7rule1, test_l7rule2]
task = database_tasks.DecrementL7policyQuota()
mock_session = mock.MagicMock()
with mock.patch('octavia.db.api.'
'get_session') as mock_get_session_local:
mock_get_session_local.return_value = mock_session
task.execute(test_object)
calls = [mock.call(mock_session, data_models.L7Policy, project_id),
mock.call(mock_session, data_models.L7Rule, project_id,
quantity=2)]
mock_decrement_quota.assert_has_calls(calls)
mock_session.commit.assert_called_once_with()
# revert
mock_session.reset_mock()
with mock.patch('octavia.db.api.'
'get_session') as mock_get_session_local:
mock_lock_session = mock.MagicMock()
mock_get_session_local.side_effect = [mock_session,
mock_lock_session,
mock_lock_session,
mock_lock_session]
task.revert(test_object, None)
calls = [mock.call(mock_session, mock_lock_session,
data_models.L7Policy, project_id),
mock.call(mock_session, mock_lock_session,
data_models.L7Rule, project_id),
mock.call(mock_session, mock_lock_session,
data_models.L7Rule, project_id)]
mock_check_quota_met.assert_has_calls(calls)
self.assertEqual(3, mock_lock_session.commit.call_count)
# revert with l7rule quota exception
mock_session.reset_mock()
mock_check_quota_met.side_effect = [None, None,
Exception('fail')]
with mock.patch('octavia.db.api.'
'get_session') as mock_get_session_local:
mock_lock_session = mock.MagicMock()
mock_get_session_local.side_effect = [mock_session,
mock_lock_session,
mock_lock_session,
mock_lock_session]
task.revert(test_object, None)
calls = [mock.call(mock_session, mock_lock_session,
data_models.L7Policy, project_id),
mock.call(mock_session, mock_lock_session,
data_models.L7Rule, project_id),
mock.call(mock_session, mock_lock_session,
data_models.L7Rule, project_id)]
mock_check_quota_met.assert_has_calls(calls)
self.assertEqual(2, mock_lock_session.commit.call_count)
self.assertEqual(1, mock_lock_session.rollback.call_count)
def test_decrement_l7rule_quota(self):
task = database_tasks.DecrementL7ruleQuota()
data_model = data_models.L7Rule
self._test_decrement_quota(task, data_model)

View File

@ -53,6 +53,9 @@ class TestDatabaseTasksQuota(base.TestCase):
mock_session = mock.MagicMock() mock_session = mock.MagicMock()
mock_get_session_local.return_value = mock_session mock_get_session_local.return_value = mock_session
if data_model == data_models.L7Policy:
test_object.l7rules = []
if data_model == data_models.Pool: if data_model == data_models.Pool:
task.execute(test_object, self.zero_pool_child_count) task.execute(test_object, self.zero_pool_child_count)
else: else:
@ -338,3 +341,92 @@ class TestDatabaseTasksQuota(base.TestCase):
result = task.execute(pool_hm_2_mem.id) result = task.execute(pool_hm_2_mem.id)
self.assertEqual({'HM': 1, 'member': 2}, result) self.assertEqual({'HM': 1, 'member': 2}, result)
def test_decrement_l7policy_quota(self):
task = database_tasks.DecrementL7policyQuota()
data_model = data_models.L7Policy
self._test_decrement_quota(task, data_model)
@mock.patch('octavia.db.repositories.Repositories.decrement_quota')
@mock.patch('octavia.db.repositories.Repositories.check_quota_met')
def test_decrement_l7policy_quota_with_children(self,
mock_check_quota_met,
mock_decrement_quota):
project_id = uuidutils.generate_uuid()
test_l7rule1 = mock.MagicMock()
test_l7rule1.project_id = project_id
test_l7rule2 = mock.MagicMock()
test_l7rule2.project_id = project_id
test_object = mock.MagicMock()
test_object.project_id = project_id
test_object.l7rules = [test_l7rule1, test_l7rule2]
task = database_tasks.DecrementL7policyQuota()
mock_session = mock.MagicMock()
with mock.patch('octavia.db.api.'
'get_session') as mock_get_session_local:
mock_get_session_local.return_value = mock_session
task.execute(test_object)
calls = [mock.call(mock_session, data_models.L7Policy, project_id),
mock.call(mock_session, data_models.L7Rule, project_id,
quantity=2)]
mock_decrement_quota.assert_has_calls(calls)
mock_session.commit.assert_called_once_with()
# revert
mock_session.reset_mock()
with mock.patch('octavia.db.api.'
'get_session') as mock_get_session_local:
mock_lock_session = mock.MagicMock()
mock_get_session_local.side_effect = [mock_session,
mock_lock_session,
mock_lock_session,
mock_lock_session]
task.revert(test_object, None)
calls = [mock.call(mock_session, mock_lock_session,
data_models.L7Policy, project_id),
mock.call(mock_session, mock_lock_session,
data_models.L7Rule, project_id),
mock.call(mock_session, mock_lock_session,
data_models.L7Rule, project_id)]
mock_check_quota_met.assert_has_calls(calls)
self.assertEqual(3, mock_lock_session.commit.call_count)
# revert with l7rule quota exception
mock_session.reset_mock()
mock_check_quota_met.side_effect = [None, None,
Exception('fail')]
with mock.patch('octavia.db.api.'
'get_session') as mock_get_session_local:
mock_lock_session = mock.MagicMock()
mock_get_session_local.side_effect = [mock_session,
mock_lock_session,
mock_lock_session,
mock_lock_session]
task.revert(test_object, None)
calls = [mock.call(mock_session, mock_lock_session,
data_models.L7Policy, project_id),
mock.call(mock_session, mock_lock_session,
data_models.L7Rule, project_id),
mock.call(mock_session, mock_lock_session,
data_models.L7Rule, project_id)]
mock_check_quota_met.assert_has_calls(calls)
self.assertEqual(2, mock_lock_session.commit.call_count)
self.assertEqual(1, mock_lock_session.rollback.call_count)
def test_decrement_l7rule_quota(self):
task = database_tasks.DecrementL7ruleQuota()
data_model = data_models.L7Rule
self._test_decrement_quota(task, data_model)

View File

@ -0,0 +1,3 @@
---
features:
- Add l7policy and l7rule to octavia quota.