Check "security_group_rule" quota during security group creation
The tracked resources quota check is done at the beginning of an API
call to the Neutron server. The API call contains a resource and an
action over the resource. In case of creation, the server checks if
the number of items requested fits in the existing quota.
In case of security group creation, the tracked resource checked is
"security_group". But "SecurityGroupDbMixin.create_security_group"
method also creates several default rules for the new group and the
quota for "security_group_rule" is not enforced.
This patch checks the number of security group rules being created
("delta") and checks in the plugin method (not in the API method) if
there is enough room for those new rules (tracked resource
"security_group_rule").
Change-Id: I0a9b91b09d6260ff96fdba2f0a455de53bbc1f00
Closes-Bug: #1858680
(cherry picked from commit 936bd67aa4
)
This commit is contained in:
parent
496132a156
commit
ff607c3f22
|
@ -41,6 +41,7 @@ from neutron.extensions import securitygroup as ext_sg
|
|||
from neutron.objects import base as base_obj
|
||||
from neutron.objects import ports as port_obj
|
||||
from neutron.objects import securitygroup as sg_obj
|
||||
from neutron import quota
|
||||
|
||||
|
||||
@resource_extend.has_resource_extenders
|
||||
|
@ -108,6 +109,12 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase,
|
|||
name=s['name'], is_default=default_sg)
|
||||
sg.create()
|
||||
|
||||
delta = len(ext_sg.sg_supported_ethertypes)
|
||||
delta = delta * 2 if default_sg else delta
|
||||
reservation = quota.QUOTAS.make_reservation(
|
||||
context, tenant_id, {'security_group_rule': delta},
|
||||
self)
|
||||
|
||||
for ethertype in ext_sg.sg_supported_ethertypes:
|
||||
if default_sg:
|
||||
# Allow intercommunication
|
||||
|
@ -127,6 +134,9 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase,
|
|||
sg.rules.append(egress_rule)
|
||||
sg.obj_reset_changes(['rules'])
|
||||
|
||||
quota.QUOTAS.commit_reservation(context,
|
||||
reservation.reservation_id)
|
||||
|
||||
# fetch sg from db to load the sg rules with sg model.
|
||||
sg = sg_obj.SecurityGroup.get_object(context, id=sg.id)
|
||||
secgroup_dict = self._make_security_group_dict(sg)
|
||||
|
|
|
@ -334,3 +334,6 @@ class ClientFixture(fixtures.Fixture):
|
|||
self.addCleanup(
|
||||
_safe_method(self.client.delete_network_log), net_log['log']['id'])
|
||||
return net_log
|
||||
|
||||
def update_quota(self, project_id, tracked_resource, quota):
|
||||
self._update_resource('quota', project_id, {tracked_resource: quota})
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# under the License.
|
||||
|
||||
from neutron_lib import constants
|
||||
from neutronclient.common import exceptions as nc_exc
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from neutron.cmd.sanity import checks
|
||||
|
@ -517,3 +518,27 @@ class TestSecurityGroupsSameNetwork(BaseSecurityGroupsSameNetworkTest):
|
|||
vm1, vm2, net_helpers.NetcatTester.TCP, port + 1)
|
||||
self.verify_no_connectivity_between_vms(
|
||||
vm2, vm1, net_helpers.NetcatTester.TCP, port + 1)
|
||||
|
||||
|
||||
class SecurityGroupRulesTest(base.BaseFullStackTestCase):
|
||||
|
||||
def setUp(self):
|
||||
host_descriptions = [environment.HostDescription()]
|
||||
env = environment.Environment(environment.EnvironmentDescription(),
|
||||
host_descriptions)
|
||||
super(SecurityGroupRulesTest, self).setUp(env)
|
||||
|
||||
def test_security_group_rule_quota(self):
|
||||
project_id = uuidutils.generate_uuid()
|
||||
quota = self.client.show_quota_details(project_id)
|
||||
sg_rules_used = quota['quota']['security_group_rule']['used']
|
||||
self.assertEqual(0, sg_rules_used)
|
||||
|
||||
self.safe_client.create_security_group(project_id)
|
||||
quota = self.client.show_quota_details(project_id)
|
||||
sg_rules_used = quota['quota']['security_group_rule']['used']
|
||||
self.safe_client.update_quota(project_id, 'security_group_rule',
|
||||
sg_rules_used)
|
||||
|
||||
self.assertRaises(nc_exc.OverQuotaClient,
|
||||
self.safe_client.create_security_group, project_id)
|
||||
|
|
|
@ -21,6 +21,7 @@ from oslo_utils import uuidutils
|
|||
|
||||
from neutron.objects import network as network_obj
|
||||
from neutron.plugins.ml2 import plugin as ml2_plugin
|
||||
from neutron import quota
|
||||
from neutron.tests.unit import testlib_api
|
||||
|
||||
|
||||
|
@ -43,6 +44,10 @@ class NetworkRBACTestCase(testlib_api.SqlTestCase):
|
|||
self.subnet_1_id = uuidutils.generate_uuid()
|
||||
self.subnet_2_id = uuidutils.generate_uuid()
|
||||
self.port_id = uuidutils.generate_uuid()
|
||||
make_res = mock.patch.object(quota.QuotaEngine, 'make_reservation')
|
||||
self.mock_quota_make_res = make_res.start()
|
||||
commit_res = mock.patch.object(quota.QuotaEngine, 'commit_reservation')
|
||||
self.mock_quota_commit_res = commit_res.start()
|
||||
|
||||
def _create_network(self, tenant_id, network_id, shared, external=False):
|
||||
network = {'tenant_id': tenant_id,
|
||||
|
|
|
@ -45,6 +45,7 @@ from neutron.db import common_db_mixin
|
|||
from neutron.db import l3_agentschedulers_db
|
||||
from neutron.db import l3_hamode_db
|
||||
from neutron.objects import l3_hamode
|
||||
from neutron import quota
|
||||
from neutron.scheduler import l3_agent_scheduler
|
||||
from neutron.services.revisions import revision_plugin
|
||||
from neutron.tests.common import helpers
|
||||
|
@ -71,6 +72,10 @@ class L3HATestFramework(testlib_api.SqlTestCase):
|
|||
notif_p = mock.patch.object(l3_hamode_db.L3_HA_NAT_db_mixin,
|
||||
'_notify_router_updated')
|
||||
self.notif_m = notif_p.start()
|
||||
make_res = mock.patch.object(quota.QuotaEngine, 'make_reservation')
|
||||
self.mock_quota_make_res = make_res.start()
|
||||
commit_res = mock.patch.object(quota.QuotaEngine, 'commit_reservation')
|
||||
self.mock_quota_commit_res = commit_res.start()
|
||||
cfg.CONF.set_override('allow_overlapping_ips', True)
|
||||
|
||||
self.plugin = FakeL3PluginWithAgents()
|
||||
|
|
|
@ -26,6 +26,7 @@ import testtools
|
|||
from neutron.db import common_db_mixin
|
||||
from neutron.db import securitygroups_db
|
||||
from neutron.extensions import securitygroup
|
||||
from neutron import quota
|
||||
from neutron.services.revisions import revision_plugin
|
||||
from neutron.tests.unit import testlib_api
|
||||
|
||||
|
@ -73,6 +74,10 @@ class SecurityGroupDbMixinTestCase(testlib_api.SqlTestCase):
|
|||
self.setup_coreplugin(core_plugin=DB_PLUGIN_KLASS)
|
||||
self.ctx = context.get_admin_context()
|
||||
self.mixin = SecurityGroupDbMixinImpl()
|
||||
make_res = mock.patch.object(quota.QuotaEngine, 'make_reservation')
|
||||
self.mock_quota_make_res = make_res.start()
|
||||
commit_res = mock.patch.object(quota.QuotaEngine, 'commit_reservation')
|
||||
self.mock_quota_commit_res = commit_res.start()
|
||||
|
||||
def test_create_security_group_conflict(self):
|
||||
with mock.patch.object(registry, "publish") as mock_publish:
|
||||
|
|
|
@ -62,6 +62,7 @@ from neutron.plugins.ml2.drivers import type_vlan
|
|||
from neutron.plugins.ml2 import managers
|
||||
from neutron.plugins.ml2 import models
|
||||
from neutron.plugins.ml2 import plugin as ml2_plugin
|
||||
from neutron import quota
|
||||
from neutron.services.revisions import revision_plugin
|
||||
from neutron.services.segments import db as segments_plugin_db
|
||||
from neutron.services.segments import plugin as segments_plugin
|
||||
|
@ -2000,6 +2001,10 @@ class TestMl2PortBinding(Ml2PluginV2TestCase,
|
|||
cfg.CONF.set_override(
|
||||
'enable_security_group', self.ENABLE_SG,
|
||||
group='SECURITYGROUP')
|
||||
make_res = mock.patch.object(quota.QuotaEngine, 'make_reservation')
|
||||
self.mock_quota_make_res = make_res.start()
|
||||
commit_res = mock.patch.object(quota.QuotaEngine, 'commit_reservation')
|
||||
self.mock_quota_commit_res = commit_res.start()
|
||||
super(TestMl2PortBinding, self).setUp()
|
||||
|
||||
def _check_port_binding_profile(self, port, profile=None):
|
||||
|
@ -2720,6 +2725,10 @@ class TestMl2PortSecurity(Ml2PluginV2TestCase):
|
|||
cfg.CONF.set_override('enable_security_group',
|
||||
False,
|
||||
group='SECURITYGROUP')
|
||||
make_res = mock.patch.object(quota.QuotaEngine, 'make_reservation')
|
||||
self.mock_quota_make_res = make_res.start()
|
||||
commit_res = mock.patch.object(quota.QuotaEngine, 'commit_reservation')
|
||||
self.mock_quota_commit_res = commit_res.start()
|
||||
super(TestMl2PortSecurity, self).setUp()
|
||||
|
||||
def test_port_update_without_security_groups(self):
|
||||
|
|
|
@ -45,6 +45,7 @@ from neutron import manager
|
|||
from neutron.objects import agent as agent_obj
|
||||
from neutron.objects import l3_hamode
|
||||
from neutron.objects import l3agent as rb_obj
|
||||
from neutron import quota
|
||||
from neutron.scheduler import l3_agent_scheduler
|
||||
from neutron.tests import base
|
||||
from neutron.tests.common import helpers
|
||||
|
@ -1477,6 +1478,10 @@ class L3HATestCaseMixin(testlib_api.SqlTestCase,
|
|||
'neutron.scheduler.l3_agent_scheduler.ChanceScheduler'
|
||||
)
|
||||
self._register_l3_agents()
|
||||
make_res = mock.patch.object(quota.QuotaEngine, 'make_reservation')
|
||||
self.mock_make_res = make_res.start()
|
||||
commit_res = mock.patch.object(quota.QuotaEngine, 'commit_reservation')
|
||||
self.mock_quota_commit_res = commit_res.start()
|
||||
|
||||
@staticmethod
|
||||
def get_router_l3_agent_binding(context, router_id, l3_agent_id=None,
|
||||
|
|
Loading…
Reference in New Issue