Merge "Add the ability to check the tenant quota in detail"
This commit is contained in:
commit
600f9d5f8e
api-ref/source
manila
api
tests/api/v2
manila_tempest_tests
releasenotes/notes
@ -2182,6 +2182,14 @@ quota_gigabytes:
|
||||
in: body
|
||||
required: true
|
||||
type: integer
|
||||
quota_gigabytes_detail:
|
||||
description: |
|
||||
The limit, in_use, reserved number of gigabytes allowed
|
||||
for each tenant.
|
||||
in: body
|
||||
min_version: 2.25
|
||||
required: true
|
||||
type: object
|
||||
quota_gigabytes_request:
|
||||
description: |
|
||||
The number of gigabytes for the tenant.
|
||||
@ -2201,6 +2209,14 @@ quota_share_networks:
|
||||
in: body
|
||||
required: true
|
||||
type: integer
|
||||
quota_share_networks_detail:
|
||||
description: |
|
||||
The limit, in_use, reserved number of share networks
|
||||
allowed for each tenant.
|
||||
in: body
|
||||
min_version: 2.25
|
||||
required: true
|
||||
type: object
|
||||
quota_share_networks_request:
|
||||
description: |
|
||||
The number of share networks for the tenant.
|
||||
@ -2213,6 +2229,14 @@ quota_shares:
|
||||
in: body
|
||||
required: true
|
||||
type: integer
|
||||
quota_shares_detail:
|
||||
description: |
|
||||
The limit, in_use, reserved number of shares allowed
|
||||
for each tenant.
|
||||
in: body
|
||||
min_version: 2.25
|
||||
required: true
|
||||
type: object
|
||||
quota_shares_request:
|
||||
description: |
|
||||
The number of shares for the tenant.
|
||||
@ -2226,6 +2250,14 @@ quota_snapshot_gigabytes:
|
||||
in: body
|
||||
required: true
|
||||
type: integer
|
||||
quota_snapshot_gigabytes_detail:
|
||||
description: |
|
||||
The limit, in_use, reserved number of gigabytes for the
|
||||
snapshots allowed for each tenant.
|
||||
in: body
|
||||
min_version: 2.25
|
||||
required: true
|
||||
type: object
|
||||
quota_snapshot_gigabytes_request:
|
||||
description: |
|
||||
The number of gigabytes for the snapshots for the
|
||||
@ -2239,6 +2271,14 @@ quota_snapshots:
|
||||
in: body
|
||||
required: true
|
||||
type: integer
|
||||
quota_snapshots_detail:
|
||||
description: |
|
||||
The limit, in_use, reserved number of snapshots allowed
|
||||
for each tenant.
|
||||
in: body
|
||||
min_version: 2.25
|
||||
required: true
|
||||
type: object
|
||||
quota_snapshots_request:
|
||||
description: |
|
||||
The number of snapshots for the tenant.
|
||||
|
@ -93,6 +93,49 @@ Response example
|
||||
:language: javascript
|
||||
|
||||
|
||||
Show quota set in detail
|
||||
========================
|
||||
|
||||
.. rest_method:: GET /v2/{tenant_id}/quota-sets/{tenant_id}/detail?user_id={user_id}
|
||||
|
||||
Shows quotas for a tenant in detail.
|
||||
|
||||
If you specify the optional ``user_id`` query parameter, you get
|
||||
the quotas for this user in the tenant. If you omit this parameter,
|
||||
you get the quotas for the project.
|
||||
|
||||
Normal response codes: 200
|
||||
Error response codes: badRequest(400), unauthorized(401), forbidden(403)
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- tenant_id: tenant_id_path
|
||||
- tenant_id: tenant_id
|
||||
- user_id: user_id_query
|
||||
|
||||
Response parameters
|
||||
-------------------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- quota_set: quota_set
|
||||
- id: quota_tenant_id
|
||||
- gigabytes: quota_gigabytes_detail
|
||||
- snapshots: quota_snapshots_detail
|
||||
- shares: quota_shares_detail
|
||||
- snapshot_gigabytes: quota_snapshot_gigabytes_detail
|
||||
- share_networks: quota_share_networks_detail
|
||||
|
||||
Response example
|
||||
----------------
|
||||
|
||||
.. literalinclude:: samples/quota-show-detail-response.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
Update quota set
|
||||
================
|
||||
|
||||
|
20
api-ref/source/samples/quota-show-detail-response.json
Normal file
20
api-ref/source/samples/quota-show-detail-response.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"quota_set": {
|
||||
"id": "16e1ab15c35a457e9c2b2aa189f544e1",
|
||||
"gigabytes": {"in_use": 0,
|
||||
"limit": 1000,
|
||||
"reserved": 0},
|
||||
"shares": {"in_use": 0,
|
||||
"limit": 50,
|
||||
"reserved": 0},
|
||||
"snapshot_gigabytes": {"in_use": 0,
|
||||
"limit": 1000,
|
||||
"reserved": 0},
|
||||
"snapshots": {"in_use": 0,
|
||||
"limit": 50,
|
||||
"reserved": 0},
|
||||
"share_networks": {"in_use": 0,
|
||||
"limit": 10,
|
||||
"reserved": 0}
|
||||
}
|
||||
}
|
@ -82,6 +82,7 @@ REST_API_VERSION_HISTORY = """
|
||||
* 2.24 - Added optional create_share_from_snapshot_support extra spec,
|
||||
which was previously inferred from the 'snapshot_support' extra
|
||||
spec. Also made the 'snapshot_support' extra spec optional.
|
||||
* 2.25 - Added quota-show detail API.
|
||||
|
||||
"""
|
||||
|
||||
@ -89,7 +90,7 @@ REST_API_VERSION_HISTORY = """
|
||||
# The default api version request is defined to be the
|
||||
# minimum version of the API supported.
|
||||
_MIN_API_VERSION = "2.0"
|
||||
_MAX_API_VERSION = "2.24"
|
||||
_MAX_API_VERSION = "2.25"
|
||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||
|
||||
|
||||
|
@ -147,3 +147,7 @@ user documentation.
|
||||
----
|
||||
Added optional create_share_from_snapshot_support extra spec. Made
|
||||
snapshot_support extra spec optional.
|
||||
|
||||
2.25
|
||||
----
|
||||
Added quota-show detail API.
|
||||
|
@ -66,14 +66,18 @@ class QuotaSetsMixin(object):
|
||||
return {k: v['limit'] for k, v in values.items()}
|
||||
|
||||
@wsgi.Controller.authorize("show")
|
||||
def _show(self, req, id):
|
||||
def _show(self, req, id, detail=False):
|
||||
context = req.environ['manila.context']
|
||||
params = parse.parse_qs(req.environ.get('QUERY_STRING', ''))
|
||||
user_id = params.get('user_id', [None])[0]
|
||||
|
||||
try:
|
||||
db.authorize_project_context(context, id)
|
||||
# _get_quotas use 'usages' to indicate whether retrieve additional
|
||||
# attributes, so pass detail to the argument.
|
||||
return self._view_builder.detail_list(
|
||||
self._get_quotas(context, id, user_id=user_id), id)
|
||||
self._get_quotas(context, id, user_id=user_id,
|
||||
usages=detail), id)
|
||||
except exception.NotAuthorized:
|
||||
raise webob.exc.HTTPForbidden()
|
||||
|
||||
@ -221,6 +225,10 @@ class QuotaSetsController(QuotaSetsMixin, wsgi.Controller):
|
||||
def show(self, req, id):
|
||||
return self._show(req, id)
|
||||
|
||||
@wsgi.Controller.api_version('2.25')
|
||||
def detail(self, req, id):
|
||||
return self._show(req, id, True)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
def defaults(self, req, id):
|
||||
return self._defaults(req, id)
|
||||
|
@ -106,7 +106,8 @@ class APIRouter(manila.api.openstack.APIRouter):
|
||||
mapper.resource("quota-set",
|
||||
"quota-sets",
|
||||
controller=self.resources["quota_sets"],
|
||||
member={"defaults": "GET"})
|
||||
member={"defaults": "GET",
|
||||
"detail": "GET"})
|
||||
|
||||
self.resources["quota_class_sets_legacy"] = (
|
||||
quota_class_sets.create_resource_legacy())
|
||||
|
@ -26,6 +26,7 @@ from oslo_config import cfg
|
||||
import webob.exc
|
||||
import webob.response
|
||||
|
||||
from manila.api.openstack import api_version_request as api_version
|
||||
from manila.api.v2 import quota_sets
|
||||
from manila import context
|
||||
from manila import exception
|
||||
@ -121,6 +122,48 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
@ddt.data(REQ, REQ_WITH_USER)
|
||||
def test_quota_detail(self, request):
|
||||
request.api_version_request = api_version.APIVersionRequest('2.25')
|
||||
quotas = {
|
||||
"shares": 23,
|
||||
"snapshots": 34,
|
||||
"gigabytes": 45,
|
||||
"snapshot_gigabytes": 56,
|
||||
"share_networks": 67,
|
||||
}
|
||||
expected = {
|
||||
'quota_set': {
|
||||
'id': self.project_id,
|
||||
'shares': {'in_use': 0,
|
||||
'limit': quotas['shares'],
|
||||
'reserved': 0},
|
||||
'gigabytes': {'in_use': 0,
|
||||
'limit': quotas['gigabytes'], 'reserved': 0},
|
||||
'snapshots': {'in_use': 0,
|
||||
'limit': quotas['snapshots'], 'reserved': 0},
|
||||
'snapshot_gigabytes': {
|
||||
'in_use': 0,
|
||||
'limit': quotas['snapshot_gigabytes'],
|
||||
'reserved': 0,
|
||||
},
|
||||
'share_networks': {
|
||||
'in_use': 0,
|
||||
'limit': quotas['share_networks'],
|
||||
'reserved': 0
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
for k, v in quotas.items():
|
||||
CONF.set_default('quota_' + k, v)
|
||||
|
||||
result = self.controller.detail(request, self.project_id)
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
request.environ['manila.context'], self.resource_name, 'show')
|
||||
|
||||
@ddt.data(REQ, REQ_WITH_USER)
|
||||
def test_show_quota(self, request):
|
||||
quotas = {
|
||||
|
@ -30,7 +30,7 @@ ShareGroup = [
|
||||
help="The minimum api microversion is configured to be the "
|
||||
"value of the minimum microversion supported by Manila."),
|
||||
cfg.StrOpt("max_api_microversion",
|
||||
default="2.24",
|
||||
default="2.25",
|
||||
help="The maximum api microversion is configured to be the "
|
||||
"value of the latest microversion supported by Manila."),
|
||||
cfg.StrOpt("region",
|
||||
|
@ -785,6 +785,17 @@ class SharesV2Client(shares_client.SharesClient):
|
||||
self.expected_success(202, resp.status)
|
||||
return body
|
||||
|
||||
def detail_quotas(self, tenant_id, user_id=None, url=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
if url is None:
|
||||
url = self._get_quotas_url(version)
|
||||
url += '/%s/detail' % tenant_id
|
||||
if user_id is not None:
|
||||
url += "?user_id=%s" % user_id
|
||||
resp, body = self.get(url, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def update_quotas(self, tenant_id, user_id=None, shares=None,
|
||||
snapshots=None, gigabytes=None, snapshot_gigabytes=None,
|
||||
share_networks=None, force=True, url=None,
|
||||
|
@ -203,3 +203,15 @@ class SharesAdminQuotasNegativeTest(base.BaseSharesAdminTest):
|
||||
self.shares_v2_client.tenant_id,
|
||||
version=version, url=url,
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_show_quota_detail_with_wrong_versions(self):
|
||||
version = '2.24'
|
||||
url = 'quota-sets'
|
||||
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.detail_quotas,
|
||||
self.shares_v2_client.tenant_id,
|
||||
version=version, url=url,
|
||||
)
|
||||
|
@ -64,3 +64,28 @@ class SharesQuotasTest(base.BaseSharesTest):
|
||||
self.assertGreater(int(quotas["shares"]), -2)
|
||||
self.assertGreater(int(quotas["snapshots"]), -2)
|
||||
self.assertGreater(int(quotas["share_networks"]), -2)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@base.skip_if_microversion_not_supported("2.25")
|
||||
def test_show_quotas_detail(self):
|
||||
quotas = self.shares_v2_client.detail_quotas(self.tenant_id)
|
||||
quota_keys = list(quotas.keys())
|
||||
for outer in ('gigabytes', 'snapshot_gigabytes', 'shares',
|
||||
'snapshots', 'share_networks'):
|
||||
self.assertIn(outer, quota_keys)
|
||||
for inner in ('in_use', 'limit', 'reserved'):
|
||||
self.assertIn(inner, list(quotas[outer].keys()))
|
||||
self.assertGreater(int(quotas[outer][inner]), -2)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@base.skip_if_microversion_not_supported("2.25")
|
||||
def test_show_quotas_detail_for_user(self):
|
||||
quotas = self.shares_v2_client.detail_quotas(self.tenant_id,
|
||||
self.user_id)
|
||||
quota_keys = list(quotas.keys())
|
||||
for outer in ('gigabytes', 'snapshot_gigabytes', 'shares',
|
||||
'snapshots', 'share_networks'):
|
||||
self.assertIn(outer, quota_keys)
|
||||
for inner in ('in_use', 'limit', 'reserved'):
|
||||
self.assertIn(inner, list(quotas[outer].keys()))
|
||||
self.assertGreater(int(quotas[outer][inner]), -2)
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- Added detail API to show user and tenant specific usages through the
|
||||
quota-sets resource.
|
Loading…
x
Reference in New Issue
Block a user