summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark McLoughlin <markmc@redhat.com>2012-09-01 09:37:15 +0100
committerMark McLoughlin <markmc@redhat.com>2012-09-01 09:37:15 +0100
commit22f0e324f3d3172b563aa67e513fe4d9318de2e5 (patch)
treead216707b726f4127307a59c7deb5996a3b039f1
parent68abbbbcf02650d24d65a1455ddd40099616c2bd (diff)
downloadnova-22f0e324f3d3172b563aa67e513fe4d9318de2e5.tar.gz
nova-22f0e324f3d3172b563aa67e513fe4d9318de2e5.tar.xz
nova-22f0e324f3d3172b563aa67e513fe4d9318de2e5.zip
Fix quota reservation expiration
Fixes bug #1040942 The db.reservation_expire() function assumes a 'usage' attribute on Reservation objects, but we don't actually define that relationship. The end result is that reservation_expire() currently traceback if it actually needs to expire any reservations. This happens pretty rarely since reservations should only need expiring if they are leaked because of another bug. Also define a test case to actually excercise the expiration code path. Add a missing chain-up to tearDown in test_limits which was causing the get_project_quotas() stub not to be unset and, in turn, the reservation expiration test to fail. Change-Id: Ib61dbf9fd5dfb5badaf05f20c423a69925d83754
-rw-r--r--nova/db/sqlalchemy/models.py6
-rw-r--r--nova/tests/api/openstack/compute/test_limits.py1
-rw-r--r--nova/tests/test_quota.py20
3 files changed, 27 insertions, 0 deletions
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 65d5eb5e0..8b8322276 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -496,6 +496,12 @@ class Reservation(BASE, NovaBase):
delta = Column(Integer)
expire = Column(DateTime, nullable=False)
+ usage = relationship(
+ "QuotaUsage",
+ foreign_keys=usage_id,
+ primaryjoin='and_(Reservation.usage_id == QuotaUsage.id,'
+ 'QuotaUsage.deleted == False)')
+
class Snapshot(BASE, NovaBase):
"""Represents a block storage device that can be attached to a VM."""
diff --git a/nova/tests/api/openstack/compute/test_limits.py b/nova/tests/api/openstack/compute/test_limits.py
index 059deabf7..2a3038267 100644
--- a/nova/tests/api/openstack/compute/test_limits.py
+++ b/nova/tests/api/openstack/compute/test_limits.py
@@ -794,6 +794,7 @@ class WsgiLimiterProxyTest(BaseLimitTestSuite):
def tearDown(self):
# restore original HTTPConnection object
httplib.HTTPConnection = self.oldHTTPConnection
+ super(WsgiLimiterProxyTest, self).tearDown()
class LimitsViewBuilderTest(test.TestCase):
diff --git a/nova/tests/test_quota.py b/nova/tests/test_quota.py
index 794c578d6..8dddef173 100644
--- a/nova/tests/test_quota.py
+++ b/nova/tests/test_quota.py
@@ -228,6 +228,26 @@ class QuotaIntegrationTestCase(test.TestCase):
self.assertRaises(exception.QuotaError,
self._create_with_injected_files, files)
+ def test_reservation_expire(self):
+ timeutils.set_time_override()
+
+ def assertInstancesReserved(reserved):
+ result = quota.QUOTAS.get_project_quotas(self.context,
+ self.context.project_id)
+ self.assertEqual(result['instances']['reserved'], reserved)
+
+ quota.QUOTAS.reserve(self.context,
+ expire=60,
+ instances=2)
+
+ assertInstancesReserved(2)
+
+ timeutils.advance_time_seconds(80)
+
+ result = quota.QUOTAS.expire(self.context)
+
+ assertInstancesReserved(0)
+
class FakeContext(object):
def __init__(self, project_id, quota_class):