Quotas API
This commit is contained in:
		| @@ -35,6 +35,7 @@ from neutron.openstack.common.db.sqlalchemy import session as neutron_session | |||||||
| from neutron.openstack.common import importutils | from neutron.openstack.common import importutils | ||||||
| from neutron.openstack.common import log as logging | from neutron.openstack.common import log as logging | ||||||
| from neutron.openstack.common import uuidutils | from neutron.openstack.common import uuidutils | ||||||
|  | from neutron import quota | ||||||
|  |  | ||||||
| from neutron import neutron_plugin_base_v2 | from neutron import neutron_plugin_base_v2 | ||||||
|  |  | ||||||
| @@ -66,8 +67,18 @@ quark_opts = [ | |||||||
|                help=_("Path to the config for the net driver")) |                help=_("Path to the config for the net driver")) | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | quark_quota_opts = [ | ||||||
|  |     cfg.IntOpt('quota_ports_per_network', | ||||||
|  |                default=64, | ||||||
|  |                help=_('Maximum ports per network per tenant')), | ||||||
|  |     cfg.IntOpt('quota_security_rules_per_group', | ||||||
|  |                default=20, | ||||||
|  |                help=_('Maximum security group rules in a group')), | ||||||
|  | ] | ||||||
|  |  | ||||||
| STRATEGY = network_strategy.STRATEGY | STRATEGY = network_strategy.STRATEGY | ||||||
| CONF.register_opts(quark_opts, "QUARK") | CONF.register_opts(quark_opts, "QUARK") | ||||||
|  | CONF.register_opts(quark_quota_opts, "QUOTAS") | ||||||
|  |  | ||||||
|  |  | ||||||
| def _pop_param(attrs, param, default=None): | def _pop_param(attrs, param, default=None): | ||||||
| @@ -93,7 +104,8 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2, | |||||||
|     supported_extension_aliases = ["mac_address_ranges", "routes", |     supported_extension_aliases = ["mac_address_ranges", "routes", | ||||||
|                                    "ip_addresses", "ports_quark", |                                    "ip_addresses", "ports_quark", | ||||||
|                                    "security-group", |                                    "security-group", | ||||||
|                                    "subnets_quark", "provider", "ip_policies"] |                                    "subnets_quark", "provider", | ||||||
|  |                                    "ip_policies", "quotas"] | ||||||
|  |  | ||||||
|     def _initDBMaker(self): |     def _initDBMaker(self): | ||||||
|         # This needs to be called after _ENGINE is configured |         # This needs to be called after _ENGINE is configured | ||||||
| @@ -125,6 +137,14 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2, | |||||||
|         self.ipam_reuse_after = CONF.QUARK.ipam_reuse_after |         self.ipam_reuse_after = CONF.QUARK.ipam_reuse_after | ||||||
|         neutron_db_api.register_models(base=models.BASEV2) |         neutron_db_api.register_models(base=models.BASEV2) | ||||||
|  |  | ||||||
|  |         quark_resources = [ | ||||||
|  |             quota.BaseResource('ports_per_network', | ||||||
|  |                                'quota_ports_per_network'), | ||||||
|  |             quota.BaseResource('security_rules_per_group', | ||||||
|  |                                'quota_security_rules_per_group'), | ||||||
|  |         ] | ||||||
|  |         quota.QUOTAS.register_resources(quark_resources) | ||||||
|  |  | ||||||
|     def _make_security_group_list(self, context, group_ids): |     def _make_security_group_list(self, context, group_ids): | ||||||
|         if not group_ids or group_ids is attributes.ATTR_NOT_SPECIFIED: |         if not group_ids or group_ids is attributes.ATTR_NOT_SPECIFIED: | ||||||
|             return ([], []) |             return ([], []) | ||||||
| @@ -590,6 +610,10 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2, | |||||||
|             if not net: |             if not net: | ||||||
|                 raise exceptions.NetworkNotFound(net_id=net_id) |                 raise exceptions.NetworkNotFound(net_id=net_id) | ||||||
|  |  | ||||||
|  |         quota.QUOTAS.limit_check( | ||||||
|  |             context, context.tenant_id, | ||||||
|  |             ports_per_network=len(net.get('ports', []))+1) | ||||||
|  |  | ||||||
|         if fixed_ips: |         if fixed_ips: | ||||||
|             for fixed_ip in fixed_ips: |             for fixed_ip in fixed_ips: | ||||||
|                 subnet_id = fixed_ip.get("subnet_id") |                 subnet_id = fixed_ip.get("subnet_id") | ||||||
| @@ -1080,9 +1104,6 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2, | |||||||
|     def create_security_group(self, context, security_group): |     def create_security_group(self, context, security_group): | ||||||
|         LOG.info("create_security_group for tenant %s" % |         LOG.info("create_security_group for tenant %s" % | ||||||
|                 (context.tenant_id)) |                 (context.tenant_id)) | ||||||
|         if (db_api.security_group_find(context).count() >= |  | ||||||
|                 CONF.QUOTAS.quota_security_group): |  | ||||||
|             raise exceptions.OverQuota(overs="security groups") |  | ||||||
|         group = security_group["security_group"] |         group = security_group["security_group"] | ||||||
|         group_name = group.get('name', '') |         group_name = group.get('name', '') | ||||||
|         if group_name == "default": |         if group_name == "default": | ||||||
| @@ -1107,14 +1128,13 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2, | |||||||
|             'group_id': '00000000-0000-0000-0000-000000000000', |             'group_id': '00000000-0000-0000-0000-000000000000', | ||||||
|             'port_egress_rules': [], |             'port_egress_rules': [], | ||||||
|             'port_ingress_rules': [ |             'port_ingress_rules': [ | ||||||
|                 {'ethertype': 'IPv4', 'protocol': 6, |                 {'ethertype': 'IPv4', 'protocol': 1}, | ||||||
|                     'port_range_min': 0, 'port_range_max': 65535}, |                 {'ethertype': 'IPv4', 'protocol': 6}, | ||||||
|                 {'ethertype': 'IPv4', 'protocol': 17, |                 {'ethertype': 'IPv4', 'protocol': 17}, | ||||||
|                     'port_range_min': 0, 'port_range_max': 65535}, |                 {'ethertype': 'IPv6', 'protocol': 1}, | ||||||
|                 {'ethertype': 'IPv6', 'protocol': 6, |                 {'ethertype': 'IPv6', 'protocol': 6}, | ||||||
|                     'port_range_min': 0, 'port_range_max': 65535}, |                 {'ethertype': 'IPv6', 'protocol': 17}, | ||||||
|                 {'ethertype': 'IPv6', 'protocol': 17, |             ]} | ||||||
|                     'port_range_min': 0, 'port_range_max': 65535}]} |  | ||||||
|  |  | ||||||
|         self.net_driver.create_security_group( |         self.net_driver.create_security_group( | ||||||
|             context, |             context, | ||||||
| @@ -1134,9 +1154,6 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2, | |||||||
|     def create_security_group_rule(self, context, security_group_rule): |     def create_security_group_rule(self, context, security_group_rule): | ||||||
|         LOG.info("create_security_group for tenant %s" % |         LOG.info("create_security_group for tenant %s" % | ||||||
|                 (context.tenant_id)) |                 (context.tenant_id)) | ||||||
|         if (db_api.security_group_rule_find(context).count() >= |  | ||||||
|                 CONF.QUOTAS.quota_security_group_rule): |  | ||||||
|             raise exceptions.OverQuota(overs="security group rules") |  | ||||||
|         rule = self._validate_security_group_rule( |         rule = self._validate_security_group_rule( | ||||||
|             context, security_group_rule["security_group_rule"]) |             context, security_group_rule["security_group_rule"]) | ||||||
|         rule['id'] = uuidutils.generate_uuid() |         rule['id'] = uuidutils.generate_uuid() | ||||||
| @@ -1147,6 +1164,10 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2, | |||||||
|         if not group: |         if not group: | ||||||
|             raise sg_ext.SecurityGroupNotFound(group_id=group_id) |             raise sg_ext.SecurityGroupNotFound(group_id=group_id) | ||||||
|  |  | ||||||
|  |         quota.QUOTAS.limit_check( | ||||||
|  |             context, context.tenant_id, | ||||||
|  |             security_rules_per_group=len(group.get('rules', []))+1) | ||||||
|  |  | ||||||
|         self.net_driver.create_security_group_rule( |         self.net_driver.create_security_group_rule( | ||||||
|             context, |             context, | ||||||
|             group_id, |             group_id, | ||||||
|   | |||||||
							
								
								
									
										49
									
								
								quark/quota_driver.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								quark/quota_driver.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | # vim: tabstop=4 shiftwidth=4 softtabstop=4 | ||||||
|  |  | ||||||
|  | # Copyright 2011 OpenStack Foundation. | ||||||
|  | # 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 neutron.db import quota_db | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class QuarkQuotaDriver(quota_db.DbQuotaDriver): | ||||||
|  |     """Driver to perform necessary checks to enforce quotas and obtain quota | ||||||
|  |     information. | ||||||
|  |  | ||||||
|  |     The default driver utilizes the local database. | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def delete_tenant_quota(context, tenant_id): | ||||||
|  |         """Delete the quota entries for a given tenant_id. | ||||||
|  |  | ||||||
|  |         Atfer deletion, this tenant will use default quota values in conf. | ||||||
|  |         """ | ||||||
|  |         tenant_quotas = context.session.query(quota_db.Quota) | ||||||
|  |         tenant_quotas = tenant_quotas.filter_by(tenant_id=tenant_id) | ||||||
|  |         tenant_quotas.delete() | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def update_quota_limit(context, tenant_id, resource, limit): | ||||||
|  |         tenant_quota = context.session.query(quota_db.Quota).filter_by( | ||||||
|  |             tenant_id=tenant_id, resource=resource).first() | ||||||
|  |  | ||||||
|  |         if tenant_quota: | ||||||
|  |             tenant_quota.update({'limit': limit}) | ||||||
|  |         else: | ||||||
|  |             tenant_quota = quota_db.Quota(tenant_id=tenant_id, | ||||||
|  |                                           resource=resource, | ||||||
|  |                                           limit=limit) | ||||||
|  |             context.session.add(tenant_quota) | ||||||
| @@ -37,6 +37,7 @@ class TestQuarkPlugin(test_base.TestBase): | |||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         super(TestQuarkPlugin, self).setUp() |         super(TestQuarkPlugin, self).setUp() | ||||||
|  |  | ||||||
|  |         cfg.CONF.set_override('quota_ports_per_network', 1, 'QUOTAS') | ||||||
|         cfg.CONF.set_override('connection', 'sqlite://', 'database') |         cfg.CONF.set_override('connection', 'sqlite://', 'database') | ||||||
|         db_api.configure_db() |         db_api.configure_db() | ||||||
|         self.plugin = quark.plugin.Plugin() |         self.plugin = quark.plugin.Plugin() | ||||||
| @@ -1219,6 +1220,18 @@ class TestQuarkCreatePort(TestQuarkPlugin): | |||||||
|             with self.assertRaises(exceptions.NetworkNotFound): |             with self.assertRaises(exceptions.NetworkNotFound): | ||||||
|                 self.plugin.create_port(self.context, port) |                 self.plugin.create_port(self.context, port) | ||||||
|  |  | ||||||
|  |     def test_create_port_net_at_max(self): | ||||||
|  |         network = dict(id=1, ports=[models.Port()]) | ||||||
|  |         mac = dict(address="aa:bb:cc:dd:ee:ff") | ||||||
|  |         port_name = "foobar" | ||||||
|  |         ip = dict() | ||||||
|  |         port = dict(port=dict(mac_address=mac["address"], network_id=1, | ||||||
|  |                               tenant_id=self.context.tenant_id, device_id=2, | ||||||
|  |                               name=port_name)) | ||||||
|  |         with self._stubs(port=port["port"], network=network, addr=ip, mac=mac): | ||||||
|  |             with self.assertRaises(exceptions.OverQuota): | ||||||
|  |                 self.plugin.create_port(self.context, port) | ||||||
|  |  | ||||||
|     def test_create_port_security_groups(self, groups=[1]): |     def test_create_port_security_groups(self, groups=[1]): | ||||||
|         network = dict(id=1) |         network = dict(id=1) | ||||||
|         mac = dict(address="aa:bb:cc:dd:ee:ff") |         mac = dict(address="aa:bb:cc:dd:ee:ff") | ||||||
| @@ -1888,6 +1901,7 @@ class TestQuarkCreateSecurityGroupRule(TestQuarkPlugin): | |||||||
|     def setUp(self, *args, **kwargs): |     def setUp(self, *args, **kwargs): | ||||||
|         super(TestQuarkCreateSecurityGroupRule, self).setUp(*args, **kwargs) |         super(TestQuarkCreateSecurityGroupRule, self).setUp(*args, **kwargs) | ||||||
|         cfg.CONF.set_override('quota_security_group_rule', 1, 'QUOTAS') |         cfg.CONF.set_override('quota_security_group_rule', 1, 'QUOTAS') | ||||||
|  |         cfg.CONF.set_override('quota_security_rules_per_group', 1, 'QUOTAS') | ||||||
|         self.rule = {'id': 1, 'ethertype': 'IPv4', |         self.rule = {'id': 1, 'ethertype': 'IPv4', | ||||||
|                      'security_group_id': 1, 'group': {'id': 1}} |                      'security_group_id': 1, 'group': {'id': 1}} | ||||||
|         self.expected = { |         self.expected = { | ||||||
| @@ -1928,6 +1942,7 @@ class TestQuarkCreateSecurityGroupRule(TestQuarkPlugin): | |||||||
|         rule = dict(self.rule, **ruleset) |         rule = dict(self.rule, **ruleset) | ||||||
|         group = rule.pop('group') |         group = rule.pop('group') | ||||||
|         expected = dict(self.expected, **ruleset) |         expected = dict(self.expected, **ruleset) | ||||||
|  |         expected.pop('group', None) | ||||||
|         with self._stubs(rule, group) as rule_create: |         with self._stubs(rule, group) as rule_create: | ||||||
|             result = self.plugin.create_security_group_rule( |             result = self.plugin.create_security_group_rule( | ||||||
|                 self.context, {'security_group_rule': rule}) |                 self.context, {'security_group_rule': rule}) | ||||||
| @@ -1973,6 +1988,11 @@ class TestQuarkCreateSecurityGroupRule(TestQuarkPlugin): | |||||||
|         with self.assertRaises(sg_ext.SecurityGroupNotFound): |         with self.assertRaises(sg_ext.SecurityGroupNotFound): | ||||||
|             self._test_create_security_rule(group=None) |             self._test_create_security_rule(group=None) | ||||||
|  |  | ||||||
|  |     def test_create_security_rule_group_at_max(self): | ||||||
|  |         with self.assertRaises(exceptions.OverQuota): | ||||||
|  |             self._test_create_security_rule( | ||||||
|  |                 group={'id': 1, 'rules': [models.SecurityGroupRule()]}) | ||||||
|  |  | ||||||
|  |  | ||||||
| class TestQuarkDeleteSecurityGroupRule(TestQuarkPlugin): | class TestQuarkDeleteSecurityGroupRule(TestQuarkPlugin): | ||||||
|     @contextlib.contextmanager |     @contextlib.contextmanager | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Kevin George
					Kevin George