RM8894
Adds a quota for the number of security groups allowed per port.
This commit is contained in:
@@ -42,7 +42,9 @@ quark_resources = [
|
||||
quota.BaseResource('routes_per_subnet',
|
||||
'quota_routes_per_subnet'),
|
||||
quota.BaseResource('security_rules_per_group',
|
||||
'quota_security_rules_per_group')
|
||||
'quota_security_rules_per_group'),
|
||||
quota.BaseResource('security_groups_per_port',
|
||||
'quota_security_groups_per_port')
|
||||
]
|
||||
|
||||
quark_quota_opts = [
|
||||
@@ -54,7 +56,10 @@ quark_quota_opts = [
|
||||
help=_('Maximum routes per subnet')),
|
||||
cfg.IntOpt('quota_security_rules_per_group',
|
||||
default=20,
|
||||
help=_('Maximum security group rules in a group'))
|
||||
help=_('Maximum security group rules in a group')),
|
||||
cfg.IntOpt("quota_security_groups_per_port",
|
||||
default=5,
|
||||
help=_("Maximum number of security groups per port"))
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
import netaddr
|
||||
from neutron.common import exceptions
|
||||
from neutron.extensions import securitygroup as sg_ext
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.openstack.common import uuidutils
|
||||
from neutron import quota
|
||||
@@ -90,9 +91,11 @@ def create_port(context, port):
|
||||
|
||||
ipam_driver = ipam.IPAM_REGISTRY.get_strategy(net["ipam_strategy"])
|
||||
net_driver = registry.DRIVER_REGISTRY.get_driver(net["network_plugin"])
|
||||
group_ids, security_groups = v.make_security_group_list(
|
||||
group_ids, security_groups = _make_security_group_list(
|
||||
context, port["port"].pop("security_groups", None))
|
||||
|
||||
quota.QUOTAS.limit_check(context, context.tenant_id,
|
||||
security_groups_per_port=len(group_ids))
|
||||
addresses = []
|
||||
mac = None
|
||||
backend_port = None
|
||||
@@ -225,6 +228,11 @@ def update_port(context, id, port):
|
||||
utils.filter_body(context, port_dict, admin_only=admin_only,
|
||||
always_filter=always_filter)
|
||||
|
||||
group_ids, security_groups = _make_security_group_list(
|
||||
context, port_dict.pop("security_groups", None))
|
||||
quota.QUOTAS.limit_check(context, context.tenant_id,
|
||||
security_groups_per_port=len(group_ids))
|
||||
|
||||
if fixed_ips is not None:
|
||||
# NOTE(mdietz): we want full control over IPAM since
|
||||
# we're allocating by subnet instead of
|
||||
@@ -283,8 +291,6 @@ def update_port(context, id, port):
|
||||
port_dict["addresses"] = port_db["ip_addresses"]
|
||||
port_dict["addresses"].extend(addresses)
|
||||
|
||||
group_ids, security_groups = v.make_security_group_list(
|
||||
context, port_dict.pop("security_groups", None))
|
||||
net_driver = registry.DRIVER_REGISTRY.get_driver(
|
||||
port_db.network["network_plugin"])
|
||||
net_driver.update_port(context, port_id=port_db.backend_key,
|
||||
@@ -489,3 +495,17 @@ def diagnose_port(context, id, fields):
|
||||
raise exceptions.PortNotFound(port_id=id, net_id='')
|
||||
port = _diag_port(context, db_port, fields)
|
||||
return {'ports': port}
|
||||
|
||||
|
||||
def _make_security_group_list(context, group_ids):
|
||||
if not group_ids or not utils.attr_specified(group_ids):
|
||||
return ([], [])
|
||||
group_ids = list(set(group_ids))
|
||||
groups = []
|
||||
for gid in group_ids:
|
||||
group = db_api.security_group_find(context, id=gid,
|
||||
scope=db_api.ONE)
|
||||
if not group:
|
||||
raise sg_ext.SecurityGroupNotFound(id=gid)
|
||||
groups.append(group)
|
||||
return (group_ids, groups)
|
||||
|
||||
@@ -18,15 +18,13 @@ View Helpers for Quark Plugin
|
||||
"""
|
||||
|
||||
import netaddr
|
||||
from neutron.extensions import securitygroup as sg_ext
|
||||
from neutron.openstack.common import log as logging
|
||||
from oslo.config import cfg
|
||||
|
||||
from quark.db import api as db_api
|
||||
from quark.db import models
|
||||
from quark import network_strategy
|
||||
from quark import protocols
|
||||
from quark import utils
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
@@ -260,17 +258,3 @@ def _make_ip_policy_dict(ipp):
|
||||
"subnet_ids": [s["id"] for s in ipp["subnets"]],
|
||||
"network_ids": [n["id"] for n in ipp["networks"]],
|
||||
"exclude": [ippc["cidr"] for ippc in ipp["exclude"]]}
|
||||
|
||||
|
||||
def make_security_group_list(context, group_ids):
|
||||
if not group_ids or not utils.attr_specified(group_ids):
|
||||
return ([], [])
|
||||
group_ids = list(set(group_ids))
|
||||
groups = []
|
||||
for gid in group_ids:
|
||||
group = db_api.security_group_find(context, id=gid,
|
||||
scope=db_api.ONE)
|
||||
if not group:
|
||||
raise sg_ext.SecurityGroupNotFound(id=gid)
|
||||
groups.append(group)
|
||||
return (group_ids, groups)
|
||||
|
||||
@@ -243,7 +243,8 @@ class TestQuarkCreatePortFailure(test_quark_plugin.TestQuarkPlugin):
|
||||
|
||||
class TestQuarkCreatePort(test_quark_plugin.TestQuarkPlugin):
|
||||
@contextlib.contextmanager
|
||||
def _stubs(self, port=None, network=None, addr=None, mac=None):
|
||||
def _stubs(self, port=None, network=None, addr=None, mac=None,
|
||||
limit_raise=False):
|
||||
if network:
|
||||
network["network_plugin"] = "BASE"
|
||||
network["ipam_strategy"] = "ANY"
|
||||
@@ -259,12 +260,16 @@ class TestQuarkCreatePort(test_quark_plugin.TestQuarkPlugin):
|
||||
mock.patch("%s.allocate_ip_address" % ipam),
|
||||
mock.patch("%s.allocate_mac_address" % ipam),
|
||||
mock.patch("%s.port_count_all" % db_mod),
|
||||
) as (port_create, net_find, alloc_ip, alloc_mac, port_count):
|
||||
mock.patch("neutron.quota.QuotaEngine.limit_check")
|
||||
) as (port_create, net_find, alloc_ip, alloc_mac, port_count,
|
||||
limit_check):
|
||||
port_create.return_value = port_models
|
||||
net_find.return_value = network
|
||||
alloc_ip.return_value = addr
|
||||
alloc_mac.return_value = mac
|
||||
port_count.return_value = 0
|
||||
if limit_raise:
|
||||
limit_check.side_effect = exceptions.OverQuota
|
||||
yield port_create
|
||||
|
||||
def test_create_port(self):
|
||||
@@ -419,6 +424,32 @@ class TestQuarkCreatePort(test_quark_plugin.TestQuarkPlugin):
|
||||
with self.assertRaises(sg_ext.SecurityGroupNotFound):
|
||||
self.test_create_port_security_groups([])
|
||||
|
||||
def test_create_port_security_groups_over_quota(self):
|
||||
network = dict(id=1)
|
||||
mac = dict(address="AA:BB:CC:DD:EE:FF")
|
||||
port_name = "foobar"
|
||||
ip = dict()
|
||||
|
||||
groups = []
|
||||
group_ids = range(6)
|
||||
for gid in group_ids:
|
||||
group = models.SecurityGroup()
|
||||
group.update({'id': gid, 'tenant_id': self.context.tenant_id,
|
||||
'name': 'foo', 'description': 'bar'})
|
||||
groups.append(group)
|
||||
|
||||
port = dict(port=dict(mac_address=mac["address"], network_id=1,
|
||||
tenant_id=self.context.tenant_id, device_id=2,
|
||||
name=port_name, security_groups=groups))
|
||||
|
||||
with self._stubs(port=port["port"], network=network, addr=ip,
|
||||
mac=mac, limit_raise=True):
|
||||
with mock.patch("quark.db.api.security_group_find") as group_find:
|
||||
group_find.return_value = groups
|
||||
port["port"]["security_groups"] = groups
|
||||
with self.assertRaises(exceptions.OverQuota):
|
||||
self.plugin.create_port(self.context, port)
|
||||
|
||||
|
||||
class TestQuarkPortCreateQuota(test_quark_plugin.TestQuarkPlugin):
|
||||
@contextlib.contextmanager
|
||||
@@ -438,12 +469,15 @@ class TestQuarkPortCreateQuota(test_quark_plugin.TestQuarkPlugin):
|
||||
mock.patch("%s.allocate_ip_address" % ipam),
|
||||
mock.patch("%s.allocate_mac_address" % ipam),
|
||||
mock.patch("quark.db.api.port_count_all"),
|
||||
) as (port_create, net_find, alloc_ip, alloc_mac, port_count):
|
||||
mock.patch("neutron.quota.QuotaEngine.limit_check")
|
||||
) as (port_create, net_find, alloc_ip, alloc_mac, port_count,
|
||||
limit_check):
|
||||
port_create.return_value = port_models
|
||||
net_find.return_value = network
|
||||
alloc_ip.return_value = addr
|
||||
alloc_mac.return_value = mac
|
||||
port_count.return_value = len(network["ports"])
|
||||
limit_check.side_effect = exceptions.OverQuota
|
||||
yield port_create
|
||||
|
||||
def test_create_port_net_at_max(self):
|
||||
@@ -473,8 +507,9 @@ class TestQuarkUpdatePort(test_quark_plugin.TestQuarkPlugin):
|
||||
mock.patch("quark.db.api.port_find"),
|
||||
mock.patch("quark.db.api.port_update"),
|
||||
mock.patch("quark.ipam.QuarkIpam.allocate_ip_address"),
|
||||
mock.patch("quark.ipam.QuarkIpam.deallocate_ips_by_port")
|
||||
) as (port_find, port_update, alloc_ip, dealloc_ip):
|
||||
mock.patch("quark.ipam.QuarkIpam.deallocate_ips_by_port"),
|
||||
mock.patch("neutron.quota.QuotaEngine.limit_check")
|
||||
) as (port_find, port_update, alloc_ip, dealloc_ip, limit_check):
|
||||
port_find.return_value = port_model
|
||||
port_update.return_value = port_model
|
||||
if new_ips:
|
||||
@@ -574,8 +609,9 @@ class TestQuarkUpdatePortSetsIps(test_quark_plugin.TestQuarkPlugin):
|
||||
with contextlib.nested(
|
||||
mock.patch("quark.db.api.port_find"),
|
||||
mock.patch("quark.db.api.port_update"),
|
||||
mock.patch("quark.ipam.QuarkIpam.deallocate_ips_by_port")
|
||||
) as (port_find, port_update, dealloc_ip):
|
||||
mock.patch("quark.ipam.QuarkIpam.deallocate_ips_by_port"),
|
||||
mock.patch("neutron.quota.QuotaEngine.limit_check")
|
||||
) as (port_find, port_update, dealloc_ip, limit_check):
|
||||
port_find.return_value = port_model
|
||||
port_update.return_value = port_model
|
||||
alloc_ip = mock.patch("quark.ipam.QuarkIpam.allocate_ip_address",
|
||||
@@ -756,7 +792,8 @@ class TestQuarkCreatePortOnSharedNetworks(test_quark_plugin.TestQuarkPlugin):
|
||||
mock.patch("%s.network_find" % db_mod),
|
||||
mock.patch("%s.allocate_ip_address" % ipam),
|
||||
mock.patch("%s.allocate_mac_address" % ipam),
|
||||
) as (port_create, net_find, alloc_ip, alloc_mac):
|
||||
mock.patch("neutron.quota.QuotaEngine.limit_check")
|
||||
) as (port_create, net_find, alloc_ip, alloc_mac, limit_check):
|
||||
port_create.return_value = port_models
|
||||
net_find.return_value = network
|
||||
alloc_ip.return_value = addr
|
||||
@@ -996,8 +1033,9 @@ class TestQuarkPortCreateFiltering(test_quark_plugin.TestQuarkPlugin):
|
||||
mock.patch("neutron.openstack.common.uuidutils.generate_uuid"),
|
||||
mock.patch("quark.plugin_views._make_port_dict"),
|
||||
mock.patch("%s.port_count_all" % db_mod),
|
||||
mock.patch("neutron.quota.QuotaEngine.limit_check")
|
||||
) as (port_create, net_find, alloc_ip, alloc_mac, gen_uuid, make_port,
|
||||
port_count):
|
||||
port_count, limit_check):
|
||||
net_find.return_value = network
|
||||
alloc_ip.return_value = addr
|
||||
alloc_mac.return_value = mac
|
||||
@@ -1084,7 +1122,8 @@ class TestQuarkPortUpdateFiltering(test_quark_plugin.TestQuarkPlugin):
|
||||
mock.patch("quark.db.api.port_update"),
|
||||
mock.patch("quark.drivers.registry.DriverRegistry.get_driver"),
|
||||
mock.patch("quark.plugin_views._make_port_dict"),
|
||||
) as (port_find, port_update, get_driver, make_port):
|
||||
mock.patch("neutron.quota.QuotaEngine.limit_check")
|
||||
) as (port_find, port_update, get_driver, make_port, limit_check):
|
||||
yield port_find, port_update
|
||||
|
||||
def test_update_port_attribute_filtering(self):
|
||||
|
||||
Reference in New Issue
Block a user