Replace "tenant_id" with "project_id" in Quota engine

This is part of the remaining technical debt of the specs
https://specs.openstack.org/openstack/neutron-specs/specs/newton/moving-to-keystone-v3.html

Blueprint: https://blueprints.launchpad.net/neutron/+spec/keystone-v3

Change-Id: I1faf520d3cdafe2de873525c8ebe1fa2114bdcd7
This commit is contained in:
Rodolfo Alonso Hernandez 2021-08-24 13:10:35 +00:00
parent 8791947a6b
commit 7dcddeb0bd
18 changed files with 579 additions and 539 deletions

View File

@ -245,7 +245,7 @@ The process of making a reservation is fairly straightforward:
on every requested resource, and then retrieving the amount of reserved on every requested resource, and then retrieving the amount of reserved
resources. resources.
* Fetch current quota limits for requested resources, by invoking the * Fetch current quota limits for requested resources, by invoking the
_get_tenant_quotas method. _get_project_quotas method.
* Fetch expired reservations for selected resources. This amount will be * Fetch expired reservations for selected resources. This amount will be
subtracted from resource usage. As in most cases there won't be any subtracted from resource usage. As in most cases there won't be any
expired reservation, this approach actually requires less DB operations than expired reservation, this approach actually requires less DB operations than

View File

