Cinder nested quotas does not handle unlimited quotas (-1) well
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Cinder |
Fix Released
|
High
|
Ryan McNair |
Bug Description
Substituting id's with name and showing only relevant info for clarity
Issue #1:
=======
The project heirarchy is as follows:
/ \
B C
~(keystone_admin)]$ cinder quota-show A
+------
| Property | Value |
+------
| volumes | 10 |
+------
~(keystone_admin)]$ cinder quota-update C --volumes 5
+------
| Property | Value |
+------
| volumes | 5 |
+------
~(keystone_admin)]$ cinder quota-update B --volumes -1
+------
| Property | Value |
+------
| volumes | -1 |
+------
~(keystone_admin)]$ cinder quota-update B --volumes 11
ERROR: Free quota available is 6. (HTTP 400) (Request-ID: req-e904d5df-
***** Should be 5 is free ********
~(keystone_admin)]$ cinder quota-update C --volumes -1
+------
| Property | Value |
+------
| volumes | -1 |
+------
~(keystone_admin)]$ cinder quota-update B --volumes 12
ERROR: Free quota available is 12. (HTTP 400) (Request-ID: req-07cbb4eb-
***** Should be 10 is free ********
~(keystone_admin)]$ cinder quota-update eae947cadd93421
+------
| Property | Value |
+------
| volumes | 11 |
+------
Issue #2:
=======
The project heirarchy is as follows:
~(keystone_admin)]$ cinder quota-show A
+------
| Property | Value |
+------
| volumes | 10 |
+------
~(keystone_admin)]$ cinder quota-update B --volumes -1
+------
| Property | Value |
+------
| volumes | -1 |
+------
~(keystone_admin)]$ cinder quota-show C
+------
| Property | Value |
+------
| volumes | 0 |
+------
************* Coming from default quota ***********
~(keystone_admin)]$ cinder quota-set C --volumes 0
ERROR: Free quota available is -1. (HTTP 400) (Request-ID: req-322d165c-
Issue #3:
=======
The project heirarchy is as follows:
~(keystone_admin)]$ cinder quota-show A
+------
| Property | Value |
+------
| volumes | 1 |
+------
~(keystone_admin)]$ cinder quota-update B --volumes -1
+------
| Property | Value |
+------
| volumes | -1 |
+------
~(keystone_admin)]$ cinder quota-update C --volumes -1
+------
| Property | Value |
+------
| volumes | -1 |
+------
< Authenticate to use project C>
~(keystone_admin)]$ cinder create 1
... success ....
~(keystone_admin)]$ cinder create 1
... success ...
**** Shouldn't work because max limit should be the grandparent, which is 1! The validation is not going recursively up the heirarchy in the case of unlimited / shared quotas. *****
Changed in cinder: | |
assignee: | nobody → Ryan McNair (rdmcnair) |
Changed in cinder: | |
importance: | Undecided → High |
milestone: | none → mitaka-3 |
Changed in cinder: | |
status: | New → In Progress |
Here are test-cases which will expose the three issues on master:
# Issue 1 child_limit_ affecting_ free(self) :
self.controlle r._get_ project = mock.Mock()
self.controlle r._get_ project. side_effect = self._get_project
self.req. environ[ 'cinder. context' ].project_ id = self.A.id
def test_neg_
cur_quota_a = self.controller .show(self. req, self.A.id)
self.assertEqu al(10, cur_quota_ a['quota_ set'][' volumes' ])
quota = {'volumes': -1}
self.controlle r.update( self.req, self.C.id, body)
self.controlle r.update( self.req, self.B.id, body)
body = {'quota_set': quota}
# Shouldn't be able to set greater than parent
quota[ 'volumes' ] = 11
self.assertRai ses(
webob. exc.HTTPBadRequ est, self.controller .update, self.req,
self. B.id, body)
# Issue 2 neg_limit_ set_grandkid_ zero_limit( self):
self.controlle r._get_ project = mock.Mock()
self.controlle r._get_ project. side_effect = self._get_project
self.req. environ[ 'cinder. context' ].project_ id = self.A.id
def test_child_
cur_quota_a = self.controller .show(self. req, self.A.id)
self.assertEqu al(10, cur_quota_ a['quota_ set'][' volumes' ])
quota = {'volumes': -1}
self.controlle r.update( self.req, self.B.id, body)
body = {'quota_set': quota}
cur_quota_d = self.controller .show(self. req, self.D.id)
self.assertEqu al(0, cur_quota_ d['quota_ set'][' volumes' ])
quota[ 'volumes' ] = 0
self.controlle r.update( self.req, self.D.id, body)
# Default child value is 0
# Should be able to set D explicitly to 0 since that's already the val
# Issue 3 negative_ one_limit_ enforced( self):
self.controlle r._get_ project = mock.Mock()
self.controlle r._get_ project. side_effect = self._get_project
self.req. environ[ 'cinder. context' ].project_ id = self.A.id
def test_grandkid_
quota = {'volumes': 1}
self.controlle r.update( self.req, self.A.id, body)
body = {'quota_set': quota}