Allow setting quota of other tenants
Currently, the quota API/CLI allows users to set quotas for current tenant only. However, admin users needs the ability to set quota for other tenants. For example: $ source /opt/stack/devstack/openrc admin admin $ openstack appcontainer quota update --containers 100 <DEMO_TENANT_UUID> Closes-Bug: #1807620 Change-Id: I9109d968d8010692644fd004a8085a43e1bdf60f
This commit is contained in:
parent
c2afcc5d70
commit
d1d5dfe5fc
@ -17,6 +17,12 @@ host_ident:
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
project_id:
|
||||
description: |
|
||||
The UUID of project in a multi-project cloud.
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
quota_class_name:
|
||||
description: |
|
||||
The name of quota class
|
||||
|
@ -9,7 +9,7 @@ Gets, updates, gets default and deletes quotas for a project.
|
||||
Update quotas for a project
|
||||
===========================
|
||||
|
||||
.. rest_method:: PUT /v1/quotas
|
||||
.. rest_method:: PUT /v1/quotas/{project_id}
|
||||
|
||||
Update the quotas for a project
|
||||
|
||||
@ -31,6 +31,7 @@ Request
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- project_id: project_id
|
||||
- containers: container-request
|
||||
- memory: memory-request
|
||||
- cpu: cpu-request
|
||||
@ -61,7 +62,7 @@ Response Example
|
||||
Get quotas for a project
|
||||
========================
|
||||
|
||||
.. rest_method:: GET /v1/quotas
|
||||
.. rest_method:: GET /v1/quotas/{project_id}
|
||||
|
||||
Get quotas for a project
|
||||
|
||||
@ -81,6 +82,10 @@ Response Codes
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- project_id: project_id
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
@ -101,7 +106,7 @@ Response Example
|
||||
Get Default quotas for a project
|
||||
================================
|
||||
|
||||
.. rest_method:: GET /v1/quotas/defaults
|
||||
.. rest_method:: GET /v1/quotas/{project_id}/defaults
|
||||
|
||||
Get the default quotas for a project
|
||||
|
||||
@ -121,6 +126,10 @@ Response Codes
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- project_id: project_id
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
@ -141,7 +150,7 @@ Response Example
|
||||
Revert Quotas to defaults
|
||||
=========================
|
||||
|
||||
.. rest_method:: DELETE /v1/quotas
|
||||
.. rest_method:: DELETE /v1/quotas/{project_id}
|
||||
|
||||
Reverts the quotas to default values for a project
|
||||
|
||||
@ -157,6 +166,10 @@ Reverts the quotas to default values for a project
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- project_id: project_id
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
|
@ -30,8 +30,8 @@ class QuotaController(base.Controller):
|
||||
'defaults': ['GET'],
|
||||
}
|
||||
|
||||
def _get_quotas(self, context, usages=False):
|
||||
values = QUOTAS.get_project_quotas(context, context.project_id,
|
||||
def _get_quotas(self, context, project_id, usages=False):
|
||||
values = QUOTAS.get_project_quotas(context, project_id,
|
||||
usages=usages)
|
||||
|
||||
if usages:
|
||||
@ -43,11 +43,11 @@ class QuotaController(base.Controller):
|
||||
@exception.wrap_pecan_controller_exception
|
||||
@validation.validate_query_param(pecan.request, schema.query_param_update)
|
||||
@validation.validated(schema.query_param_update)
|
||||
def put(self, **quotas_dict):
|
||||
def put(self, project_id, **quotas_dict):
|
||||
context = pecan.request.context
|
||||
policy.enforce(context, 'quota:update',
|
||||
target={'project_id': project_id},
|
||||
action='quota:update')
|
||||
project_id = context.project_id
|
||||
for key, value in quotas_dict.items():
|
||||
value = int(value)
|
||||
quota = objects.Quota(context, project_id=project_id, resource=key,
|
||||
@ -56,30 +56,33 @@ class QuotaController(base.Controller):
|
||||
quota.create(context)
|
||||
except exception.QuotaAlreadyExists:
|
||||
quota.update(context)
|
||||
return self._get_quotas(context)
|
||||
return self._get_quotas(context, project_id)
|
||||
|
||||
@pecan.expose('json')
|
||||
@exception.wrap_pecan_controller_exception
|
||||
def get(self, **kwargs):
|
||||
def get(self, project_id, **kwargs):
|
||||
context = pecan.request.context
|
||||
usages = kwargs.get('usages', False)
|
||||
policy.enforce(context, 'quota:get',
|
||||
target={'project_id': project_id},
|
||||
action='quota:get')
|
||||
return self._get_quotas(context, usages=usages)
|
||||
return self._get_quotas(context, project_id, usages=usages)
|
||||
|
||||
@pecan.expose('json')
|
||||
@exception.wrap_pecan_controller_exception
|
||||
def defaults(self):
|
||||
def defaults(self, project_id):
|
||||
context = pecan.request.context
|
||||
policy.enforce(context, 'quota:get_default',
|
||||
target={'project_id': project_id},
|
||||
action='quota:get_default')
|
||||
values = QUOTAS.get_defaults(context)
|
||||
return values
|
||||
|
||||
@pecan.expose('json')
|
||||
@exception.wrap_pecan_controller_exception
|
||||
def delete(self):
|
||||
def delete(self, project_id):
|
||||
context = pecan.request.context
|
||||
policy.enforce(context, 'quota:delete',
|
||||
target={'project_id': project_id},
|
||||
action='quota:delete')
|
||||
QUOTAS.destroy_all_by_project(context, context.project_id)
|
||||
QUOTAS.destroy_all_by_project(context, project_id)
|
||||
|
@ -23,7 +23,7 @@ rules = [
|
||||
description='Update quotas for a project',
|
||||
operations=[
|
||||
{
|
||||
'path': '/v1/quotas',
|
||||
'path': '/v1/quotas/{project_id}',
|
||||
'method': 'PUT'
|
||||
}
|
||||
]
|
||||
@ -34,7 +34,7 @@ rules = [
|
||||
description='Delete quotas for a project',
|
||||
operations=[
|
||||
{
|
||||
'path': '/v1/quotas',
|
||||
'path': '/v1/quotas/{project_id}',
|
||||
'method': 'DELETE'
|
||||
}
|
||||
]
|
||||
@ -45,7 +45,7 @@ rules = [
|
||||
description='Get quotas for a project',
|
||||
operations=[
|
||||
{
|
||||
'path': '/v1/quotas',
|
||||
'path': '/v1/quotas/{project_id}',
|
||||
'method': 'GET'
|
||||
}
|
||||
]
|
||||
|
@ -18,6 +18,7 @@ from zun.tests.unit.api import base as api_base
|
||||
class TestQuotaController(api_base.FunctionalTest):
|
||||
def setUp(self):
|
||||
super(TestQuotaController, self).setUp()
|
||||
self.test_project_id = 'test_project_id'
|
||||
self.default_quotas = {
|
||||
'containers': 40,
|
||||
'cpu': 20,
|
||||
@ -27,31 +28,32 @@ class TestQuotaController(api_base.FunctionalTest):
|
||||
|
||||
@mock.patch('zun.common.policy.enforce', return_value=True)
|
||||
def test_get_defaults_quota(self, mock_policy):
|
||||
response = self.get('/quotas/defaults')
|
||||
response = self.get('/quotas/%s/defaults' % self.test_project_id)
|
||||
self.assertEqual(200, response.status_int)
|
||||
self.assertEqual(self.default_quotas, response.json)
|
||||
|
||||
@mock.patch('zun.common.policy.enforce', return_value=True)
|
||||
def test_put_quota(self, mock_policy):
|
||||
def test_put_quota_with_project_id(self, mock_policy):
|
||||
update_quota_dicts = {
|
||||
'containers': '50',
|
||||
'memory': '61440'
|
||||
}
|
||||
|
||||
response = self.put_json('/quotas', update_quota_dicts)
|
||||
response = self.put_json('/quotas/%s' % self.test_project_id,
|
||||
update_quota_dicts)
|
||||
self.assertEqual(200, response.status_int)
|
||||
self.assertEqual(50, response.json['containers'])
|
||||
self.assertEqual(61440, response.json['memory'])
|
||||
|
||||
@mock.patch('zun.common.policy.enforce', return_value=True)
|
||||
def test_get_quota(self, mock_policy):
|
||||
response = self.get('/quotas')
|
||||
def test_get_quota_with_project_id(self, mock_policy):
|
||||
response = self.get('/quotas/%s' % self.test_project_id)
|
||||
self.assertEqual(200, response.status_int)
|
||||
self.assertEqual(self.default_quotas, response.json)
|
||||
|
||||
@mock.patch('zun.common.policy.enforce', return_value=True)
|
||||
def test_delete_quota(self, mock_policy):
|
||||
response = self.delete('/quotas')
|
||||
def test_delete_quota_with_project_id(self, mock_policy):
|
||||
response = self.delete('/quotas/%s' % self.test_project_id)
|
||||
self.assertEqual(200, response.status_int)
|
||||
response = self.get('/quotas')
|
||||
response = self.get('/quotas/%s' % self.test_project_id)
|
||||
self.assertEqual(self.default_quotas, response.json)
|
||||
|
Loading…
Reference in New Issue
Block a user