@ -401,8 +401,10 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
def create_network_db(self, context, network): def create_network_db(self, context, network):
# single request processing # single request processing
n = network['network'] n = network['network']
# TODO(ralonsoh): "tenant_id" reference should be removed.
project_id = n.get('project_id') or n['tenant_id']
with db_api.CONTEXT_WRITER.using(context): with db_api.CONTEXT_WRITER.using(context):
args = {'tenant_id': n['tenant_id'], args = {'tenant_id': project_id,
'id': n.get('id') or uuidutils.generate_uuid(), 'id': n.get('id') or uuidutils.generate_uuid(),
'name': n['name'], 'name': n['name'],
'mtu': n.get('mtu', constants.DEFAULT_NETWORK_MTU), 'mtu': n.get('mtu', constants.DEFAULT_NETWORK_MTU),
@ -1426,12 +1428,14 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
p = port['port'] p = port['port']
port_id = p.get('id') or uuidutils.generate_uuid() port_id = p.get('id') or uuidutils.generate_uuid()
network_id = p['network_id'] network_id = p['network_id']
# TODO(ralonsoh): "tenant_id" reference should be removed.
project_id = p.get('project_id') or p['tenant_id']
if p.get('device_owner'): if p.get('device_owner'):
self._enforce_device_owner_not_router_intf_or_device_id( self._enforce_device_owner_not_router_intf_or_device_id(
context, p.get('device_owner'), p.get('device_id'), context, p.get('device_owner'), p.get('device_id'),
p['tenant_id']) project_id)
port_data = dict(tenant_id=p['tenant_id'], port_data = dict(tenant_id=project_id,
name=p['name'], name=p['name'],
id=port_id, id=port_id,
network_id=network_id, network_id=network_id,

View File

@ -31,28 +31,28 @@ def utcnow():
class QuotaUsageInfo(collections.namedtuple( class QuotaUsageInfo(collections.namedtuple(
'QuotaUsageInfo', ['resource', 'tenant_id', 'used', 'dirty'])): 'QuotaUsageInfo', ['resource', 'project_id', 'used', 'dirty'])):
"""Information about resource quota usage.""" """Information about resource quota usage."""
class ReservationInfo(collections.namedtuple( class ReservationInfo(collections.namedtuple(
'ReservationInfo', ['reservation_id', 'tenant_id', 'ReservationInfo', ['reservation_id', 'project_id',
'expiration', 'deltas'])): 'expiration', 'deltas'])):
"""Information about a resource reservation.""" """Information about a resource reservation."""
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def get_quota_usage_by_resource_and_tenant(context, resource, tenant_id): def get_quota_usage_by_resource_and_project(context, resource, project_id):
"""Return usage info for a given resource and tenant. """Return usage info for a given resource and project.
:param context: Request context :param context: Request context
:param resource: Name of the resource :param resource: Name of the resource
:param tenant_id: Tenant identifier :param project_id: Project identifier
:returns: a QuotaUsageInfo instance :returns: a QuotaUsageInfo instance
""" """
result = quota_obj.QuotaUsage.get_object_dirty_protected( result = quota_obj.QuotaUsage.get_object_dirty_protected(
context, resource=resource, project_id=tenant_id) context, resource=resource, project_id=project_id)
if not result: if not result:
return return
return QuotaUsageInfo(result.resource, result.project_id, result.in_use, return QuotaUsageInfo(result.resource, result.project_id, result.in_use,
@ -69,22 +69,21 @@ def get_quota_usage_by_resource(context, resource):
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def get_quota_usage_by_tenant_id(context, tenant_id): def get_quota_usage_by_project_id(context, project_id):
objs = quota_obj.QuotaUsage.get_objects(context, project_id=tenant_id) objs = quota_obj.QuotaUsage.get_objects(context, project_id=project_id)
return [QuotaUsageInfo(item.resource, return [QuotaUsageInfo(item.resource,
tenant_id, project_id,
item.in_use, item.in_use,
item.dirty) for item in objs] item.dirty) for item in objs]
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def set_quota_usage(context, resource, tenant_id, def set_quota_usage(context, resource, project_id, in_use=None, delta=False):
in_use=None, delta=False):
"""Set resource quota usage. """Set resource quota usage.
:param context: instance of neutron context with db session :param context: instance of neutron context with db session
:param resource: name of the resource for which usage is being set :param resource: name of the resource for which usage is being set
:param tenant_id: identifier of the tenant for which quota usage is :param project_id: identifier of the project for which quota usage is
being set being set
:param in_use: integer specifying the new quantity of used resources, :param in_use: integer specifying the new quantity of used resources,
or a delta to apply to current used resource or a delta to apply to current used resource
@ -93,11 +92,11 @@ def set_quota_usage(context, resource, tenant_id,
""" """
with db_api.CONTEXT_WRITER.using(context): with db_api.CONTEXT_WRITER.using(context):
usage_data = quota_obj.QuotaUsage.get_object( usage_data = quota_obj.QuotaUsage.get_object(
context, resource=resource, project_id=tenant_id) context, resource=resource, project_id=project_id)
if not usage_data: if not usage_data:
# Must create entry # Must create entry
usage_data = quota_obj.QuotaUsage( usage_data = quota_obj.QuotaUsage(
context, resource=resource, project_id=tenant_id) context, resource=resource, project_id=project_id)
usage_data.create() usage_data.create()
# Perform explicit comparison with None as 0 is a valid value # Perform explicit comparison with None as 0 is a valid value
if in_use is not None: if in_use is not None:
@ -113,16 +112,16 @@ def set_quota_usage(context, resource, tenant_id,
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
@db_api.CONTEXT_WRITER @db_api.CONTEXT_WRITER
def set_quota_usage_dirty(context, resource, tenant_id, dirty=True): def set_quota_usage_dirty(context, resource, project_id, dirty=True):
"""Set quota usage dirty bit for a given resource and tenant. """Set quota usage dirty bit for a given resource and project.
:param resource: a resource for which quota usage if tracked :param resource: a resource for which quota usage if tracked
:param tenant_id: tenant identifier :param project_id: project identifier
:param dirty: the desired value for the dirty bit (defaults to True) :param dirty: the desired value for the dirty bit (defaults to True)
:returns: 1 if the quota usage data were updated, 0 otherwise. :returns: 1 if the quota usage data were updated, 0 otherwise.
""" """
obj = quota_obj.QuotaUsage.get_object( obj = quota_obj.QuotaUsage.get_object(
context, resource=resource, project_id=tenant_id) context, resource=resource, project_id=project_id)
if obj: if obj:
obj.dirty = dirty obj.dirty = dirty
obj.update() obj.update()
@ -132,16 +131,17 @@ def set_quota_usage_dirty(context, resource, tenant_id, dirty=True):
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
@db_api.CONTEXT_WRITER @db_api.CONTEXT_WRITER
def set_resources_quota_usage_dirty(context, resources, tenant_id, dirty=True): def set_resources_quota_usage_dirty(context, resources, project_id,
"""Set quota usage dirty bit for a given tenant and multiple resources. dirty=True):
"""Set quota usage dirty bit for a given project and multiple resources.
:param resources: list of resource for which the dirty bit is going :param resources: list of resource for which the dirty bit is going
to be set to be set
:param tenant_id: tenant identifier :param project_id: project identifier
:param dirty: the desired value for the dirty bit (defaults to True) :param dirty: the desired value for the dirty bit (defaults to True)
:returns: the number of records for which the bit was actually set. :returns: the number of records for which the bit was actually set.
""" """
filters = {'project_id': tenant_id} filters = {'project_id': project_id}
if resources: if resources:
filters['resource'] = resources filters['resource'] = resources
objs = quota_obj.QuotaUsage.get_objects(context, **filters) objs = quota_obj.QuotaUsage.get_objects(context, **filters)
@ -154,10 +154,10 @@ def set_resources_quota_usage_dirty(context, resources, tenant_id, dirty=True):
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
@db_api.CONTEXT_WRITER @db_api.CONTEXT_WRITER
def set_all_quota_usage_dirty(context, resource, dirty=True): def set_all_quota_usage_dirty(context, resource, dirty=True):
"""Set the dirty bit on quota usage for all tenants. """Set the dirty bit on quota usage for all projects.
:param resource: the resource for which the dirty bit should be set :param resource: the resource for which the dirty bit should be set
:returns: the number of tenants for which the dirty bit was :returns: the number of projects for which the dirty bit was
actually updated actually updated
""" """
# TODO(manjeets) consider squashing this method with # TODO(manjeets) consider squashing this method with
@ -170,7 +170,7 @@ def set_all_quota_usage_dirty(context, resource, dirty=True):
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def create_reservation(context, tenant_id, deltas, expiration=None): def create_reservation(context, project_id, deltas, expiration=None):
# This method is usually called from within another transaction. # This method is usually called from within another transaction.
# Consider using begin_nested # Consider using begin_nested
expiration = expiration or (utcnow() + datetime.timedelta(0, 120)) expiration = expiration or (utcnow() + datetime.timedelta(0, 120))
@ -179,7 +179,7 @@ def create_reservation(context, tenant_id, deltas, expiration=None):
delta_objs.append(quota_obj.ResourceDelta( delta_objs.append(quota_obj.ResourceDelta(
context, resource=resource, amount=delta)) context, resource=resource, amount=delta))
reserv_obj = quota_obj.Reservation( reserv_obj = quota_obj.Reservation(
context, project_id=tenant_id, expiration=expiration, context, project_id=project_id, expiration=expiration,
resource_deltas=delta_objs) resource_deltas=delta_objs)
reserv_obj.create() reserv_obj.create()
return ReservationInfo(reserv_obj['id'], return ReservationInfo(reserv_obj['id'],
@ -223,12 +223,12 @@ def remove_reservation(context, reservation_id, set_dirty=False):
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
@db_api.CONTEXT_READER @db_api.CONTEXT_READER
def get_reservations_for_resources(context, tenant_id, resources, def get_reservations_for_resources(context, project_id, resources,
expired=False): expired=False):
"""Retrieve total amount of reservations for specified resources. """Retrieve total amount of reservations for specified resources.
:param context: Neutron context with db session :param context: Neutron context with db session
:param tenant_id: Tenant identifier :param project_id: Project identifier
:param resources: Resources for which reserved amounts should be fetched :param resources: Resources for which reserved amounts should be fetched
:param expired: False to fetch active reservations, True to fetch expired :param expired: False to fetch active reservations, True to fetch expired
reservations (defaults to False) reservations (defaults to False)
@ -238,17 +238,17 @@ def get_reservations_for_resources(context, tenant_id, resources,
# can be mocked easily where as datetime is built in type # can be mocked easily where as datetime is built in type
# mock.path does not allow mocking built in types. # mock.path does not allow mocking built in types.
return quota_obj.Reservation.get_total_reservations_map( return quota_obj.Reservation.get_total_reservations_map(
context, utcnow(), tenant_id, resources, expired) context, utcnow(), project_id, resources, expired)
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
@db_api.CONTEXT_WRITER @db_api.CONTEXT_WRITER
def remove_expired_reservations(context, tenant_id=None, timeout=None): def remove_expired_reservations(context, project_id=None, timeout=None):
expiring_time = utcnow() expiring_time = utcnow()
if timeout: if timeout:
expiring_time -= datetime.timedelta(seconds=timeout) expiring_time -= datetime.timedelta(seconds=timeout)
return quota_obj.Reservation.delete_expired(context, expiring_time, return quota_obj.Reservation.delete_expired(context, expiring_time,
tenant_id) project_id)
class QuotaDriverAPI(object, metaclass=abc.ABCMeta): class QuotaDriverAPI(object, metaclass=abc.ABCMeta):
@ -257,7 +257,7 @@ class QuotaDriverAPI(object, metaclass=abc.ABCMeta):
@abc.abstractmethod @abc.abstractmethod
def get_default_quotas(context, resources, project_id): def get_default_quotas(context, resources, project_id):
"""Given a list of resources, retrieve the default quotas set for """Given a list of resources, retrieve the default quotas set for
a tenant. a project.
:param context: The request context, for access checks. :param context: The request context, for access checks.
:param resources: A dictionary of the registered resource keys. :param resources: A dictionary of the registered resource keys.
@ -267,7 +267,7 @@ class QuotaDriverAPI(object, metaclass=abc.ABCMeta):
@staticmethod @staticmethod
@abc.abstractmethod @abc.abstractmethod
def get_tenant_quotas(context, resources, project_id): def get_project_quotas(context, resources, project_id):
"""Retrieve the quotas for the given list of resources and project """Retrieve the quotas for the given list of resources and project
:param context: The request context, for access checks. :param context: The request context, for access checks.
@ -278,7 +278,7 @@ class QuotaDriverAPI(object, metaclass=abc.ABCMeta):
@staticmethod @staticmethod
@abc.abstractmethod @abc.abstractmethod
def get_detailed_tenant_quotas(context, resources, project_id): def get_detailed_project_quotas(context, resources, project_id):
"""Retrieve detailed quotas for the given list of resources and project """Retrieve detailed quotas for the given list of resources and project
:param context: The request context, for access checks. :param context: The request context, for access checks.
@ -291,11 +291,11 @@ class QuotaDriverAPI(object, metaclass=abc.ABCMeta):
@staticmethod @staticmethod
@abc.abstractmethod @abc.abstractmethod
def delete_tenant_quota(context, project_id): def delete_project_quota(context, project_id):
"""Delete the quota entries for a given project_id. """Delete the quota entries for a given project_id.
After deletion, this tenant will use default quota values in conf. After deletion, this project will use default quota values in conf.
Raise a "not found" error if the quota for the given tenant was Raise a "not found" error if the quota for the given project was
never defined. never defined.
:param context: The request context, for access checks. :param context: The request context, for access checks.
@ -382,15 +382,15 @@ class NullQuotaDriver(QuotaDriverAPI):
pass pass
@staticmethod @staticmethod
def get_tenant_quotas(context, resources, project_id): def get_project_quotas(context, resources, project_id):
pass pass
@staticmethod @staticmethod
def get_detailed_tenant_quotas(context, resources, project_id): def get_detailed_project_quotas(context, resources, project_id):
pass pass
@staticmethod @staticmethod
def delete_tenant_quota(context, project_id): def delete_project_quota(context, project_id):
pass pass
@staticmethod @staticmethod

View File

@ -35,139 +35,142 @@ class DbQuotaDriver(quota_api.QuotaDriverAPI):
""" """
@staticmethod @staticmethod
def get_default_quotas(context, resources, tenant_id): def get_default_quotas(context, resources, project_id):
"""Given a list of resources, retrieve the default quotas set for """Given a list of resources, retrieve the default quotas set for
a tenant. a project.
:param context: The request context, for access checks. :param context: The request context, for access checks.
:param resources: A dictionary of the registered resource keys. :param resources: A dictionary of the registered resource keys.
:param tenant_id: The ID of the tenant to return default quotas for. :param project_id: The ID of the project to return default quotas for.
:return: dict from resource name to dict of name and limit :return: dict from resource name to dict of name and limit
""" """
# Currently the tenant_id parameter is unused, since all tenants # Currently the project_id parameter is unused, since all projects
# share the same default values. This may change in the future so # share the same default values. This may change in the future so
# we include tenant-id to remain backwards compatible. # we include project ID to remain backwards compatible.
return dict((key, resource.default) return dict((key, resource.default)
for key, resource in resources.items()) for key, resource in resources.items())
@staticmethod @staticmethod
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def get_tenant_quotas(context, resources, tenant_id): def get_project_quotas(context, resources, project_id):
"""Given a list of resources, retrieve the quotas for the given """Given a list of resources, retrieve the quotas for the given
tenant. If no limits are found for the specified tenant, the operation project. If no limits are found for the specified project, the
returns the default limits. operation returns the default limits.
:param context: The request context, for access checks. :param context: The request context, for access checks.
:param resources: A dictionary of the registered resource keys. :param resources: A dictionary of the registered resource keys.
:param tenant_id: The ID of the tenant to return quotas for. :param project_id: The ID of the project to return quotas for.
:return: dict from resource name to dict of name and limit :return: dict from resource name to dict of name and limit
""" """
# init with defaults # init with defaults
tenant_quota = dict((key, resource.default) project_quota = dict((key, resource.default)
for key, resource in resources.items()) for key, resource in resources.items())
# update with tenant specific limits # update with project specific limits
quota_objs = quota_obj.Quota.get_objects(context, project_id=tenant_id) quota_objs = quota_obj.Quota.get_objects(context,
project_id=project_id)
for item in quota_objs: for item in quota_objs:
tenant_quota[item['resource']] = item['limit'] project_quota[item['resource']] = item['limit']
return tenant_quota return project_quota
@staticmethod @staticmethod
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def get_detailed_tenant_quotas(context, resources, tenant_id): def get_detailed_project_quotas(context, resources, project_id):
"""Given a list of resources and a sepecific tenant, retrieve """Given a list of resources and a specific project, retrieve
the detailed quotas (limit, used, reserved). the detailed quotas (limit, used, reserved).
:param context: The request context, for access checks. :param context: The request context, for access checks.
:param resources: A dictionary of the registered resource keys. :param resources: A dictionary of the registered resource keys.
:param project_id: The ID of the project to return quotas for.
:return dict: mapping resource name in dict to its corresponding limit :return dict: mapping resource name in dict to its corresponding limit
used and reserved. Reserved currently returns default value of 0 used and reserved. Reserved currently returns default value of 0
""" """
res_reserve_info = quota_api.get_reservations_for_resources( res_reserve_info = quota_api.get_reservations_for_resources(
context, tenant_id, resources.keys()) context, project_id, resources.keys())
tenant_quota_ext = {} project_quota_ext = {}
for key, resource in resources.items(): for key, resource in resources.items():
if isinstance(resource, res.TrackedResource): if isinstance(resource, res.TrackedResource):
used = resource.count_used(context, tenant_id, used = resource.count_used(context, project_id,
resync_usage=False) resync_usage=False)
else: else:
# NOTE(ihrachys) .count won't use the plugin we pass, but we # NOTE(ihrachys) .count won't use the plugin we pass, but we
# pass it regardless to keep the quota driver API intact # pass it regardless to keep the quota driver API intact
plugins = directory.get_plugins() plugins = directory.get_plugins()
plugin = plugins.get(key, plugins[constants.CORE]) plugin = plugins.get(key, plugins[constants.CORE])
used = resource.count(context, plugin, tenant_id) used = resource.count(context, plugin, project_id)
tenant_quota_ext[key] = { project_quota_ext[key] = {
'limit': resource.default, 'limit': resource.default,
'used': used, 'used': used,
'reserved': res_reserve_info.get(key, 0), 'reserved': res_reserve_info.get(key, 0),
} }
# update with specific tenant limits # update with specific project limits
quota_objs = quota_obj.Quota.get_objects(context, project_id=tenant_id) quota_objs = quota_obj.Quota.get_objects(context,
project_id=project_id)
for item in quota_objs: for item in quota_objs:
tenant_quota_ext[item['resource']]['limit'] = item['limit'] project_quota_ext[item['resource']]['limit'] = item['limit']
return tenant_quota_ext return project_quota_ext
@staticmethod @staticmethod
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def delete_tenant_quota(context, tenant_id): def delete_project_quota(context, project_id):
"""Delete the quota entries for a given tenant_id. """Delete the quota entries for a given project_id.
After deletion, this tenant will use default quota values in conf. After deletion, this project will use default quota values in conf.
Raise a "not found" error if the quota for the given tenant was Raise a "not found" error if the quota for the given project was
never defined. never defined.
""" """
if quota_obj.Quota.delete_objects(context, project_id=tenant_id) < 1: if quota_obj.Quota.delete_objects(context, project_id=project_id) < 1:
# No record deleted means the quota was not found # No record deleted means the quota was not found
raise exceptions.TenantQuotaNotFound(tenant_id=tenant_id) raise exceptions.TenantQuotaNotFound(tenant_id=project_id)
@staticmethod @staticmethod
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def get_all_quotas(context, resources): def get_all_quotas(context, resources):
"""Given a list of resources, retrieve the quotas for the all tenants. """Given a list of resources, retrieve the quotas for the all projects.
:param context: The request context, for access checks. :param context: The request context, for access checks.
:param resources: A dictionary of the registered resource keys. :param resources: A dictionary of the registered resource keys.
:return: quotas list of dict of tenant_id:, resourcekey1: :return: quotas list of dict of project_id:, resourcekey1:
resourcekey2: ... resourcekey2: ...
""" """
tenant_default = dict((key, resource.default) project_default = dict((key, resource.default)
for key, resource in resources.items()) for key, resource in resources.items())
all_tenant_quotas = {} all_project_quotas = {}
for quota in quota_obj.Quota.get_objects(context): for quota in quota_obj.Quota.get_objects(context):
tenant_id = quota['project_id'] project_id = quota['project_id']
# avoid setdefault() because only want to copy when actually # avoid setdefault() because only want to copy when actually
# required # required
tenant_quota = all_tenant_quotas.get(tenant_id) project_quota = all_project_quotas.get(project_id)
if tenant_quota is None: if project_quota is None:
tenant_quota = tenant_default.copy() project_quota = project_default.copy()
tenant_quota['tenant_id'] = tenant_id project_quota['project_id'] = project_id
attributes.populate_project_info(tenant_quota) attributes.populate_project_info(project_quota)
all_tenant_quotas[tenant_id] = tenant_quota all_project_quotas[project_id] = project_quota
tenant_quota[quota['resource']] = quota['limit'] project_quota[quota['resource']] = quota['limit']
# Convert values to a list to as caller expect an indexable iterable, # Convert values to a list to as caller expect an indexable iterable,
# where python3's dict_values does not support indexing # where python3's dict_values does not support indexing
return list(all_tenant_quotas.values()) return list(all_project_quotas.values())
@staticmethod @staticmethod
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def update_quota_limit(context, tenant_id, resource, limit): def update_quota_limit(context, project_id, resource, limit):
tenant_quotas = quota_obj.Quota.get_objects( project_quotas = quota_obj.Quota.get_objects(
context, project_id=tenant_id, resource=resource) context, project_id=project_id, resource=resource)
if tenant_quotas: if project_quotas:
tenant_quotas[0].limit = limit project_quotas[0].limit = limit
tenant_quotas[0].update() project_quotas[0].update()
else: else:
quota_obj.Quota(context, project_id=tenant_id, resource=resource, quota_obj.Quota(context, project_id=project_id, resource=resource,
limit=limit).create() limit=limit).create()
def _get_quotas(self, context, tenant_id, resources): def _get_quotas(self, context, project_id, resources):
"""Retrieves the quotas for specific resources. """Retrieves the quotas for specific resources.
A helper method which retrieves the quotas for the specific A helper method which retrieves the quotas for the specific
@ -175,24 +178,23 @@ class DbQuotaDriver(quota_api.QuotaDriverAPI):
context. context.
:param context: The request context, for access checks. :param context: The request context, for access checks.
:param tenant_id: the tenant_id to check quota. :param project_id: the project ID to check quota.
:param resources: A dictionary of the registered resources. :param resources: A dictionary of the registered resources.
""" """
# Grab and return the quotas (without usages) # Grab and return the quotas (without usages)
quotas = DbQuotaDriver.get_tenant_quotas( quotas = DbQuotaDriver.get_project_quotas(
context, resources, tenant_id) context, resources, project_id)
return dict((k, v) for k, v in quotas.items()) return dict((k, v) for k, v in quotas.items())
def _handle_expired_reservations(self, context, tenant_id): def _handle_expired_reservations(self, context, project_id):
LOG.debug("Deleting expired reservations for tenant:%s", tenant_id) LOG.debug("Deleting expired reservations for project: %s", project_id)
# Delete expired reservations (we don't want them to accrue # Delete expired reservations (we don't want them to accrue
# in the database) # in the database)
quota_api.remove_expired_reservations( quota_api.remove_expired_reservations(context, project_id=project_id)
context, tenant_id=tenant_id)
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def make_reservation(self, context, tenant_id, resources, deltas, plugin): def make_reservation(self, context, project_id, resources, deltas, plugin):
# Lock current reservation table # Lock current reservation table
# NOTE(salv-orlando): This routine uses DB write locks. # NOTE(salv-orlando): This routine uses DB write locks.
# These locks are acquired by the count() method invoked on resources. # These locks are acquired by the count() method invoked on resources.
@ -207,11 +209,11 @@ class DbQuotaDriver(quota_api.QuotaDriverAPI):
# to a single node will be available. # to a single node will be available.
requested_resources = deltas.keys() requested_resources = deltas.keys()
with db_api.CONTEXT_WRITER.using(context): with db_api.CONTEXT_WRITER.using(context):
# get_tenant_quotes needs in input a dictionary mapping resource # "get_project_quotas" needs in input a dictionary mapping resource
# name to BaseResosurce instances so that the default quota can be # name to BaseResosurce instances so that the default quota can be
# retrieved # retrieved
current_limits = self.get_tenant_quotas( current_limits = self.get_project_quotas(
context, resources, tenant_id) context, resources, project_id)
unlimited_resources = set([resource for (resource, limit) in unlimited_resources = set([resource for (resource, limit) in
current_limits.items() if limit < 0]) current_limits.items() if limit < 0])
# Do not even bother counting resources and calculating headroom # Do not even bother counting resources and calculating headroom
@ -230,13 +232,13 @@ class DbQuotaDriver(quota_api.QuotaDriverAPI):
# instances # instances
current_usages = dict( current_usages = dict(
(resource, resources[resource].count( (resource, resources[resource].count(
context, plugin, tenant_id, resync_usage=False)) for context, plugin, project_id, resync_usage=False)) for
resource in requested_resources) resource in requested_resources)
# Adjust for expired reservations. Apparently it is cheaper than # Adjust for expired reservations. Apparently it is cheaper than
# querying every time for active reservations and counting overall # querying every time for active reservations and counting overall
# quantity of resources reserved # quantity of resources reserved
expired_deltas = quota_api.get_reservations_for_resources( expired_deltas = quota_api.get_reservations_for_resources(
context, tenant_id, requested_resources, expired=True) context, project_id, requested_resources, expired=True)
# Verify that the request can be accepted with current limits # Verify that the request can be accepted with current limits
resources_over_limit = [] resources_over_limit = []
for resource in requested_resources: for resource in requested_resources:
@ -254,14 +256,14 @@ class DbQuotaDriver(quota_api.QuotaDriverAPI):
if res_headroom < deltas[resource]: if res_headroom < deltas[resource]:
resources_over_limit.append(resource) resources_over_limit.append(resource)
if expired_reservations: if expired_reservations:
self._handle_expired_reservations(context, tenant_id) self._handle_expired_reservations(context, project_id)
if resources_over_limit: if resources_over_limit:
raise exceptions.OverQuota(overs=sorted(resources_over_limit)) raise exceptions.OverQuota(overs=sorted(resources_over_limit))
# Success, store the reservation # Success, store the reservation
# TODO(salv-orlando): Make expiration time configurable # TODO(salv-orlando): Make expiration time configurable
return quota_api.create_reservation( return quota_api.create_reservation(
context, tenant_id, deltas) context, project_id, deltas)
def commit_reservation(self, context, reservation_id): def commit_reservation(self, context, reservation_id):
# Do not mark resource usage as dirty. If a reservation is committed, # Do not mark resource usage as dirty. If a reservation is committed,
@ -276,7 +278,7 @@ class DbQuotaDriver(quota_api.QuotaDriverAPI):
quota_api.remove_reservation(context, reservation_id, quota_api.remove_reservation(context, reservation_id,
set_dirty=True) set_dirty=True)
def limit_check(self, context, tenant_id, resources, values): def limit_check(self, context, project_id, resources, values):
"""Check simple quota limits. """Check simple quota limits.
For limits--those quotas for which there is no usage For limits--those quotas for which there is no usage
@ -289,7 +291,7 @@ class DbQuotaDriver(quota_api.QuotaDriverAPI):
nothing. nothing.
:param context: The request context, for access checks. :param context: The request context, for access checks.
:param tenant_id: The tenant_id to check the quota. :param project_id: The project ID to check the quota.
:param resources: A dictionary of the registered resources. :param resources: A dictionary of the registered resources.
:param values: A dictionary of the values to check against the :param values: A dictionary of the values to check against the
quota. quota.
@ -301,7 +303,7 @@ class DbQuotaDriver(quota_api.QuotaDriverAPI):
raise exceptions.InvalidQuotaValue(unders=sorted(unders)) raise exceptions.InvalidQuotaValue(unders=sorted(unders))
# Get the applicable quotas # Get the applicable quotas
quotas = self._get_quotas(context, tenant_id, resources) quotas = self._get_quotas(context, project_id, resources)
# Check the quotas and construct a list of the resources that # Check the quotas and construct a list of the resources that
# would be put over limit by the desired values # would be put over limit by the desired values

View File

@ -45,7 +45,7 @@ class DbQuotaNoLockDriver(quota_driver.DbQuotaDriver):
resources_over_limit = [] resources_over_limit = []
with db_api.CONTEXT_WRITER.using(context): with db_api.CONTEXT_WRITER.using(context):
# Filter out unlimited resources. # Filter out unlimited resources.
limits = self.get_tenant_quotas(context, resources, project_id) limits = self.get_project_quotas(context, resources, project_id)
unlimited_resources = set([resource for (resource, limit) in unlimited_resources = set([resource for (resource, limit) in
limits.items() if limit < 0]) limits.items() if limit < 0])
requested_resources = (set(deltas.keys()) - unlimited_resources) requested_resources = (set(deltas.keys()) - unlimited_resources)
@ -54,7 +54,7 @@ class DbQuotaNoLockDriver(quota_driver.DbQuotaDriver):
# operation is fast and by calling it before making any # operation is fast and by calling it before making any
# reservation, we ensure the freshness of the reservations. # reservation, we ensure the freshness of the reservations.
quota_api.remove_expired_reservations( quota_api.remove_expired_reservations(
context, tenant_id=project_id, context, project_id=project_id,
timeout=quota_api.RESERVATION_EXPIRATION_TIMEOUT) timeout=quota_api.RESERVATION_EXPIRATION_TIMEOUT)
# Count the number of (1) used and (2) reserved resources for this # Count the number of (1) used and (2) reserved resources for this

View File

@ -924,10 +924,10 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase,
@registry.receives(resources.NETWORK, [events.BEFORE_CREATE]) @registry.receives(resources.NETWORK, [events.BEFORE_CREATE])
def _ensure_default_security_group_handler(self, resource, event, trigger, def _ensure_default_security_group_handler(self, resource, event, trigger,
payload): payload):
if event == events.BEFORE_UPDATE: _state = (payload.states[0] if event == events.BEFORE_UPDATE else
project_id = payload.states[0]['tenant_id'] payload.latest_state)
else: # TODO(ralonsoh): "tenant_id" reference should be removed.
project_id = payload.latest_state['tenant_id'] project_id = _state.get('project_id') or _state['tenant_id']
if project_id: if project_id:
self._ensure_default_security_group(payload.context, project_id) self._ensure_default_security_group(payload.context, project_id)
@ -993,7 +993,8 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase,
return return
port_sg = port.get(ext_sg.SECURITYGROUPS) port_sg = port.get(ext_sg.SECURITYGROUPS)
if port_sg is None or not validators.is_attr_set(port_sg): if port_sg is None or not validators.is_attr_set(port_sg):
port_project = port.get('tenant_id') # TODO(ralonsoh): "tenant_id" reference should be removed.
port_project = port.get('project_id') or port.get('tenant_id')
default_sg = self._ensure_default_security_group(context, default_sg = self._ensure_default_security_group(context,
port_project) port_project)
if default_sg: if default_sg:

View File

@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import warnings
from neutron_lib.api import converters from neutron_lib.api import converters
from neutron_lib.api import extensions as api_extensions from neutron_lib.api import extensions as api_extensions
from neutron_lib.api import faults from neutron_lib.api import faults
@ -74,20 +76,20 @@ class QuotaSetsController(wsgi.Controller):
'is_visible': True} 'is_visible': True}
self._update_extended_attributes = False self._update_extended_attributes = False
def _get_quotas(self, request, tenant_id): def _get_quotas(self, request, project_id):
return self._driver.get_tenant_quotas( return self._driver.get_project_quotas(
request.context, request.context,
resource_registry.get_all_resources(), resource_registry.get_all_resources(),
tenant_id) project_id)
def default(self, request, id): def default(self, request, id):
context = request.context context = request.context
if id != context.tenant_id: if id != context.project_id:
validate_policy(context, "get_quota") validate_policy(context, "get_quota")
return {self._resource_name: self._driver.get_default_quotas( return {self._resource_name: self._driver.get_default_quotas(
context=context, context=context,
resources=resource_registry.get_all_resources(), resources=resource_registry.get_all_resources(),
tenant_id=id)} project_id=id)}
def create(self, request, body=None): def create(self, request, body=None):
msg = _('POST requests are not supported on this resource.') msg = _('POST requests are not supported on this resource.')
@ -101,20 +103,31 @@ class QuotaSetsController(wsgi.Controller):
context, resource_registry.get_all_resources())} context, resource_registry.get_all_resources())}
def tenant(self, request): def tenant(self, request):
"""Retrieve the tenant info in context.""" """Retrieve the project info in context."""
warnings.warn(
'"tenant" Quota API method is deprecated, use "project" instead')
return self._project(request, 'tenant')
def project(self, request):
"""Retrieve the project info in context."""
return self._project(request, 'project')
@staticmethod
def _project(request, key):
"""Retrieve the project info in context."""
context = request.context context = request.context
if not context.tenant_id: if not context.project_id:
raise exceptions.QuotaMissingTenant() raise exceptions.QuotaMissingTenant()
return {'tenant': {'tenant_id': context.tenant_id}} return {key: {key + '_id': context.project_id}}
def show(self, request, id): def show(self, request, id):
if id != request.context.tenant_id: if id != request.context.project_id:
validate_policy(request.context, "get_quota") validate_policy(request.context, "get_quota")
return {self._resource_name: self._get_quotas(request, id)} return {self._resource_name: self._get_quotas(request, id)}
def delete(self, request, id): def delete(self, request, id):
validate_policy(request.context, "delete_quota") validate_policy(request.context, "delete_quota")
self._driver.delete_tenant_quota(request.context, id) self._driver.delete_project_quota(request.context, id)
def update(self, request, id, body=None): def update(self, request, id, body=None):
validate_policy(request.context, "update_quota") validate_policy(request.context, "update_quota")
@ -152,7 +165,7 @@ class Quotasv2(api_extensions.ExtensionDescriptor):
def get_description(cls): def get_description(cls):
description = 'Expose functions for quotas management' description = 'Expose functions for quotas management'
if cfg.CONF.QUOTAS.quota_driver == DB_QUOTA_DRIVER: if cfg.CONF.QUOTAS.quota_driver == DB_QUOTA_DRIVER:
description += ' per tenant' description += ' per project'
return description return description
@classmethod @classmethod
@ -169,7 +182,8 @@ class Quotasv2(api_extensions.ExtensionDescriptor):
Quotasv2.get_alias(), Quotasv2.get_alias(),
controller, controller,
member_actions={DEFAULT_QUOTAS_ACTION: 'GET'}, member_actions={DEFAULT_QUOTAS_ACTION: 'GET'},
collection_actions={'tenant': 'GET'})] collection_actions={'tenant': 'GET',
'project': 'GET'})]
def get_extended_resources(self, version): def get_extended_resources(self, version):
if version == "2.0": if version == "2.0":

View File

@ -46,17 +46,17 @@ EXTENDED_ATTRIBUTES_2_0 = {
class DetailQuotaSetsController(quotasv2.QuotaSetsController): class DetailQuotaSetsController(quotasv2.QuotaSetsController):
def _get_detailed_quotas(self, request, tenant_id): def _get_detailed_quotas(self, request, project_id):
return self._driver.get_detailed_tenant_quotas( return self._driver.get_detailed_project_quotas(
request.context, request.context,
resource_registry.get_all_resources(), tenant_id) resource_registry.get_all_resources(), project_id)
def details(self, request, id): def details(self, request, id):
if id != request.context.project_id: if id != request.context.project_id:
# Check if admin # Check if admin
if not request.context.is_admin: if not request.context.is_admin:
reason = _("Only admin is authorized to access quotas for" reason = _("Only admin is authorized to access quotas for "
" another tenant") "another project")
raise n_exc.AdminRequired(reason=reason) raise n_exc.AdminRequired(reason=reason)
return {self._resource_name: return {self._resource_name:
self._get_detailed_quotas(request, id)} self._get_detailed_quotas(request, id)}
@ -95,7 +95,8 @@ class Quotasv2_detail(api_extensions.ExtensionDescriptor):
RESOURCE_COLLECTION, RESOURCE_COLLECTION,
controller, controller,
member_actions={'details': 'GET'}, member_actions={'details': 'GET'},
collection_actions={'tenant': 'GET'})] collection_actions={'tenant': 'GET',
'project': 'GET'})]
def get_extended_resources(self, version): def get_extended_resources(self, version):
return EXTENDED_ATTRIBUTES_2_0 if version == "2.0" else {} return EXTENDED_ATTRIBUTES_2_0 if version == "2.0" else {}

View File

@ -1051,7 +1051,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
def _create_network_db(self, context, network): def _create_network_db(self, context, network):
net_data = network[net_def.RESOURCE_NAME] net_data = network[net_def.RESOURCE_NAME]
tenant_id = net_data['tenant_id'] # TODO(ralonsoh): "tenant_id" reference should be removed.
tenant_id = net_data.get('project_id') or net_data['tenant_id']
with db_api.CONTEXT_WRITER.using(context): with db_api.CONTEXT_WRITER.using(context):
net_db = self.create_network_db(context, network) net_db = self.create_network_db(context, network)
net_data['id'] = net_db.id net_data['id'] = net_db.id

View File

