Fix automatic quota sync for temporary volumes

When using the automatic quota refresh via `until_refresh` and `max_age`
configuration options the calculated quota usage by the refresh will not
be correct if there are temporary volumes (such as those created from
snapshots for backups).

Normal quota usage calculation does not work like this, as it has admin
metadata stating that those are temporary volumes and are not used to
increase/decrease quota usage.

This patch fixes this by modifying existing filter that ignores
migrating volumes so it can also ignore temporary volumes based on their
admin metadata.

Closes-Bug: #1919161
Change-Id: I0fd89028684c1406f427f4c97b120ece5cf2780b
This commit is contained in:
Gorka Eguileor 2021-03-15 15:12:13 +01:00
parent 7c4b626c01
commit 8f03b26f50
3 changed files with 42 additions and 2 deletions

View File

@ -1593,10 +1593,20 @@ def _volume_data_get_for_project(context, project_id, volume_type_id=None,
# When calling the method for quotas we don't count volumes that are the
# destination of a migration since they were not accounted for quotas or
# reservations in the first place.
# Also skip temporary volumes that have 'temporary' admin_metadata key set
# to True.
if skip_internal:
admin_model = models.VolumeAdminMetadata
query = query.filter(
or_(model.migration_status.is_(None),
~model.migration_status.startswith('target:')))
and_(or_(model.migration_status.is_(None),
~model.migration_status.startswith('target:')),
~sql.exists().where(and_(model.id == admin_model.volume_id,
~admin_model.deleted,
admin_model.key == 'temporary',
admin_model.value == 'True')
)
)
)
if host:
query = query.filter(_filter_host(model.host, host))

View File

@ -554,6 +554,28 @@ class DBAPIVolumeTestCase(BaseTest):
self.ctxt, 'project', skip_internal=skip_internal)
self.assertEqual((count, gigabytes), result)
@ddt.data((True, THREE_HUNDREDS, THREE),
(False, THREE_HUNDREDS + ONE_HUNDREDS, THREE + 1))
@ddt.unpack
def test__volume_data_get_for_project_temporary(self, skip_internal,
gigabytes, count):
for i in range(3):
db.volume_create(self.ctxt,
{'project_id': 'project',
'size': ONE_HUNDREDS,
'host': 'h-%d' % i,
'volume_type_id': fake.VOLUME_TYPE_ID})
# This is a temporary volume
db.volume_create(self.ctxt, {'project_id': 'project',
'size': ONE_HUNDREDS,
'host': 'h-%d' % i,
'volume_type_id': fake.VOLUME_TYPE_ID,
'admin_metadata': {'temporary': 'True'}})
result = sqlalchemy_api._volume_data_get_for_project(
self.ctxt, 'project', skip_internal=skip_internal)
self.assertEqual((count, gigabytes), result)
def test_volume_data_get_for_project_with_host(self):
db.volume_create(self.ctxt, {'project_id': fake.PROJECT_ID,

View File

@ -0,0 +1,8 @@
---
fixes:
- |
`Bug #1919161 <https://bugs.launchpad.net/cinder/+bug/1919161>`_: Fix
automatic quota refresh to correctly account for temporary volumes. During
some cinder operations, such as create a backup from a snapshot, temporary
volumes are created and are not counted towards quota usage, but the sync
mechanism was counting them, thus incorrectly updating volume usage.