Implement specific tracked resource count method per quota driver
This patch implements a new method specific for each quota driver class. This method, "get_resource_count", returns the current number of resources created in a project of a tracked resource. A tracked resource is an instance of ``neutron.quota.resource.TrackedResource``. This method does not count the current reservations, just the actual resources created. This new method, "get_resource_count", will be added to the abstract class ``neutron_lib.db.quota_api.QuotaDriverAPI``. This patch also fixes ``TestDbQuotaDriverNoLock``, that was using a plugin inheriting from ``DbQuotaDriver`` instead of ``DbQuotaNoLockDriver``. Closes-Bug: #1982962 Change-Id: I2707506468cb60d93a4459ea364f1e79faa83838
This commit is contained in:
parent
1b9e9a6c2c
commit
bd60f0833b
@ -76,9 +76,8 @@ class DbQuotaDriver(nlib_quota_api.QuotaDriverAPI):
|
||||
|
||||
return project_quota
|
||||
|
||||
@staticmethod
|
||||
@db_api.retry_if_session_inactive()
|
||||
def get_detailed_project_quotas(context, resources, project_id):
|
||||
def get_detailed_project_quotas(self, context, resources, project_id):
|
||||
"""Given a list of resources and a specific project, retrieve
|
||||
the detailed quotas (limit, used, reserved).
|
||||
:param context: The request context, for access checks.
|
||||
@ -92,8 +91,7 @@ class DbQuotaDriver(nlib_quota_api.QuotaDriverAPI):
|
||||
project_quota_ext = {}
|
||||
for key, resource in resources.items():
|
||||
if isinstance(resource, res.TrackedResource):
|
||||
used = resource.count_used(context, project_id,
|
||||
resync_usage=False)
|
||||
used = self.get_resource_count(context, project_id, resource)
|
||||
else:
|
||||
# NOTE(ihrachys) .count won't use the plugin we pass, but we
|
||||
# pass it regardless to keep the quota driver API intact
|
||||
@ -319,6 +317,11 @@ class DbQuotaDriver(nlib_quota_api.QuotaDriverAPI):
|
||||
return tracked_resource.count(context, None, project_id,
|
||||
resync_usage=False)
|
||||
|
||||
@staticmethod
|
||||
def get_resource_count(context, project_id, tracked_resource):
|
||||
return tracked_resource.count_used(context, project_id,
|
||||
resync_usage=False)
|
||||
|
||||
def quota_limit_check(self, context, project_id, resources, deltas):
|
||||
# Ensure no value is less than zero
|
||||
unders = [key for key, val in deltas.items() if val < 0]
|
||||
|
@ -92,6 +92,10 @@ class DbQuotaNoLockDriver(quota_driver.DbQuotaDriver):
|
||||
return tracked_resource.count(context, None, project_id,
|
||||
count_db_registers=True)
|
||||
|
||||
@staticmethod
|
||||
def get_resource_count(context, project_id, tracked_resource):
|
||||
return tracked_resource.count_db_registers(context, project_id)
|
||||
|
||||
@staticmethod
|
||||
def get_workers():
|
||||
interval = quota_api.RESERVATION_EXPIRATION_TIMEOUT
|
||||
|
@ -62,6 +62,10 @@ class DbQuotaDriverNull(nlib_quota_api.QuotaDriverAPI):
|
||||
def get_resource_usage(context, project_id, resources, resource_name):
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
def get_resource_count(context, project_id, tracked_resource):
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
def quota_limit_check(context, project_id, resources, deltas):
|
||||
pass
|
||||
|
@ -60,9 +60,7 @@ class QuotaSetsController(wsgi.Controller):
|
||||
def __init__(self, plugin):
|
||||
self._resource_name = RESOURCE_NAME
|
||||
self._plugin = plugin
|
||||
self._driver = importutils.import_class(
|
||||
cfg.CONF.QUOTAS.quota_driver
|
||||
)
|
||||
self._driver = importutils.import_class(cfg.CONF.QUOTAS.quota_driver)()
|
||||
self._update_extended_attributes = True
|
||||
|
||||
def _update_attributes(self):
|
||||
|
@ -334,13 +334,13 @@ class TrackedResource(BaseResource):
|
||||
CountableResource instances.
|
||||
"""
|
||||
if count_db_registers:
|
||||
count = self._count_db_registers(context, project_id)
|
||||
count = self.count_db_registers(context, project_id)
|
||||
else:
|
||||
count = self.count_used(context, project_id, resync_usage)
|
||||
|
||||
return count + self.count_reserved(context, project_id)
|
||||
|
||||
def _count_db_registers(self, context, project_id):
|
||||
def count_db_registers(self, context, project_id):
|
||||
"""Return the existing resources (self._model_class) in a project.
|
||||
|
||||
The query executed must be as fast as possible. To avoid retrieving all
|
||||
|
@ -15,18 +15,33 @@
|
||||
|
||||
import itertools
|
||||
|
||||
import netaddr
|
||||
from neutron_lib import constants
|
||||
from neutron_lib import context
|
||||
from neutron_lib.db import api as db_api
|
||||
|
||||
from neutron.db import db_base_plugin_v2 as base_plugin
|
||||
from neutron.db import models_v2
|
||||
from neutron.db.quota import api as quota_api
|
||||
from neutron.db.quota import driver_nolock
|
||||
from neutron.objects import network as network_obj
|
||||
from neutron.objects import ports as port_obj
|
||||
from neutron.objects import quota as quota_obj
|
||||
from neutron.objects import subnet as subnet_obj
|
||||
from neutron.quota import resource as quota_resource
|
||||
from neutron.tests.unit.db.quota import test_driver
|
||||
|
||||
|
||||
class FakePlugin(base_plugin.NeutronDbPluginV2,
|
||||
driver_nolock.DbQuotaNoLockDriver):
|
||||
"""A fake plugin class containing all DB methods."""
|
||||
|
||||
|
||||
class TestDbQuotaDriverNoLock(test_driver.TestDbQuotaDriver):
|
||||
|
||||
def setUp(self):
|
||||
super(TestDbQuotaDriverNoLock, self).setUp()
|
||||
self.plugin = FakePlugin()
|
||||
self.quota_driver = driver_nolock.DbQuotaNoLockDriver()
|
||||
|
||||
@staticmethod
|
||||
@ -60,3 +75,66 @@ class TestDbQuotaDriverNoLock(test_driver.TestDbQuotaDriver):
|
||||
self.quota_driver._remove_expired_reservations()
|
||||
res = quota_obj.Reservation.get_objects(self.context)
|
||||
self.assertEqual([], res)
|
||||
|
||||
def test_get_detailed_project_quotas_resource(self):
|
||||
user_ctx = context.Context(user_id=self.project_1,
|
||||
tenant_id=self.project_1)
|
||||
tracked_resource = quota_resource.TrackedResource(
|
||||
'network', models_v2.Network, 'quota_network')
|
||||
res = {'network': tracked_resource}
|
||||
self.plugin.update_quota_limit(user_ctx, self.project_1, 'network', 20)
|
||||
self.quota_driver.make_reservation(user_ctx, self.project_1, res,
|
||||
{'network': 5}, self.plugin)
|
||||
with db_api.CONTEXT_WRITER.using(user_ctx):
|
||||
network_obj.Network(user_ctx, project_id=self.project_1).create()
|
||||
|
||||
detailed_quota = self.plugin.get_detailed_project_quotas(
|
||||
user_ctx, res, self.project_1)
|
||||
reference = {'network': {'limit': 20, 'used': 1, 'reserved': 5}}
|
||||
self.assertEqual(reference, detailed_quota)
|
||||
|
||||
@staticmethod
|
||||
def _create_tracked_resources():
|
||||
return {
|
||||
'network': quota_resource.TrackedResource(
|
||||
'network', models_v2.Network, 'quota_network'),
|
||||
'subnet': quota_resource.TrackedResource(
|
||||
'subnet', models_v2.Subnet, 'quota_subnet'),
|
||||
'port': quota_resource.TrackedResource(
|
||||
'port', models_v2.Port, 'quota_port'),
|
||||
}
|
||||
|
||||
def test_get_detailed_project_quotas_multiple_resource(self):
|
||||
resources = self._create_tracked_resources()
|
||||
for project_id in self.projects:
|
||||
user_ctx = context.Context(user_id=project_id,
|
||||
tenant_id=project_id)
|
||||
self.plugin.update_quota_limit(
|
||||
user_ctx, project_id, 'network', 101)
|
||||
self.plugin.update_quota_limit(user_ctx, project_id, 'subnet', 102)
|
||||
self.plugin.update_quota_limit(user_ctx, project_id, 'port', 103)
|
||||
|
||||
with db_api.CONTEXT_WRITER.using(user_ctx):
|
||||
net = network_obj.Network(
|
||||
user_ctx, project_id=project_id)
|
||||
net.create()
|
||||
subnet_obj.Subnet(
|
||||
user_ctx, project_id=project_id, network_id=net.id,
|
||||
ip_version=constants.IP_VERSION_4,
|
||||
cidr=netaddr.IPNetwork('1.2.3.0/24')).create()
|
||||
port_obj.Port(
|
||||
user_ctx, project_id=project_id,
|
||||
network_id=net.id,
|
||||
mac_address=netaddr.EUI('ca:fe:ca:fe:ca:fe'),
|
||||
admin_state_up=False, status='DOWN', device_id='',
|
||||
device_owner='').create()
|
||||
|
||||
reference = {'network': {'limit': 101, 'used': 1, 'reserved': 0},
|
||||
'subnet': {'limit': 102, 'used': 1, 'reserved': 0},
|
||||
'port': {'limit': 103, 'used': 1, 'reserved': 0}}
|
||||
for project_id in self.projects:
|
||||
user_ctx = context.Context(user_id=project_id,
|
||||
tenant_id=project_id)
|
||||
returned = self.plugin.get_detailed_project_quotas(
|
||||
user_ctx, resources, project_id)
|
||||
self.assertEqual(reference, returned)
|
||||
|
Loading…
Reference in New Issue
Block a user