@ -30,7 +30,7 @@ from neutron.db.quota import api as quota_api
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
def _count_resource(context, collection_name, tenant_id): def _count_resource(context, collection_name, project_id):
count_getter_name = "get_%s_count" % collection_name count_getter_name = "get_%s_count" % collection_name
getter_name = "get_%s" % collection_name getter_name = "get_%s" % collection_name
@ -45,12 +45,12 @@ def _count_resource(context, collection_name, tenant_id):
try: try:
obj_count_getter = getattr(plugins[pname], count_getter_name) obj_count_getter = getattr(plugins[pname], count_getter_name)
return obj_count_getter( return obj_count_getter(
context, filters={'tenant_id': [tenant_id]}) context, filters={'project_id': [project_id]})
except (NotImplementedError, AttributeError): except (NotImplementedError, AttributeError):
try: try:
obj_getter = getattr(plugins[pname], getter_name) obj_getter = getattr(plugins[pname], getter_name)
obj_list = obj_getter( obj_list = obj_getter(
context, filters={'tenant_id': [tenant_id]}) context, filters={'project_id': [project_id]})
return len(obj_list) if obj_list else 0 return len(obj_list) if obj_list else 0
except (NotImplementedError, AttributeError): except (NotImplementedError, AttributeError):
pass pass
@ -172,7 +172,7 @@ class TrackedResource(BaseResource):
usage data are employed when performing quota checks. usage data are employed when performing quota checks.
This class operates under the assumption that the model class This class operates under the assumption that the model class
describing the resource has a tenant identifier attribute. describing the resource has a project identifier attribute.
:param name: The name of the resource, i.e., "networks". :param name: The name of the resource, i.e., "networks".
:param model_class: The sqlalchemy model class of the resource for :param model_class: The sqlalchemy model class of the resource for
@ -191,11 +191,11 @@ class TrackedResource(BaseResource):
super(TrackedResource, self).__init__( super(TrackedResource, self).__init__(
name, flag=flag, plural_name=plural_name) name, flag=flag, plural_name=plural_name)
# Register events for addition/removal of records in the model class # Register events for addition/removal of records in the model class
# As tenant_id is immutable for all Neutron objects there is no need # As project_id is immutable for all Neutron objects there is no need
# to register a listener for update events # to register a listener for update events
self._model_class = model_class self._model_class = model_class
self._dirty_tenants = set() self._dirty_projects = set()
self._out_of_sync_tenants = set() self._out_of_sync_projects = set()
# NOTE(ralonsoh): "DbQuotaNoLockDriver" driver does not need to track # NOTE(ralonsoh): "DbQuotaNoLockDriver" driver does not need to track
# the DB events or resync the resource quota usage. # the DB events or resync the resource quota usage.
if cfg.CONF.QUOTAS.quota_driver == quota_conf.QUOTA_DB_DRIVER: if cfg.CONF.QUOTAS.quota_driver == quota_conf.QUOTA_DB_DRIVER:
@ -207,78 +207,78 @@ class TrackedResource(BaseResource):
def dirty(self): def dirty(self):
if not self._track_resource_events: if not self._track_resource_events:
return return
return self._dirty_tenants return self._dirty_projects
def mark_dirty(self, context): def mark_dirty(self, context):
if not self._dirty_tenants or not self._track_resource_events: if not self._dirty_projects or not self._track_resource_events:
return return
with db_api.CONTEXT_WRITER.using(context): with db_api.CONTEXT_WRITER.using(context):
# It is not necessary to protect this operation with a lock. # It is not necessary to protect this operation with a lock.
# Indeed when this method is called the request has been processed # Indeed when this method is called the request has been processed
# and therefore all resources created or deleted. # and therefore all resources created or deleted.
# dirty_tenants will contain all the tenants for which the # dirty_projects will contain all the projects for which the
# resource count is changed. The list might contain also tenants # resource count is changed. The list might contain also projects
# for which resource count was altered in other requests, but this # for which resource count was altered in other requests, but this
# won't be harmful. # won't be harmful.
dirty_tenants_snap = self._dirty_tenants.copy() dirty_projects_snap = self._dirty_projects.copy()
for tenant_id in dirty_tenants_snap: for project_id in dirty_projects_snap:
quota_api.set_quota_usage_dirty(context, self.name, tenant_id) quota_api.set_quota_usage_dirty(context, self.name, project_id)
self._out_of_sync_tenants |= dirty_tenants_snap self._out_of_sync_projects |= dirty_projects_snap
self._dirty_tenants -= dirty_tenants_snap self._dirty_projects -= dirty_projects_snap
def _db_event_handler(self, mapper, _conn, target): def _db_event_handler(self, mapper, _conn, target):
try: try:
tenant_id = target['tenant_id'] project_id = target['project_id']
except AttributeError: except AttributeError:
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():
LOG.error("Model class %s does not have a tenant_id " LOG.error("Model class %s does not have a project_id "
"attribute", target) "attribute", target)
self._dirty_tenants.add(tenant_id) self._dirty_projects.add(project_id)
# Retry the operation if a duplicate entry exception is raised. This # Retry the operation if a duplicate entry exception is raised. This
# can happen is two or more workers are trying to create a resource of a # can happen is two or more workers are trying to create a resource of a
# give kind for the same tenant concurrently. Retrying the operation will # give kind for the same project concurrently. Retrying the operation will
# ensure that an UPDATE statement is emitted rather than an INSERT one # ensure that an UPDATE statement is emitted rather than an INSERT one
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def _set_quota_usage(self, context, tenant_id, in_use): def _set_quota_usage(self, context, project_id, in_use):
return quota_api.set_quota_usage( return quota_api.set_quota_usage(
context, self.name, tenant_id, in_use=in_use) context, self.name, project_id, in_use=in_use)
def _resync(self, context, tenant_id, in_use): def _resync(self, context, project_id, in_use):
# Update quota usage # Update quota usage
usage_info = self._set_quota_usage(context, tenant_id, in_use) usage_info = self._set_quota_usage(context, project_id, in_use)
self._dirty_tenants.discard(tenant_id) self._dirty_projects.discard(project_id)
self._out_of_sync_tenants.discard(tenant_id) self._out_of_sync_projects.discard(project_id)
LOG.debug(("Unset dirty status for tenant:%(tenant_id)s on " LOG.debug(("Unset dirty status for project:%(project_id)s on "
"resource:%(resource)s"), "resource:%(resource)s"),
{'tenant_id': tenant_id, 'resource': self.name}) {'project_id': project_id, 'resource': self.name})
return usage_info return usage_info
def resync(self, context, tenant_id): def resync(self, context, project_id):
if (tenant_id not in self._out_of_sync_tenants or if (project_id not in self._out_of_sync_projects or
not self._track_resource_events): not self._track_resource_events):
return return
LOG.debug(("Synchronizing usage tracker for tenant:%(tenant_id)s on " LOG.debug(("Synchronizing usage tracker for project:%(project_id)s on "
"resource:%(resource)s"), "resource:%(resource)s"),
{'tenant_id': tenant_id, 'resource': self.name}) {'project_id': project_id, 'resource': self.name})
in_use = context.session.query( in_use = context.session.query(
self._model_class.tenant_id).filter_by( self._model_class.project_id).filter_by(
tenant_id=tenant_id).count() project_id=project_id).count()
# Update quota usage # Update quota usage
return self._resync(context, tenant_id, in_use) return self._resync(context, project_id, in_use)
def count_used(self, context, tenant_id, resync_usage=True): def count_used(self, context, project_id, resync_usage=True):
"""Returns the current usage count for the resource. """Returns the current usage count for the resource.
:param context: The request context. :param context: The request context.
:param tenant_id: The ID of the tenant :param project_id: The ID of the project
:param resync_usage: Default value is set to True. Syncs :param resync_usage: Default value is set to True. Syncs
with in_use usage. with in_use usage.
""" """
# Load current usage data, setting a row-level lock on the DB # Load current usage data, setting a row-level lock on the DB
usage_info = quota_api.get_quota_usage_by_resource_and_tenant( usage_info = quota_api.get_quota_usage_by_resource_and_project(
context, self.name, tenant_id) context, self.name, project_id)
# If dirty or missing, calculate actual resource usage querying # If dirty or missing, calculate actual resource usage querying
# the database and set/create usage info data # the database and set/create usage info data
@ -286,27 +286,28 @@ class TrackedResource(BaseResource):
# assumption is generally valid, but if the database is tampered with, # assumption is generally valid, but if the database is tampered with,
# or if data migrations do not take care of usage counters, the # or if data migrations do not take care of usage counters, the
# assumption will not hold anymore # assumption will not hold anymore
if (tenant_id in self._dirty_tenants or if (project_id in self._dirty_projects or
not usage_info or usage_info.dirty): not usage_info or usage_info.dirty):
LOG.debug(("Usage tracker for resource:%(resource)s and tenant:" LOG.debug(("Usage tracker for resource:%(resource)s and project:"
"%(tenant_id)s is out of sync, need to count used " "%(project_id)s is out of sync, need to count used "
"quota"), {'resource': self.name, "quota"), {'resource': self.name,
'tenant_id': tenant_id}) 'project_id': project_id})
in_use = context.session.query( in_use = context.session.query(
self._model_class.tenant_id).filter_by( self._model_class.project_id).filter_by(
tenant_id=tenant_id).count() project_id=project_id).count()
# Update quota usage, if requested (by default do not do that, as # Update quota usage, if requested (by default do not do that, as
# typically one counts before adding a record, and that would mark # typically one counts before adding a record, and that would mark
# the usage counter as dirty again) # the usage counter as dirty again)
if resync_usage: if resync_usage:
usage_info = self._resync(context, tenant_id, in_use) usage_info = self._resync(context, project_id, in_use)
else: else:
resource = usage_info.resource if usage_info else self.name resource = usage_info.resource if usage_info else self.name
tenant_id = usage_info.tenant_id if usage_info else tenant_id project_id = (usage_info.project_id if usage_info else
project_id)
dirty = usage_info.dirty if usage_info else True dirty = usage_info.dirty if usage_info else True
usage_info = quota_api.QuotaUsageInfo( usage_info = quota_api.QuotaUsageInfo(
resource, tenant_id, in_use, dirty) resource, project_id, in_use, dirty)
LOG.debug(("Quota usage for %(resource)s was recalculated. " LOG.debug(("Quota usage for %(resource)s was recalculated. "
"Used quota:%(used)d."), "Used quota:%(used)d."),
@ -314,16 +315,16 @@ class TrackedResource(BaseResource):
'used': usage_info.used}) 'used': usage_info.used})
return usage_info.used return usage_info.used
def count_reserved(self, context, tenant_id): def count_reserved(self, context, project_id):
"""Return the current reservation count for the resource.""" """Return the current reservation count for the resource."""
# NOTE(princenana) Current implementation of reservations # NOTE(princenana) Current implementation of reservations
# is ephemeral and returns the default value # is ephemeral and returns the default value
reservations = quota_api.get_reservations_for_resources( reservations = quota_api.get_reservations_for_resources(
context, tenant_id, [self.name]) context, project_id, [self.name])
reserved = reservations.get(self.name, 0) reserved = reservations.get(self.name, 0)
return reserved return reserved
def count(self, context, _plugin, tenant_id, resync_usage=True, def count(self, context, _plugin, project_id, resync_usage=True,
count_db_registers=False): count_db_registers=False):
"""Return the count of the resource. """Return the count of the resource.
@ -332,11 +333,11 @@ class TrackedResource(BaseResource):
CountableResource instances. CountableResource instances.
""" """
if count_db_registers: if count_db_registers:
count = self._count_db_registers(context, tenant_id) count = self._count_db_registers(context, project_id)
else: else:
count = self.count_used(context, tenant_id, resync_usage) count = self.count_used(context, project_id, resync_usage)
return count + self.count_reserved(context, tenant_id) 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. """Return the existing resources (self._model_class) in a project.

View File

@ -192,7 +192,7 @@ class TestQuotasController(test_functional.PecanFunctionalTest):
def test_index_admin(self): def test_index_admin(self):
# NOTE(salv-orlando): The quota controller has an hardcoded check for # NOTE(salv-orlando): The quota controller has an hardcoded check for
# admin-ness for this operation, which is supposed to return quotas for # admin-ness for this operation, which is supposed to return quotas for
# all tenants. Such check is "vestigial" from the home-grown WSGI and # all projects. Such check is "vestigial" from the home-grown WSGI and
# shall be removed # shall be removed
response = self.app.get('%s.json' % self.base_url, response = self.app.get('%s.json' % self.base_url,
headers={'X-Project-Id': 'admin', headers={'X-Project-Id': 'admin',
@ -213,7 +213,7 @@ class TestQuotasController(test_functional.PecanFunctionalTest):
self._verify_default_limits(json_body) self._verify_default_limits(json_body)
def test_get(self): def test_get(self):
# It is not ok to access another tenant's limits # It is not ok to access another project's limits
url = '%s/foo.json' % self.base_url url = '%s/foo.json' % self.base_url
response = self.app.get(url, expect_errors=True) response = self.app.get(url, expect_errors=True)
self.assertEqual(403, response.status_int) self.assertEqual(403, response.status_int)
@ -269,7 +269,7 @@ class TestQuotasController(test_functional.PecanFunctionalTest):
json_body = jsonutils.loads(response.body) json_body = jsonutils.loads(response.body)
found = False found = False
for qs in json_body['quotas']: for qs in json_body['quotas']:
if qs['tenant_id'] == 'foo': if qs['project_id'] == 'foo':
found = True found = True
self.assertTrue(found) self.assertTrue(found)
@ -283,7 +283,7 @@ class TestQuotasController(test_functional.PecanFunctionalTest):
self.assertEqual(200, response.status_int) self.assertEqual(200, response.status_int)
json_body = jsonutils.loads(response.body) json_body = jsonutils.loads(response.body)
for qs in json_body['quotas']: for qs in json_body['quotas']:
self.assertNotEqual('foo', qs['tenant_id']) self.assertNotEqual('foo', qs['project_id'])
def test_quotas_get_defaults(self): def test_quotas_get_defaults(self):
response = self.app.get('%s/foo/default.json' % self.base_url, response = self.app.get('%s/foo/default.json' % self.base_url,
@ -294,13 +294,14 @@ class TestQuotasController(test_functional.PecanFunctionalTest):
json_body = jsonutils.loads(response.body) json_body = jsonutils.loads(response.body)
self._verify_default_limits(json_body) self._verify_default_limits(json_body)
def test_get_tenant_info(self): def test_get_project_info(self):
response = self.app.get('%s/tenant.json' % self.base_url, for key in ('project', 'tenant'):
response = self.app.get('%s/%s.json' % (self.base_url, key),
headers={'X-Project-Id': 'admin', headers={'X-Project-Id': 'admin',
'X-Roles': 'admin'}) 'X-Roles': 'admin'})
self.assertEqual(200, response.status_int) self.assertEqual(200, response.status_int)
json_body = jsonutils.loads(response.body) json_body = jsonutils.loads(response.body)
self.assertEqual('admin', json_body['tenant']['tenant_id']) self.assertEqual('admin', json_body[key][key + '_id'])
class TestResourceController(TestRootController): class TestResourceController(TestRootController):
@ -318,11 +319,11 @@ class TestResourceController(TestRootController):
def _gen_port(self): def _gen_port(self):
network_id = self.plugin.create_network(context.get_admin_context(), { network_id = self.plugin.create_network(context.get_admin_context(), {
'network': 'network':
{'name': 'pecannet', 'tenant_id': 'tenid', 'shared': False, {'name': 'pecannet', 'project_id': 'tenid', 'shared': False,
'admin_state_up': True, 'status': 'ACTIVE'}})['id'] 'admin_state_up': True, 'status': 'ACTIVE'}})['id']
self.port = self.plugin.create_port(context.get_admin_context(), { self.port = self.plugin.create_port(context.get_admin_context(), {
'port': 'port':
{'tenant_id': 'tenid', 'network_id': network_id, {'project_id': 'tenid', 'network_id': network_id,
'fixed_ips': n_const.ATTR_NOT_SPECIFIED, 'fixed_ips': n_const.ATTR_NOT_SPECIFIED,
'mac_address': '00:11:22:33:44:55', 'mac_address': '00:11:22:33:44:55',
'admin_state_up': True, 'device_id': 'FF', 'admin_state_up': True, 'device_id': 'FF',
@ -364,7 +365,7 @@ class TestResourceController(TestRootController):
self._test_get_collection_with_fields_selector(fields=[]) self._test_get_collection_with_fields_selector(fields=[])
def test_project_id_in_mandatory_fields(self): def test_project_id_in_mandatory_fields(self):
# ports only specifies that tenant_id is mandatory, but project_id # ports only specifies that project_id is mandatory, but project_id
# should still be passed to the plugin. # should still be passed to the plugin.
mock_get = mock.patch.object(self.plugin, 'get_ports', mock_get = mock.patch.object(self.plugin, 'get_ports',
return_value=[]).start() return_value=[]).start()
@ -384,10 +385,10 @@ class TestResourceController(TestRootController):
# Explicitly require an attribute which is also 'required_by_policy'. # Explicitly require an attribute which is also 'required_by_policy'.
# The attribute should not be stripped while generating the response # The attribute should not be stripped while generating the response
item_resp = self.app.get( item_resp = self.app.get(
'/v2.0/ports/%s.json?fields=id&fields=tenant_id' % self.port['id'], '/v2.0/ports/%s.json?fields=id&fields=project_id' %
headers={'X-Project-Id': 'tenid'}) self.port['id'], headers={'X-Project-Id': 'tenid'})
self.assertEqual(200, item_resp.status_int) self.assertEqual(200, item_resp.status_int)
self._check_item(['id', 'tenant_id'], self._check_item(['id', 'project_id'],
jsonutils.loads(item_resp.body)['port']) jsonutils.loads(item_resp.body)['port'])
def test_duped_and_empty_fields_stripped(self): def test_duped_and_empty_fields_stripped(self):
@ -406,7 +407,7 @@ class TestResourceController(TestRootController):
'/v2.0/ports.json', '/v2.0/ports.json',
params={'port': {'network_id': self.port['network_id'], params={'port': {'network_id': self.port['network_id'],
'admin_state_up': True, 'admin_state_up': True,
'tenant_id': 'tenid'}}, 'project_id': 'tenid'}},
headers={'X-Project-Id': 'tenid'}) headers={'X-Project-Id': 'tenid'})
self.assertEqual(response.status_int, 201) self.assertEqual(response.status_int, 201)
@ -426,7 +427,7 @@ class TestResourceController(TestRootController):
'/v2.0/ports.json', '/v2.0/ports.json',
params={'port': {'network_id': self.port['network_id'], params={'port': {'network_id': self.port['network_id'],
'admin_state_up': True, 'admin_state_up': True,
'tenant_id': 'tenid'}}, 'project_id': 'tenid'}},
headers={'X-Project-Id': 'tenid'}) headers={'X-Project-Id': 'tenid'})
self.assertEqual(201, response.status_int) self.assertEqual(201, response.status_int)
@ -439,7 +440,7 @@ class TestResourceController(TestRootController):
self.assertEqual(1, len(json_body)) self.assertEqual(1, len(json_body))
self.assertIn('port', json_body) self.assertIn('port', json_body)
self.assertEqual('test', json_body['port']['name']) self.assertEqual('test', json_body['port']['name'])
self.assertEqual('tenid', json_body['port']['tenant_id']) self.assertEqual('tenid', json_body['port']['project_id'])
def test_delete(self): def test_delete(self):
response = self.app.delete('/v2.0/ports/%s.json' % self.port['id'], response = self.app.delete('/v2.0/ports/%s.json' % self.port['id'],
@ -487,10 +488,10 @@ class TestResourceController(TestRootController):
'/v2.0/ports.json', '/v2.0/ports.json',
params={'ports': [{'network_id': self.port['network_id'], params={'ports': [{'network_id': self.port['network_id'],
'admin_state_up': True, 'admin_state_up': True,
'tenant_id': 'tenid'}, 'project_id': 'tenid'},
{'network_id': self.port['network_id'], {'network_id': self.port['network_id'],
'admin_state_up': True, 'admin_state_up': True,
'tenant_id': 'tenid'}] 'project_id': 'tenid'}]
}, },
headers={'X-Project-Id': 'tenid'}) headers={'X-Project-Id': 'tenid'})
self.assertEqual(201, response.status_int) self.assertEqual(201, response.status_int)
@ -518,11 +519,11 @@ class TestResourceController(TestRootController):
params={'ports': [{'network_id': self.port['network_id'], params={'ports': [{'network_id': self.port['network_id'],
'admin_state_up': True, 'admin_state_up': True,
'security_groups': [sg_id], 'security_groups': [sg_id],
'tenant_id': 'tenid'}, 'project_id': 'tenid'},
{'network_id': self.port['network_id'], {'network_id': self.port['network_id'],
'admin_state_up': True, 'admin_state_up': True,
'security_groups': [sg_id], 'security_groups': [sg_id],
'tenant_id': 'tenid'}] 'project_id': 'tenid'}]
}, },
headers={'X-Project-Id': 'tenid'}) headers={'X-Project-Id': 'tenid'})
self.assertEqual(201, port_response.status_int) self.assertEqual(201, port_response.status_int)
@ -539,10 +540,10 @@ class TestResourceController(TestRootController):
'/v2.0/ports.json', '/v2.0/ports.json',
params={'ports': [{'network_id': self.port['network_id'], params={'ports': [{'network_id': self.port['network_id'],
'admin_state_up': True, 'admin_state_up': True,
'tenant_id': 'tenid'}, 'project_id': 'tenid'},
{'network_id': self.port['network_id'], {'network_id': self.port['network_id'],
'admin_state_up': True, 'admin_state_up': True,
'tenant_id': 'tenid'}] 'project_id': 'tenid'}]
}, },
headers={'X-Project-Id': 'tenid'}) headers={'X-Project-Id': 'tenid'})
self.assertEqual(response.status_int, 201) self.assertEqual(response.status_int, 201)
@ -556,13 +557,13 @@ class TestResourceController(TestRootController):
'/v2.0/ports.json', '/v2.0/ports.json',
params={'ports': [{'network_id': self.port['network_id'], params={'ports': [{'network_id': self.port['network_id'],
'admin_state_up': True, 'admin_state_up': True,
'tenant_id': 'tenid'}, 'project_id': 'tenid'},
{'network_id': self.port['network_id'], {'network_id': self.port['network_id'],
'admin_state_up': True, 'admin_state_up': True,
'tenant_id': 'tenid'}, 'project_id': 'tenid'},
{'network_id': 'bad_net_id', {'network_id': 'bad_net_id',
'admin_state_up': True, 'admin_state_up': True,
'tenant_id': 'tenid'}] 'project_id': 'tenid'}]
}, },
headers={'X-Project-Id': 'tenid'}, headers={'X-Project-Id': 'tenid'},
expect_errors=True) expect_errors=True)
@ -579,7 +580,7 @@ class TestResourceController(TestRootController):
'/v2.0/ports.json', '/v2.0/ports.json',
params={'ports': [{'network_id': self.port['network_id'], params={'ports': [{'network_id': self.port['network_id'],
'admin_state_up': True, 'admin_state_up': True,
'tenant_id': 'tenid'}] 'project_id': 'tenid'}]
}, },
headers={'X-Project-Id': 'tenid'}) headers={'X-Project-Id': 'tenid'})
self.assertEqual(response.status_int, 201) self.assertEqual(response.status_int, 201)
@ -598,13 +599,15 @@ class TestPaginationAndSorting(test_functional.PecanFunctionalTest):
self.addCleanup(policy.reset) self.addCleanup(policy.reset)
self.plugin = directory.get_plugin() self.plugin = directory.get_plugin()
self.ctx = context.get_admin_context() self.ctx = context.get_admin_context()
self._project_id = 'project_id1'
self._create_networks(self.RESOURCE_COUNT) self._create_networks(self.RESOURCE_COUNT)
self.networks = self._get_collection()['networks'] self.networks = self._get_collection()['networks']
def _create_networks(self, count=1): def _create_networks(self, count=1):
network_ids = [] network_ids = []
for index in range(count): for index in range(count):
network = {'name': 'pecannet-%d' % index, 'tenant_id': 'tenid', network = {'name': 'pecannet-%d' % index,
'project_id': self._project_id,
'shared': False, 'admin_state_up': True, 'shared': False, 'admin_state_up': True,
'status': 'ACTIVE'} 'status': 'ACTIVE'}
network_id = self.plugin.create_network( network_id = self.plugin.create_network(
@ -632,7 +635,8 @@ class TestPaginationAndSorting(test_functional.PecanFunctionalTest):
url = '/v2.0/%s.json' % collection url = '/v2.0/%s.json' % collection
if query_params: if query_params:
url = '%s?%s' % (url, '&'.join(query_params)) url = '%s?%s' % (url, '&'.join(query_params))
list_resp = self.app.get(url, headers={'X-Project-Id': 'tenid'}) list_resp = self.app.get(url,
headers={'X-Project-Id': self._project_id})
self.assertEqual(200, list_resp.status_int) self.assertEqual(200, list_resp.status_int)
return list_resp.json return list_resp.json
@ -735,9 +739,9 @@ class TestRequestProcessing(TestRootController):
def test_context_set_in_request(self): def test_context_set_in_request(self):
self.app.get('/v2.0/ports.json', self.app.get('/v2.0/ports.json',
headers={'X-Project-Id': 'tenant_id'}) headers={'X-Project-Id': 'project_id'})
self.assertEqual('tenant_id', self.assertEqual('project_id',
self.captured_context['neutron_context'].tenant_id) self.captured_context['neutron_context'].project_id)
def test_core_resource_identified(self): def test_core_resource_identified(self):
self.app.get('/v2.0/ports.json') self.app.get('/v2.0/ports.json')
@ -1169,4 +1173,3 @@ class TestExcludeAttributePolicy(test_functional.PecanFunctionalTest):
json_body = jsonutils.loads(response.body) json_body = jsonutils.loads(response.body)
self.assertEqual(response.status_int, 200) self.assertEqual(response.status_int, 200)
self.assertEqual('tenid', json_body['network']['project_id']) self.assertEqual('tenid', json_body['network']['project_id'])
self.assertEqual('tenid', json_body['network']['tenant_id'])

View File

@ -31,26 +31,26 @@ DB_PLUGIN_KLASS = 'neutron.db.db_base_plugin_v2.NeutronDbPluginV2'
class TestQuotaDbApi(testlib_api.SqlTestCaseLight): class TestQuotaDbApi(testlib_api.SqlTestCaseLight):
def _set_context(self): def _set_context(self):
self.tenant_id = 'Higuain' self.project_id = 'Higuain'
self.context = context.Context('Gonzalo', self.tenant_id, self.context = context.Context('Gonzalo', self.project_id,
is_admin=False, is_advsvc=False) is_admin=False, is_advsvc=False)
def _create_reservation(self, resource_deltas, def _create_reservation(self, resource_deltas,
tenant_id=None, expiration=None): project_id=None, expiration=None):
tenant_id = tenant_id or self.tenant_id project_id = project_id or self.project_id
return quota_api.create_reservation( return quota_api.create_reservation(
self.context, tenant_id, resource_deltas, expiration) self.context, project_id, resource_deltas, expiration)
def _create_quota_usage(self, resource, used, tenant_id=None): def _create_quota_usage(self, resource, used, project_id=None):
tenant_id = tenant_id or self.tenant_id project_id = project_id or self.project_id
return quota_api.set_quota_usage(context.get_admin_context(), return quota_api.set_quota_usage(context.get_admin_context(),
resource, tenant_id, in_use=used) resource, project_id, in_use=used)
def _verify_quota_usage(self, usage_info, def _verify_quota_usage(self, usage_info,
expected_resource=None, expected_resource=None,
expected_used=None, expected_used=None,
expected_dirty=None): expected_dirty=None):
self.assertEqual(self.tenant_id, usage_info.tenant_id) self.assertEqual(self.project_id, usage_info.project_id)
if expected_resource: if expected_resource:
self.assertEqual(expected_resource, usage_info.resource) self.assertEqual(expected_resource, usage_info.resource)
if expected_dirty is not None: if expected_dirty is not None:
@ -75,12 +75,12 @@ class TestQuotaDbApi(testlib_api.SqlTestCaseLight):
self._create_quota_usage('goals', 26) self._create_quota_usage('goals', 26)
# Higuain scores a double # Higuain scores a double
usage_info_1 = quota_api.set_quota_usage( usage_info_1 = quota_api.set_quota_usage(
self.context, 'goals', self.tenant_id, self.context, 'goals', self.project_id,
in_use=28) in_use=28)
self._verify_quota_usage(usage_info_1, self._verify_quota_usage(usage_info_1,
expected_used=28) expected_used=28)
usage_info_2 = quota_api.set_quota_usage( usage_info_2 = quota_api.set_quota_usage(
self.context, 'goals', self.tenant_id, self.context, 'goals', self.project_id,
in_use=24) in_use=24)
self._verify_quota_usage(usage_info_2, self._verify_quota_usage(usage_info_2,
expected_used=24) expected_used=24)
@ -89,7 +89,7 @@ class TestQuotaDbApi(testlib_api.SqlTestCaseLight):
self._create_quota_usage('goals', 26) self._create_quota_usage('goals', 26)
# Higuain scores a double # Higuain scores a double
usage_info_1 = quota_api.set_quota_usage( usage_info_1 = quota_api.set_quota_usage(
self.context, 'goals', self.tenant_id, self.context, 'goals', self.project_id,
in_use=2, delta=True) in_use=2, delta=True)
self._verify_quota_usage(usage_info_1, self._verify_quota_usage(usage_info_1,
expected_used=28) expected_used=28)
@ -98,35 +98,36 @@ class TestQuotaDbApi(testlib_api.SqlTestCaseLight):
self._create_quota_usage('goals', 26) self._create_quota_usage('goals', 26)
# Higuain needs a shower after the match # Higuain needs a shower after the match
self.assertEqual(1, quota_api.set_quota_usage_dirty( self.assertEqual(1, quota_api.set_quota_usage_dirty(
self.context, 'goals', self.tenant_id)) self.context, 'goals', self.project_id))
usage_info = quota_api.get_quota_usage_by_resource_and_tenant( usage_info = quota_api.get_quota_usage_by_resource_and_project(
self.context, 'goals', self.tenant_id) self.context, 'goals', self.project_id)
self._verify_quota_usage(usage_info, self._verify_quota_usage(usage_info,
expected_dirty=True) expected_dirty=True)
# Higuain is clean now # Higuain is clean now
self.assertEqual(1, quota_api.set_quota_usage_dirty( self.assertEqual(1, quota_api.set_quota_usage_dirty(
self.context, 'goals', self.tenant_id, dirty=False)) self.context, 'goals', self.project_id, dirty=False))
usage_info = quota_api.get_quota_usage_by_resource_and_tenant( usage_info = quota_api.get_quota_usage_by_resource_and_project(
self.context, 'goals', self.tenant_id) self.context, 'goals', self.project_id)
self._verify_quota_usage(usage_info, self._verify_quota_usage(usage_info,
expected_dirty=False) expected_dirty=False)
def test_set_dirty_non_existing_quota_usage(self): def test_set_dirty_non_existing_quota_usage(self):
self.assertEqual(0, quota_api.set_quota_usage_dirty( self.assertEqual(0, quota_api.set_quota_usage_dirty(
self.context, 'meh', self.tenant_id)) self.context, 'meh', self.project_id))
def test_set_resources_quota_usage_dirty(self): def test_set_resources_quota_usage_dirty(self):
self._create_quota_usage('goals', 26) self._create_quota_usage('goals', 26)
self._create_quota_usage('assists', 11) self._create_quota_usage('assists', 11)
self._create_quota_usage('bookings', 3) self._create_quota_usage('bookings', 3)
self.assertEqual(2, quota_api.set_resources_quota_usage_dirty( self.assertEqual(2, quota_api.set_resources_quota_usage_dirty(
self.context, ['goals', 'bookings'], self.tenant_id)) self.context, ['goals', 'bookings'], self.project_id))
usage_info_goals = quota_api.get_quota_usage_by_resource_and_tenant( usage_info_goals = quota_api.get_quota_usage_by_resource_and_project(
self.context, 'goals', self.tenant_id) self.context, 'goals', self.project_id)
usage_info_assists = quota_api.get_quota_usage_by_resource_and_tenant( usage_info_assists = quota_api.get_quota_usage_by_resource_and_project(
self.context, 'assists', self.tenant_id) self.context, 'assists', self.project_id)
usage_info_bookings = quota_api.get_quota_usage_by_resource_and_tenant( usage_info_bookings = (
self.context, 'bookings', self.tenant_id) quota_api.get_quota_usage_by_resource_and_project(
self.context, 'bookings', self.project_id))
self._verify_quota_usage(usage_info_goals, expected_dirty=True) self._verify_quota_usage(usage_info_goals, expected_dirty=True)
self._verify_quota_usage(usage_info_assists, expected_dirty=False) self._verify_quota_usage(usage_info_assists, expected_dirty=False)
self._verify_quota_usage(usage_info_bookings, expected_dirty=True) self._verify_quota_usage(usage_info_bookings, expected_dirty=True)
@ -135,30 +136,31 @@ class TestQuotaDbApi(testlib_api.SqlTestCaseLight):
self._create_quota_usage('goals', 26) self._create_quota_usage('goals', 26)
self._create_quota_usage('assists', 11) self._create_quota_usage('assists', 11)
self._create_quota_usage('bookings', 3) self._create_quota_usage('bookings', 3)
# Expect all the resources for the tenant to be set dirty # Expect all the resources for the project to be set dirty
self.assertEqual(3, quota_api.set_resources_quota_usage_dirty( self.assertEqual(3, quota_api.set_resources_quota_usage_dirty(
self.context, [], self.tenant_id)) self.context, [], self.project_id))
usage_info_goals = quota_api.get_quota_usage_by_resource_and_tenant( usage_info_goals = quota_api.get_quota_usage_by_resource_and_project(
self.context, 'goals', self.tenant_id) self.context, 'goals', self.project_id)
usage_info_assists = quota_api.get_quota_usage_by_resource_and_tenant( usage_info_assists = quota_api.get_quota_usage_by_resource_and_project(
self.context, 'assists', self.tenant_id) self.context, 'assists', self.project_id)
usage_info_bookings = quota_api.get_quota_usage_by_resource_and_tenant( usage_info_bookings = (
self.context, 'bookings', self.tenant_id) quota_api.get_quota_usage_by_resource_and_project(
self.context, 'bookings', self.project_id))
self._verify_quota_usage(usage_info_goals, expected_dirty=True) self._verify_quota_usage(usage_info_goals, expected_dirty=True)
self._verify_quota_usage(usage_info_assists, expected_dirty=True) self._verify_quota_usage(usage_info_assists, expected_dirty=True)
self._verify_quota_usage(usage_info_bookings, expected_dirty=True) self._verify_quota_usage(usage_info_bookings, expected_dirty=True)
# Higuain is clean now # Higuain is clean now
self.assertEqual(1, quota_api.set_quota_usage_dirty( self.assertEqual(1, quota_api.set_quota_usage_dirty(
self.context, 'goals', self.tenant_id, dirty=False)) self.context, 'goals', self.project_id, dirty=False))
usage_info = quota_api.get_quota_usage_by_resource_and_tenant( usage_info = quota_api.get_quota_usage_by_resource_and_project(
self.context, 'goals', self.tenant_id) self.context, 'goals', self.project_id)
self._verify_quota_usage(usage_info, self._verify_quota_usage(usage_info,
expected_dirty=False) expected_dirty=False)
def _test_set_all_quota_usage_dirty(self, expected): def _test_set_all_quota_usage_dirty(self, expected):
self._create_quota_usage('goals', 26) self._create_quota_usage('goals', 26)
self._create_quota_usage('goals', 12, tenant_id='Callejon') self._create_quota_usage('goals', 12, project_id='Callejon')
self.assertEqual(expected, quota_api.set_all_quota_usage_dirty( self.assertEqual(expected, quota_api.set_all_quota_usage_dirty(
self.context, 'goals')) self.context, 'goals'))
@ -167,13 +169,13 @@ class TestQuotaDbApi(testlib_api.SqlTestCaseLight):
# admin context we can clean only one # admin context we can clean only one
self._test_set_all_quota_usage_dirty(expected=1) self._test_set_all_quota_usage_dirty(expected=1)
def test_get_quota_usage_by_tenant(self): def test_get_quota_usage_by_project(self):
self._create_quota_usage('goals', 26) self._create_quota_usage('goals', 26)
self._create_quota_usage('assists', 11) self._create_quota_usage('assists', 11)
# Create a resource for a different tenant # Create a resource for a different project
self._create_quota_usage('mehs', 99, tenant_id='buffon') self._create_quota_usage('mehs', 99, project_id='buffon')
usage_infos = quota_api.get_quota_usage_by_tenant_id( usage_infos = quota_api.get_quota_usage_by_project_id(
self.context, self.tenant_id) self.context, self.project_id)
self.assertEqual(2, len(usage_infos)) self.assertEqual(2, len(usage_infos))
resources = [info.resource for info in usage_infos] resources = [info.resource for info in usage_infos]
@ -183,26 +185,26 @@ class TestQuotaDbApi(testlib_api.SqlTestCaseLight):
def test_get_quota_usage_by_resource(self): def test_get_quota_usage_by_resource(self):
self._create_quota_usage('goals', 26) self._create_quota_usage('goals', 26)
self._create_quota_usage('assists', 11) self._create_quota_usage('assists', 11)
self._create_quota_usage('goals', 12, tenant_id='Callejon') self._create_quota_usage('goals', 12, project_id='Callejon')
usage_infos = quota_api.get_quota_usage_by_resource( usage_infos = quota_api.get_quota_usage_by_resource(
self.context, 'goals') self.context, 'goals')
# Only 1 result expected in tenant context # Only 1 result expected in project context
self.assertEqual(1, len(usage_infos)) self.assertEqual(1, len(usage_infos))
self._verify_quota_usage(usage_infos[0], self._verify_quota_usage(usage_infos[0],
expected_resource='goals', expected_resource='goals',
expected_used=26) expected_used=26)
def test_get_quota_usage_by_tenant_and_resource(self): def test_get_quota_usage_by_project_and_resource(self):
self._create_quota_usage('goals', 26) self._create_quota_usage('goals', 26)
usage_info = quota_api.get_quota_usage_by_resource_and_tenant( usage_info = quota_api.get_quota_usage_by_resource_and_project(
self.context, 'goals', self.tenant_id) self.context, 'goals', self.project_id)
self._verify_quota_usage(usage_info, self._verify_quota_usage(usage_info,
expected_resource='goals', expected_resource='goals',
expected_used=26) expected_used=26)
def test_get_non_existing_quota_usage_returns_none(self): def test_get_non_existing_quota_usage_returns_none(self):
self.assertIsNone(quota_api.get_quota_usage_by_resource_and_tenant( self.assertIsNone(quota_api.get_quota_usage_by_resource_and_project(
self.context, 'goals', self.tenant_id)) self.context, 'goals', self.project_id))
def _verify_reserved_resources(self, expected, actual): def _verify_reserved_resources(self, expected, actual):
for (resource, delta) in actual.items(): for (resource, delta) in actual.items():
@ -214,14 +216,14 @@ class TestQuotaDbApi(testlib_api.SqlTestCaseLight):
def test_create_reservation(self): def test_create_reservation(self):
resources = {'goals': 2, 'assists': 1} resources = {'goals': 2, 'assists': 1}
resv = self._create_reservation(resources) resv = self._create_reservation(resources)
self.assertEqual(self.tenant_id, resv.tenant_id) self.assertEqual(self.project_id, resv.project_id)
self._verify_reserved_resources(resources, resv.deltas) self._verify_reserved_resources(resources, resv.deltas)
def test_create_reservation_with_expiration(self): def test_create_reservation_with_expiration(self):
resources = {'goals': 2, 'assists': 1} resources = {'goals': 2, 'assists': 1}
exp_date = datetime.datetime(2016, 3, 31, 14, 30) exp_date = datetime.datetime(2016, 3, 31, 14, 30)
resv = self._create_reservation(resources, expiration=exp_date) resv = self._create_reservation(resources, expiration=exp_date)
self.assertEqual(self.tenant_id, resv.tenant_id) self.assertEqual(self.project_id, resv.project_id)
self.assertEqual(exp_date, resv.expiration) self.assertEqual(exp_date, resv.expiration)
self._verify_reserved_resources(resources, resv.deltas) self._verify_reserved_resources(resources, resv.deltas)
@ -245,7 +247,8 @@ class TestQuotaDbApi(testlib_api.SqlTestCaseLight):
mock_utcnow.return_value = datetime.datetime( mock_utcnow.return_value = datetime.datetime(
2015, 5, 20, 0, 0) 2015, 5, 20, 0, 0)
deltas = quota_api.get_reservations_for_resources( deltas = quota_api.get_reservations_for_resources(
self.context, self.tenant_id, ['goals', 'assists', 'bookings']) self.context, self.project_id,
['goals', 'assists', 'bookings'])
self.assertIn('goals', deltas) self.assertIn('goals', deltas)
self.assertEqual(5, deltas['goals']) self.assertEqual(5, deltas['goals'])
self.assertIn('assists', deltas) self.assertIn('assists', deltas)
@ -260,7 +263,7 @@ class TestQuotaDbApi(testlib_api.SqlTestCaseLight):
2015, 5, 20, 0, 0) 2015, 5, 20, 0, 0)
self._get_reservations_for_resource_helper() self._get_reservations_for_resource_helper()
deltas = quota_api.get_reservations_for_resources( deltas = quota_api.get_reservations_for_resources(
self.context, self.tenant_id, self.context, self.project_id,
['goals', 'assists', 'bookings'], ['goals', 'assists', 'bookings'],
expired=True) expired=True)
self.assertIn('assists', deltas) self.assertIn('assists', deltas)
@ -271,7 +274,7 @@ class TestQuotaDbApi(testlib_api.SqlTestCaseLight):
def test_get_reservation_for_resources_with_empty_list(self): def test_get_reservation_for_resources_with_empty_list(self):
self.assertIsNone(quota_api.get_reservations_for_resources( self.assertIsNone(quota_api.get_reservations_for_resources(
self.context, self.tenant_id, [])) self.context, self.project_id, []))
def test_remove_expired_reservations(self): def test_remove_expired_reservations(self):
with mock.patch('neutron.db.quota.api.utcnow') as mock_utcnow: with mock.patch('neutron.db.quota.api.utcnow') as mock_utcnow:
@ -283,13 +286,13 @@ class TestQuotaDbApi(testlib_api.SqlTestCaseLight):
exp_date_2 = datetime.datetime(2015, 3, 31, 14, 30) exp_date_2 = datetime.datetime(2015, 3, 31, 14, 30)
resv_2 = self._create_reservation(resources, expiration=exp_date_2) resv_2 = self._create_reservation(resources, expiration=exp_date_2)
self.assertEqual(1, quota_api.remove_expired_reservations( self.assertEqual(1, quota_api.remove_expired_reservations(
self.context, self.tenant_id)) self.context, self.project_id))
self.assertIsNone(quota_api.get_reservation( self.assertIsNone(quota_api.get_reservation(
self.context, resv_2.reservation_id)) self.context, resv_2.reservation_id))
self.assertIsNotNone(quota_api.get_reservation( self.assertIsNotNone(quota_api.get_reservation(
self.context, resv_1.reservation_id)) self.context, resv_1.reservation_id))
def test_remove_expired_reservations_no_tenant(self): def test_remove_expired_reservations_no_project(self):
with mock.patch('neutron.db.quota.api.utcnow') as mock_utcnow: with mock.patch('neutron.db.quota.api.utcnow') as mock_utcnow:
mock_utcnow.return_value = datetime.datetime( mock_utcnow.return_value = datetime.datetime(
2015, 5, 20, 0, 0) 2015, 5, 20, 0, 0)
@ -299,7 +302,7 @@ class TestQuotaDbApi(testlib_api.SqlTestCaseLight):
exp_date_2 = datetime.datetime(2015, 3, 31, 14, 30) exp_date_2 = datetime.datetime(2015, 3, 31, 14, 30)
resv_2 = self._create_reservation(resources, resv_2 = self._create_reservation(resources,
expiration=exp_date_2, expiration=exp_date_2,
tenant_id='Callejon') project_id='Callejon')
self.assertEqual(2, quota_api.remove_expired_reservations( self.assertEqual(2, quota_api.remove_expired_reservations(
context.get_admin_context())) context.get_admin_context()))
self.assertIsNone(quota_api.get_reservation( self.assertIsNone(quota_api.get_reservation(
@ -311,14 +314,14 @@ class TestQuotaDbApi(testlib_api.SqlTestCaseLight):
class TestQuotaDbApiAdminContext(TestQuotaDbApi): class TestQuotaDbApiAdminContext(TestQuotaDbApi):
def _set_context(self): def _set_context(self):
self.tenant_id = 'Higuain' self.project_id = 'Higuain'
self.context = context.Context('Gonzalo', self.tenant_id, self.context = context.Context('Gonzalo', self.project_id,
is_admin=True, is_advsvc=True) is_admin=True, is_advsvc=True)
def test_get_quota_usage_by_resource(self): def test_get_quota_usage_by_resource(self):
self._create_quota_usage('goals', 26) self._create_quota_usage('goals', 26)
self._create_quota_usage('assists', 11) self._create_quota_usage('assists', 11)
self._create_quota_usage('goals', 12, tenant_id='Callejon') self._create_quota_usage('goals', 12, project_id='Callejon')
usage_infos = quota_api.get_quota_usage_by_resource( usage_infos = quota_api.get_quota_usage_by_resource(
self.context, 'goals') self.context, 'goals')
# 2 results expected in admin context # 2 results expected in admin context

View File

@ -28,7 +28,7 @@ from neutron.tests.unit import testlib_api
DB_PLUGIN_KLASS = 'neutron.db.db_base_plugin_v2.NeutronDbPluginV2' DB_PLUGIN_KLASS = 'neutron.db.db_base_plugin_v2.NeutronDbPluginV2'
def _count_resource(context, resource, tenant_id): def _count_resource(context, resource, project_id):
"""A fake counting function to determine current used counts""" """A fake counting function to determine current used counts"""
if resource[-1] == 's': if resource[-1] == 's':
resource = resource[:-1] resource = resource[:-1]
@ -97,7 +97,8 @@ class TestDbQuotaDriver(testlib_api.SqlTestCase,
defaults = {RESOURCE: TestResource(RESOURCE, 4)} defaults = {RESOURCE: TestResource(RESOURCE, 4)}
self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 2) self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 2)
quotas = self.plugin.get_tenant_quotas(self.context, defaults, PROJECT) quotas = self.plugin.get_project_quotas(self.context, defaults,
PROJECT)
self.assertEqual(2, quotas[RESOURCE]) self.assertEqual(2, quotas[RESOURCE])
def test_update_quota_limit(self): def test_update_quota_limit(self):
@ -105,15 +106,17 @@ class TestDbQuotaDriver(testlib_api.SqlTestCase,
self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 2) self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 2)
self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 3) self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 3)
quotas = self.plugin.get_tenant_quotas(self.context, defaults, PROJECT) quotas = self.plugin.get_project_quotas(self.context, defaults,
PROJECT)
self.assertEqual(3, quotas[RESOURCE]) self.assertEqual(3, quotas[RESOURCE])
def test_delete_tenant_quota_restores_default_limit(self): def test_delete_project_quota_restores_default_limit(self):
defaults = {RESOURCE: TestResource(RESOURCE, 4)} defaults = {RESOURCE: TestResource(RESOURCE, 4)}
self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 2) self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 2)
self.plugin.delete_tenant_quota(self.context, PROJECT) self.plugin.delete_project_quota(self.context, PROJECT)
quotas = self.plugin.get_tenant_quotas(self.context, defaults, PROJECT) quotas = self.plugin.get_project_quotas(self.context, defaults,
PROJECT)
self.assertEqual(4, quotas[RESOURCE]) self.assertEqual(4, quotas[RESOURCE])
def test_get_default_quotas(self): def test_get_default_quotas(self):
@ -123,20 +126,20 @@ class TestDbQuotaDriver(testlib_api.SqlTestCase,
quotas = self.plugin.get_default_quotas(user_ctx, defaults, PROJECT) quotas = self.plugin.get_default_quotas(user_ctx, defaults, PROJECT)
self.assertEqual(4, quotas[RESOURCE]) self.assertEqual(4, quotas[RESOURCE])
def test_get_tenant_quotas(self): def test_get_project_quotas(self):
user_ctx = context.Context(user_id=PROJECT, tenant_id=PROJECT) user_ctx = context.Context(user_id=PROJECT, tenant_id=PROJECT)
self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 2) self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 2)
quotas = self.plugin.get_tenant_quotas(user_ctx, {}, PROJECT) quotas = self.plugin.get_project_quotas(user_ctx, {}, PROJECT)
self.assertEqual(2, quotas[RESOURCE]) self.assertEqual(2, quotas[RESOURCE])
def test_get_tenant_quotas_different_tenant(self): def test_get_project_quotas_different_project(self):
user_ctx = context.Context(user_id=PROJECT, user_ctx = context.Context(user_id=PROJECT,
tenant_id='another_project') tenant_id='another_project')
self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 2) self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 2)
# It is appropriate to use assertFalse here as the expected return # It is appropriate to use assertFalse here as the expected return
# value is an empty dict (the defaults passed in the statement below # value is an empty dict (the defaults passed in the statement below
# after the request context) # after the request context)
self.assertFalse(self.plugin.get_tenant_quotas(user_ctx, {}, PROJECT)) self.assertFalse(self.plugin.get_project_quotas(user_ctx, {}, PROJECT))
def test_get_all_quotas(self): def test_get_all_quotas(self):
project_1 = 'prj_test_1' project_1 = 'prj_test_1'
@ -151,14 +154,14 @@ class TestDbQuotaDriver(testlib_api.SqlTestCase,
self.plugin.update_quota_limit(self.context, project_2, resource_2, 9) self.plugin.update_quota_limit(self.context, project_2, resource_2, 9)
quotas = self.plugin.get_all_quotas(self.context, resources) quotas = self.plugin.get_all_quotas(self.context, resources)
# Expect two tenants' quotas # Expect two projects' quotas
self.assertEqual(2, len(quotas)) self.assertEqual(2, len(quotas))
# But not quotas for the same tenant twice # But not quotas for the same project twice
self.assertNotEqual(quotas[0]['tenant_id'], quotas[1]['tenant_id']) self.assertNotEqual(quotas[0]['project_id'], quotas[1]['project_id'])
# Check the expected limits. The quotas can be in any order. # Check the expected limits. The quotas can be in any order.
for quota in quotas: for quota in quotas:
project = quota['tenant_id'] project = quota['project_id']
self.assertIn(project, (project_1, project_2)) self.assertIn(project, (project_1, project_2))
if project == project_1: if project == project_1:
expected_limit_r1 = 7 expected_limit_r1 = 7
@ -208,15 +211,15 @@ class TestDbQuotaDriver(testlib_api.SqlTestCase,
self.plugin.update_quota_limit(self.context, PROJECT, resource_name, 2) self.plugin.update_quota_limit(self.context, PROJECT, resource_name, 2)
reservation = quota_driver.make_reservation( reservation = quota_driver.make_reservation(
self.context, self.context,
self.context.tenant_id, self.context.project_id,
resources, resources,
deltas, deltas,
self.plugin) self.plugin)
self.assertIn(resource_name, reservation.deltas) self.assertIn(resource_name, reservation.deltas)
self.assertEqual(deltas[resource_name], self.assertEqual(deltas[resource_name],
reservation.deltas[resource_name]) reservation.deltas[resource_name])
self.assertEqual(self.context.tenant_id, self.assertEqual(self.context.project_id,
reservation.tenant_id) reservation.project_id)
def test_make_reservation_single_resource(self): def test_make_reservation_single_resource(self):
quota_driver = driver.DbQuotaDriver() quota_driver = driver.DbQuotaDriver()
@ -237,7 +240,7 @@ class TestDbQuotaDriver(testlib_api.SqlTestCase,
self.plugin.update_quota_limit(self.context, PROJECT, ALT_RESOURCE, 2) self.plugin.update_quota_limit(self.context, PROJECT, ALT_RESOURCE, 2)
reservation = quota_driver.make_reservation( reservation = quota_driver.make_reservation(
self.context, self.context,
self.context.tenant_id, self.context.project_id,
resources, resources,
deltas, deltas,
self.plugin) self.plugin)
@ -245,8 +248,8 @@ class TestDbQuotaDriver(testlib_api.SqlTestCase,
self.assertIn(ALT_RESOURCE, reservation.deltas) self.assertIn(ALT_RESOURCE, reservation.deltas)
self.assertEqual(1, reservation.deltas[RESOURCE]) self.assertEqual(1, reservation.deltas[RESOURCE])
self.assertEqual(2, reservation.deltas[ALT_RESOURCE]) self.assertEqual(2, reservation.deltas[ALT_RESOURCE])
self.assertEqual(self.context.tenant_id, self.assertEqual(self.context.project_id,
reservation.tenant_id) reservation.project_id)
def test_make_reservation_over_quota_fails(self): def test_make_reservation_over_quota_fails(self):
quota_driver = driver.DbQuotaDriver() quota_driver = driver.DbQuotaDriver()
@ -257,12 +260,12 @@ class TestDbQuotaDriver(testlib_api.SqlTestCase,
self.assertRaises(exceptions.OverQuota, self.assertRaises(exceptions.OverQuota,
quota_driver.make_reservation, quota_driver.make_reservation,
self.context, self.context,
self.context.tenant_id, self.context.project_id,
resources, resources,
deltas, deltas,
self.plugin) self.plugin)
def test_get_detailed_tenant_quotas_resource(self): def test_get_detailed_project_quotas_resource(self):
res = {RESOURCE: TestTrackedResource(RESOURCE, test_quota.MehModel)} res = {RESOURCE: TestTrackedResource(RESOURCE, test_quota.MehModel)}
self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 6) self.plugin.update_quota_limit(self.context, PROJECT, RESOURCE, 6)
@ -270,13 +273,13 @@ class TestDbQuotaDriver(testlib_api.SqlTestCase,
quota_driver.make_reservation(self.context, PROJECT, res, quota_driver.make_reservation(self.context, PROJECT, res,
{RESOURCE: 1}, self.plugin) {RESOURCE: 1}, self.plugin)
quota_api.set_quota_usage(self.context, RESOURCE, PROJECT, 2) quota_api.set_quota_usage(self.context, RESOURCE, PROJECT, 2)
detailed_quota = self.plugin.get_detailed_tenant_quotas(self.context, detailed_quota = self.plugin.get_detailed_project_quotas(
res, PROJECT) self.context, res, PROJECT)
self.assertEqual(6, detailed_quota[RESOURCE]['limit']) self.assertEqual(6, detailed_quota[RESOURCE]['limit'])
self.assertEqual(2, detailed_quota[RESOURCE]['used']) self.assertEqual(2, detailed_quota[RESOURCE]['used'])
self.assertEqual(1, detailed_quota[RESOURCE]['reserved']) self.assertEqual(1, detailed_quota[RESOURCE]['reserved'])
def test_get_detailed_tenant_quotas_multiple_resource(self): def test_get_detailed_project_quotas_multiple_resource(self):
project_1 = 'prj_test_1' project_1 = 'prj_test_1'
resource_1 = 'res_test_1' resource_1 = 'res_test_1'
resource_2 = 'res_test_2' resource_2 = 'res_test_2'
@ -295,9 +298,8 @@ class TestDbQuotaDriver(testlib_api.SqlTestCase,
quota_api.set_quota_usage(self.context, resource_1, project_1, 2) quota_api.set_quota_usage(self.context, resource_1, project_1, 2)
quota_api.set_quota_usage(self.context, resource_2, project_1, 3) quota_api.set_quota_usage(self.context, resource_2, project_1, 3)
detailed_quota = self.plugin.get_detailed_tenant_quotas(self.context, detailed_quota = self.plugin.get_detailed_project_quotas(
resources, self.context, resources, project_1)
project_1)
self.assertEqual(6, detailed_quota[resource_1]['limit']) self.assertEqual(6, detailed_quota[resource_1]['limit'])
self.assertEqual(1, detailed_quota[resource_1]['reserved']) self.assertEqual(1, detailed_quota[resource_1]['reserved'])

View File

@ -73,9 +73,9 @@ class QuotaExtensionTestCase(testlib_api.WebTestCase):
router.APIRouter() router.APIRouter()
def _test_quota_default_values(self, expected_values): def _test_quota_default_values(self, expected_values):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id)} env = {'neutron.context': context.Context('', project_id)}
res = self.api.get(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.get(_get_path('quotas', id=project_id, fmt=self.fmt),
extra_environ=env) extra_environ=env)
quota = self.deserialize(res) quota = self.deserialize(res)
for resource, expected_value in expected_values.items(): for resource, expected_value in expected_values.items():
@ -118,10 +118,10 @@ class QuotaExtensionDbTestCase(QuotaExtensionTestCase):
'extra1': qconf.DEFAULT_QUOTA}) 'extra1': qconf.DEFAULT_QUOTA})
def test_show_default_quotas_with_admin(self): def test_show_default_quotas_with_admin(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id + '2', env = {'neutron.context': context.Context('', project_id + '2',
is_admin=True)} is_admin=True)}
res = self.api.get(_get_path('quotas', id=tenant_id, res = self.api.get(_get_path('quotas', id=project_id,
action=DEFAULT_QUOTAS_ACTION, action=DEFAULT_QUOTAS_ACTION,
fmt=self.fmt), fmt=self.fmt),
extra_environ=env) extra_environ=env)
@ -134,11 +134,11 @@ class QuotaExtensionDbTestCase(QuotaExtensionTestCase):
self.assertEqual( self.assertEqual(
qconf.DEFAULT_QUOTA_PORT, quota['quota']['port']) qconf.DEFAULT_QUOTA_PORT, quota['quota']['port'])
def test_show_default_quotas_with_owner_tenant(self): def test_show_default_quotas_with_owner_project(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=False)} is_admin=False)}
res = self.api.get(_get_path('quotas', id=tenant_id, res = self.api.get(_get_path('quotas', id=project_id,
action=DEFAULT_QUOTAS_ACTION, action=DEFAULT_QUOTAS_ACTION,
fmt=self.fmt), fmt=self.fmt),
extra_environ=env) extra_environ=env)
@ -152,20 +152,20 @@ class QuotaExtensionDbTestCase(QuotaExtensionTestCase):
qconf.DEFAULT_QUOTA_PORT, quota['quota']['port']) qconf.DEFAULT_QUOTA_PORT, quota['quota']['port'])
def test_show_default_quotas_without_admin_forbidden_returns_403(self): def test_show_default_quotas_without_admin_forbidden_returns_403(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id + '2', env = {'neutron.context': context.Context('', project_id + '2',
is_admin=False)} is_admin=False)}
res = self.api.get(_get_path('quotas', id=tenant_id, res = self.api.get(_get_path('quotas', id=project_id,
action=DEFAULT_QUOTAS_ACTION, action=DEFAULT_QUOTAS_ACTION,
fmt=self.fmt), fmt=self.fmt),
extra_environ=env, expect_errors=True) extra_environ=env, expect_errors=True)
self.assertEqual(403, res.status_int) self.assertEqual(403, res.status_int)
def test_show_quotas_with_admin(self): def test_show_quotas_with_admin(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id + '2', env = {'neutron.context': context.Context('', project_id + '2',
is_admin=True)} is_admin=True)}
res = self.api.get(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.get(_get_path('quotas', id=project_id, fmt=self.fmt),
extra_environ=env) extra_environ=env)
self.assertEqual(200, res.status_int) self.assertEqual(200, res.status_int)
quota = self.deserialize(res) quota = self.deserialize(res)
@ -177,18 +177,18 @@ class QuotaExtensionDbTestCase(QuotaExtensionTestCase):
qconf.DEFAULT_QUOTA_PORT, quota['quota']['port']) qconf.DEFAULT_QUOTA_PORT, quota['quota']['port'])
def test_show_quotas_without_admin_forbidden_returns_403(self): def test_show_quotas_without_admin_forbidden_returns_403(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id + '2', env = {'neutron.context': context.Context('', project_id + '2',
is_admin=False)} is_admin=False)}
res = self.api.get(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.get(_get_path('quotas', id=project_id, fmt=self.fmt),
extra_environ=env, expect_errors=True) extra_environ=env, expect_errors=True)
self.assertEqual(403, res.status_int) self.assertEqual(403, res.status_int)
def test_show_quotas_with_owner_tenant(self): def test_show_quotas_with_owner_project(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=False)} is_admin=False)}
res = self.api.get(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.get(_get_path('quotas', id=project_id, fmt=self.fmt),
extra_environ=env) extra_environ=env)
self.assertEqual(200, res.status_int) self.assertEqual(200, res.status_int)
quota = self.deserialize(res) quota = self.deserialize(res)
@ -200,8 +200,8 @@ class QuotaExtensionDbTestCase(QuotaExtensionTestCase):
qconf.DEFAULT_QUOTA_PORT, quota['quota']['port']) qconf.DEFAULT_QUOTA_PORT, quota['quota']['port'])
def test_list_quotas_with_admin(self): def test_list_quotas_with_admin(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=True)} is_admin=True)}
res = self.api.get(_get_path('quotas', fmt=self.fmt), res = self.api.get(_get_path('quotas', fmt=self.fmt),
extra_environ=env) extra_environ=env)
@ -210,93 +210,93 @@ class QuotaExtensionDbTestCase(QuotaExtensionTestCase):
self.assertEqual([], quota['quotas']) self.assertEqual([], quota['quotas'])
def test_list_quotas_without_admin_forbidden_returns_403(self): def test_list_quotas_without_admin_forbidden_returns_403(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=False)} is_admin=False)}
res = self.api.get(_get_path('quotas', fmt=self.fmt), res = self.api.get(_get_path('quotas', fmt=self.fmt),
extra_environ=env, expect_errors=True) extra_environ=env, expect_errors=True)
self.assertEqual(403, res.status_int) self.assertEqual(403, res.status_int)
def test_update_quotas_without_admin_forbidden_returns_403(self): def test_update_quotas_without_admin_forbidden_returns_403(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=False)} is_admin=False)}
quotas = {'quota': {'network': 100}} quotas = {'quota': {'network': 100}}
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.put(_get_path('quotas', id=project_id, fmt=self.fmt),
self.serialize(quotas), extra_environ=env, self.serialize(quotas), extra_environ=env,
expect_errors=True) expect_errors=True)
self.assertEqual(403, res.status_int) self.assertEqual(403, res.status_int)
def test_update_quotas_with_non_integer_returns_400(self): def test_update_quotas_with_non_integer_returns_400(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=True)} is_admin=True)}
quotas = {'quota': {'network': 'abc'}} quotas = {'quota': {'network': 'abc'}}
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.put(_get_path('quotas', id=project_id, fmt=self.fmt),
self.serialize(quotas), extra_environ=env, self.serialize(quotas), extra_environ=env,
expect_errors=True) expect_errors=True)
self.assertEqual(400, res.status_int) self.assertEqual(400, res.status_int)
def test_update_quotas_with_negative_integer_returns_400(self): def test_update_quotas_with_negative_integer_returns_400(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=True)} is_admin=True)}
quotas = {'quota': {'network': -2}} quotas = {'quota': {'network': -2}}
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.put(_get_path('quotas', id=project_id, fmt=self.fmt),
self.serialize(quotas), extra_environ=env, self.serialize(quotas), extra_environ=env,
expect_errors=True) expect_errors=True)
self.assertEqual(400, res.status_int) self.assertEqual(400, res.status_int)
def test_update_quotas_with_out_of_range_integer_returns_400(self): def test_update_quotas_with_out_of_range_integer_returns_400(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=True)} is_admin=True)}
quotas = {'quota': {'network': constants.DB_INTEGER_MAX_VALUE + 1}} quotas = {'quota': {'network': constants.DB_INTEGER_MAX_VALUE + 1}}
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.put(_get_path('quotas', id=project_id, fmt=self.fmt),
self.serialize(quotas), extra_environ=env, self.serialize(quotas), extra_environ=env,
expect_errors=True) expect_errors=True)
self.assertEqual(exc.HTTPBadRequest.code, res.status_int) self.assertEqual(exc.HTTPBadRequest.code, res.status_int)
def test_update_quotas_to_unlimited(self): def test_update_quotas_to_unlimited(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=True)} is_admin=True)}
quotas = {'quota': {'network': -1}} quotas = {'quota': {'network': -1}}
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.put(_get_path('quotas', id=project_id, fmt=self.fmt),
self.serialize(quotas), extra_environ=env, self.serialize(quotas), extra_environ=env,
expect_errors=False) expect_errors=False)
self.assertEqual(200, res.status_int) self.assertEqual(200, res.status_int)
def test_update_quotas_exceeding_current_limit(self): def test_update_quotas_exceeding_current_limit(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=True)} is_admin=True)}
quotas = {'quota': {'network': 120}} quotas = {'quota': {'network': 120}}
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.put(_get_path('quotas', id=project_id, fmt=self.fmt),
self.serialize(quotas), extra_environ=env, self.serialize(quotas), extra_environ=env,
expect_errors=False) expect_errors=False)
self.assertEqual(200, res.status_int) self.assertEqual(200, res.status_int)
def test_update_quotas_with_non_support_resource_returns_400(self): def test_update_quotas_with_non_support_resource_returns_400(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=True)} is_admin=True)}
quotas = {'quota': {'abc': 100}} quotas = {'quota': {'abc': 100}}
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.put(_get_path('quotas', id=project_id, fmt=self.fmt),
self.serialize(quotas), extra_environ=env, self.serialize(quotas), extra_environ=env,
expect_errors=True) expect_errors=True)
self.assertEqual(400, res.status_int) self.assertEqual(400, res.status_int)
def test_update_quotas_with_admin(self): def test_update_quotas_with_admin(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id + '2', env = {'neutron.context': context.Context('', project_id + '2',
is_admin=True)} is_admin=True)}
quotas = {'quota': {'network': 100}} quotas = {'quota': {'network': 100}}
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.put(_get_path('quotas', id=project_id, fmt=self.fmt),
self.serialize(quotas), extra_environ=env) self.serialize(quotas), extra_environ=env)
self.assertEqual(200, res.status_int) self.assertEqual(200, res.status_int)
env2 = {'neutron.context': context.Context('', tenant_id)} env2 = {'neutron.context': context.Context('', project_id)}
res = self.api.get(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.get(_get_path('quotas', id=project_id, fmt=self.fmt),
extra_environ=env2) extra_environ=env2)
quota = self.deserialize(res) quota = self.deserialize(res)
self.assertEqual(100, quota['quota']['network']) self.assertEqual(100, quota['quota']['network'])
@ -304,44 +304,44 @@ class QuotaExtensionDbTestCase(QuotaExtensionTestCase):
self.assertEqual(qconf.DEFAULT_QUOTA_PORT, quota['quota']['port']) self.assertEqual(qconf.DEFAULT_QUOTA_PORT, quota['quota']['port'])
def test_update_attributes(self): def test_update_attributes(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id + '2', env = {'neutron.context': context.Context('', project_id + '2',
is_admin=True)} is_admin=True)}
quotas = {'quota': {'extra1': 100}} quotas = {'quota': {'extra1': 100}}
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.put(_get_path('quotas', id=project_id, fmt=self.fmt),
self.serialize(quotas), extra_environ=env) self.serialize(quotas), extra_environ=env)
self.assertEqual(200, res.status_int) self.assertEqual(200, res.status_int)
env2 = {'neutron.context': context.Context('', tenant_id)} env2 = {'neutron.context': context.Context('', project_id)}
res = self.api.get(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.get(_get_path('quotas', id=project_id, fmt=self.fmt),
extra_environ=env2) extra_environ=env2)
quota = self.deserialize(res) quota = self.deserialize(res)
self.assertEqual(100, quota['quota']['extra1']) self.assertEqual(100, quota['quota']['extra1'])
def test_delete_quotas_with_admin(self): def test_delete_quotas_with_admin(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id + '2', env = {'neutron.context': context.Context('', project_id + '2',
is_admin=True)} is_admin=True)}
# Create a quota to ensure we have something to delete # Create a quota to ensure we have something to delete
quotas = {'quota': {'network': 100}} quotas = {'quota': {'network': 100}}
self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt), self.api.put(_get_path('quotas', id=project_id, fmt=self.fmt),
self.serialize(quotas), extra_environ=env) self.serialize(quotas), extra_environ=env)
res = self.api.delete(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.delete(_get_path('quotas', id=project_id, fmt=self.fmt),
extra_environ=env) extra_environ=env)
self.assertEqual(204, res.status_int) self.assertEqual(204, res.status_int)
def test_delete_quotas_without_admin_forbidden_returns_403(self): def test_delete_quotas_without_admin_forbidden_returns_403(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=False)} is_admin=False)}
res = self.api.delete(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.delete(_get_path('quotas', id=project_id, fmt=self.fmt),
extra_environ=env, expect_errors=True) extra_environ=env, expect_errors=True)
self.assertEqual(403, res.status_int) self.assertEqual(403, res.status_int)
def test_delete_quota_with_unknown_tenant_returns_404(self): def test_delete_quota_with_unknown_project_returns_404(self):
tenant_id = 'idnotexist' project_id = 'idnotexist'
env = {'neutron.context': context.Context('', tenant_id + '2', env = {'neutron.context': context.Context('', project_id + '2',
is_admin=True)} is_admin=True)}
res = self.api.delete(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.delete(_get_path('quotas', id=project_id, fmt=self.fmt),
extra_environ=env, expect_errors=True) extra_environ=env, expect_errors=True)
self.assertEqual(exc.HTTPNotFound.code, res.status_int) self.assertEqual(exc.HTTPNotFound.code, res.status_int)
@ -353,44 +353,48 @@ class QuotaExtensionDbTestCase(QuotaExtensionTestCase):
pass pass
def test_quotas_limit_check(self): def test_quotas_limit_check(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=True)} is_admin=True)}
quotas = {'quota': {'network': 5}} quotas = {'quota': {'network': 5}}
res = self.api.put(_get_path('quotas', id=tenant_id, res = self.api.put(_get_path('quotas', id=project_id,
fmt=self.fmt), fmt=self.fmt),
self.serialize(quotas), extra_environ=env) self.serialize(quotas), extra_environ=env)
self.assertEqual(200, res.status_int) self.assertEqual(200, res.status_int)
quota.QUOTAS.limit_check(context.Context('', tenant_id), quota.QUOTAS.limit_check(context.Context('', project_id),
tenant_id, project_id,
network=4) network=4)
def test_quotas_limit_check_with_invalid_quota_value(self): def test_quotas_limit_check_with_invalid_quota_value(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
with testtools.ExpectedException(exceptions.InvalidQuotaValue): with testtools.ExpectedException(exceptions.InvalidQuotaValue):
quota.QUOTAS.limit_check(context.Context('', tenant_id), quota.QUOTAS.limit_check(context.Context('', project_id),
tenant_id, project_id,
network=-2) network=-2)
def test_quotas_limit_check_with_not_registered_resource_fails(self): def test_quotas_limit_check_with_not_registered_resource_fails(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
self.assertRaises(exceptions.QuotaResourceUnknown, self.assertRaises(exceptions.QuotaResourceUnknown,
quota.QUOTAS.limit_check, quota.QUOTAS.limit_check,
context.get_admin_context(), context.get_admin_context(),
tenant_id, project_id,
foobar=1) foobar=1)
def test_quotas_get_tenant_from_request_context(self): def test_quotas_get_project_from_request_context(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=True)} is_admin=True)}
res = self.api.get(_get_path('quotas/tenant', fmt=self.fmt), # NOTE(ralonsoh): the Quota API keeps "tenant" and "project" methods
# for compatibility. "tenant" is already deprecated and will be
# removed.
for key in ('project', 'tenant'):
res = self.api.get(_get_path('quotas/' + key, fmt=self.fmt),
extra_environ=env) extra_environ=env)
self.assertEqual(200, res.status_int) self.assertEqual(200, res.status_int)
quota = self.deserialize(res) quota = self.deserialize(res)
self.assertEqual(quota['tenant']['tenant_id'], tenant_id) self.assertEqual(quota[key][key + '_id'], project_id)
def test_quotas_get_tenant_from_empty_request_context_returns_400(self): def test_quotas_get_project_from_empty_request_context_returns_400(self):
env = {'neutron.context': context.Context('', '', env = {'neutron.context': context.Context('', '',
is_admin=True)} is_admin=True)}
res = self.api.get(_get_path('quotas/tenant', fmt=self.fmt), res = self.api.get(_get_path('quotas/tenant', fmt=self.fmt),
@ -398,20 +402,20 @@ class QuotaExtensionDbTestCase(QuotaExtensionTestCase):
self.assertEqual(400, res.status_int) self.assertEqual(400, res.status_int)
def test_make_reservation_resource_unknown_raises(self): def test_make_reservation_resource_unknown_raises(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
self.assertRaises(exceptions.QuotaResourceUnknown, self.assertRaises(exceptions.QuotaResourceUnknown,
quota.QUOTAS.make_reservation, quota.QUOTAS.make_reservation,
context.get_admin_context(), context.get_admin_context(),
tenant_id, project_id,
{'foobar': 1}, {'foobar': 1},
plugin=None) plugin=None)
def test_make_reservation_negative_delta_raises(self): def test_make_reservation_negative_delta_raises(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
self.assertRaises(exceptions.InvalidQuotaValue, self.assertRaises(exceptions.InvalidQuotaValue,
quota.QUOTAS.make_reservation, quota.QUOTAS.make_reservation,
context.get_admin_context(), context.get_admin_context(),
tenant_id, project_id,
{'network': -1}, {'network': -1},
plugin=None) plugin=None)
@ -441,34 +445,34 @@ class QuotaExtensionCfgTestCase(QuotaExtensionTestCase):
'extra1': qconf.DEFAULT_QUOTA}) 'extra1': qconf.DEFAULT_QUOTA})
def test_show_quotas_with_admin(self): def test_show_quotas_with_admin(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id + '2', env = {'neutron.context': context.Context('', project_id + '2',
is_admin=True)} is_admin=True)}
res = self.api.get(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.get(_get_path('quotas', id=project_id, fmt=self.fmt),
extra_environ=env) extra_environ=env)
self.assertEqual(200, res.status_int) self.assertEqual(200, res.status_int)
def test_show_quotas_without_admin_forbidden(self): def test_show_quotas_without_admin_forbidden(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id + '2', env = {'neutron.context': context.Context('', project_id + '2',
is_admin=False)} is_admin=False)}
res = self.api.get(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.get(_get_path('quotas', id=project_id, fmt=self.fmt),
extra_environ=env, expect_errors=True) extra_environ=env, expect_errors=True)
self.assertEqual(403, res.status_int) self.assertEqual(403, res.status_int)
def test_update_quotas_forbidden(self): def test_update_quotas_forbidden(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
quotas = {'quota': {'network': 100}} quotas = {'quota': {'network': 100}}
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.put(_get_path('quotas', id=project_id, fmt=self.fmt),
self.serialize(quotas), self.serialize(quotas),
expect_errors=True) expect_errors=True)
self.assertEqual(200, res.status_int) self.assertEqual(200, res.status_int)
def test_delete_quotas_forbidden(self): def test_delete_quotas_forbidden(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=False)} is_admin=False)}
res = self.api.delete(_get_path('quotas', id=tenant_id, fmt=self.fmt), res = self.api.delete(_get_path('quotas', id=project_id, fmt=self.fmt),
extra_environ=env, expect_errors=True) extra_environ=env, expect_errors=True)
self.assertEqual(403, res.status_int) self.assertEqual(403, res.status_int)
@ -476,7 +480,7 @@ class QuotaExtensionCfgTestCase(QuotaExtensionTestCase):
class TestDbQuotaDriver(base.BaseTestCase): class TestDbQuotaDriver(base.BaseTestCase):
"""Test for neutron.db.quota.driver.DbQuotaDriver.""" """Test for neutron.db.quota.driver.DbQuotaDriver."""
def test_get_tenant_quotas_arg(self): def test_get_project_quotas_arg(self):
"""Call neutron.db.quota.driver.DbQuotaDriver._get_quotas.""" """Call neutron.db.quota.driver.DbQuotaDriver._get_quotas."""
quota_driver = driver.DbQuotaDriver() quota_driver = driver.DbQuotaDriver()
@ -484,20 +488,20 @@ class TestDbQuotaDriver(base.BaseTestCase):
foo_quotas = {'network': 5} foo_quotas = {'network': 5}
default_quotas = {'network': 10} default_quotas = {'network': 10}
target_tenant = 'foo' target_project = 'foo'
with mock.patch.object(driver.DbQuotaDriver, with mock.patch.object(driver.DbQuotaDriver,
'get_tenant_quotas', 'get_project_quotas',
return_value=foo_quotas) as get_tenant_quotas: return_value=foo_quotas) as get_project_quotas:
quotas = quota_driver._get_quotas(ctx, quotas = quota_driver._get_quotas(ctx,
target_tenant, target_project,
default_quotas) default_quotas)
self.assertEqual(quotas, foo_quotas) self.assertEqual(quotas, foo_quotas)
get_tenant_quotas.assert_called_once_with(ctx, get_project_quotas.assert_called_once_with(ctx,
default_quotas, default_quotas,
target_tenant) target_project)
class TestQuotaDriverLoad(base.BaseTestCase): class TestQuotaDriverLoad(base.BaseTestCase):

View File

@ -67,9 +67,9 @@ class DetailQuotaExtensionDbTestCase(DetailQuotaExtensionTestCase):
fmt = 'json' fmt = 'json'
def test_show_detail_quotas(self): def test_show_detail_quotas(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id)} env = {'neutron.context': context.Context('', project_id)}
res = self.api.get(_get_path('quotas', id=tenant_id, res = self.api.get(_get_path('quotas', id=project_id,
fmt=self.fmt, fmt=self.fmt,
endpoint=DEFAULT_QUOTAS_ACTION), endpoint=DEFAULT_QUOTAS_ACTION),
extra_environ=env) extra_environ=env)
@ -95,10 +95,10 @@ class DetailQuotaExtensionDbTestCase(DetailQuotaExtensionTestCase):
'quota_network', -10, group='QUOTAS') 'quota_network', -10, group='QUOTAS')
cfg.CONF.set_override( cfg.CONF.set_override(
'quota_subnet', -50, group='QUOTAS') 'quota_subnet', -50, group='QUOTAS')
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id, env = {'neutron.context': context.Context('', project_id,
is_admin=True)} is_admin=True)}
res = self.api.get(_get_path('quotas', id=tenant_id, res = self.api.get(_get_path('quotas', id=project_id,
fmt=self.fmt, fmt=self.fmt,
endpoint=DEFAULT_QUOTAS_ACTION), endpoint=DEFAULT_QUOTAS_ACTION),
extra_environ=env) extra_environ=env)
@ -118,10 +118,10 @@ class DetailQuotaExtensionDbTestCase(DetailQuotaExtensionTestCase):
quota['quota']['port']['limit']) quota['quota']['port']['limit'])
def test_show_detail_quotas_with_admin(self): def test_show_detail_quotas_with_admin(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id + '2', env = {'neutron.context': context.Context('', project_id + '2',
is_admin=True)} is_admin=True)}
res = self.api.get(_get_path('quotas', id=tenant_id, res = self.api.get(_get_path('quotas', id=project_id,
fmt=self.fmt, fmt=self.fmt,
endpoint=DEFAULT_QUOTAS_ACTION), endpoint=DEFAULT_QUOTAS_ACTION),
extra_environ=env) extra_environ=env)
@ -141,10 +141,10 @@ class DetailQuotaExtensionDbTestCase(DetailQuotaExtensionTestCase):
quota['quota']['port']['limit']) quota['quota']['port']['limit'])
def test_detail_quotas_without_admin_forbidden_returns_403(self): def test_detail_quotas_without_admin_forbidden_returns_403(self):
tenant_id = 'tenant_id1' project_id = 'project_id1'
env = {'neutron.context': context.Context('', tenant_id + '2', env = {'neutron.context': context.Context('', project_id + '2',
is_admin=False)} is_admin=False)}
res = self.api.get(_get_path('quotas', id=tenant_id, res = self.api.get(_get_path('quotas', id=project_id,
fmt=self.fmt, fmt=self.fmt,
endpoint=DEFAULT_QUOTAS_ACTION), endpoint=DEFAULT_QUOTAS_ACTION),
extra_environ=env, expect_errors=True) extra_environ=env, expect_errors=True)

View File

@ -45,7 +45,9 @@ class BaseTestTrackedResources(test_plugin.Ml2PluginV2TestCase,
test_db_base_plugin_v2.NeutronDbPluginV2TestCase.quota_db_driver = ( test_db_base_plugin_v2.NeutronDbPluginV2TestCase.quota_db_driver = (
'neutron.db.quota.driver.DbQuotaDriver') 'neutron.db.quota.driver.DbQuotaDriver')
super(BaseTestTrackedResources, self).setUp() super(BaseTestTrackedResources, self).setUp()
self._tenant_id = uuidutils.generate_uuid() self._project_id = uuidutils.generate_uuid()
# TODO(ralonsoh): "tenant_id" reference should be removed.
self._tenant_id = self._project_id
@staticmethod @staticmethod
def _cleanup(): def _cleanup():
@ -54,7 +56,7 @@ class BaseTestTrackedResources(test_plugin.Ml2PluginV2TestCase,
def _test_init(self, resource_name): def _test_init(self, resource_name):
quota_db_api.set_quota_usage( quota_db_api.set_quota_usage(
self.ctx, resource_name, self._tenant_id) self.ctx, resource_name, self._project_id)
class BaseTestEventHandler(object): class BaseTestEventHandler(object):
@ -88,7 +90,7 @@ class BaseTestEventHandler(object):
if item: if item:
model = self.handler_mock.call_args_list[call_idx][0][-1] model = self.handler_mock.call_args_list[call_idx][0][-1]
self.assertEqual(model['id'], item['id']) self.assertEqual(model['id'], item['id'])
self.assertEqual(model['tenant_id'], item['tenant_id']) self.assertEqual(model['project_id'], item['project_id'])
call_idx = call_idx - 1 call_idx = call_idx - 1
@ -140,7 +142,7 @@ class TestTrackedResourcesEventHandler(BaseTestEventHandler,
self._test_init('subnetpool') self._test_init('subnetpool')
pool = self._make_subnetpool('json', ['10.0.0.0/8'], pool = self._make_subnetpool('json', ['10.0.0.0/8'],
name='meh', name='meh',
tenant_id=self._tenant_id)['subnetpool'] tenant_id=self._project_id)['subnetpool']
self._verify_event_handler_calls(pool) self._verify_event_handler_calls(pool)
self._delete('subnetpools', pool['id']) self._delete('subnetpools', pool['id'])
self._verify_event_handler_calls(pool, expected_call_count=2) self._verify_event_handler_calls(pool, expected_call_count=2)
@ -148,7 +150,8 @@ class TestTrackedResourcesEventHandler(BaseTestEventHandler,
def test_create_delete_securitygroup_triggers_event(self): def test_create_delete_securitygroup_triggers_event(self):
self._test_init('security_group') self._test_init('security_group')
sec_group = self._make_security_group( sec_group = self._make_security_group(
'json', 'meh', 'meh', tenant_id=self._tenant_id)['security_group'] 'json', 'meh', 'meh',
project_id=self._project_id)['security_group']
# When a security group is created it also creates 2 rules, therefore # When a security group is created it also creates 2 rules, therefore
# there will be three calls and we need to verify the first # there will be three calls and we need to verify the first
self._verify_event_handler_calls([None, None, sec_group], self._verify_event_handler_calls([None, None, sec_group],
@ -161,9 +164,10 @@ class TestTrackedResourcesEventHandler(BaseTestEventHandler,
def test_create_delete_securitygrouprule_triggers_event(self): def test_create_delete_securitygrouprule_triggers_event(self):
self._test_init('security_group_rule') self._test_init('security_group_rule')
sec_group = self._make_security_group( sec_group = self._make_security_group(
'json', 'meh', 'meh', tenant_id=self._tenant_id)['security_group'] 'json', 'meh', 'meh',
project_id=self._project_id)['security_group']
rule_req = self._build_security_group_rule( rule_req = self._build_security_group_rule(
sec_group['id'], 'ingress', 'TCP', tenant_id=self._tenant_id) sec_group['id'], 'ingress', 'TCP', tenant_id=self._project_id)
sec_group_rule = self._make_security_group_rule( sec_group_rule = self._make_security_group_rule(
'json', rule_req)['security_group_rule'] 'json', rule_req)['security_group_rule']
# When a security group is created it also creates 2 rules, therefore # When a security group is created it also creates 2 rules, therefore
@ -213,8 +217,8 @@ class TestL3ResourcesEventHandler(BaseTestEventHandler,
class TestTrackedResources(BaseTestTrackedResources): class TestTrackedResources(BaseTestTrackedResources):
def _verify_dirty_bit(self, resource_name, expected_value=True): def _verify_dirty_bit(self, resource_name, expected_value=True):
usage = quota_db_api.get_quota_usage_by_resource_and_tenant( usage = quota_db_api.get_quota_usage_by_resource_and_project(
self.ctx, resource_name, self._tenant_id) self.ctx, resource_name, self._project_id)
self.assertEqual(expected_value, usage.dirty) self.assertEqual(expected_value, usage.dirty)
def test_create_delete_network_marks_dirty(self): def test_create_delete_network_marks_dirty(self):
@ -223,14 +227,14 @@ class TestTrackedResources(BaseTestTrackedResources):
self._verify_dirty_bit('network') self._verify_dirty_bit('network')
# Clear the dirty bit # Clear the dirty bit
quota_db_api.set_quota_usage_dirty( quota_db_api.set_quota_usage_dirty(
self.ctx, 'network', self._tenant_id, dirty=False) self.ctx, 'network', self._project_id, dirty=False)
self._delete('networks', net['id']) self._delete('networks', net['id'])
self._verify_dirty_bit('network') self._verify_dirty_bit('network')
def test_list_networks_clears_dirty(self): def test_list_networks_clears_dirty(self):
self._test_init('network') self._test_init('network')
net = self._make_network('json', 'meh', True)['network'] net = self._make_network('json', 'meh', True)['network']
self.ctx.tenant_id = net['tenant_id'] self.ctx.project_id = net['project_id']
self._list('networks', neutron_context=self.ctx) self._list('networks', neutron_context=self.ctx)
self._verify_dirty_bit('network', expected_value=False) self._verify_dirty_bit('network', expected_value=False)
@ -241,7 +245,7 @@ class TestTrackedResources(BaseTestTrackedResources):
self._verify_dirty_bit('port') self._verify_dirty_bit('port')
# Clear the dirty bit # Clear the dirty bit
quota_db_api.set_quota_usage_dirty( quota_db_api.set_quota_usage_dirty(
self.ctx, 'port', self._tenant_id, dirty=False) self.ctx, 'port', self._project_id, dirty=False)
self._delete('ports', port['id']) self._delete('ports', port['id'])
self._verify_dirty_bit('port') self._verify_dirty_bit('port')
@ -249,7 +253,7 @@ class TestTrackedResources(BaseTestTrackedResources):
self._test_init('port') self._test_init('port')
net = self._make_network('json', 'meh', True)['network'] net = self._make_network('json', 'meh', True)['network']
port = self._make_port('json', net['id'])['port'] port = self._make_port('json', net['id'])['port']
self.ctx.tenant_id = port['tenant_id'] self.ctx.project_id = port['project_id']
self._list('ports', neutron_context=self.ctx) self._list('ports', neutron_context=self.ctx)
self._verify_dirty_bit('port', expected_value=False) self._verify_dirty_bit('port', expected_value=False)
@ -261,7 +265,7 @@ class TestTrackedResources(BaseTestTrackedResources):
self._verify_dirty_bit('subnet') self._verify_dirty_bit('subnet')
# Clear the dirty bit # Clear the dirty bit
quota_db_api.set_quota_usage_dirty( quota_db_api.set_quota_usage_dirty(
self.ctx, 'subnet', self._tenant_id, dirty=False) self.ctx, 'subnet', self._project_id, dirty=False)
self._delete('subnets', subnet['id']) self._delete('subnets', subnet['id'])
self._verify_dirty_bit('subnet') self._verify_dirty_bit('subnet')
@ -274,7 +278,7 @@ class TestTrackedResources(BaseTestTrackedResources):
self._verify_dirty_bit('subnet') self._verify_dirty_bit('subnet')
# Clear the dirty bit # Clear the dirty bit
quota_db_api.set_quota_usage_dirty( quota_db_api.set_quota_usage_dirty(
self.ctx, 'subnet', self._tenant_id, dirty=False) self.ctx, 'subnet', self._project_id, dirty=False)
self._delete('networks', net['network']['id']) self._delete('networks', net['network']['id'])
self._verify_dirty_bit('network') self._verify_dirty_bit('network')
self._verify_dirty_bit('subnet') self._verify_dirty_bit('subnet')
@ -284,7 +288,7 @@ class TestTrackedResources(BaseTestTrackedResources):
net = self._make_network('json', 'meh', True) net = self._make_network('json', 'meh', True)
subnet = self._make_subnet('json', net, '10.0.0.1', subnet = self._make_subnet('json', net, '10.0.0.1',
'10.0.0.0/24')['subnet'] '10.0.0.0/24')['subnet']
self.ctx.tenant_id = subnet['tenant_id'] self.ctx.project_id = subnet['project_id']
self._list('subnets', neutron_context=self.ctx) self._list('subnets', neutron_context=self.ctx)
self._verify_dirty_bit('subnet', expected_value=False) self._verify_dirty_bit('subnet', expected_value=False)
@ -292,11 +296,11 @@ class TestTrackedResources(BaseTestTrackedResources):
self._test_init('subnetpool') self._test_init('subnetpool')
pool = self._make_subnetpool('json', ['10.0.0.0/8'], pool = self._make_subnetpool('json', ['10.0.0.0/8'],
name='meh', name='meh',
tenant_id=self._tenant_id)['subnetpool'] tenant_id=self._project_id)['subnetpool']
self._verify_dirty_bit('subnetpool') self._verify_dirty_bit('subnetpool')
# Clear the dirty bit # Clear the dirty bit
quota_db_api.set_quota_usage_dirty( quota_db_api.set_quota_usage_dirty(
self.ctx, 'subnetpool', self._tenant_id, dirty=False) self.ctx, 'subnetpool', self._project_id, dirty=False)
self._delete('subnetpools', pool['id']) self._delete('subnetpools', pool['id'])
self._verify_dirty_bit('subnetpool') self._verify_dirty_bit('subnetpool')
@ -304,51 +308,51 @@ class TestTrackedResources(BaseTestTrackedResources):
self._test_init('subnetpool') self._test_init('subnetpool')
pool = self._make_subnetpool('json', ['10.0.0.0/8'], pool = self._make_subnetpool('json', ['10.0.0.0/8'],
name='meh', name='meh',
tenant_id=self._tenant_id)['subnetpool'] tenant_id=self._project_id)['subnetpool']
self.ctx.tenant_id = pool['tenant_id'] self.ctx.project_id = pool['project_id']
self._list('subnetpools', neutron_context=self.ctx) self._list('subnetpools', neutron_context=self.ctx)
self._verify_dirty_bit('subnetpool', expected_value=False) self._verify_dirty_bit('subnetpool', expected_value=False)
def test_create_delete_securitygroup_marks_dirty(self): def test_create_delete_securitygroup_marks_dirty(self):
self._test_init('security_group') self._test_init('security_group')
sec_group = self._make_security_group( sec_group = self._make_security_group(
'json', 'meh', 'meh', tenant_id=self._tenant_id)['security_group'] 'json', 'meh', 'meh', tenant_id=self._project_id)['security_group']
self._verify_dirty_bit('security_group') self._verify_dirty_bit('security_group')
# Clear the dirty bit # Clear the dirty bit
quota_db_api.set_quota_usage_dirty( quota_db_api.set_quota_usage_dirty(
self.ctx, 'security_group', self._tenant_id, dirty=False) self.ctx, 'security_group', self._project_id, dirty=False)
self._delete('security-groups', sec_group['id']) self._delete('security-groups', sec_group['id'])
self._verify_dirty_bit('security_group') self._verify_dirty_bit('security_group')
def test_list_securitygroups_clears_dirty(self): def test_list_securitygroups_clears_dirty(self):
self._test_init('security_group') self._test_init('security_group')
self._make_security_group( self._make_security_group(
'json', 'meh', 'meh', tenant_id=self._tenant_id)['security_group'] 'json', 'meh', 'meh', tenant_id=self._project_id)['security_group']
self.ctx.tenant_id = self._tenant_id self.ctx.project_id = self._project_id
self._list('security-groups', neutron_context=self.ctx) self._list('security-groups', neutron_context=self.ctx)
self._verify_dirty_bit('security_group', expected_value=False) self._verify_dirty_bit('security_group', expected_value=False)
def test_create_delete_securitygrouprule_marks_dirty(self): def test_create_delete_securitygrouprule_marks_dirty(self):
self._test_init('security_group_rule') self._test_init('security_group_rule')
sec_group = self._make_security_group( sec_group = self._make_security_group(
'json', 'meh', 'meh', tenant_id=self._tenant_id)['security_group'] 'json', 'meh', 'meh', tenant_id=self._project_id)['security_group']
rule_req = self._build_security_group_rule( rule_req = self._build_security_group_rule(
sec_group['id'], 'ingress', 'TCP', tenant_id=self._tenant_id) sec_group['id'], 'ingress', 'TCP', tenant_id=self._project_id)
sec_group_rule = self._make_security_group_rule( sec_group_rule = self._make_security_group_rule(
'json', rule_req)['security_group_rule'] 'json', rule_req)['security_group_rule']
self._verify_dirty_bit('security_group_rule') self._verify_dirty_bit('security_group_rule')
# Clear the dirty bit # Clear the dirty bit
quota_db_api.set_quota_usage_dirty( quota_db_api.set_quota_usage_dirty(
self.ctx, 'security_group_rule', self._tenant_id, dirty=False) self.ctx, 'security_group_rule', self._project_id, dirty=False)
self._delete('security-group-rules', sec_group_rule['id']) self._delete('security-group-rules', sec_group_rule['id'])
self._verify_dirty_bit('security_group_rule') self._verify_dirty_bit('security_group_rule')
def test_list_securitygrouprules_clears_dirty(self): def test_list_securitygrouprules_clears_dirty(self):
self._test_init('security_group_rule') self._test_init('security_group_rule')
self._make_security_group( self._make_security_group(
'json', 'meh', 'meh', tenant_id=self._tenant_id)['security_group'] 'json', 'meh', 'meh', tenant_id=self._project_id)['security_group']
# As the security group create operation also creates 2 security group # As the security group create operation also creates 2 security group
# rules there is no need to explicitly create any rule # rules there is no need to explicitly create any rule
self.ctx.tenant_id = self._tenant_id self.ctx.project_id = self._project_id
self._list('security-group-rules', neutron_context=self.ctx) self._list('security-group-rules', neutron_context=self.ctx)
self._verify_dirty_bit('security_group_rule', expected_value=False) self._verify_dirty_bit('security_group_rule', expected_value=False)

View File

@ -75,22 +75,22 @@ class TestResource(base.DietTestCase):
class TestTrackedResource(testlib_api.SqlTestCase): class TestTrackedResource(testlib_api.SqlTestCase):
def _add_data(self, tenant_id=None): def _add_data(self, project_id=None):
session = db_api.get_writer_session() session = db_api.get_writer_session()
with session.begin(): with session.begin():
tenant_id = tenant_id or self.tenant_id project_id = project_id or self.project_id
session.add(test_quota.MehModel( session.add(test_quota.MehModel(
meh='meh_%s' % uuidutils.generate_uuid(), meh='meh_%s' % uuidutils.generate_uuid(),
tenant_id=tenant_id)) project_id=project_id))
session.add(test_quota.MehModel( session.add(test_quota.MehModel(
meh='meh_%s' % uuidutils.generate_uuid(), meh='meh_%s' % uuidutils.generate_uuid(),
tenant_id=tenant_id)) project_id=project_id))
def _delete_data(self): def _delete_data(self):
session = db_api.get_writer_session() session = db_api.get_writer_session()
with session.begin(): with session.begin():
query = session.query(test_quota.MehModel).filter_by( query = session.query(test_quota.MehModel).filter_by(
tenant_id=self.tenant_id) project_id=self.project_id)
for item in query: for item in query:
session.delete(item) session.delete(item)
@ -98,7 +98,7 @@ class TestTrackedResource(testlib_api.SqlTestCase):
session = db_api.get_writer_session() session = db_api.get_writer_session()
with session.begin(): with session.begin():
query = session.query(test_quota.MehModel).filter_by( query = session.query(test_quota.MehModel).filter_by(
tenant_id=self.tenant_id) project_id=self.project_id)
for item in query: for item in query:
item['meh'] = 'meh-%s' % item['meh'] item['meh'] = 'meh-%s' % item['meh']
session.add(item) session.add(item)
@ -109,9 +109,9 @@ class TestTrackedResource(testlib_api.SqlTestCase):
self.setup_coreplugin(DB_PLUGIN_KLASS) self.setup_coreplugin(DB_PLUGIN_KLASS)
self.resource = 'meh' self.resource = 'meh'
self.other_resource = 'othermeh' self.other_resource = 'othermeh'
self.tenant_id = 'meh' self.project_id = 'meh'
self.context = context.Context( self.context = context.Context(
user_id='', tenant_id=self.tenant_id, is_admin=False) user_id='', project_id=self.project_id, is_admin=False)
def _create_resource(self): def _create_resource(self):
res = resource.TrackedResource( res = resource.TrackedResource(
@ -133,7 +133,7 @@ class TestTrackedResource(testlib_api.SqlTestCase):
def test_count_first_call_with_dirty_false(self): def test_count_first_call_with_dirty_false(self):
quota_api.set_quota_usage( quota_api.set_quota_usage(
self.context, self.resource, self.tenant_id, in_use=1) self.context, self.resource, self.project_id, in_use=1)
res = self._create_resource() res = self._create_resource()
self._add_data() self._add_data()
# explicitly set dirty flag to False # explicitly set dirty flag to False
@ -141,17 +141,17 @@ class TestTrackedResource(testlib_api.SqlTestCase):
self.context, self.resource, dirty=False) self.context, self.resource, dirty=False)
# Expect correct count to be returned anyway since the first call to # Expect correct count to be returned anyway since the first call to
# count() always resyncs with the db # count() always resyncs with the db
self.assertEqual(2, res.count(self.context, None, self.tenant_id)) self.assertEqual(2, res.count(self.context, None, self.project_id))
def test_count_reserved(self): def test_count_reserved(self):
res = self._create_resource() res = self._create_resource()
quota_api.create_reservation(self.context, self.tenant_id, quota_api.create_reservation(self.context, self.project_id,
{res.name: 1}) {res.name: 1})
self.assertEqual(1, res.count_reserved(self.context, self.tenant_id)) self.assertEqual(1, res.count_reserved(self.context, self.project_id))
def test_count_used_first_call_with_dirty_false(self): def test_count_used_first_call_with_dirty_false(self):
quota_api.set_quota_usage( quota_api.set_quota_usage(
self.context, self.resource, self.tenant_id, in_use=1) self.context, self.resource, self.project_id, in_use=1)
res = self._create_resource() res = self._create_resource()
self._add_data() self._add_data()
# explicitly set dirty flag to False # explicitly set dirty flag to False
@ -160,18 +160,18 @@ class TestTrackedResource(testlib_api.SqlTestCase):
# Expect correct count_used to be returned # Expect correct count_used to be returned
# anyway since the first call to # anyway since the first call to
# count_used() always resyncs with the db # count_used() always resyncs with the db
self.assertEqual(2, res.count_used(self.context, self.tenant_id)) self.assertEqual(2, res.count_used(self.context, self.project_id))
def _test_count(self): def _test_count(self):
res = self._create_resource() res = self._create_resource()
quota_api.set_quota_usage( quota_api.set_quota_usage(
self.context, res.name, self.tenant_id, in_use=0) self.context, res.name, self.project_id, in_use=0)
self._add_data() self._add_data()
return res return res
def test_count_with_dirty_false(self): def test_count_with_dirty_false(self):
res = self._test_count() res = self._test_count()
res.count(self.context, None, self.tenant_id) res.count(self.context, None, self.project_id)
# At this stage count has been invoked, and the dirty flag should be # At this stage count has been invoked, and the dirty flag should be
# false. Another invocation of count should not query the model class # false. Another invocation of count should not query the model class
set_quota = 'neutron.db.quota.api.set_quota_usage' set_quota = 'neutron.db.quota.api.set_quota_usage'
@ -179,11 +179,11 @@ class TestTrackedResource(testlib_api.SqlTestCase):
self.assertEqual(0, mock_set_quota.call_count) self.assertEqual(0, mock_set_quota.call_count)
self.assertEqual(2, res.count(self.context, self.assertEqual(2, res.count(self.context,
None, None,
self.tenant_id)) self.project_id))
def test_count_used_with_dirty_false(self): def test_count_used_with_dirty_false(self):
res = self._test_count() res = self._test_count()
res.count_used(self.context, self.tenant_id) res.count_used(self.context, self.project_id)
# At this stage count_used has been invoked, # At this stage count_used has been invoked,
# and the dirty flag should be false. Another invocation # and the dirty flag should be false. Another invocation
# of count_used should not query the model class # of count_used should not query the model class
@ -191,7 +191,7 @@ class TestTrackedResource(testlib_api.SqlTestCase):
with mock.patch(set_quota) as mock_set_quota: with mock.patch(set_quota) as mock_set_quota:
self.assertEqual(0, mock_set_quota.call_count) self.assertEqual(0, mock_set_quota.call_count)
self.assertEqual(2, res.count_used(self.context, self.assertEqual(2, res.count_used(self.context,
self.tenant_id)) self.project_id))
def test_count_with_dirty_true_resync(self): def test_count_with_dirty_true_resync(self):
res = self._test_count() res = self._test_count()
@ -199,7 +199,7 @@ class TestTrackedResource(testlib_api.SqlTestCase):
# set_quota_usage has been invoked with the correct parameters # set_quota_usage has been invoked with the correct parameters
self.assertEqual(2, res.count(self.context, self.assertEqual(2, res.count(self.context,
None, None,
self.tenant_id, self.project_id,
resync_usage=True)) resync_usage=True))
def test_count_used_with_dirty_true_resync(self): def test_count_used_with_dirty_true_resync(self):
@ -207,7 +207,7 @@ class TestTrackedResource(testlib_api.SqlTestCase):
# Expect correct count_used to be returned, which also implies # Expect correct count_used to be returned, which also implies
# set_quota_usage has been invoked with the correct parameters # set_quota_usage has been invoked with the correct parameters
self.assertEqual(2, res.count_used(self.context, self.assertEqual(2, res.count_used(self.context,
self.tenant_id, self.project_id,
resync_usage=True)) resync_usage=True))
def test_count_with_dirty_true_resync_calls_set_quota_usage(self): def test_count_with_dirty_true_resync_calls_set_quota_usage(self):
@ -216,11 +216,11 @@ class TestTrackedResource(testlib_api.SqlTestCase):
with mock.patch(set_quota_usage) as mock_set_quota_usage: with mock.patch(set_quota_usage) as mock_set_quota_usage:
quota_api.set_quota_usage_dirty(self.context, quota_api.set_quota_usage_dirty(self.context,
self.resource, self.resource,
self.tenant_id) self.project_id)
res.count(self.context, None, self.tenant_id, res.count(self.context, None, self.project_id,
resync_usage=True) resync_usage=True)
mock_set_quota_usage.assert_called_once_with( mock_set_quota_usage.assert_called_once_with(
self.context, self.resource, self.tenant_id, in_use=2) self.context, self.resource, self.project_id, in_use=2)
def test_count_used_with_dirty_true_resync_calls_set_quota_usage(self): def test_count_used_with_dirty_true_resync_calls_set_quota_usage(self):
res = self._test_count() res = self._test_count()
@ -228,25 +228,25 @@ class TestTrackedResource(testlib_api.SqlTestCase):
with mock.patch(set_quota_usage) as mock_set_quota_usage: with mock.patch(set_quota_usage) as mock_set_quota_usage:
quota_api.set_quota_usage_dirty(self.context, quota_api.set_quota_usage_dirty(self.context,
self.resource, self.resource,
self.tenant_id) self.project_id)
res.count_used(self.context, self.tenant_id, res.count_used(self.context, self.project_id,
resync_usage=True) resync_usage=True)
mock_set_quota_usage.assert_called_once_with( mock_set_quota_usage.assert_called_once_with(
self.context, self.resource, self.tenant_id, in_use=2) self.context, self.resource, self.project_id, in_use=2)
def test_count_with_dirty_true_no_usage_info(self): def test_count_with_dirty_true_no_usage_info(self):
res = self._create_resource() res = self._create_resource()
self._add_data() self._add_data()
# Invoke count without having usage info in DB - Expect correct # Invoke count without having usage info in DB - Expect correct
# count to be returned # count to be returned
self.assertEqual(2, res.count(self.context, None, self.tenant_id)) self.assertEqual(2, res.count(self.context, None, self.project_id))
def test_count_used_with_dirty_true_no_usage_info(self): def test_count_used_with_dirty_true_no_usage_info(self):
res = self._create_resource() res = self._create_resource()
self._add_data() self._add_data()
# Invoke count_used without having usage info in DB - Expect correct # Invoke count_used without having usage info in DB - Expect correct
# count_used to be returned # count_used to be returned
self.assertEqual(2, res.count_used(self.context, self.tenant_id)) self.assertEqual(2, res.count_used(self.context, self.project_id))
def test_count_with_dirty_true_no_usage_info_calls_set_quota_usage(self): def test_count_with_dirty_true_no_usage_info_calls_set_quota_usage(self):
res = self._create_resource() res = self._create_resource()
@ -255,10 +255,10 @@ class TestTrackedResource(testlib_api.SqlTestCase):
with mock.patch(set_quota_usage) as mock_set_quota_usage: with mock.patch(set_quota_usage) as mock_set_quota_usage:
quota_api.set_quota_usage_dirty(self.context, quota_api.set_quota_usage_dirty(self.context,
self.resource, self.resource,
self.tenant_id) self.project_id)
res.count(self.context, None, self.tenant_id, resync_usage=True) res.count(self.context, None, self.project_id, resync_usage=True)
mock_set_quota_usage.assert_called_once_with( mock_set_quota_usage.assert_called_once_with(
self.context, self.resource, self.tenant_id, in_use=2) self.context, self.resource, self.project_id, in_use=2)
def test_count_used_with_dirty_true_no_usage_info_calls_set_quota_usage( def test_count_used_with_dirty_true_no_usage_info_calls_set_quota_usage(
self): self):
@ -268,44 +268,44 @@ class TestTrackedResource(testlib_api.SqlTestCase):
with mock.patch(set_quota_usage) as mock_set_quota_usage: with mock.patch(set_quota_usage) as mock_set_quota_usage:
quota_api.set_quota_usage_dirty(self.context, quota_api.set_quota_usage_dirty(self.context,
self.resource, self.resource,
self.tenant_id) self.project_id)
res.count_used(self.context, self.tenant_id, resync_usage=True) res.count_used(self.context, self.project_id, resync_usage=True)
mock_set_quota_usage.assert_called_once_with( mock_set_quota_usage.assert_called_once_with(
self.context, self.resource, self.tenant_id, in_use=2) self.context, self.resource, self.project_id, in_use=2)
def test_add_delete_data_triggers_event(self): def test_add_delete_data_triggers_event(self):
res = self._create_resource() res = self._create_resource()
other_res = self._create_other_resource() other_res = self._create_other_resource()
# Validate dirty tenants since mock does not work well with SQLAlchemy # Validate dirty projects since mock does not work well with SQLAlchemy
# event handlers. # event handlers.
self._add_data() self._add_data()
self._add_data('someone_else') self._add_data('someone_else')
self.assertEqual(2, len(res._dirty_tenants)) self.assertEqual(2, len(res._dirty_projects))
# Also, the dirty flag should not be set for other resources # Also, the dirty flag should not be set for other resources
self.assertEqual(0, len(other_res._dirty_tenants)) self.assertEqual(0, len(other_res._dirty_projects))
self.assertIn(self.tenant_id, res._dirty_tenants) self.assertIn(self.project_id, res._dirty_projects)
self.assertIn('someone_else', res._dirty_tenants) self.assertIn('someone_else', res._dirty_projects)
def test_delete_data_triggers_event(self): def test_delete_data_triggers_event(self):
res = self._create_resource() res = self._create_resource()
self._add_data() self._add_data()
self._add_data('someone_else') self._add_data('someone_else')
# Artificially clear _dirty_tenants # Artificially clear _dirty_projects
res._dirty_tenants.clear() res._dirty_projects.clear()
self._delete_data() self._delete_data()
# We did not delete "someone_else", so expect only a single dirty # We did not delete "someone_else", so expect only a single dirty
# tenant # project
self.assertEqual(1, len(res._dirty_tenants)) self.assertEqual(1, len(res._dirty_projects))
self.assertIn(self.tenant_id, res._dirty_tenants) self.assertIn(self.project_id, res._dirty_projects)
def test_update_does_not_trigger_event(self): def test_update_does_not_trigger_event(self):
res = self._create_resource() res = self._create_resource()
self._add_data() self._add_data()
self._add_data('someone_else') self._add_data('someone_else')
# Artificially clear _dirty_tenants # Artificially clear _dirty_projects
res._dirty_tenants.clear() res._dirty_projects.clear()
self._update_data() self._update_data()
self.assertEqual(0, len(res._dirty_tenants)) self.assertEqual(0, len(res._dirty_projects))
def test_mark_dirty(self): def test_mark_dirty(self):
res = self._create_resource() res = self._create_resource()
@ -316,11 +316,11 @@ class TestTrackedResource(testlib_api.SqlTestCase):
res.mark_dirty(self.context) res.mark_dirty(self.context)
self.assertEqual(2, mock_set_quota_usage.call_count) self.assertEqual(2, mock_set_quota_usage.call_count)
mock_set_quota_usage.assert_any_call( mock_set_quota_usage.assert_any_call(
self.context, self.resource, self.tenant_id) self.context, self.resource, self.project_id)
mock_set_quota_usage.assert_any_call( mock_set_quota_usage.assert_any_call(
self.context, self.resource, 'someone_else') self.context, self.resource, 'someone_else')
def test_mark_dirty_no_dirty_tenant(self): def test_mark_dirty_no_dirty_project(self):
res = self._create_resource() res = self._create_resource()
set_quota_usage = 'neutron.db.quota.api.set_quota_usage_dirty' set_quota_usage = 'neutron.db.quota.api.set_quota_usage_dirty'
with mock.patch(set_quota_usage) as mock_set_quota_usage: with mock.patch(set_quota_usage) as mock_set_quota_usage:
@ -331,14 +331,14 @@ class TestTrackedResource(testlib_api.SqlTestCase):
res = self._create_resource() res = self._create_resource()
self._add_data() self._add_data()
res.mark_dirty(self.context) res.mark_dirty(self.context)
# self.tenant_id now is out of sync # self.project_id now is out of sync
set_quota_usage = 'neutron.db.quota.api.set_quota_usage' set_quota_usage = 'neutron.db.quota.api.set_quota_usage'
with mock.patch(set_quota_usage) as mock_set_quota_usage: with mock.patch(set_quota_usage) as mock_set_quota_usage:
res.resync(self.context, self.tenant_id) res.resync(self.context, self.project_id)
# and now it should be in sync # and now it should be in sync
self.assertNotIn(self.tenant_id, res._out_of_sync_tenants) self.assertNotIn(self.project_id, res._out_of_sync_projects)
mock_set_quota_usage.assert_called_once_with( mock_set_quota_usage.assert_called_once_with(
self.context, self.resource, self.tenant_id, in_use=2) self.context, self.resource, self.project_id, in_use=2)
class Test_CountResource(base.BaseTestCase): class Test_CountResource(base.BaseTestCase):
@ -355,15 +355,15 @@ class Test_CountResource(base.BaseTestCase):
context = mock.Mock() context = mock.Mock()
collection_name = 'floatingips' collection_name = 'floatingips'
tenant_id = 'fakeid' project_id = 'fakeid'
self.assertRaises( self.assertRaises(
NotImplementedError, NotImplementedError,
resource._count_resource, context, collection_name, tenant_id) resource._count_resource, context, collection_name, project_id)
for plugin in plugins.values(): for plugin in plugins.values():
for func in (plugin.get_floatingips_count, plugin.get_floatingips): for func in (plugin.get_floatingips_count, plugin.get_floatingips):
func.assert_called_with( func.assert_called_with(
context, filters={'tenant_id': [tenant_id]}) context, filters={'project_id': [project_id]})
def test_core_plugin_checked_first(self): def test_core_plugin_checked_first(self):
plugin1 = mock.Mock() plugin1 = mock.Mock()
@ -378,6 +378,6 @@ class Test_CountResource(base.BaseTestCase):
context = mock.Mock() context = mock.Mock()
collection_name = 'floatingips' collection_name = 'floatingips'
tenant_id = 'fakeid' project_id = 'fakeid'
self.assertEqual( self.assertEqual(
10, resource._count_resource(context, collection_name, tenant_id)) 10, resource._count_resource(context, collection_name, project_id))

View File

@ -101,7 +101,7 @@ class TestAuxiliaryFunctions(base.DietTestCase):
'TrackedResource.resync') as mock_resync: 'TrackedResource.resync') as mock_resync:
self.registry.set_tracked_resource('meh', test_quota.MehModel) self.registry.set_tracked_resource('meh', test_quota.MehModel)
self.registry.register_resource_by_name('meh') self.registry.register_resource_by_name('meh')
resource_registry.resync_resource(mock.ANY, 'meh', 'tenant_id') resource_registry.resync_resource(mock.ANY, 'meh', 'project_id')
self.assertEqual(0, mock_resync.call_count) self.assertEqual(0, mock_resync.call_count)
def test_resync_tracked_resource(self): def test_resync_tracked_resource(self):
@ -109,14 +109,14 @@ class TestAuxiliaryFunctions(base.DietTestCase):
'TrackedResource.resync') as mock_resync: 'TrackedResource.resync') as mock_resync:
self.registry.set_tracked_resource('meh', test_quota.MehModel) self.registry.set_tracked_resource('meh', test_quota.MehModel)
self.registry.register_resource_by_name('meh') self.registry.register_resource_by_name('meh')
resource_registry.resync_resource(mock.ANY, 'meh', 'tenant_id') resource_registry.resync_resource(mock.ANY, 'meh', 'project_id')
mock_resync.assert_called_once_with(mock.ANY, 'tenant_id') mock_resync.assert_called_once_with(mock.ANY, 'project_id')
def test_resync_non_tracked_resource(self): def test_resync_non_tracked_resource(self):
with mock.patch('neutron.quota.resource.' with mock.patch('neutron.quota.resource.'
'TrackedResource.resync') as mock_resync: 'TrackedResource.resync') as mock_resync:
self.registry.register_resource_by_name('meh') self.registry.register_resource_by_name('meh')
resource_registry.resync_resource(mock.ANY, 'meh', 'tenant_id') resource_registry.resync_resource(mock.ANY, 'meh', 'project_id')
self.assertEqual(0, mock_resync.call_count) self.assertEqual(0, mock_resync.call_count)
def test_set_resources_dirty_invoked_with_tracking_disabled(self): def test_set_resources_dirty_invoked_with_tracking_disabled(self):
@ -132,7 +132,7 @@ class TestAuxiliaryFunctions(base.DietTestCase):
self.assertEqual(0, mock_mark_dirty.call_count) self.assertEqual(0, mock_mark_dirty.call_count)
def test_set_resources_dirty_no_dirty_resource(self): def test_set_resources_dirty_no_dirty_resource(self):
ctx = context.Context('user_id', 'tenant_id', ctx = context.Context('user_id', 'project_id',
is_admin=False, is_advsvc=False) is_admin=False, is_advsvc=False)
with mock.patch('neutron.quota.resource.' with mock.patch('neutron.quota.resource.'
'TrackedResource.mark_dirty') as mock_mark_dirty: 'TrackedResource.mark_dirty') as mock_mark_dirty:
@ -140,12 +140,12 @@ class TestAuxiliaryFunctions(base.DietTestCase):
self.registry.register_resource_by_name('meh') self.registry.register_resource_by_name('meh')
res = self.registry.get_resource('meh') res = self.registry.get_resource('meh')
# This ensures dirty is false # This ensures dirty is false
res._dirty_tenants.clear() res._dirty_projects.clear()
resource_registry.set_resources_dirty(ctx) resource_registry.set_resources_dirty(ctx)
self.assertEqual(0, mock_mark_dirty.call_count) self.assertEqual(0, mock_mark_dirty.call_count)
def test_set_resources_dirty_no_tracked_resource(self): def test_set_resources_dirty_no_tracked_resource(self):
ctx = context.Context('user_id', 'tenant_id', ctx = context.Context('user_id', 'project_id',
is_admin=False, is_advsvc=False) is_admin=False, is_advsvc=False)
with mock.patch('neutron.quota.resource.' with mock.patch('neutron.quota.resource.'
'TrackedResource.mark_dirty') as mock_mark_dirty: 'TrackedResource.mark_dirty') as mock_mark_dirty:
@ -154,7 +154,7 @@ class TestAuxiliaryFunctions(base.DietTestCase):
self.assertEqual(0, mock_mark_dirty.call_count) self.assertEqual(0, mock_mark_dirty.call_count)
def test_set_resources_dirty(self): def test_set_resources_dirty(self):
ctx = context.Context('user_id', 'tenant_id', ctx = context.Context('user_id', 'project_id',
is_admin=False, is_advsvc=False) is_admin=False, is_advsvc=False)
with mock.patch('neutron.quota.resource.' with mock.patch('neutron.quota.resource.'
'TrackedResource.mark_dirty') as mock_mark_dirty: 'TrackedResource.mark_dirty') as mock_mark_dirty:
@ -163,6 +163,6 @@ class TestAuxiliaryFunctions(base.DietTestCase):
self.registry.resources['meh']._track_resource_events = True self.registry.resources['meh']._track_resource_events = True
res = self.registry.get_resource('meh') res = self.registry.get_resource('meh')
# This ensures dirty is true # This ensures dirty is true
res._dirty_tenants.add('tenant_id') res._dirty_projects.add('project_id')
resource_registry.set_resources_dirty(ctx) resource_registry.set_resources_dirty(ctx)
mock_mark_dirty.assert_called_once_with(ctx) mock_mark_dirty.assert_called_once_with(ctx)